Runtime.def 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. DEFINITION MODULE Runtime ;
  2. (* 8086 runtime library for TP3-compiled programs.
  3. The original embeds its runtime in the compiler's own code segment and
  4. copies it to the front of the generated code buffer (TPSRC7 "copyrt":
  5. "MOV CX,#start / REPZ MOVS.B" with SI=DI=0, then "MOV pc,#$2D7C" so the
  6. generated program starts past it; the .COM writer emits the runtime as a
  7. block ahead of the program). Same shape here: RT_Build assembles the
  8. library into rt[0..RT_Size-1], the compiler copies it to the front of its
  9. code buffer (behind the entry JMP) and starts pc/dc past it, so the
  10. runtime's own data lives at low, link-time-constant addresses and needs no
  11. relocation. The "front" is now at RT_Build's `base' rather than at 0.
  12. Entry offsets are *derived* from where the code actually lands, not
  13. hardcoded - see RT_Entry. Everything the compiler calls is reached by a
  14. relative CALL, and both sides shift by the same runtime size, so the
  15. displacement arithmetic in EmCall is unaffected by the runtime being
  16. prepended. *)
  17. FROM SYSTEM IMPORT BYTE ;
  18. CONST
  19. (* entry selectors for RT_Entry *)
  20. E_InitMem = 0 ; E_ProgEnd = 1 ; E_StackChk = 2 ;
  21. E_WrInt = 3 ; E_WrChar = 4 ; E_WrBool = 5 ;
  22. E_WrReal = 6 ; E_WrLn = 7 ;
  23. E_RdInt = 8 ; E_RdChar = 9 ; E_RdBool = 10 ;
  24. E_RdLn = 11 ; E_Halt = 12 ; E_WrInl = 13 ;
  25. (* Where a .COM's first byte ends up. DOS loads a .COM at CS:0100 (the
  26. 100 bytes below are the PSP), and CS = DS, so an image offset K is at
  27. DS:(K + 0100h). EVERY address baked into the image as an absolute
  28. literal must therefore carry this. It is here, in Runtime, because
  29. FixUp needs it and Compiler needs it, and one constant in one place is
  30. the only way a six-site bias can stay consistent - see the long note in
  31. Runtime.mod, which also records how the failure looks: the program
  32. runs, prints its first field, and then walks a $ that is 100h too low
  33. through the runtime's own code. *)
  34. LoadBias = 100H ;
  35. PROCEDURE RT_Build (base : CARDINAL) ;
  36. (* assemble the runtime; idempotent, called once at Compile time.
  37. `base' is the IMAGE OFFSET the runtime blob will be copied to. It is a
  38. parameter rather than an assumption because the image begins with a
  39. three-byte entry JMP, so the runtime does not sit at image offset 0 - and
  40. every address the runtime bakes into its own code (its data block, and the
  41. entry offsets RT_Entry hands back) has to be biased by it. The emitted
  42. BYTES are the same for any base, because both are computed after assembly,
  43. so the standalone probes and tests/runtime.golden pass 0 and are unaffected.
  44. NOTE, because it has already cost time: this .def file is HAND-MAINTAINED.
  45. gm2 reads X.def to resolve `FROM X IMPORT ...' and checks the
  46. implementation against it, but it does NOT rewrite it - a successful
  47. compile leaves X.def byte-identical, and deleting it makes gm2 fail with
  48. "the file containing the definition module « X » cannot be found" rather
  49. than regenerate it. So an interface change means editing Runtime.def by
  50. hand in the same commit, exactly as Editor.def was edited to add
  51. Editor.GotoOffset. Keep such changes ADDITIVE where possible: an
  52. unchanged procedure's declaration does not need re-typing, so only the
  53. lines that actually moved have to be right. *)
  54. PROCEDURE RT_Size () : CARDINAL ;
  55. (* size of the runtime in bytes - the offset at which the generated program
  56. starts inside the image *)
  57. PROCEDURE RT_Byte (i : CARDINAL) : BYTE ;
  58. (* i-th runtime byte, 0 past the end, for hex dumps *)
  59. PROCEDURE RT_Entry (i : CARDINAL) : CARDINAL ;
  60. (* offset of entry i (an E_* selector) inside the runtime; 0 if unknown *)
  61. PROCEDURE RT_CodeEnd () : CARDINAL ;
  62. (* offset where the code stops and the runtime's data block starts. Bytes
  63. from here on are strings and scratch, so disassembling them is
  64. meaningless; tests use this to sweep the code region only. *)
  65. END Runtime.