//MLOAD.BCPL
get "mdecl.d"
get "streams.d"
external [
// OS
OpenFile; Resets; Gets; Puts; PositionPage; Closes; Endofs; Wns; Wss
ReadBlock; WriteBlock; MoveBlock; SetBlock; Zero; CallSwat
Allocate; Free; Noop; TruePredicate
// MIDAS
GetField; PutField; Initialized; HaveHardware
// MASM
ErrorProtect
// MDISP
SetDisplay
// MMENU
FormMenu
// MMPRGN
DoubleNeg
// MIOC
MDatatoStream
// MPARSE
ParseTextList
// MTV
StreamFromTextName
// MTXTBUF
InputTextBuffer
// MSYM
FindInTable; UpdateRcd; @StringVec; SearchBlocks
// MOVERLAY
OverlayZone
// MCMD
DisplayError; ConfirmAct; QuickOpenFile; FormCmdmenuText; CmdMDFS
LoadDone; CmdCommentStream; SavedLoadText; ProgramStream; WssCSS
// MINIT0
FixUpFP; ErrsFP
// Hardware interface
GetMemData; PutMemData; ProcOnTest; RestoreAfterLoad
@MEMNAM; @MEMWID
// Defined here
InitLoad; LoadMB; LoadSyms; LoadData; DumpMB; CompareMB
]
static[
// local statics
@MBOutStream; @CBuf; @XtoIMemX; @XtoWdWidth
@InVecLeft; @InWdWidth; @InWds; @InDn; @InVec
NWrong; @NAddresses; @NFixups; NExtFixUps; @NWords; @NDBlocks
]
manifest [ ReadCnt = 5400B // Max word count read from .MB file
InVecSize = ReadCnt+54; MaxExtMemX = 12 ; NotDefined = -100
]
//lvProc points at LoadMB, LoadData, LoadSyms, DumpMB, or CompareMB
let InitLoad(lvProc) = valof
[ if (Initialized & HaveHardware) then if not ProcOnTest() do
[ DisplayError("Power is off","Continue-loading")
Resets(CmdCommentStream)
]
CBuf = Allocate(OverlayZone,6)
InVec = Allocate(OverlayZone,InVecSize+1)
XtoIMemX = Allocate(OverlayZone, MaxExtMemX+1)
XtoWdWidth = Allocate(OverlayZone, MaxExtMemX+1)
SetBlock(XtoIMemX,NotDefined,MaxExtMemX)
NWrong,NWords,NFixups,NExtFixUps,NAddresses,NDBlocks = 0,0,0,0,0,0
(rv lvProc)(); if Initialized then RestoreAfterLoad()
if LoadDone then FormMenu(CmdMDFS,FormCmdmenuText)
Free(OverlayZone,CBuf); Free(OverlayZone,InVec)
Free(OverlayZone,XtoIMemX); Free(OverlayZone,XtoWdWidth)
resultis -1
]
and LoadSyms() be
[ if LoadDone do
[ if not ConfirmAct("Merge symbols from ",InputTextBuffer)
then return
]
let AbortFlag = false
MoveBlock(SavedLoadText,InputTextBuffer,73)
test ErrorProtect(lv ScanMBFiles,InputTextBuffer,
TruePredicate,Noop,Noop,UpdateRcd,Noop) eq 0
ifso SavedLoadText!0 = 0
ifnot [ LoadDone,NWords = Initialized,0; ShowStats("Loaded ",true) ]
]
and LoadData() be LoadX(Noop)
and LoadMB() be LoadX(UpdateRcd)
and LoadX(SymOp) be
[ if LoadDone do
[ if not ConfirmAct("Overwrite ",SavedLoadText) then return ]
let OKFlag = nil
//Save text of files being loaded for possible MBDump()
MoveBlock(SavedLoadText,InputTextBuffer,73)
[ OKFlag = ErrorProtect(lv ScanMBFiles,InputTextBuffer,
PutMemData,Noop,FixUp,SymOp,WriteExtFixUp)
unless NExtFixUps eq 0 do
[ unless OKFlag eq 0 do
[ Puts(MBOutStream,0); PositionPage(MBOutStream,1)
OKFlag = ErrorProtect(lv GenMBIn,MBOutStream,
BadFix,BadFix,BadFix,BadFix,ExtFixUp)
]
Closes(MBOutStream)
]
]
test OKFlag eq 0
ifso SavedLoadText!0 = 0
ifnot [ LoadDone = Initialized; ShowStats("Loaded ",true) ]
]
and DumpMB() be
[ if SavedLoadText!0 eq 0 then
DisplayError("No previous LOAD file list to control dump")
if not LoadDone then WssCSS("[**Image clobbered**] ")
let TV = InputTextBuffer!0 eq 0 ? SavedLoadText,InputTextBuffer
if not ConfirmAct("Dump on ",TV) then return
MBOutStream = StreamFromTextName(QuickOpenFile,TV,".MB",
ksTypeWriteOnly,wordItem)
let OKFlag = false
[ OKFlag = ErrorProtect(lv ScanMBFiles,SavedLoadText,
TruePredicate,DumpSetMem,Noop,DumpSymbol,Noop)
Puts(MBOutStream,0)
]
Closes(MBOutStream)
if OKFlag ne 0 then ShowStats("Dumped ",false)
]
and CompareMB() be
[ let TV = InputTextBuffer!0 ne 0 ? InputTextBuffer,
(SavedLoadText!0 eq 0 ? 0,SavedLoadText)
if TV eq 0 do
[ WssCSS("Compare against ??file Name??"); return ]
if not ConfirmAct("Compare storage against ",TV) then return
MBOutStream = OpenFile("Midas.Errors",ksTypeWriteOnly,charItem,
verLatestCreate,ErrsFP,0,OverlayZone)
if MBOutStream eq 0 then DisplayError("Can't open Midas.Errors")
if ErrorProtect(lv ScanMBFiles,TV,
CompareData,Noop,BadType,Noop,BadType) do
[ test NWrong eq 0
ifso WssCSS("No errors")
ifnot
[ Wns(CmdCommentStream,NWrong,0,10)
WssCSS(" errors on Midas.Errors")
Puts(MBOutStream,15B)
if NWrong > 50 do
[ Wss(MBOutStream,"..."); Wns(MBOutStream,NWrong-50,0,10)
Wss(MBOutStream," more errors not recorded...*N")
]
]
]
Closes(MBOutStream)
]
and ScanMBFiles(TextVec,Data,SetMem,FixUp,SymDef,ExtFixUp) = valof
[ let PV,X,Y,Z,S = vec 72,1,1,1,nil; PV!0 = 72
unless ParseTextList(TextVec,lv X,PV,lv Y) then
DisplayError("No .MB file list given")
let DisplayOff = SetDisplay(true)
let OKFlag = 0
while Z < Y do
[ S = ErrorProtect(lv StreamFromTextName,QuickOpenFile,PV+Z,".MB",
ksTypeReadOnly,wordItem)
if S eq 0 then [ OKFlag = 0; break ]
OKFlag = ErrorProtect(lv GenMBIn,S,
Data,SetMem,FixUp,SymDef,ExtFixUp)
Closes(S); if OKFlag eq 0 then break
Z = Z+PV!Z+1
]
SetDisplay(DisplayOff); resultis OKFlag
]
and ShowStats(Str,ldPred) be
[ if ldPred do
[ Resets(ProgramStream); Wss(ProgramStream,"Loaded: ")
for I = 1 to SavedLoadText!0 do
Puts(ProgramStream,SavedLoadText!I)
]
if not Initialized then return
WssCSS(Str)
Wns(CmdCommentStream,NWords,0,10); WssCSS(" words, ")
Wns(CmdCommentStream,NAddresses,0,10); WssCSS(" addresses, ")
Wns(CmdCommentStream,NFixups,0,10); WssCSS(" fixups")
]
and BadType() be
[ DisplayError("Fixups on .MB file--can't compare until dumped")
]
and BadFix() be
[ DisplayError("Block type not external fixup on Midas.FixUps")
]
and WriteExtFixUp() be
[ if NExtFixUps eq 0 do
[ MBOutStream = OpenFile("Midas.Fixups",ksTypeReadWrite,wordItem,
verLatestCreate,FixUpFP,0,OverlayZone)
if MBOutStream eq 0 then
DisplayError("Unable to open Midas.Fixups")
]
NExtFixUps = NExtFixUps+1
WriteBlock(MBOutStream,InWds,InDn)
]
and DumpSetMem(MemX,BlockAddress,WordCount) be
[ if WordCount eq 0 then return
Puts(MBOutStream,9+(MemX lshift 8))
Puts(MBOutStream,BlockAddress)
Puts(MBOutStream,WordCount)
let AddrVec = vec 1; AddrVec!0 = 0; AddrVec!1 = BlockAddress
for I = 1 to WordCount do
[ GetMemData(MemX,AddrVec,CBuf)
for I = 0 to InWdWidth-1 do Puts(MBOutStream,CBuf!I)
AddrVec!1 = AddrVec!1+1
]
]
and ExtFixUp()
be
[ let SymbDef,SymbDefSize = vec size Symb/16,nil
unless FindInTable(StringVec,SymbDef,lv SymbDefSize)
& SymbDef>>Symb.A.Type eq AddrSymb do
[ DisplayError(" is undefined external","use 0",StringVec)
SymbDef>>Symb.A.A2 = 0; Resets(CmdCommentStream)
]
FixUp(SymbDef>>Symb.A.A2)
]
and FixUp(NewBits) be
[ let AVec,Bit1 = vec 1,(InWds!3)<<lh
AVec!0, AVec!1 = 0, InWds!2
let Buf = vec 6
let IMemX = XtoIMemX!(InWds!1)
GetMemData(IMemX,AVec,Buf)
PutField(Bit1,(InWds!3)<<rh-Bit1+1,Buf,NewBits)
PutMemData(IMemX,AVec,Buf)
NFixups = NFixups+1
]
and DumpSymbol(Str,Body,Size) be
[ Puts(MBOutStream,10+(Body>>Symb.A.X lshift 8))
Puts(MBOutStream,Body>>Symb.A.A2)
let N = Str>>lh rshift 1
for I = 0 to N do Puts(MBOutStream,Str!I)
]
and CompareData(MemX,AddrVec,DataVec) be
[ GetMemData(MemX,AddrVec,CBuf)
for I = 0 to InWdWidth-1 do
[ if DataVec!I ne CBuf!I do
[ NWrong = NWrong+1
if NWrong > 50 then return
Puts(MBOutStream,15B); Puts(MBOutStream,12B)
Wss(MBOutStream,MEMNAM!MemX)
Wns(MBOutStream,AddrVec!1,5,8)
Wss(MBOutStream," = ")
SearchBlocks(MBOutStream,MemX,AddrVec)
Wss(MBOutStream," was ")
MDatatoStream(MBOutStream,MemX,CBuf)
Wss(MBOutStream," should be ")
MDatatoStream(MBOutStream,MemX,DataVec); return
]
]
]
//InWds!0 = XMemX
//InWds!1 = memory width
//X holds name
and DefMem(X) be
[ let SymbDef,SymbDefSize = vec size Symb/16,nil
let XMemX,BitWidth = InWds!1,InWds!2
unless FindInTable(X,SymbDef,lv SymbDefSize) logand
SymbDef>>Symb.A.Type eq MemSymb
do DisplayError("Unknown memory name")
if SymbDef>>Symb.M.BitWidth ne BitWidth
then DisplayError("Mem width does not match")
XtoIMemX!XMemX = SymbDef>>Symb.M.X
XtoWdWidth!XMemX = (BitWidth+15) rshift 4
]
// In Vec stuff
and GenMBIn(Stream,Data,SetMem,FixUp,SymDef,ExtFixUp) = valof
[ if Stream eq 0 then CallSwat("Stream arg is 0 to GenMBIn")
InVecLeft,InWdWidth = 0,0
let MemX,AddrVec,Body = nil,vec 2,vec size Symb.A/16
let InExtX,BlockAddress,WordCount = nil,nil,0
Zero(AddrVec,2); Body>>Symb.A.Type = AddrSymb
while true do
[ if InVecLeft < 53 then if not Endofs(Stream) do
[ MoveBlock(InVec,InWds,InVecLeft)
InWds = InVec
InVecLeft = InVecLeft+ReadBlock(Stream,InVec+InVecLeft,ReadCnt)
]
switchon InWds>>rh into // Dispatch on block type
[
// Block types created by Micro
case 0: NWords = NWords+WordCount // terminating block
SetMem(MemX,BlockAddress,WordCount)
resultis -1
case 1: if InWdWidth le 0 then
DisplayError("Data word before setting memory in .MB")
InDn = InWdWidth+2 // data word
if not Data(MemX,AddrVec,InWds+2) then
DisplayError("Bad address for data word")
AddrVec!1 = AddrVec!1 + 1
WordCount = WordCount+1
endcase
case 2: InDn = 3 // set current memory
NWords = NWords+WordCount
SetMem(MemX,BlockAddress,WordCount)
InExtX = InWds!1; BlockAddress = InWds!2
AddrVec!1 = BlockAddress
MemX = XtoIMemX!InExtX
if MemX eq NotDefined % InExtX < 0 % InExtX > MaxExtMemX
then DisplayError("Illegal memory index in .MB")
InWdWidth = XtoWdWidth!InExtX
WordCount = 0; endcase
case 3: InDn = 5; FixUp(InWds!4) // fix up (forward ref)
endcase
case 4: InDn = ConvertMicroString(3) // memory def
DefMem(StringVec)
endcase
case 5: InDn = ConvertMicroString(3) // symbol def
Body>>Symb.A.X = XtoIMemX!(InWds!1)
Body>>Symb.A.A2 = InWds!2
SymDef(StringVec,Body,size Symb.A/16)
NAddresses = NAddresses+1
endcase
case 6: InDn = ConvertMicroString(4) // external fixup
ExtFixUp(); endcase
// New block types created by Dump
case 9: SetMem(MemX,BlockAddress,WordCount) // data block
NWords = NWords+WordCount
NDBlocks = NDBlocks+1
MemX = InWds>>lh; BlockAddress = InWds!1
AddrVec!1 = BlockAddress
WordCount = InWds!2
InWdWidth = (MEMWID!MemX + 15) rshift 4
InVecLeft = InVecLeft-3; InWds = InWds+3
for I = 1 to WordCount do
[ if InVecLeft < 53 then if not Endofs(Stream) do
[ MoveBlock(InVec,InWds,InVecLeft)
InWds = InVec
InVecLeft = InVecLeft+ReadBlock(Stream,InVec+InVecLeft,ReadCnt)
]
if not Data(MemX,AddrVec,InWds) then
DisplayError("Bad address or MemX in data block")
AddrVec!1 = AddrVec!1 + 1
InVecLeft = InVecLeft-InWdWidth
if InVecLeft < 0 then
DisplayError("Incomplete block terminating .MB file")
InWds = InWds+InWdWidth
]
loop
case 10: InDn = 3+((InWds!2)<<lh rshift 1) // symbol def (bcpl string)
Body>>Symb.A.X = InWds>>lh
Body>>Symb.A.A2 = InWds!1
SymDef(InWds+2,Body,size Symb.A/16)
NAddresses = NAddresses+1
endcase
default: DisplayError("Unknown block type")
]
InVecLeft = InVecLeft-InDn
if InVecLeft < 0 then
DisplayError("Incomplete block terminating .MB file")
InWds = InWds+InDn
]
]
// Arg is the number of words preceding the Micro text string
and ConvertMicroString(N) = valof
[ let MaxLen = InVecLeft-N
if MaxLen > 49 then MaxLen = 49
let W,R,L = nil,nil,0
for I = 0 to MaxLen do
[ W = InWds!(N+I); R = W<<lh; StringVec!I = L+R
if R eq 0 do [ StringVec>>lh = I+I; resultis N+I+1 ]
L = W lshift 8
if L eq 0 do [ StringVec>>lh = I+I+1; resultis N+I+1 ]
]
DisplayError("Bad block read from .MB file")
]