Add interrupt definition syntax and interrupt handling in VM execution state
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user