<> <> DIRECTORY Basics USING [BITAND, BITSHIFT, HighByte, LongNumber, LowByte, LowHalf], IO USING [card, int, PutF, STREAM], Process USING [MsecToTicks, SetTimeout], PupDefs USING [GetFreePupBuffer, MsToTocks, PupAddressLookup, PupAddressToRope, PupBuffer, PupPackageMake, PupPackageDestroy, PupRouterSendThis, PupSocket, PupSocketID, PupSocketDestroy, PupSocketMake, ReturnFreePupBuffer, SetPupContentsWords, UniqueLocalPupAddress], PupTypes USING [fillInHostID, fillInNetID, fillInPupAddress, Pair, PupAddress, PupType], PupStream USING [GetPupAddress, PupNameTrouble], Rope USING [ROPE], TeleLoad; TeleLoadImpl: MONITOR IMPORTS Basics, IO, Process, PupDefs, PupStream EXPORTS TeleLoad = BEGIN OPEN TeleLoad; BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED]; And: BitOp = INLINE { RETURN[Basics.BITAND[a,b]]; }; Shift: BitOp = INLINE { RETURN[Basics.BITSHIFT[a,b]]; }; locMaxByte: PUBLIC NAT _ 150; NameToAddress: PUBLIC SAFE PROC [name: Rope.ROPE] RETURNS [address: PupTypes.PupAddress, ok: BOOL _ TRUE] = TRUSTED { address _ PupStream.GetPupAddress[teleSwatSocket, name ! PupStream.PupNameTrouble => {ok _ FALSE; CONTINUE; }]; }; AddressToName: PUBLIC SAFE PROC [address: PupTypes.PupAddress] RETURNS [nameRope, addressRope: Rope.ROPE] = TRUSTED { nameRope _ PupDefs.PupAddressLookup[address]; addressRope _ PupDefs.PupAddressToRope[address]; }; Start: PUBLIC SAFE PROC [host: Rope.ROPE, log: IO.STREAM] RETURNS [h: Handle] = TRUSTED { sendHim: PupTypes.PupAddress; allok: BOOL; [sendHim, allok] _ NameToAddress[host]; sendHim.socket _ TeleLoad.teleSwatSocket; IF NOT allok THEN RETURN[NIL]; h _ NEW[TLObject _ [ host: host, address: sendHim, cacheSize: locMaxByte, log: log]]; RETURN[h]; }; Stop: PUBLIC SAFE PROC [h: Handle] = TRUSTED { IF h=NIL THEN RETURN; h.host _ NIL; h.log _ NIL; }; Store: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GStore[h: h, requestcb: cb, type: coreStoreRequest, tries: tries]; }; Fetch: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GFetch[h: h, requestcb: cb, type: coreFetchRequest, tries: tries]; }; SlaveStore: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GStore[h: h, requestcb: cb, type: slaveStoreRequest, tries: tries]; }; SlaveFetch: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GFetch[h: h, requestcb: cb, type: slaveFetchRequest, tries: tries]; }; Call: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GExchange[h: h, requestcb: cb, type: callRequest, tries: tries]; }; Go: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GStore[h: h, requestcb: cb, type: goRequest, tries: 1]; }; GoFromBreak: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GStore[h: h, requestcb: cb, type: goFromBreakRequest, tries: 1]; }; SingleStep: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GStore[h: h, requestcb: cb, type: singleStepRequest, tries: 1]; }; FetchState: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; [ok, attempts] _ GFetch[h: h, requestcb: cb, type: stateFetchRequest, tries: tries]; }; GoToDebugger: PUBLIC ENTRY TeleLoadProc = TRUSTED { ENABLE UNWIND => NULL; b: PupDefs.PupBuffer _ PupDefs.GetFreePupBuffer[]; replycb: CorePkt; replycb _ LOOPHOLE[@b.pupBody]; replycb.advice _ cb.advice; replycb.address _ cb.address; replycb.count _ cb.count; FOR j: CARDINAL IN [0..cb.count) DO replycb.data[j] _ cb.data[j]; ENDLOOP; PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((cb.count+1)/2)]; b.pupID _ NewPupID[]; b.pupType _ debugRequest; KingSend[b, h.address]; }; <> eventServerUseCount: INT _ 0; eventServerActive: BOOL _ FALSE; eventServerProcess: PROCESS; eventServerPollingInterval: NAT _ 500; eventSocket: PupDefs.PupSocket _ NIL; eventClientProcedure: EventProc; eventClientData: REF ANY; StartEventServer: PUBLIC ENTRY SAFE PROC [proc: EventProc, clientData: REF ANY] = TRUSTED { eventServerUseCount _ eventServerUseCount + 1; IF eventServerUseCount > 1 THEN RETURN; IF eventServerActive THEN RETURN; eventClientProcedure _ proc; eventClientData _ clientData; eventServerActive _ TRUE; eventServerProcess _ FORK TeleloadEventServer[]; }; StopEventServer: PUBLIC ENTRY SAFE PROC = TRUSTED { eventServerUseCount _ MAX[0, eventServerUseCount - 1]; IF eventServerUseCount > 0 THEN RETURN; eventServerActive _ FALSE; JOIN eventServerProcess; }; TeleloadEventServer: PROC = { b: PupDefs.PupBuffer _ NIL; er: EventRecord; cp: CorePkt; PupDefs.PupPackageMake[]; eventSocket _ PupDefs.PupSocketMake[local: teleSwatSocket, remote: [PupTypes.fillInNetID, PupTypes.fillInHostID, teleSwatSocket], ticks: PupDefs.MsToTocks[eventServerPollingInterval]]; DO b _ eventSocket.get[]; IF b # NIL THEN { cp _ LOOPHOLE[@b.pupBody]; er _ LOOPHOLE[@cp^.data]; eventClientProcedure[b.source, er^, eventClientData]; PupDefs.ReturnFreePupBuffer[b]; }; IF NOT eventServerActive THEN EXIT; ENDLOOP; eventClientData _ NIL; eventClientProcedure _ NIL; PupDefs.PupSocketDestroy[eventSocket]; PupDefs.PupPackageDestroy[]; }; GStore: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: NAT] RETURNS [a: BOOL _ TRUE, actualAttempts: NAT] = { b: PupDefs.PupBuffer _ NIL; id: PupTypes.Pair _ NewPupID[]; replycb: CorePkt; IF h=NIL THEN RETURN[FALSE, 0]; FOR actualAttempts IN [1..tries] DO IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; b _ PupDefs.GetFreePupBuffer[]; replycb _ LOOPHOLE[@b.pupBody]; replycb.advice _ requestcb.advice; replycb.address _ requestcb.address; replycb.count _ requestcb.count; FOR j: CARDINAL IN [0..requestcb.count) DO replycb.data[j] _ requestcb.data[j]; ENDLOOP; PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((requestcb.count+1)/2)]; b _ Exchange[h, b, type, id]; IF b=NIL THEN LOOP; replycb _ LOOPHOLE[@b.pupBody]; IF NOT Check[requestcb, replycb] THEN LOOP; requestcb.advice _ replycb.advice; EXIT; REPEAT FINISHED => a _ FALSE; ENDLOOP; IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; }; GFetch: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: CARDINAL] RETURNS [a: BOOL _ TRUE, actualAttempts: NAT] = { b: PupDefs.PupBuffer _ NIL; id: PupTypes.Pair _ NewPupID[]; replycb: CorePkt; IF h=NIL THEN RETURN[FALSE, 0]; FOR actualAttempts IN [1..tries] DO IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; b _ PupDefs.GetFreePupBuffer[]; replycb _ LOOPHOLE[@b.pupBody]; replycb.advice _ requestcb.advice; replycb.address _ requestcb.address; replycb.count _ requestcb.count; PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]]; b _ Exchange[h, b, type, id]; IF b=NIL THEN LOOP; replycb _ LOOPHOLE[@b.pupBody]; IF replycb.address # requestcb.address THEN LOOP; IF replycb.count # requestcb.count THEN LOOP; FOR j: CARDINAL IN [0..requestcb.count) DO requestcb.data[j] _ replycb.data[j]; ENDLOOP; requestcb.advice _ replycb.advice; EXIT; REPEAT FINISHED => a _ FALSE; ENDLOOP; IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; }; GExchange: INTERNAL PROC [h: Handle, requestcb: CoreBlock, type: PupTypes.PupType, tries: CARDINAL] RETURNS [a: BOOL _ TRUE, actualAttempts: NAT] = { b: PupDefs.PupBuffer _ NIL; id: PupTypes.Pair _ NewPupID[]; replycb: CorePkt; IF h=NIL THEN RETURN[FALSE, 0]; FOR actualAttempts IN [1..tries] DO IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; b _ PupDefs.GetFreePupBuffer[]; replycb _ LOOPHOLE[@b.pupBody]; replycb.advice _ requestcb.advice; replycb.address _ requestcb.address; replycb.count _ requestcb.count; FOR j: CARDINAL IN [0..requestcb.count) DO replycb.data[j] _ requestcb.data[j]; ENDLOOP; PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]+((requestcb.count+1)/2)]; b.pupID _ id; b _ Exchange[h, b, type, id]; IF b=NIL THEN LOOP; replycb _ LOOPHOLE[@b.pupBody]; IF replycb.address # requestcb.address THEN LOOP; IF replycb.count # requestcb.count THEN LOOP; FOR j: CARDINAL IN [0..requestcb.count) DO requestcb.data[j] _ replycb.data[j]; ENDLOOP; requestcb.advice _ replycb.advice; EXIT; REPEAT FINISHED => a _ FALSE; ENDLOOP; IF b#NIL THEN PupDefs.ReturnFreePupBuffer[b]; }; Exchange: INTERNAL PROC [h: Handle, request: PupDefs.PupBuffer, type: PupTypes.PupType, id: PupTypes.Pair] RETURNS[PupDefs.PupBuffer] = { reply: PupDefs.PupBuffer _ NIL; request.pupID _ id; request.pupType _ type; KingSend[request, h.address]; DO IF reply#NIL THEN PupDefs.ReturnFreePupBuffer[reply]; reply _ KingGet[h.address]; IF reply = NIL THEN RETURN[NIL]; IF reply.pupType # LOOPHOLE[LOOPHOLE[type, CARDINAL]+1] THEN LOOP; IF reply.pupID # id THEN LOOP; RETURN[reply]; ENDLOOP; }; Check: INTERNAL PROC [a: CoreBlock, b: CorePkt] RETURNS [BOOL] = { IF a.address # b.address THEN RETURN[FALSE]; IF a.count # b.count THEN RETURN[FALSE]; FOR i: CARDINAL IN [0..a.count) DO IF a.data[i] # b.data[i] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; }; <> Failed: PUBLIC ERROR = CODE; <<>> GetCoreBlock: PUBLIC ENTRY SAFE PROC[h: Handle, addr: CoreAddress, count: CARDINAL, addressSpace: AddressSpace _ main] RETURNS [cb: CoreBlock] = TRUSTED { ENABLE UNWIND => NULL; RETURN [GetCoreBlockInternal[h, addr, count, addressSpace]]; }; GetCoreBlockInternal: INTERNAL PROC[h: Handle, addr: CoreAddress, count: CARDINAL, addressSpace: AddressSpace] RETURNS [cb: CoreBlock] = { ok: BOOLEAN; tries: NAT; cb _ NEW[CoreBlockObject[count]]; cb.address _ addr; cb.advice _ [FALSE, FALSE, 0]; [ok, tries] _ GFetch[h, cb, IF addressSpace = main THEN coreFetchRequest ELSE slaveFetchRequest, 5]; IF NOT ok THEN { IF h.log # NIL THEN h.log.PutF[" ... %d byte read from %08x failed, (%d tries).\n", IO.card[count], IO.card[cb.address], IO.int[tries]]; cb_NIL; ERROR Failed; }; }; ReadWord: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace _ main] RETURNS [v: CARDINAL] = TRUSTED { ENABLE UNWIND => NULL; RETURN [ReadInternal[h, addr, addressSpace] + (Shift[ReadInternal[h, addr+1, addressSpace], 8])]; }; Read: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace _ main] RETURNS [v: CARDINAL] = TRUSTED { ENABLE UNWIND => NULL; RETURN[ReadInternal[h, addr, addressSpace]]; }; ReadInternal: INTERNAL PROC [h: Handle, addr: CoreAddress, addressSpace: AddressSpace] RETURNS [v: CARDINAL] = { temp: Basics.LongNumber; blockAddr: CoreAddress; count: NAT _ h.cacheSize; IF h.cacheSize = 0 THEN h.cacheSize _ locMaxByte; h.cacheSize _ MAX[1, MIN[h.cacheSize, locMaxByte]]; temp.lc _ addr; temp.lc _ temp.lc - (temp.lc MOD h.cacheSize); blockAddr _ temp.lc; IF h.cacheCB = NIL THEN { h.cacheCB _ GetCoreBlockInternal[h: h, addr: blockAddr, count: h.cacheSize, addressSpace: addressSpace]; h.addressSpace _ addressSpace; }; IF h.cacheCB.address # blockAddr OR h.addressSpace # addressSpace THEN { FlushWritesInternal[h]; h.cacheCB _ GetCoreBlockInternal[h: h, addr: blockAddr, count: h.cacheSize, addressSpace: addressSpace]; h.addressSpace _ addressSpace; }; RETURN[h.cacheCB.data[Basics.LowHalf[addr-blockAddr]]]; }; WriteWord: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace _ main] = TRUSTED { ENABLE UNWIND => NULL; WriteInternal[h, addr, And[value, 377B], addressSpace]; WriteInternal[h, addr + 1, Shift[value, -8], addressSpace]; }; Write: PUBLIC ENTRY SAFE PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace _ main] = TRUSTED { ENABLE UNWIND => NULL; WriteInternal[h, addr, value, addressSpace]; }; WriteInternal: INTERNAL PROC [h: Handle, addr: CoreAddress, value: CARDINAL, addressSpace: AddressSpace] = { temp: Basics.LongNumber; blockAddr: CoreAddress; [] _ ReadInternal[h, addr, addressSpace]; temp.lc _ addr; temp.lc _ temp.lc - (temp.lc MOD h.cacheSize); blockAddr _ temp.lc; h.cacheCB.data[Basics.LowHalf[addr-blockAddr]] _ value; h.dirty _ TRUE; }; FlushWrites: PUBLIC ENTRY SAFE PROC [h: Handle] = TRUSTED { ENABLE UNWIND => NULL; FlushWritesInternal[h]; }; FlushWritesInternal: INTERNAL PROC [h: Handle] = { IF h.dirty THEN { ok: BOOL; tries: NAT; [ok, tries] _ GStore[h, h.cacheCB, IF h.addressSpace = main THEN coreStoreRequest ELSE slaveStoreRequest, 5]; h.dirty _ FALSE; IF NOT ok THEN { IF h.log # NIL THEN h.log.PutF[" Write to %08x failed (%d tries), cache reset anyway.\n", IO.card[h.cacheCB.address], IO.int[tries]]; ERROR Failed; }; }; }; ResetCache: PUBLIC ENTRY SAFE PROC [h: Handle] = TRUSTED { ENABLE UNWIND => NULL; FlushWritesInternal[h]; h.cacheCB _ NIL; }; SetCacheSize: PUBLIC ENTRY SAFE PROC [h: Handle, bytes: NAT] = TRUSTED { ENABLE UNWIND => NULL; FlushWritesInternal[h]; h.cacheCB _ NIL; h.cacheSize _ IF bytes = 0 THEN locMaxByte ELSE MAX[1, MIN[locMaxByte, bytes]]; }; Swab: PUBLIC SAFE PROC [a: CARDINAL] RETURNS [b: CARDINAL] = TRUSTED { b _ Basics.BITSHIFT[Basics.LowByte[a], 8] + Basics.HighByte[a]; }; SwabState: PUBLIC SAFE PROC [state: State8086Object] RETURNS [State8086Object] = TRUSTED { FOR i: Registers8086 IN [AX..FL] DO state.Regs[i] _ Swab[state.Regs[i]]; ENDLOOP; RETURN[state]; }; SwabEvent: PUBLIC SAFE PROC [state: EventRecordObject] RETURNS [EventRecordObject] = TRUSTED { state.regs _ SwabState[state.regs]; state.reason _ Swab[state.reason]; state.clockLow _ Swab[state.clockLow]; state.clockHigh _ Swab[state.clockHigh]; state.bootSwitches _ Swab[state.bootSwitches]; state.advice _ Swab[state.advice]; state.monRelays _ Swab[state.monRelays]; state.tlNet _ Swab[state.tlNet]; state.tlHost _ Swab[state.tlHost]; state.tlImHost _ Swab[state.tlImHost]; state.localNet _ Swab[state.localNet]; RETURN[state]; }; <> <<>> <> kingUseCount: INT _ 0; kingWait: CONDITION; lastPacket: PupDefs.PupBuffer; pleaseStopKing: BOOL _ TRUE; myID: PupTypes.Pair _ [1711, 1]; <> king: PupDefs.PupSocket; kingProcess: PROCESS; KingGet: INTERNAL PROC [from: PupTypes.PupAddress] RETURNS [PupDefs.PupBuffer] = { b: PupDefs.PupBuffer; IF lastPacket # NIL AND lastPacket.source.net = from.net AND lastPacket.source.host = from.host THEN { b _ lastPacket; lastPacket _ NIL; RETURN[b]; }; WAIT kingWait; IF lastPacket # NIL AND lastPacket.source.net = from.net AND lastPacket.source.host = from.host THEN { b _ lastPacket; lastPacket _ NIL; RETURN[b]; }; RETURN[NIL]; }; NewPupID: INTERNAL PROC RETURNS [PupTypes.Pair] = { myID.b _ myID.b + 1; RETURN [myID]; }; KingSend: INTERNAL PROC [b: PupDefs.PupBuffer _ NIL, to: PupTypes.PupAddress] = { IF king = NIL THEN { PupDefs.ReturnFreePupBuffer[b]; RETURN; }; b.dest _ to; b.source _ king.getLocalAddress[]; PupDefs.PupRouterSendThis[b]; }; KingDaemon: PROC = { us: PupTypes.PupAddress _ PupDefs.UniqueLocalPupAddress[PupTypes.fillInPupAddress]; b: PupDefs.PupBuffer; SetKingPacket: ENTRY PROC [b: PupDefs.PupBuffer] = { IF lastPacket # NIL THEN PupDefs.ReturnFreePupBuffer[lastPacket]; lastPacket _ b; NOTIFY kingWait; }; king _ PupDefs.PupSocketMake[local: us.socket, remote: us, ticks: PupDefs.MsToTocks[500]]; DO IF pleaseStopKing THEN EXIT; b _ king.get[]; IF b # NIL THEN SetKingPacket[b]; ENDLOOP; PupDefs.PupSocketDestroy[king]; king _ NIL; SetKingPacket[NIL]; }; StartKing: PUBLIC ENTRY SAFE PROC = TRUSTED { kingUseCount _ kingUseCount + 1; IF kingUseCount > 1 THEN RETURN; IF NOT pleaseStopKing THEN RETURN; pleaseStopKing _ FALSE; kingProcess _ FORK KingDaemon[]; }; StopKing: PUBLIC SAFE PROC = TRUSTED { giveUp: BOOL _ FALSE; GetLock: ENTRY PROC = { kingUseCount _ MAX[0, kingUseCount - 1]; IF kingUseCount > 0 THEN giveUp _ TRUE; IF pleaseStopKing THEN giveUp _ TRUE; pleaseStopKing _ TRUE; }; GetLock[]; IF NOT giveUp THEN JOIN kingProcess; }; StopHimProbing: PUBLIC ENTRY SAFE PROC [h: Handle, setPointers: BOOL] = TRUSTED { replycb: CorePkt; b: PupDefs.PupBuffer _ NIL; IF h = NIL THEN RETURN; b _ PupDefs.GetFreePupBuffer[]; replycb _ LOOPHOLE[@b.pupBody]; replycb.advice _ [setPointers, FALSE, 0]; replycb.address _ 0; replycb.count _ 10; PupDefs.SetPupContentsWords[b, SIZE[CorePktObject]]; b.pupID _ NewPupID[]; b.pupType _ coreFetchRequest; KingSend[b, h.address]; }; GetEventData: PUBLIC SAFE PROC [h: Handle, setPointers: BOOL] RETURNS [event: EventRecordObject, ok: BOOL] = TRUSTED { deleteOnReturn: BOOL _ FALSE; er: EventRecord; cb: CoreBlock; IF h = NIL THEN RETURN [event: event, ok: FALSE]; cb _ NEW[CoreBlockObject[SIZE[EventRecordObject] * 2]]; cb.address _ 0DA00H; cb.advice _ [setPointers, FALSE, 0]; ok _ Fetch[h, cb, 1].ok; IF NOT ok THEN RETURN [event: event, ok: FALSE]; er _ LOOPHOLE[BASE[DESCRIPTOR[cb.data]], EventRecord]; event _ SwabEvent[er^]; RETURN [event: event, ok: TRUE]; }; <> Process.SetTimeout[condition: @kingWait, ticks: Process.MsecToTicks[500]]; END. December 30, 1981 3:14 PM, Stewart, created from AudioSocket.mesa December 22, 1982 3:17 pm, Stewart, modifications to TeleLoad April 25, 1983 11:22 am, LCS, new Event interface and locMaxByte May 28, 1983 5:47 pm, LCS, cacheSize added, in order to make alteration of running program safe! December 26, 1983 2:40 pm, LCS, patchup addresses with StripChar