-- HexImpl6.mesa
-- Last Modified: Stewart January 7, 1982 11:22 AM
-- Converts an Intel absolute loader format file into
--Intel hexadecimal absolute loader format.
DIRECTORY
ComParse USING [Close, FreeString, Get, Open],
Inline,
IntelHex6,
StreamDefs,
WF;
HexImpl6: PROGRAM
IMPORTS ComParse, Inline, IntelHex6, StreamDefs, WF =
BEGIN
iName: STRING ← NIL;
oName: STRING ← NIL;
switches: STRING ← NIL;
iS: StreamDefs.DiskHandle ← NIL;
oS: StreamDefs.DiskHandle ← NIL;
Mode: TYPE = {both, even, odd};
mode: Mode;
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 = {
DataFlush[];
WF.FWF0[oS, ":00000001FF*n"L];
};
-- Write a start record.
myPutStartRecord: IntelHex6.PutStartRecordProc = {
ck: CARDINAL;
DataFlush[];
ck ← CkSum[4+3+WordCk[frame]+WordCk[bytepos]];
WF.FWF3[oS, ":04000003%04x%04x%02x*n"L, frame, bytepos, ck];
};
-- Write an extended address record.
PutAddress: PROC [frame: CARDINAL] = {
ck: CARDINAL ← CkSum[2+2+WordCk[frame]];
WF.FWF2[oS, ":02000002%04x%02x*n"L, frame, ck];
};
InitLocalStorage: PROC = {
gfirst ← gda ← LAST[LONG CARDINAL];
gptr ← oldframe ← LAST[CARDINAL];
frameinit ← FALSE;
};
-- Write a data record after every byte filling a paragraph
--Write a new extended address record first thing and
--thereafter when the bank changes.
-- global variables for data address
-- gfirst is the next address not yet written out
-- gda is the expected next byte arriving from DataByte
-- gptr is pointer into cache
-- oldframe is the frame of the last extended address record
-- frameinit is a first-time through flag
gfirst, gda: LONG CARDINAL;
gptr, oldframe: CARDINAL;
gdata: ARRAY [0..16) OF CARDINAL;
frameinit: BOOLEAN;
NewDataAddress: PROC [addr: LONG CARDINAL] = {
gptr ← 0;
gfirst ← gda ← addr;
IF NOT frameinit OR oldframe#High[addr] THEN {
PutAddress[frame: High[addr]];
oldframe ← High[addr];
frameinit ← TRUE;
};
};
myDataByte: IntelHex6.DataByteProc = {
SELECT mode FROM
even => {
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 NOT frameinit THEN NewDataAddress[adr];
IF adr#gda OR High[adr]#oldframe THEN {
DataFlush[];
NewDataAddress[adr];
};
gdata[gptr] ← d;
gptr ← gptr+1;
gda ← adr+1;
IF And[Low[gda], 17B] = 0 THEN DataFlush[];
};
DataFlush: PROC = {
outChecksum: CARDINAL ← 0;
IF gptr=0 THEN RETURN;
WF.FWF2[oS, ":%02x%04x00"L, gptr, Low[gfirst]];
outChecksum ← gptr + WordCk[Low[gfirst]];
FOR i: CARDINAL IN [0..gptr) DO
WF.FWF1[oS, "%02x"L, gdata[i]];
outChecksum ← outChecksum + gdata[i];
ENDLOOP;
WF.FWF1[oS, "%02x*n"L, CkSum[outChecksum]];
gptr ← 0;
gfirst ← gda;
};
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
{
ComParse.Open[];
iName ← ComParse.Get[];
IF iName = NIL THEN {
WF.WF0["Usage: Hex filename outputfilename*n"L];
GOTO Cleanup;
};
oName ← ComParse.Get[];
IF oName=NIL THEN {
WF.WF0["Usage: Hex filename outputfilename*n"L];
GOTO Cleanup;
};
switches ← ComParse.Get[];
mode ← both;
IF switches = NIL THEN mode ← both
ELSE {
FOR i: CARDINAL IN [0..switches.length) DO
SELECT switches[i] 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"]; };
ENDCASE;
ENDLOOP;
};
iS ← StreamDefs.NewByteStream[iName, StreamDefs.Read !
StreamDefs.FileNameError => {
WF.WF1["Hex %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] THEN WF.WF0[" Failed*n"];
GOTO Cleanup;
EXITS
Cleanup => {
ComParse.Close[];
IF iS#NIL THEN iS.destroy[iS];
IF oS#NIL THEN oS.destroy[oS];
IF oName#NIL AND oName#iName THEN ComParse.FreeString[oName];
IF iName#NIL THEN ComParse.FreeString[iName];
};
};
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