| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- MODULE trans8to64 ;
- (* trans8to64 : translate a classic 16-bit Turbo Modula-2 .MCD binary
- into a 64-bit MC64 .MC4 image that mcint can boot.
- 16-bit file layout (little-endian) ::
- header : 16 bytes
- fileSize u16 (byte count not counting header)
- moduleStart u16 (blob offset of the module descriptor)
- codeSize u16 (size of the blob that follows the header)
- nbDependencies u16
- reserved [8] bytes
- blob : codeSize bytes
- + moduleStart descriptor:
- +66..73 name[8] +74,75 loadAddr
- +76,77 checksum +78,79 procsAddr
- +80 flags (bit2=TOINIT)
- +81 varCount +82 proc count k0 +83 depCount
- +84 var sizes : varCount*u16 BYTES
- proc table : cell i (i16) at procsAddr-2*i, descending;
- proc_i = (procsAddr-2*i) + 1 + cell
- scan i while cell<0 ; codeEnd = procsAddr-2*k0
- dependencies : nbDeps * 12 bytes (dropped by mc64)
- 16-bit dependencies : nbDependencies u16 (header +6) ; records of 12 bytes
- (name[8], version u16, location u16) sit at blob offset +4 (header +4),
- at the tail of the blob. The 64-bit image carries dcnt (DescDepCount)
- and an 8-byte name per dependency, appended at the image tail.
- 64-bit output : 64-byte "MC64" header + descriptor + translated code +
- rebuilt proc table (cells relative to cell start) + dcnt*8 dep-name table.
- Operand translation (locked against mc64/Interpreter.mod) ::
- 8E word imm 2B -> 8B zero-extended (CARDINAL/word semantics)
- 8F dword imm 4B -> 8B via 8E, sign-extended (LONGINT constant)
- CD switch u16 low/high(range size)/ret ; cells = high+1
- 64-bit: low u64, highw=low+high u64, t u64, cells i64
- cells relative to cell-start+8 ; call-switch return
- pushed as eot+t (mc64 CD honours t)
- CF push_code 2B -> 8B, target preserved
- E0/E1 jp 2B -> 8B, target preserved
- DC limit_check : 16-bit pops its limit (no operand) ; the 64-bit form
- reads a u8 immediate. Reference modules only contain DC in dead code
- (right after a leave), so we emit `DC 00` (never executed).
- All other opcodes have identical operand widths and pass through.
- Limitations :
- - global slots / module-table address tricks (e.g. 0xFFF7/0xFFFF) do
- not map onto the mc64 data window => globals misbehave at run time.
- - extern references 0xEF/0xF0 point at dependencies; mc64 sets dcnt=0,
- so such calls crash if executed.
- - 8F used for REAL constants decodes as a LONGINT.
- - runnable only for dependency-free modules; TOINIT (flags bit2) is
- preserved, so a module with a real proc0 init runs under mcint.
- *)
- FROM FileIO IMPORT ReadFile, WriteFile ;
- FROM Console IMPORT WriteString, WriteLn, WriteLongCard, Fatal ;
- FROM ProgramArgs IMPORT ArgChan, NextArg ;
- FROM TextIO IMPORT ReadString ;
- CONST
- MaxBuf = 65535 ;
- HeaderSize = 64 ;
- DescName = 264 ;
- DescLoadAddr = 280 ;
- DescChecksum = 288 ;
- DescFlags = 292 ;
- DescVarCount = 293 ;
- DescDepCount = 294 ;
- DescPad = 295 ;
- DescProcs = 296 ;
- DescVarSizes = 304 ;
- VAR
- inName, outName : ARRAY [0 .. 200] OF CHAR ;
- src : ARRAY [0 .. MaxBuf] OF CHAR ;
- dst : ARRAY [0 .. MaxBuf] OF CHAR ;
- map : ARRAY [0 .. MaxBuf] OF LONGCARD ;
- got : CARDINAL ;
- ms, cs : CARDINAL ;
- ndeps, deps16 : CARDINAL ;
- k2 : CARDINAL ;
- desc, procs16 : CARDINAL ;
- k0 : CARDINAL ;
- codeEnd : CARDINAL ;
- flags8, vcnt : CARDINAL ;
- varSizes : ARRAY [0 .. 31] OF CARDINAL ;
- procAddrs : ARRAY [0 .. 255] OF CARDINAL ;
- ents : ARRAY [0 .. 256] OF CARDINAL ;
- nEnt : CARDINAL ;
- codeOff, procTabImg, imgLen : CARDINAL ;
- i, j, sum : CARDINAL ;
- PROCEDURE H16 (off : CARDINAL) : CARDINAL ;
- BEGIN
- RETURN ORD (src [off]) + 256 * ORD (src [off + 1]) ;
- END H16 ;
- PROCEDURE B (p : CARDINAL) : CARDINAL ;
- BEGIN
- RETURN ORD (src [16 + p]) ;
- END B ;
- PROCEDURE Get16 (p : CARDINAL) : CARDINAL ;
- BEGIN
- IF (p > MaxBuf) OR (p + 1 > MaxBuf) THEN
- Fatal ("trans8to64: Get16 out of range") ;
- END ;
- RETURN ORD (src [16 + p]) + 256 * ORD (src [16 + p + 1]) ;
- END Get16 ;
- PROCEDURE Sig16 (p : CARDINAL) : LONGINT ;
- VAR v : CARDINAL ;
- BEGIN
- v := Get16 (p) ;
- IF v >= 32768 THEN
- RETURN VAL (LONGINT, v) - 65536 ;
- ELSE
- RETURN VAL (LONGINT, v) ;
- END ;
- END Sig16 ;
- PROCEDURE Align8 (c : CARDINAL) : CARDINAL ;
- BEGIN
- IF (c MOD 8) # 0 THEN
- RETURN c + 8 - (c MOD 8) ;
- ELSE
- RETURN c ;
- END ;
- END Align8 ;
- PROCEDURE WB (off : CARDINAL; v : CARDINAL) ;
- BEGIN
- dst [HeaderSize + off] := CHR (v MOD 256) ;
- END WB ;
- PROCEDURE Put64 (off : CARDINAL; v : LONGCARD) ;
- VAR j : CARDINAL ;
- BEGIN
- FOR j := 0 TO 7 DO
- dst [HeaderSize + off + j] := CHR (VAL (CARDINAL, v MOD 256)) ;
- v := v DIV 256 ;
- END ;
- END Put64 ;
- PROCEDURE Put32 (off, v : CARDINAL) ;
- BEGIN
- dst [HeaderSize + off] := CHR (v MOD 256) ;
- dst [HeaderSize + off + 1] := CHR ((v DIV 256) MOD 256) ;
- dst [HeaderSize + off + 2] := CHR ((v DIV 65536) MOD 256) ;
- dst [HeaderSize + off + 3] := CHR (v DIV 16777216) ;
- END Put32 ;
- (* number of sub-opcode operand bytes consumed by 0x12 quad ops *)
- PROCEDURE QuadLen (sub : CARDINAL) : CARDINAL ;
- BEGIN
- CASE sub OF
- | 0H, 1H, 2H, 4H, 5H, 6H : RETURN 1 ;
- | 3H, 7H : RETURN 2 ;
- | 0AH : RETURN 1 ;
- ELSE RETURN 0 ;
- END ;
- END QuadLen ;
- PROCEDURE InstrLen16 (p : CARDINAL) : CARDINAL ;
- VAR op, sub, v : CARDINAL ;
- BEGIN
- op := B (p) ;
- CASE op OF
- | 02H : RETURN 2 ;
- | 08H, 09H, 0AH, 0CH,
- 11H, 18H, 19H, 1AH, 1CH,
- 2CH, 2DH, 2EH,
- 3CH, 3DH, 3EH,
- 40H,
- 80H, 81H, 82H, 84H, 85H, 86H, 87H, 8DH,
- 0AEH, 0AFH, 0B0H, 0B1H,
- 0D4H, 0DEH, 0DFH,
- 0ECH, 0EDH, 0EEH, 0F0H : RETURN 2 ;
- | 0BH, 1BH, 2FH, 3FH, 83H, 0EFH : RETURN 3 ;
- | 12H : sub := B (p + 1) ; RETURN 2 + QuadLen (sub) ;
- | 8CH : RETURN 2 + B (p + 1) ;
- | 8EH, 0CFH, 0E0H, 0E1H : RETURN 3 ;
- | 8FH : RETURN 5 ;
- | 0CDH : v := Get16 (p + 3) ;
- IF v >= 30000 THEN
- v := 30000 ;
- END ;
- RETURN 7 + 2 * (v + 1) ; ELSE RETURN 1 ;
- END ;
- END InstrLen16 ;
- PROCEDURE InstrInfo (p : CARDINAL; VAR sz16, out, op : CARDINAL) ;
- BEGIN
- op := B (p) ;
- sz16 := InstrLen16 (p) ;
- out := sz16 ;
- CASE op OF
- | 8EH, 8FH, 0CFH, 0E0H, 0E1H : out := 9 ;
- | 0CDH : out := 25 + 8 * (Get16 (p + 3) + 1) ;
- | 0DCH : out := 2 ;
- ELSE out := sz16 ;
- END ;
- END InstrInfo ;
- (* pass 1 : assign image offsets to every instruction in [start, stop) *)
- PROCEDURE Laying (start, stop : CARDINAL; VAR startImg : CARDINAL) ;
- VAR p, op, sz16, out, cur : CARDINAL ;
- BEGIN
- p := start ;
- cur := startImg ;
- WHILE p < stop DO
- InstrInfo (p, sz16, out, op) ;
- IF p + sz16 > stop THEN
- sz16 := stop - p ;
- out := sz16 ;
- END ;
- map [p] := VAL (LONGCARD, cur) ;
- IF cur + out > MaxBuf THEN
- Fatal ("trans8to64: output too large") ;
- END ;
- cur := cur + out ;
- p := p + sz16 ;
- END ;
- map [stop] := VAL (LONGCARD, cur) ;
- startImg := cur ;
- END Laying ;
- (* pass 2 : emit [start, stop) at curImg (must follow pass 1 exactly) *)
- PROCEDURE Emitting (start, stop : CARDINAL; VAR curImg : CARDINAL) ;
- VAR p, op, sz16, out, cur, j, N, low, high, ret, tgt16, lsw, msw : CARDINAL ;
- first, eot, t, off64, rel64, cellImg, idx : LONGCARD ;
- BEGIN
- p := start ;
- cur := curImg ;
- WHILE p < stop DO
- InstrInfo (p, sz16, out, op) ;
- IF p + sz16 > stop THEN
- sz16 := stop - p ;
- out := sz16 ;
- op := 0H ;
- END ;
- IF op = 8EH THEN
- WB (cur, 8EH) ;
- Put64 (cur + 1, VAL (LONGCARD, Get16 (p + 1))) ;
- ELSIF op = 8FH THEN
- lsw := Get16 (p + 1) ;
- msw := Get16 (p + 3) ;
- IF B (p + 4) >= 128 THEN
- off64 := VAL (LONGCARD,
- (VAL (LONGINT, msw) - 65536) * 65536 +
- VAL (LONGINT, lsw)) ;
- ELSE
- off64 := VAL (LONGCARD,
- VAL (LONGINT, msw) * 65536 + VAL (LONGINT, lsw)) ;
- END ;
- WB (cur, 8EH) ;
- Put64 (cur + 1, off64) ;
- ELSIF op = 0CFH THEN
- tgt16 := VAL (CARDINAL,
- VAL (LONGINT, p) + 2 + Sig16 (p + 1)) ;
- off64 := map [tgt16] - (VAL (LONGCARD, cur) + 8) ;
- WB (cur, 0CFH) ;
- Put64 (cur + 1, off64) ;
- ELSIF (op = 0E0H) OR (op = 0E1H) THEN
- tgt16 := VAL (CARDINAL,
- VAL (LONGINT, p) + 2 + Sig16 (p + 1)) ;
- off64 := map [tgt16] - (VAL (LONGCARD, cur) + 9) ;
- WB (cur, op) ;
- Put64 (cur + 1, off64) ;
- ELSIF op = 0DCH THEN
- WB (cur, 0DCH) ;
- WB (cur + 1, 0) ;
- ELSIF op = 0CDH THEN
- low := Get16 (p + 1) ;
- high := Get16 (p + 3) ;
- ret := Get16 (p + 5) ;
- N := high + 1 ;
- WB (cur, 0CDH) ;
- Put64 (cur + 1, VAL (LONGCARD, low)) ;
- Put64 (cur + 9, VAL (LONGCARD, low + high)) ;
- first := VAL (LONGCARD, cur) + 25 ;
- eot := first + VAL (LONGCARD, N) * 8 ;
- idx := VAL (LONGCARD, p) + 6 + VAL (LONGCARD, ret) ;
- IF idx > VAL (LONGCARD, MaxBuf) THEN
- idx := VAL (LONGCARD, codeEnd) ;
- END ;
- t := map [VAL (CARDINAL, idx)] - eot ;
- Put64 (cur + 17, t) ;
- FOR j := 0 TO N - 1 DO
- cellImg := VAL (LONGCARD, cur) + 25 + VAL (LONGCARD, j) * 8 ;
- tgt16 := VAL (CARDINAL,
- VAL (LONGINT, p) + 7 + VAL (LONGINT, j) * 2 +
- 1 + Sig16 (p + 7 + 2 * j)) ;
- rel64 := map [tgt16] - (cellImg + 8) ;
- Put64 (VAL (CARDINAL, cellImg), rel64) ;
- END ;
- ELSE
- FOR j := 0 TO sz16 - 1 DO
- WB (cur + j, B (p + j)) ;
- END ;
- END ;
- cur := cur + out ;
- p := p + sz16 ;
- END ;
- curImg := cur ;
- END Emitting ;
- (* insert an entry, keeping ents[] sorted and unique *)
- PROCEDURE AddEnt (e : CARDINAL) ;
- VAR i, j : CARDINAL ;
- BEGIN
- i := 0 ;
- WHILE (i < nEnt) AND (ents [i] < e) DO
- INC (i) ;
- END ;
- IF (i < nEnt) AND (ents [i] = e) THEN
- RETURN ;
- END ;
- j := nEnt ;
- WHILE j > i DO
- ents [j] := ents [j - 1] ;
- DEC (j) ;
- END ;
- ents [i] := e ;
- INC (nEnt) ;
- END AddEnt ;
- PROCEDURE Usage ;
- BEGIN
- WriteString ("usage: trans8to64 in.MCD out.MC4") ;
- WriteLn ;
- END Usage ;
- BEGIN
- NextArg ;
- ReadString (ArgChan (), inName) ;
- NextArg ;
- ReadString (ArgChan (), outName) ;
- IF (inName [0] = 0C) OR (outName [0] = 0C) THEN
- Usage ;
- HALT (1) ;
- END ;
- IF NOT ReadFile (inName, src, got) THEN
- Fatal ("trans8to64: cannot read input") ;
- END ;
- IF got <= 16 THEN
- Fatal ("trans8to64: input too short") ;
- END ;
- FOR i := 0 TO MaxBuf DO
- dst [i] := 0C ;
- END ;
- ms := H16 (2) ;
- cs := H16 (4) ;
- IF 16 + cs > got THEN
- Fatal ("trans8to64: header/blob size mismatch") ;
- END ;
- ndeps := H16 (6) ;
- deps16 := cs ;
- IF ndeps > 32 THEN
- Fatal ("trans8to64: too many dependencies") ;
- END ;
- IF 16 + deps16 + ndeps * 12 > got THEN
- Fatal ("trans8to64: dependency table out of range") ;
- END ;
- IF ms + 84 > cs THEN
- Fatal ("trans8to64: descriptor out of range") ;
- END ;
- desc := ms ;
- procs16 := Get16 (desc + 78) ;
- flags8 := B (desc + 80) ;
- vcnt := B (desc + 81) ;
- IF vcnt > 32 THEN
- Fatal ("trans8to64: too many var sizes") ;
- END ;
- IF desc + 84 + 2 * vcnt > cs THEN
- Fatal ("trans8to64: var sizes out of range") ;
- END ;
- IF procs16 + 2 > cs THEN
- Fatal ("trans8to64: procs table out of range") ;
- END ;
- (* count proc-table cells (negative, descending) *)
- k0 := 0 ;
- WHILE (procs16 >= 2 * k0) AND (Sig16 (procs16 - 2 * k0) < 0) DO
- INC (k0) ;
- END ;
- IF k0 > 255 THEN
- Fatal ("trans8to64: too many procedures") ;
- END ;
- codeEnd := procs16 - 2 * k0 ;
- IF k0 > 0 THEN
- FOR j := 0 TO k0 - 1 DO
- procAddrs [j] := VAL (CARDINAL,
- VAL (LONGINT, procs16 - 2 * j) + 1 +
- Sig16 (procs16 - 2 * j)) ;
- END ;
- END ;
- (* sorted unique proc entries + final code end *)
- nEnt := 0 ;
- IF k0 > 0 THEN
- FOR j := 0 TO k0 - 1 DO
- IF procAddrs [j] <= codeEnd THEN
- AddEnt (procAddrs [j]) ;
- END ;
- END ;
- END ;
- AddEnt (codeEnd) ;
- (* 16-bit var sizes *)
- IF vcnt > 0 THEN
- FOR j := 0 TO vcnt - 1 DO
- varSizes [j] := Get16 (desc + 84 + 2 * j) ;
- END ;
- END ;
- codeOff := Align8 (304 + vcnt * 8) ;
- IF codeOff < 312 THEN
- codeOff := 312 ;
- END ;
- (* pass 1 : assign positions ; intervals start at each proc entry *)
- procTabImg := codeOff ;
- IF nEnt >= 2 THEN
- FOR j := 0 TO nEnt - 2 DO
- Laying (ents [j], ents [j + 1], procTabImg) ;
- END ;
- END ;
- (* descriptor *)
- FOR j := 0 TO 7 DO
- WB (DescName + j, B (desc + 66 + j)) ;
- END ;
- Put64 (DescLoadAddr, VAL (LONGCARD, Get16 (desc + 74))) ;
- WB (DescFlags, flags8) ;
- WB (DescVarCount, vcnt) ;
- WB (DescDepCount, ndeps) ;
- WB (DescPad, 0) ;
- IF vcnt > 0 THEN
- FOR j := 0 TO vcnt - 1 DO
- Put64 (DescVarSizes + j * 8, VAL (LONGCARD, Align8 (varSizes [j]))) ;
- END ;
- END ;
- (* pad the code region to 8 before the proc table *)
- procTabImg := Align8 (procTabImg) ;
- (* pass 2 : emit *)
- imgLen := codeOff ;
- FOR j := 0 TO nEnt - 2 DO
- Emitting (ents [j], ents [j + 1], imgLen) ;
- END ;
- imgLen := Align8 (imgLen) ;
- IF imgLen > procTabImg THEN
- procTabImg := imgLen ;
- END ;
- Put64 (DescProcs, VAL (LONGCARD, procTabImg)) ;
- (* rebuild the proc table : cell = target - cellAddr *)
- FOR j := 0 TO k0 - 1 DO
- Put64 (procTabImg + j * 8,
- map [procAddrs [j]] - VAL (LONGCARD, procTabImg + j * 8)) ;
- END ;
- imgLen := procTabImg + k0 * 8 ;
- (* append the dependency name table at the image tail : 8 bytes each *)
- IF ndeps > 0 THEN
- IF imgLen + ndeps * 8 > MaxBuf THEN
- Fatal ("trans8to64: output too large") ;
- END ;
- FOR j := 0 TO ndeps - 1 DO
- FOR k2 := 0 TO 7 DO
- WB (imgLen + k2, B (deps16 + j * 12 + k2)) ;
- END ;
- INC (imgLen, 8) ;
- END ;
- END ;
- (* file header : magic *)
- dst [0] := 'M' ;
- dst [1] := 'C' ;
- dst [2] := '6' ;
- dst [3] := '4' ;
- (* checksum over the image bytes, excluding the checksum field itself *)
- sum := 0 ;
- FOR i := HeaderSize TO HeaderSize + imgLen - 1 DO
- IF NOT ((i >= 352) AND (i <= 355)) THEN
- sum := sum + ORD (dst [i]) ;
- END ;
- END ;
- Put32 (DescChecksum, sum) ;
- IF HeaderSize + imgLen > MaxBuf + 1 THEN
- Fatal ("trans8to64: output too large") ;
- END ;
- IF NOT WriteFile (outName, dst, HeaderSize + imgLen) THEN
- Fatal ("trans8to64: cannot write output") ;
- END ;
- WriteString ("trans8to64: ") ;
- WriteString (inName) ;
- WriteString (" -> ") ;
- WriteString (outName) ;
- WriteString (" : ok (") ;
- WriteLongCard (VAL (LONGCARD, HeaderSize + imgLen)) ;
- WriteString (" bytes)") ;
- WriteLn ;
- END trans8to64.
|