Add interrupt struct and IVT reader

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-03-04 16:41:37 -05:00
parent ce352c000c
commit bf83601cdf
4 changed files with 72 additions and 9 deletions

View File

@@ -1,3 +1,5 @@
use crate::addr::Addr;
macro_rules! interrupts { macro_rules! interrupts {
{ {
$($variant:ident = $value:expr),* $(,)? $($variant:ident = $value:expr),* $(,)?
@@ -17,3 +19,32 @@ interrupts! {
ILLEGAL_MEMORY_ADDRESS = 2, ILLEGAL_MEMORY_ADDRESS = 2,
HARDWARE_EVENT = 3, HARDWARE_EVENT = 3,
} }
pub const IVT_LENGTH: usize = 512;
#[derive(Debug, Clone, Copy, Default)]
pub struct Interrupt(u64);
const ENABLED_MASK: u64 = 0x8000_0000_0000_0000;
const ADDR_MASK: u64 = 0x07ff_ffff_ffff_ffff;
impl Interrupt {
pub fn enabled(&self) -> bool {
(self.0 & ENABLED_MASK) != 0
}
pub fn set_enabled(&mut self, enabled: bool) {
let enabled = (enabled as u64) << 63;
self.0 |= enabled;
}
pub fn addr(&self) -> Addr {
Addr((self.0 & ADDR_MASK) << 5)
}
pub fn set_addr(&mut self, addr: Addr) {
let addr = (addr.0 >> 5) & ADDR_MASK;
self.0 &= !ADDR_MASK;
self.0 |= addr;
}
}

View File

@@ -58,31 +58,32 @@ impl Asm for DataSection {
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> { fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
let names = names::get_section_names(self)?; let names = names::get_section_names(self)?;
session.name_stack.push(names); session.name_stack.push(names);
let section_len = self.len() as u64; let content_len = self.len() as u64;
let (start, end) = match self.org { let (start, end) = match self.org {
SectionOrg::Start(start) => (start, start + (section_len as u64)), SectionOrg::Start(start) => (start, start + (content_len as u64)),
SectionOrg::StartEnd(start, end) => (start, end), SectionOrg::StartEnd(start, end) => (start, end),
}; };
session.pos = Addr(start); session.pos = Addr(start);
if start > end { if start > end {
return Err(AsmError::StartGreaterThanEnd { start, end }); return Err(AsmError::StartGreaterThanEnd { start, end });
} }
let len = end - start - 1; let len = end - start;
if len > section_len { if content_len > len {
return Err(AsmError::SectionTooShort { return Err(AsmError::SectionTooShort {
name: self.name.clone(),
section_end: end, section_end: end,
section_size: start + section_len, section_size: start + content_len,
}); });
} }
let mut contents = Vec::with_capacity(section_len as usize); let mut contents = Vec::with_capacity(content_len as usize);
for line in self.lines.iter() { for line in self.lines.iter() {
contents.extend(line.assemble(session)?); contents.extend(line.assemble(session)?);
session.pos += line.len(); session.pos += line.len();
} }
assert_eq!( assert_eq!(
contents.len() as u64, contents.len() as u64,
section_len, content_len,
"in section {}", "in section {}",
self.name self.name
); );
@@ -90,7 +91,7 @@ impl Asm for DataSection {
Ok(obj::DataSection { Ok(obj::DataSection {
name: self.name.clone(), name: self.name.clone(),
start, start,
len: section_len, len: content_len,
contents, contents,
}) })
} }

View File

@@ -51,6 +51,7 @@ pub enum AsmError {
section_size section_size
))] ))]
SectionTooShort { SectionTooShort {
name: String,
section_end: u64, section_end: u64,
section_size: u64, section_size: u64,
}, },

View File

@@ -1,4 +1,5 @@
use crate::{addr::*, error::*, flags::*, inst::*, mem::*, obj::obj::*, reg::*}; use crate::{addr::*, error::*, flags::*, inst::*, interrupt::*, mem::*, obj::obj::*, reg::*};
use std::mem;
pub struct State { pub struct State {
regs: [u64; NUM_REGS], regs: [u64; NUM_REGS],
@@ -47,6 +48,10 @@ impl State {
Ok(()) Ok(())
} }
////////////////////////////////////////////////////////////////////////////////
// Memory
////////////////////////////////////////////////////////////////////////////////
pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> { pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> {
let mut cursor = MemCursor::new(self.mem.as_slice()); let mut cursor = MemCursor::new(self.mem.as_slice());
cursor.set_position(addr); cursor.set_position(addr);
@@ -131,6 +136,31 @@ impl State {
self.set_reg_unchecked(FLAGS, flags.bits()); self.set_reg_unchecked(FLAGS, flags.bits());
} }
////////////////////////////////////////////////////////////////////////////////
// Interrupts
////////////////////////////////////////////////////////////////////////////////
pub fn ivt(&self) -> Result<&[Interrupt]> {
let ivt_addr = self.get_reg_unchecked(IVT);
if ivt_addr % 64 != 0 {
panic!("illegal IVT address {:#x}; must be divisible by 64", ivt_addr);
}
let start = ivt_addr as usize;
let end = start + (IVT_LENGTH * mem::size_of::<Interrupt>());
if end > self.mem.len() {
return Err(VmError::MemOutOfBounds { addr: Addr(ivt_addr) });
}
// This is safe because we check the bounds above
let slice_ptr = (&self.mem[start..]).as_ptr();
let slice = unsafe {
std::slice::from_raw_parts(slice_ptr as *const Interrupt, IVT_LENGTH)
};
Ok(slice)
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Execution // Execution
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////