From 88db4070a8e7666651aff7845106dd71a5cb5c3e Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Mon, 2 Aug 2021 02:12:39 -0400 Subject: [PATCH] Move CPU cycle tracking into static method --- gbso/cpu/insn.py | 429 +++++++++++++++++++++++++++++-------- gbso/cpu/state.py | 1 - gbso/program/program.py | 10 +- gbso/program/test_case.py | 33 ++- tests/insn/test_alu16.py | 10 - tests/insn/test_alu8.py | 31 --- tests/insn/test_bit.py | 4 - tests/insn/test_cpu.py | 3 - tests/insn/test_loads16.py | 5 - tests/insn/test_loads8.py | 20 -- tests/insn/test_shift.py | 38 ---- 11 files changed, 371 insertions(+), 213 deletions(-) diff --git a/gbso/cpu/insn.py b/gbso/cpu/insn.py index 0b7092d..b3c1026 100644 --- a/gbso/cpu/insn.py +++ b/gbso/cpu/insn.py @@ -6,6 +6,11 @@ from gbso.cpu.regs import R16, R8 class Insn(ABC): + @staticmethod + @abstractmethod + def cycles() -> int: + pass + @abstractmethod def exec(self, cpu: CPU) -> None: pass @@ -20,9 +25,12 @@ class LD_R_R(Insn): dst: R8 src: R8 + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(self.dst, cpu.get_reg8(self.src)) - cpu.state.cycles += 4 def pretty(self) -> str: return f"LD {self.dst.value}, {self.src.value}" @@ -33,9 +41,12 @@ class LD_R_N8(Insn): dst: R8 imm: int + @staticmethod + def cycles() -> int: + return 8 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(self.dst, self.imm) - cpu.state.cycles += 8 def pretty(self) -> str: return f"LD {self.dst.value}, {hex(self.imm)}" @@ -45,9 +56,12 @@ class LD_R_N8(Insn): class LD_R_HL(Insn): dst: 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))) - cpu.state.cycles += 8 def pretty(self) -> str: return f"LD {self.dst.value}, (HL)" @@ -57,9 +71,12 @@ class LD_R_HL(Insn): class LD_HL_R(Insn): src: R8 + @staticmethod + def cycles() -> int: + return 8 + def exec(self, cpu: CPU) -> None: cpu.hl = cpu.get_reg8(self.src) - cpu.state.cycles += 8 def pretty(self) -> str: return f"LD (HL), {self.src.value}" @@ -69,9 +86,12 @@ class LD_HL_R(Insn): class LD_HL_N(Insn): imm: int + @staticmethod + def cycles() -> int: + return 12 + def exec(self, cpu: CPU) -> None: cpu.set_mem8(cpu.get_reg16(R16.HL), self.imm) - cpu.state.cycles += 12 def pretty(self) -> str: return f"LD (HL), {hex(self.imm & 0xff)}" @@ -79,9 +99,12 @@ class LD_HL_N(Insn): @dataclass class LD_A_BC(Insn): + @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))) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD A, (BC)" @@ -89,9 +112,12 @@ class LD_A_BC(Insn): @dataclass class LD_A_DE(Insn): + @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))) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD A, (DE)" @@ -101,9 +127,12 @@ class LD_A_DE(Insn): class LD_A_NN(Insn): nn: int + @staticmethod + def cycles() -> int: + return 16 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(R8.A, cpu.get_mem8(self.nn)) - cpu.state.cycles += 16 def pretty(self) -> str: return f"LD A, ({hex(self.nn)})" @@ -111,9 +140,12 @@ class LD_A_NN(Insn): @dataclass class LD_BC_A(Insn): + @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)) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD (BC), A" @@ -121,9 +153,12 @@ class LD_BC_A(Insn): @dataclass class LD_DE_A(Insn): + @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)) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD (DE), A" @@ -133,9 +168,12 @@ class LD_DE_A(Insn): class LD_NN_A(Insn): nn: int + @staticmethod + def cycles() -> int: + return 16 + def exec(self, cpu: CPU) -> None: cpu.set_mem8(self.nn, cpu.get_reg8(R8.A)) - cpu.state.cycles += 16 def pretty(self) -> str: return f"LD ({hex(self.nn)}), A" @@ -145,9 +183,12 @@ class LD_NN_A(Insn): class LD_A_FF_N(Insn): n: int + @staticmethod + def cycles() -> int: + return 12 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(R8.A, cpu.get_mem8(0xFF00 + self.n)) - cpu.state.cycles += 12 def pretty(self) -> str: return f"LD A, (0xFF00 + {hex(self.n)})" @@ -157,9 +198,12 @@ class LD_A_FF_N(Insn): class LD_FF_N_A(Insn): n: int + @staticmethod + def cycles() -> int: + return 12 + def exec(self, cpu: CPU) -> None: cpu.set_mem8(0xFF00 + self.n, cpu.get_reg8(R8.A)) - cpu.state.cycles += 12 def pretty(self) -> str: return f"LD (0xFF00 + {hex(self.n)}), A" @@ -167,9 +211,12 @@ class LD_FF_N_A(Insn): @dataclass class LD_A_FF_C(Insn): + @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))) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD A, (0xFF00 + C)" @@ -177,9 +224,12 @@ class LD_A_FF_C(Insn): @dataclass class LD_FF_C_A(Insn): + @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)) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD (0xFF00 + C), A" @@ -187,11 +237,14 @@ class LD_FF_C_A(Insn): @dataclass class LDI_HL_A(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "LDI (HL), A" @@ -199,11 +252,14 @@ class LDI_HL_A(Insn): @dataclass class LDI_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "LDI A, (HL)" @@ -211,11 +267,14 @@ class LDI_A_HL(Insn): @dataclass class LDD_HL_A(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "LDD (HL), A" @@ -223,11 +282,14 @@ class LDD_HL_A(Insn): @dataclass class LDD_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "LDD A, (HL)" @@ -238,9 +300,12 @@ class LD_RR_NN(Insn): rr: R16 nn: int + @staticmethod + def cycles() -> int: + return 12 + def exec(self, cpu: CPU) -> None: cpu.set_reg16(self.rr, self.nn) - cpu.state.cycles += 12 def pretty(self) -> str: return f"LD {self.rr.value}, {hex(self.nn)}" @@ -250,9 +315,12 @@ class LD_RR_NN(Insn): class LD_NN_SP(Insn): nn: int + @staticmethod + def cycles() -> int: + return 20 + def exec(self, cpu: CPU) -> None: cpu.set_mem16(self.nn, cpu.get_reg16(R16.SP)) - cpu.state.cycles += 20 def pretty(self) -> str: return f"LD ({hex(self.nn)}), SP" @@ -260,9 +328,12 @@ class LD_NN_SP(Insn): @dataclass class LD_SP_HL(Insn): + @staticmethod + def cycles() -> int: + return 8 + def exec(self, cpu: CPU) -> None: cpu.set_reg16(R16.SP, cpu.get_reg16(R16.HL)) - cpu.state.cycles += 8 def pretty(self) -> str: return "LD SP, HL" @@ -274,11 +345,14 @@ class LD_SP_HL(Insn): class PUSH_RR(Insn): rr: R16 + @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)) - cpu.state.cycles += 16 def pretty(self) -> str: return f"PUSH {self.rr.value}" @@ -288,11 +362,14 @@ class PUSH_RR(Insn): class POP_RR(Insn): rr: R16 + @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) - cpu.state.cycles += 12 def pretty(self) -> str: return f"POP {self.rr.value}" @@ -302,11 +379,14 @@ class POP_RR(Insn): class ADD_A_R(Insn): r: 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) - cpu.state.cycles += 4 def pretty(self) -> str: return f"ADD A, {self.r.value}" @@ -316,11 +396,14 @@ class ADD_A_R(Insn): class ADD_A_N(Insn): n: int + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"ADD A, {hex(self.n)}" @@ -328,11 +411,14 @@ class ADD_A_N(Insn): @dataclass class ADD_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"ADD A, (HL)" @@ -342,11 +428,14 @@ class ADD_A_HL(Insn): class ADC_A_R(Insn): r: 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) - cpu.state.cycles += 4 def pretty(self) -> str: return f"ADC A, {self.r.value}" @@ -356,11 +445,14 @@ class ADC_A_R(Insn): class ADC_A_N(Insn): n: int + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"ADC A, {hex(self.n)}" @@ -368,11 +460,14 @@ class ADC_A_N(Insn): @dataclass class ADC_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"ADC A, (HL)" @@ -382,11 +477,14 @@ class ADC_A_HL(Insn): class SUB_A_R(Insn): r: 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) - cpu.state.cycles += 4 def pretty(self) -> str: return f"SUB A, {self.r.value}" @@ -396,11 +494,14 @@ class SUB_A_R(Insn): class SUB_A_N(Insn): n: int + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SUB A, {hex(self.n)}" @@ -408,11 +509,14 @@ class SUB_A_N(Insn): @dataclass class SUB_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "SUB A, (HL)" @@ -422,11 +526,14 @@ class SUB_A_HL(Insn): class SBC_A_R(Insn): r: 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) - cpu.state.cycles += 4 def pretty(self) -> str: return f"SBC A, {self.r.value}" @@ -436,11 +543,14 @@ class SBC_A_R(Insn): class SBC_A_N(Insn): n: int + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SBC A, {hex(self.n)}" @@ -448,11 +558,14 @@ class SBC_A_N(Insn): @dataclass class SBC_A_HL(Insn): + @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) - cpu.state.cycles += 8 def pretty(self) -> str: return "SBC A, (HL)" @@ -462,11 +575,14 @@ class SBC_A_HL(Insn): class AND_A_R(Insn): r: 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 - cpu.state.cycles += 4 def pretty(self) -> str: return f"AND A, {self.r.value}" @@ -476,11 +592,14 @@ class AND_A_R(Insn): class AND_A_N(Insn): n: int + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"AND A, {hex(self.n)}" @@ -488,11 +607,14 @@ class AND_A_N(Insn): @dataclass class AND_A_HL(Insn): + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return "AND A, (HL)" @@ -502,11 +624,14 @@ class AND_A_HL(Insn): class XOR_A_R(Insn): r: 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 - cpu.state.cycles += 4 def pretty(self) -> str: return f"XOR A, {self.r.value}" @@ -516,11 +641,14 @@ class XOR_A_R(Insn): class XOR_A_N(Insn): n: int + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"XOR A, {hex(self.n)}" @@ -528,11 +656,14 @@ class XOR_A_N(Insn): @dataclass class XOR_A_HL(Insn): + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return "XOR A, (HL)" @@ -542,11 +673,14 @@ class XOR_A_HL(Insn): class OR_A_R(Insn): r: 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 - cpu.state.cycles += 4 def pretty(self) -> str: return f"OR A, {self.r.value}" @@ -556,11 +690,14 @@ class OR_A_R(Insn): class OR_A_N(Insn): n: int + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"OR A, {hex(self.n)}" @@ -568,11 +705,14 @@ class OR_A_N(Insn): @dataclass class OR_A_HL(Insn): + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return "OR A, (HL)" @@ -582,9 +722,12 @@ class OR_A_HL(Insn): class CP_A_R(Insn): r: 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 - cpu.state.cycles += 4 def pretty(self) -> str: return f"CP A, {self.r.value}" @@ -594,9 +737,12 @@ class CP_A_R(Insn): class CP_A_N(Insn): n: int + @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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"CP A, {hex(self.n)}" @@ -604,11 +750,14 @@ class CP_A_N(Insn): @dataclass class CP_A_HL(Insn): + @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 ) - cpu.state.cycles += 8 def pretty(self) -> str: return "CP A, (HL)" @@ -618,9 +767,12 @@ class CP_A_HL(Insn): class INC_R(Insn): r: R8 + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(self.r, cpu.get_reg8(self.r) + 1) - cpu.state.cycles += 4 def pretty(self) -> str: return f"INC {self.r.value}" @@ -630,10 +782,13 @@ class INC_R(Insn): class INC_HL(Insn): r: R8 + @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) - cpu.state.cycles += 12 def pretty(self) -> str: return "INC (HL)" @@ -643,9 +798,12 @@ class INC_HL(Insn): class DEC_R(Insn): r: R8 + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(self.r, cpu.get_reg8(self.r) - 1) - cpu.state.cycles += 4 def pretty(self) -> str: return f"DEC {self.r.value}" @@ -655,10 +813,13 @@ class DEC_R(Insn): class DEC_HL(Insn): r: R8 + @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) - cpu.state.cycles += 12 def pretty(self) -> str: return "DEC (HL)" @@ -666,9 +827,12 @@ class DEC_HL(Insn): @dataclass class CPL(Insn): + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.set_reg8(R8.A, cpu.get_reg8(R8.A) ^ 0xFF) - cpu.state.cycles += 4 def pretty(self) -> str: return "CPL" @@ -678,11 +842,14 @@ class CPL(Insn): class ADD_HL_RR(Insn): rr: 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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"ADD HL, {self.rr.value}" @@ -692,9 +859,12 @@ class ADD_HL_RR(Insn): class INC_RR(Insn): rr: R16 + @staticmethod + def cycles() -> int: + return 8 + def exec(self, cpu: CPU) -> None: cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) + 1) - cpu.state.cycles += 8 def pretty(self) -> str: return f"INC {self.rr.value}" @@ -704,9 +874,12 @@ class INC_RR(Insn): class DEC_RR(Insn): rr: R16 + @staticmethod + def cycles() -> int: + return 8 + def exec(self, cpu: CPU) -> None: cpu.set_reg16(self.rr, cpu.get_reg16(self.rr) - 1) - cpu.state.cycles += 8 def pretty(self) -> str: return f"DEC {self.rr.value}" @@ -716,11 +889,14 @@ class DEC_RR(Insn): class ADD_SP_DD(Insn): dd: int + @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) - cpu.state.cycles += 16 def pretty(self) -> str: return f"ADD SP, {self.dd}" @@ -730,11 +906,14 @@ class ADD_SP_DD(Insn): class LD_HL_SP_DD(Insn): dd: int + @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) - cpu.state.cycles += 12 def pretty(self) -> str: return f"LD HL, SP + {self.dd}" @@ -742,11 +921,14 @@ class LD_HL_SP_DD(Insn): @dataclass class RLCA(Insn): + @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) - cpu.state.cycles += 4 def pretty(self) -> str: return "RLCA" @@ -754,12 +936,15 @@ class RLCA(Insn): @dataclass class RLA(Insn): + @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 - cpu.state.cycles += 4 def pretty(self) -> str: return "RLA" @@ -767,11 +952,14 @@ class RLA(Insn): @dataclass class RRCA(Insn): + @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)) - cpu.state.cycles += 4 def pretty(self) -> str: return "RRCA" @@ -779,12 +967,15 @@ class RRCA(Insn): @dataclass class RRA(Insn): + @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 - cpu.state.cycles += 4 def pretty(self) -> str: return "RRA" @@ -794,11 +985,14 @@ class RRA(Insn): class RLC_R(Insn): r: 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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"RLC {self.r.value}" @@ -806,10 +1000,13 @@ class RLC_R(Insn): @dataclass class RLC_HL(Insn): + @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 - cpu.state.cycles += 16 def pretty(self) -> str: return f"RLC (HL)" @@ -819,12 +1016,15 @@ class RLC_HL(Insn): class RL_R(Insn): r: 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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"RL {self.r.value}" @@ -832,11 +1032,14 @@ class RL_R(Insn): @dataclass class RL_HL(Insn): + @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 - cpu.state.cycles += 16 def pretty(self) -> str: return "RL (HL)" @@ -846,11 +1049,14 @@ class RL_HL(Insn): class RRC_R(Insn): r: 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)) - cpu.state.cycles += 8 def pretty(self) -> str: return f"RRC {self.r.value}" @@ -858,10 +1064,13 @@ class RRC_R(Insn): @dataclass class RRC_HL(Insn): + @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) - cpu.state.cycles += 16 def pretty(self) -> str: return "RRC (HL)" @@ -871,12 +1080,15 @@ class RRC_HL(Insn): class RR_R(Insn): r: 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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"RR {self.r.value}" @@ -884,11 +1096,14 @@ class RR_R(Insn): @dataclass class RR_HL(Insn): + @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 - cpu.state.cycles += 16 def pretty(self) -> str: return "RR (HL)" @@ -898,11 +1113,14 @@ class RR_HL(Insn): class SLA_R(Insn): r: 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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SLA {self.r.value}" @@ -910,10 +1128,13 @@ class SLA_R(Insn): @dataclass class SLA_HL(Insn): + @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 - cpu.state.cycles += 16 def pretty(self) -> str: return "SLA (HL)" @@ -923,11 +1144,14 @@ class SLA_HL(Insn): class SWAP_R(Insn): r: 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 - cpu.state.cycles += 8 def pretty(self) -> str: return f"SWAP {self.r.value}" @@ -935,10 +1159,13 @@ class SWAP_R(Insn): @dataclass class SWAP_HL(Insn): + @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 - cpu.state.cycles += 16 def pretty(self) -> str: return "SWAP (HL)" @@ -948,11 +1175,14 @@ class SWAP_HL(Insn): class SRA_R(Insn): r: 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))) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SRA {self.r.value}" @@ -960,10 +1190,13 @@ class SRA_R(Insn): @dataclass class SRA_HL(Insn): + @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)) - cpu.state.cycles += 16 def pretty(self) -> str: return "SRA (HL)" @@ -973,11 +1206,14 @@ class SRA_HL(Insn): class SRL_R(Insn): r: 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) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SRL {self.r.value}" @@ -985,10 +1221,13 @@ class SRL_R(Insn): @dataclass class SRL_HL(Insn): + @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.state.cycles += 16 def pretty(self) -> str: return "SRL (HL)" @@ -999,9 +1238,12 @@ class SET_N_R(Insn): n: int r: 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)) - cpu.state.cycles += 8 def pretty(self) -> str: return f"SET {self.n}, {self.r.value}" @@ -1011,10 +1253,13 @@ class SET_N_R(Insn): class SET_N_HL(Insn): n: int + @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)) - cpu.state.cycles += 16 def pretty(self) -> str: return f"SET {self.n}, (HL)" @@ -1025,9 +1270,12 @@ class RES_N_R(Insn): n: int r: 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)) - cpu.state.cycles += 8 def pretty(self) -> str: return f"RES {self.n}, (HL)" @@ -1037,10 +1285,13 @@ class RES_N_R(Insn): class RES_N_HL(Insn): n: int + @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)) - cpu.state.cycles += 16 def pretty(self) -> str: return f"RES {self.n}, (HL)" @@ -1048,9 +1299,12 @@ class RES_N_HL(Insn): @dataclass class CCF(Insn): + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.state.carry = cpu.state.carry ^ 1 - cpu.state.cycles += 4 def pretty(self) -> str: return "CCF" @@ -1058,9 +1312,12 @@ class CCF(Insn): @dataclass class SCF(Insn): + @staticmethod + def cycles() -> int: + return 4 + def exec(self, cpu: CPU) -> None: cpu.state.carry = 1 - cpu.state.cycles += 4 def pretty(self) -> str: return "SCF" @@ -1068,6 +1325,10 @@ class SCF(Insn): @dataclass class UNUSED(Insn): + @staticmethod + def cycles() -> int: + return 0 + def exec(self, cpu: CPU) -> None: pass diff --git a/gbso/cpu/state.py b/gbso/cpu/state.py index bd8f69c..7917850 100644 --- a/gbso/cpu/state.py +++ b/gbso/cpu/state.py @@ -8,7 +8,6 @@ from gbso.cpu.regs import R8 @dataclass class CPUState: carry: int = 0 - cycles: int = 0 sp: int = 0 reg8: Dict[R8, int] = field(default_factory=lambda: defaultdict(lambda: 0)) memory: Dict[int, int] = field(default_factory=lambda: defaultdict(lambda: 0)) diff --git a/gbso/program/program.py b/gbso/program/program.py index 5b07d0c..0b39b1b 100644 --- a/gbso/program/program.py +++ b/gbso/program/program.py @@ -1,23 +1,21 @@ from dataclasses import dataclass -from typing import List, Optional, Union +from typing import List, Optional from gbso.cpu.cpu import CPU -from gbso.cpu.regs import R8 from gbso.cpu.state import CPUState from gbso.cpu.insn import Insn -# TODO: Support 16-bit memory/register outputs -Output = Union[R8, int] - @dataclass class Program: insns: List[Insn] - outputs: List[Output] def execute(self, init_state: Optional[CPUState] = None) -> CPU: cpu = CPU(state=init_state) for insn in self.insns: insn.exec(cpu) return cpu + + def perf(self) -> int: + return sum([insn.cycles() for insn in self.insns]) diff --git a/gbso/program/test_case.py b/gbso/program/test_case.py index 01ee6de..0f391ee 100644 --- a/gbso/program/test_case.py +++ b/gbso/program/test_case.py @@ -1,28 +1,39 @@ from dataclasses import dataclass +from typing import List, Union + +from gbso.cpu.cpu import CPU from gbso.cpu.regs import R8 from gbso.program.program import Program - from gbso.cpu.state import CPUState +# TODO: Support 16-bit memory/register outputs +Output = Union[R8, int] + + @dataclass class TestCase: __test__ = False state: CPUState -def eq_on_testcase(p: Program, q: Program, case: TestCase) -> int: +# TODO: Allow p_cpu to be computed AOT +# TODO: Add penalty for undefined behavior (uninitialized register/memory reads) +def eq_on_testcase( + p: Program, q: Program, case: TestCase, outputs: List[Output] +) -> int: p_cpu = p.execute(case.state) q_cpu = q.execute(case.state) - delta = 0 - for o in p.outputs: - if type(o) == R8: - delta += eq_8bit(p_cpu.state.reg8[o], q_cpu.state.reg8[o]) - elif type(o) == int: - delta += eq_8bit(p_cpu.state.memory[o], q_cpu.state.memory[o]) - else: - raise TypeError(f"unknown output type {type(o)}") - # TODO: Add penalty for undefined behavior (uninitialized register/memory reads) + return sum([eq_on_output(o, p_cpu, q_cpu) for o in outputs]) + + +def eq_on_output(o: Output, p_cpu: CPU, q_cpu: CPU) -> int: + if type(o) == R8: + delta = eq_8bit(p_cpu.state.reg8[o], q_cpu.state.reg8[o]) + elif type(o) == int: + delta = eq_8bit(p_cpu.state.memory[o], q_cpu.state.memory[o]) + else: + raise TypeError(f"unknown output type {type(o)}") return delta diff --git a/tests/insn/test_alu16.py b/tests/insn/test_alu16.py index 15e9a0b..303b15d 100644 --- a/tests/insn/test_alu16.py +++ b/tests/insn/test_alu16.py @@ -13,14 +13,12 @@ def test_add_hl_rr(rr): assert cpu.get_reg16(R16.HL) == 0xBE01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 cpu.set_reg16(rr, 0xFFFF - 0xBE01 + 1) ADD_HL_RR(rr).exec(cpu) assert cpu.get_reg16(R16.HL) == 0 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 @pytest.mark.parametrize("rr", set(R16) - {R16.AF}) @@ -31,7 +29,6 @@ def test_inc_rr(rr): INC_RR(rr).exec(cpu) assert cpu.get_reg16(rr) == 0xABCE - assert cpu.state.cycles == 8 @pytest.mark.parametrize("rr", set(R16) - {R16.AF}) @@ -42,7 +39,6 @@ def test_dec_rr(rr): DEC_RR(rr).exec(cpu) assert cpu.get_reg16(rr) == 0xABCC - assert cpu.state.cycles == 8 def test_add_sp_dd(): @@ -53,19 +49,16 @@ def test_add_sp_dd(): assert cpu.get_reg16(R16.SP) == 0xFFFE assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 ADD_SP_DD(2).exec(cpu) assert cpu.get_reg16(R16.SP) == 0 assert cpu.state.carry == 1 - assert cpu.state.cycles == 32 ADD_SP_DD(-1).exec(cpu) assert cpu.get_reg16(R16.SP) == 0xFFFF assert cpu.state.carry == 1 - assert cpu.state.cycles == 48 def test_ld_hl_sp_dd(): @@ -76,18 +69,15 @@ def test_ld_hl_sp_dd(): assert cpu.get_reg16(R16.HL) == 0 assert cpu.state.carry == 1 - assert cpu.state.cycles == 12 cpu.set_reg16(R16.SP, 0) LD_HL_SP_DD(-1).exec(cpu) assert cpu.get_reg16(R16.HL) == 0xFFFF assert cpu.state.carry == 1 - assert cpu.state.cycles == 24 cpu.set_reg16(R16.SP, 0xFFFF) LD_HL_SP_DD(-2).exec(cpu) assert cpu.get_reg16(R16.HL) == 0xFFFD assert cpu.state.carry == 0 - assert cpu.state.cycles == 36 diff --git a/tests/insn/test_alu8.py b/tests/insn/test_alu8.py index 717e33e..af6bde8 100644 --- a/tests/insn/test_alu8.py +++ b/tests/insn/test_alu8.py @@ -12,14 +12,12 @@ def test_add_a_r(r): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 cpu.set_reg8(r, 0x81) ADD_A_R(r).exec(cpu) assert cpu.get_reg8(R8.A) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("n", n8()) @@ -31,7 +29,6 @@ def test_add_a_n(n): assert cpu.get_reg8(R8.A) == (0x7F + n) & 0xFF assert cpu.state.carry == (1 if n >= 0x81 else 0) - assert cpu.state.cycles == 8 def test_add_a_hl(): @@ -43,14 +40,12 @@ def test_add_a_hl(): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 cpu.set_mem8(0x1234, 0x81) ADD_A_HL().exec(cpu) assert cpu.get_reg8(R8.A) == 0 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 @pytest.mark.parametrize("r", set(R8) - {R8.A}) @@ -62,21 +57,18 @@ def test_adc_a_r(r): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 cpu.set_reg8(r, 0x81) ADC_A_R(r).exec(cpu) assert cpu.get_reg8(R8.A) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 cpu.set_reg8(r, 0x00) ADC_A_R(r).exec(cpu) assert cpu.get_reg8(R8.A) == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 12 @pytest.mark.parametrize("n", n8()) @@ -88,7 +80,6 @@ def test_adc_a_n(n): assert cpu.get_reg8(R8.A) == (0x7F + n) & 0xFF assert cpu.state.carry == (1 if n >= 0x81 else 0) - assert cpu.state.cycles == 8 def test_adc_a_hl(): @@ -100,21 +91,18 @@ def test_adc_a_hl(): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 cpu.hl = 0x81 ADC_A_HL().exec(cpu) assert cpu.get_reg8(R8.A) == 0 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 cpu.hl = 0x00 ADC_A_HL().exec(cpu) assert cpu.get_reg8(R8.A) == 1 assert cpu.state.carry == 0 - assert cpu.state.cycles == 24 # TODO: SUB_A_R, SUB_A_N, SUB_A_HL, SBC_A_R, SBC_A_N, SBC_A_HL @@ -130,7 +118,6 @@ def test_and_a_r(r): assert cpu.get_reg8(R8.A) == 0x12 assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 @pytest.mark.parametrize("n", n8()) @@ -142,7 +129,6 @@ def test_and_a_n(n): assert cpu.get_reg8(R8.A) == 0x12 & n assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_and_a_hl(): @@ -156,7 +142,6 @@ def test_and_a_hl(): assert cpu.get_reg8(R8.A) == 0x12 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", set(R8) - {R8.A}) @@ -169,7 +154,6 @@ def test_xor_a_r(r): assert cpu.get_reg8(R8.A) == 0x6D assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 @pytest.mark.parametrize("n", n8()) @@ -181,7 +165,6 @@ def test_xor_a_n(n): assert cpu.get_reg8(R8.A) == 0x12 ^ n assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_xor_a_hl(): @@ -195,7 +178,6 @@ def test_xor_a_hl(): assert cpu.get_reg8(R8.A) == 0x6D assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", set(R8) - {R8.A}) @@ -208,7 +190,6 @@ def test_or_a_r(r): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 @pytest.mark.parametrize("n", n8()) @@ -220,7 +201,6 @@ def test_or_a_n(n): assert cpu.get_reg8(R8.A) == 0x12 | n assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_or_a_hl(): @@ -234,7 +214,6 @@ def test_or_a_hl(): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", set(R8) - {R8.A}) @@ -247,14 +226,12 @@ def test_cp_a_r(r): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 4 cpu.set_reg8(r, 0x80) CP_A_R(r).exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("n", n8()) @@ -266,7 +243,6 @@ def test_cp_a_n(n): assert cpu.get_reg8(R8.A) == 0x12 assert cpu.state.carry == (1 if 0x12 < n else 0) - assert cpu.state.cycles == 8 def test_cp_a_hl(): @@ -280,7 +256,6 @@ def test_cp_a_hl(): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 cpu.set_mem8(0x1234, 0x80) @@ -288,7 +263,6 @@ def test_cp_a_hl(): assert cpu.get_reg8(R8.A) == 0x7F assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 @pytest.mark.parametrize("r,n", [(r, n) for r in R8 for n in n8()]) @@ -299,7 +273,6 @@ def test_inc_r(r, n): INC_R(r).exec(cpu) assert cpu.get_reg8(r) == (n + 1) & 0xFF - assert cpu.state.cycles == 4 @pytest.mark.parametrize("n", n8()) @@ -311,7 +284,6 @@ def test_inc_hl(n): INC_HL(n).exec(cpu) assert cpu.hl == (n + 1) & 0xFF - assert cpu.state.cycles == 12 @pytest.mark.parametrize("r,n", [(r, n) for r in R8 for n in n8()]) @@ -322,7 +294,6 @@ def test_dec_r(r, n): DEC_R(r).exec(cpu) assert cpu.get_reg8(r) == (n - 1) & 0xFF - assert cpu.state.cycles == 4 @pytest.mark.parametrize("n", n8()) @@ -334,7 +305,6 @@ def test_dec_hl(n): DEC_HL(n).exec(cpu) assert cpu.hl == (n - 1) & 0xFF - assert cpu.state.cycles == 12 # TODO: Test DAA after implementing it @@ -348,4 +318,3 @@ def test_cpl(n): CPL().exec(cpu) assert cpu.get_reg8(R8.A) == n ^ 0xFF - assert cpu.state.cycles == 4 diff --git a/tests/insn/test_bit.py b/tests/insn/test_bit.py index dfc64b0..050b0b3 100644 --- a/tests/insn/test_bit.py +++ b/tests/insn/test_bit.py @@ -10,7 +10,6 @@ def test_set_n_r(n, r): SET_N_R(n, r).exec(cpu) assert cpu.get_reg8(r) == 1 << n - assert cpu.state.cycles == 8 @pytest.mark.parametrize("n", range(8)) @@ -21,7 +20,6 @@ def test_set_n_hl(n): SET_N_HL(n).exec(cpu) assert cpu.hl == 1 << n - assert cpu.state.cycles == 16 @pytest.mark.parametrize("n,r", [(n, r) for n in range(8) for r in R8]) @@ -32,7 +30,6 @@ def test_res_n_r(n, r): RES_N_R(n, r).exec(cpu) assert cpu.get_reg8(r) == 0xFF - (1 << n) - assert cpu.state.cycles == 8 @pytest.mark.parametrize("n", range(8)) @@ -44,4 +41,3 @@ def test_res_n_hl(n): RES_N_HL(n).exec(cpu) assert cpu.hl == 0xFF - (1 << n) - assert cpu.state.cycles == 16 diff --git a/tests/insn/test_cpu.py b/tests/insn/test_cpu.py index acab9c7..75530be 100644 --- a/tests/insn/test_cpu.py +++ b/tests/insn/test_cpu.py @@ -7,12 +7,10 @@ def test_ccf(): CCF().exec(cpu) assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 CCF().exec(cpu) assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_scf(): @@ -21,4 +19,3 @@ def test_scf(): SCF().exec(cpu) assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 diff --git a/tests/insn/test_loads16.py b/tests/insn/test_loads16.py index 71f290a..4f650a5 100644 --- a/tests/insn/test_loads16.py +++ b/tests/insn/test_loads16.py @@ -10,7 +10,6 @@ def test_ld_rr_nn(rr): LD_RR_NN(rr, 0x1234).exec(cpu) assert cpu.get_reg16(rr) == 0x1234 - assert cpu.state.cycles == 12 def test_ld_nn_sp(): @@ -20,7 +19,6 @@ def test_ld_nn_sp(): LD_NN_SP(0x1234).exec(cpu) assert cpu.get_mem16(0x1234) == 0xABCD - assert cpu.state.cycles == 20 def test_ld_sp_hl(): @@ -30,7 +28,6 @@ def test_ld_sp_hl(): LD_SP_HL().exec(cpu) assert cpu.get_reg16(R16.SP) == 0x1234 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("rr", set(R16) - {R16.AF, R16.SP}) @@ -43,7 +40,6 @@ def test_push_rr(rr): assert cpu.get_reg16(R16.SP) == 0xFFFD assert cpu.get_mem16(0xFFFD) == 0x1234 - assert cpu.state.cycles == 16 @pytest.mark.parametrize("rr", set(R16) - {R16.AF, R16.SP}) @@ -56,4 +52,3 @@ def test_pop_rr(rr): assert cpu.get_reg16(R16.SP) == 0xFFFF assert cpu.get_reg16(rr) == 0x1234 - assert cpu.state.cycles == 12 diff --git a/tests/insn/test_loads8.py b/tests/insn/test_loads8.py index d41991e..9425a6f 100644 --- a/tests/insn/test_loads8.py +++ b/tests/insn/test_loads8.py @@ -10,7 +10,6 @@ def test_ld_r_r(dst, src): LD_R_R(dst, src).exec(cpu) assert cpu.get_reg8(src) == 0x7F - assert cpu.state.cycles == 4 @pytest.mark.parametrize("r,imm", [(r, imm) for r in R8 for imm in n8()]) @@ -19,7 +18,6 @@ def test_ld_r_n8(r, imm): LD_R_N8(r, 0x7F).exec(cpu) assert cpu.get_reg8(r) == 0x7F - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", R8) @@ -30,7 +28,6 @@ def test_ld_r_hl(r): LD_R_HL(r).exec(cpu) assert cpu.get_reg8(r) == 0x7F - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", R8) @@ -48,8 +45,6 @@ def test_ld_hl_r(r): else: assert cpu.hl == 0x7F - assert cpu.state.cycles == 8 - @pytest.mark.parametrize("imm", n8()) def test_ld_hl_n8(imm): @@ -59,7 +54,6 @@ def test_ld_hl_n8(imm): LD_HL_N(imm).exec(cpu) assert cpu.hl == imm - assert cpu.state.cycles == 12 def test_ld_a_bc(): @@ -70,7 +64,6 @@ def test_ld_a_bc(): LD_A_BC().exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 8 def test_ld_a_de(): @@ -81,7 +74,6 @@ def test_ld_a_de(): LD_A_DE().exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 8 # @pytest.mark.parametrize("nn", n16()) @@ -92,7 +84,6 @@ def test_ld_a_nn(nn=0x1234): LD_A_NN(nn).exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 16 def test_ld_bc_a(): @@ -103,7 +94,6 @@ def test_ld_bc_a(): LD_BC_A().exec(cpu) assert cpu.get_mem8(0x1234) == 0x7F - assert cpu.state.cycles == 8 def test_ld_de_a(): @@ -114,7 +104,6 @@ def test_ld_de_a(): LD_DE_A().exec(cpu) assert cpu.get_mem8(0x1234) == 0x7F - assert cpu.state.cycles == 8 # @pytest.mark.parametrize("nn", n16()) @@ -125,7 +114,6 @@ def test_ld_nn_a(nn=0x1234): LD_NN_A(nn).exec(cpu) assert cpu.get_mem8(nn) == 0x7F - assert cpu.state.cycles == 16 @pytest.mark.parametrize("n", n8()) @@ -136,7 +124,6 @@ def test_ld_a_ff_n(n): LD_A_FF_N(n).exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 12 @pytest.mark.parametrize("n", n8()) @@ -147,7 +134,6 @@ def test_ld_ff_n_a(n): LD_FF_N_A(n).exec(cpu) assert cpu.get_mem8(0xFF00 + n) == 0x7F - assert cpu.state.cycles == 12 def test_ld_a_ff_c(): @@ -158,7 +144,6 @@ def test_ld_a_ff_c(): LD_A_FF_C().exec(cpu) assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 8 def test_ld_ff_c_a(): @@ -169,7 +154,6 @@ def test_ld_ff_c_a(): LD_FF_C_A().exec(cpu) assert cpu.get_mem8(0xFF12) == 0x7F - assert cpu.state.cycles == 8 def test_ldi_hl_a(): @@ -181,7 +165,6 @@ def test_ldi_hl_a(): assert cpu.get_reg16(R16.HL) == 0x1235 assert cpu.get_mem8(0x1234) == 0x7F - assert cpu.state.cycles == 8 def test_ldi_a_hl(): @@ -193,7 +176,6 @@ def test_ldi_a_hl(): assert cpu.get_reg16(R16.HL) == 0x1235 assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 8 def test_ldd_hl_a(): @@ -205,7 +187,6 @@ def test_ldd_hl_a(): assert cpu.get_reg16(R16.HL) == 0x1233 assert cpu.get_mem8(0x1234) == 0x7F - assert cpu.state.cycles == 8 def test_ldd_a_hl(): @@ -217,4 +198,3 @@ def test_ldd_a_hl(): assert cpu.get_reg16(R16.HL) == 0x1233 assert cpu.get_reg8(R8.A) == 0x7F - assert cpu.state.cycles == 8 diff --git a/tests/insn/test_shift.py b/tests/insn/test_shift.py index 6361dcf..a70feda 100644 --- a/tests/insn/test_shift.py +++ b/tests/insn/test_shift.py @@ -11,13 +11,11 @@ def test_rlca(): assert cpu.get_reg8(R8.A) == 0x01 assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 RLCA().exec(cpu) assert cpu.get_reg8(R8.A) == 0x02 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_rla(): @@ -28,13 +26,11 @@ def test_rla(): assert cpu.get_reg8(R8.A) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 RLA().exec(cpu) assert cpu.get_reg8(R8.A) == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_rrca(): @@ -45,13 +41,11 @@ def test_rrca(): assert cpu.get_reg8(R8.A) == 0x80 assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 RRCA().exec(cpu) assert cpu.get_reg8(R8.A) == 0x40 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_rra(): @@ -62,13 +56,11 @@ def test_rra(): assert cpu.get_reg8(R8.A) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 4 RRA().exec(cpu) assert cpu.get_reg8(R8.A) == 0x80 assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 @pytest.mark.parametrize("r", R8) @@ -80,13 +72,11 @@ def test_rlc_r(r): assert cpu.get_reg8(r) == 0x01 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 RLC_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x02 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_rlc_hl(): @@ -97,13 +87,11 @@ def test_rlc_hl(): assert cpu.hl == 0x01 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 RLC_HL().exec(cpu) assert cpu.hl == 0x02 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -115,13 +103,11 @@ def test_rl_r(r): assert cpu.get_reg8(r) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 RL_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_rl_hl(): @@ -132,13 +118,11 @@ def test_rl_hl(): assert cpu.hl == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 RL_HL().exec(cpu) assert cpu.hl == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -150,13 +134,11 @@ def test_rrc_r(r): assert cpu.get_reg8(r) == 0x80 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 RRC_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x40 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_rrc_hl(): @@ -168,13 +150,11 @@ def test_rrc_hl(): assert cpu.hl == 0x80 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 RRC_HL().exec(cpu) assert cpu.hl == 0x40 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -186,13 +166,11 @@ def test_rr_r(r): assert cpu.get_reg8(r) == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 RR_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x80 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_rr_hl(): @@ -204,13 +182,11 @@ def test_rr_hl(): assert cpu.hl == 0x00 assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 RR_HL().exec(cpu) assert cpu.hl == 0x80 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -222,14 +198,12 @@ def test_sla_r(r): assert cpu.get_reg8(r) == 0xFE assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 cpu.set_reg8(r, 0x01) SLA_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x02 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_sla_hl(): @@ -241,14 +215,12 @@ def test_sla_hl(): assert cpu.hl == 0xFE assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 cpu.hl = 0x01 SLA_HL().exec(cpu) assert cpu.hl == 0x02 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -260,7 +232,6 @@ def test_swap_r(r): assert cpu.get_reg8(r) == 0xBA assert cpu.state.carry == 0 - assert cpu.state.cycles == 8 def test_swap_hl(): @@ -272,7 +243,6 @@ def test_swap_hl(): assert cpu.hl == 0xBA assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 @pytest.mark.parametrize("r", R8) @@ -284,14 +254,12 @@ def test_sra_r(r): assert cpu.get_reg8(r) == 0xFF assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 cpu.set_reg8(r, 0x02) SRA_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_sra_hl(): @@ -303,14 +271,12 @@ def test_sra_hl(): assert cpu.hl == 0xFF assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 cpu.hl = 0x02 SRA_HL().exec(cpu) assert cpu.hl == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32 @pytest.mark.parametrize("r", R8) @@ -322,14 +288,12 @@ def test_srl_r(r): assert cpu.get_reg8(r) == 0x7F assert cpu.state.carry == 1 - assert cpu.state.cycles == 8 cpu.set_reg8(r, 0x02) SRL_R(r).exec(cpu) assert cpu.get_reg8(r) == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 16 def test_srl_hl(): @@ -341,11 +305,9 @@ def test_srl_hl(): assert cpu.hl == 0x7F assert cpu.state.carry == 1 - assert cpu.state.cycles == 16 cpu.hl = 0x02 SRL_HL().exec(cpu) assert cpu.hl == 0x01 assert cpu.state.carry == 0 - assert cpu.state.cycles == 32