Skip to content

Commit

Permalink
Support non maskable interrupts
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanizag committed Jul 21, 2021
1 parent aba8cf0 commit b4ad9a3
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 20 deletions.
24 changes: 22 additions & 2 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use super::opcode::*;
use super::registers::*;
use super::state::*;

const NMI_ADDRESS: u16 = 0x0066;

/// The Z80 cpu emulator.
///
/// Executes Z80 instructions changing the cpu State and Machine
Expand Down Expand Up @@ -59,8 +61,21 @@ impl Cpu {
/// * `sys` - A representation of the emulated machine that has the Machine trait
///
pub fn execute_instruction(&mut self, sys: &mut dyn Machine) {
let pc = self.state.reg.pc();
if self.is_halted() && !self.state.nmi_pending {
// The CPU is in HALT state. Only interrupts can execute.
return
}

let mut env = Environment::new(&mut self.state, sys);
if env.state.nmi_pending {
env.state.nmi_pending = false;
env.state.halted = false;
env.state.reg.start_nmi();
env.subroutine_call(NMI_ADDRESS);
}


let pc = env.state.reg.pc();
let opcode = self.decoder.decode(&mut env);
if self.trace {
print!("==> {:04x}: {:20}", pc, opcode.disasm(&mut env));
Expand All @@ -81,7 +96,7 @@ impl Cpu {
self.state.reg.get8(Reg8::F)
);
println!(" [{:02x} {:02x} {:02x}]", sys.peek(pc),
sys.peek(pc+1), sys.peek(pc+2));
sys.peek(pc.wrapping_add(1)), sys.peek(pc.wrapping_add(2)));
}
}

Expand All @@ -104,6 +119,11 @@ impl Cpu {
pub fn is_halted(&self) -> bool {
self.state.halted
}

/// Non maskable interrupt request
pub fn signal_nmi(&mut self) {
self.state.nmi_pending = true
}
}


10 changes: 10 additions & 0 deletions src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ impl <'a> Environment<'_> {
(l as u16) + ((h as u16) << 8)
}

pub fn subroutine_call(&mut self, address: u16) {
self.push(self.state.reg.pc());
self.state.reg.set_pc(address);
}

pub fn subroutine_return(&mut self) {
let pc = self.pop();
self.state.reg.set_pc(pc);
}

pub fn set_index(&mut self, index: Reg16) {
self.state.index = index;
self.state.index_changed = true;
Expand Down
4 changes: 2 additions & 2 deletions src/opcode_alu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn build_operator_a_r(r: Reg8, (op, name): (Operator, &str)) -> Opcode {
if r != Reg8::_HL && r != Reg8::H && r != Reg8::L {
// Fast version
Opcode {
name: format!("{} A, {:?}", name, r),
name: format!("{} A, {}", name, r),
action: Box::new(move |env: &mut Environment| {
let a = env.state.reg.a();
let b = env.state.reg.get8(r);
Expand All @@ -17,7 +17,7 @@ pub fn build_operator_a_r(r: Reg8, (op, name): (Operator, &str)) -> Opcode {
}
} else {
Opcode {
name: format!("{} A, {:?}", name, r),
name: format!("{} A, {}", name, r),
action: Box::new(move |env: &mut Environment| {
env.load_displacement(r);

Expand Down
24 changes: 8 additions & 16 deletions src/opcode_jumps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ pub fn build_call() -> Opcode {
name: "CALL nn".to_string(),
action: Box::new(move |env: &mut Environment| {
let address = env.advance_immediate16();
env.push(env.state.reg.pc());
env.state.reg.set_pc(address);
env.subroutine_call(address);
})
}
}
Expand All @@ -99,8 +98,7 @@ pub fn build_call_eq((flag, value, name): (Flag, bool, &str)) -> Opcode {
action: Box::new(move |env: &mut Environment| {
let address = env.advance_immediate16();
if env.state.reg.get_flag(flag) == value {
env.push(env.state.reg.pc());
env.state.reg.set_pc(address);
env.subroutine_call(address);
}
})
}
Expand All @@ -111,23 +109,18 @@ pub fn build_rst(d: u8) -> Opcode {
name: format!("RST {:02x}h", d),
action: Box::new(move |env: &mut Environment| {
let address = d as u16;
env.push(env.state.reg.pc());
env.state.reg.set_pc(address);
env.subroutine_call(address);
})
}
}

// Returns
fn operation_return(env: &mut Environment) {
let pc = env.pop();
env.state.reg.set_pc(pc);
}

pub fn build_ret() -> Opcode {
Opcode {
name: "RET".to_string(),
action: Box::new(move |env: &mut Environment| {
operation_return(env);
env.subroutine_return();
})
}
}
Expand All @@ -136,7 +129,7 @@ pub fn build_reti() -> Opcode {
Opcode {
name: "RETI".to_string(),
action: Box::new(move |env: &mut Environment| {
operation_return(env);
env.subroutine_return();
})
}
}
Expand All @@ -145,9 +138,8 @@ pub fn build_retn() -> Opcode {
Opcode {
name: "RETN".to_string(),
action: Box::new(move |env: &mut Environment| {
operation_return(env);

// TODO: "The contents of IIF2 is copied back into IIF1"
env.subroutine_return();
env.state.reg.end_nmi();
})
}
}
Expand All @@ -157,7 +149,7 @@ pub fn build_ret_eq((flag, value, name): (Flag, bool, &str)) -> Opcode {
name: format!("RET {}", name),
action: Box::new(move |env: &mut Environment| {
if env.state.reg.get_flag(flag) == value {
operation_return(env);
env.subroutine_return();
}
})
}
Expand Down
11 changes: 11 additions & 0 deletions src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,12 +373,23 @@ impl Registers {
}

pub(crate) fn set_interrupts(&mut self, v: bool) {
self.iff1 = v;
self.iff2 = v;
}

pub(crate) fn set_interrupt_mode(&mut self, im: u8) {
self.im = im;
}

pub(crate) fn start_nmi(&mut self) {
self.iff2 = self.iff1;
self.iff1 = false;
}

pub(crate) fn end_nmi(&mut self) {
self.iff1 = self.iff2;
}

}

#[cfg(test)]
Expand Down
3 changes: 3 additions & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub struct State {
pub reg: Registers,
/// Halt state of the CPU
pub halted: bool,
/// Non maskable interrupt signaled
pub nmi_pending: bool,
// Alternate index management
pub index: Reg16, // Using HL, IX or IY
pub displacement: i8, // Used for (IX+d) and (iY+d)
Expand All @@ -22,6 +24,7 @@ impl State {
State {
reg: Registers::new(),
halted: false,
nmi_pending: false,
index: Reg16::HL,
displacement: 0,
displacement_loaded: false,
Expand Down

0 comments on commit b4ad9a3

Please sign in to comment.