Add interrupt handlers in cpu

This commit is contained in:
Fabien Freling 2016-02-29 23:07:42 +01:00
parent 4df4aea484
commit 033f63ec42
2 changed files with 69 additions and 12 deletions

View file

@ -130,6 +130,11 @@ let read_pc_2bytes cpu mem =
inc_pc cpu 2; inc_pc cpu 2;
word word
(*************************************************
*
* Stack manipulation
*
************************************************)
let pop_stack cpu mem = let pop_stack cpu mem =
let low = Memory.get mem cpu.reg.sp in let low = Memory.get mem cpu.reg.sp in
cpu.reg.sp <- (cpu.reg.sp + 1) mod 0xFFFF; cpu.reg.sp <- (cpu.reg.sp + 1) mod 0xFFFF;
@ -137,11 +142,23 @@ let pop_stack cpu mem =
cpu.reg.sp <- (cpu.reg.sp + 1) mod 0xFFFF; cpu.reg.sp <- (cpu.reg.sp + 1) mod 0xFFFF;
merge_bytes low high merge_bytes low high
let push_pc_stack cpu mem =
let (high, low) = split_2B cpu.reg.pc in
cpu.reg.sp <- pred cpu.reg.sp;
Memory.set mem cpu.reg.sp high;
cpu.reg.sp <- pred cpu.reg.sp;
Memory.set mem cpu.reg.sp low
(**
http://imrannazar.com/GameBoy-Z80-Opcode-Map
https://github.com/sinamas/gambatte/blob/master/libgambatte/src/cpu.cpp
*) (*************************************************
*
* CPU instructions
*
************************************************)
(** http://imrannazar.com/GameBoy-Z80-Opcode-Map
https://github.com/sinamas/gambatte/blob/master/libgambatte/src/cpu.cpp *)
let run cpu (mem: Memory.map) = let run cpu (mem: Memory.map) =
print_cpu_state cpu; print_cpu_state cpu;
let opcode = read_pc_byte cpu mem |> char_of_int in let opcode = read_pc_byte cpu mem |> char_of_int in
@ -294,7 +311,8 @@ let run cpu (mem: Memory.map) =
inst, 8 inst, 8
| '\xFB' -> let inst = sprintf "EI" in | '\xFB' -> let inst = sprintf "EI" in
(* enable interrupts, IME=1 *) (* enable interrupts *)
Interrupt.ime := true;
inst, 4 inst, 4
| x -> eprintf "opcode 0x%02X\n" (int_of_char x); | x -> eprintf "opcode 0x%02X\n" (int_of_char x);
@ -304,3 +322,41 @@ let run cpu (mem: Memory.map) =
in in
inc_cycles cpu cycles; inc_cycles cpu cycles;
inst, cycles inst, cycles
(*************************************************
*
* Interrupt handlers
*
************************************************)
let handle_interrupt cpu mem flag =
let int_vector = match flag with
| Interrupt.V_Blank -> 0x40
| Interrupt.LCD_Stat -> 0x48
| Interrupt.Timer -> 0x50
| Interrupt.Serial -> 0x58
| Interrupt.Joypad -> 0x60 in
(* TODO: reset IF flag *)
Interrupt.ime := false;
push_pc_stack cpu mem;
cpu.reg.pc <- int_vector
(* TODO: run cpu until RETI is called *)
let handle_interrupts cpu mem ie if_ =
if not !Interrupt.ime then
() (* Interrupt Master Enable flag set to false, nothing to do *)
else
begin
(* N.B.: flags are precomputed once but an interrupt could be requested
during that time *)
let interrupts = ie land if_ in
let flags = Interrupt.get_flags interrupts in
match flags with
| [] -> () (* No interrupt *)
| _ -> List.iter (fun x -> handle_interrupt cpu mem x) flags
end

View file

@ -6,15 +6,16 @@
* LICENSE file at the top level directory of this source tree. * LICENSE file at the top level directory of this source tree.
*) *)
(* let IME = ref false;; *) let ime = ref false;;
type t = type t =
| V_Blank | V_Blank
| LCD_Stat | LCD_Stat
| Timer | Timer
| Serial | Serial
| Joypad | Joypad
(** Return the list of interrupt flags sorted by priority. *)
let get_flags byte = let get_flags byte =
let nth_interrupt i = let nth_interrupt i =
@ -34,6 +35,6 @@ let get_flags byte =
get_flag byte (i + 1) (interrupt :: accu) get_flag byte (i + 1) (interrupt :: accu)
else else
get_flag byte (i + 1) accu get_flag byte (i + 1) accu
| _ -> accu in | _ -> List.rev accu in
get_flag byte 0 [] get_flag byte 0 []