//MDload1 -- first pass loader for Micro binaries // last edited July 5, 1980 8:35 AM get "mddecl.d" external // defined here [ Load1 // (sources, outs, tempzone, zone) ] external [ // OS Closes Puts; WriteBlock Allocate; Free MoveBlock; SetBlock; Zero Noop // Template PutTemplate // MDmain @IP @DMachine @NInstructions @IM @RM @IFUM // MDinit Version Xternal // MDerr Err ErrHeaderProc PutBlanks PutAddress PutName // MDload AllocInbuf OpenSource DoFixups Load LoadFile dataIM0; dataIM1; dataIM2 dataRM; dataIFUM; dataALUFM dataDISP; dataIMLOCK; dataIMMASK dataOther; dataSkip @mData @mWidths @mNames @mSymMax fixTab @Symbols; @SymLength // MDload0 sourceNameWidth ] structure V: // VERSION parameter [ machine byte version byte ] structure S0: // first word of symbol [ blank bit 1 char0 bit 7 blank bit 1 char1 bit 7 ] manifest [ nHash = 26 ] static [ maxMemX = 0 verMemX = -1 mCounts mSeen fixSyms nFix = 0 @fixPtr = 0 @outstrm; @outmemx = -1; @outaddr = -1 ] let Load1(sources, outs, tempzone, zone) be [ Symbols = Allocate(zone, SymLength) mNames = Allocate(zone, nMemX) mNames!IMmemx = "IM" mNames!RMmemx = "RM" mWidths = Allocate(zone, nMemX) SetBlock(mWidths, -1, nMemX) mData = Allocate(zone, nMemX) SetBlock(mData, dataOther, nMemX) mCounts = Allocate(tempzone, nMemX) Zero(IM, IMsize*lIM) Zero(RM, RMsize) mSeen = Allocate(tempzone, nMemX) SetBlock(mSeen, false, nMemX) mSymMax = Allocate(zone, nMemX) SetBlock(mSymMax, -1, nMemX) AllocInbuf(tempzone, 2000b) fixSyms = Allocate(tempzone, nHash) Load(sources, outs, tempzone, zone, LoadFile1) if verMemX ge 0 then mData!verMemX = dataSkip Version = (Version ls 0? 0, Version<<V.version) Err(PassMessage, "*NTotal of $Ob instructions", NInstructions) for i = maxMemX+1 to nMemX-1 do [ if mCounts!i ne 0 then Err(PassMessage, "$6UOb words in $S", mCounts!i, mNames!i) ] fixPtr = 0 ResolveSyms(Noop, WExt) // count undefined refs fixTab = Allocate(zone, fixPtr+1) fixPtr = fixTab ResolveSyms(storefix, WExt) @fixPtr = -1 if nFix ne 0 then [ test Xternal ifso Err(PassMessage, "$D external symbols:", nFix) ifnot Err(PassFatal, "$D undefined symbols:", nFix) let sym = nil for h = 0 to nHash-1 do [ let p = fixSyms!h while p ne 0 do [ fixPtr = 0 MapSym(p, WExt, (Xternal? -1, WExt), Noop) Err(PassMessage, " $P -- $D reference(s)", PutName, p+1, fixPtr/2) unless Xternal do // print all references [ let PrintRef(loc, sym) be [ test (loc&140000b) eq 140000b ifso Err(PassMessage, " IFU: InsSet=$O, opcode=$O", (loc rshift 8)&3, loc&377b) ifnot Err(PassMessage, " $P", PutAddress, loc&(IMsize-1)) ] MapSym(p, WExt, -1, PrintRef) ] p = @p ] ] ] Err(PassMessage, "") ] and LoadFile1(source, outs, tempzone, zone) be [ static [ sourceName ] let s = OpenSource(source) sourceName = source>>Source.pName source>>Source.niFirst = NInstructions source>>Source.niLast = NImax // in case of error outstrm = outs let load1EHP(s) be [ PutTemplate(s, "In $S:*N", sourceName) ErrHeaderProc = 0 ] ErrHeaderProc = load1EHP LoadFile(s, tempzone, zone, data1, sym1, mem1, fix1, xfix1) ErrHeaderProc = 0 Closes(s) source>>Source.niLast = NInstructions Err(PassMessage, "$S$P$6UOb instructions written $S", sourceName, PutBlanks, sourceNameWidth-sourceName>>BS.length, NInstructions-source>>Source.niFirst, source>>Source.pDate) ] and mem1(mdp, bp, zone) be [ let memx, width = mdp!1, mdp!2 if (memx le 0) % (memx ge nMemX) then Err(Fatal, "Illegal memory #$UO", memx) mWidths!memx = width let sp = mdp+3 let s = Allocate(zone, bp-sp) let n = 0 until sp>>bytes↑n eq 0 do [ s>>BS.char↑(n+1) = sp>>bytes↑n n = n+1 ] s>>BS.length = n memname(memx, s) let imwidth = nil // width of IM in output if memx eq IMmemx then // decide which machine [ switchon width into [ case 80: // Dorado model 0 case 96: // Dorado model 1 DMachine, maxMemX = width/48, 4 // = 1 or 2 imwidth = width-32 // = 48 or 64 mWidths!IFUMmemx = 32 mWidths!ALUFMmemx = 8 memname(IFUMmemx, "IFUM") memname(ALUFMmemx, "ALUFM") mData!IFUMmemx = dataIFUM mData!ALUFMmemx = dataALUFM mData!IMmemx = (width eq 80? dataIM1, dataIM2) endcase case 84: // D0 DMachine, maxMemX = 0, 2 imwidth = 64 mData!IMmemx = dataIM0 endcase default: maxMemX = 0 // illegal ] if (Version ge 0) & (DMachine ne Version<<V.machine) then Err(Fatal, "IM width disagrees with /V or with VERSION from file") mData!RMmemx = dataRM ] test memx gr maxMemX ifso // must be unknown or fake [ if StringEqual(s, "DISP") then [ mData!memx = dataDISP; return ] if StringEqual(s, "IMLOCK") then [ mData!memx = dataIMLOCK; return ] if StringEqual(s, "RVREL") then [ mData!memx = dataSkip; return ] if StringEqual(s, "VERSION") then [ verMemX = memx; return ] if StringEqual(s, "IMMASK") then [ mData!memx = dataIMMASK; return ] ] ifnot [ if memx le 0 then Err(Fatal, "Definition for unknown memory #$O $S ($O bits)", memx, s, width) unless width eq mWidths!memx do Err(Fatal, "Memory #$O not valid $S", memx, mNames!memx) ] if mSeen!memx return mSeen!memx = true // Copy memory def to output if memx eq IMmemx then mdp!2 = imwidth // output IM has different width WriteBlock(outstrm, mdp, bp-mdp) ] and memname(memx, s) be [ let ns = mNames!memx if (ns ne 0) & not StringEqual(ns, s) then Err(Fatal, "Memory #$O $S redefined as $S", memx, ns, s) mNames!memx = s ] and data1(bp, memx, addr, dwds) be // Data for unknown memory -- just copy unless undefined or VERSION test memx eq verMemX ifso dataVer(addr, bp!2) ifnot test mSeen!memx ifnot Err(Fatal, (memx eq 0? "Data word before address set", "Data for unknown memory $UO"), memx) ifso [ if (memx ne outmemx) % (addr ne outaddr+1) then [ Puts(outstrm, MBaddress) Puts(outstrm, memx) Puts(outstrm, addr) ] outmemx, outaddr = memx, addr WriteBlock(outstrm, bp, dwds) mCounts!memx = mCounts!memx+1 ] and dataVer(adr, v) be [ if adr eq 0 then [ if ((Version ge 0) & (Version ne v)) % ((DMachine ge 0) & (DMachine ne v<<V.machine)) then Err(Fatal, "File says VERSION=$UO -- disagrees with /V or with IM width", v) Version = v DMachine = v<<V.machine ] ] and sym1(ap, bp, zone) be // Save symbols for later output [ let memx, addr = ap!1, ap!2 unless mSeen!memx return // skip DISP, IMLOCK, RVREL, VERSION let sp = ap+3 let sval = AddSym(sp, 0, zone, 1)-1 sval>>Sym.memx = memx sval>>Sym.addr = addr if sval>>Sym.addr ne addr then Err(NonFatal, "$S symbol $P = $UO, >7777 not allowed", mNames!memx, PutName, sp, addr) if (memx ne IMmemx) & (addr gr mSymMax!memx) then mSymMax!memx = addr ] and fix1(bp) be // Fixup for unknown memory -- just copy WriteBlock(outstrm, bp, 5) and xfix1(ap, bp, zone) be [ let memx, addr, field = ap!1, ap!2, ap!3 let sp = ap+4 let lvptr = fixSyms+(@sp rem nHash) let sym = AddSym(sp, lvptr, zone, 3) if sym!-1 ls 0 then // new entry [ sym!-3, sym!-2, sym!-1 = WNull, WNull, WNull nFix = nFix+1 ] test (memx eq IMmemx) & ((field eq W1field) % (field eq W2field)) ifso [ let ip = IP(addr) test field eq W1field ifso [ ip>>IM.W1 = sym!-1; sym!-1 = addr ] ifnot [ ip>>IM.W2 = sym!-2; sym!-2 = addr ] ] ifnot test (memx eq IFUMmemx) & (field eq IFADfield) ifso [ (IFUM+addr*lIFUM)>>IFUM.IFAD = sym!-3; sym!-3 = addr ] ifnot test memx eq IMmemx ifso Err(PassFatal, "$P....External reference to $P", PutAddress, addr, PutName, sp) ifnot Err(PassFatal, "$S $UO....External reference to $P", mNames!memx, addr, PutName, sp) ] and StringEqual(s1, s2) = valof [ let n1 = s1>>BS.length if s2>>BS.length ne n1 resultis false for i = 1 to n1 do if s1>>BS.char↑i ne s2>>BS.char↑i resultis false resultis true ] and ResolveSyms(proc, skipval) be // Resolve external references [ if nFix ne 0 then for i = 0 to nHash-1 do [ let lvsym = fixSyms+i while @lvsym ne 0 do [ let sym, value = @lvsym, nil let rsym = FindSym(sym+1) test rsym ne 0 ifso [ value = (rsym!-1)<<Sym.addr nFix = nFix-1 @lvsym = @sym // remove symbol from chain ] ifnot [ value = WExt // save ptr to symbol in fixTab lvsym = sym ] MapSym(sym, value, skipval, proc) ] ] endfix: ] and MapSym(sym, value, skipval, proc) be // Map a procedure over all undefined references from a symbol [ let addr = sym!-1 until addr eq WNull do [ if value eq WExt then [ proc(addr, sym); fixPtr = fixPtr+2 ] let ip = IP(addr) addr = ip>>IM.W1 if value ne skipval then ip>>IM.W1 = value ] addr = sym!-2 until addr eq WNull do [ if value eq WExt then [ proc(addr+100000b, sym); fixPtr = fixPtr+2 ] let ip = IP(addr) addr = ip>>IM.W2 if value ne skipval then ip>>IM.W2 = value ] addr = sym!-3 until addr eq WNull do [ if value eq WExt then [ proc(addr+140000b, sym); fixPtr = fixPtr+2 ] let ip = IFUM+addr*lIFUM addr = ip>>IFUM.IFAD if value ne skipval then ip>>IFUM.IFAD = value ] ] and storefix(addr, sym) be @fixPtr, fixPtr!1 = addr, sym and FindSym(sp) = valof // Look up a symbol in Symbols, return 0 if missing. // The symbol is already in internal format (end marked by bit 0). [ let s0 = @sp let c0 = s0<<S0.char0 let ptr = Symbols! ((c0 ls 41b? 0, (c0-40b)*2) + (s0<<S0.char1 ge $N? 1, 0)) until ptr eq 0 do [ if ptr!1 eq s0 then // quick rejection check [ let sym, tsym = ptr+1, sp [ if @sym ls 0 resultis ptr sym, tsym = sym+1, tsym+1 ] repeatwhile @sym eq @tsym ] ptr = @ptr ] resultis 0 ] and AddSym(sp, lvptr, zone, extra) = valof // Look up a symbol, insert it if missing. // If lvptr=0, hash it into Symbols. // Keep the chain in increasing alphabetical order. [ let ep = sp until (@ep)<<rh eq 0 do [ @ep = @ep & 77577b ep = ep+1 ] let s0 = @sp // Pick up s0 before setting bit 0 in last word if (@ep eq 0) & (ep ne sp) then ep = ep-1 @ep = @ep+100000b let c0 = s0<<S0.char0 if lvptr eq 0 then lvptr = Symbols + ((c0 ls 41b? 0, (c0-40b)*2) + (s0<<S0.char1 ge $N? 1, 0)) until @lvptr eq 0 do [ if ((@lvptr)!1&77777b) ge s0 then // quick rejection check [ let sym, tsym = @lvptr+1, sp while @sym eq @tsym do [ if @sym ls 0 resultis @lvptr sym, tsym = sym+1, tsym+1 ] if (@sym&77777b) gr (@tsym&77777b) break // insert here ] lvptr = @lvptr ] if zone eq 0 resultis 0 // don't insert let nw = ep+1-sp let sym = Allocate(zone, nw+extra+1)+extra @sym = @lvptr @lvptr = sym MoveBlock(sym+1, sp, nw) if extra gr 0 then sym!-1 = -1 // mark as new resultis sym ]