// Raid.bcpl - Raid debugger for InterLisp-D
// Last change September 27, 1981 9:36 PM by Bill van Melle
// Last change September 19, 1981 2:02 PM by Bill van Melle
// Last change August 4, 1981 12:41 PM by Beau Sheil
// Last change May 22, 1981 12:01 PM by Beau Sheil
// Last change May 20, 1981 9:56 PM by Beau Sheil
// Last change April 14, 1981 8:26 PM by Beau Sheil
// Tone change April 5, 1981 4:14 PM by Beau Sheil
get "Raid.decl"
get "Streams.d"
external [ // procedures defined
RAID; uCodeCheck; RAIDCode; RaidReset
CRLF; ReadNum; ReadStrng; ReadChar
// from RaidStack
PrintFxtn; PrintBF; PrintAddrs; PrintBytes
// from RaidPrint
Lprint; LispStack; LispFrame; ShowStackBlocks; Wb; Wn; Wo
// from RaidProcs
ShowRealCore; TeleRaid; AtomNum
// from Stack
CONTEXTSWITCH; GetFXP
// from OS
ShowDisplayStream; Endofs; Gets; Resets; Puts; Wc; Ws
GetBitPos; SetBitPos; SetLmarg; EraseBits; CharWidth
CallSwat; MyFrame
SetScreenColor; FlashScreen
// misc
ReadFlags; ReadRP; @BGetBasePtr; @BGetBase; @BPutBase; IGetBase
@APutBase32; @AtomNotNIL; MkSmallPos; SmallUnbox
Iresume; MoveValue
uPCTracing; UCase; DisplayVMinBitMap
OpenSoc; CloseSoc
// statics used
keys; @LispKbd; dsp; @lvKT; @lvNIL; @InterruptChar
uradix; uprintlevel; ulistlength
@dlispDsp; @DisplayAddrHi; VMDisplay
EmulatorSpace; @uPCTraceAddr
// from RaidStack
lastFrame; linkUsed; raidStackFX
doRaid // label used to abort typein
]
static [ crCount = 1; crMax = 60 ; RaidFrame; TeleRaidSocket ]
manifest RaidSoc = #33 // TeleRaid socket number
structure String: [ length byte; char↑1,255 byte ]
let RAID(X ;numargs na) = na ? RAIDCode("Called from Lisp", X) ,
RAIDCode("Called from Swat", lvNIL)
and uCodeCheck(code) = RAIDCode("Called from uCode", SmallUnbox(code))
and RAIDCode(st, param) = valof
[
RaidFrame = MyFrame()
if dsp eq 0 then CallSwat("Raid: No dsp", st) // Before APutBase32
Resets(keys); Resets(LispKbd) // clear any type-ahead
APutBase32(InterruptChar, lvNIL) // clear any InterruptChar
if DisplayAddrHi then ShowDisplayStream(dsp, DSalone)
Ws("*NRaid: "); Ws(st); Wc($*S); Lprint(param)
TeleRaidSocket = OpenSoc(0, RaidSoc) // Open TeleRaid socket
raidStackFX = GetFXP()
lastFrame = 0
linkUsed = 0
// This ATROCITY is due to Bcpl's refusal to allow strings as table entries
// The effect of this series of bindings is to create a table of character
// code, prompt message pairs on the stack
let c2, v2 = #2, "Show bytes"
let c4, v4 = #4, "Return to top level"
let c5, v5 = #5, "Enable interrupts"
let c6, v6 = #6, "Show basic frame"
let c7, v7 = #7, "Show stack blocks"
let c12, v12 = #12, "Next frame"
let c13, v13 = #13, "Kill Lisp"
let c14, v14 = #14, "Lisp Stack from frame"
let c16, v16 = #16, "Return NIL"
let c17, v17 = #17, "Atom number for atom "
let c20, v20 = #20, "Turn microcode PC tracing "
let c23, v23 = #23, "Call Swat"
let c24, v24 = #24, "Return T"
let c25, v25 = #25, "Show Lisp user screen"
let c26, v26 = #26, "Set to NIL the atom "
let c30, v30 = #30, "Show frame extension"
let c32, v32 = #32, "Turn VM display "
let cc, vc = $,, "Word from 2 bytes "
let cp, vp = $+, "Add 2 octal numbers "
let ca, va = $←, "Set word"
let cb, vb = $↑, "Previous frame"
let cq, vq = $?, "Show help"
let cA, vA = $A, "Atom top level value"
let cB, vB = $B, "Show virtual addrs"
let cC, vC = $C, "Coremap"
let cD, vD = $D, "Atom definition"
let cE, vE = $E, "Error msg"
let cF, vF = $F, "Show frame number "
let cJ, vJ = $J, "Set Raid list length"
let cL, vL = $L, "Lisp stack"
let cM, vM = $M, "Memory map check"
let cN, vN = $N, "Set Raid list depth"
let cO, vO = $O, "Show emulator addrs"
let cP, vP = $P, "Property list of atom "
let cQ, vQ = $Q, "Set Raid screen size"
let cS, vS = $S, "Show stack addrs"
let cU, vU = $U, "Set Raid radix"
let cV, vV = $V, "Show Lisp object"
let cW, vW = $W, "Walk stack blocks"
let cZ, vZ = $Z, "Show Vmem flags"
let cend = 0 // 0 marks end of command table
let V = nil
[
doRaid: Ws("*N@"); crCount = 1
switchon GetCom(lv c2) into
[
case 0: //Noop
loop
case 2: //↑B{onum, onum, onum}
StartLoc(""); PrintBytes()
loop
case 4: //↑D{} call \RAIDEXITFN
if Confirm() then
[
test AtomNotNIL(IGetBase(IFPInterruptEnable))
ifso [ V = 0; break ]
ifnot Ws("Interrupts are off. Restore them using ↑E first.")
]
CRLF()
loop
case 5: //↑E
if Confirm() then APutBase32(IGetBase(IFPInterruptEnable), lvKT)
loop
case 6: //↑F{onum}
AtLoc(" stack"); PrintBF(ReadNum(8))
loop
case 7: //↑G{onum}
StartLoc(" stack"); ShowStackBlocks(ReadNum(8), true)
loop
case #13: //↑K{} to kill
if Confirm() then finish
loop
case #14: //↑L{from fx; $A or $C}
AtLoc(" stack");
LispStack(ReadNum(8))
lastFrame = 0
loop
case $*N: //do nothing
loop
case #16: //↑N{} return NIL
V = lvNIL
break
case #17: //↑O{string} get atom number
[ let a = ReadAtom(); Ws("is "); Wo(a) ]
CRLF()
loop
case #20: //↑P{} uPC tracing
if Confirm(uPCTraceAddr ? "off", "on") then uPCTracing(true)
loop
case #23: //↑S{} gets Swat
if Confirm() then CallSwat("Raid")
loop
case #24: //↑T{} return T
V = lvKT
break
case #25: //↑U{} show Lisp display
if Confirm() then
[ unless DisplayAddrHi do [ Ws(" No Lisp display to show"); loop ]
ShowDisplayStream(dlispDsp, DSalone) // show lisp display
until Gets(keys) do loop // wait for a keystroke
ShowDisplayStream(dsp, DSalone) // restore Raid dsp
]
loop
case #26: //↑V{onum}
[ let a = ReadAtom(); if Confirm("") then APutBase32(a, lvNIL) ]
loop
case #30: //↑X{onum}
AtLoc(" stack"); PrintFxtn(ReadNum(8))
loop
case #32: //↑Z{} displayVM
if Confirm(VMDisplay ? "off", "on") then DisplayVMinBitMap()
loop
case $,: //,(onum}
Wo(ReadNum(8) lshift 8 + ReadNum(8))
CRLF()
loop
case $+: //+(onum}
Wo(ReadNum(8) + ReadNum(8))
CRLF()
loop
case $←: //←(onum, onum, onum}
AtLoc("")
[ let v0, v1 = ReadNum(8), ReadNum(8)
BPutBase(v0, v1, GetNewNum(BGetBase(v0, v1), 8)) ]
CRLF()
loop
case $?: //help
ShowHelp(lv c2)
loop
case $A: //A{onum}
Ws(" for ")
Lprint(BGetBasePtr(TOPVALspace,TOPVALbase+ReadAtom() lshift 1))
loop
case $B: //B{onum, onum, onum}
StartLoc(""); PrintAddrs(ReadNum(8))
loop
case $C: //C{}
CRLF()
ShowRealCore()
loop
case $D: //D{onum}
Ws(" for ")
PrintAddrs(DEFspace,DEFbase+ReadAtom() lshift 1,2)
loop
case $E: //E
Ws(" was: "); Ws(st); Wc($*S); Lprint(param)
loop
case $F: //F{dnum, $A or $C}
LispFrame()
loop
case #12: //LF (next frame)
LispFrame(lastFrame+1, linkUsed)
loop
case $↑: //↑ (previous frame)
LispFrame(lastFrame-1, linkUsed)
loop
case $J: //J{dnum}
ulistlength = GetNewNum(ulistlength, 10)
loop
case $L: //L{$A or $C}
LispStack()
loop
case $M: //Memory map diagnostic
if Confirm() then Ws("Sorry, not yet implemented")
loop
case $N: //N{dnum}
uprintlevel = GetNewNum(uprintlevel, 10)
loop
case $O: //O{onum, onum}
StartLoc(" Alto"); PrintAddrs(EmulatorSpace)
loop
case $P: //P{onum}
Lprint(BGetBasePtr(PLISTspace,PLISTbase+ReadAtom() lshift 1))
loop
case $Q: //Q{dnum}
crMax = GetNewNum(crMax, 10)
loop
case $S: //S{onum, onum}
StartLoc(" stack"); PrintAddrs(STACKspace)
loop
case $U: //U{dnum}
[ let N = GetNewNum(uradix, 10)
test (N ge 2)&(N le 10)
ifso uradix = N
ifnot Ws("Invalid, uradix not set") ]
loop
case $V: //V{onum, onum}
AtLoc("")
[ let v0, v1 = ReadNum(8), ReadNum(8)
Lprint(lv v0) ]
loop
case $W: //W
CRLF()
ShowStackBlocks(0, false)
loop
case $Z: //Z{onum, onum}
Ws(" for virtual pages from ")
[ let s = ReadNum(8); Ws(" to ")
let f = ReadNum(8)
Ws("*N VP Flags RealP*N")
for i = s to f
do [ Wo(i); Ws(" "); Wo(ReadFlags(i)); Wo(ReadRP(i)); CRLF() ]
]
loop
default: Ws("??"); Resets(keys)
loop
]
] repeat
// Exit sequence. Just return unless ↑D, in which case call RaidExitFn
CloseSoc(TeleRaidSocket); CRLF(); Resets(keys); Resets(LispKbd)
if DisplayAddrHi then ShowDisplayStream(dlispDsp, DSalone)
// ↑D exit (V=0) used to worry about flushing the Bcpl stack. But reentry
// from Lisp does this automatically since the Chord change.
resultis V ? V, (IGetBase(1) ? Iresume(CONTEXTSWITCH(MkSmallPos(1))),
CallSwat("No hard return context"))
]
and CRLF() be
[
Wc($*N)
test crCount gr crMax
ifso [ crCount = 1
SetScreenColor(true) // flash screen
let c = Gets(keys) // wait for keystroke
SetScreenColor(false) // restore screen
if c eq DEL then RaidReset()
]
ifnot crCount = crCount + 1
]
and Confirm(s ;numargs n) = valof
[ Resets(keys)
if n gr 0 then Ws(s)
Ws(" [Confirm] ")
let val = (Gets(keys) eq $*N)
unless val do Ws("XXX")
Wc($*N)
resultis val
]
and GetCom(CT, s) = valof // CT => command table
[
while Endofs(keys) do
[ let v = TeleRaid(TeleRaidSocket) // v is 0 or a Raid command
if v then resultis v ] // Execute Raid command
let c = UCase(ReadChar())
[ if c eq CT!0
then [ Ws(" - ") // found it
Ws(CT!1)
break ]
CT=CT+2
] repeatwhile CT!0 // 0 entry ends the table
resultis c
]
and GetNewNum(old, rad) = valof
[
Ws(" currently "); Wn(old, rad); Ws(" to ")
resultis ReadNum(rad)
]
and AtLoc(s) be // prints common msg
[ Ws(" at"); Ws(s); Ws(" location ") ]
and StartLoc(s) be // prints common msg
[ Ws(" starting at"); Ws(s); Ws(" location ") ]
and ReadChar() = valof // read character and echo it, abort on DEL
[
let c = Gets(keys)
if c eq DEL then RaidReset(" XXX")
PrintComChar (c)
resultis c
]
and PrintComChar (ch) be
[
test (ch ge $*S) % (ch eq $*N)
ifso Wc(ch)
ifnot test ch eq #12
ifso Ws ("LF")
ifnot [ Wc($↑); Wc (ch%#100) ]
]
and ReadNum(radix) = valof // read number in given radix
[
let s = vec 50
unless ReadStrng(s) do RaidReset(" XXX")
let num=0
for i=1 to s>>String.length do
[ let c = (s>>String.char↑i)-$0
test (c ge 0) & (c ls radix)
ifso num=num*radix+c
ifnot RaidReset(" XXX")
]
resultis num
]
and ReadAtom() = valof // obtains atom number from typein
[ let s = vec 50
unless ReadStrng(s) do RaidReset(" XXX")
let num=0
for i=1 to s>>String.length do
[ let c = (s>>String.char↑i)-$0
test (c ge 0) & (c le 7)
ifso num=num*8+c
ifnot resultis AtomNum(s)
]
resultis num
]
and ReadStrng(str, maxlen, inited, noecho; numargs na) = valof
// Read string (up to space or cr) into str, return 0 if DEL typed
[ if na ls 4 then noecho = false
if na ls 3 then inited = false
if na ls 2 then maxlen = 99
let index = inited ? str>>String.length , 0
[ let ch=Gets(keys)
if ch eq DEL then resultis 0
test (ch eq 1) % (ch eq #10) // ↑A or BS
ifso test index gr 0
ifso [ unless noecho
do EraseBits(dsp, -CharWidth(dsp, str>>String.char↑index))
index = index - 1
]
ifnot FlashScreen()
ifnot test ch eq $*s
ifso [ if index eq 0 then loop // flush leading space
unless noecho do Wc(ch)
break ]
ifnot [
if inited
then [ // overwriting init string
let width = 0
for i = 1 to index
do width = width + CharWidth(dsp, str>>String.char↑i)
EraseBits (dsp, -width)
index = 0
inited = false
]
unless noecho do Wc(ch)
if ch eq $*N then break
if index ge maxlen
then [ FlashScreen(); loop ]
index = index+1
str>>String.char↑index = ch
]
] repeat
unless (index&1) ne 0
do str>>String.char↑(index+1) = 0 // null last byte
str>>String.length = index
resultis str
]
and RaidReset(errmsg; numargs na) be // retto Raid command loop
[
if na gr 0 then Ws(errmsg)
Wc($*N)
SetLmarg(dsp, 8) // reset margin
MyFrame()!0 = RaidFrame
RaidFrame!1 = doRaid - 1 // to restart command loop
]
and ShowHelp(CT) be // CT => start of command table
[
Ws("*N*NRAID commands*N*N")
[ PrintComChar(CT!0); Ws(" - "); Ws(CT!1)
test GetBitPos(dsp) gr 300
ifso CRLF()
ifnot SetBitPos(dsp, 300)
CT=CT+2
] repeatwhile CT!0 // 0 entry ends the table
CRLF()
]