Loader2.mod 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. IMPLEMENTATION MODULE Loader2 ;
  2. FROM SYSTEM IMPORT ADR ;
  3. IMPORT FIO ;
  4. FROM FIO IMPORT OpenToRead, ReadNBytes, Close, IsNoError ;
  5. FROM Memory IMPORT ArenaBase, LoadImage, ReadByte, ReadWord, ReadSlot,
  6. FillBytes, ReadLong ;
  7. FROM Global IMPORT SetModuleBase, SetModuleProcs, SetModuleFlag,
  8. SetCurrentModule, GetModuleBase, GetModuleFlag ;
  9. FROM Local IMPORT Init, SetGP, SetIP ;
  10. FROM Instruction IMPORT ProcedureAddress ;
  11. FROM Interpreter IMPORT Run ;
  12. FROM Extended IMPORT SetHeapBase ;
  13. FROM Console IMPORT Fatal ;
  14. CONST
  15. HeaderSize = 64 ;
  16. DescDeps = 0 ;
  17. DescLink = 256 ;
  18. DescName = 264 ;
  19. DescLoadAddr = 280 ;
  20. DescChecksum = 288 ;
  21. DescFlags = 292 ;
  22. DescVarCount = 293 ;
  23. DescDepCount = 294 ;
  24. DescPad = 295 ;
  25. DescProcs = 296 ;
  26. DescVarSizes = 304 ;
  27. MaxDeps = 32 ;
  28. VAR
  29. buf : ARRAY [0 .. 65535] OF CHAR ;
  30. f : FIO.File ;
  31. (* Load one translated .MC4 image into module `slot`. The image and its
  32. zero-filled data window (plus globals) are placed at `next` and `next` is
  33. advanced past them, so several modules share the arena without overlap
  34. (multi-window arena). The requested module lives at MTBL slot `dcnt`,
  35. its dependencies at slots 0..dcnt-1 (the 16-bit source references the
  36. first import as mod 0). *)
  37. PROCEDURE LoadOne (slot: CARDINAL; name: ARRAY OF CHAR; VAR next: LONGCARD ;
  38. allowDeps: BOOLEAN) ;
  39. VAR
  40. got : CARDINAL ;
  41. i : CARDINAL ;
  42. imgLen, desc, procsAbs, dataWin, vnext, sz : LONGCARD ;
  43. chk, sum : CARDINAL ;
  44. fl, vcnt, dcnt : CARDINAL ;
  45. j : CARDINAL ;
  46. BEGIN
  47. f := OpenToRead (name) ;
  48. IF NOT IsNoError (f) THEN
  49. Fatal ("loader: cannot open module file") ;
  50. END ;
  51. got := ReadNBytes (f, HIGH (buf) + 1, ADR (buf)) ;
  52. Close (f) ;
  53. IF got <= 64 THEN
  54. Fatal ("loader: file too short") ;
  55. END ;
  56. imgLen := VAL (LONGCARD, got) - HeaderSize ;
  57. desc := next ;
  58. LoadImage (buf, HeaderSize, desc, got - HeaderSize) ;
  59. dcnt := ReadByte (desc + VAL (LONGCARD, DescDepCount)) ;
  60. IF (dcnt # 0) AND NOT allowDeps THEN
  61. Fatal ("loader: nested dependencies not supported yet") ;
  62. END ;
  63. chk := ReadLong (desc + VAL (LONGCARD, DescChecksum)) ;
  64. sum := 0 ;
  65. FOR i := HeaderSize TO got - 1 DO
  66. IF NOT ((i >= 352) AND (i <= 355)) THEN
  67. sum := sum + ORD (buf [i]) ;
  68. END ;
  69. END ;
  70. IF chk # sum THEN
  71. Fatal ("loader: checksum mismatch") ;
  72. END ;
  73. procsAbs := desc + ReadSlot (desc + VAL (LONGCARD, DescProcs)) ;
  74. fl := ReadByte (desc + VAL (LONGCARD, DescFlags)) ;
  75. vcnt := ReadByte (desc + VAL (LONGCARD, DescVarCount)) ;
  76. dataWin := desc + imgLen ;
  77. IF (dataWin MOD 8) # 0 THEN
  78. dataWin := dataWin + 8 - (dataWin MOD 8) ;
  79. END ;
  80. vnext := dataWin ;
  81. FOR j := 1 TO vcnt DO
  82. sz := ReadSlot (desc + (VAL (LONGCARD, DescVarSizes) +
  83. (VAL (LONGCARD, j) - 1) * 8)) ;
  84. IF (sz MOD 8) # 0 THEN
  85. sz := sz + 8 - (sz MOD 8) ;
  86. END ;
  87. FillBytes (vnext, sz, 0) ;
  88. vnext := vnext + sz ;
  89. END ;
  90. SetModuleBase (slot, dataWin) ;
  91. SetModuleProcs (slot, procsAbs) ;
  92. SetModuleFlag (slot, fl) ;
  93. next := vnext ;
  94. END LoadOne ;
  95. PROCEDURE Call (name: ARRAY OF CHAR) ;
  96. VAR
  97. got : CARDINAL ;
  98. imgLen, next : LONGCARD ;
  99. dcnt : CARDINAL ;
  100. j, k : CARDINAL ;
  101. mainDataWin : LONGCARD ;
  102. fl : CARDINAL ;
  103. depName : ARRAY [0 .. MaxDeps - 1] OF ARRAY [0 .. 15] OF CHAR ;
  104. fname : ARRAY [0 .. 255] OF CHAR ;
  105. BEGIN
  106. f := OpenToRead (name) ;
  107. IF NOT IsNoError (f) THEN
  108. Fatal ("loader: cannot open module file") ;
  109. END ;
  110. got := ReadNBytes (f, HIGH (buf) + 1, ADR (buf)) ;
  111. Close (f) ;
  112. IF got <= 64 THEN
  113. Fatal ("loader: file too short") ;
  114. END ;
  115. imgLen := VAL (LONGCARD, got) - HeaderSize ;
  116. dcnt := ORD (buf [HeaderSize + DescDepCount]) ;
  117. IF dcnt > MaxDeps THEN
  118. Fatal ("loader: too many dependencies") ;
  119. END ;
  120. (* dependency names are the last dcnt*8 bytes of the image (file tail) *)
  121. FOR j := 1 TO dcnt DO
  122. FOR k := 0 TO 7 DO
  123. depName [j - 1] [k] :=
  124. buf [got - dcnt * 8 + (j - 1) * 8 + k] ;
  125. END ;
  126. depName [j - 1] [8] := 0C ;
  127. END ;
  128. next := ArenaBase () ;
  129. (* dependencies first (slots 0..dcnt-1), then the requested module
  130. (slot dcnt). In the 16-bit source, extern references use mod 0 for
  131. the first import, so MTBL slot 0 must be the first dependency. *)
  132. FOR j := 1 TO dcnt DO
  133. k := 0 ;
  134. WHILE (k < 16) AND (depName [j - 1] [k] # 0C) DO
  135. fname [k] := depName [j - 1] [k] ;
  136. INC (k) ;
  137. END ;
  138. fname [k] := '.' ;
  139. fname [k + 1] := 'M' ;
  140. fname [k + 2] := 'C' ;
  141. fname [k + 3] := '4' ;
  142. fname [k + 4] := 0C ;
  143. LoadOne (j - 1, fname, next, FALSE) ;
  144. END ;
  145. LoadOne (dcnt, name, next, TRUE) ;
  146. SetHeapBase (next) ;
  147. mainDataWin := GetModuleBase (dcnt) ;
  148. fl := GetModuleFlag (dcnt) ;
  149. SetCurrentModule (dcnt) ;
  150. Init () ;
  151. SetGP (mainDataWin) ;
  152. (* initializers run dependency-first, the requested module last *)
  153. FOR j := 1 TO dcnt DO
  154. IF (GetModuleFlag (j - 1) DIV 4) MOD 2 # 0 THEN
  155. Init () ;
  156. SetGP (GetModuleBase (j - 1)) ;
  157. SetCurrentModule (j - 1) ;
  158. SetIP (ProcedureAddress (j - 1, 0)) ;
  159. Run () ;
  160. END ;
  161. END ;
  162. IF (fl DIV 4) MOD 2 # 0 THEN (* TOINIT : run the module initializer *)
  163. Init () ;
  164. SetGP (mainDataWin) ;
  165. SetCurrentModule (dcnt) ;
  166. SetIP (ProcedureAddress (dcnt, 0)) ;
  167. Run () ;
  168. END ;
  169. END Call ;
  170. END Loader2.