-- IntelHexImpl6.mesa -- Last Modified: Stewart January 5, 1982 12:20 PM -- Converts an Intel absolute loader format file into --commands to an output stream. DIRECTORY Ascii USING [CR], Inline, IntelHex6; IntelHexImpl6: PROGRAM IMPORTS Inline EXPORTS IntelHex6 = 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[Inline.BITAND[a,b]]; }; Shift: BitOp = INLINE { RETURN[Inline.BITSHIFT[a,b]]; }; -- 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]]; }; ProcessFile: PUBLIC PROC [in: IntelHex6.IStream, out: IntelHex6.OStream, errs: IntelHex6.PutCharProc] RETURNS [success: BOOLEAN] = { 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[Ascii.CR]; }; { 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: Inline.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