-- MBImpl6.mesa -- Last Modified: Stewart 7-Jan-82 18:19:40 -- Converts an Intel absolute loader format file into --An MB format file for Prom blowing. -- ObjToMB infile outfile -[eob] -s romsize(dec) -a romaddress(hex) -- e: even bytes only, o: odd bytes only, b: both -- for even and odd, the address within the rom is divided by 2. DIRECTORY ComParse USING [Close, FreeString, Get, Open], Inline, IntelHex6, Storage USING [Words, FreeWords], StreamDefs, String, WF; MBImpl6: PROGRAM IMPORTS ComParse, Inline, IntelHex6, Storage, StreamDefs, String, WF = BEGIN iName: STRING _ NIL; oName: STRING _ NIL; token: STRING _ NIL; iS: StreamDefs.DiskHandle _ NIL; oS: StreamDefs.DiskHandle _ NIL; Mode: TYPE = {both, even, odd}; mode: Mode; Lose: SIGNAL = CODE; myIStream: IntelHex6.IStream _ [ endof: myEndOf, get: myGetByte, GetPosition: myGetPosition, SetPosition: mySetPosition ]; myOStream: IntelHex6.OStream _ [ PutEndRecord: myPutEndRecord, PutStartRecord: myPutStartRecord, DataByte: myDataByte ]; BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED]; And: BitOp = INLINE { RETURN[Inline.BITAND[a,b]]; }; Shift: BitOp = INLINE { RETURN[Inline.BITSHIFT[a,b]]; }; WordOp: TYPE = PROC [a: UNSPECIFIED] RETURNS [UNSPECIFIED]; Low: WordOp = INLINE { RETURN[Inline.LowHalf[a]]; }; High: WordOp = INLINE { RETURN[Inline.HighHalf[a]]; }; -- sum of bytes, contribution to checksum WordCk: PROC [c: CARDINAL] RETURNS [CARDINAL] = { v: Inline.BytePair _ LOOPHOLE[c]; RETURN [v.low+v.high]; }; -- The checksum is the value making sum of checked bytes equal zero. CkSum: PROC [c: CARDINAL] RETURNS [CARDINAL] = { v: INTEGER _ And[c, 377B]; v _ -v; v _ And[v, 377B]; RETURN [LOOPHOLE[v, CARDINAL]]; }; -- Write an end record. myPutEndRecord: IntelHex6.PutEndRecordProc = { NULL; }; -- Write a start record. myPutStartRecord: IntelHex6.PutStartRecordProc = { NULL; }; InitLocalStorage: PROC = { maxadr _ 0; }; GetHex: PROC [s: STRING] RETURNS [CARDINAL] = { c: CARDINAL _ 0; neg: BOOLEAN _ FALSE; FOR i: CARDINAL IN [0..s.length) DO SELECT s[i] FROM '- => neg _ TRUE; IN ['0..'9] => c _ (c*16)+(s[i]-'0); IN ['a..'f] => c _ (c*16)+(s[i]-'a)+10; IN ['A..'F] => c _ (c*16)+(s[i]-'A)+10; ENDCASE; ENDLOOP; IF neg THEN c _ 0-c; RETURN[c]; }; -- Write a data record after every byte filling a paragraph --Write a new extended address record first thing and --thereafter when the bank changes. Byte: TYPE = [0..377B]; data: DESCRIPTOR FOR PACKED ARRAY [0..8192) OF Byte; maxadr, rombase, romsize: CARDINAL; myDataByte: IntelHex6.DataByteProc = { locadr: CARDINAL; IF adr { IF And[Low[adr], 1] # 0 THEN RETURN; adr _ adr/2; -- right shift }; odd => { IF And[Low[adr], 1] = 0 THEN RETURN; adr _ adr/2; -- right shift }; ENDCASE; IF High[adr]#0 THEN { WF.WF0[" Address outside 64K!*n"]; SIGNAL Lose; }; IF adr >= (rombase+romsize) THEN RETURN; locadr _ Low[adr]; IF locadr > maxadr THEN maxadr _ locadr; data[locadr] _ d; }; OByte: PROC [x: CARDINAL] = INLINE { oS.put[oS, x]; }; OWord: PROC [x: CARDINAL] = INLINE { oS.put[oS, Inline.HighByte[x]]; oS.put[oS, Inline.LowByte[x]]; }; MakeMBFile: PROC = { OWord[4]; -- boilerplate OWord[1]; -- memorynumber OWord[8]; -- memorywidth in bits FOR i: CARDINAL IN [0..oName.length) DO OByte[oName[i]-0C]; ENDLOOP; OByte[0]; -- ASCIZ end of string -- pad to word boundary IF And[oName.length, 1] = 0 THEN OByte[0]; OWord[2]; -- set current memory and location OWord[1]; -- memorynumber again OWord[0]; -- location FOR i: CARDINAL IN [0..maxadr] DO OWord[1]; -- memory data word OWord[0]; -- source line number (not used) OWord[Shift[data[i], 8]]; -- left justified ENDLOOP; OWord[0]; -- end of file }; myEndOf: IntelHex6.EndOfProc = { RETURN[iS.endof[iS]]; }; myGetByte: IntelHex6.GetByteProc = { RETURN[iS.get[iS]]; }; myGetPosition: IntelHex6.GetPositionProc = { RETURN[StreamDefs.GetPosition[iS]]; }; mySetPosition: IntelHex6.SetPositionProc = { StreamDefs.SetPosition[iS, p]; }; myPutC: IntelHex6.PutCharProc = { WF.WFC[c]; }; -- Mainline code { CLState: TYPE = { in, out, done }; cls: CLState _ in; data _ DESCRIPTOR[Storage.Words[4096], 8192]; ComParse.Open[]; mode _ both; rombase _ 0; romsize _ 2048; DO token _ ComParse.Get[]; IF token = NIL THEN EXIT; IF token[0]#'- THEN SELECT cls FROM in => { iName _ token; cls _ out; LOOP; }; out => { oName _ token; cls _ done; LOOP; }; ENDCASE => { WF.WF0[" syntax errors*n"]; GOTO Cleanup; }; IF token.length<2 THEN { WF.WF0[" Bad switch*n"]; GOTO Cleanup; }; SELECT token[1] FROM 'e => { mode _ even; WF.WF0[" even mode*n"]; }; 'o => { mode _ odd; WF.WF0[" odd mode*n"]; }; 'b => { mode _ both; WF.WF0[" both mode*n"]; }; 's => { ComParse.FreeString[token]; token _ ComParse.Get[]; romsize _ String.StringToDecimal[token]; WF.WF1[" rom size = %d bytes*n", romsize]; IF romsize > 8192 THEN { WF.WF0[" Max rom capacity 8192*n"]; GOTO Cleanup; }; }; 'a => { ComParse.FreeString[token]; token _ ComParse.Get[]; rombase _ GetHex[token]; WF.WF1[" rom address = %x*n", rombase]; }; ENDCASE; ComParse.FreeString[token]; ENDLOOP; IF iName = NIL OR oName=NIL THEN { WF.WF0["Usage: ObjToMB filename outputfilename*n"L]; GOTO Cleanup; }; iS _ StreamDefs.NewByteStream[iName, StreamDefs.Read ! StreamDefs.FileNameError => { WF.WF1["ObjToMB %s: no such file*n"L, iName]; GOTO Cleanup; };]; oS _ StreamDefs.NewByteStream[oName, StreamDefs.Write + StreamDefs.Append]; iS.reset[iS]; oS.reset[oS]; InitLocalStorage[]; IF NOT IntelHex6.ProcessFile[in: myIStream, out: myOStream, errs: myPutC ! Lose => GOTO Cleanup] THEN WF.WF0[" Failed*n"]; MakeMBFile[]; GOTO Cleanup; EXITS Cleanup => { ComParse.Close[]; IF iS#NIL THEN iS.destroy[iS]; IF oS#NIL THEN oS.destroy[oS]; IF oName#NIL THEN ComParse.FreeString[oName]; IF iName#NIL THEN ComParse.FreeString[iName]; Storage.FreeWords[BASE[data]]; }; }; END. October 4, 1981 3:06 PM, LStewart; Created December 23, 1981 3:31 PM, LStewart; Suppress duplicate address records 2-Jan-82 11:45:27, LStewart; Use IntelHex6 January 7, 1982 11:22 AM, LStewart; Fewer extended address records January 7, 1982 5:52 PM, LStewart; MB files