-- TeleDebImpl6.mesa -- Last modified: -- Stewart, September 7, 1982 10:41 PM DIRECTORY Inline, IntelHex6, IODefs, PupDefs USING [GetPupPackageUseCount], PupRouterDefs USING [numberOfNetworks], Storage USING [FreeString, String], StreamDefs, String, TeleLoad6, WF; TeleDebImpl6: PROGRAM IMPORTS Inline, IntelHex6, IODefs, PupDefs, PupRouterDefs, Storage, StreamDefs, String, TeleLoad6, WF = { TeleDebugData: TYPE = RECORD [ h: TeleLoad6.Handle ← NIL, iS: StreamDefs.StreamHandle ← NIL, program: TeleLoad6.CoreBlock ← NIL, programName: STRING ← NIL, larkState: TeleLoad6.State8086Object, altered: BOOLEAN ← FALSE]; z: MDSZone ← TeleLoad6.GetZone[]; tdd: POINTER TO TeleDebugData ← NIL; MaxLump: CARDINAL = 128; Failed: SIGNAL = CODE; BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED]; And: BitOp = INLINE {RETURN[Inline.BITAND[a, b]]; }; Shift: BitOp = INLINE {RETURN[Inline.BITSHIFT[a, b]]; }; myEndOf: IntelHex6.EndOfProc = {RETURN[tdd.iS.endof[tdd.iS]]; }; myGetByte: IntelHex6.GetByteProc = {RETURN[tdd.iS.get[tdd.iS]]; }; myGetPosition: IntelHex6.GetPositionProc = { RETURN[StreamDefs.GetPosition[tdd.iS]]; }; mySetPosition: IntelHex6.SetPositionProc = { StreamDefs.SetPosition[tdd.iS, p]; }; myPutC: IntelHex6.PutCharProc = {WF.WFC[c]; }; MCR: PROC = {WF.WFCR[]; }; Main: PROC = { { ENABLE ABORTED => GO TO CleanUp; c: CHARACTER; tdd ← z.NEW[TeleDebugData]; tdd↑ ← [larkState: [ALL[0]]]; WF.WF0["TeleDeb*n"]; tdd.iS ← NIL; FOR i: TeleLoad6.Registers8086 IN [AX..DX] DO tdd.larkState.Regs[i] ← 0; ENDLOOP; tdd.larkState.Regs[SP] ← 100B; tdd.altered ← FALSE; DO ENABLE { IODefs.Rubout => {WF.WF0[" !Rubout!*n"]; CONTINUE; }; String.InvalidNumber => {WF.WF0[" !InvalidNumber!*n"]; CONTINUE; }; }; NoEcho[]; WF.WF0["%% "]; c ← IODefs.ReadChar[]; WF.WF0[" "]; SELECT c FROM 'b, 'B => Blit[]; 'o, 'O => Open[]; 'c, 'C => Close[]; 'd, 'D => Fetch[]; 'g, 'G => SetState[]; 'l, 'L => Load[]; 'm, 'M => MemoryTest[]; 'p, 'P => Parse[]; 'r, 'R => AlterRegister[]; 's, 'S => Store[]; 'x, 'X => GetState[]; 'q, 'Q => EXIT; '? => Help[]; ENDCASE => WF.WF0[" type '? for Help*n"]; ENDLOOP; EXITS CleanUp => NULL; }; IF tdd.h # NIL THEN Close[]; WF.WF0["TeleDeb quitting*n"]; IF tdd.programName # NIL THEN Storage.FreeString[tdd.programName]; { x: TeleLoad6.CoreBlock; WHILE tdd.program # NIL DO x ← tdd.program; tdd.program ← tdd.program.next; z.FREE[@x]; ENDLOOP; }; z.FREE[@tdd]; }; Echo: PROC = {NULL; }; NoEcho: PROC = {NULL; }; Help: PROC = { WF.WF0["BLT "]; WF.WF0["Close "]; WF.WF0["Display "]; WF.WF0["G(store state and go) "]; WF.WF0["Load "]; WF.WF0["MemoryTest "]; WF.WF0["Open "]; WF.WF0["Parse "]; WF.WF0["Register (Change register) "]; WF.WF0["Store "]; WF.WF0["Quit "]; WF.WF0["X(fetch state) "]; WF.WF0["*n"]; }; Open: PROC = { host: STRING ← [50]; IF tdd.h # NIL THEN {WF.WF0["Please close connection first.*n"]; RETURN; }; Echo[]; WF.WF0["Open connection with: "]; String.AppendString[to: host, from: "Skylark"]; IODefs.ReadID[host]; MCR[]; tdd.h ← TeleLoad6.Start[host]; IF tdd.h = NIL THEN WF.WF0[" . . . returns NIL*n"]; }; Close: PROC = { IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; WF.WF0["Close connection.*n"]; TeleLoad6.Stop[tdd.h]; tdd.h ← NIL; }; Blit: PROC = { cb: TeleLoad6.CoreBlock; source, destination, highAddr: TeleLoad6.CoreAddress; count: CARDINAL; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; WF.WF0["BLT from (hex) "]; source ← GetHex[16]; WF.WF0[" to (hex) "]; destination ← GetHex[16]; WF.WF0[" count (hex) "]; count ← Inline.LowHalf[GetHex[16]]; cb ← z.NEW[TeleLoad6 .CoreBlockObject[MaxLump]]; highAddr ← source + count - 1; DO IF source + MaxLump > highAddr THEN { count ← Inline.LowHalf[highAddr - source]; z.FREE[@cb]; cb ← z.NEW[TeleLoad6 .CoreBlockObject[count]]; } ELSE count ← MaxLump; --Fetch old contents cb.address ← source; IF NOT TeleLoad6.Fetch[tdd.h, cb].success THEN { MCR[]; WF.WF2["cannot fetch %u bytes from address %04lx*n", count, @source]; EXIT; }; -- Store old contents cb.address ← destination; IF NOT TeleLoad6.Store[tdd.h, cb].success THEN { MCR[]; WF.WF2["cannot restore %u bytes at address %04lx*n", count, @destination]; EXIT; }; WF.WFC['.]; destination ← destination + MaxLump; source ← source + MaxLump; IF source > highAddr THEN EXIT; ENDLOOP; z.FREE[@cb]; MCR[]; }; Fetch: PROC = { cb: TeleLoad6.CoreBlock; offset: CARDINAL; maddr, addr: TeleLoad6.CoreAddress; count: CARDINAL; res: TeleLoad6.Result; WF.WF0["Display data, "]; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; Echo[]; WF.WF0[" address (hex): "]; addr ← GetHex[16]; WF.WF0[" count (decimal): "]; count ← Inline.LowHalf[GetHex[10]]; WF.WF1[" (= %xH)*n", count]; cb ← z.NEW[TeleLoad6 .CoreBlockObject[count]]; cb.address ← addr; res ← TeleLoad6.Fetch[tdd.h, cb]; IF NOT res.success THEN {WF.WF0[" ... failed*n"]; RETURN; }; maddr ← addr - (addr MOD 16); -- round down to nearest multiple of 16 count ← count + Inline.LowHalf[addr - maddr]; offset ← 0; FOR i: CARDINAL IN [0..count) DO IF (i MOD 16) = 0 THEN WF.WF1[IF maddr > LAST[CARDINAL] THEN " %08lx" ELSE " %04lx", @maddr]; IF maddr < addr THEN {WF.WF0[" "]; offset ← offset + 1; } ELSE WF.WF1[" %02x", cb.data[i - offset]]; maddr ← maddr + 1; IF (i MOD 16) = 15 THEN WF.WFCR[]; REPEAT FINISHED => IF (i MOD 16) # 7 THEN WF.WFCR[]; ENDLOOP; z.FREE[@cb]; }; Store: PROC = { addr: TeleLoad6.CoreAddress; count: CARDINAL; val: CARDINAL; cb: TeleLoad6.CoreBlock; res: TeleLoad6.Result; WF.WF0["Store data,"]; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; Echo[]; WF.WF0[" address (hex): "]; addr ← GetHex[16]; WF.WF0[" count (decimal): "]; count ← Inline.LowHalf[GetHex[16]]; WF.WF1[" (= %04xH)*n", count]; cb ← z.NEW[TeleLoad6 .CoreBlockObject[count]]; cb.address ← addr; WF.WF1["enter %u hex bytes, >FF to abort.*n", count]; FOR i: CARDINAL IN [0..count) DO val ← Inline.LowHalf[GetHex[16]]; IF val > 377B THEN {WF.WF0[" XXX*n"]; z.FREE[@cb]; RETURN; }; cb.data[i] ← Inline.LowByte[val]; IF i MOD 8 = 7 THEN WF.WF0["*n"]; ENDLOOP; MCR[]; res ← TeleLoad6.Store[tdd.h, cb]; IF NOT res.success THEN WF.WF0[" ... failed*n"]; MCR[]; z.FREE[@cb]; }; GetHex: PROC [radix: CARDINAL] RETURNS [LONG CARDINAL] = { r: STRING ← [100]; IODefs.ReadID[r]; RETURN[String.StringToLongNumber[r, radix]]; }; Parse: PROC = { myIStream: IntelHex6.IStream ← [ endof: myEndOf, get: myGetByte, GetPosition: myGetPosition, SetPosition: mySetPosition]; myOStream: IntelHex6.OStream ← [ PutEndRecord: myPutEndRecord, PutStartRecord: myPutStartRecord, DataByte: myDataByte]; -- Write an end record. myPutEndRecord: IntelHex6.PutEndRecordProc = { DataFlush[]; MCR[]; WF.WF0["...End*n"]; }; -- Write a start record. myPutStartRecord: IntelHex6.PutStartRecordProc = { DataFlush[]; MCR[]; WF.WF2["Start at %04x:%04x*n", frame, bytepos]; tdd.larkState[CS] ← frame; tdd.larkState[IP] ← bytepos; tdd.altered ← TRUE; }; myDataByte: IntelHex6.DataByteProc = { IF gnaflag OR adr # gda THEN DataFlush[]; gdata[gptr] ← d; IF gptr = 0 THEN fda ← adr; gptr ← gptr + 1; gda ← adr + 1; IF gptr >= TeleLoad6.MaxByte THEN DataFlush[]; }; DataFlush: PROC = { cb: TeleLoad6.CoreBlock; IF gptr = 0 THEN RETURN; gnaflag ← FALSE; cb ← z.NEW[TeleLoad6 .CoreBlockObject[gptr]]; IF cb = NIL THEN SIGNAL Failed; cb.address ← fda; FOR i: CARDINAL IN [0..gptr) DO cb.data[i] ← gdata[i]; ENDLOOP; gptr ← 0; cb.next ← tdd.program; tdd.program ← cb; WF.WFC['!]; }; gda: LONG CARDINAL ← LAST[LONG CARDINAL]; fda: LONG CARDINAL; gptr: CARDINAL ← 0; gdata: PACKED ARRAY [0..TeleLoad6.MaxByte) OF TeleLoad6.Byte; gnaflag: BOOLEAN ← TRUE; iName: STRING ← Storage.String[50]; x: TeleLoad6.CoreBlock; -- code for Load starts here IF tdd.programName # NIL THEN { String.AppendString[to: iName, from: tdd.programName]; Storage.FreeString[tdd.programName]; }; WHILE tdd.program # NIL DO x ← tdd.program; tdd.program ← tdd.program.next; z.FREE[@x]; ENDLOOP; Echo[]; WF.WF0["Name of .obj file: "]; IODefs.ReadID[iName]; FOR i: CARDINAL IN [0..iName.length) DO IF iName[i] = '. THEN EXIT; REPEAT FINISHED => String.AppendString[to: iName, from: ".obj"]; ENDLOOP; MCR[]; IF iName = NIL THEN {WF.WF0["Bad file name*n"]; RETURN; }; tdd.programName ← iName; tdd.iS ← StreamDefs.NewByteStream[ name: iName, access: StreamDefs.Read ! StreamDefs.FileNameError => { tdd.iS ← NIL; WF.WF0[" ... file not found*n"]; CONTINUE; }]; IF tdd.iS = NIL THEN RETURN; FOR i: TeleLoad6.Registers8086 IN [AX..FL] DO tdd.larkState.Regs[i] ← 0; ENDLOOP; tdd.larkState.Regs[SP] ← 100B; tdd.altered ← TRUE; IF NOT IntelHex6.ProcessFile[ in: myIStream, out: myOStream, errs: myPutC ! Failed => {MCR[]; WF.WF0[" ...TeleLoad Error*n"]; CONTINUE; }] THEN { MCR[]; WF.WF0[" ...IntelHex Failure*n"]; }; tdd.iS.destroy[tdd.iS]; tdd.iS ← NIL; }; Load: PROC = { a: TeleLoad6.CoreBlock; res: TeleLoad6.Result; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; IF tdd.program = NIL THEN Parse[]; WF.WF1["Loading %s: ", tdd.programName]; a ← tdd.program; WHILE a # NIL DO res ← TeleLoad6.Store[tdd.h, a]; IF res.attempts = 1 THEN WF.WFC['!] ELSE WF.WF1["%1d",res.attempts]; IF NOT res.success THEN {MCR[]; WF.WF0["Teleload Error*n"]; EXIT; }; a ← a.next; ENDLOOP; MCR[]; }; MemoryTest: PROC = { saved, cb: TeleLoad6.CoreBlock; lowAddr, highAddr, addr: TeleLoad6.CoreAddress; count: CARDINAL; TestLump: PROC [testValue: CARDINAL] RETURNS [BOOLEAN] = { cb.address ← addr; FOR i: CARDINAL IN [0..count) DO cb.data[i] ← testValue; ENDLOOP; IF NOT TeleLoad6.Store[tdd.h, cb].success THEN { IF NOT TeleLoad6.Fetch[tdd.h, cb].success THEN WF.WF0["contact lost*n"]; FOR i: CARDINAL IN [0..count) DO IF cb.data[i] # testValue THEN { ta: TeleLoad6.CoreAddress ← addr + i; WF.WF3[ "loc %4lx is %02x, should be %02x*n", @ta, cb.data[i], testValue]; EXIT; }; ENDLOOP; WF.WF3[ "test of %d bytes of %02x at address %04lx failed*n", count, testValue, @addr]; RETURN[FALSE]; }; RETURN[TRUE]; }; WF.WF0["Memory Test, "]; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; Echo[]; WF.WF0[" low address (hex): "]; lowAddr ← GetHex[16]; WF.WF0[" high address (hex): "]; highAddr ← GetHex[16]; saved ← z.NEW[TeleLoad6 .CoreBlockObject[MaxLump]]; cb ← z.NEW[TeleLoad6 .CoreBlockObject[MaxLump]]; addr ← lowAddr; DO IF addr + MaxLump > highAddr THEN { count ← Inline.LowHalf[highAddr - addr]; z.FREE[@saved]; z.FREE[@cb]; cb ← z.NEW[TeleLoad6.CoreBlockObject[count]]; saved ← z.NEW[TeleLoad6.CoreBlockObject[count]]; } ELSE count ← MaxLump; --Fetch old contents saved.address ← addr; IF NOT TeleLoad6.Fetch[tdd.h, saved].success THEN { WF.WF2["cannot fetch %d bytes from address %04lx*n", count, @addr]; EXIT; }; IF NOT TestLump[0377B] THEN EXIT; IF NOT TestLump[0B] THEN EXIT; IF NOT TestLump[0252B] THEN EXIT; IF NOT TestLump[0125B] THEN EXIT; -- Store old contents IF NOT TeleLoad6.Store[tdd.h, saved].success THEN { WF.WF2["cannot restore %d bytes at address %04lx*n", count, @addr]; EXIT; }; addr ← addr + MaxLump; IF addr > highAddr THEN EXIT; ENDLOOP; z.FREE[@saved]; z.FREE[@cb]; MCR[]; }; RegNames: ARRAY TeleLoad6.Registers8086 OF STRING = [ "AX", "BX", "CX", "DX", "SP", "BP", "SI", "DI", "CS", "DS", "SS", "ES", "IP", "FL"]; GetState: PROC = { cb: TeleLoad6.CoreBlock; ok: BOOLEAN; pp: TeleLoad6.State8086; size: CARDINAL = SIZE[TeleLoad6.State8086Object]*2; WF.WF0["GetState*n"]; IF NOT tdd.altered THEN { IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; cb ← z.NEW[TeleLoad6 .CoreBlockObject[size]]; cb.address ← 1; ok ← TeleLoad6.FetchState[tdd.h, cb].success; IF NOT ok THEN {WF.WF0[" ... failed*n"]; z.FREE[@cb]; RETURN; }; pp ← LOOPHOLE[@cb.data, TeleLoad6.State8086]; FOR i: TeleLoad6.Registers8086 IN [AX..FL] DO pp.Regs[i] ← Swab[pp.Regs[i]]; ENDLOOP; tdd.larkState ← pp↑; pp ← NIL; }; FOR i: TeleLoad6.Registers8086 IN [AX..SI] DO PutReg[i, tdd.larkState.Regs[i]]; ENDLOOP; WF.WFCR[]; FOR i: TeleLoad6.Registers8086 IN [DI..FL] DO PutReg[i, tdd.larkState.Regs[i]]; ENDLOOP; WF.WFCR[]; z.FREE[@cb]; }; SetState: PROC = { cb: TeleLoad6.CoreBlock; ok: BOOLEAN; pp: TeleLoad6.State8086; size: CARDINAL = SIZE[TeleLoad6.State8086Object]*2; WF.WF0["GO!*n"]; IF tdd.h = NIL THEN {WF.WF0["Connection not open*n"]; RETURN; }; cb ← z.NEW[TeleLoad6 .CoreBlockObject[size]]; cb.address ← 1; pp ← LOOPHOLE[BASE[DESCRIPTOR[cb.data]], TeleLoad6.State8086]; pp↑ ← tdd.larkState; FOR i: TeleLoad6.Registers8086 IN [AX..FL] DO pp.Regs[i] ← Swab[pp.Regs[i]]; ENDLOOP; pp ← NIL; ok ← TeleLoad6.StoreState[tdd.h, cb].success; IF NOT ok THEN WF.WF0[" ... failed*n"]; z.FREE[@cb]; }; PutReg: PROC [i: TeleLoad6.Registers8086, v: CARDINAL] = { WF.WF2[" %2s=%04x", RegNames[i], v]; }; AlterRegister: PROC = { i: TeleLoad6.Registers8086; r: STRING ← [50]; Echo[]; WF.WF0["Change register: "]; IODefs.ReadID[r]; SELECT TRUE FROM String.EquivalentString[s1: r, s2: "0"] => { FOR i: TeleLoad6.Registers8086 IN [AX..FL] DO tdd.larkState.Regs[i] ← 0; ENDLOOP; tdd.larkState.Regs[SP] ← 100B; tdd.altered ← TRUE; RETURN; }; String.EquivalentString[s1: r, s2: "r"] => {tdd.altered ← FALSE; RETURN; }; ENDCASE; FOR i IN TeleLoad6.Registers8086 DO IF String.EquivalentString[s1: r, s2: RegNames[i]] THEN EXIT; REPEAT FINISHED => { WF.WF0[ " ... unknown register*nRegisters are 0 (clear), r (reset), plus 8086 registers.*n"]; RETURN; }; ENDLOOP; WF.WF1[" value for register %s (hex): ", RegNames[i]]; tdd.larkState[i] ← Inline.LowHalf[GetHex[16]]; WF.WF2[" new value %s: %04x*n", RegNames[i], tdd.larkState[i]]; tdd.altered ← TRUE; }; Swab: PROC [a: CARDINAL] RETURNS [b: CARDINAL] = { b ← Inline.BITSHIFT[Inline.LowByte[a], 8] + Inline.HighByte[a]; }; -- Main program [] ← PupDefs.GetPupPackageUseCount[]; PupRouterDefs.numberOfNetworks ← 255; Main[]; }. July 27, 1982 5:54 PM, L. Stewart, MDSZone September 7, 1982 10:41 PM, L. Stewart, added attempt counters