-- file: MBImpl.mesa -- last modified by McCreight, August 18, 1981 5:10 PM -- written by McCreight, August 4, 1981 2:44 PM DIRECTORY InlineDefs: FROM "InlineDefs", MB: FROM "MB", StreamDefs: FROM "StreamDefs", StringDefs: FROM "StringDefs"; MBImpl: PROGRAM IMPORTS InlineDefs,StringDefs EXPORTS MB = PUBLIC BEGIN OPEN MB; IllegalMBFormat: SIGNAL = CODE; curMB: MBHandle ← NIL; curMem: MBMemoryPtr ← NIL; -- always in curMB curWord: MBWordPtr ← NIL; -- always in curMem ReadMB: PROCEDURE [ s: StreamDefs.StreamHandle -- a word stream -- , z: UNCOUNTED ZONE] RETURNS [mb: MBHandle] = BEGIN FakeItem: TYPE = ARRAY [0..99] OF WORD; fakeItem: FakeItem; item: LONG POINTER TO MBItem ← LONG[LOOPHOLE[@fakeItem]]; curLC: CARDINAL; -- in curMem GetNextItem: PROCEDURE = BEGIN -- fakeItem and item must lie in the same storage i: CARDINAL; fakeItem[0] ← s.get[s]; SELECT item.itemType FROM end => RETURN; dataWord => FOR i IN [1..1 + (curMem.width + 15)/16] DO fakeItem[i] ← s.get[s] ENDLOOP; setLC => FOR i IN [1..2] DO fakeItem[i] ← s.get[s] ENDLOOP; fixup => FOR i IN [1..4] DO fakeItem[i] ← s.get[s] ENDLOOP; memName, addrSym => BEGIN FOR i IN [1..2] DO fakeItem[i] ← s.get[s] ENDLOOP; FOR i IN [3..99] DO c: PACKED ARRAY [0..1] OF CHARACTER; fakeItem[i] ← s.get[s]; c ← LOOPHOLE[fakeItem[i], PACKED ARRAY [0..1] OF CHARACTER]; IF c[0] = 0C OR c[1] = 0C THEN EXIT; ENDLOOP; END; extRef => BEGIN FOR i IN [1..3] DO fakeItem[i] ← s.get[s] ENDLOOP; FOR i IN [4..99] DO c: PACKED ARRAY [0..1] OF CHARACTER; fakeItem[i] ← s.get[s]; c ← LOOPHOLE[fakeItem[i], PACKED ARRAY [0..1] OF CHARACTER]; IF c[0] = 0C OR c[1] = 0C THEN EXIT; ENDLOOP; END; ENDCASE; END; FindMem: PROCEDURE [memNo: CARDINAL] RETURNS [m: MBMemoryPtr] = { FOR m ← mb, m.nextMem UNTIL m = NIL OR m.memNo = memNo DO ENDLOOP}; mb ← NIL; s.reset[s]; DO GetNextItem[]; WITH ditem: item SELECT FROM end => EXIT; dataWord => BEGIN w: MBWordPtr ← FindWord[curMem, curLC]; FOR i: CARDINAL IN [0..curMem.width) DO w.value[i] ← ditem.bits[i] ENDLOOP; curLC ← curLC + 1; END; setLC => BEGIN curMem ← FindMem[ditem.memNo]; curLC ← ditem.location; END; fixup => BEGIN w: MBWordPtr ← FindWord[FindMem[ditem.memNo], ditem.location]; FOR i: CARDINAL IN [ditem.firstBit..ditem.lastBit] DO w.value[i] ← ditem.bits[i - ditem.firstBit] ENDLOOP; END; memName => BEGIN nameLen: CARDINAL; mb ← z.NEW[ MBMemory ← [ zone: z, nextMem: mb, name: NIL, memNo: ditem.memNo, length: 0, width: ditem.width, words: NIL, symbols: NIL]]; FOR nameLen ← 0, nameLen + 1 WHILE ditem.name[nameLen] # 0C DO ENDLOOP; mb.name ← z.NEW[StringBody [nameLen]]; FOR i: CARDINAL IN [0..nameLen) DO mb.name[i] ← ditem.name[i] ENDLOOP; mb.name.length ← nameLen; END; addrSym => BEGIN nameLen: CARDINAL; m: MBMemoryPtr ← FindMem[ditem.memNo]; m.symbols ← z.NEW[ MBSym ← [nextSym: m.symbols, location: ditem.location, name: NIL]]; FOR nameLen ← 0, nameLen + 1 WHILE ditem.name[nameLen] # 0C DO ENDLOOP; m.symbols.name ← z.NEW[StringBody [nameLen]]; FOR i: CARDINAL IN [0..nameLen) DO m.symbols.name[i] ← ditem.name[i] ENDLOOP; m.symbols.name.length ← nameLen; END; ENDCASE => SIGNAL IllegalMBFormat; ENDLOOP; END; -- of ReadMB FreeMBMemory: PROCEDURE [memP: LONG POINTER TO MBMemoryPtr] = BEGIN IF curMB = memP↑ THEN curMB ← NIL; IF memP↑ # NIL THEN BEGIN m: MBMemoryPtr ← memP↑; z: UNCOUNTED ZONE ← m.zone; z.FREE[@m.name]; FreeMBMemoryWords[m]; FreeMBMemorySymbols[m]; memP↑ ← m.nextMem; z.FREE[@m]; END; END; FreeMBMemoryWords: PROCEDURE [mem: MBMemoryPtr] = BEGIN WHILE mem.words # NIL DO w: MBWordPtr ← mem.words; mem.words ← w.nextWord; mem.zone.FREE[@w]; ENDLOOP; END; FreeMBMemorySymbols: PROCEDURE [mem: MBMemoryPtr] = BEGIN WHILE mem.symbols # NIL DO s: MBSymPtr ← mem.symbols; mem.symbols ← s.nextSym; mem.zone.FREE[@s.name]; mem.zone.FREE[@s]; ENDLOOP; END; FreeMB: PROCEDURE [mb: MBHandle] = { WHILE mb # NIL DO FreeMBMemory[@mb] ENDLOOP}; FindWord: PROCEDURE [m: MBMemoryPtr, location: LONG CARDINAL] RETURNS [w: MBWordPtr] = BEGIN -- words appear in address order lastw: MBWordPtr ← NIL; w ← IF m = curMem AND curWord # NIL AND curWord.location <= location THEN curWord ELSE m.words; WHILE w # NIL AND w.location < location DO lastw ← w; w ← w.nextWord ENDLOOP; IF w = NIL OR location < w.location THEN BEGIN -- insert a new word w ← m.zone.NEW[ MBWord [m.width] ← [nextWord: w, location: location, value: NULL]]; FOR i: CARDINAL IN [0..m.width) DO w.value[i] ← FALSE ENDLOOP; IF lastw = NIL THEN m.words ← w ELSE lastw.nextWord ← w; END; IF m = curMem THEN curWord ← w; END; -- of FindWord FindMBMemory: PROCEDURE [mb: MBHandle, memName: STRING] RETURNS [MBMemoryPtr] = BEGIN FOR mem: MBMemoryPtr ← mb, mem.nextMem WHILE mem # NIL DO IF EquivalentLongStrings[mem.name, memName] THEN RETURN[mem]; ENDLOOP; RETURN[NIL]; END; AnalyzeMemory: PROCEDURE [mem: MBMemoryPtr] RETURNS [decodeWidth, wordCount, wordWidth: CARDINAL] = BEGIN maxAddress: LONG CARDINAL ← 0; wordWidth ← mem.width; decodeWidth ← 0; wordCount ← 0; FOR w: MBWordPtr ← mem.words, w.nextWord WHILE w # NIL DO WHILE w.location > maxAddress DO maxAddress ← 2*maxAddress+1; decodeWidth ← decodeWidth + 1; ENDLOOP; wordCount ← wordCount + 1; ENDLOOP; END; -- of AnalyzeMemory SuppressDefaultWords: PROCEDURE [mem: MBMemoryPtr, default: BOOLEAN] = BEGIN pWord: LONG POINTER TO MBWordPtr ← @mem.words; FOR w: MBWordPtr ← pWord↑, pWord↑ WHILE w # NIL DO FOR i: CARDINAL IN [0..mem.width) DO IF w.value[i] # default THEN GOTO notDefault; REPEAT notDefault => pWord ← @w.nextWord; FINISHED => {t: MBWordPtr ← w; pWord↑ ← w.nextWord; mem.zone.FREE[@t]}; ENDLOOP; ENDLOOP; END; ReCast: PROCEDURE [mem: MBMemoryPtr, newWordWidth: CARDINAL] = BEGIN -- steals low-order address bits to widen the word by a power of 2. -- puts all original bit 0's together, then all bit 1's, then bit 2's, etc. newMem: MBMemory ← mem↑; factor: CARDINAL; FOR factor ← 1, 2*factor WHILE factor*mem.width<newWordWidth DO ENDLOOP; newMem.width ← factor*mem.width; newMem.words ← NIL; curMem ← NIL; FOR w: MBWordPtr ← mem.words, w.nextWord WHILE w#NIL DO newW: MBWordPtr ← FindWord[@newMem, w.location/factor]; FOR i: CARDINAL IN [0..mem.width) DO newW.value[InlineDefs.LowHalf[factor*i+(w.location MOD factor)]] ← w.value[i]; ENDLOOP; ENDLOOP; FreeMBMemoryWords[mem]; FreeMBMemorySymbols[@newMem]; mem↑ ← newMem; END; PermuteAddress: PROCEDURE [mem: MBMemoryPtr, p: PermutationPtr] = BEGIN newMem: MBMemory ← mem↑; newMem.words ← NIL; curMem ← NIL; FOR w: MBWordPtr ← mem.words, w.nextWord WHILE w#NIL DO loc: LONG CARDINAL ← 0; newW: MBWordPtr; FOR i: CARDINAL DECREASING IN [0..p.length) DO WITH p.seq[i] SELECT FROM constantFalse => loc ← 2*loc+(IF invert THEN 1 ELSE 0); addrBit => loc ← 2*loc+(IF InlineDefs.BITXOR[invert, w.value[index]] THEN 1 ELSE 0); ENDCASE; ENDLOOP; newW ← FindWord[@newMem, loc]; FOR i: CARDINAL IN [0..mem.width) DO newW.value[i] ← w.value[i]; ENDLOOP; ENDLOOP; FreeMBMemoryWords[mem]; FreeMBMemorySymbols[@newMem]; mem↑ ← newMem; END; PermuteData: PROCEDURE [mem: MBMemoryPtr, p: PermutationPtr] = BEGIN newMem: MBMemory ← mem↑; newMem.width ← p.length; newMem.words ← NIL; curMem ← NIL; FOR w: MBWordPtr ← mem.words, w.nextWord WHILE w#NIL DO newW: MBWordPtr ← FindWord[@newMem, w.location]; FOR i: CARDINAL IN [0..p.length) DO WITH p.seq[i] SELECT FROM constantFalse => newW.value[i] ← invert; addrBit => newW.value[i] ← InlineDefs.BITXOR[invert, w.value[index]]; ENDCASE; ENDLOOP; ENDLOOP; FreeMBMemoryWords[mem]; mem↑ ← newMem; END; FindMBBit: PROCEDURE [ mb: MBHandle, memName: STRING, word: LONG CARDINAL, bit: CARDINAL] RETURNS [BOOLEAN] = BEGIN lastWord: MBWordPtr; IF curMB # mb OR curMem = NIL OR NOT EquivalentLongStrings[memName, curMem.name] THEN BEGIN curMB ← mb; curMem ← mb; curWord ← NIL; FOR curMem ← mb, curMem.nextMem UNTIL curMem = NIL OR EquivalentLongStrings[memName, curMem.name] DO ENDLOOP; END; IF curWord = NIL OR word < curWord.location THEN curWord ← curMem.words; lastWord ← curWord; WHILE curWord # NIL AND curWord.location < word DO lastWord ← curWord; curWord ← curWord.nextWord; ENDLOOP; IF word = curWord.location THEN RETURN[curWord.value[bit]] ELSE {curWord ← lastWord -- for next search -- ; RETURN[FALSE]}; END; -- of FindMBBit EquivalentLongStrings: PROCEDURE [a, b: LONG STRING] RETURNS [BOOLEAN] = BEGIN IF a.length # b.length THEN RETURN[FALSE]; FOR i: CARDINAL IN [0..a.length) DO IF StringDefs.UpperCase[a[i]] # StringDefs.UpperCase[b[i]] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]; END; END. -- of MBImpl