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.

766 lines
17KB

  1. #include "user.inc"
  2. ; *** Consts ***
  3. ; Number of rows in the argspec table
  4. ARGSPEC_TBL_CNT .equ 27
  5. ; Number of rows in the primary instructions table
  6. INSTR_TBLP_CNT .equ 58
  7. ; size in bytes of each row in the primary instructions table
  8. INSTR_TBLP_ROWSIZE .equ 8
  9. ; *** Code ***
  10. .org USER_CODE
  11. call parseLine
  12. ld b, 0
  13. ld c, a ; written bytes
  14. ret
  15. unsetZ:
  16. push bc
  17. ld b, a
  18. inc b
  19. cp b
  20. pop bc
  21. ret
  22. ; run RLA the number of times specified in B
  23. rlaX:
  24. ; first, see if B == 0 to see if we need to bail out
  25. inc b
  26. dec b
  27. ret z ; Z flag means we had B = 0
  28. .loop: rla
  29. djnz .loop
  30. ret
  31. ; If string at (HL) starts with ( and ends with ), "enter" into the parens
  32. ; (advance HL and put a null char at the end of the string) and set Z.
  33. ; Otherwise, do nothing and reset Z.
  34. enterParens:
  35. ld a, (hl)
  36. cp '('
  37. ret nz ; nothing to do
  38. push hl
  39. ld a, 0 ; look for null char
  40. ; advance until we get null
  41. .loop:
  42. cpi
  43. jp z, .found
  44. jr .loop
  45. .found:
  46. dec hl ; cpi over-advances. go back to null-char
  47. dec hl ; looking at the last char before null
  48. ld a, (hl)
  49. cp ')'
  50. jr nz, .doNotEnter
  51. ; We have parens. While we're here, let's put a null
  52. xor a
  53. ld (hl), a
  54. pop hl ; back at the beginning. Let's advance.
  55. inc hl
  56. cp a ; ensure Z
  57. ret ; we're good!
  58. .doNotEnter:
  59. pop hl
  60. call unsetZ
  61. ret
  62. ; Checks whether A is 'N' or 'M'
  63. checkNOrM:
  64. cp 'N'
  65. ret z
  66. cp 'M'
  67. ret
  68. ; Parse the decimal char at A and extract it's 0-9 numerical value. Put the
  69. ; result in A.
  70. ;
  71. ; On success, the carry flag is reset. On error, it is set.
  72. parseDecimal:
  73. ; First, let's see if we have an easy 0-9 case
  74. cp '0'
  75. ret c ; if < '0', we have a problem
  76. cp '9'+1
  77. ; We are in the 0-9 range
  78. sub a, '0' ; C is clear
  79. ret
  80. ; Parses the string at (HL) and returns the 16-bit value in IX.
  81. ; As soon as the number doesn't fit 16-bit any more, parsing stops and the
  82. ; number is invalid. If the number is valid, Z is set, otherwise, unset.
  83. ; If (HL) contains a number inside parens, we properly enter into it.
  84. ; Upon successful return, A is set to 'N' for a parens-less number, 'M' for
  85. ; a number inside parens.
  86. parseNumber:
  87. push hl
  88. push de
  89. push bc
  90. ; Let's see if we have parens and already set the A result in B.
  91. ld b, 'N' ; if no parens
  92. call enterParens
  93. jr nz, .noparens
  94. ld b, 'M' ; we have parens and entered it.
  95. .noparens:
  96. ld ix, 0
  97. .loop:
  98. ld a, (hl)
  99. cp 0
  100. jr z, .end ; success!
  101. call parseDecimal
  102. jr c, .error
  103. ; Now, let's add A to IX. First, multiply by 10.
  104. ld d, ixh ; we need a copy of the initial copy for later
  105. ld e, ixl
  106. add ix, ix ; x2
  107. add ix, ix ; x4
  108. add ix, ix ; x8
  109. add ix, de ; x9
  110. add ix, de ; x10
  111. add a, ixl
  112. jr nc, .nocarry
  113. inc ixh
  114. .nocarry:
  115. ld ixl, a
  116. ; We didn't bother checking for the C flag at each step because we
  117. ; check for overflow afterwards. If ixh < d, we overflowed
  118. ld a, ixh
  119. cp d
  120. jr c, .error ; carry is set? overflow
  121. inc hl
  122. jr .loop
  123. .error:
  124. call unsetZ
  125. .end:
  126. ld a, b
  127. pop bc
  128. pop de
  129. pop hl
  130. ret
  131. ; Sets Z is A is ';', CR, LF, or null.
  132. isLineEnd:
  133. cp ';'
  134. ret z
  135. cp 0
  136. ret z
  137. cp 0x0d
  138. ret z
  139. cp 0x0a
  140. ret
  141. ; Sets Z is A is ' ' or ','
  142. isSep:
  143. cp ' '
  144. ret z
  145. cp ','
  146. ret
  147. ; Sets Z is A is ' ', ',', ';', CR, LF, or null.
  148. isSepOrLineEnd:
  149. call isSep
  150. ret z
  151. call isLineEnd
  152. ret
  153. ; read word in (HL) and put it in (DE), null terminated. A is the read
  154. ; length. HL is advanced to the next separator char.
  155. readWord:
  156. push bc
  157. ld b, 4
  158. .loop:
  159. ld a, (hl)
  160. call isSepOrLineEnd
  161. jr z, .success
  162. call JUMP_UPCASE
  163. ld (de), a
  164. inc hl
  165. inc de
  166. djnz .loop
  167. .success:
  168. xor a
  169. ld (de), a
  170. ld a, 4
  171. sub a, b
  172. jr .end
  173. .error:
  174. xor a
  175. ld (de), a
  176. .end:
  177. pop bc
  178. ret
  179. ; (HL) being a string, advance it to the next non-sep character.
  180. ; Set Z if we could do it before the line ended, reset Z if we couldn't.
  181. toWord:
  182. .loop:
  183. ld a, (hl)
  184. call isLineEnd
  185. jr z, .error
  186. call isSep
  187. jr nz, .success
  188. inc hl
  189. jr .loop
  190. .error:
  191. ; we need the Z flag to be unset and it is set now. Let's CP with
  192. ; something it can't be equal to, something not a line end.
  193. cp 'a' ; Z flag unset
  194. ret
  195. .success:
  196. ; We need the Z flag to be set and it is unset. Let's compare it with
  197. ; itself to return a set Z
  198. cp a
  199. ret
  200. ; Read arg from (HL) into argspec at (DE)
  201. ; HL is advanced to the next word. Z is set if there's a next word.
  202. readArg:
  203. push de
  204. ld de, tmpBuf
  205. call readWord
  206. push hl
  207. ld hl, tmpBuf
  208. call parseArg
  209. pop hl
  210. pop de
  211. ld (de), a
  212. ; When A is a number, IX is set with the value of that number. Because
  213. ; We don't use the space allocated to store those numbers in any other
  214. ; occasion, we store IX there unconditonally, LSB first.
  215. inc de
  216. ld a, ixl
  217. ld (de), a
  218. inc de
  219. ld a, ixh
  220. ld (de), a
  221. call toWord
  222. ret
  223. ; Read line from (HL) into (curWord), (curArg1) and (curArg2)
  224. readLine:
  225. push de
  226. xor a
  227. ld (curWord), a
  228. ld (curArg1), a
  229. ld (curArg2), a
  230. ld de, curWord
  231. call readWord
  232. call toWord
  233. jr nz, .end
  234. ld de, curArg1
  235. call readArg
  236. jr nz, .end
  237. ld de, curArg2
  238. call readArg
  239. .end:
  240. pop de
  241. ret
  242. ; Returns length of string at (HL) in A.
  243. strlen:
  244. push bc
  245. push hl
  246. ld bc, 0
  247. ld a, 0 ; look for null char
  248. .loop:
  249. cpi
  250. jp z, .found
  251. jr .loop
  252. .found:
  253. ; How many char do we have? the (NEG BC)-1, which started at 0 and
  254. ; decreased at each CPI call. In this routine, we stay in the 8-bit
  255. ; realm, so C only.
  256. ld a, c
  257. neg
  258. dec a
  259. pop hl
  260. pop bc
  261. ret
  262. ; find argspec for string at (HL). Returns matching argspec in A.
  263. ; Return value 0xff holds a special meaning: arg is not empty, but doesn't match
  264. ; any argspec (A == 0 means arg is empty). A return value of 0xff means an
  265. ; error.
  266. ;
  267. ; If the parsed argument is a number constant, 'N' is returned and IX contains
  268. ; the value of that constant.
  269. parseArg:
  270. call strlen
  271. cp 0
  272. ret z ; empty string? A already has our result: 0
  273. push bc
  274. push de
  275. push hl
  276. ld de, argspecTbl
  277. ; DE now points the the "argspec char" part of the entry, but what
  278. ; we're comparing in the loop is the string next to it. Let's offset
  279. ; DE by one so that the loop goes through strings.
  280. inc de
  281. ld b, ARGSPEC_TBL_CNT
  282. .loop1:
  283. ld a, 4
  284. call JUMP_STRNCMP
  285. jr z, .found ; got it!
  286. ld a, 5
  287. call JUMP_ADDDE
  288. djnz .loop1
  289. ; We exhausted the argspecs. Let's see if it's a number. This sets
  290. ; A to 'N' or 'M'
  291. call parseNumber
  292. jr z, .end ; Alright, we have a parsed number in IX. We're
  293. ; done.
  294. ; not a number
  295. ld a, 0xff
  296. jr .end
  297. .found:
  298. ; found the matching argspec row. Our result is one byte left of DE.
  299. dec de
  300. ld a, (de)
  301. .end:
  302. pop hl
  303. pop de
  304. pop bc
  305. ret
  306. ; Returns, with Z, whether A is a groupId
  307. isGroupId:
  308. cp 0xc ; max group id + 1
  309. jr nc, .notgroup ; >= 0xc? not a group
  310. cp 0
  311. jr z, .notgroup ; 0? not supposed to happen. something's wrong.
  312. ; A is a group. ensure Z is set
  313. cp a
  314. ret
  315. .notgroup:
  316. call unsetZ
  317. ret
  318. ; Find argspec A in group id H.
  319. ; Set Z according to whether we found the argspec
  320. ; If found, the value in A is the argspec value in the group (its index).
  321. findInGroup:
  322. push bc
  323. push hl
  324. cp 0 ; is our arg empty? If yes, we have nothing to do
  325. jr z, .notfound
  326. push af
  327. ld a, h
  328. cp 0xa
  329. jr z, .specialGroupCC
  330. cp 0xb
  331. jr z, .specialGroupABCDEHL
  332. pop af
  333. ; regular group
  334. push de
  335. ld de, argGrpTbl
  336. ; group ids start at 1. decrease it, then multiply by 4 to have a
  337. ; proper offset in argGrpTbl
  338. dec h
  339. push af
  340. ld a, h
  341. rla
  342. rla
  343. call JUMP_ADDDE ; At this point, DE points to our group
  344. pop af
  345. ex hl, de ; And now, HL points to the group
  346. pop de
  347. ld bc, 4
  348. jr .find
  349. .specialGroupCC:
  350. ld hl, argGrpCC
  351. jr .specialGroupEnd
  352. .specialGroupABCDEHL:
  353. ld hl, argGrpABCDEHL
  354. .specialGroupEnd:
  355. pop af ; from the push af just before the special group check
  356. ld bc, 8
  357. .find:
  358. ; This part is common to regular and special group. We expect HL to
  359. ; point to the group and BC to contain its length.
  360. push bc ; save the start value loop index so we can sub
  361. .loop:
  362. cpi
  363. jr z, .found
  364. jp po, .notfound
  365. jr .loop
  366. .found:
  367. ; we found our result! Now, what we want to put in A is the index of
  368. ; the found argspec.
  369. pop hl ; we pop from the "push bc" above. L is now 4 or 8
  370. ld a, l
  371. sub c
  372. dec a ; cpi DECs BC even when there's a match, so C == the
  373. ; number of iterations we've made. But our index is
  374. ; zero-based (1 iteration == 0 index).
  375. cp a ; ensure Z is set
  376. jr .end
  377. .notfound:
  378. pop bc ; from the push bc in .find
  379. call unsetZ
  380. .end:
  381. pop hl
  382. pop bc
  383. ret
  384. ; Compare argspec from instruction table in A with argument in (HL).
  385. ; For constant args, it's easy: if A == (HL), it's a success.
  386. ; If it's not this, then we check if it's a numerical arg.
  387. ; If A is a group ID, we do something else: we check that (HL) exists in the
  388. ; groupspec (argGrpTbl)
  389. matchArg:
  390. cp a, (hl)
  391. ret z
  392. ; not an exact match, let's check for numerical constants.
  393. call JUMP_UPCASE
  394. cp 'N'
  395. jr z, .expectsNumber
  396. cp 'M'
  397. jr z, .expectsNumber
  398. jr .notNumber
  399. .expectsNumber:
  400. ld a, (hl)
  401. call checkNOrM ; In parsed arg, we don't have 'n' or 'm', only
  402. ; 'N' and 'M'
  403. ret ; whether we match or not, the result of Z is
  404. ; the good one.
  405. .notNumber:
  406. ; A bit of a delicate situation here: we want A to go in H but also
  407. ; (HL) to go in A. If not careful, we overwrite each other. EXX is
  408. ; necessary to avoid invoving other registers.
  409. push hl
  410. exx
  411. ld h, a
  412. push hl
  413. exx
  414. ld a, (hl)
  415. pop hl
  416. call findInGroup
  417. pop hl
  418. ret
  419. ; Compare primary row at (DE) with string at curWord. Sets Z flag if there's a
  420. ; match, reset if not.
  421. matchPrimaryRow:
  422. push hl
  423. push ix
  424. ld hl, curWord
  425. ld a, 4
  426. call JUMP_STRNCMP
  427. jr nz, .end
  428. ; name matches, let's see the rest
  429. ld ixh, d
  430. ld ixl, e
  431. ld hl, curArg1
  432. ld a, (ix+4)
  433. call matchArg
  434. jr nz, .end
  435. ld hl, curArg2
  436. ld a, (ix+5)
  437. call matchArg
  438. .end:
  439. pop ix
  440. pop hl
  441. ret
  442. ; Parse line at (HL) and write resulting opcode(s) in (DE). Returns the number
  443. ; of bytes written in A.
  444. ;
  445. ; Overwrites IX
  446. parseLine:
  447. call readLine
  448. ; Check whether we have errors. We don't do any parsing if we do.
  449. ld a, (curArg1)
  450. cp 0xff
  451. jr z, .error
  452. ret z
  453. ld a, (curArg2)
  454. cp 0xff
  455. jr nz, .noerror
  456. .error:
  457. ld a, 0
  458. ret
  459. .noerror:
  460. push de
  461. ld de, instrTBlPrimary
  462. ld b, INSTR_TBLP_CNT
  463. .loop:
  464. ld a, (de)
  465. call matchPrimaryRow
  466. jr z, .match
  467. ld a, INSTR_TBLP_ROWSIZE
  468. call JUMP_ADDDE
  469. djnz .loop
  470. ; no match
  471. xor a
  472. pop de
  473. ret
  474. .match:
  475. ; We have our matching instruction row. We're getting pretty near our
  476. ; goal here!
  477. ; First, let's go in IX mode. It's easier to deal with offsets here.
  478. ld ixh, d
  479. ld ixl, e
  480. ; First, let's see if we're dealing with a group here
  481. ld a, (ix+4) ; first argspec
  482. call isGroupId
  483. jr z, .firstArgIsGroup
  484. ; First arg not a group. Maybe second is?
  485. ld a, (ix+5) ; 2nd argspec
  486. call isGroupId
  487. jr nz, .notgroup
  488. ; Second arg is group
  489. ld de, curArg2
  490. jr .isGroup
  491. .firstArgIsGroup:
  492. ld de, curArg1
  493. .isGroup:
  494. ; A is a group, good, now let's get its value. DE is pointing to
  495. ; the argument.
  496. push hl
  497. ld h, a
  498. ld a, (de)
  499. call findInGroup ; we don't check for match, it's supposed to
  500. ; always match. Something is very wrong if it
  501. ; doesn't
  502. ; Now, we have our arg "group value" in A. Were going to need to
  503. ; displace it left by the number of steps specified in the table.
  504. push bc
  505. push af
  506. ld a, (ix+6) ; displacement bit
  507. ld b, a
  508. pop af
  509. call rlaX
  510. pop bc
  511. ; At this point, we have a properly displaced value in A. We'll want
  512. ; to OR it with the opcode.
  513. or (ix+7) ; upcode
  514. pop hl
  515. ; Success!
  516. jr .writeFirstOpcode
  517. .notgroup:
  518. ; not a group? easy as pie: we return the opcode directly.
  519. ld a, (ix+7) ; upcode is on 8th byte
  520. .writeFirstOpcode:
  521. ; At the end, we have our final opcode in A!
  522. pop de
  523. ld (de), a
  524. ; Good, we are probably finished here for many primary opcodes. However,
  525. ; some primary opcodes take 8 or 16 bit constants as an argument and
  526. ; if that's the case here, we need to write it too.
  527. ; We still have our instruction row in IX. Let's revisit it.
  528. push hl ; we use HL to point to the currently read arg
  529. ld a, (ix+4) ; first argspec
  530. ld hl, curArg1
  531. call checkNOrM
  532. jr z, .withWord
  533. cp 'n'
  534. jr z, .withByte
  535. cp 'm'
  536. jr z, .withByte
  537. ld a, (ix+5) ; second argspec
  538. ld hl, curArg2
  539. call checkNOrM
  540. jr z, .withWord
  541. cp 'n'
  542. jr z, .withByte
  543. cp 'm'
  544. jr z, .withByte
  545. ; nope, no number, aright, only one opcode
  546. ld a, 1
  547. jr .end
  548. .withByte:
  549. ; verify that the MSB in argument is zero
  550. inc hl
  551. inc hl ; MSB is 2nd byte
  552. ld a, (hl)
  553. dec hl ; HL now points to LSB
  554. cp 0
  555. jr nz, .numberTruncated
  556. ; Clear to proceed. HL already points to our number
  557. inc de
  558. ldi
  559. ld a, 2
  560. jr .end
  561. .withWord:
  562. inc de
  563. inc hl ; HL now points to LSB
  564. ; Clear to proceed. HL already points to our number
  565. ldi ; LSB written, we point to MSB now
  566. ldi ; MSB written
  567. ld a, 3
  568. jr .end
  569. .numberTruncated:
  570. ; problem: not zero, so value is truncated. error
  571. xor a
  572. .end:
  573. pop hl
  574. ret
  575. ; In instruction metadata below, argument types arge indicated with a single
  576. ; char mnemonic that is called "argspec". This is the table of correspondance.
  577. ; Single letters are represented by themselves, so we don't need as much
  578. ; metadata.
  579. ; Special meaning:
  580. ; 0 : no arg
  581. ; 1-10 : group id (see Groups section)
  582. ; 0xff: error
  583. ; Format: 1 byte argspec + 4 chars string
  584. argspecTbl:
  585. .db 'A', "A", 0, 0, 0
  586. .db 'B', "B", 0, 0, 0
  587. .db 'C', "C", 0, 0, 0
  588. .db 'D', "D", 0, 0, 0
  589. .db 'E', "E", 0, 0, 0
  590. .db 'H', "H", 0, 0, 0
  591. .db 'L', "L", 0, 0, 0
  592. .db 'h', "HL", 0, 0
  593. .db 'l', "(HL)"
  594. .db 'd', "DE", 0, 0
  595. .db 'e', "(DE)"
  596. .db 'b', "BC", 0, 0
  597. .db 'c', "(BC)"
  598. .db 'a', "AF", 0, 0
  599. .db 'f', "AF'", 0
  600. .db 'x', "(IX)" ; always come with displacement
  601. .db 'y', "(IY)" ; with JP
  602. .db 's', "SP", 0, 0
  603. .db 'p', "(SP)"
  604. ; we also need argspecs for the condition flags
  605. .db 'Z', "Z", 0, 0, 0
  606. .db 'z', "NZ", 0, 0
  607. .db '^', "C", 0, 0, 0
  608. .db '=', "NC", 0, 0
  609. .db '+', "P", 0, 0, 0
  610. .db '-', "M", 0, 0, 0
  611. .db '1', "PO", 0, 0
  612. .db '2', "PE", 0, 0
  613. ; argspecs not in the list:
  614. ; n -> N
  615. ; N -> NN
  616. ; m -> (N) (running out of mnemonics. 'm' for 'memory pointer')
  617. ; M -> (NN)
  618. ; Groups
  619. ; Groups are specified by strings of argspecs. To facilitate jumping to them,
  620. ; we have a fixed-sized table. Because most of them are 2 or 4 bytes long, we
  621. ; have a table that is 4 in size to minimize consumed space. We treat the two
  622. ; groups that take 8 bytes in a special way.
  623. ;
  624. ; The table below is in order, starting with group 0x01
  625. argGrpTbl:
  626. .db "bdha" ; 0x01
  627. .db "Zz^=" ; 0x02
  628. .db "bdhs" ; 0x03
  629. argGrpCC:
  630. .db "Zz^=+-12" ; 0xa
  631. argGrpABCDEHL:
  632. .db "BCDEHL_A" ; 0xb
  633. ; This is a list of primary instructions (single upcode) that lead to a
  634. ; constant (no group code to insert). Format:
  635. ;
  636. ; 4 bytes for the name (fill with zero)
  637. ; 1 byte for arg constant
  638. ; 1 byte for 2nd arg constant
  639. ; 1 byte displacement for group arguments
  640. ; 1 byte for upcode
  641. instrTBlPrimary:
  642. .db "ADD", 0, 'A', 'h', 0, 0x86 ; ADD A, HL
  643. .db "ADD", 0, 'A', 0xb, 0, 0b10000000 ; ADD A, r
  644. .db "ADD", 0, 'A', 'n', 0, 0xc6 ; ADD A, n
  645. .db "ADC", 0, 'A', 'h', 0, 0x8e ; ADC A, HL
  646. .db "ADC", 0, 'A', 0xb, 0, 0b10001000 ; ADC A, r
  647. .db "AND", 0, 'l', 0, 0, 0xa6 ; AND (HL)
  648. .db "AND", 0, 0xa, 0, 0, 0b10100000 ; AND r
  649. .db "CCF", 0, 0, 0, 0, 0x3f ; CCF
  650. .db "CP",0,0, 'l', 0, 0, 0xbe ; CP (HL)
  651. .db "CP",0,0, 0xb, 0, 0, 0b10111000 ; CP r
  652. .db "CPL", 0, 0, 0, 0, 0x2f ; CPL
  653. .db "DAA", 0, 0, 0, 0, 0x27 ; DAA
  654. .db "DI",0,0, 0, 0, 0, 0xf3 ; DI
  655. .db "DEC", 0, 'l', 0, 0, 0x35 ; DEC (HL)
  656. .db "DEC", 0, 0xb, 0, 3, 0b00000101 ; DEC r
  657. .db "DEC", 0, 0x3, 0, 4, 0b00001011 ; DEC s
  658. .db "EI",0,0, 0, 0, 0, 0xfb ; EI
  659. .db "EX",0,0, 'p', 'h', 0, 0xe3 ; EX (SP), HL
  660. .db "EX",0,0, 'a', 'f', 0, 0x08 ; EX AF, AF'
  661. .db "EX",0,0, 'd', 'h', 0, 0xeb ; EX DE, HL
  662. .db "EXX", 0, 0, 0, 0, 0xd9 ; EXX
  663. .db "HALT", 0, 0, 0, 0x76 ; HALT
  664. .db "IN",0,0, 'A', 'm', 0, 0xdb ; IN A, (n)
  665. .db "INC", 0, 'l', 0, 0, 0x34 ; INC (HL)
  666. .db "INC", 0, 0xb, 0, 3, 0b00000100 ; INC r
  667. .db "INC", 0, 0x3, 0, 4, 0b00000011 ; INC s
  668. .db "JP",0,0, 'l', 0, 0, 0xe9 ; JP (HL)
  669. .db "JP",0,0, 'N', 0, 0, 0xc3 ; JP NN
  670. .db "LD",0,0, 'c', 'A', 0, 0x02 ; LD (BC), A
  671. .db "LD",0,0, 'e', 'A', 0, 0x12 ; LD (DE), A
  672. .db "LD",0,0, 'A', 'c', 0, 0x0a ; LD A, (BC)
  673. .db "LD",0,0, 'A', 'e', 0, 0x0a ; LD A, (DE)
  674. .db "LD",0,0, 's', 'h', 0, 0x0a ; LD SP, HL
  675. .db "LD",0,0, 'l', 0xb, 0, 0b01110000 ; LD (HL), r
  676. .db "LD",0,0, 0xb, 'l', 3, 0b01000110 ; LD r, (HL)
  677. .db "LD",0,0, 'l', 'n', 0, 0x36 ; LD (HL), n
  678. .db "LD",0,0, 0xb, 'n', 3, 0b00000110 ; LD r, (HL)
  679. .db "LD",0,0, 0x3, 'N', 4, 0b00000001 ; LD dd, n
  680. .db "NOP", 0, 0, 0, 0, 0x00 ; NOP
  681. .db "OR",0,0, 'l', 0, 0, 0xb6 ; OR (HL)
  682. .db "OR",0,0, 0xb, 0, 0, 0b10110000 ; OR r
  683. .db "OUT", 0, 'm', 'A', 0, 0xd3 ; OUT (n), A
  684. .db "POP", 0, 0x1, 0, 4, 0b11000001 ; POP qq
  685. .db "PUSH", 0x1, 0, 4, 0b11000101 ; PUSH qq
  686. .db "RET", 0, 0xa, 0, 3, 0b11000000 ; RET cc
  687. .db "RET", 0, 0, 0, 0, 0xc9 ; RET
  688. .db "RLA", 0, 0, 0, 0, 0x17 ; RLA
  689. .db "RLCA", 0, 0, 0, 0x07 ; RLCA
  690. .db "RRA", 0, 0, 0, 0, 0x1f ; RRA
  691. .db "RRCA", 0, 0, 0, 0x0f ; RRCA
  692. .db "SBC", 0, 'A', 'h', 0, 0x9e ; SBC A, HL
  693. .db "SBC", 0, 'A', 0xb, 0, 0b10011000 ; SBC A, r
  694. .db "SCF", 0, 0, 0, 0, 0x37 ; SCF
  695. .db "SUB", 0, 'A', 'h', 0, 0x96 ; SUB A, HL
  696. .db "SUB", 0, 'A', 0xb, 0, 0b10010000 ; SUB A, r
  697. .db "SUB", 0, 'n', 0, 0, 0xd6 ; SUB n
  698. .db "XOR", 0, 'l', 0, 0, 0xae ; XOR (HL)
  699. .db "XOR", 0, 0xb, 0, 0, 0b10101000 ; XOR r
  700. ; *** Variables ***
  701. ; enough space for 4 chars and a null
  702. curWord:
  703. .db 0, 0, 0, 0, 0
  704. ; Args are 3 bytes: argspec, then values of numerical constants (when that's
  705. ; appropriate)
  706. curArg1:
  707. .db 0, 0, 0
  708. curArg2:
  709. .db 0, 0, 0
  710. ; space for tmp stuff
  711. tmpBuf:
  712. .fill 0x20