moa/src/interrupts.rs
transistor 93c080eae6 Fixed interrupts
Previously the m68k wasn't masking interrupts with an equal priorty.
I also modified how they work, such that the cpus will check the
controller rather than wait for the notification call
2021-10-29 22:02:29 -07:00

87 lines
2.0 KiB
Rust

use std::iter;
use crate::error::Error;
use crate::devices::TransmutableBox;
pub struct Signal {
pub current: bool,
pub previous: bool,
}
impl Signal {
pub fn new() -> Signal {
Signal {
current: false,
previous: false,
}
}
pub fn has_changed(&mut self) -> Option<bool> {
if self.current != self.previous {
self.previous = self.current;
Some(self.current)
} else {
None
}
}
pub fn set(&mut self, value: bool) {
self.current = value;
}
}
pub struct InterruptController {
pub target: Option<TransmutableBox>,
pub interrupts: Vec<(bool, u8)>,
pub highest: u8,
}
impl InterruptController {
pub fn new() -> InterruptController {
InterruptController {
target: None,
interrupts: vec![(false, 0); 7],
highest: 0,
}
}
pub fn set_target(&mut self, dev: TransmutableBox) -> Result<(), Error> {
if self.target.is_some() {
return Err(Error::new("Interruptable device already set, and interrupt controller only supports one receiver"));
}
self.target = Some(dev);
Ok(())
}
pub fn set(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error> {
self.interrupts[priority as usize].0 = state;
self.interrupts[priority as usize].1 = number;
if state && priority > self.highest {
self.highest = priority;
}
Ok(())
}
pub fn check(&mut self) -> (bool, u8) {
if self.highest > 0 {
(true, self.highest)
} else {
(false, 0)
}
}
pub fn acknowledge(&mut self, priority: u8) -> Result<u8, Error> {
let acknowledge = self.interrupts[priority as usize].1;
self.interrupts[priority as usize].0 = false;
while self.highest > 0 && !self.interrupts[self.highest as usize].0 {
self.highest -= 1;
}
Ok(acknowledge)
}
}