Modules.Mod.txt 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. MODULE Modules; (*Link and load on RISC; NW 20.10.2013 / 9.4.2016*)
  2. IMPORT SYSTEM, Files;
  3. CONST versionkey = 1X; MT = 12; DescSize = 80;
  4. TYPE Module* = POINTER TO ModDesc;
  5. Command* = PROCEDURE;
  6. ModuleName* = ARRAY 32 OF CHAR;
  7. ModDesc* = RECORD
  8. name*: ModuleName;
  9. next*: Module;
  10. key*, num*, size*, refcnt*: INTEGER;
  11. data*, code*, imp*, cmd*, ent*, ptr*, unused: INTEGER (*addresses*)
  12. END ;
  13. VAR root*, M: Module;
  14. MTOrg*, AllocPtr*, res*: INTEGER;
  15. importing*, imported*: ModuleName;
  16. limit: INTEGER;
  17. PROCEDURE ThisFile(name: ARRAY OF CHAR): Files.File;
  18. VAR i: INTEGER;
  19. filename: ModuleName;
  20. BEGIN i := 0;
  21. WHILE name[i] # 0X DO filename[i] := name[i]; INC(i) END ;
  22. filename[i] := "."; filename[i+1] := "r"; filename[i+2] := "s"; filename[i+3] := "c"; filename[i+4] := 0X;
  23. RETURN Files.Old(filename)
  24. END ThisFile;
  25. PROCEDURE error(n: INTEGER; name: ARRAY OF CHAR);
  26. BEGIN res := n; importing := name
  27. END error;
  28. PROCEDURE Check(s: ARRAY OF CHAR);
  29. VAR i: INTEGER; ch: CHAR;
  30. BEGIN ch := s[0]; res := 1; i := 1;
  31. IF (ch >= "A") & (ch <= "Z") OR (ch >= "a") & (ch <= "z") THEN
  32. REPEAT ch := s[i]; INC(i)
  33. UNTIL ~((ch >= "0") & (ch <= "9") OR (ch >= "A") & (ch <= "Z")
  34. OR (ch >= "a") & (ch <= "z") OR (ch = ".")) OR (i = 32);
  35. IF (i < 32) & (ch = 0X) THEN res := 0 END
  36. END
  37. END Check;
  38. PROCEDURE Load*(name: ARRAY OF CHAR; VAR newmod: Module);
  39. (*search module in list; if not found, load module.
  40. res = 0: already present or loaded; res = 2: file not available; res = 3: key conflict;
  41. res = 4: bad file version; res = 5: corrupted file; res = 7: no space*)
  42. VAR mod, impmod: Module;
  43. i, n, key, impkey, mno, nofimps, size: INTEGER;
  44. p, u, v, w: INTEGER; (*addresses*)
  45. ch: CHAR;
  46. body: Command;
  47. fixorgP, fixorgD, fixorgT: INTEGER;
  48. disp, adr, inst, pno, vno, dest, offset: INTEGER;
  49. name1, impname: ModuleName;
  50. F: Files.File; R: Files.Rider;
  51. import: ARRAY 16 OF Module;
  52. BEGIN mod := root; res := 0; nofimps := 0;
  53. WHILE (mod # NIL) & (name # mod.name) DO mod := mod.next END ;
  54. IF mod = NIL THEN (*load*)
  55. Check(name);
  56. IF res = 0 THEN F := ThisFile(name) ELSE F := NIL END ;
  57. IF F # NIL THEN
  58. Files.Set(R, F, 0); Files.ReadString(R, name1); Files.ReadInt(R, key); Files.Read(R, ch);
  59. Files.ReadInt(R, size); importing := name1;
  60. IF ch = versionkey THEN
  61. Files.ReadString(R, impname); (*imports*)
  62. WHILE (impname[0] # 0X) & (res = 0) DO
  63. Files.ReadInt(R, impkey);
  64. Load(impname, impmod); import[nofimps] := impmod; importing := name1;
  65. IF res = 0 THEN
  66. IF impmod.key = impkey THEN INC(impmod.refcnt); INC(nofimps)
  67. ELSE error(3, name1); imported := impname
  68. END
  69. END ;
  70. Files.ReadString(R, impname)
  71. END
  72. ELSE error(2, name1)
  73. END
  74. ELSE error(1, name)
  75. END ;
  76. IF res = 0 THEN (*search for a hole in the list allocate and link*)
  77. INC(size, DescSize); mod := root;
  78. WHILE (mod # NIL) & ~((mod.name[0] = 0X) & (mod.size >= size)) DO mod := mod.next END ;
  79. IF mod = NIL THEN (*no large enough hole was found*)
  80. IF AllocPtr + size < limit THEN (*allocate*)
  81. p := AllocPtr; mod := SYSTEM.VAL(Module, p);
  82. AllocPtr := (p + size + 100H) DIV 20H * 20H; mod.size := AllocPtr - p; mod.num := root.num + 1;
  83. mod.next := root; root := mod
  84. ELSE error(7, name1)
  85. END
  86. ELSE (*fill hole*) p := SYSTEM.VAL(INTEGER, mod)
  87. END
  88. END ;
  89. IF res = 0 THEN (*read file*)
  90. INC(p, DescSize); (*allocate descriptor*)
  91. mod.name := name; mod.key := key; mod.refcnt := 0;
  92. mod.data := p; (*data*)
  93. SYSTEM.PUT(mod.num * 4 + MTOrg, p); (*module table entry*)
  94. Files.ReadInt(R, n);
  95. WHILE n > 0 DO Files.ReadInt(R, w); SYSTEM.PUT(p, w); INC(p, 4); DEC(n, 4) END ; (*type descriptors*)
  96. Files.ReadInt(R, n);
  97. WHILE n > 0 DO SYSTEM.PUT(p, 0); INC(p, 4); DEC(n, 4) END ; (*variable space*)
  98. Files.ReadInt(R, n);
  99. WHILE n > 0 DO Files.Read(R, ch); SYSTEM.PUT(p, ch); INC(p); DEC(n) END ; (*strings*)
  100. mod.code := p; (*program*)
  101. Files.ReadInt(R, n);
  102. WHILE n > 0 DO Files.ReadInt(R, w); SYSTEM.PUT(p, w); INC(p, 4); DEC(n) END ; (*program code*)
  103. mod.imp := p; (*copy imports*)
  104. i := 0;
  105. WHILE i < nofimps DO
  106. SYSTEM.PUT(p, import[i]); INC(p, 4); INC(i)
  107. END ;
  108. mod.cmd := p; (*commands*) Files.Read(R, ch);
  109. WHILE ch # 0X DO
  110. REPEAT SYSTEM.PUT(p, ch); INC(p); Files.Read(R, ch) UNTIL ch = 0X;
  111. REPEAT SYSTEM.PUT(p, 0X); INC(p) UNTIL p MOD 4 = 0;
  112. Files.ReadInt(R, n); SYSTEM.PUT(p, n); INC(p, 4); Files.Read(R, ch)
  113. END ;
  114. REPEAT SYSTEM.PUT(p, 0X); INC(p) UNTIL p MOD 4 = 0;
  115. mod.ent := p; (*entries*)
  116. Files.ReadInt(R, n);
  117. WHILE n > 0 DO Files.ReadInt(R, w); SYSTEM.PUT(p, w); INC(p, 4); DEC(n) END ;
  118. mod.ptr := p; (*pointer references*)
  119. Files.ReadInt(R, w);
  120. WHILE w >= 0 DO SYSTEM.PUT(p, mod.data + w); INC(p, 4); Files.ReadInt(R, w) END ;
  121. SYSTEM.PUT(p, 0); INC(p, 4);
  122. Files.ReadInt(R, fixorgP); Files.ReadInt(R, fixorgD); Files.ReadInt(R, fixorgT);
  123. Files.ReadInt(R, w); body := SYSTEM.VAL(Command, mod.code + w);
  124. Files.Read(R, ch);
  125. IF ch # "O" THEN (*corrupted file*) mod := NIL; error(4, name) END
  126. END ;
  127. IF res = 0 THEN (*fixup of BL*)
  128. adr := mod.code + fixorgP*4;
  129. WHILE adr # mod.code DO
  130. SYSTEM.GET(adr, inst);
  131. mno := inst DIV 100000H MOD 10H;
  132. pno := inst DIV 1000H MOD 100H;
  133. disp := inst MOD 1000H;
  134. SYSTEM.GET(mod.imp + (mno-1)*4, impmod);
  135. SYSTEM.GET(impmod.ent + pno*4, dest); dest := dest + impmod.code;
  136. offset := (dest - adr - 4) DIV 4;
  137. SYSTEM.PUT(adr, (offset MOD 1000000H) + 0F7000000H);
  138. adr := adr - disp*4
  139. END ;
  140. (*fixup of LDR/STR/ADD*)
  141. adr := mod.code + fixorgD*4;
  142. WHILE adr # mod.code DO
  143. SYSTEM.GET(adr, inst);
  144. mno := inst DIV 100000H MOD 10H;
  145. disp := inst MOD 1000H;
  146. IF mno = 0 THEN (*global*)
  147. SYSTEM.PUT(adr, (inst DIV 1000000H * 10H + MT) * 100000H + mod.num * 4)
  148. ELSE (*import*)
  149. SYSTEM.GET(mod.imp + (mno-1)*4, impmod); v := impmod.num;
  150. SYSTEM.PUT(adr, (inst DIV 1000000H * 10H + MT) * 100000H + v*4);
  151. SYSTEM.GET(adr+4, inst); vno := inst MOD 100H;
  152. SYSTEM.GET(impmod.ent + vno*4, offset);
  153. IF ODD(inst DIV 100H) THEN offset := offset + impmod.code - impmod.data END ;
  154. SYSTEM.PUT(adr+4, inst DIV 10000H * 10000H + offset)
  155. END ;
  156. adr := adr - disp*4
  157. END ;
  158. (*fixup of type descriptors*)
  159. adr := mod.data + fixorgT*4;
  160. WHILE adr # mod.data DO
  161. SYSTEM.GET(adr, inst);
  162. mno := inst DIV 1000000H MOD 10H;
  163. vno := inst DIV 1000H MOD 1000H;
  164. disp := inst MOD 1000H;
  165. IF mno = 0 THEN (*global*) inst := mod.data + vno
  166. ELSE (*import*)
  167. SYSTEM.GET(mod.imp + (mno-1)*4, impmod);
  168. SYSTEM.GET(impmod.ent + vno*4, offset);
  169. inst := impmod.data + offset
  170. END ;
  171. SYSTEM.PUT(adr, inst); adr := adr - disp*4
  172. END ;
  173. body (*initialize module*)
  174. ELSIF res = 3 THEN importing := name;
  175. WHILE nofimps > 0 DO DEC(nofimps); DEC(import[nofimps].refcnt) END
  176. END
  177. END ;
  178. newmod := mod
  179. END Load;
  180. PROCEDURE ThisCommand*(mod: Module; name: ARRAY OF CHAR): Command;
  181. VAR k, adr, w: INTEGER; ch: CHAR;
  182. s: ARRAY 32 OF CHAR;
  183. BEGIN res := 5; w := 0;
  184. IF mod # NIL THEN
  185. adr := mod.cmd; SYSTEM.GET(adr, ch);
  186. WHILE (ch # 0X) & (res # 0) DO k := 0; (*read command name*)
  187. REPEAT s[k] := ch; INC(k); INC(adr); SYSTEM.GET(adr, ch) UNTIL ch = 0X;
  188. s[k] := 0X;
  189. REPEAT INC(adr) UNTIL adr MOD 4 = 0;
  190. SYSTEM.GET(adr, k); INC(adr, 4);
  191. IF s = name THEN res := 0; w := mod.code + k ELSE SYSTEM.GET(adr, ch) END
  192. END
  193. END
  194. RETURN SYSTEM.VAL(Command, w)
  195. END ThisCommand;
  196. PROCEDURE Free*(name: ARRAY OF CHAR);
  197. VAR mod, imp: Module; p, q: INTEGER;
  198. BEGIN mod := root; res := 0;
  199. WHILE (mod # NIL) & (mod.name # name) DO mod := mod.next END ;
  200. IF mod # NIL THEN
  201. IF mod.refcnt = 0 THEN
  202. mod.name[0] := 0X; p := mod.imp; q := mod.cmd;
  203. WHILE p < q DO SYSTEM.GET(p, imp); DEC(imp.refcnt); INC(p, 4) END ;
  204. ELSE res := 1
  205. END
  206. END
  207. END Free;
  208. PROCEDURE Init*;
  209. BEGIN Files.Init; MTOrg := SYSTEM.REG(MT);
  210. SYSTEM.GET(16, AllocPtr); SYSTEM.GET(20, root); SYSTEM.GET(24, limit); DEC(limit, 8000H)
  211. END Init;
  212. BEGIN Init; Load("Oberon", M);
  213. LED(res); REPEAT UNTIL FALSE (*only if load fails*)
  214. END Modules.