IntelHexImpl.mesa
Last Modified: Stewart December 21, 1983 2:49 pm
Converts an Intel absolute loader format file into
commands to an output stream.
DIRECTORY
Basics,
IntelHex;
IntelHexImpl: PROGRAM
IMPORTS Basics
EXPORTS IntelHex =
BEGIN
signal raised on unexpected end of input file
iEOF: SIGNAL = CODE;
signal raised on checksum error in input file
ChecksumError: SIGNAL = CODE;
BitOp: TYPE = PROC [a, b: UNSPECIFIED] RETURNS [UNSPECIFIED];
And: BitOp = INLINE { RETURN[Basics.BITAND[a,b]]; };
Shift: BitOp = INLINE { RETURN[Basics.BITSHIFT[a,b]]; };
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]];
};
ProcessFile: PUBLIC SAFE PROC [in: IntelHex.IStream, out: IntelHex.OStream, errs: IntelHex.PutCharProc]
RETURNS [success: BOOLEAN] = TRUSTED {
PutS: PROC [s: STRING] = {
FOR i: CARDINAL IN [0..s.length) DO errs[s[i]]; ENDLOOP;
};
PutL: PROC [s: STRING] = { PutS[s]; PutCR[]; };
PutHexNum: PROC [x: CARDINAL] = {
Dig: PROC [y: CARDINAL] RETURNS [CHARACTER] = {
y ← And[y, 017B];
IF y < 10 THEN RETURN[y+'0]
ELSE RETURN[y-10+'A];
};
errs[Dig[Shift[x, -12]]];
errs[Dig[Shift[x, -8]]];
errs[Dig[Shift[x, -4]]];
errs[Dig[x]];
};
PutCR: PROC = { errs['\n]; };
{
ENABLE {
iEOF => {
PutL["Unexpected end of input file."];
GOTO ReturnFalse;
};
ChecksumError => {
PutL["Checksum error in input file."];
GOTO ReturnFalse;
};
};
inCkecksum: CARDINAL; -- checksum of input record
rectype, length, count, frame, bytepos: CARDINAL;
read a character, adding to input checksum
CkChar: PROC RETURNS[v: CARDINAL] = {
IF in.endof[] THEN SIGNAL iEOF;
v ← in.get[];
inCkecksum ← inCkecksum+v;
};
read a word, adding to input checksum
CkWord: PROC RETURNS [CARDINAL] = {
v: Basics.BytePair;
IF in.endof[] THEN SIGNAL iEOF;
v.high ← in.get[];
v.low ← in.get[];
inCkecksum ← inCkecksum+v.high + v.low;
RETURN[LOOPHOLE[v, CARDINAL]];
};
CheckChecksum: PROC = {
[] ← CkChar[];
IF And[inCkecksum, 377B]#0 THEN SIGNAL ChecksumError;
};
Write a data record after every byte filling a paragraph
global variables for data address
gda: LONG CARDINAL;
Set a new data address.
NewDataAddress: PROC [frame, bytepos: CARDINAL] = {
gda ← Shift[frame, 4] + bytepos;
};
DataByte: PROC [d: CARDINAL] = {
out.DataByte[adr: gda, d: d];
gda ← gda+1;
};
handle physical iterated data record
the input file must be in the right position on entry and is
left at the end of the iterated block on exit
DumpRepeated: PROC [length: CARDINAL] RETURNS [CARDINAL] = {
rptcount, blockcount, nlength: CARDINAL;
pos: LONG CARDINAL;
rptcount ← CkWord[];
blockcount ← CkWord[];
length ← length-4;
IF blockcount = 0 THEN {
count: CARDINAL ← CkChar[];
nlength ← length - count - 1;
pos ← in.GetPosition[];
THROUGH [0..rptcount) DO
in.SetPosition[pos];
THROUGH[0..count) DO DataByte[CkChar[]]; ENDLOOP;
ENDLOOP;
}
ELSE {
pos ← in.GetPosition[];
THROUGH [0..rptcount) DO
nlength ← length;
in.SetPosition[pos];
THROUGH[0..blockcount) DO
nlength ← DumpRepeated[nlength];
ENDLOOP;
ENDLOOP;
};
RETURN [nlength];
};
Read each record, writing corresponding output record(s).
DO
inCkecksum ← 0;
rectype ← CkChar[];
SELECT rectype FROM
200B, 202B => {
length ← CkWord[];
count ← CkChar[];
length ← length - count - 1;
THROUGH [0..count) DO [] ← CkChar[]; ENDLOOP;
CheckChecksum[];
};
212B => {
modtype: CARDINAL;
length ← CkWord[];
modtype ← CkChar[];
SELECT Shift[modtype, -6] FROM
0 => out.PutEndRecord[];
1, 3 => {
frame ← CkWord[];
bytepos ← CkWord[];
out.PutStartRecord[frame: frame, bytepos: bytepos];
out.PutEndRecord[];
};
ENDCASE => {
PutS["Invalid end record attributes: "];
PutHexNum[modtype];
PutCR[];
};
CheckChecksum[];
EXIT; -- end of module, stop here
};
204B => {
length ← CkWord[];
frame ← CkWord[];
bytepos ← CkChar[];
length ← length - 4;
NewDataAddress[frame: frame, bytepos: bytepos];
THROUGH [0..length) DO DataByte[CkChar[]]; ENDLOOP;
CheckChecksum[];
};
206B => {
filepos: LONG CARDINAL;
length ← CkWord[];
frame ← CkWord[];
bytepos ← CkChar[];
length ← length - 4;
filepos ← in.GetPosition[];
NewDataAddress[frame: frame, bytepos: bytepos];
Check checksum up front, due to complexity of
iterated block structure and danger of double counting.
THROUGH [0..length) DO [] ← CkChar[]; ENDLOOP;
CheckChecksum[];
in.SetPosition[filepos];
length ← DumpRepeated[length];
length should be 0
IF length#0 THEN {
PutL["End PIData, non zero length."];
GOTO ReturnFalse;
};
must eat checksum character
[] ← CkChar[];
};
ENDCASE => {
PutS["Unknown record type: "];
PutHexNum[rectype];
PutCR[];
length ← CkWord[];
THROUGH [0..length-1) DO [] ← CkChar[]; ENDLOOP;
CheckChecksum[];
};
ENDLOOP;
RETURN[TRUE];
};
EXITS
ReturnFalse => RETURN[FALSE];
}; -- end of ProcessFile
END.
October 4, 1981 3:06 PM, LStewart; Created
December 23, 1981 3:31 PM, LStewart; Suppress duplicate address records
1-Jan-82 21:05:41, L. Stewart, Rewrite with Defs file
April 25, 1983 3:44 pm, LCS, CEDAR
December 21, 1983 2:49 pm, L. Stewart.pa, Cedar 5