Add interrupt handlers in cpu
This commit is contained in:
parent
4df4aea484
commit
033f63ec42
66
src/cpu.ml
66
src/cpu.ml
|
@ -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
|
||||
|
|
|
@ -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 []
|
||||
|
|
Loading…
Reference in a new issue