-- 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