Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
4.9KB

  1. #include "user.inc"
  2. .org USER_CODE
  3. call parseLine
  4. ld b, 0
  5. ld c, a ; written bytes
  6. ret
  7. ; Sets Z is A is ';', CR, LF, or null.
  8. isLineEnd:
  9. cp ';'
  10. ret z
  11. cp 0
  12. ret z
  13. cp 0x0d
  14. ret z
  15. cp 0x0a
  16. ret
  17. ; Sets Z is A is ' ' or ','
  18. isSep:
  19. cp ' '
  20. ret z
  21. cp ','
  22. ret
  23. ; Sets Z is A is ' ', ',', ';', CR, LF, or null.
  24. isSepOrLineEnd:
  25. call isSep
  26. ret z
  27. call isLineEnd
  28. ret
  29. ; read word in (HL) and put it in (DE), null terminated. A is the read
  30. ; length. HL is advanced to the next separator char.
  31. readWord:
  32. push bc
  33. ld b, 4
  34. .loop:
  35. ld a, (hl)
  36. call isSepOrLineEnd
  37. jr z, .success
  38. call JUMP_UPCASE
  39. ld (de), a
  40. inc hl
  41. inc de
  42. djnz .loop
  43. .success:
  44. xor a
  45. ld (de), a
  46. ld a, 4
  47. sub a, b
  48. jr .end
  49. .error:
  50. xor a
  51. ld (de), a
  52. .end:
  53. pop bc
  54. ret
  55. ; (HL) being a string, advance it to the next non-sep character.
  56. ; Set Z if we could do it before the line ended, reset Z if we couldn't.
  57. toWord:
  58. .loop:
  59. ld a, (hl)
  60. call isLineEnd
  61. jr z, .error
  62. call isSep
  63. jr nz, .success
  64. inc hl
  65. jr .loop
  66. .error:
  67. ; we need the Z flag to be unset and it is set now. Let's CP with
  68. ; something it can't be equal to, something not a line end.
  69. cp 'a' ; Z flag unset
  70. ret
  71. .success:
  72. ; We need the Z flag to be set and it is unset. Let's compare it with
  73. ; itself to return a set Z
  74. cp a
  75. ret
  76. readLine:
  77. push de
  78. xor a
  79. ld (curWord), a
  80. ld (curArg1), a
  81. ld (curArg2), a
  82. ld de, curWord
  83. call readWord
  84. call toWord
  85. jr nz, .end
  86. ld de, curArg1
  87. call readWord
  88. call toWord
  89. jr nz, .end
  90. ld de, curArg2
  91. call readWord
  92. .end:
  93. pop de
  94. ret
  95. ; match argument string at (HL) with argspec A.
  96. ; Set Z/NZ on match
  97. matchArg:
  98. cp 0
  99. jr z, .matchnone
  100. ; Z is unset. TODO: implement rest
  101. jr .end
  102. .matchnone:
  103. ld a, (hl)
  104. cp 0 ; arg must be null to match
  105. .end:
  106. ret
  107. ; Compare primary row at (DE) with string at curWord. Sets Z flag if there's a
  108. ; match, reset if not.
  109. matchPrimaryRow:
  110. push hl
  111. push ix
  112. ld hl, curWord
  113. ld a, 4
  114. call JUMP_STRNCMP
  115. jr nz, .end
  116. ; name matches, let's see the rest
  117. ld ixh, d
  118. ld ixl, e
  119. ld hl, curArg1
  120. ld a, (ix+4)
  121. call matchArg
  122. jr nz, .end
  123. ld hl, curArg2
  124. ld a, (ix+5)
  125. call matchArg
  126. .end:
  127. pop ix
  128. pop hl
  129. ret
  130. ; Parse line at (HL) and write resulting opcode(s) in (DE). Returns the number
  131. ; of bytes written in A.
  132. parseLine:
  133. call readLine
  134. push de
  135. ld de, instTBlPrimary
  136. .loop:
  137. ld a, (de)
  138. cp 0
  139. jr z, .nomatch ; we reached last entry
  140. call matchPrimaryRow
  141. jr z, .match
  142. ld a, 7
  143. call JUMP_ADDDE
  144. jr .loop
  145. .nomatch:
  146. xor a
  147. pop de
  148. ret
  149. .match:
  150. ld a, 6 ; upcode is on 7th byte
  151. call JUMP_ADDDE
  152. ld a, (de)
  153. pop de
  154. ld (de), a
  155. ld a, 1
  156. ret
  157. ; In instruction metadata below, argument types arge indicated with a single
  158. ; char mnemonic that is called "argspec". This is the table of correspondance.
  159. ; Single letters are represented by themselves, so we don't need as much
  160. ; metadata.
  161. argspecsSingle:
  162. .db "ABCDEHL", 0
  163. ; Format: 1 byte argspec + 4 chars string
  164. argspecTbl:
  165. .db 'h', "HL", 0, 0
  166. .db 'l', "(HL)"
  167. .db 'd', "DE", 0, 0
  168. .db 'e', "(DE)"
  169. .db 'b', "BC", 0, 0
  170. .db 'c', "(BC)"
  171. .db 'a', "AF", 0, 0
  172. .db 'f', "AF'", 0
  173. .db 'x', "(IX)"
  174. .db 'y', "(IY)"
  175. .db 's', "SP", 0, 0
  176. .db 'p', "(SP)"
  177. .db 0
  178. ; This is a list of primary instructions (single upcode) that lead to a
  179. ; constant (no group code to insert).
  180. ; That doesn't mean that they don't take any argument though. For example,
  181. ; "DEC IX" leads to a special upcode. These kind of constants are indicated
  182. ; as a single byte to save space. Meaning:
  183. ;
  184. ; All single char registers (A/B/C etc) -> themselves
  185. ; HL -> h
  186. ; (HL) -> l
  187. ; DE -> d
  188. ; (DE) -> e
  189. ; BC -> b
  190. ; (BC) -> c
  191. ; IX -> X
  192. ; (IX) -> x
  193. ; IY -> Y
  194. ; (IY) -> y
  195. ; AF -> a
  196. ; AF' -> f
  197. ; SP -> s
  198. ; (SP) -> p
  199. ; None -> 0
  200. ;
  201. ; This is a sorted list of "primary" (single byte) instructions along with
  202. ; metadata
  203. ; 4 bytes for the name (fill with zero)
  204. ; 1 byte for arg constant
  205. ; 1 byte for 2nd arg constant
  206. ; 1 byte for upcode
  207. instTBlPrimary:
  208. .db "ADD", 0, 'A', 'h', 0x86 ; ADD A, HL
  209. .db "CCF", 0, 0, 0, 0x3f ; CCF
  210. .db "CPL", 0, 0, 0, 0x2f ; CPL
  211. .db "DAA", 0, 0, 0, 0x27 ; DAA
  212. .db "DI",0,0, 0, 0, 0xf3 ; DI
  213. .db "EI",0,0, 0, 0, 0xfb ; EI
  214. .db "EX",0,0, 'p', 'h', 0xe3 ; EX (SP), HL
  215. .db "EX",0,0, 'a', 'f', 0x08 ; EX AF, AF'
  216. .db "EX",0,0, 'd', 'h', 0xeb ; EX DE, HL
  217. .db "EXX", 0, 0, 0, 0xd9 ; EXX
  218. .db "HALT", 0, 0, 0x76 ; HALT
  219. .db "INC", 0, 'l', 0, 0x34 ; INC (HL)
  220. .db "JP",0,0, 'l', 0, 0xe9 ; JP (HL)
  221. .db "LD",0,0, 'c', 'A', 0x02 ; LD (BC), A
  222. .db "LD",0,0, 'e', 'A', 0x12 ; LD (DE), A
  223. .db "LD",0,0, 'A', 'c', 0x0a ; LD A, (BC)
  224. .db "LD",0,0, 'A', 'e', 0x0a ; LD A, (DE)
  225. .db "LD",0,0, 's', 'h', 0x0a ; LD SP, HL
  226. .db "NOP", 0, 0, 0, 0x00 ; NOP
  227. .db "RET", 0, 0, 0, 0xc9 ; RET
  228. .db "RLA", 0, 0, 0, 0x17 ; RLA
  229. .db "RLCA", 0, 0, 0x07 ; RLCA
  230. .db "RRA", 0, 0, 0, 0x1f ; RRA
  231. .db "RRCA", 0, 0, 0x0f ; RRCA
  232. .db "SCF", 0, 0, 0, 0x37 ; SCF
  233. .db 0
  234. ; *** Variables ***
  235. ; enough space for 4 chars and a null
  236. curWord:
  237. .db 0, 0, 0, 0, 0
  238. curArg1:
  239. .db 0, 0, 0, 0, 0
  240. curArg2:
  241. .db 0, 0, 0, 0, 0