@ -1,8 +1,8 @@ | |||||
from abc import ABC, abstractmethod | from abc import ABC, abstractmethod | ||||
from dataclasses import dataclass | from dataclasses import dataclass | ||||
from gbso.cpu import CPU | |||||
from gbso.regs import R16, R8 | |||||
from gbso.cpu.cpu import CPU | |||||
from gbso.cpu.regs import R16, R8 | |||||
class Insn(ABC): | class Insn(ABC): |
@ -0,0 +1,14 @@ | |||||
from collections import defaultdict | |||||
from dataclasses import dataclass, field | |||||
from typing import Dict | |||||
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)) |
@ -1,4 +1,4 @@ | |||||
from gbso.program import Program | |||||
from gbso.program.program import Program | |||||
def optimize(prgm: Program) -> Program: | def optimize(prgm: Program) -> Program: | ||||
@ -1,19 +0,0 @@ | |||||
from dataclasses import dataclass | |||||
from typing import List, Optional, Set, Union | |||||
from gbso.cpu import CPU, CPUState | |||||
from gbso.insn import Insn | |||||
from gbso.regs import R8 | |||||
@dataclass | |||||
class Program: | |||||
outputs: Set[Union[R8, int]] | |||||
insns: List[Insn] | |||||
init_state: Optional[CPUState] = None | |||||
def execute(self) -> CPU: | |||||
cpu = CPU(state=self.init_state) | |||||
for insn in self.insns: | |||||
insn.exec(cpu) | |||||
return cpu |
@ -0,0 +1,23 @@ | |||||
from dataclasses import dataclass | |||||
from typing import List, Optional, Union | |||||
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 |
@ -0,0 +1,36 @@ | |||||
from dataclasses import dataclass | |||||
from gbso.cpu.regs import R8 | |||||
from gbso.program.program import Program | |||||
from gbso.cpu.state import CPUState | |||||
@dataclass | |||||
class TestCase: | |||||
__test__ = False | |||||
state: CPUState | |||||
def eq_on_testcase(p: Program, q: Program, case: TestCase) -> 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 delta | |||||
# Counts differing bits between two 8-bit values | |||||
def eq_8bit(x: int, y: int) -> int: | |||||
delta = 0 | |||||
for i in range(8): | |||||
mask = 1 << i | |||||
if x & mask != y & mask: | |||||
delta += 1 | |||||
return 0 |