hosts: PUBLIC LIST OF TeleDebOps.TeleDebugData;
Junk: SIGNAL = CODE;
duplicate copies
BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED];
And: BitOp = INLINE { RETURN[Inline.BITAND[a,b]]; };
Shift: BitOp = INLINE { RETURN[Inline.BITSHIFT[a,b]]; };
IsASPorCR: IO.DeliverWhenProc = TRUSTED { RETURN [char=' OR char = '\n]; };
Main:
PROC [hostName: Rope.
ROPE] = {
{
ENABLE ABORTED => GO TO CleanUp;
c: CHAR;
tdd: TeleDebOps.TeleDebugData ← CreateWindow[];
eventsStream ← tdd.out;
TeleLoad.StartEventServer[NoteEvents];
IF hostName #
NIL
THEN {
tdd.out.PutF["Opening connection with %g\n", IO.rope[hostName]];
tdd ← SetupHost[tdd, hostName];
TeleDebOps.SetHostByRef[tdd];
};
WHILE tdd.h =
NIL
DO
tdd ← OpenConnection[tdd];
ENDLOOP;
DO
ENABLE {
IO.Error => {
tdd.out.PutF[" !IO.Error!\n" ! ANY => CONTINUE];
CONTINUE;
};
IO.Signal, Junk =>
TRUSTED {
tdd.out.PutF[" !IO.Signal!\n" ! ANY => CONTINUE];
CONTINUE;
};
Failed => CONTINUE;
};
NoEcho[tdd];
tdd.out.PutF["%% "];
c ← tdd.in.GetChar[];
tdd.out.PutF[" "];
SELECT c
FROM
'a => AlterVariable[tdd];
'A => AlterVariablesFromFile[tdd];
'b, 'B => Blit[tdd];
'c, 'C => SetCurrentProgram[tdd];
'd => Fetch[tdd, TRUE];
'D => Fetch[tdd, FALSE];
'g => Go[tdd, FALSE];
'G => Go[tdd, TRUE];
'h => GoFromBreak[tdd, FALSE];
'H => GoFromBreak[tdd, TRUE];
'l => Load[tdd, TRUE];
'L => Load[tdd, FALSE];
'm, 'M => MemoryTest[tdd];
'n => SingleStep[tdd, FALSE];
'N => SingleStep[tdd, TRUE];
'o, 'O => tdd ← OpenConnection[tdd];
'p => Parse[tdd];
'P => Patch[tdd];
'r, 'R => AlterRegister[tdd];
's, 'S => Store[tdd];
'v, 'V => Verify[tdd];
'x => GetState[tdd, FALSE];
'X => GetState[tdd, TRUE];
'y, 'Y => YankVariable[tdd];
'z, 'Z => GoToDebugger[tdd, TRUE];
'. => ResetCache[tdd];
'? => Help[tdd];
' => InteractiveDebug[tdd];
ENDCASE => tdd.out.PutF[" type '? for Help\n"];
tdd.out.Flush[];
ENDLOOP;
EXITS CleanUp => NULL;
};
};
OpenConnection:
PROC [old: TeleDebOps.TeleDebugData]
RETURNS [new: TeleDebOps.TeleDebugData] = {
newHostName: Rope.ROPE;
Echo[old];
old.out.PutF["Open connection with: "];
newHostName ← old.edit.GetToken[];
TeleDebOps.MCR[old.out];
new ← SetupHost[old, newHostName];
TeleDebOps.SetHostByRef[new];
};
EnumerateHosts:
PROC [ep:
PROC [TeleDebOps.TeleDebugData]
RETURNS [continue:
BOOL]] = {
FOR hl:
LIST
OF TeleDebOps.TeleDebugData ← hosts, hl.rest
WHILE hl #
NIL
DO
IF NOT ep[hl.first] THEN EXIT;
ENDLOOP;
};
FindByNameOrAddress:
PUBLIC
PROC [hostName: Rope.
ROPE]
RETURNS [htd: TeleDebOps.TeleDebugData] = {
pa: PupTypes.PupAddress;
ok: BOOL;
NameEP:
PROC [td: TeleDebOps.TeleDebugData]
RETURNS [continue:
BOOL] = {
IF Rope.Equal[hostName, td.h.host,
FALSE]
OR pa = td.h.address
THEN {
htd ← td;
RETURN [FALSE];
};
RETURN [TRUE];
};
[pa, ok] ← TeleLoad.NameToAddress[hostName];
IF ok THEN hostName ← TeleLoad.AddressToName[pa].nameRope;
htd ← NIL;
EnumerateHosts[NameEP];
};
FindByAddress:
PROC [who: PupTypes.PupAddress]
RETURNS [htd: TeleDebOps.TeleDebugData] = {
AddressEP:
PROC [td: TeleDebOps.TeleDebugData]
RETURNS [continue:
BOOL] = {
IF who = td.h.address
THEN {
htd ← td;
RETURN [FALSE];
};
RETURN [TRUE];
};
htd ← NIL;
EnumerateHosts[AddressEP];
};
CreateWindow:
PROC
RETURNS [tdd: TeleDebOps.TeleDebugData] = {
tdd ← NEW[TeleDebugDataObject];
[tdd.in, tdd.out] ← ViewerIO.CreateViewerStreams[name: "TeleDeb", editedStream: FALSE];
tdd.edit ← IO.CreateEditedStream[in: tdd.in, echoTo: tdd.out, deliverWhen: IsASPorCR];
tdd.origecho ← tdd.in.SetEcho[NIL];
TypeScript.ChangeLooks[ViewerIO.GetViewerFromStream[tdd.out], 'f];
tdd.out.PutF["TeleDeb of %t running at %t\n", IO.time[Runtime.GetBcdTime[]], IO.time[]];
};
SetupHost:
PROC [old: TeleDebOps.TeleDebugData, hostName: Rope.
ROPE]
RETURNS [tdd: TeleDebOps.TeleDebugData] = {
nameRope, addressRope: Rope.ROPE;
pa: PupTypes.PupAddress;
ok: BOOL;
check to see if there is one already
tdd ← FindByNameOrAddress[hostName];
IF tdd =
NIL
THEN {
IF old.h # NIL THEN tdd ← NEW[TeleDebugDataObject]
ELSE tdd ← old;
[pa, ok] ← TeleLoad.NameToAddress[hostName];
IF ok
THEN {
[nameRope: nameRope, addressRope: addressRope] ← TeleLoad.AddressToName[pa];
tdd.in ← old.in;
tdd.out ← old.out;
tdd.edit ← old.edit;
tdd.origecho ← old.origecho;
tdd.h ← TeleLoad.Start[hostName];
IF tdd.h =
NIL
THEN {
tdd.out.PutF[" . . . returns NIL.\n"];
tdd ← old;
}
ELSE {
tdd.out.PutChar['\n];
hosts ← CONS[tdd, hosts];
};
}
ELSE {
old.out.PutF[" . . . returns NIL.\n"];
tdd ← old;
};
};
IF tdd.h #
NIL
THEN {
[nameRope: nameRope, addressRope: addressRope] ← TeleLoad.AddressToName[tdd.h.address];
ViewerIO.GetViewerFromStream[tdd.out].name ← Rope.Cat["TeleDeb ", nameRope, " [", addressRope, "]"];
ViewerOps.PaintViewer[ViewerIO.GetViewerFromStream[tdd.out], caption];
};
};
eventsStream: IO.STREAM;
NoteEvents:
PROC [who: PupTypes.PupAddress, cb: TeleLoad.EventRecordObject] =
TRUSTED {
hostRope: Rope.ROPE;
addressRope: Rope.ROPE;
longClock: LONG CARDINAL;
[nameRope: hostRope, addressRope: addressRope] ← TeleLoad.AddressToName[who];
eventsStream.PutF["\nEvent from %g (%g): %04xH\n", IO.rope[hostRope], IO.rope[addressRope], IO.card[TeleDebOps.Swab[cb.reason]]];
longClock ← TeleDebOps.Swab[cb.clockHigh];
longClock ← longClock * 65536;
longClock ← longClock + TeleDebOps.Swab[cb.clockLow];
eventsStream.PutF["clock %08x, switches: %04xH, advice: %04xH\n", IO.card[longClock], IO.card[TeleDebOps.Swab[cb.bootSwitches]], IO.card[TeleDebOps.Swab[cb.advice]]];
DisplayState[s: eventsStream, state: SwabState[cb.regs]];
eventsStream.PutF["%% "];
};
Echo: PROC [tdd: TeleDebOps.TeleDebugData] = { [] ← tdd.in.SetEcho[tdd.origecho]; };
NoEcho: PROC [tdd: TeleDebOps.TeleDebugData] = { [] ← tdd.in.SetEcho[NIL]; };
Help:
PROC [tdd: TeleDebOps.TeleDebugData] = {
tdd.out.PutRope["a(lter variable), "];
tdd.out.PutRope["A(lter variables from file) "];
tdd.out.PutRope["BLT, "];
tdd.out.PutRope["C(urrent Program) "];
tdd.out.PutRope["d(isplay words), D(isplay bytes), "];
tdd.out.PutRope["g(store state and go) "];
tdd.out.PutRope["G(fetch state then go) "];
tdd.out.PutRope["h(store state and go from break) "];
tdd.out.PutRope["H(fetch state then go from break) "];
tdd.out.PutRope["l(oad) "];
tdd.out.PutRope["L(oad without first Zap) "];
tdd.out.PutRope["M(emoryTest) "];
tdd.out.PutRope["n(store state and single step) "];
tdd.out.PutRope["N(fetch state then single step) "];
tdd.out.PutRope["O(pen Connection) "];
tdd.out.PutRope["p(arse Program) "];
tdd.out.PutRope["p(atch Program) "];
tdd.out.PutRope["Register (Change register) "];
tdd.out.PutRope["S(tore) "];
tdd.out.PutRope["Q(uit) "];
tdd.out.PutRope["V(erify) "];
tdd.out.PutRope["x(display state) "];
tdd.out.PutRope["X(fetch state and set debug pointers) "];
tdd.out.PutRope["y(ank {print variable}) "];
tdd.out.PutRope["Z(ap { go to debugger }) "];
tdd.out.PutRope[".(reset Display cache) "];
tdd.out.PutRope["SP(ace: enter Swat mode) "];
tdd.out.PutRope["\n"];
};
Blit:
PROC [tdd: TeleDebOps.TeleDebugData] = {
source, destination: TeleLoad.CoreAddress;
count: LONG CARDINAL;
tdd.out.PutF["BLT from (hex) "];
source ← GetHex[tdd.edit];
tdd.out.PutF[" to (hex) "];
destination ← GetHex[tdd.edit];
tdd.out.PutF[" count (hex) "];
count ← GetHex[tdd.edit];
BlitInternal[tdd: tdd, source: source, destination: destination, count: count];
};
BlitInternal:
PROC [tdd: TeleDebOps.TeleDebugData, source, destination: TeleLoad.CoreAddress, count:
LONG
CARDINAL] = {
cb: TeleLoad.CoreBlock;
highAddr: TeleLoad.CoreAddress;
cb ← NEW[TeleLoad.CoreBlockObject[locMaxByte]];
highAddr ← source+count-1;
DO
IF source+locMaxByte > highAddr
THEN {
count ← highAddr-source;
cb ← NEW[TeleLoad.CoreBlockObject[count]];
}
ELSE count ← locMaxByte;
Fetch old contents
cb.address ← source;
cb.advice ← [FALSE, FALSE, 0];
IF
NOT TeleLoad.Fetch[tdd.h, cb].ok
THEN {
MCR[tdd.out];
tdd.out.PutF["cannot fetch %d bytes from address %04xH\r", IO.card[count], IO.card[source]];
EXIT;
};
Store old contents
cb.address ← destination;
cb.advice ← [FALSE, FALSE, 0];
IF
NOT TeleLoad.Store[tdd.h, cb].ok
THEN {
MCR[tdd.out];
tdd.out.PutF["cannot restore %d bytes at address %04xH\r", IO.card[count], IO.card[destination]];
EXIT;
};
tdd.out.PutChar['.];
destination ← destination + locMaxByte;
source ← source + locMaxByte;
IF source > highAddr THEN EXIT;
ENDLOOP;
MCR[tdd.out];
};
Fetch:
PROC [tdd: TeleDebOps.TeleDebugData, words:
BOOL] = {
addr: TeleLoad.CoreAddress;
count: CARDINAL ← 0;
tdd.out.PutF["Dump "];
Echo[tdd];
tdd.out.PutF["(hex address) "];
addr ← GetHex[tdd.edit];
IF tdd.edit.GetChar[] #'\n
THEN {
tdd.out.PutF[" (decimal count): "];
count ← Inline.LowHalf[tdd.edit.GetInt[]];
tdd.out.PutF[" (= %xH)\n", IO.card[count]];
};
Show[tdd, addr, count, words];
};
Store:
PROC [tdd: TeleDebOps.TeleDebugData] = {
ENABLE TeleDebOps.Failed => GOTO Quit;
addr: TeleLoad.CoreAddress;
val: CARDINAL;
tdd.out.PutF["Store data,"];
Echo[tdd];
tdd.out.PutF[" address (hex): "];
addr ← GetHex[tdd.edit];
tdd.out.PutF[" end with >FF"];
DO
ENABLE {
IO.Error => CONTINUE;
};
tdd.out.PutF["\n%04xH: ", IO.card[addr]];
val ← Inline.LowHalf[GetHex[tdd.edit]];
IF val > 377B THEN EXIT;
Write[tdd, addr, val];
addr ← addr + 1;
ENDLOOP;
FlushWrites[tdd];
MCR[tdd.out];
EXITS
Quit => NULL;
};
Show:
PUBLIC
PROC[host: TeleDebOps.TeleDebugData, addr: TeleLoad.CoreAddress, count:
CARDINAL, words:
BOOL ←
FALSE] = {
chars: STRING ← [16];
val, wval: CARDINAL;
{
ENABLE TeleDebOps.Failed => CONTINUE;
always get the newest data
TeleDebOps.FlushWrites[host: host];
TeleDebOps.ResetCache[host: host];
chars.length ← 16;
IF count = 0 THEN count ← 64
ELSE count ← count + (addr MOD 16);
addr ← addr - (addr MOD 16); -- round down to nearest multiple of 16
IF (count MOD 16) # 0 THEN count ← count + 16 - (count MOD 16); -- and round up
FOR i:
CARDINAL
IN [0..count)
DO
IF (i
MOD 16) = 0
THEN
host.out.PutF[IF addr + i > LAST[CARDINAL] THEN " %08x" ELSE " %04xH", IO.card[addr + i]];
IF words
THEN {
IF (i
MOD 2) = 0
THEN {
val ← TeleDebOps.Read[host, addr+i];
chars[i MOD 16] ← IF val IN [40B..176B] THEN LOOPHOLE[val] ELSE '.;
wval ← val;
val ← TeleDebOps.Read[host, addr+i+1];
chars[(i + 1) MOD 16] ← IF val IN [40B..176B] THEN LOOPHOLE[val] ELSE '.;
wval ← wval + Shift[val, 8];
host.out.PutF[" %04xH", IO.card[wval]];
};
}
ELSE {
val ← TeleDebOps.Read[host, addr+i];
host.out.PutF[" %02x", IO.card[val]];
chars[i MOD 16] ← IF val IN [40B..176B] THEN LOOPHOLE[val] ELSE '.;
};
IF (i
MOD 16) = 15
THEN {
host.out.PutF[" "];
FOR j: NAT IN [0..16) DO host.out.PutChar[chars[j]]; ENDLOOP;
host.out.PutChar['\n];
};
ENDLOOP;
};
};
GetHex:
PUBLIC
PROC [h:
IO.Handle]
RETURNS [
LONG
CARDINAL] = {
r: Rope.ROPE ← h.GetToken[];
v: Convert.Value ← Convert.Parse[text: [rope[r]], template: [unsigned[base: 16]]].value;
RETURN[NARROW[v, Convert.Value[unsigned]! ANY => SIGNAL Junk].unsigned];
};
Parse:
PROC [tdd: TeleDebOps.TeleDebugData] = {
iName: Rope.ROPE;
code for Load starts here
Echo[tdd];
tdd.out.PutF["Parse, Name of .obj file: "];
iName ← tdd.edit.GetToken[];
TeleDebOps.MCR[tdd.out];
tdd.program ← TeleDebOps.ReadProgramFromDisk[iName, tdd.out];
TeleDebOps.ResetPatchList[tdd.program];
TeleDebOps.MCR[tdd.out];
TeleDebOps.AddOrReplaceProgram[tdd.program];
};
Patch:
PROC [tdd: TeleDebOps.TeleDebugData] = {
progName: Rope.ROPE;
prog: TeleDebOps.Program;
pfName: Rope.ROPE;
pl: LIST OF TeleDebOps.PatchItem;
Echo[tdd];
tdd.out.PutF["Program Name: "];
progName ← tdd.edit.GetToken[];
TeleDebOps.MCR[tdd.out];
prog ← TeleDebOps.FetchProgram[progName];
IF prog =
NIL
THEN {
tdd.out.PutF[" %g not found\n", IO.rope[progName]];
RETURN;
};
tdd.out.PutF["Patch File Name: "];
pfName ← tdd.edit.GetToken[];
TeleDebOps.MCR[tdd.out];
pl ← TeleDebOps.PatchFromFile[host: tdd, fileName: pfName];
WHILE pl #
NIL
DO
TeleDebOps.PatchProgramWord[program: prog, address: pl.first.address, wordValue: pl.first.wordValue];
pl ← pl.rest;
ENDLOOP;
};
SetCurrentProgram:
PROC [tdd: TeleDebOps.TeleDebugData] = {
iName: Rope.ROPE;
Echo[tdd];
tdd.out.PutF["Set current .obj file: "];
iName ← tdd.edit.GetToken[];
TeleDebOps.MCR[tdd.out];
tdd.program ← TeleDebOps.FetchProgram[iName];
IF tdd.program =
NIL
THEN {
tdd.program ← TeleDebOps.ReadProgramFromDisk[iName, tdd.out];
TeleDebOps.ResetPatchList[tdd.program];
IF tdd.program # NIL THEN TeleDebOps.AddOrReplaceProgram[tdd.program];
};
};
Load:
PROC [tdd: TeleDebOps.TeleDebugData, zap:
BOOL] = {
TeleDebOps.MCR[tdd.out];
tdd.out.PutF["Load\n"];
IF zap THEN GoToDebugger[tdd, FALSE];
IF tdd.program = NIL THEN SetCurrentProgram[tdd];
tdd.larkState ← tdd.program.startState;
TeleDebOps.LoadProgram[host: tdd, program: tdd.program, log: tdd.out];
TeleDebOps.MCR[tdd.out];
};
check to see if the program is correct
Verify:
PROC [tdd: TeleDebOps.TeleDebugData] = {
IF tdd.program =
NIL
THEN {
tdd.out.PutF["Program not parsed.\n"];
RETURN;
};
TeleDebOps.VerifyProgram[host: tdd, program: tdd.program, log: tdd.out];
};
MemoryTest:
PROC [tdd: TeleDebOps.TeleDebugData] = {
saved, cb: TeleLoad.CoreBlock;
lowAddr, highAddr, addr: TeleLoad.CoreAddress;
count: CARDINAL;
TestLump:
PROC [testValue:
CARDINAL]
RETURNS [
BOOL] = {
cb.address ← addr;
cb.advice ← [FALSE, FALSE, 0];
FOR i: CARDINAL IN [0..count) DO cb.data[i] ← testValue; ENDLOOP;
IF
NOT TeleLoad.Store[tdd.h, cb].ok
THEN {
cb.advice ← [FALSE, FALSE, 0];
IF NOT TeleLoad.Fetch[tdd.h, cb].ok THEN tdd.out.PutF["contact lost\r"];
FOR i:
CARDINAL
IN [0..count)
DO
IF cb.data[i] # testValue
THEN {
tdd.out.PutF["loc %4x is %02x, should be %02x\r", IO.card[addr+i], IO.card[cb.data[i]], IO.card[testValue]];
EXIT;
};
ENDLOOP;
tdd.out.PutF["test of %d bytes of %02x at address %04xH failed\r", IO.card[count], IO.card[testValue], IO.card[addr]];
RETURN [FALSE];
};
RETURN[TRUE];
};
tdd.out.PutF["Memory Test, "];
IF tdd.h =
NIL
THEN {
tdd.out.PutF["Connection not open\n"];
RETURN;
};
Echo[tdd];
tdd.out.PutF[" low address (hex): "];
lowAddr ← GetHex[tdd.edit];
tdd.out.PutF[" high address (hex): "];
highAddr ← GetHex[tdd.edit];
saved ← NEW[TeleLoad.CoreBlockObject[locMaxByte]];
cb ← NEW[TeleLoad.CoreBlockObject[locMaxByte]];
addr ← lowAddr;
DO
IF addr+locMaxByte > highAddr
THEN {
count ← Inline.LowHalf[highAddr-addr];
cb ← NEW[TeleLoad.CoreBlockObject[count]];
saved ← NEW[TeleLoad.CoreBlockObject[count]];
}
ELSE count ← locMaxByte;
Fetch old contents
saved.address ← addr;
saved.advice ← [FALSE, FALSE, 0];
IF
NOT TeleLoad.Fetch[tdd.h, saved].ok
THEN {
tdd.out.PutF["cannot fetch %d bytes from address %04xH\r", IO.card[count], IO.card[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
saved.advice ← [FALSE, FALSE, 0];
IF
NOT TeleLoad.Store[tdd.h, saved].ok
THEN {
tdd.out.PutF["cannot restore %d bytes at address %04xH\r", IO.card[count], IO.card[addr]];
EXIT;
};
addr ← addr + locMaxByte;
IF addr > highAddr THEN EXIT;
ENDLOOP;
};
myFork: UserExec.CommandProc =
TRUSTED {
argv: UECP.Argv ← UECP.Parse[commands: event.commandLine];
hostName: Rope.ROPE ← IF argv.argc > 1 THEN argv[1] ELSE NIL;
Process.Detach[FORK Main[hostName]];
};
RegNames:
ARRAY TeleLoad.Registers8086
OF Rope.
ROPE = [
"AX", "BX", "CX", "DX", "SP", "BP", "SI", "DI", "CS", "DS", "SS", "ES", "IP", "FL"];
GetState:
PROC[tdd: TeleDebOps.TeleDebugData, forceGet:
BOOLEAN ←
FALSE] = {
tdd.out.PutF["State "];
IF forceGet THEN FetchState[tdd, [TRUE, TRUE, 1234]];
tdd.out.PutChar['\n];
DisplayState[s: tdd.out, state: tdd.larkState];
};
DisplayState:
PROC[s:
IO.
STREAM, state: TeleLoad.State8086Object] = {
FOR i: TeleLoad.Registers8086 IN [AX..SI] DO PutReg[s, i, state.Regs[i]]; ENDLOOP;
s.PutChar['\n];
FOR i: TeleLoad.Registers8086 IN [DI..FL] DO PutReg[s, i, state.Regs[i]]; ENDLOOP;
s.PutChar['\n];
};
SwabState:
PROC [state: TeleLoad.State8086Object]
RETURNS [TeleLoad.State8086Object] = {
FOR i: TeleLoad.Registers8086
IN [
AX..
FL]
DO
state.Regs[i] ← TeleDebOps.Swab[state.Regs[i]];
ENDLOOP;
RETURN[state];
};
FetchState:
PUBLIC
PROC[host: TeleDebOps.TeleDebugData, adv: TeleLoad.Advice ← [
FALSE,
FALSE, 0]] = {
cb: TeleLoad.CoreBlock;
ok: BOOLEAN;
tries: NAT;
pp: TeleLoad.State8086;
size: CARDINAL = SIZE[TeleLoad.State8086Object]*2;
IF host.h =
NIL
THEN {
host.out.PutF["Connection not open\n"];
RETURN;
};
cb ← NEW[TeleLoad.CoreBlockObject[size]];
cb.address ← 1;
cb.advice ← adv;
[ok, tries] ← TeleLoad.FetchState[host.h, cb];
IF
NOT ok
THEN {
host.out.PutF[" ... failed (%d attempts)\n", IO.int[tries]];
RETURN;
};
pp ← LOOPHOLE[BASE[DESCRIPTOR[cb.data]], TeleLoad.State8086];
host.larkState ← SwabState[pp^];
pp ← NIL;
};
Go:
PROC [tdd: TeleDebOps.TeleDebugData, gs:
BOOL ←
FALSE] = {
tdd.out.PutF["GO!\n"];
SetState[tdd, TeleLoad.Go, gs];
};
SingleStep:
PROC [tdd: TeleDebOps.TeleDebugData, gs:
BOOL ←
FALSE] = {
tdd.out.PutF["SingleStep!\n"];
SetState[tdd, TeleLoad.SingleStep, gs];
};
GoFromBreak:
PROC [tdd: TeleDebOps.TeleDebugData, gs:
BOOL ←
FALSE] = {
tdd.out.PutF["Break and Go!\n"];
SetState[tdd, TeleLoad.GoFromBreak, gs];
};
SetState:
PROC [tdd: TeleDebOps.TeleDebugData, tp: TeleLoad.TeleLoadProc, getState:
BOOL] = {
cb: TeleLoad.CoreBlock;
ok: BOOLEAN;
pp: TeleLoad.State8086;
size: CARDINAL = SIZE[TeleLoad.State8086Object]*2;
IF tdd.h =
NIL
THEN {
tdd.out.PutF["Connection not open\n"];
RETURN;
};
IF getState THEN FetchState[tdd];
cb ← NEW[TeleLoad.CoreBlockObject[size]];
cb.address ← 1;
cb.advice ← [FALSE, FALSE, 0];
pp ← LOOPHOLE[BASE[DESCRIPTOR[cb.data]], TeleLoad.State8086];
pp^ ← SwabState[tdd.larkState];
pp ← NIL;
ok ← tp[tdd.h, cb].ok;
IF NOT ok THEN tdd.out.PutF[" ... failed\n"];
};
GoToDebugger:
PROC [tdd: TeleDebOps.TeleDebugData, print:
BOOL] = {
IF print THEN tdd.out.PutRope["Debug!\n"];
SetState[tdd, TeleLoad.GoToDebugger, FALSE];
};
PutReg:
PROC [s:
IO.
STREAM, i: TeleLoad.Registers8086, v:
CARDINAL] = {
s.PutF[" %2s=%04xH", IO.rope[RegNames[i]], IO.card[v]];
};
AlterRegister:
PROC [tdd: TeleDebOps.TeleDebugData] = {
i: TeleLoad.Registers8086;
r: Rope.ROPE;
Echo[tdd];
tdd.out.PutF["Change register: "];
r ← tdd.edit.GetToken[];
SELECT
TRUE
FROM
Rope.Equal[s1: r, s2: "0", case:
FALSE] => {
FOR i: TeleLoad.Registers8086 IN [AX..FL] DO tdd.larkState.Regs[i] ← 0; ENDLOOP;
tdd.larkState.Regs[IP] ← 1024; -- 00400H
tdd.larkState.Regs[SP] ← 54256; -- 0D3F0H
RETURN;
};
Rope.Equal[s1: r, s2: "r", case:
FALSE] => {
FetchState[tdd];
RETURN;
};
Rope.Equal[s1: r, s2: "s", case:
FALSE] => {
IF tdd.program # NIL THEN tdd.larkState ← tdd.program.startState
ELSE tdd.out.PutF[" . . .No program specified\n"];
RETURN;
};
ENDCASE;
FOR i
IN TeleLoad.Registers8086
DO
IF Rope.Equal[s1: r, s2: RegNames[i], case: FALSE] THEN EXIT;
REPEAT
FINISHED => {
tdd.out.PutF[" ... unknown register\nRegisters are 0 (clear), r(emote), s(tartState of program), plus 8086 registers.\n"];
RETURN;
};
ENDLOOP;
tdd.out.PutF[" value for register %s (hex): ", IO.rope[RegNames[i]]];
tdd.larkState[i] ← Inline.LowHalf[GetHex[tdd.edit]];
tdd.out.PutF[" new value %s: %04xH\n", IO.rope[RegNames[i]], IO.card[tdd.larkState[i]]];
};
InteractiveDebug:
PROC [tdd: TeleDebOps.TeleDebugData] = {
ENABLE TeleDebOps.Failed => CONTINUE;
address: INT;
value: CARDINAL;
variableRope: Rope.ROPE;
found: BOOL;
sym: TeleDebOps.STObject;
c: CHAR;
PrintVarAddress:
PROC = {
sym ← TeleDebOps.ProcedureEnclosing[tdd.program, address];
tdd.out.PutF["\n%04xH (%g", IO.card[address], IO.rope[sym.id]];
IF sym.addr # address THEN tdd.out.PutF[" + %04xH): ", IO.card[address - sym.addr]]
ELSE tdd.out.PutF["): "];
};
Echo[tdd];
TeleDebOps.ResetCache[tdd];
variableRope ← tdd.edit.GetToken[];
[item: sym, found: found] ← TeleDebOps.FindVariable[tdd.program, variableRope];
IF found THEN address ← sym.addr
ELSE address ← GetHex[IO.RIS[variableRope]];
PrintVarAddress[];
DO
value ← TeleDebOps.ReadWord[host: tdd, addr: address];
tdd.out.PutF["%04xH (%6d) ", IO.card[value], IO.card[value]];
NoEcho[tdd];
c ← tdd.in.GetChar[];
Echo[tdd];
SELECT c
FROM
Ascii.
LF, 'n => {
address ← address + 2;
PrintVarAddress[];
};
Ascii.
BS, 'p => {
address ← address - 2;
PrintVarAddress[];
};
Ascii.CR => EXIT;
'? => {
tdd.out.PutF["LF, n => next word, BS, p => previous, CR => exit, Hex number => change\n"];
PrintVarAddress[];
};
'← => {
tdd.out.PutF[" ← "];
value ← Inline.LowHalf[GetHex[tdd.edit]];
TeleDebOps.WriteWord[tdd, address, value];
TeleDebOps.FlushWrites[tdd];
address ← address + 2;
PrintVarAddress[];
WHILE tdd.in.CharsAvail[] DO [] ← tdd.in.GetChar[]; ENDLOOP;
};
ENDCASE => {
tdd.out.PutF["LF, n => next word, BS, p => previous, CR => exit, ← => new hex value\n"];
PrintVarAddress[];
WHILE tdd.in.CharsAvail[] DO [] ← tdd.in.GetChar[]; ENDLOOP;
};
ENDLOOP;
TeleDebOps.MCR[tdd.out];
TeleDebOps.ResetCache[tdd];
};
Init:
PROC = {
PupDefs.PupPackageMake[];
UserExec.RegisterCommand[name: "TeleDeb.~", proc: myFork, briefDoc: "Lark Downloading and debugging"];
};
Main program
Init[];
}.