// RaidProcs.bcpl. Supplementary procedures for RAID
// Flushed TeleRaid July 20, 1983 2:49 PM by Bill van Melle
// Last modified March 30, 1983 11:31 AM by Bill van Melle
// Last modified December 16, 1982 10:15 PM by Bill van Melle
// Last modified July 21, 1982 9:32 PM by Bill van Melle
// Last modified September 19, 1981 2:01 PM by Bill van Melle
// Last modified August 4, 1981 12:47 PM by Beau Sheil

get "AltoDefs.d"
get "Raid.decl"
get "Stats.decl"
get "Vmem.decl"
get "Streams.d"

external [
// procedures defined here
ReadNum; ReadAtom; AtomNum; ShowRealCore
DisplayVMinBitMap; DisplayVMbit; DoYankDef
// statics
VMDisplay
]

external [
// procedures used
CRLF; Ws; Wo; Wc; Bytes2
StealFromBcplDisplay; AddToBcplDisplay; DumpBlockToStats
RaidReset; RAIDCode; ReadStrng; PrintAddrs; Confirm
@BGetBase; @BGetBasePtr; @XPutBase; @BGetBase32; @BPutBase32
@XSetReadBR; @RRead; @RWrite
BP; ReadFlags; VirtualPage; EmAddr; MkSmallPos; IGetBase
InitStats; CloseStats; IndexedPageIO; LookupPage; EqNIL

// OS procs used
Zero; ShowDisplayStream; CreateDiskStream

// statics used
EmulatorSpace; LastRealPageNo; @lvVPtr
dsp; @DisplayAddrHi
statsFP; statsFile; LispFmap
]

static [
VMDisplay = 0
]

manifest [ LastSegment = 63
// 22-bit address space
IMSize = #20000; DummyHeight = 32
VMbitMapOffset = 2+2*lDCB// bitmap within VMDisplay
VMDisplayWidth = 16; VMDisplayHeight = LastSegment+1
VMDisplayScanLines = DummyHeight + VMDisplayHeight
VMDisplaySize = VMbitMapOffset + VMDisplayWidth*VMDisplayHeight
]

structure String: [ length byte; char↑1,255 byte ]

