Fix dumb mistake in address calculation for interrupts, add more registers to interrupt call stack
Interrupts need to be on 8-byte (or 64-bit) bounds. I had mistakenly decided to shift right by 5 (which isn't even dividing by 64, it's 32) -but since this an address pointing at byte ranges, that should be divided by 8, or >> 3. Additionally, interrupts add all 32 general purpose registers to the stack because otherwise they become useless. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -26,7 +26,7 @@ pub const IVT_LENGTH: usize = 512;
|
||||
pub struct Interrupt(u64);
|
||||
|
||||
const ENABLED_MASK: u64 = 0x8000_0000_0000_0000;
|
||||
const ADDR_MASK: u64 = 0x07ff_ffff_ffff_ffff;
|
||||
const ADDR_MASK: u64 = 0x1fff_ffff_ffff_ffff;
|
||||
|
||||
impl Interrupt {
|
||||
pub fn enabled(&self) -> bool {
|
||||
@@ -39,11 +39,11 @@ impl Interrupt {
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> Addr {
|
||||
Addr((self.0 & ADDR_MASK) << 5)
|
||||
Addr((self.0 & ADDR_MASK) << 3)
|
||||
}
|
||||
|
||||
pub fn set_addr(&mut self, addr: Addr) {
|
||||
let addr = (addr.0 >> 5) & ADDR_MASK;
|
||||
let addr = (addr.0 >> 3) & ADDR_MASK;
|
||||
self.0 &= !ADDR_MASK;
|
||||
self.0 |= addr;
|
||||
}
|
||||
|
||||
@@ -181,23 +181,23 @@ impl State {
|
||||
let ip = return_ip;
|
||||
let flags = self.get_reg_unchecked(FLAGS);
|
||||
let status = self.status();
|
||||
let r0 = self.get_reg_unchecked(R00);
|
||||
let r1 = self.get_reg_unchecked(R01);
|
||||
|
||||
self.push(Source::Imm(fp))?;
|
||||
self.push(Source::Imm(ip))?;
|
||||
self.push(Source::Imm(flags))?;
|
||||
self.push(Source::Imm(status))?;
|
||||
self.push(Source::Imm(r0))?;
|
||||
self.push(Source::Imm(r1))?;
|
||||
|
||||
// push R0 .. R31
|
||||
for reg in R00 ..= R31 {
|
||||
self.push(Source::Reg(reg))?;
|
||||
}
|
||||
|
||||
let sp = self.sp();
|
||||
self.set_reg_unchecked(FP, sp - 48);
|
||||
self.set_reg_unchecked(IP, interrupt.addr().0);
|
||||
self.set_reg_unchecked(R00, index as u64);
|
||||
self.set_reg_unchecked(R01, aux);
|
||||
|
||||
Ok(self.ip())
|
||||
Ok(interrupt.addr().0)
|
||||
}
|
||||
|
||||
/// Exit/return from the current interrupt.
|
||||
@@ -207,8 +207,10 @@ impl State {
|
||||
|
||||
self.set_reg_unchecked(SP, sp);
|
||||
|
||||
self.pop(Dest::Reg(R01))?;
|
||||
self.pop(Dest::Reg(R00))?;
|
||||
// pop R31 .. R0
|
||||
for reg in R31 ..= R00 {
|
||||
self.pop(Dest::Reg(reg))?;
|
||||
}
|
||||
self.pop(Dest::Reg(STATUS))?;
|
||||
self.pop(Dest::Reg(FLAGS))?;
|
||||
self.pop(Dest::Reg(IP))?;
|
||||
@@ -258,11 +260,14 @@ impl State {
|
||||
}
|
||||
}
|
||||
Inst::IDiv(d, s) => {
|
||||
// TODO : catch divide by zero
|
||||
let dest = self.load_dest(d)? as i64;
|
||||
let source = self.load_source(s)? as i64;
|
||||
let value = dest.wrapping_div(source);
|
||||
self.store_dest(d, value as u64)?;
|
||||
if source == 0 {
|
||||
next_ip = self.interrupt(next_ip, DIVIDE_BY_ZERO, 0)?;
|
||||
} else {
|
||||
let value = dest.wrapping_div(source);
|
||||
self.store_dest(d, value as u64)?;
|
||||
}
|
||||
}
|
||||
Inst::Mod(d, s) => {
|
||||
let value = self.load_dest(d)? % self.load_source(s)?;
|
||||
|
||||
Reference in New Issue
Block a user