// VMemB.bcpl. D* virtual memory package
// Last modified March 19, 1985 6:38 PM by Bill van Melle
// Last modified December 13, 1984 11:50 AM by Bill van Melle
// Gutted November 19, 1984 5:34 PM by Bill van Melle
// Last modified May 25, 1983 10:58 AM by Bill van Melle
// Last modified March 14, 1983 5:31 PM by Bill van Melle
// Last modified February 4, 1983 10:33 PM by Bill van Melle
// Major pruning December 16, 1982 10:27 PM by Bill van Melle
// Last modified May 17, 1982 1:58 PM by Bill van Melle
get "LispBcpl.decl"
get "Stats.decl"
get "VMem.decl"
get "Streams.d"
external // SUBRS
[ PageFault // (lvPtr)
MOREVMEMFILE // (filepage)
WRITEMAPSUBR // (vp rp flags)
LISPFINISH // () returns to Alto exec
// other entries
IGetBase // (offset)
IPutBase // (offset, val)
LookupPage // (vp)
RemapMemory // () cleans up on exit
WriteSwapBuf // () writes any dirty page out to vmem
]
external [ // OS procedures
CallSwat; Zero
// fpr LISPFINISH:
CreateDiskStream; PositionPage; FileLength; ReadBlock; Closes
// Other procs used
LispCleanup; LoadRam; Fault; MachineType; DeImplementedSubr
BP; VP; VP2
IndexedPageIO; SmallUnbox
@BGetBase; @BPutBase; MkSmallPos; EqNIL; EmUnbox
// Raid procs
Ws; Wo; RaidReset; PrintPtr; RAIDCode
// Statics
realPageTableSetup; memAvailTable; FirstRealPageNo // exported
noFaultFlg; SwapBuf; SwapBufVp; SwapBufFileP; SwapBufDirty
lvAbortFlag // OS
LispFmap; @RMSK
@lvNIL; @lvKT; @MiscSTATSbase
insideRaid; EmulatorSpace
LastRealPageNo
// fpr LISPFINISH:
PupZoneStart; PupZoneLength; altoUcodeFp; uCodeLoaded
// Other external VMem procs (from VmemA.asm)
ReadFlags // (VP) -> oldflags
ReadRP // (VP) -> RP
SetFlags // (VP, RP, flags)
]
static
[ @Bpt; @BptSegment; BptSize; @BufVp; @BufRP
@RPoffset; LispFmap
realPageTableSetup = false
memAvailTable
FirstRealPageNo
SwapBuf
SwapBufVp = 0
SwapBufFileP = 0
SwapBufDirty = false
]
let PageFault(lvPtr, ac2) = valof // page fault handler
[
let vp = VP(lvPtr)
if vp ne SwapBufVp
then [
let flags = ReadFlags(vp)
test (flags & VACANT) ne VACANT
ifso resultis RAIDCode("Fault on resident page", lvPtr, true)
ifnot [
let filep = LookupPage(vp)
test filep
ifso [
if not insideRaid
then RAIDCode("Non-Raid fault inside Bcpl. ↑N to continue", lvPtr)
if vp ne SwapBufVp
then ReadSwapBuf(vp, filep)
]
ifnot InvalidAddr (lvPtr)
]
]
if (@ac2)!2 gr Fault
then SwapBufDirty = true // write fault
ac2!4 = EmulatorSpace
// adjust reference to point at core buffer
ac2!5 = ((ac2!5) & RMSK) + SwapBuf
resultis lvPtr
]
and ReadSwapBuf(vp, filep) be
[
if SwapBufDirty then WriteSwapBuf()
IndexedPageIO(LispFmap, filep, SwapBuf, 1, false)
SwapBufVp = vp
SwapBufFileP = filep
SwapBufDirty = false
]
and WriteSwapBuf() be
[
if SwapBufDirty then IndexedPageIO(LispFmap, SwapBufFileP, SwapBuf, 1, true)
SwapBufDirty = false
]
and InvalidAddr (lvPtr) be
[
if insideRaid
then [ Ws ("Invalid address: ")
PrintPtr (lvPtr!0, lvPtr!1)
RaidReset()
]
RAIDCode("Invalid address", lvPtr, true)
] repeat
and LookupPage(vp) = valof
[ // Returns page in vmem file or 0 if the page does not exist
compileif (not BigAddressSpace)
then [ if (vp𢋠) ne 0 then InvalidVP(vp) ]
let pmpE = BGetBase(PMTspace, PMTbase + vp<<PVP.key1)
if pmpE eq -1 then resultis 0
let px = PAGEMAPbase + pmpE + vp<<PVP.key2
resultis BGetBase(PAGEMAPspace, px)
]
and IGetBase(disp) = BGetBase(INTERFACEspace,INTERFACEbase+disp)
and IPutBase(disp,val) be BPutBase(INTERFACEspace,INTERFACEbase+disp,val)
and InvalidVP(vp) be
[
if insideRaid
then [ Ws ("Invalid VP: ")
Wo(vp, true)
RaidReset()
]
RAIDCode("Invalid VP", MkSmallPos(vp))
] repeat
and LISPFINISH() be
[
LispCleanup()
if altoUcodeFp & uCodeLoaded
then [ // reload alto microcode
let s = CreateDiskStream(altoUcodeFp, ksTypeReadOnly, wordItem)
altoUcodeFp = 0
unless s do finish
let sl = (FileLength(s) + 1) rshift 1 - WordsPerPage
// length of LoadRam buffer we need
let buffer = ((PupZoneStart+PupZoneLength) + WordsPerPage-1) & not (WordsPerPage-1)
PositionPage(s, 2)
ReadBlock(s, buffer, sl)
Closes(s)
LoadRam((MachineType() eq Dolphin? buffer-1, buffer), 1)
]
finish
]
and RemapMemory() be
[ // restore map to virgin state on exit
unless realPageTableSetup do return
// I hope the emulator pages are ok, because we don't have a table for them
let firstvp = VP2((EmulatorSpace eq 0? 1, 0), 0) // first non-emulator page
let rp = FirstRealPageNo
let lastvp = MachineType() eq Dorado? #177777, #37777
let vp = firstvp-1
[ vp = vp + 1
SetFlags (vp, 0, VACANT) // unmap everything
] repeatuntil vp eq lastvp
let bitBase = memAvailTable + (rp rshift 4)
let lastBitBase = memAvailTable + ((LastRealPageNo-1) rshift 4)
vp = firstvp
for base = bitBase to lastBitBase
do [
let info = @base
for i = 0 to 15
do [
if (info&1) eq 1
then [
SetFlags(vp, rp, 0) // map this vp into this page
vp = vp+1
]
info = info rshift 1
rp = rp+1
]
]
]
and WRITEMAPSUBR (vp, rp, flags) = valof
[
SetFlags (SmallUnbox(vp), SmallUnbox(rp), SmallUnbox(flags))
resultis vp
]
and MOREVMEMFILE (filepage) = DeImplementedSubr()