oboy/src/cpu.ml

111 lines
2.7 KiB
OCaml

open Printf
(** http://bgb.bircd.org/pandocs.htm#cpuregistersandflags
http://gameboy.mongenel.com/dmg/lesson1.html *)
type registers = {
mutable a : char; (* accumulator *)
mutable f : char; (* flags *)
mutable b : char;
mutable c : char;
mutable d : char;
mutable e : char;
mutable h : char;
mutable l : char;
mutable sp : int; (* stack pointer *)
mutable pc : int; (* program counter *)
}
(* type flags = {
z : bool; (* zero *)
n : bool; (* substraction *)
h : bool; (* half-carry *)
cy : bool; (* carry *)
} *)
type t = {
reg : registers;
mutable cycles : int;
}
(** http://bgb.bircd.org/pandocs.htm#powerupsequence *)
let init_registers =
{
a = '\x00';
f = '\x00';
b = '\x00';
c = '\x00';
d = '\x00';
e = '\x00';
h = '\x00';
l = '\x00';
sp = 0xFFFE;
pc = 0x0100;
}
let init_cpu =
{ reg = init_registers; cycles = 0 }
let inc_pc cpu count =
cpu.reg.pc <- cpu.reg.pc + count
let inc_cycles cpu count =
cpu.cycles <- cpu.cycles + count
let merge_bytes low high =
(int_of_char high) * 256 + (int_of_char low)
let split_2B x =
let low = x mod 256 |> char_of_int in
let high = x / 256 |> char_of_int in
(high, low)
let read_2B b addr =
let low = Bytes.get b addr in
let high = Bytes.get b (addr + 1) in
merge_bytes low high
let inc_BC cpu =
let v = merge_bytes cpu.reg.c cpu.reg.b in
let low, high = split_2B (v + 1) in
cpu.reg.c <- low;
cpu.reg.b <- high
(** http://imrannazar.com/GameBoy-Z80-Opcode-Map *)
let run cpu (cartridge: Cartridge.t) =
let data = cartridge.full_rom in
let n = Bytes.get data (cpu.reg.pc + 1) in
let nn = Bytes.get data (cpu.reg.pc + 2) in
(* Hexa.print_slice cartridge.full_rom cpu.reg.pc (cpu.reg.pc + 7); *)
match Bytes.get data cpu.reg.pc with
| '\x00' -> printf " NOP\n";
inc_pc cpu 1; inc_cycles cpu 4
| '\x03' -> printf " INC \tBC\n";
inc_BC cpu;
inc_pc cpu 1; inc_cycles cpu 8
| '\x3E' -> printf " LD \tA, 0x%02X\n" (int_of_char n);
cpu.reg.a <- n;
inc_pc cpu 2; inc_cycles cpu 8
| '\xAF' -> printf " XOR \tA, A\n";
let int_A = int_of_char cpu.reg.a in
cpu.reg.a <- char_of_int @@ int_A lxor int_A;
inc_pc cpu 1; inc_cycles cpu 4
| '\xC3' -> let addr = read_2B data (cpu.reg.pc + 1) in
printf " JP \t0x%04X\n" addr;
cpu.reg.pc <- addr; inc_cycles cpu 16
| '\xE0' -> printf " LDH \t(0x%02X), A\n" (int_of_char n);
(* fixme *)
inc_pc cpu 2; inc_cycles cpu 12
| '\xF3' -> printf " DI\n";
(* fixme *)
inc_pc cpu 1; inc_cycles cpu 4
| _ as x -> eprintf "opcode %02X\n" (int_of_char x); failwith "Unimplemented opcode."