mkdtest.mod 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. MODULE mkdtest ;
  2. (* Generates example.MC4, a single-module MC64 image that exercises far
  3. more of the interpreter than boot.MC4 :
  4. proc0 (TOINIT, main) :
  5. - a CARDINAL do-while loop g := g*2+1 (10 iterations) -> 2047
  6. - 32-bit arithmetic : add sub mul div mod
  7. - bit set ops / power2 (BitOp, Shl64)
  8. - 0x40 extended dispatch : drop, uc_add, uc_mul, uc_div, uc_mod,
  9. long_negate, build_field_mask
  10. - load_imm_word (0x8E), real arithmetic (real_add -> real_to_long)
  11. - dup / swap / copy_block
  12. - control flow : jp_fwd (0xE2), jpfalse_back (0xE5), jp_back (0xE4)
  13. - load/store global (0x2D/0x3D), global_dw (0x09), local_dw
  14. (0x08/0x18), proc_call (0xED) to proc1
  15. proc1 (print_num) :
  16. prints the CARDINAL in FP[3] as decimal text followed by CRLF via
  17. the SYSTEM write-string service. Exercises Enter/Leave (0xD4/0x85),
  18. load_param (0x03), reserve (0xD2), udiv/umod (0xA9/0xAA),
  19. store_indexed_byte (0x1D) and a do-while digit loop. *)
  20. FROM FileIO IMPORT WriteFile ;
  21. FROM Console IMPORT Fatal ;
  22. FROM SYSTEM IMPORT ADR ;
  23. CONST
  24. HeaderSize = 64 ;
  25. DescName = 264 ;
  26. DescChecksum = 288 ;
  27. DescFlags = 292 ;
  28. DescVarCount = 293 ;
  29. DescDepCount = 294 ;
  30. DescProcs = 296 ;
  31. ProcTable = 304 ;
  32. CodeOff = 312 ;
  33. BufSize = 4096 ;
  34. VAR
  35. buf : ARRAY [0 .. BufSize - 1] OF CHAR ;
  36. pcimg : CARDINAL ; (* image-relative cursor into the code *)
  37. i, sum : CARDINAL ;
  38. lp : CARDINAL ; (* loop label *)
  39. p1, pt : CARDINAL ; (* image offsets of proc1 and the proc table *)
  40. TYPE
  41. RealView = RECORD CASE : BOOLEAN OF
  42. | TRUE : r : REAL ;
  43. | FALSE : w : LONGCARD ;
  44. END ;
  45. END ;
  46. VAR
  47. rv : RealView ;
  48. PROCEDURE Op (o : CARDINAL) ;
  49. BEGIN
  50. buf [HeaderSize + pcimg] := CHR (o MOD 256) ;
  51. INC (pcimg) ;
  52. END Op ;
  53. PROCEDURE OpB (o, b : CARDINAL) ;
  54. BEGIN
  55. Op (o) ;
  56. buf [HeaderSize + pcimg] := CHR (b MOD 256) ;
  57. INC (pcimg) ;
  58. END OpB ;
  59. PROCEDURE Put32 (off, v : CARDINAL) ;
  60. BEGIN
  61. buf [off] := CHR (v MOD 256) ;
  62. buf [off + 1] := CHR ((v DIV 256) MOD 256) ;
  63. buf [off + 2] := CHR ((v DIV 65536) MOD 256) ;
  64. buf [off + 3] := CHR (v DIV 16777216) ;
  65. END Put32 ;
  66. PROCEDURE Put64 (off : CARDINAL ; v : LONGCARD) ;
  67. VAR j : CARDINAL ;
  68. BEGIN
  69. FOR j := 0 TO 7 DO
  70. buf [off + j] := CHR (VAL (CARDINAL, v MOD 256)) ;
  71. v := v DIV 256 ;
  72. END ;
  73. END Put64 ;
  74. PROCEDURE ImmB (b : CARDINAL) ;
  75. BEGIN
  76. OpB (8DH, b) ; (* load_imm_byte *)
  77. END ImmB ;
  78. PROCEDURE ImmU64 (v : LONGCARD) ;
  79. BEGIN
  80. Op (8EH) ; (* load_imm_word, 8-byte immediate *)
  81. Put64 (HeaderSize + pcimg, v) ;
  82. INC (pcimg, 8) ;
  83. END ImmU64 ;
  84. PROCEDURE Cg (n : CARDINAL) ;
  85. BEGIN
  86. OpB (2DH, n) ; (* load_global *)
  87. END Cg ;
  88. PROCEDURE Sg (n : CARDINAL) ;
  89. BEGIN
  90. OpB (3DH, n) ; (* store_global *)
  91. END Sg ;
  92. PROCEDURE Mark (VAR m : CARDINAL) ;
  93. BEGIN
  94. m := pcimg ;
  95. END Mark ;
  96. PROCEDURE JBack (o : CARDINAL ; m : CARDINAL) ;
  97. BEGIN
  98. Op (o) ;
  99. buf [HeaderSize + pcimg] := CHR (pcimg + 1 - m) ;
  100. INC (pcimg) ;
  101. END JBack ;
  102. PROCEDURE EStr (s : ARRAY OF CHAR ; nl : BOOLEAN) ;
  103. VAR len, i2 : CARDINAL ;
  104. BEGIN
  105. Op (8CH) ; (* call_rel : pc-relative string pointer *)
  106. IF nl THEN
  107. len := LENGTH (s) + 3 ;
  108. ELSE
  109. len := LENGTH (s) + 1 ;
  110. END ;
  111. buf [HeaderSize + pcimg] := CHR (len) ;
  112. INC (pcimg) ;
  113. IF LENGTH (s) > 0 THEN
  114. FOR i2 := 0 TO LENGTH (s) - 1 DO
  115. buf [HeaderSize + pcimg + i2] := s [i2] ;
  116. END ;
  117. END ;
  118. INC (pcimg, LENGTH (s)) ;
  119. IF nl THEN
  120. buf [HeaderSize + pcimg] := CHR (13) ; (* CR *)
  121. buf [HeaderSize + pcimg + 1] := CHR (10) ; (* LF *)
  122. INC (pcimg, 2) ;
  123. END ;
  124. buf [HeaderSize + pcimg] := 0C ; (* NUL *)
  125. INC (pcimg) ;
  126. END EStr ;
  127. PROCEDURE PrintStr ;
  128. BEGIN
  129. ImmB (1) ; (* system id = write NUL-terminated string *)
  130. Op (0C3H) ; (* system *)
  131. END PrintStr ;
  132. PROCEDURE Label (s : ARRAY OF CHAR) ;
  133. BEGIN
  134. EStr (s, FALSE) ;
  135. PrintStr ;
  136. END Label ;
  137. PROCEDURE Nl ;
  138. BEGIN
  139. EStr ("", TRUE) ;
  140. PrintStr ;
  141. END Nl ;
  142. PROCEDURE CallPrint ;
  143. BEGIN
  144. OpB (0EDH, 1) ; (* proc_call 1 *)
  145. END CallPrint ;
  146. PROCEDURE RealBits (v : REAL) ;
  147. BEGIN
  148. rv.r := v ;
  149. Op (8EH) ;
  150. Put64 (HeaderSize + pcimg, rv.w) ;
  151. INC (pcimg, 8) ;
  152. END RealBits ;
  153. BEGIN
  154. FOR i := 0 TO BufSize - 1 DO
  155. buf [i] := 0C ;
  156. END ;
  157. (* file header : magic *)
  158. buf [0] := 'M' ;
  159. buf [1] := 'C' ;
  160. buf [2] := '6' ;
  161. buf [3] := '4' ;
  162. (* descriptor *)
  163. buf [HeaderSize + DescName] := 'e' ;
  164. buf [HeaderSize + DescName + 1] := 'x' ;
  165. buf [HeaderSize + DescName + 2] := 'a' ;
  166. buf [HeaderSize + DescName + 3] := 'm' ;
  167. buf [HeaderSize + DescName + 4] := 'p' ;
  168. buf [HeaderSize + DescName + 5] := 'l' ;
  169. buf [HeaderSize + DescName + 6] := 'e' ;
  170. buf [HeaderSize + DescFlags] := CHR (4) ; (* TOINIT *)
  171. buf [HeaderSize + DescVarCount] := CHR (0) ;
  172. buf [HeaderSize + DescDepCount] := CHR (0) ;
  173. (* DescProcs is filled in once the table position is known *)
  174. pcimg := CodeOff ;
  175. (* ================= proc0 : main *)
  176. OpB (0D4H, 250) ; (* enter : 5 local slots *)
  177. Label ("mc64 test vm :: opcode exercise") ; Nl ;
  178. (* --- CARDINAL do-while loop : g := g*2+1, 10 iterations -> 1023 *)
  179. ImmB (1) ; Sg (0) ; (* g := 1 *)
  180. ImmB (10) ; Sg (2) ; (* i := 10 *)
  181. Mark (lp) ;
  182. Cg (0) ; ImmB (2) ; Op (0A8H) ; OpB (0AEH, 1) ; Sg (0) ; (* g := g*2+1 *)
  183. Cg (2) ; Op (0ADH) ; Sg (2) ; (* i := i-1 *)
  184. Cg (2) ; Op (0ABH) ; (* (i = 0)? *)
  185. JBack (0E5H, lp) ; (* jpfalse_back while i # 0 *)
  186. Label ("g after 10*2+1 = ") ; Cg (0) ; CallPrint ;
  187. Label ("add 10+6 = ") ; ImmB (10) ; ImmB (6) ; Op (0A6H) ; CallPrint ;
  188. Label ("sub 20-7 = ") ; ImmB (20) ; ImmB (7) ; Op (0A7H) ; CallPrint ;
  189. Label ("mul 6*7 = ") ; ImmB (6) ; ImmB (7) ; Op (0A8H) ; CallPrint ;
  190. Label ("div 100/8 = ") ; ImmB (100) ; ImmB (8) ; Op (0A9H) ; CallPrint ;
  191. Label ("mod 100%8 = ") ; ImmB (100) ; ImmB (8) ; Op (0AAH) ; CallPrint ;
  192. Label ("bitand FF&0F = ") ; ImmB (255) ; ImmB (15) ; Op (0E8H) ; CallPrint ;
  193. Label ("bitor F0|0F = ") ; ImmB (240) ; ImmB (15) ; Op (0E6H) ; CallPrint ;
  194. Label ("bitxor FF^0F = ") ; ImmB (255) ; ImmB (15) ; Op (0E9H) ; CallPrint ;
  195. Label ("power2 2^6 = ") ; ImmB (6) ; Op (0EAH) ; CallPrint ;
  196. Label ("uc_add (2^32-1)+2 = ") ;
  197. ImmU64 (0FFFFFFFFH) ; ImmB (2) ; Op (40H) ; Op (18H) ;
  198. Op (0BAH) ; CallPrint ;
  199. Label ("uc_mul 1234567890*2 = ") ;
  200. ImmU64 (1234567890) ; ImmB (2) ; Op (40H) ; Op (1AH) ;
  201. Op (0BAH) ; CallPrint ;
  202. Label ("uc_div 2^36/2^16 = ") ;
  203. ImmU64 (1000000000H) ;
  204. ImmU64 (65536) ;
  205. Op (40H) ; Op (1BH) ; Op (0BAH) ; CallPrint ;
  206. Label ("uc_mod (2^32+6) rem 16 = ") ;
  207. ImmU64 (100000006H) ; ImmB (16) ;
  208. Op (40H) ; Op (1CH) ; Op (0BAH) ; CallPrint ;
  209. Label ("long_negate F0F0F0F0 low = ") ;
  210. ImmU64 (4042322160) ; Op (40H) ; Op (03H) ;
  211. Op (0BAH) ; CallPrint ;
  212. Label ("field_mask (1<<8)-(1<<2) = ") ;
  213. ImmB (2) ; ImmB (8) ; Op (40H) ; Op (04H) ; CallPrint ;
  214. Label ("real_add 3.5+2.25 = ") ;
  215. RealBits (3.5) ; RealBits (2.25) ; Op (0D6H) ; Op (0BFH) ; CallPrint ;
  216. Label ("dup+add check = ") ;
  217. ImmB (2) ; Op (20H) ; Op (0A6H) ; ImmB (1) ; Op (0A6H) ; CallPrint ;
  218. Label ("swap check = ") ;
  219. ImmB (1) ; ImmB (2) ; Op (21H) ; Op (0A6H) ; CallPrint ;
  220. Label ("load_global_dw g = ") ;
  221. Op (09H) ; Op (00H) ; CallPrint ;
  222. Label ("local_dw FP[-2] = ") ;
  223. ImmB (99) ; OpB (18H, 0FEH) ; (* store_local_dw -2 *)
  224. OpB (08H, 0FEH) ; CallPrint ; (* load_local_dw -2 *)
  225. Label ("drop then 12 = ") ;
  226. ImmB (11) ; Op (40H) ; Op (00H) ; (* drop *)
  227. ImmB (12) ; CallPrint ;
  228. Label ("jp_fwd skip -> 7 = ") ;
  229. Op (0E2H) ; Op (03H) ; (* forward jump over 3 bytes *)
  230. ImmB (5) ; Op (0A6H) ; (* skipped at run time *)
  231. ImmB (7) ; CallPrint ;
  232. Label ("copy_block -> ") ;
  233. ImmB (4) ; Op (0D2H) ; Op (20H) ; (* dst := reserve 4 ; keep a copy *)
  234. EStr ("abc", FALSE) ; (* src string inline (call_rel) *)
  235. ImmB (4) ; Op (30H) ; (* copy_block : dst, src, size *)
  236. PrintStr ; (* write the copied "abc" *)
  237. Nl ;
  238. Op (50H) ; (* end_program *)
  239. p1 := pcimg ;
  240. (* ================= proc1 : print_num *)
  241. OpB (0D4H, 250) ; (* enter : 5 local slots *)
  242. ImmB (16) ; Op (0D2H) ; Sg (1) ; (* GP[1] := output buffer *)
  243. Op (90H) ; Op (90H) ; Sg (2) ; Sg (3) ; (* GP[2] count := 0, GP[3] index := 0 *)
  244. Op (03H) ; (* load_param 1 : the value *)
  245. Mark (lp) ;
  246. Cg (2) ; Op (0ACH) ; Sg (2) ; (* count := count + 1 *)
  247. Op (20H) ; ImmB (10) ; Op (0AAH) ; (* dup ; 10 ; umod -> remainder *)
  248. Op (21H) ; ImmB (10) ; Op (0A9H) ; (* swap ; 10 ; udiv -> quotient *)
  249. Op (20H) ; Op (0ABH) ; (* dup ; eq0 (quotient = 0) *)
  250. JBack (0E5H, lp) ; (* jpfalse_back while quotient # 0 *)
  251. Op (40H) ; Op (00H) ; (* drop the trailing quotient 0 *)
  252. Mark (lp) ;
  253. ImmB (48) ; Op (0A6H) ; Sg (4) ; (* GP[4] := char (digit + ORD('0')) *)
  254. Cg (1) ; Cg (3) ; Op (0A6H) ; (* addr := buf + index *)
  255. Op (90H) ; Cg (4) ; Op (1DH) ; (* buf [index] := char *)
  256. Cg (3) ; Op (0ACH) ; Sg (3) ; (* index := index + 1 *)
  257. Cg (2) ; Op (0ADH) ; Sg (2) ; (* count := count - 1 *)
  258. Cg (2) ; Op (0ABH) ; (* (count = 0)? *)
  259. JBack (0E5H, lp) ; (* jpfalse_back while count # 0 *)
  260. Cg (1) ; Cg (3) ; Op (0A6H) ; (* addr := buf + index *)
  261. Op (90H) ; Op (90H) ; Op (1DH) ; (* buf [index] := 0 (NUL) *)
  262. Cg (1) ; PrintStr ; (* write the number *)
  263. Nl ; (* CRLF *)
  264. OpB (85H, 0) ; (* fct_leave 0 *)
  265. (* procedure table, placed after the code so it never overlaps it *)
  266. pt := pcimg ;
  267. Put64 (HeaderSize + DescProcs, VAL (LONGCARD, pt)) ;
  268. Put64 (HeaderSize + pt, VAL (LONGCARD, 312) - VAL (LONGCARD, pt)) ;
  269. Put64 (HeaderSize + pt + 8,
  270. VAL (LONGCARD, p1) - VAL (LONGCARD, pt + 8)) ;
  271. INC (pcimg, 16) ;
  272. (* checksum over the image, excluding the checksum field *)
  273. sum := 0 ;
  274. FOR i := HeaderSize TO HeaderSize + pcimg - 1 DO
  275. IF NOT ((i >= 352) AND (i <= 355)) THEN
  276. sum := sum + ORD (buf [i]) ;
  277. END ;
  278. END ;
  279. Put32 (HeaderSize + DescChecksum, sum) ;
  280. IF NOT WriteFile ("example.MC4", buf, HeaderSize + pcimg) THEN
  281. Fatal ("mkdtest: cannot write example.MC4") ;
  282. END ;
  283. END mkdtest.