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.

1254 lines
33KB

  1. ; *** Consts ***
  2. ; Number of rows in the argspec table
  3. .equ ARGSPEC_TBL_CNT 33
  4. ; size in bytes of each row in the primary instructions table
  5. .equ INSTR_TBL_ROWSIZE 6
  6. ; Instruction IDs They correspond to the index of the table in instrNames
  7. .equ I_ADC 0x00
  8. .equ I_ADD 0x01
  9. .equ I_AND 0x02
  10. .equ I_BIT 0x03
  11. .equ I_CALL 0x04
  12. .equ I_CCF 0x05
  13. .equ I_CP 0x06
  14. .equ I_CPD 0x07
  15. .equ I_CPDR 0x08
  16. .equ I_CPI 0x09
  17. .equ I_CPIR 0x0a
  18. .equ I_CPL 0x0b
  19. .equ I_DAA 0x0c
  20. .equ I_DEC 0x0d
  21. .equ I_DI 0x0e
  22. .equ I_DJNZ 0x0f
  23. .equ I_EI 0x10
  24. .equ I_EX 0x11
  25. .equ I_EXX 0x12
  26. .equ I_HALT 0x13
  27. .equ I_IM 0x14
  28. .equ I_IN 0x15
  29. .equ I_INC 0x16
  30. .equ I_IND 0x17
  31. .equ I_INDR 0x18
  32. .equ I_INI 0x19
  33. .equ I_INIR 0x1a
  34. .equ I_JP 0x1b
  35. .equ I_JR 0x1c
  36. .equ I_LD 0x1d
  37. .equ I_LDD 0x1e
  38. .equ I_LDDR 0x1f
  39. .equ I_LDI 0x20
  40. .equ I_LDIR 0x21
  41. .equ I_NEG 0x22
  42. .equ I_NOP 0x23
  43. .equ I_OR 0x24
  44. .equ I_OTDR 0x25
  45. .equ I_OTIR 0x26
  46. .equ I_OUT 0x27
  47. .equ I_POP 0x28
  48. .equ I_PUSH 0x29
  49. .equ I_RES 0x2a
  50. .equ I_RET 0x2b
  51. .equ I_RETI 0x2c
  52. .equ I_RETN 0x2d
  53. .equ I_RL 0x2e
  54. .equ I_RLA 0x2f
  55. .equ I_RLC 0x30
  56. .equ I_RLCA 0x31
  57. .equ I_RR 0x32
  58. .equ I_RRA 0x33
  59. .equ I_RRC 0x34
  60. .equ I_RRCA 0x35
  61. .equ I_RST 0x36
  62. .equ I_SBC 0x37
  63. .equ I_SCF 0x38
  64. .equ I_SET 0x39
  65. .equ I_SLA 0x3a
  66. .equ I_SRL 0x3b
  67. .equ I_SUB 0x3c
  68. .equ I_XOR 0x3d
  69. ; *** Variables ***
  70. ; Args are 3 bytes: argspec, then values of numerical constants (when that's
  71. ; appropriate)
  72. .equ INS_CURARG1 INS_RAMSTART
  73. .equ INS_CURARG2 INS_CURARG1+3
  74. .equ INS_UPCODE INS_CURARG2+3
  75. .equ INS_RAMEND INS_UPCODE+4
  76. ; *** Code ***
  77. ; Checks whether A is 'N' or 'M'
  78. checkNOrM:
  79. cp 'N'
  80. ret z
  81. cp 'M'
  82. ret
  83. ; Checks whether A is 'n', 'm'
  84. checknm:
  85. cp 'n'
  86. ret z
  87. cp 'm'
  88. ret
  89. checklxy:
  90. cp 'l'
  91. ret z
  92. ; Checks whether A is 'x', 'y'
  93. checkxy:
  94. cp 'x'
  95. ret z
  96. cp 'y'
  97. ret
  98. ; Reads string in (HL) and returns the corresponding ID (I_*) in A. Sets Z if
  99. ; there's a match.
  100. getInstID:
  101. push bc
  102. push de
  103. ld b, I_XOR+1 ; I_XOR is the last
  104. ld c, 4
  105. ld de, instrNames
  106. call findStringInList
  107. pop de
  108. pop bc
  109. ret
  110. ; Parse the string at (HL) and check if it starts with IX+, IY+, IX- or IY-.
  111. ; Sets Z if yes, unset if no. On success, A contains either '+' or '-'.
  112. parseIXY:
  113. push hl
  114. ld a, (hl)
  115. call upcase
  116. cp 'I'
  117. jr nz, .end ; Z already unset
  118. inc hl
  119. ld a, (hl)
  120. call upcase
  121. cp 'X'
  122. jr z, .match1
  123. cp 'Y'
  124. jr z, .match1
  125. jr .end ; Z already unset
  126. .match1:
  127. ; Alright, we have IX or IY. Let's see if we have + or - next.
  128. inc hl
  129. ld a, (hl)
  130. cp '+'
  131. jr z, .end ; Z is already set
  132. cp '-'
  133. ; The value of Z at this point is our final result
  134. .end:
  135. pop hl
  136. ret
  137. ; find argspec for string at (HL). Returns matching argspec in A.
  138. ; Return value 0xff holds a special meaning: arg is not empty, but doesn't match
  139. ; any argspec (A == 0 means arg is empty). A return value of 0xff means an
  140. ; error.
  141. ;
  142. ; If the parsed argument is a number constant, 'N' is returned and IX contains
  143. ; the value of that constant.
  144. parseArg:
  145. call strlen
  146. or a
  147. ret z ; empty string? A already has our result: 0
  148. push bc
  149. push de
  150. push hl
  151. ; We always initialize IX to zero so that non-numerical args end up with
  152. ; a clean zero.
  153. ld ix, 0
  154. ld de, argspecTbl
  155. ; DE now points the the "argspec char" part of the entry, but what
  156. ; we're comparing in the loop is the string next to it. Let's offset
  157. ; DE by one so that the loop goes through strings.
  158. inc de
  159. ld b, ARGSPEC_TBL_CNT
  160. .loop1:
  161. ld a, 4
  162. call strncmpI
  163. jr z, .found ; got it!
  164. ld a, 5
  165. call addDE
  166. djnz .loop1
  167. ; We exhausted the argspecs. Let's see if we're inside parens.
  168. call enterParens
  169. jr z, .withParens
  170. ; (HL) has no parens
  171. call .maybeParseExpr
  172. jr nz, .nomatch
  173. ; We have a proper number in no parens. Number in IX.
  174. ld a, 'N'
  175. jr .end
  176. .withParens:
  177. ld b, 0 ; make sure it doesn't hold '-'
  178. ld c, 'M' ; C holds the argspec type until we reach
  179. ; .numberInParens
  180. ; We have parens. First, let's see if we have a (IX+d) type of arg.
  181. call parseIXY
  182. jr nz, .parseNumberInParens ; not I{X,Y}. just parse number.
  183. ; We have IX+/IY+/IX-/IY-.
  184. ; A contains either '+' or '-'. Save it for later, in B.
  185. ld b, a
  186. inc hl ; (HL) now points to X or Y
  187. ld a, (hl)
  188. call upcase
  189. inc hl ; advance HL to the number part
  190. inc hl ; this is the number
  191. cp 'Y'
  192. jr nz, .notY
  193. ld c, 'y'
  194. jr .parseNumberInParens
  195. .notY:
  196. ld c, 'x'
  197. .parseNumberInParens:
  198. call .maybeParseExpr
  199. jr nz, .nomatch
  200. ; We have a proper number in parens. Number in IX
  201. ; is '-' in B? if yes, we need to negate the low part of IX
  202. ld a, b
  203. cp '-'
  204. jr nz, .dontNegateIX
  205. ; we need to negate the low part of IX
  206. ; TODO: when parsing routines properly support unary negative numbers,
  207. ; We could replace this complicated scheme below with a nice hack where
  208. ; we start parsing our displacement number at the '+' and '-' char.
  209. ; HL isn't needed anymore and can be destroyed.
  210. push ix \ pop hl
  211. ld a, l
  212. neg
  213. ld l, a
  214. push hl \ pop ix
  215. .dontNegateIX:
  216. ld a, c ; M, x, or y
  217. jr .end
  218. .nomatch:
  219. ; We get no match
  220. ld a, 0xff
  221. jr .end
  222. .found:
  223. ; found the matching argspec row. Our result is one byte left of DE.
  224. dec de
  225. ld a, (de)
  226. .end:
  227. pop hl
  228. pop de
  229. pop bc
  230. ret
  231. .maybeParseExpr:
  232. ; Before we try to parse expr in (HL), first check if we're in first
  233. ; pass if we are, skip parseExpr. Most of the time, that parse is
  234. ; harmless, but in some cases it causes false failures. For example,
  235. ; a "-" operator can cause is to falsely overflow and generate
  236. ; truncation error.
  237. call zasmIsFirstPass
  238. ret z
  239. jp parseExpr
  240. ; Returns, with Z, whether A is a groupId
  241. isGroupId:
  242. or a
  243. jp z, unsetZ ; not a group
  244. cp 0xd ; max group id + 1
  245. jp nc, unsetZ ; >= 0xd? not a group
  246. ; A is a group. ensure Z is set
  247. cp a
  248. ret
  249. ; Find argspec A in group id H.
  250. ; Set Z according to whether we found the argspec
  251. ; If found, the value in A is the argspec value in the group (its index).
  252. findInGroup:
  253. push bc
  254. push hl
  255. or a ; is our arg empty? If yes, we have nothing to do
  256. jr z, .notfound
  257. push af
  258. ld a, h
  259. cp 0xa
  260. jr z, .specialGroupCC
  261. cp 0xb
  262. jr z, .specialGroupABCDEHL
  263. jr nc, .notfound ; > 0xb? not a group
  264. pop af
  265. ; regular group
  266. push de
  267. ld de, argGrpTbl
  268. ; group ids start at 1. decrease it, then multiply by 4 to have a
  269. ; proper offset in argGrpTbl
  270. dec h
  271. push af
  272. ld a, h
  273. rla
  274. rla
  275. call addDE ; At this point, DE points to our group
  276. pop af
  277. ex de, hl ; And now, HL points to the group
  278. pop de
  279. ld bc, 4
  280. jr .find
  281. .specialGroupCC:
  282. ld hl, argGrpCC
  283. jr .specialGroupEnd
  284. .specialGroupABCDEHL:
  285. ld hl, argGrpABCDEHL
  286. .specialGroupEnd:
  287. pop af ; from the push af just before the special group check
  288. ld bc, 8
  289. .find:
  290. ; This part is common to regular and special group. We expect HL to
  291. ; point to the group and BC to contain its length.
  292. push bc ; save the start value loop index so we can sub
  293. .loop:
  294. cpi
  295. jr z, .found
  296. jp po, .notfound
  297. jr .loop
  298. .found:
  299. ; we found our result! Now, what we want to put in A is the index of
  300. ; the found argspec.
  301. pop hl ; we pop from the "push bc" above. L is now 4 or 8
  302. ld a, l
  303. sub c
  304. dec a ; cpi DECs BC even when there's a match, so C == the
  305. ; number of iterations we've made. But our index is
  306. ; zero-based (1 iteration == 0 index).
  307. cp a ; ensure Z is set
  308. jr .end
  309. .notfound:
  310. pop bc ; from the push bc in .find
  311. call unsetZ
  312. .end:
  313. pop hl
  314. pop bc
  315. ret
  316. ; Compare argspec from instruction table in A with argument in (HL).
  317. ; IX must point to argspec row.
  318. ; For constant args, it's easy: if A == (HL), it's a success.
  319. ; If it's not this, then we check if it's a numerical arg.
  320. ; If A is a group ID, we do something else: we check that (HL) exists in the
  321. ; groupspec (argGrpTbl). Moreover, we go and write the group's "value" (index)
  322. ; in (HL+1). This will save us significant processing later in spitUpcode.
  323. ; Set Z according to whether we match or not.
  324. matchArg:
  325. cp (hl)
  326. ret z
  327. ; not an exact match. Before we continue: is A zero? Because if it is,
  328. ; we have to stop right here: no match possible.
  329. or a
  330. jr nz, .skip1 ; not a zero, we can continue
  331. ; zero, stop here
  332. cp 1 ; unset Z
  333. ret
  334. .skip1:
  335. ; If our argspec is 'l', then we also match 'x' and 'y'
  336. cp 'l'
  337. jr nz, .skip2
  338. ; Does it accept IX and IY?
  339. bit 4, (ix+3)
  340. ld a, (hl)
  341. jp nz, checkxy ; bit set: our result is checkxy
  342. ; doesn't accept? then we don't match
  343. jp unsetZ
  344. .skip2:
  345. ; Alright, let's start with a special case. Is it part of the special
  346. ; "BIT" group, 0xc? If yes, we actually expect a number, which will
  347. ; then be ORed like a regular group index.
  348. cp 0xc
  349. jr z, .expectsBIT
  350. ; not an exact match, let's check for numerical constants.
  351. call upcase
  352. call checkNOrM
  353. jr z, .expectsNumber
  354. jr .notNumber
  355. .expectsNumber:
  356. ; Our argument is a number N or M. Never a lower-case version. At this
  357. ; point in the processing, we don't care about whether N or M is upper,
  358. ; we do truncation tests later. So, let's just perform the same == test
  359. ; but in a case-insensitive way instead
  360. cp (hl)
  361. ret ; whether we match or not, the result of Z is
  362. ; the good one.
  363. .expectsBIT:
  364. ld a, (hl)
  365. cp 'N'
  366. inc hl
  367. ld a, (hl)
  368. dec hl
  369. cp 8
  370. jr c, .isBit ; A < 8
  371. ; not a bit
  372. or a ; unset Z
  373. ret
  374. .isBit:
  375. cp a ; set Z
  376. ret
  377. .notNumber:
  378. ; A bit of a delicate situation here: we want A to go in H but also
  379. ; (HL) to go in A. If not careful, we overwrite each other. EXX is
  380. ; necessary to avoid invoving other registers.
  381. push hl
  382. exx
  383. ld h, a
  384. push hl
  385. exx
  386. ld a, (hl)
  387. pop hl
  388. call findInGroup
  389. pop hl
  390. ret nz
  391. ; we found our group? let's write down its "value" in (HL+1). We hold
  392. ; this value in A at the moment.
  393. inc hl
  394. ld (hl), a
  395. dec hl
  396. ret
  397. ; Compare primary row at (DE) with ID in A. Sets Z flag if there's a match.
  398. matchPrimaryRow:
  399. push hl
  400. push ix
  401. push de \ pop ix
  402. cp (ix)
  403. jr nz, .end
  404. ; name matches, let's see the rest
  405. ld hl, INS_CURARG1
  406. ld a, (ix+1)
  407. call matchArg
  408. jr nz, .end
  409. ld hl, INS_CURARG2
  410. ld a, (ix+2)
  411. call matchArg
  412. .end:
  413. pop ix
  414. pop hl
  415. ret
  416. ; *** Special opcodes ***
  417. ; The special upcode handling routines below all have the same signature.
  418. ; Instruction row is at IX and we're expected to perform the same task as
  419. ; spitUpcode. The number of bytes, however, must go in C instead of A
  420. ; No need to preserve HL, DE, BC and IX: it's handled by spitUpcode already.
  421. ; Handle like a regular "JP (IX+d)" except that we refuse any displacement: if
  422. ; a displacement is specified, we error out.
  423. handleJPIXY:
  424. ld a, (INS_CURARG1+1)
  425. or a ; numerical argument *must* be zero
  426. jr nz, .error
  427. ; ok, we're good
  428. ld a, 0xe9 ; second upcode
  429. ld (INS_UPCODE), a
  430. ld c, 1
  431. ret
  432. .error:
  433. ld c, 0
  434. ret
  435. handleBITR:
  436. ld b, 0b01000000
  437. jr _handleBITR
  438. handleSETR:
  439. ld b, 0b11000000
  440. jr _handleBITR
  441. handleRESR:
  442. ld b, 0b10000000
  443. _handleBITR:
  444. ; get group value
  445. ld a, (INS_CURARG2+1) ; group value
  446. ld c, a
  447. ; write first upcode
  448. ld a, 0xcb ; first upcode
  449. ld (INS_UPCODE), a
  450. ; get bit value
  451. ld a, (INS_CURARG1+1) ; 0-7
  452. rlca ; clears cary if any
  453. rla
  454. rla
  455. ; Now we have group value in stack, bit value in A (properly shifted)
  456. ; and we want to OR them together
  457. or c ; Now we have our ORed value
  458. or b ; and with our "base" value and we're good!
  459. ld (INS_UPCODE+1), a
  460. ld c, 2
  461. ret
  462. handleIM:
  463. ld a, (INS_CURARG1+1)
  464. cp 0
  465. jr z, .im0
  466. cp 1
  467. jr z, .im1
  468. cp 2
  469. jr z, .im2
  470. ; error
  471. ld c, 0
  472. ret
  473. .im0:
  474. ld a, 0x46
  475. jr .proceed
  476. .im1:
  477. ld a, 0x56
  478. jr .proceed
  479. .im2:
  480. ld a, 0x5e
  481. .proceed:
  482. ld (INS_UPCODE+1), a
  483. ld a, 0xed
  484. ld (INS_UPCODE), a
  485. ld c, 2
  486. ret
  487. handleLDIXYn:
  488. ld a, 0x36 ; second upcode
  489. ld (INS_UPCODE), a
  490. ld a, (INS_CURARG1+1) ; IXY displacement
  491. ld (INS_UPCODE+1), a
  492. ld a, (INS_CURARG2+1) ; N
  493. ld (INS_UPCODE+2), a
  494. ld c, 3
  495. ret
  496. handleLDIXYr:
  497. ld a, (INS_CURARG2+1) ; group value
  498. or 0b01110000 ; second upcode
  499. ld (INS_UPCODE), a
  500. ld a, (INS_CURARG1+1) ; IXY displacement
  501. ld (INS_UPCODE+1), a
  502. ld c, 2
  503. ret
  504. handleLDrIXY:
  505. ld a, (INS_CURARG1+1) ; group value
  506. rlca \ rla \ rla
  507. or 0b01000110 ; second upcode
  508. ld (INS_UPCODE), a
  509. ld a, (INS_CURARG2+1) ; IXY displacement
  510. ld (INS_UPCODE+1), a
  511. ld c, 2
  512. ret
  513. handleLDrr:
  514. ; first argument is displaced by 3 bits, second argument is not
  515. ; displaced and we or that with a leading 0b01000000
  516. ld a, (INS_CURARG1+1) ; group value
  517. rlca
  518. rla
  519. rla
  520. ld c, a ; store it
  521. ld a, (INS_CURARG2+1) ; other group value
  522. or c
  523. or 0b01000000
  524. ld (INS_UPCODE), a
  525. ld c, 1
  526. ret
  527. handleRST:
  528. ld a, (INS_CURARG1+1)
  529. ; verify that A is either 0x08, 0x10, 0x18, 0x20, 0x28, 0x30 or 0x38.
  530. ; Good news: the relevant bits (bits 5:3) are already in place. We only
  531. ; have to verify that they're surrounded by zeroes.
  532. ld c, 0b11000111
  533. and c
  534. jr nz, .error
  535. ; We're in range. good.
  536. ld a, (INS_CURARG1+1)
  537. or c
  538. ld (INS_UPCODE), a
  539. ld c, 1
  540. ret
  541. .error:
  542. ld c, 0
  543. ret
  544. ; Compute the upcode for argspec row at (DE) and arguments in curArg{1,2} and
  545. ; writes the resulting upcode to IO.
  546. ; A is zero, with Z set, on success. A is non-zero, with Z unset, on error.
  547. spitUpcode:
  548. push ix
  549. push de
  550. push hl
  551. push bc
  552. ; First, let's go in IX mode. It's easier to deal with offsets here.
  553. push de \ pop ix
  554. ; before we begin, are we in a 'l' argspec? Is it flagged for IX/IY
  555. ; acceptance? If yes, a 'x' or 'y' instruction? Check this on both
  556. ; args and if we detect a 'x' or 'y', things are *always* the same:
  557. ; the upcode is exactly the same as its (HL) counterpart except that
  558. ; it is preceeded by 0xdd or 0xfd. If we're 'x' or 'y', then it means
  559. ; that we've already been matched to a 'l' argspec, so after spitting
  560. ; 0xdd or 0xfd, we can continue as normal.
  561. ld a, (ix+1)
  562. call checklxy
  563. jr z, .isl
  564. ld a, (ix+2)
  565. call checklxy
  566. jr nz, .begin ; no point in checking further.
  567. .isl:
  568. ld a, (INS_CURARG1)
  569. cp 'x'
  570. jr z, .isx
  571. cp 'y'
  572. jr z, .isy
  573. ld a, (INS_CURARG2)
  574. cp 'x'
  575. jr z, .isx
  576. cp 'y'
  577. jr z, .isy
  578. jr .begin
  579. .isx:
  580. ld a, 0xdd
  581. call ioPutB
  582. jr .begin
  583. .isy:
  584. ld a, 0xfd
  585. call ioPutB
  586. .begin:
  587. ; Are we a "special instruction"?
  588. bit 5, (ix+3)
  589. jr z, .normalInstr ; not set: normal instruction
  590. ; We are a special instruction. Fetch handler (little endian, remember).
  591. ld l, (ix+4)
  592. ld h, (ix+5)
  593. call callHL
  594. ; We have our result written in INS_UPCODE and C is set.
  595. jp .writeIO
  596. .normalInstr:
  597. ; we begin by writing our "base upcode", which can be one or two bytes
  598. ld a, (ix+4) ; first upcode
  599. ld (INS_UPCODE), a
  600. ; from this point, DE points to "where we are" in terms of upcode
  601. ; writing.
  602. ld de, INS_UPCODE+1
  603. ld c, 1 ; C holds our upcode count
  604. ; Now, let's determine if we have one or two upcode. As a general rule,
  605. ; we simply have to check if (ix+5) == 0, which means one upcode.
  606. ; However, some two-upcodes instructions have a 0 (ix+5) because they
  607. ; expect group OR-ing into it and all other bits are zero. See "RLC r".
  608. ; To handle those cases, we *also* check for Bit 6 in (ix+3).
  609. ld a, (ix+5) ; second upcode
  610. or a ; do we have a second upcode?
  611. jr nz, .twoUpcodes
  612. bit 6, (ix+3)
  613. jr z, .onlyOneUpcode ; not set: single upcode
  614. .twoUpcodes:
  615. ; we have two upcodes
  616. ld (de), a
  617. inc de
  618. inc c
  619. .onlyOneUpcode:
  620. ; now, let's see if we're dealing with a group here
  621. ld a, (ix+1) ; first argspec
  622. call isGroupId
  623. jr z, .firstArgIsGroup
  624. ; First arg not a group. Maybe second is?
  625. ld a, (ix+2) ; 2nd argspec
  626. call isGroupId
  627. jr nz, .writeExtraBytes ; not a group? nothing to do. go to
  628. ; next step: write extra bytes
  629. ; Second arg is group
  630. ld hl, INS_CURARG2
  631. jr .isGroup
  632. .firstArgIsGroup:
  633. ld hl, INS_CURARG1
  634. .isGroup:
  635. ; A is a group, good, now let's get its value. HL is pointing to
  636. ; the argument. Our group value is at (HL+1).
  637. inc hl
  638. ld a, (hl)
  639. ; Now, we have our arg "group value" in A. Were going to need to
  640. ; displace it left by the number of steps specified in the table.
  641. push af
  642. ld a, (ix+3) ; displacement bit
  643. and 0xf ; we only use the lower nibble.
  644. ld b, a
  645. pop af
  646. call rlaX
  647. ; At this point, we have a properly displaced value in A. We'll want
  648. ; to OR it with the opcode.
  649. ; However, we first have to verify whether this ORing takes place on
  650. ; the second upcode or the first.
  651. bit 6, (ix+3)
  652. jr z, .firstUpcode ; not set: first upcode
  653. or (ix+5) ; second upcode
  654. ld (INS_UPCODE+1), a
  655. jr .writeExtraBytes
  656. .firstUpcode:
  657. or (ix+4) ; first upcode
  658. ld (INS_UPCODE), a
  659. jr .writeExtraBytes
  660. .writeExtraBytes:
  661. ; Good, we are probably finished here for many primary opcodes. However,
  662. ; some primary opcodes take 8 or 16 bit constants as an argument and
  663. ; if that's the case here, we need to write it too.
  664. ; We still have our instruction row in IX and we have DE pointing to
  665. ; where we should write next (which could be the second or the third
  666. ; byte of INS_UPCODE).
  667. ld a, (ix+1) ; first argspec
  668. ld hl, INS_CURARG1
  669. call checkNOrM
  670. jr z, .withWord
  671. call checknm
  672. jr z, .withByte
  673. ld a, (INS_CURARG1)
  674. call checkxy
  675. jr z, .withByte
  676. ld a, (ix+2) ; second argspec
  677. ld hl, INS_CURARG2
  678. call checkNOrM
  679. jr z, .withWord
  680. call checknm
  681. jr z, .withByte
  682. ld a, (INS_CURARG2)
  683. call checkxy
  684. jr z, .withByte
  685. ; nope, no number, alright, we're finished here
  686. jr .writeIO
  687. .withByte:
  688. inc hl
  689. ; HL points to our number (LSB), with (HL+1) being our MSB which should
  690. ; normally by zero. However, if our instruction is jr or djnz, that
  691. ; number is actually a 2-bytes address that has to be relative to PC,
  692. ; so it's a special case. Let's check for this special case.
  693. bit 7, (ix+3)
  694. jr z, .absoluteValue ; bit not set? regular byte value,
  695. ; Our argument is a relative address ("e" type in djnz and jr). We have
  696. ; to subtract PC from it.
  697. ; First, check whether we're on first pass. If we are, skip processing
  698. ; below because not having real symbol value makes relative address
  699. ; verification falsely fail.
  700. inc c ; one extra byte is written
  701. call zasmIsFirstPass
  702. jr z, .writeIO
  703. ; We're on second pass
  704. push de ; Don't let go of this, that's our dest
  705. push hl
  706. call zasmGetPC ; --> HL
  707. ex de, hl
  708. pop hl
  709. call intoHL
  710. dec hl ; what we write is "e-2"
  711. dec hl
  712. call subDEFromHL
  713. pop de ; Still have it? good
  714. ; HL contains our number and we'll check its bounds. If It's negative,
  715. ; H is going to be 0xff and L has to be >= 0x80. If it's positive,
  716. ; H is going to be 0 and L has to be < 0x80.
  717. ld a, l
  718. cp 0x80
  719. jr c, .skipHInc ; a < 0x80, H is expected to be 0
  720. ; A being >= 0x80 is only valid in cases where HL is negative and
  721. ; within bounds. This only happens is H == 0xff. Let's increase it to 0.
  722. inc h
  723. .skipHInc:
  724. ; Let's write our value now even though we haven't checked our bounds
  725. ; yet. This way, we don't have to store A somewhere else.
  726. ld (de), a
  727. ld a, h
  728. or a ; cp 0
  729. jr nz, .numberTruncated ; if A is anything but zero, we're out
  730. ; of bounds.
  731. jr .writeIO
  732. .absoluteValue:
  733. ; verify that the MSB in argument is zero
  734. inc hl ; MSB is 2nd byte
  735. ld a, (hl)
  736. dec hl ; HL now points to LSB
  737. or a ; cp 0
  738. jr nz, .numberTruncated
  739. push bc
  740. ldi
  741. pop bc
  742. inc c
  743. jr .writeIO
  744. .withWord:
  745. inc hl ; HL now points to LSB
  746. ; Clear to proceed. HL already points to our number
  747. push bc
  748. ldi ; LSB written, we point to MSB now
  749. ldi ; MSB written
  750. pop bc
  751. inc c ; two extra bytes are written
  752. inc c
  753. ; to writeIO
  754. .writeIO:
  755. ; Before we write IO, let's check a very specific case: is our first
  756. ; upcode 0xcb and our byte count == 3? If yes, then swap the two last
  757. ; bytes. In all instructions except 0xcb ones, IX/IY displacement comes
  758. ; last, but in all 0xcb instructions, they come 2nd last.
  759. call .checkCB
  760. ; Let's write INS_UPCODE to IO
  761. dec c \ inc c ; is C zero?
  762. jr z, .numberTruncated
  763. ld b, c ; save output byte count
  764. ld hl, INS_UPCODE
  765. .loopWrite:
  766. ld a, (hl)
  767. call ioPutB
  768. jr nz, .ioError
  769. inc hl
  770. djnz .loopWrite
  771. cp a ; ensure Z
  772. jr .end
  773. .numberTruncated:
  774. ; Z already unset
  775. ld a, ERR_OVFL
  776. jr .end
  777. .ioError:
  778. ; Z already unset
  779. ld a, SHELL_ERR_IO_ERROR
  780. ; continue to .end
  781. .end:
  782. pop bc
  783. pop hl
  784. pop de
  785. pop ix
  786. ret
  787. .checkCB:
  788. ld a, (INS_UPCODE)
  789. cp 0xcb
  790. ret nz
  791. ld a, c
  792. cp 3
  793. ret nz
  794. ; We are in 0xcb + displacement situation. Swap bytes 2 and 3.
  795. ld a, (INS_UPCODE+1)
  796. ex af, af'
  797. ld a, (INS_UPCODE+2)
  798. ld (INS_UPCODE+1), a
  799. ex af, af'
  800. ld (INS_UPCODE+2), a
  801. ret
  802. ; Parse argument in (HL) and place it in (DE)
  803. ; Sets Z on success, reset on error.
  804. processArg:
  805. call parseArg
  806. cp 0xff
  807. jr z, .error
  808. ld (de), a
  809. ; When A is a number, IX is set with the value of that number. Because
  810. ; We don't use the space allocated to store those numbers in any other
  811. ; occasion, we store IX there unconditonally, LSB first.
  812. inc de
  813. push hl
  814. push ix \ pop hl
  815. call writeHLinDE
  816. pop hl
  817. cp a ; ensure Z is set
  818. ret
  819. .error:
  820. ld a, ERR_BAD_ARG
  821. call unsetZ
  822. ret
  823. ; Parse instruction specified in A (I_* const) with args in I/O and write
  824. ; resulting opcode(s) in I/O.
  825. ; Sets Z on success. On error, A contains an error code (ERR_*)
  826. parseInstruction:
  827. push bc
  828. push hl
  829. push de
  830. ; A is reused in matchPrimaryRow but that register is way too changing.
  831. ; Let's keep a copy in a more cosy register.
  832. ld c, a
  833. xor a
  834. ld (INS_CURARG1), a
  835. ld (INS_CURARG2), a
  836. call readWord
  837. jr nz, .nomorearg
  838. ld de, INS_CURARG1
  839. call processArg
  840. jr nz, .error ; A is set to error
  841. call readComma
  842. jr nz, .nomorearg
  843. call readWord
  844. jr nz, .badfmt
  845. ld de, INS_CURARG2
  846. call processArg
  847. jr nz, .error ; A is set to error
  848. .nomorearg:
  849. ; Parsing done, no error, let's move forward to instr row matching!
  850. ; To speed up things a little, we use a poor man's indexing. Full
  851. ; bisecting would involve too much complexity.
  852. ld a, c ; recall A param
  853. ld de, instrTBl
  854. cp I_EX
  855. jr c, .loop
  856. ld de, instrTBlEX
  857. cp I_LD
  858. jr c, .loop
  859. ld de, instrTBlLD
  860. cp I_RET
  861. jr c, .loop
  862. ld de, instrTBlRET
  863. .loop:
  864. ld a, c ; recall A param
  865. call matchPrimaryRow
  866. jr z, .match
  867. ld a, INSTR_TBL_ROWSIZE
  868. call addDE
  869. ld a, (de)
  870. cp 0xff
  871. jr nz, .loop
  872. ; No signature match
  873. ld a, ERR_BAD_ARG
  874. jr .error
  875. .match:
  876. ; We have our matching instruction row. We're getting pretty near our
  877. ; goal here!
  878. call spitUpcode
  879. jr .end ; Z and A set properly, even on error
  880. .badfmt:
  881. ; Z already unset
  882. ld a, ERR_BAD_FMT
  883. .error:
  884. ; A is set to error already
  885. call unsetZ
  886. .end:
  887. pop de
  888. pop hl
  889. pop bc
  890. ret
  891. ; In instruction metadata below, argument types arge indicated with a single
  892. ; char mnemonic that is called "argspec". This is the table of correspondence.
  893. ; Single letters are represented by themselves, so we don't need as much
  894. ; metadata.
  895. ; Special meaning:
  896. ; 0 : no arg
  897. ; 1-10 : group id (see Groups section)
  898. ; 0xff: error
  899. ; Format: 1 byte argspec + 4 chars string
  900. argspecTbl:
  901. .db 'A', "A", 0, 0, 0
  902. .db 'B', "B", 0, 0, 0
  903. .db 'C', "C", 0, 0, 0
  904. .db 'k', "(C)", 0
  905. .db 'D', "D", 0, 0, 0
  906. .db 'E', "E", 0, 0, 0
  907. .db 'H', "H", 0, 0, 0
  908. .db 'L', "L", 0, 0, 0
  909. .db 'I', "I", 0, 0, 0
  910. .db 'R', "R", 0, 0, 0
  911. .db 'h', "HL", 0, 0
  912. .db 'l', "(HL)"
  913. .db 'd', "DE", 0, 0
  914. .db 'e', "(DE)"
  915. .db 'b', "BC", 0, 0
  916. .db 'c', "(BC)"
  917. .db 'a', "AF", 0, 0
  918. .db 'f', "AF'", 0
  919. .db 'X', "IX", 0, 0
  920. .db 'Y', "IY", 0, 0
  921. .db 'x', "(IX)" ; always come with displacement
  922. .db 'y', "(IY)" ; with JP
  923. .db 's', "SP", 0, 0
  924. .db 'p', "(SP)"
  925. ; we also need argspecs for the condition flags
  926. .db 'Z', "Z", 0, 0, 0
  927. .db 'z', "NZ", 0, 0
  928. ; C is in conflict with the C register. The situation is ambiguous, but
  929. ; doesn't cause actual problems.
  930. .db '=', "NC", 0, 0
  931. .db '+', "P", 0, 0, 0
  932. .db '-', "M", 0, 0, 0
  933. .db '1', "PO", 0, 0
  934. .db '2', "PE", 0, 0
  935. ; argspecs not in the list:
  936. ; n -> N
  937. ; N -> NN
  938. ; m -> (N) (running out of mnemonics. 'm' for 'memory pointer')
  939. ; M -> (NN)
  940. ; Groups
  941. ; Groups are specified by strings of argspecs. To facilitate jumping to them,
  942. ; we have a fixed-sized table. Because most of them are 2 or 4 bytes long, we
  943. ; have a table that is 4 in size to minimize consumed space. We treat the two
  944. ; groups that take 8 bytes in a special way.
  945. ;
  946. ; The table below is in order, starting with group 0x01
  947. argGrpTbl:
  948. .db "bdha" ; 0x01
  949. .db "ZzC=" ; 0x02
  950. .db "bdhs" ; 0x03
  951. .db "bdXs" ; 0x04
  952. .db "bdYs" ; 0x05
  953. argGrpCC:
  954. .db "zZ=C12+-" ; 0xa
  955. argGrpABCDEHL:
  956. .db "BCDEHL_A" ; 0xb
  957. ; SPECIAL GROUP "BIT": 0xc
  958. ; When special group "0xc" shows up in argspec, it means: accept a number
  959. ; between 0 and 7. The value is then treated like a regular group value.
  960. ; Each row is 4 bytes wide, fill with zeroes
  961. instrNames:
  962. .db "ADC", 0
  963. .db "ADD", 0
  964. .db "AND", 0
  965. .db "BIT", 0
  966. .db "CALL"
  967. .db "CCF", 0
  968. .db "CP",0,0
  969. .db "CPD", 0
  970. .db "CPDR"
  971. .db "CPI", 0
  972. .db "CPIR"
  973. .db "CPL", 0
  974. .db "DAA", 0
  975. .db "DEC", 0
  976. .db "DI",0,0
  977. .db "DJNZ"
  978. .db "EI",0,0
  979. .db "EX",0,0
  980. .db "EXX", 0
  981. .db "HALT"
  982. .db "IM",0,0
  983. .db "IN",0,0
  984. .db "INC", 0
  985. .db "IND", 0
  986. .db "INDR"
  987. .db "INI", 0
  988. .db "INIR"
  989. .db "JP",0,0
  990. .db "JR",0,0
  991. .db "LD",0,0
  992. .db "LDD", 0
  993. .db "LDDR"
  994. .db "LDI", 0
  995. .db "LDIR"
  996. .db "NEG", 0
  997. .db "NOP", 0
  998. .db "OR",0,0
  999. .db "OTDR"
  1000. .db "OTIR"
  1001. .db "OUT", 0
  1002. .db "POP", 0
  1003. .db "PUSH"
  1004. .db "RES", 0
  1005. .db "RET", 0
  1006. .db "RETI"
  1007. .db "RETN"
  1008. .db "RL", 0, 0
  1009. .db "RLA", 0
  1010. .db "RLC", 0
  1011. .db "RLCA"
  1012. .db "RR", 0, 0
  1013. .db "RRA", 0
  1014. .db "RRC", 0
  1015. .db "RRCA"
  1016. .db "RST", 0
  1017. .db "SBC", 0
  1018. .db "SCF", 0
  1019. .db "SET", 0
  1020. .db "SLA", 0
  1021. .db "SRL", 0
  1022. .db "SUB", 0
  1023. .db "XOR", 0
  1024. ; This is a list of all supported instructions. Each row represent a combination
  1025. ; of instr/argspecs (which means more than one row per instr). Format:
  1026. ;
  1027. ; 1 byte for the instruction ID
  1028. ; 1 byte for arg constant
  1029. ; 1 byte for 2nd arg constant
  1030. ; 1 byte displacement for group arguments + flags
  1031. ; 2 bytes for upcode (2nd byte is zero if instr is one byte)
  1032. ;
  1033. ; An "arg constant" is a char corresponding to either a row in argspecTbl or
  1034. ; a group index in argGrpTbl (values < 0x10 are considered group indexes).
  1035. ;
  1036. ; The displacement bit is split in 2 nibbles: lower nibble is the displacement
  1037. ; value, upper nibble is for flags:
  1038. ;
  1039. ; Bit 7: indicates that the numerical argument is of the 'e' type and has to be
  1040. ; decreased by 2 (djnz, jr).
  1041. ; Bit 6: it indicates that the group argument's value is to be placed on the
  1042. ; second upcode rather than the first.
  1043. ; Bit 5: Indicates that this row is handled very specially: the next two bytes
  1044. ; aren't upcode bytes, but a routine address to call to handle this case with
  1045. ; custom code.
  1046. ; Bit 4: When in an 'l' argspec, this means "I accept IX and IY variants".
  1047. ; This table needs to be kept in ascending order of I_* value.
  1048. instrTBl:
  1049. .db I_ADC, 'A', 'l', 0, 0x8e , 0 ; ADC A, (HL)
  1050. .db I_ADC, 'A', 0xb, 0, 0b10001000 , 0 ; ADC A, r
  1051. .db I_ADC, 'A', 'n', 0, 0xce , 0 ; ADC A, n
  1052. .db I_ADC, 'h', 0x3, 0x44, 0xed, 0b01001010 ; ADC HL, ss
  1053. .db I_ADD, 'A', 'l', 0x10, 0x86 , 0 ; ADD A, (HL) + (IX/Y)
  1054. .db I_ADD, 'A', 0xb, 0, 0b10000000 , 0 ; ADD A, r
  1055. .db I_ADD, 'A', 'n', 0, 0xc6 , 0 ; ADD A, n
  1056. .db I_ADD, 'h', 0x3, 4, 0b00001001 , 0 ; ADD HL, ss
  1057. .db I_ADD, 'X', 0x4, 0x44, 0xdd, 0b00001001 ; ADD IX, pp
  1058. .db I_ADD, 'Y', 0x5, 0x44, 0xfd, 0b00001001 ; ADD IY, rr
  1059. .db I_AND, 'l', 0, 0x10, 0xa6 , 0 ; AND (HL) + (IX/Y)
  1060. .db I_AND, 0xb, 0, 0, 0b10100000 , 0 ; AND r
  1061. .db I_AND, 'n', 0, 0, 0xe6 , 0 ; AND n
  1062. .db I_BIT, 0xc, 'l', 0x53, 0xcb, 0b01000110 ; BIT b, (HL) + (IX/Y)
  1063. .db I_BIT, 0xc, 0xb, 0x20 \ .dw handleBITR ; BIT b, r
  1064. .db I_CALL,0xa, 'N', 3, 0b11000100 , 0 ; CALL cc, NN
  1065. .db I_CALL,'N', 0, 0, 0xcd , 0 ; CALL NN
  1066. .db I_CCF, 0, 0, 0, 0x3f , 0 ; CCF
  1067. .db I_CP, 'l', 0, 0x10, 0xbe , 0 ; CP (HL) + (IX/Y)
  1068. .db I_CP, 0xb, 0, 0, 0b10111000 , 0 ; CP r
  1069. .db I_CP, 'n', 0, 0, 0xfe , 0 ; CP n
  1070. .db I_CPD, 0, 0, 0, 0xed, 0xa9 ; CPD
  1071. .db I_CPDR,0, 0, 0, 0xed, 0xb9 ; CPDR
  1072. .db I_CPI, 0, 0, 0, 0xed, 0xa1 ; CPI
  1073. .db I_CPIR,0, 0, 0, 0xed, 0xb1 ; CPIR
  1074. .db I_CPL, 0, 0, 0, 0x2f , 0 ; CPL
  1075. .db I_DAA, 0, 0, 0, 0x27 , 0 ; DAA
  1076. .db I_DEC, 'l', 0, 0x10, 0x35 , 0 ; DEC (HL) + (IX/Y)
  1077. .db I_DEC, 'X', 0, 0, 0xdd, 0x2b ; DEC IX
  1078. .db I_DEC, 'Y', 0, 0, 0xfd, 0x2b ; DEC IY
  1079. .db I_DEC, 0xb, 0, 3, 0b00000101 , 0 ; DEC r
  1080. .db I_DEC, 0x3, 0, 4, 0b00001011 , 0 ; DEC ss
  1081. .db I_DI, 0, 0, 0, 0xf3 , 0 ; DI
  1082. .db I_DJNZ,'n', 0, 0x80, 0x10 , 0 ; DJNZ e
  1083. .db I_EI, 0, 0, 0, 0xfb , 0 ; EI
  1084. instrTBlEX:
  1085. .db I_EX, 'p', 'h', 0, 0xe3 , 0 ; EX (SP), HL
  1086. .db I_EX, 'p', 'X', 0, 0xdd, 0xe3 ; EX (SP), IX
  1087. .db I_EX, 'p', 'Y', 0, 0xfd, 0xe3 ; EX (SP), IY
  1088. .db I_EX, 'a', 'f', 0, 0x08 , 0 ; EX AF, AF'
  1089. .db I_EX, 'd', 'h', 0, 0xeb , 0 ; EX DE, HL
  1090. .db I_EXX, 0, 0, 0, 0xd9 , 0 ; EXX
  1091. .db I_HALT,0, 0, 0, 0x76 , 0 ; HALT
  1092. .db I_IM, 'n', 0, 0x20 \ .dw handleIM ; IM {0,1,2}
  1093. .db I_IN, 'A', 'm', 0, 0xdb , 0 ; IN A, (n)
  1094. .db I_IN, 0xb, 'k', 0x43, 0xed, 0b01000000 ; IN r, (C)
  1095. .db I_INC, 'l', 0, 0x10, 0x34 , 0 ; INC (HL) + (IX/Y)
  1096. .db I_INC, 'X', 0, 0, 0xdd , 0x23 ; INC IX
  1097. .db I_INC, 'Y', 0, 0, 0xfd , 0x23 ; INC IY
  1098. .db I_INC, 0xb, 0, 3, 0b00000100 , 0 ; INC r
  1099. .db I_INC, 0x3, 0, 4, 0b00000011 , 0 ; INC ss
  1100. .db I_IND, 0, 0, 0, 0xed, 0xaa ; IND
  1101. .db I_INDR,0, 0, 0, 0xed, 0xba ; INDR
  1102. .db I_INI, 0, 0, 0, 0xed, 0xa2 ; INI
  1103. .db I_INIR,0, 0, 0, 0xed, 0xb2 ; INIR
  1104. .db I_JP, 'x', 0, 0x20 \ .dw handleJPIXY ; JP (IX)
  1105. .db I_JP, 'y', 0, 0x20 \ .dw handleJPIXY ; JP (IY)
  1106. .db I_JP, 'l', 0, 0, 0xe9 , 0 ; JP (HL)
  1107. .db I_JP, 0xa, 'N', 3, 0b11000010 , 0 ; JP cc, NN
  1108. .db I_JP, 'N', 0, 0, 0xc3 , 0 ; JP NN
  1109. .db I_JR, 'n', 0, 0x80, 0x18 , 0 ; JR e
  1110. .db I_JR, 'C', 'n', 0x80, 0x38 , 0 ; JR C, e
  1111. .db I_JR, '=', 'n', 0x80, 0x30 , 0 ; JR NC, e
  1112. .db I_JR, 'Z', 'n', 0x80, 0x28 , 0 ; JR Z, e
  1113. .db I_JR, 'z', 'n', 0x80, 0x20 , 0 ; JR NZ, e
  1114. instrTBlLD:
  1115. .db I_LD, 'c', 'A', 0, 0x02 , 0 ; LD (BC), A
  1116. .db I_LD, 'e', 'A', 0, 0x12 , 0 ; LD (DE), A
  1117. .db I_LD, 'A', 'c', 0, 0x0a , 0 ; LD A, (BC)
  1118. .db I_LD, 'A', 'e', 0, 0x1a , 0 ; LD A, (DE)
  1119. .db I_LD, 's', 'h', 0, 0xf9 , 0 ; LD SP, HL
  1120. .db I_LD, 'A', 'I', 0, 0xed, 0x57 ; LD A, I
  1121. .db I_LD, 'I', 'A', 0, 0xed, 0x47 ; LD I, A
  1122. .db I_LD, 'A', 'R', 0, 0xed, 0x5f ; LD A, R
  1123. .db I_LD, 'R', 'A', 0, 0xed, 0x4f ; LD R, A
  1124. .db I_LD, 'l', 0xb, 0, 0b01110000 , 0 ; LD (HL), r
  1125. .db I_LD, 0xb, 'l', 3, 0b01000110 , 0 ; LD r, (HL)
  1126. .db I_LD, 'l', 'n', 0, 0x36 , 0 ; LD (HL), n
  1127. .db I_LD, 0xb, 'n', 3, 0b00000110 , 0 ; LD r, n
  1128. .db I_LD, 0xb, 0xb, 0x20 \ .dw handleLDrr ; LD r, r'
  1129. .db I_LD, 0x3, 'N', 4, 0b00000001 , 0 ; LD dd, nn
  1130. .db I_LD, 'X', 'N', 0, 0xdd, 0x21 ; LD IX, NN
  1131. .db I_LD, 'Y', 'N', 0, 0xfd, 0x21 ; LD IY, NN
  1132. .db I_LD, 'M', 'A', 0, 0x32 , 0 ; LD (NN), A
  1133. .db I_LD, 'A', 'M', 0, 0x3a , 0 ; LD A, (NN)
  1134. .db I_LD, 'M', 'h', 0, 0x22 , 0 ; LD (NN), HL
  1135. .db I_LD, 'h', 'M', 0, 0x2a , 0 ; LD HL, (NN)
  1136. .db I_LD, 'M', 'X', 0, 0xdd, 0x22 ; LD (NN), IX
  1137. .db I_LD, 'X', 'M', 0, 0xdd, 0x2a ; LD IX, (NN)
  1138. .db I_LD, 'M', 'Y', 0, 0xfd, 0x22 ; LD (NN), IY
  1139. .db I_LD, 'Y', 'M', 0, 0xfd, 0x2a ; LD IY, (NN)
  1140. .db I_LD, 'M', 0x3, 0x44, 0xed, 0b01000011 ; LD (NN), dd
  1141. .db I_LD, 0x3, 'M', 0x44, 0xed, 0b01001011 ; LD dd, (NN)
  1142. .db I_LD, 'x', 'n', 0x20 \ .dw handleLDIXYn ; LD (IX+d), n
  1143. .db I_LD, 'y', 'n', 0x20 \ .dw handleLDIXYn ; LD (IY+d), n
  1144. .db I_LD, 'x', 0xb, 0x20 \ .dw handleLDIXYr ; LD (IX+d), r
  1145. .db I_LD, 'y', 0xb, 0x20 \ .dw handleLDIXYr ; LD (IY+d), r
  1146. .db I_LD, 0xb, 'x', 0x20 \ .dw handleLDrIXY ; LD r, (IX+d)
  1147. .db I_LD, 0xb, 'y', 0x20 \ .dw handleLDrIXY ; LD r, (IY+d)
  1148. .db I_LDD, 0, 0, 0, 0xed, 0xa8 ; LDD
  1149. .db I_LDDR,0, 0, 0, 0xed, 0xb8 ; LDDR
  1150. .db I_LDI, 0, 0, 0, 0xed, 0xa0 ; LDI
  1151. .db I_LDIR,0, 0, 0, 0xed, 0xb0 ; LDIR
  1152. .db I_NEG, 0, 0, 0, 0xed, 0x44 ; NEG
  1153. .db I_NOP, 0, 0, 0, 0x00 , 0 ; NOP
  1154. .db I_OR, 'l', 0, 0x10, 0xb6 , 0 ; OR (HL) + (IX/Y)
  1155. .db I_OR, 0xb, 0, 0, 0b10110000 , 0 ; OR r
  1156. .db I_OR, 'n', 0, 0, 0xf6 , 0 ; OR n
  1157. .db I_OTDR,0, 0, 0, 0xed, 0xbb ; OTDR
  1158. .db I_OTIR,0, 0, 0, 0xed, 0xb3 ; OTIR
  1159. .db I_OUT, 'm', 'A', 0, 0xd3 , 0 ; OUT (n), A
  1160. .db I_OUT, 'k', 0xb, 0x43, 0xed, 0b01000001 ; OUT (C), r
  1161. .db I_POP, 'X', 0, 0, 0xdd, 0xe1 ; POP IX
  1162. .db I_POP, 'Y', 0, 0, 0xfd, 0xe1 ; POP IY
  1163. .db I_POP, 0x1, 0, 4, 0b11000001 , 0 ; POP qq
  1164. .db I_PUSH,'X', 0, 0, 0xdd, 0xe5 ; PUSH IX
  1165. .db I_PUSH,'Y', 0, 0, 0xfd, 0xe5 ; PUSH IY
  1166. .db I_PUSH,0x1, 0, 4, 0b11000101 , 0 ; PUSH qq
  1167. .db I_RES, 0xc, 'l', 0x53, 0xcb, 0b10000110 ; RES b, (HL) + (IX/Y)
  1168. .db I_RES, 0xc, 0xb, 0x20 \ .dw handleRESR ; RES b, r
  1169. instrTBlRET:
  1170. .db I_RET, 0, 0, 0, 0xc9 , 0 ; RET
  1171. .db I_RET, 0xa, 0, 3, 0b11000000 , 0 ; RET cc
  1172. .db I_RETI,0, 0, 0, 0xed, 0x4d ; RETI
  1173. .db I_RETN,0, 0, 0, 0xed, 0x45 ; RETN
  1174. .db I_RL, 0xb, 0,0x40, 0xcb, 0b00010000 ; RL r
  1175. .db I_RL, 'l', 0,0x10, 0xcb, 0b00010110 ; RL (HL) + (IX/Y)
  1176. .db I_RLA, 0, 0, 0, 0x17 , 0 ; RLA
  1177. .db I_RLC, 0xb, 0,0x40, 0xcb, 0b00000000 ; RLC r
  1178. .db I_RLCA,0, 0, 0, 0x07 , 0 ; RLCA
  1179. .db I_RR, 0xb, 0,0x40, 0xcb, 0b00011000 ; RR r
  1180. .db I_RR, 'l', 0,0x10, 0xcb, 0b00011110 ; RR (HL) + (IX/Y)
  1181. .db I_RRA, 0, 0, 0, 0x1f , 0 ; RRA
  1182. .db I_RRC, 0xb, 0,0x40, 0xcb, 0b00001000 ; RRC r
  1183. .db I_RRCA,0, 0, 0, 0x0f , 0 ; RRCA
  1184. .db I_RST, 'n', 0, 0x20 \ .dw handleRST ; RST p
  1185. .db I_SBC, 'A', 'l', 0, 0x9e , 0 ; SBC A, (HL)
  1186. .db I_SBC, 'A', 0xb, 0, 0b10011000 , 0 ; SBC A, r
  1187. .db I_SBC,'h',0x3,0x44, 0xed, 0b01000010 ; SBC HL, ss
  1188. .db I_SCF, 0, 0, 0, 0x37 , 0 ; SCF
  1189. .db I_SET, 0xc, 'l', 0x53, 0xcb, 0b11000110 ; SET b, (HL) + (IX/Y)
  1190. .db I_SET, 0xc, 0xb, 0x20 \ .dw handleSETR ; SET b, r
  1191. .db I_SLA, 0xb, 0,0x40, 0xcb, 0b00100000 ; SLA r
  1192. .db I_SRL, 0xb, 0,0x40, 0xcb, 0b00111000 ; SRL r
  1193. .db I_SRL, 'l', 0,0x10, 0xcb, 0b00111110 ; SRL (HL) + (IX/Y)
  1194. .db I_SUB, 'l', 0, 0, 0x96 , 0 ; SUB (HL)
  1195. .db I_SUB, 0xb, 0, 0, 0b10010000 , 0 ; SUB r
  1196. .db I_SUB, 'n', 0, 0, 0xd6 , 0 ; SUB n
  1197. .db I_XOR, 'l', 0, 0, 0xae , 0 ; XOR (HL)
  1198. .db I_XOR, 0xb, 0, 0, 0b10101000 , 0 ; XOR r
  1199. .db I_XOR, 'n', 0, 0, 0xee , 0 ; XOR n
  1200. .db 0xff