Basic support for CPU opcodes.
Support for 2 opcodes: nop and jump. These are the first opcodes encountered in Super Mario Land.
This commit is contained in:
		
							parent
							
								
									fa09906bcb
								
							
						
					
					
						commit
						b2c7e7b947
					
				
					 3 changed files with 80 additions and 27 deletions
				
			
		
							
								
								
									
										68
									
								
								src/cpu.ml
									
										
									
									
									
								
							
							
						
						
									
										68
									
								
								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 = {
 | 
					type registers = {
 | 
				
			||||||
  a : char; (* accumulator *)
 | 
					  mutable a : char; (* accumulator *)
 | 
				
			||||||
  b : char;
 | 
					  mutable f : char; (* flags *)
 | 
				
			||||||
  c : char;
 | 
					  mutable b : char;
 | 
				
			||||||
  d : char;
 | 
					  mutable c : char;
 | 
				
			||||||
  e : char;
 | 
					  mutable d : char;
 | 
				
			||||||
  h : char;
 | 
					  mutable e : char;
 | 
				
			||||||
  l : char;
 | 
					  mutable h : char;
 | 
				
			||||||
 | 
					  mutable l : char;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sp : int; (* stack pointer *)
 | 
					  mutable sp : int; (* stack pointer *)
 | 
				
			||||||
  pc : int; (* program counter *)
 | 
					  mutable pc : int; (* program counter *)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type flags = {
 | 
					(* type flags = {
 | 
				
			||||||
  z  : bool; (* zero *)
 | 
					  z  : bool; (* zero *)
 | 
				
			||||||
  n  : bool; (* substraction *)
 | 
					  n  : bool; (* substraction *)
 | 
				
			||||||
  h  : bool; (* half-carry *)
 | 
					  h  : bool; (* half-carry *)
 | 
				
			||||||
  cy : bool; (* carry *)
 | 
					  cy : bool; (* carry *)
 | 
				
			||||||
}
 | 
					} *)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type t = {
 | 
					type t = {
 | 
				
			||||||
  reg : registers;
 | 
					  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."
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/hexa.ml
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/hexa.ml
									
										
									
									
									
								
							| 
						 | 
					@ -1,14 +1,14 @@
 | 
				
			||||||
open Printf
 | 
					open Printf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let print_bytes b ?(width=8) =
 | 
					let rec print_slice ?(width=8) b start last =
 | 
				
			||||||
  let l = Bytes.length b in
 | 
					 | 
				
			||||||
  let rec print_line b start last =
 | 
					 | 
				
			||||||
  if start < last then
 | 
					  if start < last then
 | 
				
			||||||
    let max = min (start + width - 1) last in
 | 
					    let max = min (start + width - 1) last in
 | 
				
			||||||
    for i = start to max do
 | 
					    for i = start to max do
 | 
				
			||||||
      printf "%02X " (Bytes.get b i |> int_of_char)
 | 
					      printf "%02X " (Bytes.get b i |> int_of_char)
 | 
				
			||||||
    done;
 | 
					    done;
 | 
				
			||||||
    print_newline ();
 | 
					    print_newline ();
 | 
				
			||||||
      print_line b (start + width) last
 | 
					    print_slice ~width b (start + width) last
 | 
				
			||||||
  in
 | 
					
 | 
				
			||||||
  print_line b 0 l
 | 
					let print_bytes ?(width=8) b width =
 | 
				
			||||||
 | 
					  let l = Bytes.length b in
 | 
				
			||||||
 | 
					  print_slice ~width b 0 l
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/oboy.ml
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								src/oboy.ml
									
										
									
									
									
								
							| 
						 | 
					@ -1,5 +1,9 @@
 | 
				
			||||||
open Printf
 | 
					open Printf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let rec run (cpu: Cpu.t) (cartridge: Cartridge.t) =
 | 
				
			||||||
 | 
					  Cpu.run cpu cartridge;
 | 
				
			||||||
 | 
					  run cpu cartridge
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(** Power up sequence
 | 
					(** Power up sequence
 | 
				
			||||||
    http://bgb.bircd.org/pandocs.htm#powerupsequence *)
 | 
					    http://bgb.bircd.org/pandocs.htm#powerupsequence *)
 | 
				
			||||||
let power_up cartridge =
 | 
					let power_up cartridge =
 | 
				
			||||||
| 
						 | 
					@ -10,12 +14,19 @@ let power_up cartridge =
 | 
				
			||||||
    print_endline "Valid ROM.";
 | 
					    print_endline "Valid ROM.";
 | 
				
			||||||
    printf "Title: %s\n" cartridge.title;
 | 
					    printf "Title: %s\n" cartridge.title;
 | 
				
			||||||
    printf "ROM size: %iKB\n" cartridge.rom_size;
 | 
					    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 () =
 | 
					let () =
 | 
				
			||||||
  if Array.length Sys.argv < 2
 | 
					  if Array.length Sys.argv < 2 then
 | 
				
			||||||
  then print_endline "Please specify a ROM.";
 | 
					  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
 | 
					  let cartridge = Cartridge.read_cartridge Sys.argv.(1) in
 | 
				
			||||||
  match cartridge with
 | 
					  match cartridge with
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue