~
BEGIN
QUIT: CARD32 = SoftcardMonitorExch.QUIT;
SPARCDEAD: CARD32 = 0;
MONTRACE: CARD32 = 8;
MONENTER: CARD32 = MONTRACE+1;
MONDISPLAY: CARD32 = MONENTER+1;
MONFILL: CARD32 = MONDISPLAY+1;
MONOPEN8: CARD32 = MONFILL+1;
MONOPEN16: CARD32 = MONOPEN8+1;
MONOPEN32: CARD32 = MONOPEN16+1;
MONDUMP: CARD32 = MONOPEN32+1;
MONBRK: CARD32 = MONDUMP+1;
MONCALL: CARD32 = MONBRK+1;
firstAvailableCode: CARD32 ← MONCALL+1; --so that it can be looked at with the interpreter
ROPE: TYPE ~ Rope.ROPE;
CommandProcHandle:
TYPE ~
REF CommandProcHandleRec;
CommandProcHandleRec:
TYPE ~
RECORD[
cmd: ROPE,
doc: ROPE,
proc: SoftcardMonitor.CommandProc
];
CheckTool:
PROC ~ {
IF in=NIL THEN GOTO CreateOne;
IF IO.EndOf[in ! IO.Error => GOTO CreateOne] THEN GOTO CreateOne;
EXITS
CreateOne => CreateTool[];
};
CreateTool:
PROC ~ {
[in, out] ← ViewerIO.CreateViewerStreams[name: "Puff Monitor"];
TRUSTED {
monitorProcess ← FORK DoMonitor[];
Process.Detach[monitorProcess];
};
};
nestingRope: ROPE ← "~";
prompt: ROPE ← "> ";
PutPrompt:
PROC ~ {
IO.PutF[out, "%l%g%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]];
};
DoMonitor:
PROC ~ {
Description of the procedure.
state: SoftcardMonitor.State ← NEW[SoftcardMonitor.StateRec];
DO
quit: BOOLEAN ← FALSE;
WaitForMonitorStart[];
UNTIL quit
DO
found: BOOLEAN;
val: SymTab.Val;
cmdLine: ROPE ;
args: SoftcardMonitor.Arguments;
PutPrompt[];
cmdLine ← IO.GetLineRope[in];
args ← ParseToTokens[cmdLine];
IF args#
NIL
THEN {
[found, val] ← SymTab.Fetch[cmdTable, args[0]];
IF found
THEN {
ENABLE Convert.Error => {IO.PutRope[out, "Invalid number\n"]; CONTINUE};
proc: SoftcardMonitor.CommandProc ← NARROW[val, CommandProcHandle].proc;
quit ← proc[args, in, out, state];
}
ELSE IO.PutF[out, "*** cmd ""%g"" unknown\n", IO.rope[args[0]]];
};
ENDLOOP;
IO.PutF[out, "%l%gmonitor exited\n%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]];
prompt ← Rope.Substr[base: prompt, start: Rope.Length[nestingRope]];
DisableMonitor[];
ENDLOOP;
};
ActionDisplay: SoftcardMonitorExch.ActionProc ~ {
i: CARD32 ← 0;
IF data1=0
AND data2=0
THEN {
ReleaseLock[];
RETURN;
};
CheckTool[];
IO.PutF[out, "%l", IO.char['f]];
WHILE r.length>i
DO
modulo: NAT ← 0;
lineSize: CARD32 ← MIN[16, r.length-i];
letters: ROPE ← Rope.FromRefText[r, i, lineSize];
IO.PutF[out, "%8x: ", IO.card[data1]];
FOR j:
CARD32
IN [i..i+lineSize)
DO
IO.PutF[out, "%02x", IO.card[ORD[r[j]]]];
modulo ← modulo+1;
IF modulo=4
THEN {
IO.PutRope[out, " "];
modulo ← 0;
};
ENDLOOP;
FOR j:
CARD32
IN [i+lineSize..i+16)
DO
IO.PutRope[out, " "];
modulo ← modulo+1;
IF modulo=4
THEN {
IO.PutRope[out, " "];
modulo ← 0;
};
ENDLOOP;
IO.PutF[out, "\t%g\n", IO.rope[letters]];
data1 ← data1+16;
i ← i+16;
ENDLOOP;
IO.PutF[out, "%l", IO.char['F]];
};
ActionDump: SoftcardMonitorExch.ActionProc ~ {
i: CARD32 ← 0;
ireg: NAT ← 0;
CheckTool[];
IO.PutF[out, "%l", IO.rope["f"]];
WHILE r.length>i
DO
lineSize: CARD32 ← MIN[4, r.length-i];
IO.PutF[out, "r%02d: ", IO.card[ireg]];
FOR j:
CARD32
IN [i..i+lineSize)
DO
IO.PutF[out, "%02x", IO.card[ORD[r[j]]]];
ENDLOOP;
i ← i+lineSize;
IF (i MOD 16) =0 THEN IO.PutChar[out, '\n] ELSE IO.PutChar[out, ' ];
ireg ← ireg+1;
ENDLOOP;
IO.PutF[out, "%l", IO.rope["F"]];
ReleaseLock[];
};
ActionTrace: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutF[out, "%8xH, %8xH\n", IO.card[data1], IO.card[data2]];
};
ActionEnter: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
SELECT data1
FROM
0 => IO.PutF[out, "\n***** UNEXPECTED TRAP # %d *****\n\n", IO.card[data2]];
1 => IO.PutF[out, "\n***** UNCAUGHT ERROR *****\n\n"];
ENDCASE => IO.PutF[out, "\n***** BREAKPOINT # %x *****\n\n", IO.card[data2]];
prompt ← Rope.Concat[nestingRope, prompt];
IF monitorlevel#0 THEN PutPrompt[];
ReleaseLock[];
EnableMonitor[];
};
ActionCall: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutF[out, "returns : %8xH\n", IO.card[data2]];
ReleaseLock[];
};
ActionBrk: SoftcardMonitorExch.ActionProc ~ {
IF data2#0 THEN [] ← CardTab.Insert[brktable, data1, NEW[CARD ← data2]];
};
ActionDead: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutRope[out, "\n***** INTERNAL SPARC ERROR *****\n\n"];
};
Register:
PUBLIC PROC [cmd, doc:
ROPE, proc: SoftcardMonitor.CommandProc] ~ {
cmdH: CommandProcHandle ← NEW[CommandProcHandleRec ← [cmd, doc, proc]];
[] ← SymTab.Store[cmdTable, cmd, cmdH];
};
Commands
DisplayCmd: SoftcardMonitor.CommandProc ~ {
first: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
last: CARD32 ← IF args.argc<3 THEN first+4 ELSE CardFromRope[args[2], state];
waitForAnswer ← TRUE;
state.here ← last;
SoftcardMonitorExch.PutPacket[MONDISPLAY, first, last];
WaitForLock[];
};
DumpCmd: SoftcardMonitor.CommandProc ~ {
addr: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
waitForAnswer ← TRUE;
SoftcardMonitorExch.PutPacket[MONDUMP, addr];
WaitForLock[];
};
FillCmd: SoftcardMonitor.CommandProc ~ {
first: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
last: CARD32 ← IF args.argc<3 THEN first+1 ELSE CardFromRope[args[2], state];
val: CARD32 ← IF args.argc<4 THEN 0 ELSE CardFromRope[args[3], state];
format: {b, w, l};
format ←
IF args.argc>4
THEN
SELECT Rope.Fetch[args[4]]
FROM
'b, 'B => b,
'w, 'W => w,
'l, 'L => l,
ENDCASE => b
ELSE
SELECT val
FROM
IN [0..100h) => b,
IN [100h..10000h) => w,
ENDCASE => l;
state.here ← last;
IF val# 0
THEN {
--beware of the Cedar (weird) byte order...
r: REF TEXT ← NEW[TEXT[4]];
r.length ← 0;
SELECT format
FROM
b => PutByteInBuf[val, r, 0];
w => {
IF first
MOD 2#0
THEN {
IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[first]];
RETURN;
};
PutWordInBuf[val, r, 0];
};
ENDCASE => {
IF first
MOD 4#0
THEN {
IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[first]];
RETURN;
};
PutLongInBuf[val, r, 0];
};
SoftcardMonitorExch.PutPacket[MONFILL, first, last, r];
}
ELSE SoftcardMonitorExch.PutPacket[MONFILL, first, last];
};
Open8Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32 ← IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
SoftcardMonitorExch.PutPacket[MONOPEN8, add, val];
};
Open16Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32 ← IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
IF add MOD 2#0 THEN IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONOPEN16, add, val];
};
Open32Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32 ← IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONOPEN32, add, val];
};
SetBrkCmd: SoftcardMonitor.CommandProc ~ {
add: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONBRK, add, 0];
};
ClearBrkCmd: SoftcardMonitor.CommandProc ~ {
add: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE {
found: BOOLEAN;
val: CardTab.Val;
[found, val] ← CardTab.Fetch[brktable, add];
IF found
THEN {
SoftcardMonitorExch.PutPacket[MONBRK, add, NARROW[val, REF CARD]^];
[] ← CardTab.Delete[brktable, add];
}
ELSE IO.PutF[out, "%x: no break (known) there\n", IO.card[add]];
};
};
CallCmd: SoftcardMonitor.CommandProc ~ {
nArgs, addr: CARD32;
IF args.argc<2 OR args.argc>7 THEN RETURN;
IF symbols=NIL THEN FillSymbols[];
IF symbols=NIL THEN RETURN;
addr ← SparcSymbols.GetAddress[args[1], symbols];
IF addr=0
THEN {
addr ← SparcSymbols.GetAddress[Rope.Cat["←", args[1]], symbols];
IF addr=0 THEN {IO.PutRope[out, "unknown function\n"]; RETURN}
ELSE IO.PutF[out, "using ←%g instead\n", [rope[args[1]]] ];
};
nArgs ← args.argc-2;
r.length ← 0;
FOR i:
CARD32
IN [0..nArgs)
DO
PutLongInBuf[CardFromRope[args[i+2], state], r, 4*i];
ENDLOOP;
waitForAnswer ← TRUE;
SoftcardMonitorExch.PutPacket[MONCALL, addr, nArgs, r];
WaitForLock[];
};
ContinueCmd: SoftcardMonitor.CommandProc ~ {
SoftcardMonitorExch.PutPacket[QUIT];
quit ← TRUE;
};
local commands
ListBrkCmd: SoftcardMonitor.CommandProc ~ {
PrintOne: CardTab.EachPairAction ~ {
opcode: CARD32 ← NARROW[val, REF CARD]^;
IO.PutF[out, "\t%8x (%8x)\n", IO.card[key], IO.card[opcode]];
};
[] ← CardTab.Pairs[brktable, PrintOne];
};
HelpCmd: SoftcardMonitor.CommandProc ~ {
PrintOne: SymTab.EachPairAction ~ {
doc: ROPE ← NARROW[val, CommandProcHandle].doc;
IO.PutF[out, "\t%g %g\n", IO.rope[key], IO.rope[doc]];
};
IF args.argc<2 THEN [] ← SymTab.Pairs[cmdTable, PrintOne]
ELSE
FOR i:
NAT
IN [1..args.argc)
DO
found: BOOLEAN;
val: SymTab.Val;
[found, val] ← SymTab.Fetch[cmdTable, args[i]];
IF found
THEN {
doc: ROPE ← NARROW[val, CommandProcHandle].doc;
IO.PutF[out, "\t%g %g\n", IO.rope[args[i]], IO.rope[doc]];
}
ELSE IO.PutF[out, "%g: unknown\n", IO.rope[args[i]]];
ENDLOOP;
};
TranslateCmd: SoftcardMonitor.CommandProc ~ {
IF symbols=NIL THEN FillSymbols[];
IF symbols#
NIL
THEN {
addr: CARD32 ← SparcSymbols.GetAddress[args[1], symbols];
IF addr=0 THEN addr ← SparcSymbols.GetAddress[Rope.Cat["←", args[1]], symbols];
IF addr=0
THEN {
IO.PutRope[out, "unknown symbol"];
RETURN;
}
ELSE {
name: ROPE ← SparcSymbols.GetClosestName[addr, symbols];
IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]];
};
};
};
WhereIsCmd: SoftcardMonitor.CommandProc ~ {
name: ROPE;
addr: CARD32 ← IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
state.here ← addr;
IF symbols=NIL THEN FillSymbols[];
IF symbols#
NIL
THEN {
name ← SparcSymbols.GetClosestName[addr, symbols];
addr ← SparcSymbols.GetAddress[name, symbols];
IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]];
};
};
r: REF TEXT ← NEW[TEXT[2048]];
in, out: IO.STREAM;
monitorProcess: PROCESS ← NIL;
cmdTable: SymTab.Ref ← SymTab.Create[];
brktable: CardTab.Ref ← CardTab.Create[];
symbols: SparcSymbols.Tables ← NIL;
Register["h", "cmd1 cmd2 ...: prints doc on commands", HelpCmd];
Register["?", "cmd1 cmd2 ...: prints doc on commands", HelpCmd];
Register["v", "firstAdd lastAdd : displays memory", DisplayCmd];
Register["d", " : dumps register contents", DumpCmd];
Register["f", "firstAdd lastAdd [val 𡤀] [format]: fills memory with val; \n\tuses byte word(16) or long (32) chunks depending on format if specified or val size otherwise", FillCmd];
Register["o", "add [val 𡤀] : puts byte val at add", Open8Cmd];
Register["e", "add [val 𡤀] : puts short val at add", Open16Cmd];
Register["l", "add [val 𡤀] : puts long val at add", Open32Cmd];
Register["c", "gives the control back to the Sparc", ContinueCmd];
Register["cb", "add : clears the breakpoint at add", ClearBrkCmd];
Register["sb", "add : sets a breakpoint at add", SetBrkCmd];
Register["lb", " : lists all breakpoints", ListBrkCmd];
Register["tr", "name: translates a name to hexa", TranslateCmd];
Register["whereis", "add: finds the closest ext name to such add", WhereIsCmd];
Register["call", "name arg0 ...): calls the function(5 32b args max)", CallCmd];
SoftcardMonitorExch.Register[SPARCDEAD, ActionDead, NIL];
SoftcardMonitorExch.Register[MONTRACE, ActionTrace, NIL];
SoftcardMonitorExch.Register[MONENTER, ActionEnter, NIL];
SoftcardMonitorExch.Register[MONDISPLAY, ActionDisplay, r];
SoftcardMonitorExch.Register[MONDUMP, ActionDump, r];
SoftcardMonitorExch.Register[MONBRK, ActionBrk, NIL];
SoftcardMonitorExch.Register[MONCALL, ActionCall, NIL];
SparcSoftcardLoaderOps.RegisterStartProc[$SparcMonitor, ResetMonitor];