DIRECTORY Basics, IntelHex; IntelHexImpl: PROGRAM IMPORTS Basics EXPORTS IntelHex = BEGIN iEOF: SIGNAL = CODE; 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]]; }; 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]]; }; 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; CkChar: PROC RETURNS[v: CARDINAL] = { IF in.endof[] THEN SIGNAL iEOF; v _ in.get[]; inCkecksum _ inCkecksum+v; }; 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; }; gda: LONG CARDINAL; NewDataAddress: PROC [frame, bytepos: CARDINAL] = { gda _ Shift[frame, 4] + bytepos; }; DataByte: PROC [d: CARDINAL] = { out.DataByte[adr: gda, d: d]; gda _ gda+1; }; 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]; }; 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]; THROUGH [0..length) DO [] _ CkChar[]; ENDLOOP; CheckChecksum[]; in.SetPosition[filepos]; length _ DumpRepeated[length]; IF length#0 THEN { PutL["End PIData, non zero length."]; GOTO ReturnFalse; }; [] _ 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 „IntelHexImpl.mesa Last Modified: Stewart December 21, 1983 2:49 pm Converts an Intel absolute loader format file into commands to an output stream. signal raised on unexpected end of input file signal raised on checksum error in input file sum of bytes, contribution to checksum The checksum is the value making sum of checked bytes equal zero. read a character, adding to input checksum read a word, adding to input checksum Write a data record after every byte filling a paragraph global variables for data address Set a new data address. 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 Read each record, writing corresponding output record(s). Check checksum up front, due to complexity of iterated block structure and danger of double counting. length should be 0 must eat checksum character Ę‹˜Jšœ™Jšœ1™1Jšœ2™2Jšœ™J˜šĎk ˜ J˜J˜ J˜—Jšœ˜Jšœ˜šœ ˜Jš˜J˜Jšœ-™-Jšœœœ˜J˜Jšœ-™-Jšœœœ˜J˜Jš Ďnœœœ œœ œ˜=J˜Jšœ œœœ ˜4Jšœœœœ ˜8J˜J˜Jšœ&™&š žœœœœœ˜1Jšœœ˜!Jšœ˜J˜J˜—JšœA™Aš žœœœœœ˜0Jšœœ˜J˜J˜Jšœœœ˜J˜J˜——šž œœ œJ˜gJšœ œ ˜&J˜šžœœœ˜Jš œœœœ œ˜8J˜J˜—Jšžœœœ˜/J˜šž œœœ˜!š žœœœœ œ˜/J˜Jšœœœ˜Jšœœ ˜J˜—J˜J˜J˜J˜ J˜J˜—Jšžœœ˜J˜J˜šœ˜˜ J˜&Jšœ ˜J˜—˜J˜&Jšœ ˜J˜—J˜J˜—Jšœ œĎc˜2Jšœ(œ˜1J˜Jšœ*™*šžœœœœ˜%Jšœ œœ˜J˜ J˜J˜J˜—Jšœ%™%šžœœœœ˜#J˜Jšœ œœ˜J˜J˜J˜'Jšœœœ˜J˜J˜—šž œœ˜J˜Jšœœœ˜5J˜J˜—Jšœ8™8Jšœ!™!Jšœœœ˜J˜Jšœ™šžœœœ˜3J˜ J˜J˜—šžœœœ˜ J˜J˜ J˜J˜—Jšœ$™$Jšœ<™