|
|
- from abc import ABC, abstractmethod
- from collections import defaultdict
- from dataclasses import dataclass
- from enum import Enum
- from typing import Dict, List, Type
-
- from gbso.cpu.cpu import CPU
- from gbso.cpu.regs import R16, R8
-
-
- class Operand(Enum):
- R8 = "R8"
- R16 = "R16" # BC, DE, HL, SP
- R16_NO_SP = "R16_NO_SP" # BC, DE, HL
- IMM3 = "IMM3"
- IMM8 = "IMM8"
- IMM16 = "IMM16"
- SIMM8 = "SIMM8"
-
-
- class Insn(ABC):
- @staticmethod
- @abstractmethod
- def signature() -> List[Operand]:
- pass
-
- @staticmethod
- @abstractmethod
- def cycles() -> int:
- pass
-
- @abstractmethod
- def exec(self, cpu: CPU) -> None:
- pass
-
- @abstractmethod
- def pretty(self) -> str:
- pass
-
-
- @dataclass
- class LD_R_R(Insn):
- dst: R8
- src: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8, Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.dst, cpu.get_reg8(self.src))
-
- def pretty(self) -> str:
- return f"LD {self.dst.value}, {self.src.value}"
-
-
- @dataclass
- class LD_R_N8(Insn):
- dst: R8
- imm: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8, Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.dst, self.imm)
-
- def pretty(self) -> str:
- return f"LD {self.dst.value}, {hex(self.imm)}"
-
-
- @dataclass
- class LD_R_HL(Insn):
- dst: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.dst, cpu.get_mem8(cpu.get_reg16(R16.HL)))
-
- def pretty(self) -> str:
- return f"LD {self.dst.value}, (HL)"
-
-
- @dataclass
- class LD_HL_R(Insn):
- src: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.hl = cpu.get_reg8(self.src)
-
- def pretty(self) -> str:
- return f"LD (HL), {self.src.value}"
-
-
- @dataclass
- class LD_HL_N(Insn):
- imm: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(cpu.get_reg16(R16.HL), self.imm)
-
- def pretty(self) -> str:
- return f"LD (HL), {hex(self.imm & 0xff)}"
-
-
- @dataclass
- class LD_A_BC(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_mem8(cpu.get_reg16(R16.BC)))
-
- def pretty(self) -> str:
- return "LD A, (BC)"
-
-
- @dataclass
- class LD_A_DE(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_mem8(cpu.get_reg16(R16.DE)))
-
- def pretty(self) -> str:
- return "LD A, (DE)"
-
-
- @dataclass
- class LD_A_NN(Insn):
- nn: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM16]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_mem8(self.nn))
-
- def pretty(self) -> str:
- return f"LD A, ({hex(self.nn)})"
-
-
- @dataclass
- class LD_BC_A(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(cpu.get_reg16(R16.BC), cpu.get_reg8(R8.A))
-
- def pretty(self) -> str:
- return "LD (BC), A"
-
-
- @dataclass
- class LD_DE_A(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(cpu.get_reg16(R16.DE), cpu.get_reg8(R8.A))
-
- def pretty(self) -> str:
- return "LD (DE), A"
-
-
- @dataclass
- class LD_NN_A(Insn):
- nn: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM16]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(self.nn, cpu.get_reg8(R8.A))
-
- def pretty(self) -> str:
- return f"LD ({hex(self.nn)}), A"
-
-
- @dataclass
- class LD_A_FF_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_mem8(0xFF00 + self.n))
-
- def pretty(self) -> str:
- return f"LD A, (0xFF00 + {hex(self.n)})"
-
-
- @dataclass
- class LD_FF_N_A(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(0xFF00 + self.n, cpu.get_reg8(R8.A))
-
- def pretty(self) -> str:
- return f"LD (0xFF00 + {hex(self.n)}), A"
-
-
- @dataclass
- class LD_A_FF_C(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_mem8(0xFF00 + cpu.get_reg8(R8.C)))
-
- def pretty(self) -> str:
- return "LD A, (0xFF00 + C)"
-
-
- @dataclass
- class LD_FF_C_A(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem8(0xFF00 + cpu.get_reg8(R8.C), cpu.get_reg8(R8.A))
-
- def pretty(self) -> str:
- return "LD (0xFF00 + C), A"
-
-
- @dataclass
- class LDI_HL_A(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_reg8(R8.A))
- cpu.set_reg16(R16.HL, hl + 1)
-
- def pretty(self) -> str:
- return "LDI (HL), A"
-
-
- @dataclass
- class LDI_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_reg8(R8.A, cpu.get_mem8(hl))
- cpu.set_reg16(R16.HL, hl + 1)
-
- def pretty(self) -> str:
- return "LDI A, (HL)"
-
-
- @dataclass
- class LDD_HL_A(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_reg8(R8.A))
- cpu.set_reg16(R16.HL, hl - 1)
-
- def pretty(self) -> str:
- return "LDD (HL), A"
-
-
- @dataclass
- class LDD_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_reg8(R8.A, cpu.get_mem8(hl))
- cpu.set_reg16(R16.HL, hl - 1)
-
- def pretty(self) -> str:
- return "LDD A, (HL)"
-
-
- @dataclass
- class LD_RR_NN(Insn):
- rr: R16
- nn: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16, Operand.IMM16]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg16(self.rr, self.nn)
-
- def pretty(self) -> str:
- return f"LD {self.rr.value}, {hex(self.nn)}"
-
-
- @dataclass
- class LD_NN_SP(Insn):
- nn: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM16]
-
- @staticmethod
- def cycles() -> int:
- return 20
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_mem16(self.nn, cpu.get_reg16(R16.SP))
-
- def pretty(self) -> str:
- return f"LD ({hex(self.nn)}), SP"
-
-
- @dataclass
- class LD_SP_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg16(R16.SP, cpu.get_reg16(R16.HL))
-
- def pretty(self) -> str:
- return "LD SP, HL"
-
-
- # NOTE: Normally we would support PUSH AF, but then non-carry flags could impact
- # the program (by popping or inspecting where F was stored)
- @dataclass
- class PUSH_RR(Insn):
- rr: R16
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16_NO_SP]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- sp = cpu.get_reg16(R16.SP) - 2
- cpu.set_reg16(R16.SP, sp)
- cpu.set_mem16(sp, cpu.get_reg16(self.rr))
-
- def pretty(self) -> str:
- return f"PUSH {self.rr.value}"
-
-
- @dataclass
- class POP_RR(Insn):
- rr: R16
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16_NO_SP]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- sp = cpu.get_reg16(R16.SP)
- cpu.set_reg16(self.rr, cpu.get_mem16(sp))
- cpu.set_reg16(R16.SP, sp + 2)
-
- def pretty(self) -> str:
- return f"POP {self.rr.value}"
-
-
- @dataclass
- class ADD_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + cpu.get_reg8(self.r)
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADD A, {self.r.value}"
-
-
- @dataclass
- class ADD_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + self.n
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADD A, {hex(self.n)}"
-
-
- @dataclass
- class ADD_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + cpu.get_mem8(cpu.get_reg16(R16.HL))
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADD A, (HL)"
-
-
- @dataclass
- class ADC_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + cpu.get_reg8(self.r) + cpu.state.carry
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADC A, {self.r.value}"
-
-
- @dataclass
- class ADC_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + self.n + cpu.state.carry
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADC A, {hex(self.n)}"
-
-
- @dataclass
- class ADC_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) + cpu.get_mem8(cpu.get_reg16(R16.HL)) + cpu.state.carry
- cpu.state.carry = 1 if a > 0xFF else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"ADC A, (HL)"
-
-
- @dataclass
- class SUB_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - cpu.get_reg8(self.r)
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"SUB A, {self.r.value}"
-
-
- @dataclass
- class SUB_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - self.n
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"SUB A, {hex(self.n)}"
-
-
- @dataclass
- class SUB_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - cpu.get_mem8(cpu.get_reg16(R16.HL))
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return "SUB A, (HL)"
-
-
- @dataclass
- class SBC_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - cpu.get_reg8(self.r) - cpu.state.carry
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"SBC A, {self.r.value}"
-
-
- @dataclass
- class SBC_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - self.n - cpu.state.carry
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return f"SBC A, {hex(self.n)}"
-
-
- @dataclass
- class SBC_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) - cpu.get_mem8(cpu.get_reg16(R16.HL)) - cpu.state.carry
- cpu.state.carry = 1 if a < 0 else 0
- cpu.set_reg8(R8.A, a)
-
- def pretty(self) -> str:
- return "SBC A, (HL)"
-
-
- @dataclass
- class AND_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) & cpu.get_reg8(self.r)
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"AND A, {self.r.value}"
-
-
- @dataclass
- class AND_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) & self.n
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"AND A, {hex(self.n)}"
-
-
- @dataclass
- class AND_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) & cpu.get_mem8(cpu.get_reg16(R16.HL))
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return "AND A, (HL)"
-
-
- @dataclass
- class XOR_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) ^ cpu.get_reg8(self.r)
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"XOR A, {self.r.value}"
-
-
- @dataclass
- class XOR_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) ^ self.n
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"XOR A, {hex(self.n)}"
-
-
- @dataclass
- class XOR_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) ^ cpu.get_mem8(cpu.get_reg16(R16.HL))
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return "XOR A, (HL)"
-
-
- @dataclass
- class OR_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) | cpu.get_reg8(self.r)
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"OR A, {self.r.value}"
-
-
- @dataclass
- class OR_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) | self.n
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"OR A, {hex(self.n)}"
-
-
- @dataclass
- class OR_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A) | cpu.get_mem8(cpu.get_reg16(R16.HL))
- cpu.set_reg8(R8.A, a)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return "OR A, (HL)"
-
-
- @dataclass
- class CP_A_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1 if cpu.get_reg8(R8.A) < cpu.get_reg8(self.r) else 0
-
- def pretty(self) -> str:
- return f"CP A, {self.r.value}"
-
-
- @dataclass
- class CP_A_N(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1 if cpu.get_reg8(R8.A) < self.n else 0
-
- def pretty(self) -> str:
- return f"CP A, {hex(self.n)}"
-
-
- @dataclass
- class CP_A_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = (
- 1 if cpu.get_reg8(R8.A) < cpu.get_mem8(cpu.get_reg16(R16.HL)) else 0
- )
-
- def pretty(self) -> str:
- return "CP A, (HL)"
-
-
- @dataclass
- class INC_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.r, cpu.get_reg8(self.r) + 1)
-
- def pretty(self) -> str:
- return f"INC {self.r.value}"
-
-
- @dataclass
- class INC_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_mem8(hl) + 1)
-
- def pretty(self) -> str:
- return "INC (HL)"
-
-
- @dataclass
- class DEC_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.r, cpu.get_reg8(self.r) - 1)
-
- def pretty(self) -> str:
- return f"DEC {self.r.value}"
-
-
- @dataclass
- class DEC_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_mem8(hl) - 1)
-
- def pretty(self) -> str:
- return "DEC (HL)"
-
-
- # TODO: Implement DAA
-
-
- @dataclass
- class CPL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(R8.A, cpu.get_reg8(R8.A) ^ 0xFF)
-
- def pretty(self) -> str:
- return "CPL"
-
-
- @dataclass
- class ADD_HL_RR(Insn):
- rr: R16
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL) + cpu.get_reg16(self.rr)
- cpu.state.carry = 1 if hl > 0xFFFF else 0
- cpu.set_reg16(R16.HL, hl)
-
- def pretty(self) -> str:
- return f"ADD HL, {self.rr.value}"
-
-
- @dataclass
- class INC_RR(Insn):
- rr: R16
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) + 1)
-
- def pretty(self) -> str:
- return f"INC {self.rr.value}"
-
-
- @dataclass
- class DEC_RR(Insn):
- rr: R16
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R16]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) - 1)
-
- def pretty(self) -> str:
- return f"DEC {self.rr.value}"
-
-
- @dataclass
- class ADD_SP_DD(Insn):
- dd: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.SIMM8]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- sp = cpu.get_reg16(R16.SP) + self.dd
- cpu.state.carry = 1 if sp > 0xFFFF or sp < 0 else 0
- cpu.set_reg16(R16.SP, sp & 0xFFFF)
-
- def pretty(self) -> str:
- return f"ADD SP, {self.dd}"
-
-
- @dataclass
- class LD_HL_SP_DD(Insn):
- dd: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.SIMM8]
-
- @staticmethod
- def cycles() -> int:
- return 12
-
- def exec(self, cpu: CPU) -> None:
- sp = cpu.get_reg16(R16.SP) + self.dd
- cpu.state.carry = 1 if sp > 0xFFFF or sp < 0 else 0
- cpu.set_reg16(R16.HL, sp & 0xFFFF)
-
- def pretty(self) -> str:
- return f"LD HL, SP + {self.dd}"
-
-
- @dataclass
- class RLCA(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A)
- cpu.state.carry = (a >> 7) & 1
- cpu.set_reg8(R8.A, ((a << 1) & 0xFF) | cpu.state.carry)
-
- def pretty(self) -> str:
- return "RLCA"
-
-
- @dataclass
- class RLA(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A)
- next_carry = (a >> 7) & 1
- cpu.set_reg8(R8.A, ((a << 1) & 0xFF) | cpu.state.carry)
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return "RLA"
-
-
- @dataclass
- class RRCA(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A)
- cpu.state.carry = a & 1
- cpu.set_reg8(R8.A, (a >> 1) | (cpu.state.carry << 7))
-
- def pretty(self) -> str:
- return "RRCA"
-
-
- @dataclass
- class RRA(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- a = cpu.get_reg8(R8.A)
- next_carry = a & 1
- cpu.set_reg8(R8.A, (a >> 1) | (cpu.state.carry << 7))
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return "RRA"
-
-
- @dataclass
- class RLC_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.state.carry = (r >> 7) & 1
- cpu.set_reg8(self.r, ((r << 1) & 0xFF) | cpu.state.carry)
-
- def pretty(self) -> str:
- return f"RLC {self.r.value}"
-
-
- @dataclass
- class RLC_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = (cpu.hl >> 7) & 1
- cpu.hl = ((cpu.hl << 1) & 0xFF) | cpu.state.carry
-
- def pretty(self) -> str:
- return f"RLC (HL)"
-
-
- @dataclass
- class RL_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- next_carry = (r >> 7) & 1
- cpu.set_reg8(self.r, ((r << 1) & 0xFF) | cpu.state.carry)
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return f"RL {self.r.value}"
-
-
- @dataclass
- class RL_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- next_carry = (cpu.hl >> 7) & 1
- cpu.hl = ((cpu.hl << 1) & 0xFF) | cpu.state.carry
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return "RL (HL)"
-
-
- @dataclass
- class RRC_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.state.carry = r & 1
- cpu.set_reg8(self.r, (r >> 1) | (cpu.state.carry << 7))
-
- def pretty(self) -> str:
- return f"RRC {self.r.value}"
-
-
- @dataclass
- class RRC_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = cpu.hl & 1
- cpu.hl = (cpu.hl >> 1) | (cpu.state.carry << 7)
-
- def pretty(self) -> str:
- return "RRC (HL)"
-
-
- @dataclass
- class RR_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- next_carry = r & 1
- cpu.set_reg8(self.r, (r >> 1) | (cpu.state.carry << 7))
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return f"RR {self.r.value}"
-
-
- @dataclass
- class RR_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- next_carry = cpu.hl & 1
- cpu.hl = (cpu.hl >> 1) | (cpu.state.carry << 7)
- cpu.state.carry = next_carry
-
- def pretty(self) -> str:
- return "RR (HL)"
-
-
- @dataclass
- class SLA_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.state.carry = 1 if r & (1 << 7) else 0
- cpu.set_reg8(self.r, (r << 1) & 0xFF)
-
- def pretty(self) -> str:
- return f"SLA {self.r.value}"
-
-
- @dataclass
- class SLA_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1 if cpu.hl & (1 << 7) else 0
- cpu.hl = (cpu.hl << 1) & 0xFF
-
- def pretty(self) -> str:
- return "SLA (HL)"
-
-
- @dataclass
- class SWAP_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.set_reg8(self.r, ((r << 4) & 0xFF) | (r >> 4))
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return f"SWAP {self.r.value}"
-
-
- @dataclass
- class SWAP_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.hl = ((cpu.hl << 4) & 0xFF) | (cpu.hl >> 4)
- cpu.state.carry = 0
-
- def pretty(self) -> str:
- return "SWAP (HL)"
-
-
- @dataclass
- class SRA_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.state.carry = 1 if r & (1 << 0) else 0
- cpu.set_reg8(self.r, (r >> 1) | (r & (1 << 7)))
-
- def pretty(self) -> str:
- return f"SRA {self.r.value}"
-
-
- @dataclass
- class SRA_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1 if cpu.hl & (1 << 0) else 0
- cpu.hl = (cpu.hl >> 1) | (cpu.hl & (1 << 7))
-
- def pretty(self) -> str:
- return "SRA (HL)"
-
-
- @dataclass
- class SRL_R(Insn):
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- r = cpu.get_reg8(self.r)
- cpu.state.carry = 1 if r & (1 << 0) else 0
- cpu.set_reg8(self.r, r >> 1)
-
- def pretty(self) -> str:
- return f"SRL {self.r.value}"
-
-
- @dataclass
- class SRL_HL(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1 if cpu.hl & (1 << 0) else 0
- cpu.hl = cpu.hl >> 1
-
- def pretty(self) -> str:
- return "SRL (HL)"
-
-
- @dataclass
- class SET_N_R(Insn):
- n: int
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM3, Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.r, cpu.get_reg8(self.r) | (1 << self.n))
-
- def pretty(self) -> str:
- return f"SET {self.n}, {self.r.value}"
-
-
- @dataclass
- class SET_N_HL(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM3]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_mem8(hl) | (1 << self.n))
-
- def pretty(self) -> str:
- return f"SET {self.n}, (HL)"
-
-
- @dataclass
- class RES_N_R(Insn):
- n: int
- r: R8
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM3, Operand.R8]
-
- @staticmethod
- def cycles() -> int:
- return 8
-
- def exec(self, cpu: CPU) -> None:
- cpu.set_reg8(self.r, cpu.get_reg8(self.r) & ~(1 << self.n))
-
- def pretty(self) -> str:
- return f"RES {self.n}, (HL)"
-
-
- @dataclass
- class RES_N_HL(Insn):
- n: int
-
- @staticmethod
- def signature() -> List[Operand]:
- return [Operand.IMM3]
-
- @staticmethod
- def cycles() -> int:
- return 16
-
- def exec(self, cpu: CPU) -> None:
- hl = cpu.get_reg16(R16.HL)
- cpu.set_mem8(hl, cpu.get_mem8(hl) & ~(1 << self.n))
-
- def pretty(self) -> str:
- return f"RES {self.n}, (HL)"
-
-
- @dataclass
- class CCF(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = cpu.state.carry ^ 1
-
- def pretty(self) -> str:
- return "CCF"
-
-
- @dataclass
- class SCF(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 4
-
- def exec(self, cpu: CPU) -> None:
- cpu.state.carry = 1
-
- def pretty(self) -> str:
- return "SCF"
-
-
- @dataclass
- class UNUSED(Insn):
- @staticmethod
- def signature() -> List[Operand]:
- return []
-
- @staticmethod
- def cycles() -> int:
- return 0
-
- def exec(self, cpu: CPU) -> None:
- pass
-
- def pretty(self) -> str:
- return "UNUSED"
-
-
- ALL_INSN_CLASSES: List[Type[Insn]] = [
- cls for cls in Insn.__subclasses__() if cls != Insn # type: ignore
- ]
-
- INSNS_BY_SIGNATURE: Dict[str, List[Type[Insn]]] = defaultdict(list)
-
-
- def get_signature_class(insn: Insn) -> List[Type[Insn]]:
- signature_key = get_signature_key(insn.signature())
- return INSNS_BY_SIGNATURE[signature_key]
-
-
- def get_signature_key(signature: List[Operand]) -> str:
- return "-".join([ty.value for ty in signature])
-
-
- for insn_cls in ALL_INSN_CLASSES:
- signature_key = get_signature_key(insn_cls.signature())
- INSNS_BY_SIGNATURE[signature_key].append(insn_cls)
|