trans8to64.mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. MODULE trans8to64 ;
  2. (* trans8to64 : translate a classic 16-bit Turbo Modula-2 .MCD binary
  3. into a 64-bit MC64 .MCD image that mcint can boot.
  4. 16-bit file layout (little-endian) ::
  5. header : 16 bytes
  6. fileSize u16 (byte count not counting header)
  7. moduleStart u16 (blob offset of the module descriptor)
  8. codeSize u16 (size of the blob that follows the header)
  9. nbDependencies u16
  10. reserved [8] bytes
  11. blob : codeSize bytes
  12. + moduleStart descriptor:
  13. +66..73 name[8] +74,75 loadAddr
  14. +76,77 checksum +78,79 procsAddr
  15. +80 flags (bit2=TOINIT)
  16. +81 varCount +82 proc count k0 +83 depCount
  17. +84 var sizes : varCount*u16 BYTES
  18. proc table : cell i (i16) at procsAddr-2*i, descending;
  19. proc_i = (procsAddr-2*i) + 1 + cell
  20. scan i while cell<0 ; codeEnd = procsAddr-2*k0
  21. dependencies : nbDeps * 12 bytes (dropped by mc64)
  22. 64-bit output : 64-byte "MC64" header + descriptor + translated code +
  23. rebuilt proc table (cells relative to cell start).
  24. Operand translation (locked against mc64/Interpreter.mod) ::
  25. 8E word imm 2B -> 8B zero-extended (CARDINAL/word semantics)
  26. 8F dword imm 4B -> 8B via 8E, sign-extended (LONGINT constant)
  27. CD switch u16 low/high(range size)/ret ; cells = high+1
  28. 64-bit: low u64, highw=low+high u64, t u64, cells i64
  29. cells relative to cell-start+8 ; call-switch return
  30. pushed as eot+t (mc64 CD honours t)
  31. CF push_code 2B -> 8B, target preserved
  32. E0/E1 jp 2B -> 8B, target preserved
  33. DC limit_check : 16-bit pops its limit (no operand) ; the 64-bit form
  34. reads a u8 immediate. Reference modules only contain DC in dead code
  35. (right after a leave), so we emit `DC 00` (never executed).
  36. All other opcodes have identical operand widths and pass through.
  37. Limitations :
  38. - global slots / module-table address tricks (e.g. 0xFFF7/0xFFFF) do
  39. not map onto the mc64 data window => globals misbehave at run time.
  40. - extern references 0xEF/0xF0 point at dependencies; mc64 sets dcnt=0,
  41. so such calls crash if executed.
  42. - 8F used for REAL constants decodes as a LONGINT.
  43. - runnable only for dependency-free modules; TOINIT (flags bit2) is
  44. preserved, so a module with a real proc0 init runs under mcint.
  45. *)
  46. FROM FileIO IMPORT ReadFile, WriteFile ;
  47. FROM Console IMPORT WriteString, WriteLn, WriteLongCard, Fatal ;
  48. FROM ProgramArgs IMPORT ArgChan, NextArg ;
  49. FROM TextIO IMPORT ReadString ;
  50. CONST
  51. MaxBuf = 65535 ;
  52. HeaderSize = 64 ;
  53. DescName = 264 ;
  54. DescLoadAddr = 280 ;
  55. DescChecksum = 288 ;
  56. DescFlags = 292 ;
  57. DescVarCount = 293 ;
  58. DescDepCount = 294 ;
  59. DescPad = 295 ;
  60. DescProcs = 296 ;
  61. DescVarSizes = 304 ;
  62. VAR
  63. inName, outName : ARRAY [0 .. 200] OF CHAR ;
  64. src : ARRAY [0 .. MaxBuf] OF CHAR ;
  65. dst : ARRAY [0 .. MaxBuf] OF CHAR ;
  66. map : ARRAY [0 .. MaxBuf] OF LONGCARD ;
  67. got : CARDINAL ;
  68. ms, cs : CARDINAL ;
  69. desc, procs16 : CARDINAL ;
  70. k0 : CARDINAL ;
  71. codeEnd : CARDINAL ;
  72. flags8, vcnt : CARDINAL ;
  73. varSizes : ARRAY [0 .. 31] OF CARDINAL ;
  74. procAddrs : ARRAY [0 .. 255] OF CARDINAL ;
  75. ents : ARRAY [0 .. 256] OF CARDINAL ;
  76. nEnt : CARDINAL ;
  77. codeOff, procTabImg, imgLen : CARDINAL ;
  78. i, j, sum : CARDINAL ;
  79. PROCEDURE H16 (off : CARDINAL) : CARDINAL ;
  80. BEGIN
  81. RETURN ORD (src [off]) + 256 * ORD (src [off + 1]) ;
  82. END H16 ;
  83. PROCEDURE B (p : CARDINAL) : CARDINAL ;
  84. BEGIN
  85. RETURN ORD (src [16 + p]) ;
  86. END B ;
  87. PROCEDURE Get16 (p : CARDINAL) : CARDINAL ;
  88. BEGIN
  89. IF (p > MaxBuf) OR (p + 1 > MaxBuf) THEN
  90. Fatal ("trans8to64: Get16 out of range") ;
  91. END ;
  92. RETURN ORD (src [16 + p]) + 256 * ORD (src [16 + p + 1]) ;
  93. END Get16 ;
  94. PROCEDURE Sig16 (p : CARDINAL) : LONGINT ;
  95. VAR v : CARDINAL ;
  96. BEGIN
  97. v := Get16 (p) ;
  98. IF v >= 32768 THEN
  99. RETURN VAL (LONGINT, v) - 65536 ;
  100. ELSE
  101. RETURN VAL (LONGINT, v) ;
  102. END ;
  103. END Sig16 ;
  104. PROCEDURE Align8 (c : CARDINAL) : CARDINAL ;
  105. BEGIN
  106. IF (c MOD 8) # 0 THEN
  107. RETURN c + 8 - (c MOD 8) ;
  108. ELSE
  109. RETURN c ;
  110. END ;
  111. END Align8 ;
  112. PROCEDURE WB (off : CARDINAL; v : CARDINAL) ;
  113. BEGIN
  114. dst [HeaderSize + off] := CHR (v MOD 256) ;
  115. END WB ;
  116. PROCEDURE Put64 (off : CARDINAL; v : LONGCARD) ;
  117. VAR j : CARDINAL ;
  118. BEGIN
  119. FOR j := 0 TO 7 DO
  120. dst [HeaderSize + off + j] := CHR (VAL (CARDINAL, v MOD 256)) ;
  121. v := v DIV 256 ;
  122. END ;
  123. END Put64 ;
  124. PROCEDURE Put32 (off, v : CARDINAL) ;
  125. BEGIN
  126. dst [HeaderSize + off] := CHR (v MOD 256) ;
  127. dst [HeaderSize + off + 1] := CHR ((v DIV 256) MOD 256) ;
  128. dst [HeaderSize + off + 2] := CHR ((v DIV 65536) MOD 256) ;
  129. dst [HeaderSize + off + 3] := CHR (v DIV 16777216) ;
  130. END Put32 ;
  131. (* number of sub-opcode operand bytes consumed by 0x12 quad ops *)
  132. PROCEDURE QuadLen (sub : CARDINAL) : CARDINAL ;
  133. BEGIN
  134. CASE sub OF
  135. | 0H, 1H, 2H, 4H, 5H, 6H : RETURN 1 ;
  136. | 3H, 7H : RETURN 2 ;
  137. | 0AH : RETURN 1 ;
  138. ELSE RETURN 0 ;
  139. END ;
  140. END QuadLen ;
  141. PROCEDURE InstrLen16 (p : CARDINAL) : CARDINAL ;
  142. VAR op, sub, v : CARDINAL ;
  143. BEGIN
  144. op := B (p) ;
  145. CASE op OF
  146. | 02H : RETURN 2 ;
  147. | 08H, 09H, 0AH, 0CH,
  148. 11H, 18H, 19H, 1AH, 1CH,
  149. 2CH, 2DH, 2EH,
  150. 3CH, 3DH, 3EH,
  151. 40H,
  152. 80H, 81H, 82H, 84H, 85H, 86H, 87H, 8DH,
  153. 0AEH, 0AFH, 0B0H, 0B1H,
  154. 0D4H, 0DEH, 0DFH,
  155. 0ECH, 0EDH, 0EEH, 0F0H : RETURN 2 ;
  156. | 0BH, 1BH, 2FH, 3FH, 83H, 0EFH : RETURN 3 ;
  157. | 12H : sub := B (p + 1) ; RETURN 2 + QuadLen (sub) ;
  158. | 8CH : RETURN 2 + B (p + 1) ;
  159. | 8EH, 0CFH, 0E0H, 0E1H : RETURN 3 ;
  160. | 8FH : RETURN 5 ;
  161. | 0CDH : v := Get16 (p + 3) ;
  162. IF v >= 30000 THEN
  163. v := 30000 ;
  164. END ;
  165. RETURN 7 + 2 * (v + 1) ; ELSE RETURN 1 ;
  166. END ;
  167. END InstrLen16 ;
  168. PROCEDURE InstrInfo (p : CARDINAL; VAR sz16, out, op : CARDINAL) ;
  169. BEGIN
  170. op := B (p) ;
  171. sz16 := InstrLen16 (p) ;
  172. out := sz16 ;
  173. CASE op OF
  174. | 8EH, 8FH, 0CFH, 0E0H, 0E1H : out := 9 ;
  175. | 0CDH : out := 25 + 8 * (Get16 (p + 3) + 1) ;
  176. | 0DCH : out := 2 ;
  177. ELSE out := sz16 ;
  178. END ;
  179. END InstrInfo ;
  180. (* pass 1 : assign image offsets to every instruction in [start, stop) *)
  181. PROCEDURE Laying (start, stop : CARDINAL; VAR startImg : CARDINAL) ;
  182. VAR p, op, sz16, out, cur : CARDINAL ;
  183. BEGIN
  184. p := start ;
  185. cur := startImg ;
  186. WHILE p < stop DO
  187. InstrInfo (p, sz16, out, op) ;
  188. IF p + sz16 > stop THEN
  189. sz16 := stop - p ;
  190. out := sz16 ;
  191. END ;
  192. map [p] := VAL (LONGCARD, cur) ;
  193. IF cur + out > MaxBuf THEN
  194. Fatal ("trans8to64: output too large") ;
  195. END ;
  196. cur := cur + out ;
  197. p := p + sz16 ;
  198. END ;
  199. map [stop] := VAL (LONGCARD, cur) ;
  200. startImg := cur ;
  201. END Laying ;
  202. (* pass 2 : emit [start, stop) at curImg (must follow pass 1 exactly) *)
  203. PROCEDURE Emitting (start, stop : CARDINAL; VAR curImg : CARDINAL) ;
  204. VAR p, op, sz16, out, cur, j, N, low, high, ret, tgt16, lsw, msw : CARDINAL ;
  205. first, eot, t, off64, rel64, cellImg, idx : LONGCARD ;
  206. BEGIN
  207. p := start ;
  208. cur := curImg ;
  209. WHILE p < stop DO
  210. InstrInfo (p, sz16, out, op) ;
  211. IF p + sz16 > stop THEN
  212. sz16 := stop - p ;
  213. out := sz16 ;
  214. op := 0H ;
  215. END ;
  216. IF op = 8EH THEN
  217. WB (cur, 8EH) ;
  218. Put64 (cur + 1, VAL (LONGCARD, Get16 (p + 1))) ;
  219. ELSIF op = 8FH THEN
  220. lsw := Get16 (p + 1) ;
  221. msw := Get16 (p + 3) ;
  222. IF B (p + 4) >= 128 THEN
  223. off64 := VAL (LONGCARD,
  224. (VAL (LONGINT, msw) - 65536) * 65536 +
  225. VAL (LONGINT, lsw)) ;
  226. ELSE
  227. off64 := VAL (LONGCARD,
  228. VAL (LONGINT, msw) * 65536 + VAL (LONGINT, lsw)) ;
  229. END ;
  230. WB (cur, 8EH) ;
  231. Put64 (cur + 1, off64) ;
  232. ELSIF op = 0CFH THEN
  233. tgt16 := VAL (CARDINAL,
  234. VAL (LONGINT, p) + 2 + Sig16 (p + 1)) ;
  235. off64 := map [tgt16] - (VAL (LONGCARD, cur) + 8) ;
  236. WB (cur, 0CFH) ;
  237. Put64 (cur + 1, off64) ;
  238. ELSIF (op = 0E0H) OR (op = 0E1H) THEN
  239. tgt16 := VAL (CARDINAL,
  240. VAL (LONGINT, p) + 2 + Sig16 (p + 1)) ;
  241. off64 := map [tgt16] - (VAL (LONGCARD, cur) + 9) ;
  242. WB (cur, op) ;
  243. Put64 (cur + 1, off64) ;
  244. ELSIF op = 0DCH THEN
  245. WB (cur, 0DCH) ;
  246. WB (cur + 1, 0) ;
  247. ELSIF op = 0CDH THEN
  248. low := Get16 (p + 1) ;
  249. high := Get16 (p + 3) ;
  250. ret := Get16 (p + 5) ;
  251. N := high + 1 ;
  252. WB (cur, 0CDH) ;
  253. Put64 (cur + 1, VAL (LONGCARD, low)) ;
  254. Put64 (cur + 9, VAL (LONGCARD, low + high)) ;
  255. first := VAL (LONGCARD, cur) + 25 ;
  256. eot := first + VAL (LONGCARD, N) * 8 ;
  257. idx := VAL (LONGCARD, p) + 6 + VAL (LONGCARD, ret) ;
  258. IF idx > VAL (LONGCARD, MaxBuf) THEN
  259. idx := VAL (LONGCARD, codeEnd) ;
  260. END ;
  261. t := map [VAL (CARDINAL, idx)] - eot ;
  262. Put64 (cur + 17, t) ;
  263. FOR j := 0 TO N - 1 DO
  264. cellImg := VAL (LONGCARD, cur) + 25 + VAL (LONGCARD, j) * 8 ;
  265. tgt16 := VAL (CARDINAL,
  266. VAL (LONGINT, p) + 7 + VAL (LONGINT, j) * 2 +
  267. 1 + Sig16 (p + 7 + 2 * j)) ;
  268. rel64 := map [tgt16] - (cellImg + 8) ;
  269. Put64 (VAL (CARDINAL, cellImg), rel64) ;
  270. END ;
  271. ELSE
  272. FOR j := 0 TO sz16 - 1 DO
  273. WB (cur + j, B (p + j)) ;
  274. END ;
  275. END ;
  276. cur := cur + out ;
  277. p := p + sz16 ;
  278. END ;
  279. curImg := cur ;
  280. END Emitting ;
  281. (* insert an entry, keeping ents[] sorted and unique *)
  282. PROCEDURE AddEnt (e : CARDINAL) ;
  283. VAR i, j : CARDINAL ;
  284. BEGIN
  285. i := 0 ;
  286. WHILE (i < nEnt) AND (ents [i] < e) DO
  287. INC (i) ;
  288. END ;
  289. IF (i < nEnt) AND (ents [i] = e) THEN
  290. RETURN ;
  291. END ;
  292. j := nEnt ;
  293. WHILE j > i DO
  294. ents [j] := ents [j - 1] ;
  295. DEC (j) ;
  296. END ;
  297. ents [i] := e ;
  298. INC (nEnt) ;
  299. END AddEnt ;
  300. PROCEDURE Usage ;
  301. BEGIN
  302. WriteString ("usage: trans8to64 in.MCD out.MCD") ;
  303. WriteLn ;
  304. END Usage ;
  305. BEGIN
  306. NextArg ;
  307. ReadString (ArgChan (), inName) ;
  308. NextArg ;
  309. ReadString (ArgChan (), outName) ;
  310. IF (inName [0] = 0C) OR (outName [0] = 0C) THEN
  311. Usage ;
  312. HALT (1) ;
  313. END ;
  314. IF NOT ReadFile (inName, src, got) THEN
  315. Fatal ("trans8to64: cannot read input") ;
  316. END ;
  317. IF got <= 16 THEN
  318. Fatal ("trans8to64: input too short") ;
  319. END ;
  320. FOR i := 0 TO MaxBuf DO
  321. dst [i] := 0C ;
  322. END ;
  323. ms := H16 (2) ;
  324. cs := H16 (4) ;
  325. IF 16 + cs > got THEN
  326. Fatal ("trans8to64: header/blob size mismatch") ;
  327. END ;
  328. IF ms + 84 > cs THEN
  329. Fatal ("trans8to64: descriptor out of range") ;
  330. END ;
  331. desc := ms ;
  332. procs16 := Get16 (desc + 78) ;
  333. flags8 := B (desc + 80) ;
  334. vcnt := B (desc + 81) ;
  335. IF vcnt > 32 THEN
  336. Fatal ("trans8to64: too many var sizes") ;
  337. END ;
  338. IF desc + 84 + 2 * vcnt > cs THEN
  339. Fatal ("trans8to64: var sizes out of range") ;
  340. END ;
  341. IF procs16 + 2 > cs THEN
  342. Fatal ("trans8to64: procs table out of range") ;
  343. END ;
  344. (* count proc-table cells (negative, descending) *)
  345. k0 := 0 ;
  346. WHILE (procs16 >= 2 * k0) AND (Sig16 (procs16 - 2 * k0) < 0) DO
  347. INC (k0) ;
  348. END ;
  349. IF k0 > 255 THEN
  350. Fatal ("trans8to64: too many procedures") ;
  351. END ;
  352. codeEnd := procs16 - 2 * k0 ;
  353. IF k0 > 0 THEN
  354. FOR j := 0 TO k0 - 1 DO
  355. procAddrs [j] := VAL (CARDINAL,
  356. VAL (LONGINT, procs16 - 2 * j) + 1 +
  357. Sig16 (procs16 - 2 * j)) ;
  358. END ;
  359. END ;
  360. (* sorted unique proc entries + final code end *)
  361. nEnt := 0 ;
  362. IF k0 > 0 THEN
  363. FOR j := 0 TO k0 - 1 DO
  364. IF procAddrs [j] <= codeEnd THEN
  365. AddEnt (procAddrs [j]) ;
  366. END ;
  367. END ;
  368. END ;
  369. AddEnt (codeEnd) ;
  370. (* 16-bit var sizes *)
  371. IF vcnt > 0 THEN
  372. FOR j := 0 TO vcnt - 1 DO
  373. varSizes [j] := Get16 (desc + 84 + 2 * j) ;
  374. END ;
  375. END ;
  376. codeOff := Align8 (304 + vcnt * 8) ;
  377. IF codeOff < 312 THEN
  378. codeOff := 312 ;
  379. END ;
  380. (* pass 1 : assign positions ; intervals start at each proc entry *)
  381. procTabImg := codeOff ;
  382. IF nEnt >= 2 THEN
  383. FOR j := 0 TO nEnt - 2 DO
  384. Laying (ents [j], ents [j + 1], procTabImg) ;
  385. END ;
  386. END ;
  387. (* descriptor *)
  388. FOR j := 0 TO 7 DO
  389. WB (DescName + j, B (desc + 66 + j)) ;
  390. END ;
  391. Put64 (DescLoadAddr, VAL (LONGCARD, Get16 (desc + 74))) ;
  392. WB (DescFlags, flags8) ;
  393. WB (DescVarCount, vcnt) ;
  394. WB (DescDepCount, 0) ;
  395. WB (DescPad, 0) ;
  396. IF vcnt > 0 THEN
  397. FOR j := 0 TO vcnt - 1 DO
  398. Put64 (DescVarSizes + j * 8, VAL (LONGCARD, Align8 (varSizes [j]))) ;
  399. END ;
  400. END ;
  401. (* pad the code region to 8 before the proc table *)
  402. procTabImg := Align8 (procTabImg) ;
  403. (* pass 2 : emit *)
  404. imgLen := codeOff ;
  405. FOR j := 0 TO nEnt - 2 DO
  406. Emitting (ents [j], ents [j + 1], imgLen) ;
  407. END ;
  408. imgLen := Align8 (imgLen) ;
  409. IF imgLen > procTabImg THEN
  410. procTabImg := imgLen ;
  411. END ;
  412. Put64 (DescProcs, VAL (LONGCARD, procTabImg)) ;
  413. (* rebuild the proc table : cell = target - cellAddr *)
  414. FOR j := 0 TO k0 - 1 DO
  415. Put64 (procTabImg + j * 8,
  416. map [procAddrs [j]] - VAL (LONGCARD, procTabImg + j * 8)) ;
  417. END ;
  418. imgLen := procTabImg + k0 * 8 ;
  419. (* file header : magic *)
  420. dst [0] := 'M' ;
  421. dst [1] := 'C' ;
  422. dst [2] := '6' ;
  423. dst [3] := '4' ;
  424. (* checksum over the image bytes, excluding the checksum field itself *)
  425. sum := 0 ;
  426. FOR i := HeaderSize TO HeaderSize + imgLen - 1 DO
  427. IF NOT ((i >= 352) AND (i <= 355)) THEN
  428. sum := sum + ORD (dst [i]) ;
  429. END ;
  430. END ;
  431. Put32 (DescChecksum, sum) ;
  432. IF HeaderSize + imgLen > MaxBuf + 1 THEN
  433. Fatal ("trans8to64: output too large") ;
  434. END ;
  435. IF NOT WriteFile (outName, dst, HeaderSize + imgLen) THEN
  436. Fatal ("trans8to64: cannot write output") ;
  437. END ;
  438. WriteString ("trans8to64: ") ;
  439. WriteString (inName) ;
  440. WriteString (" -> ") ;
  441. WriteString (outName) ;
  442. WriteString (" : ok (") ;
  443. WriteLongCard (VAL (LONGCARD, HeaderSize + imgLen)) ;
  444. WriteString (" bytes)") ;
  445. WriteLn ;
  446. END trans8to64.