Kernel.Mod.txt 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. MODULE Kernel; (*NW/PR 11.4.86 / 27.12.95 / 4.2.2014*)
  2. IMPORT SYSTEM;
  3. CONST SectorLength* = 1024;
  4. timer = -64; spiData = -48; spiCtrl = -44;
  5. CARD0 = 1; SPIFAST = 4;
  6. FSoffset = 80000H; (*256MB in 512-byte blocks*)
  7. mapsize = 10000H; (*1K sectors, 64MB*)
  8. TYPE Sector* = ARRAY SectorLength OF BYTE;
  9. VAR allocated*, NofSectors*: INTEGER;
  10. heapOrg*, heapLim*: INTEGER;
  11. stackOrg* , stackSize*, MemLim*: INTEGER;
  12. clock: INTEGER;
  13. list0, list1, list2, list3: INTEGER; (*lists of free blocks of size n*256, 128, 64, 32 bytes*)
  14. data: INTEGER; (*SPI data in*)
  15. sectorMap: ARRAY mapsize DIV 32 OF SET;
  16. (* ---------- New: heap allocation ----------*)
  17. PROCEDURE GetBlock(VAR p: LONGINT; len: LONGINT);
  18. (*len is multiple of 256*)
  19. VAR q0, q1, q2, size: LONGINT; done: BOOLEAN;
  20. BEGIN q0 := 0; q1 := list0; done := FALSE;
  21. WHILE ~done & (q1 # 0) DO
  22. SYSTEM.GET(q1, size); SYSTEM.GET(q1+8, q2);
  23. IF size < len THEN (*no fit*) q0 := q1; q1 := q2
  24. ELSIF size = len THEN (*extract -> p*)
  25. done := TRUE; p := q1;
  26. IF q0 # 0 THEN SYSTEM.PUT(q0+8, q2) ELSE list0 := q2 END
  27. ELSE (*reduce size*)
  28. done := TRUE; p := q1; q1 := q1 + len;
  29. SYSTEM.PUT(q1, size-len); SYSTEM.PUT(q1+4, -1); SYSTEM.PUT(q1+8, q2);
  30. IF q0 # 0 THEN SYSTEM.PUT(q0+8, q1) ELSE list0 := q1 END
  31. END
  32. END ;
  33. IF ~done THEN p := 0 END
  34. END GetBlock;
  35. PROCEDURE GetBlock128(VAR p: LONGINT);
  36. VAR q: LONGINT;
  37. BEGIN
  38. IF list1 # 0 THEN p := list1; SYSTEM.GET(list1+8, list1)
  39. ELSE GetBlock(q, 256); SYSTEM.PUT(q+128, 128); SYSTEM.PUT(q+132, -1); SYSTEM.PUT(q+136, list1);
  40. list1 := q + 128; p := q
  41. END
  42. END GetBlock128;
  43. PROCEDURE GetBlock64(VAR p: LONGINT);
  44. VAR q: LONGINT;
  45. BEGIN
  46. IF list2 # 0 THEN p := list2; SYSTEM.GET(list2+8, list2)
  47. ELSE GetBlock128(q); SYSTEM.PUT(q+64, 64); SYSTEM.PUT(q+68, -1); SYSTEM.PUT(q+72, list2);
  48. list2 := q + 64; p := q
  49. END
  50. END GetBlock64;
  51. PROCEDURE GetBlock32(VAR p: LONGINT);
  52. VAR q: LONGINT;
  53. BEGIN
  54. IF list3 # 0 THEN p := list3; SYSTEM.GET(list3+8, list3)
  55. ELSE GetBlock64(q); SYSTEM.PUT(q+32, 32); SYSTEM.PUT(q+36, -1); SYSTEM.PUT(q+40, list3);
  56. list3 := q + 32; p := q
  57. END
  58. END GetBlock32;
  59. PROCEDURE New*(VAR ptr: LONGINT; tag: LONGINT);
  60. (*called by NEW via MT[0]; ptr and tag are pointers*)
  61. VAR p, size, lim: LONGINT;
  62. BEGIN SYSTEM.GET(tag, size);
  63. IF size = 32 THEN GetBlock32(p)
  64. ELSIF size = 64 THEN GetBlock64(p)
  65. ELSIF size = 128 THEN GetBlock128(p)
  66. ELSE GetBlock(p, (size+255) DIV 256 * 256)
  67. END ;
  68. IF p = 0 THEN ptr := 0
  69. ELSE ptr := p+8; SYSTEM.PUT(p, tag); lim := p + size; INC(p, 4); INC(allocated, size);
  70. WHILE p < lim DO SYSTEM.PUT(p, 0); INC(p, 4) END
  71. END
  72. END New;
  73. (* ---------- Garbage collector ----------*)
  74. PROCEDURE Mark*(pref: LONGINT);
  75. VAR pvadr, offadr, offset, tag, p, q, r: LONGINT;
  76. BEGIN SYSTEM.GET(pref, pvadr); (*pointers < heapOrg considered NIL*)
  77. WHILE pvadr # 0 DO
  78. SYSTEM.GET(pvadr, p); SYSTEM.GET(p-4, offadr);
  79. IF (p >= heapOrg) & (offadr = 0) THEN q := p; (*mark elements in data structure with root p*)
  80. REPEAT SYSTEM.GET(p-4, offadr);
  81. IF offadr = 0 THEN SYSTEM.GET(p-8, tag); offadr := tag + 16 ELSE INC(offadr, 4) END ;
  82. SYSTEM.PUT(p-4, offadr); SYSTEM.GET(offadr, offset);
  83. IF offset # -1 THEN (*down*)
  84. SYSTEM.GET(p+offset, r); SYSTEM.GET(r-4, offadr);
  85. IF (r >= heapOrg) & (offadr = 0) THEN SYSTEM.PUT(p+offset, q); q := p; p := r END
  86. ELSE (*up*) SYSTEM.GET(q-4, offadr); SYSTEM.GET(offadr, offset);
  87. IF p # q THEN SYSTEM.GET(q+offset, r); SYSTEM.PUT(q+offset, p); p := q; q := r END
  88. END
  89. UNTIL (p = q) & (offset = -1)
  90. END ;
  91. INC(pref, 4); SYSTEM.GET(pref, pvadr)
  92. END
  93. END Mark;
  94. PROCEDURE Scan*;
  95. VAR p, q, mark, tag, size: LONGINT;
  96. BEGIN p := heapOrg;
  97. REPEAT SYSTEM.GET(p+4, mark); q := p;
  98. WHILE mark = 0 DO
  99. SYSTEM.GET(p, tag); SYSTEM.GET(tag, size); INC(p, size); SYSTEM.GET(p+4, mark)
  100. END ;
  101. size := p - q; DEC(allocated, size); (*size of free block*)
  102. IF size > 0 THEN
  103. IF size MOD 64 # 0 THEN
  104. SYSTEM.PUT(q, 32); SYSTEM.PUT(q+4, -1); SYSTEM.PUT(q+8, list3); list3 := q; INC(q, 32); DEC(size, 32)
  105. END ;
  106. IF size MOD 128 # 0 THEN
  107. SYSTEM.PUT(q, 64); SYSTEM.PUT(q+4, -1); SYSTEM.PUT(q+8, list2); list2 := q; INC(q, 64); DEC(size, 64)
  108. END ;
  109. IF size MOD 256 # 0 THEN
  110. SYSTEM.PUT(q, 128); SYSTEM.PUT(q+4, -1); SYSTEM.PUT(q+8, list1); list1 := q; INC(q, 128); DEC(size, 128)
  111. END ;
  112. IF size > 0 THEN
  113. SYSTEM.PUT(q, size); SYSTEM.PUT(q+4, -1); SYSTEM.PUT(q+8, list0); list0 := q; INC(q, size)
  114. END
  115. END ;
  116. IF mark > 0 THEN SYSTEM.GET(p, tag); SYSTEM.GET(tag, size); SYSTEM.PUT(p+4, 0); INC(p, size)
  117. ELSE (*free*) SYSTEM.GET(p, size); INC(p, size)
  118. END
  119. UNTIL p >= heapLim
  120. END Scan;
  121. (* ---------- Disk storage management ----------*)
  122. PROCEDURE SPIIdle(n: INTEGER); (*send n FFs slowly with no card selected*)
  123. BEGIN SYSTEM.PUT(spiCtrl, 0);
  124. WHILE n > 0 DO DEC(n); SYSTEM.PUT(spiData, -1);
  125. REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0);
  126. SYSTEM.GET(spiData, data)
  127. END
  128. END SPIIdle;
  129. PROCEDURE SPI(n: INTEGER); (*send&rcv byte slowly with card selected*)
  130. BEGIN SYSTEM.PUT(spiCtrl, CARD0); SYSTEM.PUT(spiData, n);
  131. REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0);
  132. SYSTEM.GET(spiData, data)
  133. END SPI;
  134. PROCEDURE SPICmd(n, arg: INTEGER);
  135. VAR i, crc: INTEGER;
  136. BEGIN (*send cmd*)
  137. REPEAT SPIIdle(1) UNTIL data = 255; (*flush while unselected*)
  138. REPEAT SPI(255) UNTIL data = 255; (*flush while selected*)
  139. IF n = 8 THEN crc := 135 ELSIF n = 0 THEN crc := 149 ELSE crc := 255 END;
  140. SPI(n MOD 64 + 64); (*send command*)
  141. FOR i := 24 TO 0 BY -8 DO SPI(ROR(arg, i)) END; (*send arg*)
  142. SPI(crc); i := 32;
  143. REPEAT SPI(255); DEC(i) UNTIL (data < 80H) OR (i = 0)
  144. END SPICmd;
  145. PROCEDURE SDShift(VAR n: INTEGER);
  146. VAR data: INTEGER;
  147. BEGIN SPICmd(58, 0); (*CMD58 get card capacity bit*)
  148. SYSTEM.GET(spiData, data); SPI(-1);
  149. IF (data # 0) OR ~SYSTEM.BIT(spiData, 6) THEN n := n * 512 END ; (*non-SDHC card*)
  150. SPI(-1); SPI(-1); SPIIdle(1) (*flush response*)
  151. END SDShift;
  152. PROCEDURE ReadSD(src, dst: INTEGER);
  153. VAR i: INTEGER;
  154. BEGIN SDShift(src); SPICmd(17, src); ASSERT(data = 0); (*CMD17 read one block*)
  155. i := 0; (*wait for start data marker*)
  156. REPEAT SPI(-1); INC(i) UNTIL data = 254;
  157. SYSTEM.PUT(spiCtrl, SPIFAST + CARD0);
  158. FOR i := 0 TO 508 BY 4 DO
  159. SYSTEM.PUT(spiData, -1);
  160. REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0);
  161. SYSTEM.GET(spiData, data); SYSTEM.PUT(dst, data); INC(dst, 4)
  162. END;
  163. SPI(255); SPI(255); SPIIdle(1) (*may be a checksum; deselect card*)
  164. END ReadSD;
  165. PROCEDURE WriteSD(dst, src: INTEGER);
  166. VAR i, n: INTEGER; x: BYTE;
  167. BEGIN SDShift(dst); SPICmd(24, dst); ASSERT(data = 0); (*CMD24 write one block*)
  168. SPI(254); (*write start data marker*)
  169. SYSTEM.PUT(spiCtrl, SPIFAST + CARD0);
  170. FOR i := 0 TO 508 BY 4 DO
  171. SYSTEM.GET(src, n); INC(src, 4); SYSTEM.PUT(spiData, n);
  172. REPEAT UNTIL SYSTEM.BIT(spiCtrl, 0)
  173. END;
  174. SPI(255); SPI(255); (*dummy checksum*) i := 0;
  175. REPEAT SPI(-1); INC(i); UNTIL (data MOD 32 = 5) OR (i = 10000);
  176. ASSERT(data MOD 32 = 5); SPIIdle(1) (*deselect card*)
  177. END WriteSD;
  178. PROCEDURE InitSecMap*;
  179. VAR i: INTEGER;
  180. BEGIN NofSectors := 0; sectorMap[0] := {0 .. 31}; sectorMap[1] := {0 .. 31};
  181. FOR i := 2 TO mapsize DIV 32 - 1 DO sectorMap[i] := {} END
  182. END InitSecMap;
  183. PROCEDURE MarkSector*(sec: INTEGER);
  184. BEGIN sec := sec DIV 29; ASSERT(SYSTEM.H(0) = 0);
  185. INCL(sectorMap[sec DIV 32], sec MOD 32); INC(NofSectors)
  186. END MarkSector;
  187. PROCEDURE FreeSector*(sec: INTEGER);
  188. BEGIN sec := sec DIV 29; ASSERT(SYSTEM.H(0) = 0);
  189. EXCL(sectorMap[sec DIV 32], sec MOD 32); DEC(NofSectors)
  190. END FreeSector;
  191. PROCEDURE AllocSector*(hint: INTEGER; VAR sec: INTEGER);
  192. VAR s: INTEGER;
  193. BEGIN (*find free sector, starting after hint*)
  194. hint := hint DIV 29; ASSERT(SYSTEM.H(0) = 0); s := hint;
  195. REPEAT INC(s);
  196. IF s = mapsize THEN s := 1 END ;
  197. UNTIL ~(s MOD 32 IN sectorMap[s DIV 32]);
  198. INCL(sectorMap[s DIV 32], s MOD 32); INC(NofSectors); sec := s * 29
  199. END AllocSector;
  200. PROCEDURE GetSector*(src: INTEGER; VAR dst: Sector);
  201. BEGIN src := src DIV 29; ASSERT(SYSTEM.H(0) = 0);
  202. src := src * 2 + FSoffset;
  203. ReadSD(src, SYSTEM.ADR(dst)); ReadSD(src+1, SYSTEM.ADR(dst)+512)
  204. END GetSector;
  205. PROCEDURE PutSector*(dst: INTEGER; VAR src: Sector);
  206. BEGIN dst := dst DIV 29; ASSERT(SYSTEM.H(0) = 0);
  207. dst := dst * 2 + FSoffset;
  208. WriteSD(dst, SYSTEM.ADR(src)); WriteSD(dst+1, SYSTEM.ADR(src)+512)
  209. END PutSector;
  210. (*-------- Miscellaneous procedures----------*)
  211. PROCEDURE Time*(): INTEGER;
  212. VAR t: INTEGER;
  213. BEGIN SYSTEM.GET(timer, t); RETURN t
  214. END Time;
  215. PROCEDURE Clock*(): INTEGER;
  216. BEGIN RETURN clock
  217. END Clock;
  218. PROCEDURE SetClock*(dt: INTEGER);
  219. BEGIN clock := dt
  220. END SetClock;
  221. PROCEDURE Install*(Padr, at: INTEGER);
  222. BEGIN SYSTEM.PUT(at, 0E7000000H + (Padr - at) DIV 4 -1)
  223. END Install;
  224. PROCEDURE Trap(VAR a: INTEGER; b: INTEGER);
  225. VAR u, v, w: INTEGER;
  226. BEGIN u := SYSTEM.REG(15); SYSTEM.GET(u - 4, v); w := v DIV 10H MOD 10H; (*trap number*)
  227. IF w = 0 THEN New(a, b)
  228. ELSE (*stop*) LED(w + 192); REPEAT UNTIL FALSE
  229. END
  230. END Trap;
  231. PROCEDURE Init*;
  232. BEGIN Install(SYSTEM.ADR(Trap), 20H); (*install temporary trap*)
  233. SYSTEM.GET(12, MemLim); SYSTEM.GET(24, heapOrg);
  234. stackOrg := heapOrg; stackSize := 8000H; heapLim := MemLim;
  235. list1 := 0; list2 := 0; list3 := 0; list0 := heapOrg;
  236. SYSTEM.PUT(list0, heapLim - heapOrg); SYSTEM.PUT(list0+4, -1); SYSTEM.PUT(list0+8, 0);
  237. allocated := 0; clock := 0; InitSecMap
  238. END Init;
  239. END Kernel.