let AtomNum(S) = valof
// Finds atom number for BCPL string. pn char format is that of bcpl strings
[
let LEN = S>>String.length
let NW = LEN rshift 1

// Compute the hash code for the name. Mimic the behavior of LISP
let SS = 0
for i = 1 to LEN do
[ let h1 = ((SS & #7777) lshift 2) + SS
SS = (h1 lshift 8) + h1 + S>>String.char↑i
]

[
let H = ((SS𒿑) rem (AHTSIZE lshift 8)) + AHTbase

// H is the virtual address in the AtomHashTable
let P = BGetBase(AHTspace, H)
// P is address of hash table entry
if P eq 0 then RaidReset("No such atom")

// since P was non zero, it is the virtual address of an atom+1
P = P-1

// fetch atom and check its pname. Check its characters (word-by-word)
// with those in pname. Count is first byte, and pad byte (if any) is 0.
XSetReadBR(BGetBasePtr(PNPspace, PNPbase+(P lshift 1)))
for i = 0 to NW do if RRead(i) ne S!i goto reprobe

resultis P
// pnames are the same; return virtual address

reprobe: SS = SS+HashInc
] repeat
// comparison failed so reprobe
]

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 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 ShowRealCore() be
// Displays a segment page usage map
[
CRLF()
Ws (" State of virtual memory file: ")
Ws (IGetBase(IFPKey) eq IFPValidKey? "C", "Inc")
Ws ("onsistent")
CRLF(); CRLF()
let base = vec LastSegment+2; Zero(base, LastSegment+3)
let ndirty, nlocked = 0, 0
let bp = BP(0)
for i = 2 to BptSize do
[
bp = bp+3// next one. Skips the dummy header
if bp>>BPT.LOCK
then nlocked = nlocked+1
let vp = bp>>BPT.VP
let bucket = vp<<VP.segment
if (bucket le LastSegment) & ((ReadFlags(vp) & DIRTYbit) ne 0)
then ndirty = ndirty+1
base!bucket = base!bucket + 1
]
base!EmulatorSpace = PagesPerSegment
// Emulator done specially
Ws(" Segment Pages Contents*N")
let total = 0
for i = 0 to LastSegment do unless base!i eq 0
do [ Ws(" "); Wo(i); Ws(" "); Wo(base!i)
// The following is not a SELECT as the choices are not exclusive
if i ge MDSLo & i le MDSHi then Ws(" Main data space")
if i eq PNPspace then Ws(" PName pointers")
if i eq DEFspace then Ws(" Definitions")
if i eq TOPVALspace then Ws(" TopVals")
if i eq PLISTspace then Ws(" Property lists")
if i eq AHTspace then Ws(" Atom Hash Table")
if i eq PMTspace then Ws(" Primary Page Map (PMT)")
if i eq PAGEMAPspace then Ws(" Secondary Page Map")
if i eq INTERFACEspace then Ws(" Interface page")
if i eq MDSTYPEspace then Ws(" MDS type table")
if i eq STATSspace then Ws(" Statistics")
if i eq STACKspace then Ws(" Stack")
if i eq EmulatorSpace then Ws(" Alto emulator")
if i eq DisplayAddrHi & DisplayAddrHi ne 0
then Ws(" Lisp display bitmap")
if i ge PncLo & i le PncHi then Ws(" PName characters")
if i ge ArrayLo & i le ArrayHi then Ws(" Arrays and strings")
if i eq GCMainspace then Ws(" GC main table")
if i eq GCCollspace then Ws(" GC collision table")
CRLF()
total = total + base!i ]
Ws(" Total "); Wo(total); Ws(" pages in use"); CRLF()
let sp = " "
Ws(sp); Wo(base!(LastSegment+1)); Ws(" Empty"); CRLF()
Ws(sp); Wo(LastRealPageNo-base!(LastSegment+2))
Ws(" Total available pages"); CRLF()
Ws(sp); Wo(nlocked); Ws(" pages locked"); CRLF()
Ws(sp); Wo(ndirty); Ws(" pages dirty"); CRLF()
]

and DisplayVMinBitMap() be
[
if VMDisplay then
[ VMDisplay = 0
AddToBcplDisplay(VMDisplay, VMDisplaySize, VMDisplayScanLines)
return
]

VMDisplay = StealFromBcplDisplay(VMDisplaySize, VMDisplayScanLines)

let VMDisplayDCB = VMDisplay + 2
// insert a null dcb DummyHeight/2 scan lines high first
VMDisplay>>DS.fdcb = VMDisplayDCB
VMDisplayDCB>>DCB.next = VMDisplayDCB + lDCB
VMDisplayDCB>>DCB.width = 0
VMDisplayDCB>>DCB.bitmap = 0
VMDisplayDCB>>DCB.height = DummyHeight/2

VMDisplayDCB = VMDisplayDCB + lDCB
VMDisplay>>DS.ldcb = VMDisplayDCB
VMDisplayDCB>>DCB.next = 0
VMDisplayDCB>>DCB.height = VMDisplayHeight/2
VMDisplayDCB>>DCB.indentation = 1
VMDisplayDCB>>DCB.width = VMDisplayWidth
VMDisplayDCB>>DCB.bitmap = VMDisplay + VMbitMapOffset

// Turn on bits for pages already in core. Emulator done specially.
for i=0 to PagesPerSegment-1 do DisplayVMbit(Bytes2(EmulatorSpace,i), true)
for i=0 to LastRealPageNo-1-PagesPerSegment do
[ let vp = VirtualPage(i)
unless vp<<VP.segment gr LastSegment do DisplayVMbit(vp, true)
]
ShowDisplayStream(VMDisplay, DSabove, dsp)
]

and DisplayVMbit(vp, turnOnBit) be
[
// segement selects row; hi order 4 bits address word; lo order 4 get bit
let bitInWord = #100000 rshift (vp<<VP.page & #17)
let Addr = VMDisplay + VMbitMapOffset + (vp<<VP.segment*VMDisplayWidth) +
vp<<VP.page rshift 4
@Addr = turnOnBit ? @Addr % bitInWord, @Addr & not bitInWord
]
and DoYankDef() be
[
Ws(" from atom ")
let a = ReadAtom()
BGetBase32(DEFspace, DEFbase+(a lshift 1))
test EqNIL(lvVPtr)
ifso Ws ("[no definition")
ifnot [ Wc($[); PrintAddrs(DEFspace,DEFbase+(a lshift 1), 2) ]
Ws("] and smash it into definition cell of atom ")
let b = ReadAtom()
Ws("[was ")
PrintAddrs(DEFspace,DEFbase+(b lshift 1), 2)
Wc($])
if Confirm()
then [
// since lvVPtr has been smashed by now...
BGetBase32(DEFspace, DEFbase+(a lshift 1))
BPutBase32(DEFspace,DEFbase+(b lshift 1), lvVPtr)
]
]