//MLOAD.BCPL // 9 May 1983 get "mcommon.d" get "mdecl.d" get "streams.d" external [ // OS SetBlock; Zero; CreateDiskStream; Resets; Puts Gets; PositionPage; Closes; Endofs; ReadBlock; WriteBlock Allocate; Free; Noop; TruePredicate // MIDAS MidasSwat; Initialized; TimeLoad; ElapsedTime // MASM Wss; @WssCSS; ResetsCSS VUsc; GetField; PutField; ErrorProtect; DoubleNeg // MDISP SetDisplay // MIOC Wns; DataToStream // MTXTBUF InputTextBuffer // MSYM StreamFromTextName; SkipBlankToken; FindInTable; SearchBlocks @StringVec // MSYMOV UpdateRcd; CleanUpBlocks // MOVERLAY OverlayZone // MCMD DisplayError; ErrorAbort; ConfirmAct; FormCmdMenu; WnsCSSD LoadDone; CmdCommentStream; SavedLoadText; ProgramStream; Confirmed // MINIT0 @MBlock; FixUpFP; ErrsFP // Resident machine-dependent files GetMemData; PutMemData @MEMNAM; @MEMWID; @MEMCON; @MEMFORMS; @ScreenWidth // Load overlay machine-dependent file PrepareLoad; RestoreAfterLoad; PutMDSymOnly; LoadCleanUp // Defined here InitLoad; LoadMB; LoadSyms; LoadData; DumpMB; CompareMB; DoingLoad ] static[ // local statics @MBOutStream; @CBuf; @XtoIMemX; @XtoWdWidth; DoingLoad = false @InVecLeft; @InWdWidth; @InWds; @InDn; @InVec NWrong; NAddresses; NFixups; NExtFixUps; NWords; NDBlocks ] manifest [ MaxExtMemX = 16 ; NotDefined = -100 ReadCnt = #4000 // Max word count read from .MB file //Note that the sum of InVecSize and the sizes of the Load and Directory //overlays must all fit in OverlayZone. InVecSize = ReadCnt+54 ] //lvProc points at LoadMB, LoadData, LoadSyms, DumpMB, or CompareMB //**Ugly binding of vec's to statics here** let InitLoad(lvProc,nil,nil) = valof [ let DisplayState = SetDisplay(true) InVec = Allocate(OverlayZone,InVecSize+1) let CBufv = vec ValSize-1 let XtoIMemXv = vec MaxExtMemX SetBlock(XtoIMemXv,NotDefined,MaxExtMemX) let XtoWdWidthv = vec MaxExtMemX CBuf,XtoIMemX,XtoWdWidth = CBufv,XtoIMemXv,XtoWdWidthv NWrong,NWords,NFixups,NExtFixUps,NAddresses,NDBlocks = 0,0,0,0,0,0 let OKFlag = ErrorProtect(lvProc) Confirmed = false Free(OverlayZone,InVec) if DoingLoad do [ DoingLoad = false ErrorProtect(lv RestoreAfterLoad) ] if OKFlag & Initialized & LoadDone then FormCmdMenu() SetDisplay(DisplayState) ElapsedTime(lv TimeLoad) resultis OKFlag ] and LoadSyms() = LoadX(UpdateRcd,0) and LoadData() = LoadX(ChkUpdateRcd,1) and LoadMB() = LoadX(UpdateRcd,2) and LoadX(SymOp,LoadType) = valof [ if InputTextBuffer!0 eq 0 then ErrorAbort("??file name??") if LoadDone do [ if not ConfirmAct(LoadType eq 0 ? "Merge symbols with ", "Overwrite ",SavedLoadText) then resultis false ] PrepareLoad(LoadType) //Don't ordinarily need Midas.FixUps, but have to open it now because //MemDef blocks have to be written before it is known whether or not //there are any external fixups. MBOutStream = CreateDiskStream(FixUpFP) //ksTypeReadWrite,wordItem if MBOutStream eq 0 then MidasSwat(NoFixups) //Save text of files being loaded for possible dump MBlock(SavedLoadText,InputTextBuffer,ScreenWidth) let DataOp,FixUpOp,ExtFixUpOp,DefMemOp = nil,nil,nil,nil test LoadType eq 0 ifso [ DataOp,FixUpOp = PutMDSymOnly,Noop ExtFixUpOp,DefMemOp = Noop,DefMem ] ifnot [ DataOp,FixUpOp = PutMemData,FixUp ExtFixUpOp,DefMemOp = WriteExtFixUp,DumpMemDef ] let OKFlag = ErrorProtect(lv ScanMBFiles,InputTextBuffer,DataOp, Noop,FixUpOp,SymOp,ExtFixUpOp,DefMemOp) if NExtFixUps ne 0 do [ if OKFlag ne 0 do [ PutsMBO(0); PositionPage(MBOutStream,1) OKFlag = ErrorProtect(lv GenMBIn,MBOutStream, BadFix,BadFix,BadFix,BadFix,ExtFixUp,DefMem) ] ] Closes(MBOutStream) test OKFlag eq 0 ifso SavedLoadText!0 = 0 ifnot [ if LoadType eq 0 then NWords = 0 ShowStats("Loaded ") if Initialized do [ Resets(ProgramStream); Wss(ProgramStream,"Loaded: ") for I = 1 to SavedLoadText!0 do Puts(ProgramStream,SavedLoadText!I) LoadDone = true ] ] CleanUpBlocks() //Write dirty in-core blocks on symtab file LoadCleanUp() //Build pointers into symtab file resultis OKFlag ] and DumpMB() = valof [ if SavedLoadText!0 eq 0 then ErrorAbort("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 resultis false MBOutStream = StreamFromTextName(TV,".MB",ksTypeWriteOnly,wordItem) PrepareLoad(false) let OKFlag = false OKFlag = ErrorProtect(lv ScanMBFiles,SavedLoadText, TruePredicate,DumpSetMem,Noop,DumpSymbol,Noop,DumpMemDef) PutsMBO(0) Closes(MBOutStream) if OKFlag ne 0 then ShowStats("Dumped ") resultis OKFlag ] and CompareMB() = valof [ let TV = InputTextBuffer!0 ne 0 ? InputTextBuffer,SavedLoadText if TV!0 eq 0 do ErrorAbort("Compare against ??file name??") if not ConfirmAct("Compare storage against ",TV) then resultis false MBOutStream = CreateDiskStream(ErrsFP,ksTypeWriteOnly,charItem) if MBOutStream eq 0 then MidasSwat(NoCompare) PrepareLoad(false) let OKFlag = ErrorProtect(lv ScanMBFiles,TV, CompareData,Noop,BadType,Noop,BadType,DefMem) if OKFlag do [ test NWrong eq 0 ifso WssCSS("No errors") ifnot [ WnsCSSD(NWrong); WssCSS(" errors on Midas.Compare") PutsMBO($*N) if NWrong > 50 do [ Wss(MBOutStream,"..."); Wns(MBOutStream,NWrong-50,0,10) Wss(MBOutStream," more errors not recorded...*N") ] ] ] Closes(MBOutStream); resultis OKFlag ] and ScanMBFiles(TV,Data,SetMem,FixUp,SymDef,ExtFixUp,MemDef) = valof [ let PV,X,Z,S = vec 72,1,1,nil; PV!0 = 72 while X le TV!0 do [ SkipBlankToken(TV,lv X) let Size = (TV!0) - X + 1 for I = X to TV!0 do if TV!I eq $, then [ Size = I - X; break ] if X+Size > PV!0 then ErrorAbort("No .MB file list given") PV!X = Size MBlock(PV+X+1,TV+X,Size) X = X+Size+1 //Skip comma in TV, Size in PV ] let OKFlag = 0 while Z < X do [ S = StreamFromTextName(PV+Z,".MB",ksTypeReadOnly,wordItem) //DoingLoad is a flag for PutMemData/GetMemData which may cause variant //operation of these procedures. It also determines whether or not //RestoreAfterLoad() is called. Avoid setting the flag until here so //that RestoreAfterLoad won't be called unless the hardware is touched. DoingLoad = true OKFlag = ErrorProtect(lv GenMBIn,S, Data,SetMem,FixUp,SymDef,ExtFixUp,MemDef) Closes(S); if OKFlag eq 0 then break Z = Z+PV!Z+1 ] resultis OKFlag ] and PutsMBO(Char) be Puts(MBOutStream,Char) and ShowStats(Str) be [ if Initialized do [ WssCSS(Str) WnsCSSD(NWords); WssCSS(" words, ") WnsCSSD(NAddresses); WssCSS(" addresses, ") WnsCSSD(NFixups); WssCSS(" fixups ") ] ] and BadType(NewBits) be [ ErrorAbort("Fixups on .MB file--can't compare until dumped") ] and BadFix(nil,nil,nil) be MidasSwat(BadFixupFile) and WriteExtFixUp(Str,VMemX,Ptr) be [ NExtFixUps = NExtFixUps+1 PutsMBO(12+(VMemX lshift 8)) PutsMBO(Ptr!0) PutsMBO(Ptr!1) ] //Write data block for previous SetMem/dblock when new SetMem/dblock //is seen or when EOF is seen. and DumpSetMem(InExtX,BlockAddress,WordCount) be [ if WordCount eq 0 then return PutsMBO(9+(InExtX lshift 8)) PutsMBO(BlockAddress) PutsMBO(WordCount) let AVec = vec 1; AVec!0 = 0; AVec!1 = BlockAddress let MemX = XtoIMemX!InExtX for I = 1 to WordCount do [ unless GetMemData(MemX,CBuf,AVec) do ErrorAbort("GetMemData failed for ",MEMNAM!MemX) WriteBlock(MBOutStream,CBuf,InWdWidth) AVec!1 = AVec!1+1 ] ] and ExtFixUp(Str,VMemX,Ptr) be [ let SymbDef,SymbDefSize = vec size Symb/16,nil unless FindInTable(Str,SymbDef,lv SymbDefSize) & SymbDef>>Symb.A.Type eq AddrSymb do [ DisplayError(" is und external","use 0",Str) SymbDef>>Symb.A.A2 = 0; ResetsCSS() ] FixUp(SymbDef>>Symb.A.A2,VMemX,Ptr) ] and FixUp(NewBits,VMemX,Ptr) be [ let AVec = vec 1 AVec!0, AVec!1 = 0, Ptr!0 let Bit1,LastBit = (Ptr+1)>>lh,(Ptr+1)>>rh let MemX = CheckMemX(VMemX,"Fixup") if (LastBit ge MEMWID!MemX) % (((LastBit-Bit1) & 177760B) ne 0) do ErrorAbort("Ill. fixup") NFixups = NFixups+1 if GetMemData(MemX,CBuf,AVec) do [ PutField(Bit1,LastBit-Bit1+1,CBuf,NewBits) if PutMemData(MemX,CBuf,AVec) then return ] ErrorAbort("Bad addr for fixup") ] and DumpSymbol(Str,Body,Size,InExtX) be [ PutsMBO(10+(InExtX lshift 8)) PutsMBO(Body>>Symb.A.A2) for I = 0 to Str>>lh rshift 1 do PutsMBO(Str!I) ] //LdData does not put addresses in the symbol table except those //in memories marked with the "load-anyway" bit. This aims mainly at //the "Loader.mb" file, which is sometimes loaded with symbols for //debugging, and sometimes not, to avoid poluting the symbol table. and ChkUpdateRcd(Str,Body,BodySize,InExtX) be [ if (MEMCON+(Body>>Symb.A.X))>>MRType.Retain ne 0 then UpdateRcd(Str,Body,BodySize) ] and CompareData(MemX,DVec,AVec) = valof [ unless GetMemData(MemX,CBuf,AVec) do resultis false if VUsc(DVec,CBuf,InWdWidth) ne 0 do [ NWrong = NWrong+1 if NWrong le 50 do [ Wss(MBOutStream,MEMNAM!MemX) Wns(MBOutStream,AVec!1,5,8) Wss(MBOutStream," = ") SearchBlocks(MBOutStream,MemX,AVec) Wss(MBOutStream," was ") DataToStream(MBOutStream,MEMFORMS!MemX,MEMWID!MemX,CBuf) Wss(MBOutStream," should be ") DataToStream(MBOutStream,MEMFORMS!MemX,MEMWID!MemX,DVec) PutsMBO($*n) ] ] resultis true ] and DumpMemDef(VMemX,BitWidth,Str) be [ PutsMBO(11+(VMemX lshift 8)) PutsMBO(BitWidth) WriteBlock(MBOutStream,Str,(Str>>lh rshift 1)+1) DefMem(VMemX,BitWidth,Str) ] and DefMem(VMemX,BitWidth,Str) be [ let SymbDef,SymbDefSize = vec size Symb/16,nil unless FindInTable(Str,SymbDef,lv SymbDefSize) & (SymbDef>>Symb.A.Type eq MemSymb) do ErrorAbort("Unknown mem name ",Str) let MemX = SymbDef>>Symb.M.X if MEMWID!MemX ne BitWidth then ErrorAbort("Mem width mismatch ",Str) XtoIMemX!VMemX = MemX XtoWdWidth!VMemX = (BitWidth+15) rshift 4 ] // In Vec stuff and GenMBIn(Stream,Data,SetMem,FixUp,SymDef,ExtFixUp,MemDef) = valof [ InVecLeft,InWdWidth,InDn = 0,0,0 let VMemX,MemX,Body = nil,nil,vec size Symb.A/16 let InExtX,BlockAddress,WordCount = nil,nil,0 Body>>Symb.A.Type = AddrSymb let AVec0,AVec1 = 0,nil let AVec = lv AVec0 //Arrange to manipulate AVec!1 directly [ FillVec(Stream) switchon InWds>>rh into // Dispatch on block type [ // Block types created by Micro case 0: NWords = NWords+WordCount // terminating block SetMem(InExtX,BlockAddress,WordCount) resultis -1 case 1: if InWdWidth le 0 then // data word ErrorAbort("Data word before SetMem") InDn = InWdWidth+2 if not Data(MemX,InWds+2,AVec) then ErrorAbort("Bad address for data word") AVec1 = AVec1 + 1; WordCount = WordCount+1 loop case 2: NWords = NWords+WordCount // set current memory SetMem(InExtX,BlockAddress,WordCount) WordCount = 0 InDn = 3 InExtX = InWds!1 BlockAddress = InWds!2 AVec1 = BlockAddress MemX = CheckMemX(InExtX,"SetMem block") InWdWidth = XtoWdWidth!InExtX; loop case 3: InDn = 5 // fixup FixUp(InWds!4,InWds!1,InWds+2) loop case 4: InDn = ConvertMicroString(3) // memory def MemDef(InWds!1,InWds!2,StringVec) loop case 5: InDn = ConvertMicroString(3) // symbol def VMemX = InWds!1 Body>>Symb.A.X = CheckMemX(VMemX,StringVec) Body>>Symb.A.A2 = InWds!2 SymDef(StringVec,Body,size Symb.A/16,VMemX) NAddresses = NAddresses+1 loop case 6: InDn = ConvertMicroString(4) // ext. fixup ExtFixUp(StringVec,InWds!1,InWds+2); loop // New block types created by Dump case 9: NWords = NWords+WordCount // data block SetMem(InExtX,BlockAddress,WordCount) NDBlocks = NDBlocks+1 InExtX = InWds>>lh MemX = CheckMemX(InExtX,"Data block") BlockAddress = InWds!1 AVec1 = BlockAddress WordCount = InWds!2 InWdWidth = XtoWdWidth!InExtX InDn = 3 for I = 1 to WordCount do [ FillVec(Stream) if not Data(MemX,InWds,AVec) then ErrorAbort("Bad addr in data block") AVec1 = AVec1 + 1 InDn = InWdWidth ] loop case 10: InDn = 3+((InWds!2)<<lh rshift 1) // symbol def (bcpl str) VMemX = InWds>>lh Body>>Symb.A.X = CheckMemX(VMemX,InWds+2) Body>>Symb.A.A2 = InWds!1 SymDef(InWds+2,Body,size Symb.A/16,VMemX) NAddresses = NAddresses+1 loop case 11: InDn = 3+((InWds!2)<<lh rshift 1) // memory def (bcpl str) MemDef(InWds>>lh,InWds!1,InWds+2) loop case 12: InDn = 4+((InWds!3)<<lh rshift 1) // ext. fixup (bcpl str) ExtFixUp(InWds+3,InWds>>lh,InWds+1); loop default: ErrorAbort("Bad blk type") ] ] repeat ] //*This is only use of InVecLeft and InDn outside GenMBIn and FillVec(Stream) be [ InVecLeft = InVecLeft-InDn if InVecLeft < 0 then ErrorAbort("Incom block ending .MB file") InWds = InWds+InDn if InVecLeft < 53 then if not Endofs(Stream) do [ MBlock(InVec,InWds,InVecLeft) InWds = InVec InVecLeft = InVecLeft+ReadBlock(Stream,InVec+InVecLeft,ReadCnt) ] ] // 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 ] ] test MaxLen eq 49 ifso [ StringVec>>lh = MaxLen ErrorAbort(StringVec," str too long in .MB file") ] ifnot ErrorAbort(".MB file truncated inside string") ] and CheckMemX(VMemX,Str) = valof [ if (VMemX & 177760B) eq 0 do [ let MemX = XtoIMemX!VMemX if MemX ne NotDefined then resultis MemX ] ErrorAbort(Str," ill. MemX") ]