-- 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