diff --git a/README.md b/README.md index 53d447e..3be25e9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ # gbso An implementation of the stochastic superoptimization algorithm [STOKE](docs/asplos13.pdf) for the Sharp LR35902 (also known as GB-Z80). + +## Setup + +Make sure you have [Poetry](https://python-poetry.org/) and Python 3.9+ installed. Then run: + +``` +$ poetry install +``` + +## Usage + +Input programs are specified as a list of CPU instructions. For a list of instructions available to the processor, take a look at [insn.py](/gbso/cpu/insn.py) or a [standard reference](https://gbdev.io/pandocs/CPU_Instruction_Set.html). + +Once you have the program specified, call `gbso.optimize.optimize` on the program. A superoptimized, behaviorally equivalent program will be returned. Additional parameters are available to the optimization function to control search. + +For a comprehensive example, see [ex.py](/ex.py). diff --git a/ex.py b/ex.py index 3b4d937..d2d4476 100644 --- a/ex.py +++ b/ex.py @@ -1,8 +1,16 @@ from gbso.cpu.insn import * from gbso.cpu.regs import R8, R16 -from gbso.optimize import optimize +from gbso.optimize import ( + DEFAULT_PROB_INSN, + DEFAULT_PROB_INSN_UNUSED, + DEFAULT_PROB_OPCODE, + DEFAULT_PROB_OPERAND, + DEFAULT_PROB_SWAP, + optimize, +) from gbso.program.program import Program +from gbso.program.mutate import mutate_program rLCDC = 0xFF40 rIE = 0xFFFF @@ -10,8 +18,8 @@ rIE = 0xFFFF IEF_VBLANK = 1 << 0 prgm = Program( - outputs=set([R8.A]), insns=[ + LD_R_N8(R8.A, 12), LD_RR_NN(R16.HL, rLCDC), RES_N_HL(7), RES_N_HL(2), @@ -20,6 +28,16 @@ prgm = Program( ], ) -prgm_opt = optimize(prgm) -for insn in prgm_opt.insns: - print(insn.pretty()) +optimized_prgm = optimize(prgm) +optimized_prgm.display() + +for _ in range(10): + prgm = mutate_program( + prgm, + prob_opcode=DEFAULT_PROB_OPCODE, + prob_operand=DEFAULT_PROB_OPERAND, + prob_swap=DEFAULT_PROB_SWAP, + prob_insn=DEFAULT_PROB_INSN, + prob_insn_unused=DEFAULT_PROB_INSN_UNUSED, + ) + prgm.display() diff --git a/gbso/program/mutate.py b/gbso/program/mutate.py index d59b63c..0b87bc1 100644 --- a/gbso/program/mutate.py +++ b/gbso/program/mutate.py @@ -3,7 +3,7 @@ from gbso.cpu.regs import R16, R16_WITHOUT_SP, R8 from random import choice, randint, random, randrange from typing import List, Tuple, Type, TypeVar, Union -from gbso.cpu.insn import ALL_INSN_CLASSES, Insn, Operand, UNUSED +from gbso.cpu.insn import ALL_INSN_CLASSES, Insn, Operand, UNUSED, get_signature_class from gbso.program.program import Program @@ -31,20 +31,30 @@ def mutate_program( ] ) new_prgm = prgm + print("======") if mutation == Mutation.OPCODE: + print("OPCODE") new_prgm = mutate_opcode(prgm) elif mutation == Mutation.OPERAND: + print("OPERAND") new_prgm = mutate_operand(prgm) elif mutation == Mutation.SWAP: + print("SWAP") new_prgm = mutate_swap(prgm) elif mutation == Mutation.INSTRUCTION: + print("INSN") new_prgm = mutate_insn(prgm, prob_insn_unused) return new_prgm -# TODO: Implement def mutate_opcode(prgm: Program) -> Program: - return prgm + i = randrange(len(prgm.insns)) + next_insn_cls = choice(get_signature_class(prgm.insns[i])) + + insns = prgm.insns.copy() + insns[i] = next_insn_cls(*vars(prgm.insns[i]).values()) + + return Program(insns=insns) # TODO: Implement diff --git a/gbso/program/program.py b/gbso/program/program.py index 0b39b1b..588145a 100644 --- a/gbso/program/program.py +++ b/gbso/program/program.py @@ -19,3 +19,8 @@ class Program: def perf(self) -> int: return sum([insn.cycles() for insn in self.insns]) + + def display(self) -> None: + print("=" * 10) + for insn in self.insns: + print(insn.pretty())