From b2c7e7b947972a8478384ffce4d69c0041105c50 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Fri, 27 Feb 2015 22:24:26 +0100 Subject: [PATCH] Basic support for CPU opcodes. Support for 2 opcodes: nop and jump. These are the first opcodes encountered in Super Mario Land. --- src/cpu.ml | 68 +++++++++++++++++++++++++++++++++++++++++++---------- src/hexa.ml | 22 ++++++++--------- src/oboy.ml | 17 +++++++++++--- 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/cpu.ml b/src/cpu.ml index 3b16045..69cba2e 100644 --- a/src/cpu.ml +++ b/src/cpu.ml @@ -1,26 +1,68 @@ -(** http://bgb.bircd.org/pandocs.htm#cpuregistersandflags *) +open Printf + +(** http://bgb.bircd.org/pandocs.htm#cpuregistersandflags + http://gameboy.mongenel.com/dmg/lesson1.html *) type registers = { - a : char; (* accumulator *) - b : char; - c : char; - d : char; - e : char; - h : char; - l : char; + 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; - sp : int; (* stack pointer *) - pc : int; (* program counter *) + mutable sp : int; (* stack pointer *) + mutable pc : int; (* program counter *) } -type flags = { +(* type flags = { z : bool; (* zero *) n : bool; (* substraction *) h : bool; (* half-carry *) cy : bool; (* carry *) -} +} *) type t = { reg : registers; - flags : flags; + 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 read_2B b addr = + let low = Bytes.get b addr in + let high = Bytes.get b (addr + 1) in + (int_of_char high) * 256 + (int_of_char low) + +(** http://imrannazar.com/GameBoy-Z80-Opcode-Map *) +let run cpu (cartridge: Cartridge.t) = +(* Hexa.print_slice cartridge.full_rom cpu.reg.pc (cpu.reg.pc + 7) ~width:16; *) + match Bytes.get cartridge.full_rom cpu.reg.pc with + | '\x00' -> printf " nop\n"; inc_pc cpu 1; inc_cycles cpu 4 + | '\xC3' -> let addr = read_2B cartridge.full_rom (cpu.reg.pc + 1) in + printf " jp 0x%02x\n" addr; cpu.reg.pc <- addr; inc_cycles cpu 16 + | _ as x -> eprintf "OpCode %02X\n" (int_of_char x); failwith "Unimplemented opcode." diff --git a/src/hexa.ml b/src/hexa.ml index e176b6d..cd3ee88 100644 --- a/src/hexa.ml +++ b/src/hexa.ml @@ -1,14 +1,14 @@ open Printf -let print_bytes b ?(width=8) = +let rec print_slice ?(width=8) b start last = + if start < last then + let max = min (start + width - 1) last in + for i = start to max do + printf "%02X " (Bytes.get b i |> int_of_char) + done; + print_newline (); + print_slice ~width b (start + width) last + +let print_bytes ?(width=8) b width = let l = Bytes.length b in - let rec print_line b start last = - if start < last then - let max = min (start + width - 1) last in - for i = start to max do - printf "%02X " (Bytes.get b i |> int_of_char) - done; - print_newline (); - print_line b (start + width) last - in - print_line b 0 l + print_slice ~width b 0 l diff --git a/src/oboy.ml b/src/oboy.ml index 8313563..7bc667f 100644 --- a/src/oboy.ml +++ b/src/oboy.ml @@ -1,5 +1,9 @@ open Printf +let rec run (cpu: Cpu.t) (cartridge: Cartridge.t) = + Cpu.run cpu cartridge; + run cpu cartridge + (** Power up sequence http://bgb.bircd.org/pandocs.htm#powerupsequence *) let power_up cartridge = @@ -10,12 +14,19 @@ let power_up cartridge = print_endline "Valid ROM."; printf "Title: %s\n" cartridge.title; printf "ROM size: %iKB\n" cartridge.rom_size; - printf "RAM size: %iKB\n" cartridge.ram_size + printf "RAM size: %iKB\n" cartridge.ram_size; + + let cpu = Cpu.init_cpu in + run cpu cartridge let () = - if Array.length Sys.argv < 2 - then print_endline "Please specify a ROM."; + if Array.length Sys.argv < 2 then + begin + prerr_endline "Please specify a ROM."; + eprintf "Usage: %s path/to/rom\n" Sys.argv.(0); + exit 1; + end; let cartridge = Cartridge.read_cartridge Sys.argv.(1) in match cartridge with