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;
word
(*************************************************
*
* Stack manipulation
*
************************************************)
let pop_stack cpu mem =
let low = Memory.get mem cpu.reg.sp in
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;
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) =
print_cpu_state cpu;
let opcode = read_pc_byte cpu mem |> char_of_int in
@ -294,7 +311,8 @@ let run cpu (mem: Memory.map) =
inst, 8
| '\xFB' -> let inst = sprintf "EI" in
(* enable interrupts, IME=1 *)
(* enable interrupts *)
Interrupt.ime := true;
inst, 4
| x -> eprintf "opcode 0x%02X\n" (int_of_char x);
@ -304,3 +322,41 @@ let run cpu (mem: Memory.map) =
in
inc_cycles cpu 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,7 +6,7 @@
* LICENSE file at the top level directory of this source tree.
*)
(* let IME = ref false;; *)
let ime = ref false;;
type t =
| V_Blank
@ -15,6 +15,7 @@ type t =
| Serial
| Joypad
(** Return the list of interrupt flags sorted by priority. *)
let get_flags byte =
let nth_interrupt i =
@ -34,6 +35,6 @@ let get_flags byte =
get_flag byte (i + 1) (interrupt :: accu)
else
get_flag byte (i + 1) accu
| _ -> accu in
| _ -> List.rev accu in
get_flag byte 0 []