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(0xFF%02X), A\n" (int_of_char n); (* fixme *) inc_pc cpu 2; inc_cycles cpu 12 | '\xF0' -> printf " LDH \tA, (0xFF%02X)\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."