MBImpl.mesa
Last Modified: Stewart December 22, 1983 3:39 pm
Converts an Intel absolute loader format file into
An MB format file for Prom blowing.
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.STREAMNIL;
oS: IO.STREAMNIL;
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]]; };
sum of bytes, contribution to checksum
WordCk: PROC [c: CARDINAL] RETURNS [CARDINAL] = {
v: Basics.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: IntelHex.PutEndRecordProc = {
NULL;
};
Write a start record.
myPutStartRecord: IntelHex.PutStartRecordProc = {
NULL;
};
InitLocalStorage: PROC = {
maxadr ← 0;
};
GetHex: PROC [s: Rope.ROPE] RETURNS [CARDINAL] = {
c: CARDINAL ← 0;
neg: BOOLEANFALSE;
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];
};
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];
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: INTLOOPHOLE[adr];
IF intadr<0 THEN {
out.PutF[" Address outside range of INT!\n"];
SIGNAL Lose;
};
IF intadr<rombase THEN RETURN;
IF intadr>LAST[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
pad to word boundary
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"];
};
Mainline code
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[];
process file list
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;
process data list
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;
};
};
documentation: Rope.ROPE = "Optional arguments in [], default values in (), explanations in {}, '* => repeatable\nObjToMb -hexfile inputfilename -outputfile outputfilename [-even -odd -both (both)] [-baseaddress HexRomBaseAddress (0)] [-romsize DecimalRomSize (2048)] [-fixup HexAddress HexValue]* [-binaryfile filename address count] [-keyfile filename address count fileOffset] [-fixupfile filename] [-mbname filename]\n";
Mainline code
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