From 033f63ec4209490c634893aa5625528f2c2c7a30 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Mon, 29 Feb 2016 23:07:42 +0100 Subject: [PATCH] Add interrupt handlers in cpu --- src/cpu.ml | 66 ++++++++++++++++++++++++++++++++++++++++++++---- src/interrupt.ml | 15 ++++++----- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/cpu.ml b/src/cpu.ml index 4215bf1..a860504 100644 --- a/src/cpu.ml +++ b/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 diff --git a/src/interrupt.ml b/src/interrupt.ml index b175557..3e28847 100644 --- a/src/interrupt.ml +++ b/src/interrupt.ml @@ -6,15 +6,16 @@ * LICENSE file at the top level directory of this source tree. *) -(* let IME = ref false;; *) +let ime = ref false;; type t = - | V_Blank - | LCD_Stat - | Timer - | Serial - | Joypad + | V_Blank + | LCD_Stat + | Timer + | 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 []