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;
|
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
|
||||||
|
|
|
@ -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 []
|
||||||
|
|
Loading…
Reference in a new issue