Add interrupt definition syntax and interrupt handling in VM execution state

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-03-06 12:17:05 -05:00
parent bf83601cdf
commit b1f2de198e
6 changed files with 89 additions and 10 deletions

View File

@@ -4,7 +4,7 @@ macro_rules! interrupts {
{ {
$($variant:ident = $value:expr),* $(,)? $($variant:ident = $value:expr),* $(,)?
} => { } => {
pub type IntVec = u8; pub type IntVec = usize;
$( $(
#[allow(dead_code)] #[allow(dead_code)]
@@ -47,4 +47,8 @@ impl Interrupt {
self.0 &= !ADDR_MASK; self.0 &= !ADDR_MASK;
self.0 |= addr; self.0 |= addr;
} }
pub fn to_vec(&self) -> Vec<u8> {
self.0.to_le_bytes().to_vec()
}
} }

View File

@@ -7,6 +7,7 @@ use self::{error::*, session::AsmSession};
use crate::{ use crate::{
addr::Addr, addr::Addr,
inst, inst,
interrupt::Interrupt,
obj::{ obj::{
obj::{self, Object}, obj::{self, Object},
syn::ast::*, syn::ast::*,
@@ -142,7 +143,7 @@ impl Asm for DataLine {
impl Asm for ValueDef { impl Asm for ValueDef {
type Out = Vec<u8>; type Out = Vec<u8>;
fn assemble(&self, _: &mut AsmSession) -> Result<Self::Out> { fn assemble(&self, session: &mut AsmSession) -> Result<Self::Out> {
match self { match self {
ValueDef::Int(x, s) => Ok(x.to_le_bytes().iter().copied().take(s.len()).collect()), ValueDef::Int(x, s) => Ok(x.to_le_bytes().iter().copied().take(s.len()).collect()),
ValueDef::String(s) => { ValueDef::String(s) => {
@@ -157,6 +158,17 @@ impl Asm for ValueDef {
out.extend(bytes); out.extend(bytes);
Ok(out) Ok(out)
} }
ValueDef::Interrupt(e, a) => {
use std::convert::TryInto;
let mut interrupt = Interrupt::default();
interrupt.set_enabled(*e);
let mut addr_bytes = a.assemble(session)?;
addr_bytes.resize(8, 0);
let addr_bytes: [u8; 8] = addr_bytes.as_slice().try_into().unwrap();
let addr = u64::from_ne_bytes(addr_bytes);
interrupt.set_addr(Addr(addr));
Ok(interrupt.to_vec())
}
} }
} }
} }

View File

@@ -1,4 +1,5 @@
use crate::{ use crate::{
interrupt::Interrupt,
inst, inst,
reg::Reg, reg::Reg,
}; };
@@ -84,6 +85,7 @@ pub enum ValueDef {
Int(u64, IntSize), Int(u64, IntSize),
String(String), String(String),
ZString(String), ZString(String),
Interrupt(bool, Value),
} }
impl ValueDef { impl ValueDef {
@@ -92,6 +94,7 @@ impl ValueDef {
ValueDef::Int(_, s) => s.len(), ValueDef::Int(_, s) => s.len(),
ValueDef::String(s) => 8 + s.as_bytes().len(), ValueDef::String(s) => 8 + s.as_bytes().len(),
ValueDef::ZString(s) => s.as_bytes().len() + 1, ValueDef::ZString(s) => s.as_bytes().len() + 1,
ValueDef::Interrupt(_, _) => std::mem::size_of::<Interrupt>(),
} }
} }
} }

View File

@@ -24,9 +24,9 @@ u64 "U64"
\.u16 "U16_DEF" \.u16 "U16_DEF"
\.u32 "U32_DEF" \.u32 "U32_DEF"
\.u64 "U64_DEF" \.u64 "U64_DEF"
\.[iu](8|16|32|64) "INT_DEF"
\.string "STR_DEF" \.string "STR_DEF"
\.zstring "ZSTR_DEF" \.zstring "ZSTR_DEF"
\.interrupt "INTERRUPT_DEF"
"([^"]|\\[\\nt0"'])*" "STRING" "([^"]|\\[\\nt0"'])*" "STRING"
add "ADD" add "ADD"
sub "SUB" sub "SUB"

View File

@@ -54,13 +54,11 @@ ValueDef -> ValueDef:
| 'U64_DEF' Int { ValueDef::Int($2, IntSize::U64) } | 'U64_DEF' Int { ValueDef::Int($2, IntSize::U64) }
| 'STR_DEF' String { ValueDef::String($2) } | 'STR_DEF' String { ValueDef::String($2) }
| 'ZSTR_DEF' String { ValueDef::ZString($2) } | 'ZSTR_DEF' String { ValueDef::ZString($2) }
| 'INTERRUPT_DEF' Int 'COMMA' ConstValue { ValueDef::Interrupt($2 != 0, $4) }
; ;
Value -> Value: Value -> Value:
Int { Value::Int($1) } ConstValue { $1 }
| Reg { Value::Reg($1) }
| Name { Value::Name($1) }
| 'BUCKBUCK' { Value::Here }
| 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) } | 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) }
| 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) } | 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) }
| 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) } | 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) }
@@ -69,6 +67,13 @@ Value -> Value:
//| 'LBRACKET' ArrayValues 'RBRACKET' { Value::Array($2) } //| 'LBRACKET' ArrayValues 'RBRACKET' { Value::Array($2) }
; ;
ConstValue -> Value:
Int { Value::Int($1) }
| Reg { Value::Reg($1) }
| Name { Value::Name($1) }
| 'BUCKBUCK' { Value::Here }
;
/* /*
ArrayValues -> Vec<Value>: ArrayValues -> Vec<Value>:
ArrayValues Value { $1.push($2); $1 } ArrayValues Value { $1.push($2); $1 }

View File

@@ -107,6 +107,10 @@ impl State {
self.get_reg_unchecked(FP) self.get_reg_unchecked(FP)
} }
pub fn status(&self) -> u64 {
self.get_reg_unchecked(STATUS)
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Flags // Flags
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -161,6 +165,53 @@ impl State {
Ok(slice) Ok(slice)
} }
/// Invoke an interrupt.
pub fn interrupt(&mut self, return_ip: u64, index: usize, aux: u64) -> Result<()> {
assert!(index < IVT_LENGTH, "invalid interrupt index");
let interrupt = self.ivt()?[index];
if !interrupt.enabled() {
return Ok(());
}
let fp = self.fp();
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))?;
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(())
}
/// Exit/return from the current interrupt.
pub fn exit_interrupt(&mut self) -> Result<()> {
let fp = self.fp();
let sp = fp + 48;
self.set_reg_unchecked(SP, sp);
self.pop(Dest::Reg(R01))?;
self.pop(Dest::Reg(R00))?;
self.pop(Dest::Reg(STATUS))?;
self.pop(Dest::Reg(FLAGS))?;
self.pop(Dest::Reg(IP))?;
self.pop(Dest::Reg(FP))?;
Ok(())
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Execution // Execution
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -194,9 +245,13 @@ impl State {
self.store_dest(d, value)?; self.store_dest(d, value)?;
} }
Inst::Div(d, s) => { Inst::Div(d, s) => {
// TODO : catch divide by zero let src = self.load_source(s)?;
let value = self.load_dest(d)?.wrapping_div(self.load_source(s)?); if src == 0 {
self.store_dest(d, value)?; return self.interrupt(next_ip, DIVIDE_BY_ZERO, 0);
} else {
let value = self.load_dest(d)?.wrapping_div(src);
self.store_dest(d, value)?;
}
} }
Inst::IDiv(d, s) => { Inst::IDiv(d, s) => {
// TODO : catch divide by zero // TODO : catch divide by zero