gameboy superoptimizer
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.

1714 lines
34 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. from abc import ABC, abstractmethod
  2. from collections import defaultdict
  3. from dataclasses import dataclass
  4. from enum import Enum
  5. from typing import Dict, List, Type
  6. from gbso.cpu.cpu import CPU
  7. from gbso.cpu.regs import R16, R8
  8. class Operand(Enum):
  9. R8 = "R8"
  10. R16 = "R16" # BC, DE, HL, SP
  11. R16_NO_SP = "R16_NO_SP" # BC, DE, HL
  12. IMM3 = "IMM3"
  13. IMM8 = "IMM8"
  14. IMM16 = "IMM16"
  15. SIMM8 = "SIMM8"
  16. class Insn(ABC):
  17. @staticmethod
  18. @abstractmethod
  19. def signature() -> List[Operand]:
  20. pass
  21. @staticmethod
  22. @abstractmethod
  23. def cycles() -> int:
  24. pass
  25. @abstractmethod
  26. def exec(self, cpu: CPU) -> None:
  27. pass
  28. @abstractmethod
  29. def pretty(self) -> str:
  30. pass
  31. @dataclass
  32. class LD_R_R(Insn):
  33. dst: R8
  34. src: R8
  35. @staticmethod
  36. def signature() -> List[Operand]:
  37. return [Operand.R8, Operand.R8]
  38. @staticmethod
  39. def cycles() -> int:
  40. return 4
  41. def exec(self, cpu: CPU) -> None:
  42. cpu.set_reg8(self.dst, cpu.get_reg8(self.src))
  43. def pretty(self) -> str:
  44. return f"LD {self.dst.value}, {self.src.value}"
  45. @dataclass
  46. class LD_R_N8(Insn):
  47. dst: R8
  48. imm: int
  49. @staticmethod
  50. def signature() -> List[Operand]:
  51. return [Operand.R8, Operand.IMM8]
  52. @staticmethod
  53. def cycles() -> int:
  54. return 8
  55. def exec(self, cpu: CPU) -> None:
  56. cpu.set_reg8(self.dst, self.imm)
  57. def pretty(self) -> str:
  58. return f"LD {self.dst.value}, {hex(self.imm)}"
  59. @dataclass
  60. class LD_R_HL(Insn):
  61. dst: R8
  62. @staticmethod
  63. def signature() -> List[Operand]:
  64. return [Operand.R8]
  65. @staticmethod
  66. def cycles() -> int:
  67. return 8
  68. def exec(self, cpu: CPU) -> None:
  69. cpu.set_reg8(self.dst, cpu.get_mem8(cpu.get_reg16(R16.HL)))
  70. def pretty(self) -> str:
  71. return f"LD {self.dst.value}, (HL)"
  72. @dataclass
  73. class LD_HL_R(Insn):
  74. src: R8
  75. @staticmethod
  76. def signature() -> List[Operand]:
  77. return [Operand.R8]
  78. @staticmethod
  79. def cycles() -> int:
  80. return 8
  81. def exec(self, cpu: CPU) -> None:
  82. cpu.hl = cpu.get_reg8(self.src)
  83. def pretty(self) -> str:
  84. return f"LD (HL), {self.src.value}"
  85. @dataclass
  86. class LD_HL_N(Insn):
  87. imm: int
  88. @staticmethod
  89. def signature() -> List[Operand]:
  90. return [Operand.IMM8]
  91. @staticmethod
  92. def cycles() -> int:
  93. return 12
  94. def exec(self, cpu: CPU) -> None:
  95. cpu.set_mem8(cpu.get_reg16(R16.HL), self.imm)
  96. def pretty(self) -> str:
  97. return f"LD (HL), {hex(self.imm & 0xff)}"
  98. @dataclass
  99. class LD_A_BC(Insn):
  100. @staticmethod
  101. def signature() -> List[Operand]:
  102. return []
  103. @staticmethod
  104. def cycles() -> int:
  105. return 8
  106. def exec(self, cpu: CPU) -> None:
  107. cpu.set_reg8(R8.A, cpu.get_mem8(cpu.get_reg16(R16.BC)))
  108. def pretty(self) -> str:
  109. return "LD A, (BC)"
  110. @dataclass
  111. class LD_A_DE(Insn):
  112. @staticmethod
  113. def signature() -> List[Operand]:
  114. return []
  115. @staticmethod
  116. def cycles() -> int:
  117. return 8
  118. def exec(self, cpu: CPU) -> None:
  119. cpu.set_reg8(R8.A, cpu.get_mem8(cpu.get_reg16(R16.DE)))
  120. def pretty(self) -> str:
  121. return "LD A, (DE)"
  122. @dataclass
  123. class LD_A_NN(Insn):
  124. nn: int
  125. @staticmethod
  126. def signature() -> List[Operand]:
  127. return [Operand.IMM16]
  128. @staticmethod
  129. def cycles() -> int:
  130. return 16
  131. def exec(self, cpu: CPU) -> None:
  132. cpu.set_reg8(R8.A, cpu.get_mem8(self.nn))
  133. def pretty(self) -> str:
  134. return f"LD A, ({hex(self.nn)})"
  135. @dataclass
  136. class LD_BC_A(Insn):
  137. @staticmethod
  138. def signature() -> List[Operand]:
  139. return []
  140. @staticmethod
  141. def cycles() -> int:
  142. return 8
  143. def exec(self, cpu: CPU) -> None:
  144. cpu.set_mem8(cpu.get_reg16(R16.BC), cpu.get_reg8(R8.A))
  145. def pretty(self) -> str:
  146. return "LD (BC), A"
  147. @dataclass
  148. class LD_DE_A(Insn):
  149. @staticmethod
  150. def signature() -> List[Operand]:
  151. return []
  152. @staticmethod
  153. def cycles() -> int:
  154. return 8
  155. def exec(self, cpu: CPU) -> None:
  156. cpu.set_mem8(cpu.get_reg16(R16.DE), cpu.get_reg8(R8.A))
  157. def pretty(self) -> str:
  158. return "LD (DE), A"
  159. @dataclass
  160. class LD_NN_A(Insn):
  161. nn: int
  162. @staticmethod
  163. def signature() -> List[Operand]:
  164. return [Operand.IMM16]
  165. @staticmethod
  166. def cycles() -> int:
  167. return 16
  168. def exec(self, cpu: CPU) -> None:
  169. cpu.set_mem8(self.nn, cpu.get_reg8(R8.A))
  170. def pretty(self) -> str:
  171. return f"LD ({hex(self.nn)}), A"
  172. @dataclass
  173. class LD_A_FF_N(Insn):
  174. n: int
  175. @staticmethod
  176. def signature() -> List[Operand]:
  177. return [Operand.IMM8]
  178. @staticmethod
  179. def cycles() -> int:
  180. return 12
  181. def exec(self, cpu: CPU) -> None:
  182. cpu.set_reg8(R8.A, cpu.get_mem8(0xFF00 + self.n))
  183. def pretty(self) -> str:
  184. return f"LD A, (0xFF00 + {hex(self.n)})"
  185. @dataclass
  186. class LD_FF_N_A(Insn):
  187. n: int
  188. @staticmethod
  189. def signature() -> List[Operand]:
  190. return [Operand.IMM8]
  191. @staticmethod
  192. def cycles() -> int:
  193. return 12
  194. def exec(self, cpu: CPU) -> None:
  195. cpu.set_mem8(0xFF00 + self.n, cpu.get_reg8(R8.A))
  196. def pretty(self) -> str:
  197. return f"LD (0xFF00 + {hex(self.n)}), A"
  198. @dataclass
  199. class LD_A_FF_C(Insn):
  200. @staticmethod
  201. def signature() -> List[Operand]:
  202. return []
  203. @staticmethod
  204. def cycles() -> int:
  205. return 8
  206. def exec(self, cpu: CPU) -> None:
  207. cpu.set_reg8(R8.A, cpu.get_mem8(0xFF00 + cpu.get_reg8(R8.C)))
  208. def pretty(self) -> str:
  209. return "LD A, (0xFF00 + C)"
  210. @dataclass
  211. class LD_FF_C_A(Insn):
  212. @staticmethod
  213. def signature() -> List[Operand]:
  214. return []
  215. @staticmethod
  216. def cycles() -> int:
  217. return 8
  218. def exec(self, cpu: CPU) -> None:
  219. cpu.set_mem8(0xFF00 + cpu.get_reg8(R8.C), cpu.get_reg8(R8.A))
  220. def pretty(self) -> str:
  221. return "LD (0xFF00 + C), A"
  222. @dataclass
  223. class LDI_HL_A(Insn):
  224. @staticmethod
  225. def signature() -> List[Operand]:
  226. return []
  227. @staticmethod
  228. def cycles() -> int:
  229. return 8
  230. def exec(self, cpu: CPU) -> None:
  231. hl = cpu.get_reg16(R16.HL)
  232. cpu.set_mem8(hl, cpu.get_reg8(R8.A))
  233. cpu.set_reg16(R16.HL, hl + 1)
  234. def pretty(self) -> str:
  235. return "LDI (HL), A"
  236. @dataclass
  237. class LDI_A_HL(Insn):
  238. @staticmethod
  239. def signature() -> List[Operand]:
  240. return []
  241. @staticmethod
  242. def cycles() -> int:
  243. return 8
  244. def exec(self, cpu: CPU) -> None:
  245. hl = cpu.get_reg16(R16.HL)
  246. cpu.set_reg8(R8.A, cpu.get_mem8(hl))
  247. cpu.set_reg16(R16.HL, hl + 1)
  248. def pretty(self) -> str:
  249. return "LDI A, (HL)"
  250. @dataclass
  251. class LDD_HL_A(Insn):
  252. @staticmethod
  253. def signature() -> List[Operand]:
  254. return []
  255. @staticmethod
  256. def cycles() -> int:
  257. return 8
  258. def exec(self, cpu: CPU) -> None:
  259. hl = cpu.get_reg16(R16.HL)
  260. cpu.set_mem8(hl, cpu.get_reg8(R8.A))
  261. cpu.set_reg16(R16.HL, hl - 1)
  262. def pretty(self) -> str:
  263. return "LDD (HL), A"
  264. @dataclass
  265. class LDD_A_HL(Insn):
  266. @staticmethod
  267. def signature() -> List[Operand]:
  268. return []
  269. @staticmethod
  270. def cycles() -> int:
  271. return 8
  272. def exec(self, cpu: CPU) -> None:
  273. hl = cpu.get_reg16(R16.HL)
  274. cpu.set_reg8(R8.A, cpu.get_mem8(hl))
  275. cpu.set_reg16(R16.HL, hl - 1)
  276. def pretty(self) -> str:
  277. return "LDD A, (HL)"
  278. @dataclass
  279. class LD_RR_NN(Insn):
  280. rr: R16
  281. nn: int
  282. @staticmethod
  283. def signature() -> List[Operand]:
  284. return [Operand.R16, Operand.IMM16]
  285. @staticmethod
  286. def cycles() -> int:
  287. return 12
  288. def exec(self, cpu: CPU) -> None:
  289. cpu.set_reg16(self.rr, self.nn)
  290. def pretty(self) -> str:
  291. return f"LD {self.rr.value}, {hex(self.nn)}"
  292. @dataclass
  293. class LD_NN_SP(Insn):
  294. nn: int
  295. @staticmethod
  296. def signature() -> List[Operand]:
  297. return [Operand.IMM16]
  298. @staticmethod
  299. def cycles() -> int:
  300. return 20
  301. def exec(self, cpu: CPU) -> None:
  302. cpu.set_mem16(self.nn, cpu.get_reg16(R16.SP))
  303. def pretty(self) -> str:
  304. return f"LD ({hex(self.nn)}), SP"
  305. @dataclass
  306. class LD_SP_HL(Insn):
  307. @staticmethod
  308. def signature() -> List[Operand]:
  309. return []
  310. @staticmethod
  311. def cycles() -> int:
  312. return 8
  313. def exec(self, cpu: CPU) -> None:
  314. cpu.set_reg16(R16.SP, cpu.get_reg16(R16.HL))
  315. def pretty(self) -> str:
  316. return "LD SP, HL"
  317. # NOTE: Normally we would support PUSH AF, but then non-carry flags could impact
  318. # the program (by popping or inspecting where F was stored)
  319. @dataclass
  320. class PUSH_RR(Insn):
  321. rr: R16
  322. @staticmethod
  323. def signature() -> List[Operand]:
  324. return [Operand.R16_NO_SP]
  325. @staticmethod
  326. def cycles() -> int:
  327. return 16
  328. def exec(self, cpu: CPU) -> None:
  329. sp = cpu.get_reg16(R16.SP) - 2
  330. cpu.set_reg16(R16.SP, sp)
  331. cpu.set_mem16(sp, cpu.get_reg16(self.rr))
  332. def pretty(self) -> str:
  333. return f"PUSH {self.rr.value}"
  334. @dataclass
  335. class POP_RR(Insn):
  336. rr: R16
  337. @staticmethod
  338. def signature() -> List[Operand]:
  339. return [Operand.R16_NO_SP]
  340. @staticmethod
  341. def cycles() -> int:
  342. return 12
  343. def exec(self, cpu: CPU) -> None:
  344. sp = cpu.get_reg16(R16.SP)
  345. cpu.set_reg16(self.rr, cpu.get_mem16(sp))
  346. cpu.set_reg16(R16.SP, sp + 2)
  347. def pretty(self) -> str:
  348. return f"POP {self.rr.value}"
  349. @dataclass
  350. class ADD_A_R(Insn):
  351. r: R8
  352. @staticmethod
  353. def signature() -> List[Operand]:
  354. return [Operand.R8]
  355. @staticmethod
  356. def cycles() -> int:
  357. return 4
  358. def exec(self, cpu: CPU) -> None:
  359. a = cpu.get_reg8(R8.A) + cpu.get_reg8(self.r)
  360. cpu.state.carry = 1 if a > 0xFF else 0
  361. cpu.set_reg8(R8.A, a)
  362. def pretty(self) -> str:
  363. return f"ADD A, {self.r.value}"
  364. @dataclass
  365. class ADD_A_N(Insn):
  366. n: int
  367. @staticmethod
  368. def signature() -> List[Operand]:
  369. return [Operand.IMM8]
  370. @staticmethod
  371. def cycles() -> int:
  372. return 8
  373. def exec(self, cpu: CPU) -> None:
  374. a = cpu.get_reg8(R8.A) + self.n
  375. cpu.state.carry = 1 if a > 0xFF else 0
  376. cpu.set_reg8(R8.A, a)
  377. def pretty(self) -> str:
  378. return f"ADD A, {hex(self.n)}"
  379. @dataclass
  380. class ADD_A_HL(Insn):
  381. @staticmethod
  382. def signature() -> List[Operand]:
  383. return []
  384. @staticmethod
  385. def cycles() -> int:
  386. return 8
  387. def exec(self, cpu: CPU) -> None:
  388. a = cpu.get_reg8(R8.A) + cpu.get_mem8(cpu.get_reg16(R16.HL))
  389. cpu.state.carry = 1 if a > 0xFF else 0
  390. cpu.set_reg8(R8.A, a)
  391. def pretty(self) -> str:
  392. return f"ADD A, (HL)"
  393. @dataclass
  394. class ADC_A_R(Insn):
  395. r: R8
  396. @staticmethod
  397. def signature() -> List[Operand]:
  398. return [Operand.R8]
  399. @staticmethod
  400. def cycles() -> int:
  401. return 4
  402. def exec(self, cpu: CPU) -> None:
  403. a = cpu.get_reg8(R8.A) + cpu.get_reg8(self.r) + cpu.state.carry
  404. cpu.state.carry = 1 if a > 0xFF else 0
  405. cpu.set_reg8(R8.A, a)
  406. def pretty(self) -> str:
  407. return f"ADC A, {self.r.value}"
  408. @dataclass
  409. class ADC_A_N(Insn):
  410. n: int
  411. @staticmethod
  412. def signature() -> List[Operand]:
  413. return [Operand.IMM8]
  414. @staticmethod
  415. def cycles() -> int:
  416. return 8
  417. def exec(self, cpu: CPU) -> None:
  418. a = cpu.get_reg8(R8.A) + self.n + cpu.state.carry
  419. cpu.state.carry = 1 if a > 0xFF else 0
  420. cpu.set_reg8(R8.A, a)
  421. def pretty(self) -> str:
  422. return f"ADC A, {hex(self.n)}"
  423. @dataclass
  424. class ADC_A_HL(Insn):
  425. @staticmethod
  426. def signature() -> List[Operand]:
  427. return []
  428. @staticmethod
  429. def cycles() -> int:
  430. return 8
  431. def exec(self, cpu: CPU) -> None:
  432. a = cpu.get_reg8(R8.A) + cpu.get_mem8(cpu.get_reg16(R16.HL)) + cpu.state.carry
  433. cpu.state.carry = 1 if a > 0xFF else 0
  434. cpu.set_reg8(R8.A, a)
  435. def pretty(self) -> str:
  436. return f"ADC A, (HL)"
  437. @dataclass
  438. class SUB_A_R(Insn):
  439. r: R8
  440. @staticmethod
  441. def signature() -> List[Operand]:
  442. return [Operand.R8]
  443. @staticmethod
  444. def cycles() -> int:
  445. return 4
  446. def exec(self, cpu: CPU) -> None:
  447. a = cpu.get_reg8(R8.A) - cpu.get_reg8(self.r)
  448. cpu.state.carry = 1 if a < 0 else 0
  449. cpu.set_reg8(R8.A, a)
  450. def pretty(self) -> str:
  451. return f"SUB A, {self.r.value}"
  452. @dataclass
  453. class SUB_A_N(Insn):
  454. n: int
  455. @staticmethod
  456. def signature() -> List[Operand]:
  457. return [Operand.IMM8]
  458. @staticmethod
  459. def cycles() -> int:
  460. return 8
  461. def exec(self, cpu: CPU) -> None:
  462. a = cpu.get_reg8(R8.A) - self.n
  463. cpu.state.carry = 1 if a < 0 else 0
  464. cpu.set_reg8(R8.A, a)
  465. def pretty(self) -> str:
  466. return f"SUB A, {hex(self.n)}"
  467. @dataclass
  468. class SUB_A_HL(Insn):
  469. @staticmethod
  470. def signature() -> List[Operand]:
  471. return []
  472. @staticmethod
  473. def cycles() -> int:
  474. return 8
  475. def exec(self, cpu: CPU) -> None:
  476. a = cpu.get_reg8(R8.A) - cpu.get_mem8(cpu.get_reg16(R16.HL))
  477. cpu.state.carry = 1 if a < 0 else 0
  478. cpu.set_reg8(R8.A, a)
  479. def pretty(self) -> str:
  480. return "SUB A, (HL)"
  481. @dataclass
  482. class SBC_A_R(Insn):
  483. r: R8
  484. @staticmethod
  485. def signature() -> List[Operand]:
  486. return [Operand.R8]
  487. @staticmethod
  488. def cycles() -> int:
  489. return 4
  490. def exec(self, cpu: CPU) -> None:
  491. a = cpu.get_reg8(R8.A) - cpu.get_reg8(self.r) - cpu.state.carry
  492. cpu.state.carry = 1 if a < 0 else 0
  493. cpu.set_reg8(R8.A, a)
  494. def pretty(self) -> str:
  495. return f"SBC A, {self.r.value}"
  496. @dataclass
  497. class SBC_A_N(Insn):
  498. n: int
  499. @staticmethod
  500. def signature() -> List[Operand]:
  501. return [Operand.IMM8]
  502. @staticmethod
  503. def cycles() -> int:
  504. return 8
  505. def exec(self, cpu: CPU) -> None:
  506. a = cpu.get_reg8(R8.A) - self.n - cpu.state.carry
  507. cpu.state.carry = 1 if a < 0 else 0
  508. cpu.set_reg8(R8.A, a)
  509. def pretty(self) -> str:
  510. return f"SBC A, {hex(self.n)}"
  511. @dataclass
  512. class SBC_A_HL(Insn):
  513. @staticmethod
  514. def signature() -> List[Operand]:
  515. return []
  516. @staticmethod
  517. def cycles() -> int:
  518. return 8
  519. def exec(self, cpu: CPU) -> None:
  520. a = cpu.get_reg8(R8.A) - cpu.get_mem8(cpu.get_reg16(R16.HL)) - cpu.state.carry
  521. cpu.state.carry = 1 if a < 0 else 0
  522. cpu.set_reg8(R8.A, a)
  523. def pretty(self) -> str:
  524. return "SBC A, (HL)"
  525. @dataclass
  526. class AND_A_R(Insn):
  527. r: R8
  528. @staticmethod
  529. def signature() -> List[Operand]:
  530. return [Operand.R8]
  531. @staticmethod
  532. def cycles() -> int:
  533. return 4
  534. def exec(self, cpu: CPU) -> None:
  535. a = cpu.get_reg8(R8.A) & cpu.get_reg8(self.r)
  536. cpu.set_reg8(R8.A, a)
  537. cpu.state.carry = 0
  538. def pretty(self) -> str:
  539. return f"AND A, {self.r.value}"
  540. @dataclass
  541. class AND_A_N(Insn):
  542. n: int
  543. @staticmethod
  544. def signature() -> List[Operand]:
  545. return [Operand.IMM8]
  546. @staticmethod
  547. def cycles() -> int:
  548. return 8
  549. def exec(self, cpu: CPU) -> None:
  550. a = cpu.get_reg8(R8.A) & self.n
  551. cpu.set_reg8(R8.A, a)
  552. cpu.state.carry = 0
  553. def pretty(self) -> str:
  554. return f"AND A, {hex(self.n)}"
  555. @dataclass
  556. class AND_A_HL(Insn):
  557. @staticmethod
  558. def signature() -> List[Operand]:
  559. return []
  560. @staticmethod
  561. def cycles() -> int:
  562. return 8
  563. def exec(self, cpu: CPU) -> None:
  564. a = cpu.get_reg8(R8.A) & cpu.get_mem8(cpu.get_reg16(R16.HL))
  565. cpu.set_reg8(R8.A, a)
  566. cpu.state.carry = 0
  567. def pretty(self) -> str:
  568. return "AND A, (HL)"
  569. @dataclass
  570. class XOR_A_R(Insn):
  571. r: R8
  572. @staticmethod
  573. def signature() -> List[Operand]:
  574. return [Operand.R8]
  575. @staticmethod
  576. def cycles() -> int:
  577. return 4
  578. def exec(self, cpu: CPU) -> None:
  579. a = cpu.get_reg8(R8.A) ^ cpu.get_reg8(self.r)
  580. cpu.set_reg8(R8.A, a)
  581. cpu.state.carry = 0
  582. def pretty(self) -> str:
  583. return f"XOR A, {self.r.value}"
  584. @dataclass
  585. class XOR_A_N(Insn):
  586. n: int
  587. @staticmethod
  588. def signature() -> List[Operand]:
  589. return [Operand.IMM8]
  590. @staticmethod
  591. def cycles() -> int:
  592. return 8
  593. def exec(self, cpu: CPU) -> None:
  594. a = cpu.get_reg8(R8.A) ^ self.n
  595. cpu.set_reg8(R8.A, a)
  596. cpu.state.carry = 0
  597. def pretty(self) -> str:
  598. return f"XOR A, {hex(self.n)}"
  599. @dataclass
  600. class XOR_A_HL(Insn):
  601. @staticmethod
  602. def signature() -> List[Operand]:
  603. return []
  604. @staticmethod
  605. def cycles() -> int:
  606. return 8
  607. def exec(self, cpu: CPU) -> None:
  608. a = cpu.get_reg8(R8.A) ^ cpu.get_mem8(cpu.get_reg16(R16.HL))
  609. cpu.set_reg8(R8.A, a)
  610. cpu.state.carry = 0
  611. def pretty(self) -> str:
  612. return "XOR A, (HL)"
  613. @dataclass
  614. class OR_A_R(Insn):
  615. r: R8
  616. @staticmethod
  617. def signature() -> List[Operand]:
  618. return [Operand.R8]
  619. @staticmethod
  620. def cycles() -> int:
  621. return 4
  622. def exec(self, cpu: CPU) -> None:
  623. a = cpu.get_reg8(R8.A) | cpu.get_reg8(self.r)
  624. cpu.set_reg8(R8.A, a)
  625. cpu.state.carry = 0
  626. def pretty(self) -> str:
  627. return f"OR A, {self.r.value}"
  628. @dataclass
  629. class OR_A_N(Insn):
  630. n: int
  631. @staticmethod
  632. def signature() -> List[Operand]:
  633. return [Operand.IMM8]
  634. @staticmethod
  635. def cycles() -> int:
  636. return 8
  637. def exec(self, cpu: CPU) -> None:
  638. a = cpu.get_reg8(R8.A) | self.n
  639. cpu.set_reg8(R8.A, a)
  640. cpu.state.carry = 0
  641. def pretty(self) -> str:
  642. return f"OR A, {hex(self.n)}"
  643. @dataclass
  644. class OR_A_HL(Insn):
  645. @staticmethod
  646. def signature() -> List[Operand]:
  647. return []
  648. @staticmethod
  649. def cycles() -> int:
  650. return 8
  651. def exec(self, cpu: CPU) -> None:
  652. a = cpu.get_reg8(R8.A) | cpu.get_mem8(cpu.get_reg16(R16.HL))
  653. cpu.set_reg8(R8.A, a)
  654. cpu.state.carry = 0
  655. def pretty(self) -> str:
  656. return "OR A, (HL)"
  657. @dataclass
  658. class CP_A_R(Insn):
  659. r: R8
  660. @staticmethod
  661. def signature() -> List[Operand]:
  662. return [Operand.R8]
  663. @staticmethod
  664. def cycles() -> int:
  665. return 4
  666. def exec(self, cpu: CPU) -> None:
  667. cpu.state.carry = 1 if cpu.get_reg8(R8.A) < cpu.get_reg8(self.r) else 0
  668. def pretty(self) -> str:
  669. return f"CP A, {self.r.value}"
  670. @dataclass
  671. class CP_A_N(Insn):
  672. n: int
  673. @staticmethod
  674. def signature() -> List[Operand]:
  675. return [Operand.IMM8]
  676. @staticmethod
  677. def cycles() -> int:
  678. return 8
  679. def exec(self, cpu: CPU) -> None:
  680. cpu.state.carry = 1 if cpu.get_reg8(R8.A) < self.n else 0
  681. def pretty(self) -> str:
  682. return f"CP A, {hex(self.n)}"
  683. @dataclass
  684. class CP_A_HL(Insn):
  685. @staticmethod
  686. def signature() -> List[Operand]:
  687. return []
  688. @staticmethod
  689. def cycles() -> int:
  690. return 8
  691. def exec(self, cpu: CPU) -> None:
  692. cpu.state.carry = (
  693. 1 if cpu.get_reg8(R8.A) < cpu.get_mem8(cpu.get_reg16(R16.HL)) else 0
  694. )
  695. def pretty(self) -> str:
  696. return "CP A, (HL)"
  697. @dataclass
  698. class INC_R(Insn):
  699. r: R8
  700. @staticmethod
  701. def signature() -> List[Operand]:
  702. return [Operand.R8]
  703. @staticmethod
  704. def cycles() -> int:
  705. return 4
  706. def exec(self, cpu: CPU) -> None:
  707. cpu.set_reg8(self.r, cpu.get_reg8(self.r) + 1)
  708. def pretty(self) -> str:
  709. return f"INC {self.r.value}"
  710. @dataclass
  711. class INC_HL(Insn):
  712. @staticmethod
  713. def signature() -> List[Operand]:
  714. return []
  715. @staticmethod
  716. def cycles() -> int:
  717. return 12
  718. def exec(self, cpu: CPU) -> None:
  719. hl = cpu.get_reg16(R16.HL)
  720. cpu.set_mem8(hl, cpu.get_mem8(hl) + 1)
  721. def pretty(self) -> str:
  722. return "INC (HL)"
  723. @dataclass
  724. class DEC_R(Insn):
  725. r: R8
  726. @staticmethod
  727. def signature() -> List[Operand]:
  728. return [Operand.R8]
  729. @staticmethod
  730. def cycles() -> int:
  731. return 4
  732. def exec(self, cpu: CPU) -> None:
  733. cpu.set_reg8(self.r, cpu.get_reg8(self.r) - 1)
  734. def pretty(self) -> str:
  735. return f"DEC {self.r.value}"
  736. @dataclass
  737. class DEC_HL(Insn):
  738. @staticmethod
  739. def signature() -> List[Operand]:
  740. return []
  741. @staticmethod
  742. def cycles() -> int:
  743. return 12
  744. def exec(self, cpu: CPU) -> None:
  745. hl = cpu.get_reg16(R16.HL)
  746. cpu.set_mem8(hl, cpu.get_mem8(hl) - 1)
  747. def pretty(self) -> str:
  748. return "DEC (HL)"
  749. # TODO: Implement DAA
  750. @dataclass
  751. class CPL(Insn):
  752. @staticmethod
  753. def signature() -> List[Operand]:
  754. return []
  755. @staticmethod
  756. def cycles() -> int:
  757. return 4
  758. def exec(self, cpu: CPU) -> None:
  759. cpu.set_reg8(R8.A, cpu.get_reg8(R8.A) ^ 0xFF)
  760. def pretty(self) -> str:
  761. return "CPL"
  762. @dataclass
  763. class ADD_HL_RR(Insn):
  764. rr: R16
  765. @staticmethod
  766. def signature() -> List[Operand]:
  767. return [Operand.R16]
  768. @staticmethod
  769. def cycles() -> int:
  770. return 8
  771. def exec(self, cpu: CPU) -> None:
  772. hl = cpu.get_reg16(R16.HL) + cpu.get_reg16(self.rr)
  773. cpu.state.carry = 1 if hl > 0xFFFF else 0
  774. cpu.set_reg16(R16.HL, hl)
  775. def pretty(self) -> str:
  776. return f"ADD HL, {self.rr.value}"
  777. @dataclass
  778. class INC_RR(Insn):
  779. rr: R16
  780. @staticmethod
  781. def signature() -> List[Operand]:
  782. return [Operand.R16]
  783. @staticmethod
  784. def cycles() -> int:
  785. return 8
  786. def exec(self, cpu: CPU) -> None:
  787. cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) + 1)
  788. def pretty(self) -> str:
  789. return f"INC {self.rr.value}"
  790. @dataclass
  791. class DEC_RR(Insn):
  792. rr: R16
  793. @staticmethod
  794. def signature() -> List[Operand]:
  795. return [Operand.R16]
  796. @staticmethod
  797. def cycles() -> int:
  798. return 8
  799. def exec(self, cpu: CPU) -> None:
  800. cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) - 1)
  801. def pretty(self) -> str:
  802. return f"DEC {self.rr.value}"
  803. @dataclass
  804. class ADD_SP_DD(Insn):
  805. dd: int
  806. @staticmethod
  807. def signature() -> List[Operand]:
  808. return [Operand.SIMM8]
  809. @staticmethod
  810. def cycles() -> int:
  811. return 16
  812. def exec(self, cpu: CPU) -> None:
  813. sp = cpu.get_reg16(R16.SP) + self.dd
  814. cpu.state.carry = 1 if sp > 0xFFFF or sp < 0 else 0
  815. cpu.set_reg16(R16.SP, sp & 0xFFFF)
  816. def pretty(self) -> str:
  817. return f"ADD SP, {self.dd}"
  818. @dataclass
  819. class LD_HL_SP_DD(Insn):
  820. dd: int
  821. @staticmethod
  822. def signature() -> List[Operand]:
  823. return [Operand.SIMM8]
  824. @staticmethod
  825. def cycles() -> int:
  826. return 12
  827. def exec(self, cpu: CPU) -> None:
  828. sp = cpu.get_reg16(R16.SP) + self.dd
  829. cpu.state.carry = 1 if sp > 0xFFFF or sp < 0 else 0
  830. cpu.set_reg16(R16.HL, sp & 0xFFFF)
  831. def pretty(self) -> str:
  832. return f"LD HL, SP + {self.dd}"
  833. @dataclass
  834. class RLCA(Insn):
  835. @staticmethod
  836. def signature() -> List[Operand]:
  837. return []
  838. @staticmethod
  839. def cycles() -> int:
  840. return 4
  841. def exec(self, cpu: CPU) -> None:
  842. a = cpu.get_reg8(R8.A)
  843. cpu.state.carry = (a >> 7) & 1
  844. cpu.set_reg8(R8.A, ((a << 1) & 0xFF) | cpu.state.carry)
  845. def pretty(self) -> str:
  846. return "RLCA"
  847. @dataclass
  848. class RLA(Insn):
  849. @staticmethod
  850. def signature() -> List[Operand]:
  851. return []
  852. @staticmethod
  853. def cycles() -> int:
  854. return 4
  855. def exec(self, cpu: CPU) -> None:
  856. a = cpu.get_reg8(R8.A)
  857. next_carry = (a >> 7) & 1
  858. cpu.set_reg8(R8.A, ((a << 1) & 0xFF) | cpu.state.carry)
  859. cpu.state.carry = next_carry
  860. def pretty(self) -> str:
  861. return "RLA"
  862. @dataclass
  863. class RRCA(Insn):
  864. @staticmethod
  865. def signature() -> List[Operand]:
  866. return []
  867. @staticmethod
  868. def cycles() -> int:
  869. return 4
  870. def exec(self, cpu: CPU) -> None:
  871. a = cpu.get_reg8(R8.A)
  872. cpu.state.carry = a & 1
  873. cpu.set_reg8(R8.A, (a >> 1) | (cpu.state.carry << 7))
  874. def pretty(self) -> str:
  875. return "RRCA"
  876. @dataclass
  877. class RRA(Insn):
  878. @staticmethod
  879. def signature() -> List[Operand]:
  880. return []
  881. @staticmethod
  882. def cycles() -> int:
  883. return 4
  884. def exec(self, cpu: CPU) -> None:
  885. a = cpu.get_reg8(R8.A)
  886. next_carry = a & 1
  887. cpu.set_reg8(R8.A, (a >> 1) | (cpu.state.carry << 7))
  888. cpu.state.carry = next_carry
  889. def pretty(self) -> str:
  890. return "RRA"
  891. @dataclass
  892. class RLC_R(Insn):
  893. r: R8
  894. @staticmethod
  895. def signature() -> List[Operand]:
  896. return [Operand.R8]
  897. @staticmethod
  898. def cycles() -> int:
  899. return 8
  900. def exec(self, cpu: CPU) -> None:
  901. r = cpu.get_reg8(self.r)
  902. cpu.state.carry = (r >> 7) & 1
  903. cpu.set_reg8(self.r, ((r << 1) & 0xFF) | cpu.state.carry)
  904. def pretty(self) -> str:
  905. return f"RLC {self.r.value}"
  906. @dataclass
  907. class RLC_HL(Insn):
  908. @staticmethod
  909. def signature() -> List[Operand]:
  910. return []
  911. @staticmethod
  912. def cycles() -> int:
  913. return 16
  914. def exec(self, cpu: CPU) -> None:
  915. cpu.state.carry = (cpu.hl >> 7) & 1
  916. cpu.hl = ((cpu.hl << 1) & 0xFF) | cpu.state.carry
  917. def pretty(self) -> str:
  918. return f"RLC (HL)"
  919. @dataclass
  920. class RL_R(Insn):
  921. r: R8
  922. @staticmethod
  923. def signature() -> List[Operand]:
  924. return [Operand.R8]
  925. @staticmethod
  926. def cycles() -> int:
  927. return 8
  928. def exec(self, cpu: CPU) -> None:
  929. r = cpu.get_reg8(self.r)
  930. next_carry = (r >> 7) & 1
  931. cpu.set_reg8(self.r, ((r << 1) & 0xFF) | cpu.state.carry)
  932. cpu.state.carry = next_carry
  933. def pretty(self) -> str:
  934. return f"RL {self.r.value}"
  935. @dataclass
  936. class RL_HL(Insn):
  937. @staticmethod
  938. def signature() -> List[Operand]:
  939. return []
  940. @staticmethod
  941. def cycles() -> int:
  942. return 16
  943. def exec(self, cpu: CPU) -> None:
  944. next_carry = (cpu.hl >> 7) & 1
  945. cpu.hl = ((cpu.hl << 1) & 0xFF) | cpu.state.carry
  946. cpu.state.carry = next_carry
  947. def pretty(self) -> str:
  948. return "RL (HL)"
  949. @dataclass
  950. class RRC_R(Insn):
  951. r: R8
  952. @staticmethod
  953. def signature() -> List[Operand]:
  954. return [Operand.R8]
  955. @staticmethod
  956. def cycles() -> int:
  957. return 8
  958. def exec(self, cpu: CPU) -> None:
  959. r = cpu.get_reg8(self.r)
  960. cpu.state.carry = r & 1
  961. cpu.set_reg8(self.r, (r >> 1) | (cpu.state.carry << 7))
  962. def pretty(self) -> str:
  963. return f"RRC {self.r.value}"
  964. @dataclass
  965. class RRC_HL(Insn):
  966. @staticmethod
  967. def signature() -> List[Operand]:
  968. return []
  969. @staticmethod
  970. def cycles() -> int:
  971. return 16
  972. def exec(self, cpu: CPU) -> None:
  973. cpu.state.carry = cpu.hl & 1
  974. cpu.hl = (cpu.hl >> 1) | (cpu.state.carry << 7)
  975. def pretty(self) -> str:
  976. return "RRC (HL)"
  977. @dataclass
  978. class RR_R(Insn):
  979. r: R8
  980. @staticmethod
  981. def signature() -> List[Operand]:
  982. return [Operand.R8]
  983. @staticmethod
  984. def cycles() -> int:
  985. return 8
  986. def exec(self, cpu: CPU) -> None:
  987. r = cpu.get_reg8(self.r)
  988. next_carry = r & 1
  989. cpu.set_reg8(self.r, (r >> 1) | (cpu.state.carry << 7))
  990. cpu.state.carry = next_carry
  991. def pretty(self) -> str:
  992. return f"RR {self.r.value}"
  993. @dataclass
  994. class RR_HL(Insn):
  995. @staticmethod
  996. def signature() -> List[Operand]:
  997. return []
  998. @staticmethod
  999. def cycles() -> int:
  1000. return 16
  1001. def exec(self, cpu: CPU) -> None:
  1002. next_carry = cpu.hl & 1
  1003. cpu.hl = (cpu.hl >> 1) | (cpu.state.carry << 7)
  1004. cpu.state.carry = next_carry
  1005. def pretty(self) -> str:
  1006. return "RR (HL)"
  1007. @dataclass
  1008. class SLA_R(Insn):
  1009. r: R8
  1010. @staticmethod
  1011. def signature() -> List[Operand]:
  1012. return [Operand.R8]
  1013. @staticmethod
  1014. def cycles() -> int:
  1015. return 8
  1016. def exec(self, cpu: CPU) -> None:
  1017. r = cpu.get_reg8(self.r)
  1018. cpu.state.carry = 1 if r & (1 << 7) else 0
  1019. cpu.set_reg8(self.r, (r << 1) & 0xFF)
  1020. def pretty(self) -> str:
  1021. return f"SLA {self.r.value}"
  1022. @dataclass
  1023. class SLA_HL(Insn):
  1024. @staticmethod
  1025. def signature() -> List[Operand]:
  1026. return []
  1027. @staticmethod
  1028. def cycles() -> int:
  1029. return 16
  1030. def exec(self, cpu: CPU) -> None:
  1031. cpu.state.carry = 1 if cpu.hl & (1 << 7) else 0
  1032. cpu.hl = (cpu.hl << 1) & 0xFF
  1033. def pretty(self) -> str:
  1034. return "SLA (HL)"
  1035. @dataclass
  1036. class SWAP_R(Insn):
  1037. r: R8
  1038. @staticmethod
  1039. def signature() -> List[Operand]:
  1040. return [Operand.R8]
  1041. @staticmethod
  1042. def cycles() -> int:
  1043. return 8
  1044. def exec(self, cpu: CPU) -> None:
  1045. r = cpu.get_reg8(self.r)
  1046. cpu.set_reg8(self.r, ((r << 4) & 0xFF) | (r >> 4))
  1047. cpu.state.carry = 0
  1048. def pretty(self) -> str:
  1049. return f"SWAP {self.r.value}"
  1050. @dataclass
  1051. class SWAP_HL(Insn):
  1052. @staticmethod
  1053. def signature() -> List[Operand]:
  1054. return []
  1055. @staticmethod
  1056. def cycles() -> int:
  1057. return 16
  1058. def exec(self, cpu: CPU) -> None:
  1059. cpu.hl = ((cpu.hl << 4) & 0xFF) | (cpu.hl >> 4)
  1060. cpu.state.carry = 0
  1061. def pretty(self) -> str:
  1062. return "SWAP (HL)"
  1063. @dataclass
  1064. class SRA_R(Insn):
  1065. r: R8
  1066. @staticmethod
  1067. def signature() -> List[Operand]:
  1068. return [Operand.R8]
  1069. @staticmethod
  1070. def cycles() -> int:
  1071. return 8
  1072. def exec(self, cpu: CPU) -> None:
  1073. r = cpu.get_reg8(self.r)
  1074. cpu.state.carry = 1 if r & (1 << 0) else 0
  1075. cpu.set_reg8(self.r, (r >> 1) | (r & (1 << 7)))
  1076. def pretty(self) -> str:
  1077. return f"SRA {self.r.value}"
  1078. @dataclass
  1079. class SRA_HL(Insn):
  1080. @staticmethod
  1081. def signature() -> List[Operand]:
  1082. return []
  1083. @staticmethod
  1084. def cycles() -> int:
  1085. return 16
  1086. def exec(self, cpu: CPU) -> None:
  1087. cpu.state.carry = 1 if cpu.hl & (1 << 0) else 0
  1088. cpu.hl = (cpu.hl >> 1) | (cpu.hl & (1 << 7))
  1089. def pretty(self) -> str:
  1090. return "SRA (HL)"
  1091. @dataclass
  1092. class SRL_R(Insn):
  1093. r: R8
  1094. @staticmethod
  1095. def signature() -> List[Operand]:
  1096. return [Operand.R8]
  1097. @staticmethod
  1098. def cycles() -> int:
  1099. return 8
  1100. def exec(self, cpu: CPU) -> None:
  1101. r = cpu.get_reg8(self.r)
  1102. cpu.state.carry = 1 if r & (1 << 0) else 0
  1103. cpu.set_reg8(self.r, r >> 1)
  1104. def pretty(self) -> str:
  1105. return f"SRL {self.r.value}"
  1106. @dataclass
  1107. class SRL_HL(Insn):
  1108. @staticmethod
  1109. def signature() -> List[Operand]:
  1110. return []
  1111. @staticmethod
  1112. def cycles() -> int:
  1113. return 16
  1114. def exec(self, cpu: CPU) -> None:
  1115. cpu.state.carry = 1 if cpu.hl & (1 << 0) else 0
  1116. cpu.hl = cpu.hl >> 1
  1117. def pretty(self) -> str:
  1118. return "SRL (HL)"
  1119. @dataclass
  1120. class SET_N_R(Insn):
  1121. n: int
  1122. r: R8
  1123. @staticmethod
  1124. def signature() -> List[Operand]:
  1125. return [Operand.IMM3, Operand.R8]
  1126. @staticmethod
  1127. def cycles() -> int:
  1128. return 8
  1129. def exec(self, cpu: CPU) -> None:
  1130. cpu.set_reg8(self.r, cpu.get_reg8(self.r) | (1 << self.n))
  1131. def pretty(self) -> str:
  1132. return f"SET {self.n}, {self.r.value}"
  1133. @dataclass
  1134. class SET_N_HL(Insn):
  1135. n: int
  1136. @staticmethod
  1137. def signature() -> List[Operand]:
  1138. return [Operand.IMM3]
  1139. @staticmethod
  1140. def cycles() -> int:
  1141. return 16
  1142. def exec(self, cpu: CPU) -> None:
  1143. hl = cpu.get_reg16(R16.HL)
  1144. cpu.set_mem8(hl, cpu.get_mem8(hl) | (1 << self.n))
  1145. def pretty(self) -> str:
  1146. return f"SET {self.n}, (HL)"
  1147. @dataclass
  1148. class RES_N_R(Insn):
  1149. n: int
  1150. r: R8
  1151. @staticmethod
  1152. def signature() -> List[Operand]:
  1153. return [Operand.IMM3, Operand.R8]
  1154. @staticmethod
  1155. def cycles() -> int:
  1156. return 8
  1157. def exec(self, cpu: CPU) -> None:
  1158. cpu.set_reg8(self.r, cpu.get_reg8(self.r) & ~(1 << self.n))
  1159. def pretty(self) -> str:
  1160. return f"RES {self.n}, (HL)"
  1161. @dataclass
  1162. class RES_N_HL(Insn):
  1163. n: int
  1164. @staticmethod
  1165. def signature() -> List[Operand]:
  1166. return [Operand.IMM3]
  1167. @staticmethod
  1168. def cycles() -> int:
  1169. return 16
  1170. def exec(self, cpu: CPU) -> None:
  1171. hl = cpu.get_reg16(R16.HL)
  1172. cpu.set_mem8(hl, cpu.get_mem8(hl) & ~(1 << self.n))
  1173. def pretty(self) -> str:
  1174. return f"RES {self.n}, (HL)"
  1175. @dataclass
  1176. class CCF(Insn):
  1177. @staticmethod
  1178. def signature() -> List[Operand]:
  1179. return []
  1180. @staticmethod
  1181. def cycles() -> int:
  1182. return 4
  1183. def exec(self, cpu: CPU) -> None:
  1184. cpu.state.carry = cpu.state.carry ^ 1
  1185. def pretty(self) -> str:
  1186. return "CCF"
  1187. @dataclass
  1188. class SCF(Insn):
  1189. @staticmethod
  1190. def signature() -> List[Operand]:
  1191. return []
  1192. @staticmethod
  1193. def cycles() -> int:
  1194. return 4
  1195. def exec(self, cpu: CPU) -> None:
  1196. cpu.state.carry = 1
  1197. def pretty(self) -> str:
  1198. return "SCF"
  1199. @dataclass
  1200. class UNUSED(Insn):
  1201. @staticmethod
  1202. def signature() -> List[Operand]:
  1203. return []
  1204. @staticmethod
  1205. def cycles() -> int:
  1206. return 0
  1207. def exec(self, cpu: CPU) -> None:
  1208. pass
  1209. def pretty(self) -> str:
  1210. return "UNUSED"
  1211. ALL_INSN_CLASSES: List[Type[Insn]] = [
  1212. cls for cls in Insn.__subclasses__() if cls not in {Insn, UNUSED} # type: ignore
  1213. ]
  1214. INSNS_BY_SIGNATURE: Dict[str, List[Type[Insn]]] = defaultdict(list)
  1215. def get_signature_class(insn: Insn) -> List[Type[Insn]]:
  1216. signature_key = get_signature_key(insn.signature())
  1217. return INSNS_BY_SIGNATURE[signature_key]
  1218. def get_signature_key(signature: List[Operand]) -> str:
  1219. return "-".join([ty.value for ty in signature])
  1220. for insn_cls in ALL_INSN_CLASSES:
  1221. signature_key = get_signature_key(insn_cls.signature())
  1222. INSNS_BY_SIGNATURE[signature_key].append(insn_cls)