<> <> <> <> DIRECTORY Basics, Commander USING [CommandProc, Register], CommandTool, Convert, FS USING [Error, StreamOpen], IntelHex, IO, Rope; MBImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, FS, Basics, IntelHex, IO, Rope = BEGIN iName: Rope.ROPE; oName: Rope.ROPE; mbName: Rope.ROPE; token: Rope.ROPE; iS: IO.STREAM _ NIL; oS: IO.STREAM _ NIL; out: IO.STREAM; argv: CommandTool.ArgumentVector; Mode: TYPE = {both, even, odd}; mode: Mode; FileType: TYPE = {hex, ascii, binary}; DataItem: TYPE = RECORD [address, value: INT]; FileItem: TYPE = RECORD [name: Rope.ROPE, type: FileType, address: INT, count: INT, fileOffset: INT]; Lose: SIGNAL = CODE; myIStream: IntelHex.IStream _ [ endof: myEndOf, get: myGetByte, GetPosition: myGetPosition, SetPosition: mySetPosition ]; myOStream: IntelHex.OStream _ [ PutEndRecord: myPutEndRecord, PutStartRecord: myPutStartRecord, DataByte: myDataByte ]; BitOp: TYPE = PROC [a, b: CARDINAL] RETURNS [CARDINAL]; And: BitOp = INLINE { RETURN[Basics.BITAND[a,b]]; }; Shift: BitOp = INLINE { RETURN[Basics.BITSHIFT[a,b]]; }; WordOp: TYPE = PROC [a: LONG CARDINAL] RETURNS [CARDINAL]; Low: WordOp = INLINE { RETURN[Basics.LowHalf[a]]; }; High: WordOp = INLINE { RETURN[Basics.HighHalf[a]]; }; <> WordCk: PROC [c: CARDINAL] RETURNS [CARDINAL] = { v: Basics.BytePair _ LOOPHOLE[c]; RETURN [v.low+v.high]; }; <> CkSum: PROC [c: CARDINAL] RETURNS [CARDINAL] = { v: INTEGER _ And[c, 377B]; v _ -v; v _ And[v, 377B]; RETURN [LOOPHOLE[v, CARDINAL]]; }; <> myPutEndRecord: IntelHex.PutEndRecordProc = { NULL; }; <> myPutStartRecord: IntelHex.PutStartRecordProc = { NULL; }; InitLocalStorage: PROC = { maxadr _ 0; }; GetHex: PROC [s: Rope.ROPE] RETURNS [CARDINAL] = { c: CARDINAL _ 0; neg: BOOLEAN _ FALSE; FOR i: INT IN [0..s.Length[]) DO SELECT s.Fetch[i] FROM '- => neg _ TRUE; IN ['0..'9] => c _ (c*16)+(s.Fetch[i]-'0); IN ['a..'f] => c _ (c*16)+(s.Fetch[i]-'a)+10; IN ['A..'F] => c _ (c*16)+(s.Fetch[i]-'A)+10; ENDCASE; ENDLOOP; IF neg THEN c _ 0-c; RETURN[c]; }; <> <> <> Byte: TYPE = [0..377B]; DataRec: TYPE = RECORD [s: PACKED SEQUENCE size: NAT OF Byte]; data: REF DataRec; maxadr, rombase, romsize: INT; dataList: LIST OF REF DataItem; fileList: LIST OF REF FileItem; myDataByte: IntelHex.DataByteProc = { locadr: CARDINAL; intadr: INT _ LOOPHOLE[adr]; IF intadr<0 THEN { out.PutF[" Address outside range of INT!\n"]; SIGNAL Lose; }; IF intadrLAST[CARDINAL] THEN { out.PutF[" Address outside 64K!\n"]; SIGNAL Lose; }; intadr _ intadr-rombase; SELECT mode FROM even => { IF And[Low[intadr], 1] # 0 THEN RETURN; intadr _ intadr/2; -- right shift }; odd => { IF And[Low[intadr], 1] = 0 THEN RETURN; intadr _ intadr/2; -- right shift }; ENDCASE; IF intadr >= romsize THEN RETURN; locadr _ Low[intadr]; IF locadr > maxadr THEN maxadr _ locadr; data[locadr] _ d; }; OByte: PROC [x: CARDINAL] = INLINE { oS.PutChar[LOOPHOLE[x]]; }; OWord: PROC [x: CARDINAL] = INLINE { oS.PutChar[LOOPHOLE[Basics.HighByte[x]]]; oS.PutChar[LOOPHOLE[Basics.LowByte[x]]]; }; MakeMBFile: PROC = { namelength: INT _ mbName.Length[]; OWord[4]; -- boilerplate OWord[1]; -- memorynumber OWord[8]; -- memorywidth in bits FOR i: INT IN [0..namelength) DO OByte[mbName.Fetch[i]-0C]; ENDLOOP; OByte[0]; -- ASCIZ end of string <> IF And[Low[namelength], 1] = 0 THEN OByte[0]; OWord[2]; -- set current memory and location OWord[1]; -- memorynumber again OWord[0]; -- location FOR i: INT 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: IntelHex.EndOfProc = { RETURN[iS.EndOf[]]; }; myGetByte: IntelHex.GetByteProc = { RETURN[LOOPHOLE[iS.GetChar[]]]; }; myGetPosition: IntelHex.GetPositionProc = { RETURN[iS.GetIndex[]]; }; mySetPosition: IntelHex.SetPositionProc = { iS.SetIndex[p]; }; myPutC: IntelHex.PutCharProc = { out.PutChar[c]; }; ProcessBinaryFile: PROC [f: REF FileItem] = { address: INT _ f.address; THROUGH [0..f.count) DO myDataByte[adr: address, d: Basics.LowByte[myGetByte[]]]; address _ address + 1; ENDLOOP; }; ProcessAsciiFile: PROC [f: REF FileItem] = { address, value: INT; token: Rope.ROPE; out.PutF[" "]; DO token _ IO.GetTokenRope[iS].token; IF token.Length[] = 0 THEN EXIT; address _ GetHex[token]; token _ IO.GetTokenRope[iS].token; IF token.Length[] = 0 THEN EXIT; value _ GetHex[token]; WHILE ~iS.EndOf[] AND iS.GetChar[] # '\n DO NULL ENDLOOP; out.PutF["(%04x, %02x) ", IO.int[address], IO.int[value]]; myDataByte[adr: address, d: Basics.LowByte[Low[value]]]; ENDLOOP; out.PutF["\n"]; }; <> Main: Commander.CommandProc = { argIndex: NAT _ 1; NextToken: PROC RETURNS [t: Rope.ROPE] = { IF argIndex >= argv.argc THEN RETURN [NIL]; t _ argv[argIndex]; argIndex _ argIndex + 1; }; Case: PROC [c: Rope.ROPE] RETURNS [BOOL] = { RETURN [Rope.Equal[c, token, FALSE]]; }; out _ cmd.out; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; CONTINUE; }]; IF argv = NIL THEN RETURN[$Failure, msg]; mode _ both; rombase _ 0; romsize _ 2048; dataList _ NIL; fileList _ NIL; iS _ NIL; oS _ NIL; DO token _ NextToken[]; IF token.Length[]=0 THEN EXIT; SELECT TRUE FROM Case["-hexfile"] => { fileList _ CONS[NEW[FileItem _ [name: NextToken[], type: hex, address: 0, count: 0, fileOffset: 0]], fileList]; }; Case["-outputfile"] => oName _ NextToken[]; Case["-mbname"] => mbName _ NextToken[]; Case["-even"] => mode _ even; Case["-odd"] => mode _ odd; Case["-both"] => mode _ both; Case["-romsize"] => romsize _ Convert.IntFromRope[NextToken[]]; Case["-baseaddress"] => rombase _ GetHex[NextToken[]]; Case["-fixup"] => { dataAddress, dataValue: INT; dataAddress _ GetHex[NextToken[]]; dataValue _ GetHex[NextToken[]]; dataList _ CONS[NEW[DataItem _ [address: dataAddress, value: dataValue]], dataList]; }; Case["-binaryfile"] => { fileName: Rope.ROPE; fileAddress, fileCount: INT; fileName _ NextToken[]; fileAddress _ GetHex[NextToken[]]; fileCount _ Convert.IntFromRope[NextToken[]]; fileList _ CONS[NEW[FileItem _ [name: fileName, type: binary, address: fileAddress, count: fileCount, fileOffset: 0]], fileList]; }; Case["-keyfile"] => { fileName: Rope.ROPE; fileAddress, fileCount, fileOffset: INT; fileName _ NextToken[]; fileAddress _ GetHex[NextToken[]]; fileCount _ Convert.IntFromRope[NextToken[]]; fileOffset _ GetHex[NextToken[]]; fileList _ CONS[NEW[FileItem _ [name: fileName, type: binary, address: fileAddress, count: fileCount, fileOffset: fileOffset]], fileList]; }; Case["-fixupfile"] => { fileList _ CONS[NEW[FileItem _ [name: NextToken[], type: ascii, address: 0, count: 0, fileOffset: 0]], fileList]; }; ENDCASE => { out.PutF["Unknown switch token: %s\n", IO.rope[token]]; LOOP; }; ENDLOOP; IF romsize NOT IN[0..LAST[NAT]] THEN { out.PutF["Romsize must be positive and less than 32768!\n"]; GOTO Cleanup; }; IF oName.Length[] = 0 THEN { out.PutF[" no output file specified\n"]; GOTO Cleanup; }; IF mbName.Length[] = 0 THEN mbName _ oName; out.PutF[" output file = %s\n", IO.rope[oName]]; out.PutF[" mb file name = %s\n", IO.rope[mbName]]; out.PutF[" rom size = %d bytes\n", IO.int[romsize]]; out.PutF[" rom address = %x\n", IO.int[rombase]]; data _ NEW[DataRec[Basics.LowHalf[romsize]]]; oS _ FS.StreamOpen[oName, $create]; InitLocalStorage[]; <> WHILE fileList # NIL DO iName _ fileList.first.name; out.PutF[" file: %s, type=%s, address=%04x, count = %d\n", IO.rope[fileList.first.name], IO.rope[SELECT fileList.first.type FROM hex => "hex", binary => "binary", ascii => "ascii", ENDCASE => ERROR], IO.int[fileList.first.address], IO.int[fileList.first.count]]; iS _ FS.StreamOpen[iName ! FS.Error => TRUSTED { out.PutF["ObjToMB %s: no such file\n", IO.rope[iName]]; GOTO Cleanup; };]; iS.SetIndex[fileList.first.fileOffset]; SELECT fileList.first.type FROM hex => { IF NOT IntelHex.ProcessFile[in: myIStream, out: myOStream, errs: myPutC ! Lose => { iS.Close[]; GOTO Cleanup; }] THEN out.PutF[" Hex File processing of %s failed*n", IO.rope[iName]]; }; ascii => ProcessAsciiFile[fileList.first]; binary => ProcessBinaryFile[fileList.first]; ENDCASE => ERROR; iS.Close[]; iS _ NIL; fileList _ fileList.rest; ENDLOOP; <> WHILE dataList # NIL DO out.PutF[" fixup: address = %04x, data = %04x\n", IO.int[dataList.first.address], IO.int[dataList.first.value]]; myDataByte[adr: dataList.first.address, d: Basics.LowByte[Low[dataList.first.value]]]; myDataByte[adr: dataList.first.address+1, d: Basics.HighByte[Low[dataList.first.value]]]; dataList _ dataList.rest; ENDLOOP; MakeMBFile[]; GOTO Cleanup; EXITS Cleanup => { IF iS#NIL THEN iS.Close[]; IF oS#NIL THEN oS.Close[]; oName _ NIL; iName _ NIL; data _ NIL; dataList _ NIL; fileList _ NIL; }; }; <> <> Commander.Register["ObjToMb", Main, "Convert Intel format binary object files to .mb files"]; 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 March 19, 1982 4:20 pm, L. Stewart, convert to Cedar 2.5.1 May 5, 1982 4:42 pm, L. Stewart, extensions, Cedar 3 March 19, 1983 5:46 pm, L. Stewart, Cedar 4.0 April 29, 1983 1:17 pm, L. Stewart, added keyfile facility June 12, 1983 5:24 pm, L. Stewart, Cedar 4.2 December 22, 1983 3:39 pm, L. Stewart, Cedar 5