TeleDebImpl.mesa
Last modified:
Stewart, April 7, 1983 2:18 pm, cleanup
DIRECTORY
Ascii,
Convert,
Inline,
IO,
Process,
PupTypes,
PupDefs,
Rope,
Runtime USING [GetBcdTime],
TeleDebOps,
TeleLoad,
Time,
Transaction,
TypeScript USING [ChangeLooks],
ViewerIO USING [CreateViewerStreams, GetViewerFromStream],
ViewerOps USING [PaintViewer],
UECP USING [Argv, Parse],
UserExec;
TeleDebImpl: PROGRAM
IMPORTS Convert, Inline, IO, Process, PupDefs, Rope, Runtime, TeleDebOps, TeleLoad, Time, TypeScript, UECP, UserExec, ViewerIO, ViewerOps
EXPORTS TeleDebOps =
{
OPEN TeleDebOps;
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: BOOLFALSE] = {
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.ROPEIF 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: BOOLEANFALSE] = {
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: BOOLFALSE] = {
tdd.out.PutF["GO!\n"];
SetState[tdd, TeleLoad.Go, gs];
};
SingleStep: PROC [tdd: TeleDebOps.TeleDebugData, gs: BOOLFALSE] = {
tdd.out.PutF["SingleStep!\n"];
SetState[tdd, TeleLoad.SingleStep, gs];
};
GoFromBreak: PROC [tdd: TeleDebOps.TeleDebugData, gs: BOOLFALSE] = {
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]]];
};
YankVariable: PROC [tdd: TeleDebOps.TeleDebugData] = {
variableName: Rope.ROPE;
Echo[tdd];
tdd.out.PutF["Print variable: "];
variableName ← tdd.edit.GetToken[];
TeleDebOps.PrintVariable[tdd, variableName];
TeleDebOps.MCR[tdd.out];
};
AlterVariable: PROC [tdd: TeleDebOps.TeleDebugData] = {
variableName: Rope.ROPE;
offset: NAT;
value: CARDINAL;
Echo[tdd];
tdd.out.PutF["Alter variable. Name: "];
variableName ← tdd.edit.GetToken[];
tdd.out.PutF[" Offset (decimal): "];
offset ← And[Inline.LowHalf[tdd.edit.GetInt[]], 077777B];
tdd.out.PutF[" new value (hex) "];
value ← Inline.LowHalf[GetHex[tdd.edit]];
TeleDebOps.MCR[tdd.out];
[] ← TeleDebOps.SetValue[host: tdd, name: variableName, value: value, offset: offset];
};
AlterVariablesFromFile: PROC [tdd: TeleDebOps.TeleDebugData] = {
fileName: Rope.ROPE;
pl: LIST OF TeleDebOps.PatchItem;
Echo[tdd];
tdd.out.PutF["Alter variables from file. Filename: "];
fileName ← tdd.edit.GetToken[];
TeleDebOps.MCR[tdd.out];
pl ← TeleDebOps.PatchFromFile[host: tdd, fileName: fileName];
WHILE pl # NIL DO
TeleDebOps.WriteWord[host: host, addr: pl.first.address, value: pl.first.wordValue];
tdd.out.PutChar['p];
pl ← pl.rest;
ENDLOOP;
TeleDebOps.FlushWrites[host];
TeleDebOps.MCR[tdd.out];
};
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[];
}.
Swinehart, November 8, 1982 4:51 pm
Stewart, November 19, 1982 3:53 pm
Stewart, December 6, 1982 4:33 pm, Cedar 3.5
Stewart, December 22, 1982 3:31 pm, mods to TeleLoad
Stewart, December 28, 1982 1:33 pm, smaller locMaxByte