diff --git a/src/libvm/src/interrupt.rs b/src/libvm/src/interrupt.rs index 45d4e43..1f563ba 100644 --- a/src/libvm/src/interrupt.rs +++ b/src/libvm/src/interrupt.rs @@ -4,7 +4,7 @@ macro_rules! interrupts { { $($variant:ident = $value:expr),* $(,)? } => { - pub type IntVec = u8; + pub type IntVec = usize; $( #[allow(dead_code)] @@ -47,4 +47,8 @@ impl Interrupt { self.0 &= !ADDR_MASK; self.0 |= addr; } + + pub fn to_vec(&self) -> Vec { + self.0.to_le_bytes().to_vec() + } } diff --git a/src/libvm/src/obj/assemble.rs b/src/libvm/src/obj/assemble.rs index f9f44b2..26c8bd5 100644 --- a/src/libvm/src/obj/assemble.rs +++ b/src/libvm/src/obj/assemble.rs @@ -7,6 +7,7 @@ use self::{error::*, session::AsmSession}; use crate::{ addr::Addr, inst, + interrupt::Interrupt, obj::{ obj::{self, Object}, syn::ast::*, @@ -142,7 +143,7 @@ impl Asm for DataLine { impl Asm for ValueDef { type Out = Vec; - fn assemble(&self, _: &mut AsmSession) -> Result { + fn assemble(&self, session: &mut AsmSession) -> Result { match self { ValueDef::Int(x, s) => Ok(x.to_le_bytes().iter().copied().take(s.len()).collect()), ValueDef::String(s) => { @@ -157,6 +158,17 @@ impl Asm for ValueDef { out.extend(bytes); 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()) + } } } } diff --git a/src/libvm/src/obj/syn/ast.rs b/src/libvm/src/obj/syn/ast.rs index eb775b4..2aa8c6f 100644 --- a/src/libvm/src/obj/syn/ast.rs +++ b/src/libvm/src/obj/syn/ast.rs @@ -1,4 +1,5 @@ use crate::{ + interrupt::Interrupt, inst, reg::Reg, }; @@ -84,6 +85,7 @@ pub enum ValueDef { Int(u64, IntSize), String(String), ZString(String), + Interrupt(bool, Value), } impl ValueDef { @@ -92,6 +94,7 @@ impl ValueDef { ValueDef::Int(_, s) => s.len(), ValueDef::String(s) => 8 + s.as_bytes().len(), ValueDef::ZString(s) => s.as_bytes().len() + 1, + ValueDef::Interrupt(_, _) => std::mem::size_of::(), } } } diff --git a/src/libvm/src/obj/syn/lexer.l b/src/libvm/src/obj/syn/lexer.l index fd75e52..4fa0dbf 100644 --- a/src/libvm/src/obj/syn/lexer.l +++ b/src/libvm/src/obj/syn/lexer.l @@ -24,9 +24,9 @@ u64 "U64" \.u16 "U16_DEF" \.u32 "U32_DEF" \.u64 "U64_DEF" -\.[iu](8|16|32|64) "INT_DEF" \.string "STR_DEF" \.zstring "ZSTR_DEF" +\.interrupt "INTERRUPT_DEF" "([^"]|\\[\\nt0"'])*" "STRING" add "ADD" sub "SUB" diff --git a/src/libvm/src/obj/syn/parser.y b/src/libvm/src/obj/syn/parser.y index 3f6c4a7..68e75e9 100644 --- a/src/libvm/src/obj/syn/parser.y +++ b/src/libvm/src/obj/syn/parser.y @@ -54,13 +54,11 @@ ValueDef -> ValueDef: | 'U64_DEF' Int { ValueDef::Int($2, IntSize::U64) } | 'STR_DEF' String { ValueDef::String($2) } | 'ZSTR_DEF' String { ValueDef::ZString($2) } + | 'INTERRUPT_DEF' Int 'COMMA' ConstValue { ValueDef::Interrupt($2 != 0, $4) } ; Value -> Value: - Int { Value::Int($1) } - | Reg { Value::Reg($1) } - | Name { Value::Name($1) } - | 'BUCKBUCK' { Value::Here } + ConstValue { $1 } | 'LPAREN' Value 'RPAREN' { Value::Addr(Box::new($2), IntSize::U64) } | 'LPAREN' Value 'RPAREN' 'U8' { Value::Addr(Box::new($2), IntSize::U8) } | 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) } @@ -69,6 +67,13 @@ Value -> Value: //| '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: ArrayValues Value { $1.push($2); $1 } diff --git a/src/libvm/src/state.rs b/src/libvm/src/state.rs index 81cd3a8..803f79d 100644 --- a/src/libvm/src/state.rs +++ b/src/libvm/src/state.rs @@ -107,6 +107,10 @@ impl State { self.get_reg_unchecked(FP) } + pub fn status(&self) -> u64 { + self.get_reg_unchecked(STATUS) + } + //////////////////////////////////////////////////////////////////////////////// // Flags //////////////////////////////////////////////////////////////////////////////// @@ -161,6 +165,53 @@ impl State { 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 //////////////////////////////////////////////////////////////////////////////// @@ -194,9 +245,13 @@ impl State { self.store_dest(d, value)?; } Inst::Div(d, s) => { - // TODO : catch divide by zero - let value = self.load_dest(d)?.wrapping_div(self.load_source(s)?); - self.store_dest(d, value)?; + let src = self.load_source(s)?; + if src == 0 { + 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) => { // TODO : catch divide by zero