Add interrupt struct and IVT reader
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
use crate::addr::Addr;
|
||||
|
||||
macro_rules! interrupts {
|
||||
{
|
||||
$($variant:ident = $value:expr),* $(,)?
|
||||
@@ -17,3 +19,32 @@ interrupts! {
|
||||
ILLEGAL_MEMORY_ADDRESS = 2,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,31 +58,32 @@ impl Asm for DataSection {
|
||||
fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
|
||||
let names = names::get_section_names(self)?;
|
||||
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 {
|
||||
SectionOrg::Start(start) => (start, start + (section_len as u64)),
|
||||
SectionOrg::Start(start) => (start, start + (content_len as u64)),
|
||||
SectionOrg::StartEnd(start, end) => (start, end),
|
||||
};
|
||||
session.pos = Addr(start);
|
||||
if start > end {
|
||||
return Err(AsmError::StartGreaterThanEnd { start, end });
|
||||
}
|
||||
let len = end - start - 1;
|
||||
if len > section_len {
|
||||
let len = end - start;
|
||||
if content_len > len {
|
||||
return Err(AsmError::SectionTooShort {
|
||||
name: self.name.clone(),
|
||||
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() {
|
||||
contents.extend(line.assemble(session)?);
|
||||
session.pos += line.len();
|
||||
}
|
||||
assert_eq!(
|
||||
contents.len() as u64,
|
||||
section_len,
|
||||
content_len,
|
||||
"in section {}",
|
||||
self.name
|
||||
);
|
||||
@@ -90,7 +91,7 @@ impl Asm for DataSection {
|
||||
Ok(obj::DataSection {
|
||||
name: self.name.clone(),
|
||||
start,
|
||||
len: section_len,
|
||||
len: content_len,
|
||||
contents,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ pub enum AsmError {
|
||||
section_size
|
||||
))]
|
||||
SectionTooShort {
|
||||
name: String,
|
||||
section_end: u64,
|
||||
section_size: u64,
|
||||
},
|
||||
|
||||
@@ -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 {
|
||||
regs: [u64; NUM_REGS],
|
||||
@@ -47,6 +48,10 @@ impl State {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> {
|
||||
let mut cursor = MemCursor::new(self.mem.as_slice());
|
||||
cursor.set_position(addr);
|
||||
@@ -131,6 +136,31 @@ impl State {
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Reference in New Issue
Block a user