From 2b8663037f79a2ae9e291b47323a96efb486b923 Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Tue, 3 Mar 2020 19:05:50 -0500 Subject: [PATCH] First part of libvm transition Signed-off-by: Alek Ratzloff --- Cargo.lock | 25 ++- Cargo.toml | 17 +- build.rs | 18 -- src/main.rs | 4 +- src/vm/addr.rs | 73 ------ src/vm/disassemble.rs | 294 ------------------------ src/vm/error.rs | 25 --- src/vm/flags.rs | 8 - src/vm/inst.rs | 263 ---------------------- src/vm/mem.rs | 278 ----------------------- src/vm/mod.rs | 8 - src/vm/obj/assemble.rs | 360 ----------------------------- src/vm/obj/assemble/error.rs | 114 ---------- src/vm/obj/assemble/includes.rs | 68 ------ src/vm/obj/assemble/names.rs | 104 --------- src/vm/obj/assemble/session.rs | 72 ------ src/vm/obj/error.rs | 45 ---- src/vm/obj/mod.rs | 4 - src/vm/obj/obj.rs | 269 ---------------------- src/vm/obj/syn/ast.rs | 255 --------------------- src/vm/obj/syn/convert.rs | 2 - src/vm/obj/syn/lexer.l | 67 ------ src/vm/obj/syn/mod.rs | 15 -- src/vm/obj/syn/parser.y | 221 ------------------ src/vm/reg.rs | 77 ------- src/vm/state.rs | 387 -------------------------------- src/vm/tick.rs | 189 ---------------- src/vm/visit.rs | 96 -------- 28 files changed, 21 insertions(+), 3337 deletions(-) delete mode 100644 build.rs delete mode 100644 src/vm/addr.rs delete mode 100644 src/vm/disassemble.rs delete mode 100644 src/vm/error.rs delete mode 100644 src/vm/flags.rs delete mode 100644 src/vm/inst.rs delete mode 100644 src/vm/mem.rs delete mode 100644 src/vm/mod.rs delete mode 100644 src/vm/obj/assemble.rs delete mode 100644 src/vm/obj/assemble/error.rs delete mode 100644 src/vm/obj/assemble/includes.rs delete mode 100644 src/vm/obj/assemble/names.rs delete mode 100644 src/vm/obj/assemble/session.rs delete mode 100644 src/vm/obj/error.rs delete mode 100644 src/vm/obj/mod.rs delete mode 100644 src/vm/obj/obj.rs delete mode 100644 src/vm/obj/syn/ast.rs delete mode 100644 src/vm/obj/syn/convert.rs delete mode 100644 src/vm/obj/syn/lexer.l delete mode 100644 src/vm/obj/syn/mod.rs delete mode 100644 src/vm/obj/syn/parser.y delete mode 100644 src/vm/reg.rs delete mode 100644 src/vm/state.rs delete mode 100644 src/vm/tick.rs delete mode 100644 src/vm/visit.rs diff --git a/Cargo.lock b/Cargo.lock index 2890c91..225792e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,6 +262,22 @@ name = "libc" version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libvm" +version = "0.1.0" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfgrammar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lrlex 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lrpar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rerun_except 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "snafu 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -419,14 +435,7 @@ dependencies = [ name = "rasp" version = "0.1.0" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cfgrammar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lrlex 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lrpar 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rerun_except 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libvm 0.1.0", "snafu 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index 8fafac7..ab14faa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,24 +4,9 @@ version = "0.1.0" authors = ["Alek Ratzloff "] edition = "2018" -build = "build.rs" - # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] structopt = "0.3" -bitflags = "1" -byteorder = "1" -lazy_static = "1" snafu = "0.6.2" - -cfgrammar = "0.6" -lrlex = "0.6" -lrpar = "0.6" -regex = "*" - -[build-dependencies] -cfgrammar = "0.6" -lrlex = "0.6" -lrpar = "0.6" -rerun_except = "0.1" +libvm = { path = "src/libvm" } diff --git a/build.rs b/build.rs deleted file mode 100644 index efc0667..0000000 --- a/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use cfgrammar::yacc::YaccKind; -use lrlex::LexerBuilder; -use lrpar::{CTParserBuilder}; -use rerun_except::rerun_except; - -fn main() -> Result<(), Box> { - let lex_rule_ids_map = CTParserBuilder::new() - .yacckind(YaccKind::Grmtools) - .process_file_in_src("vm/obj/syn/parser.y")?; - LexerBuilder::new() - .rule_ids_map(lex_rule_ids_map) - .process_file_in_src("vm/obj/syn/lexer.l")?; - rerun_except(&[ - "examples/*.asm", - "tests/*.asm", - ]).unwrap(); - Ok(()) -} diff --git a/src/main.rs b/src/main.rs index 9308029..264fd3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ #![allow(dead_code)] mod common; -mod vm; + +extern crate libvm as vm; use structopt::StructOpt; use snafu::Snafu; @@ -130,3 +131,4 @@ fn main() -> Result<()> { process::exit((status & 0xffff_ffff) as i32); } } + diff --git a/src/vm/addr.rs b/src/vm/addr.rs deleted file mode 100644 index e13ab95..0000000 --- a/src/vm/addr.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::{ - cmp::Ordering, - fmt::{self, Formatter, LowerHex}, - ops::{Add, AddAssign}, -}; - -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct Addr(pub u64); - -impl LowerHex for Addr { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - let Addr(v) = self; - LowerHex::fmt(v, fmt) - } -} - -impl Add for Addr -where - T: Add, - u64: Add, -{ - type Output = Addr; - - fn add(self, rhs: T) -> Self::Output { - Addr(self.0 + rhs) - } -} - -macro_rules! impl_add_assign { - ($ty:ty) => { - impl AddAssign<$ty> for Addr { - fn add_assign(&mut self, rhs: $ty) { - self.0 = self.0 + (rhs as u64); - } - } - } -} - -impl_add_assign!(usize); -impl_add_assign!(u64); - -macro_rules! impl_cmp { - ($ty:ty) => { - impl PartialEq<$ty> for Addr { - fn eq(&self, other: &$ty) -> bool { - self.0 == (*other as u64) - } - } - - impl PartialOrd<$ty> for Addr { - fn partial_cmp(&self, other: &$ty) -> Option { - let other = *other as u64; - self.0.partial_cmp(&other) - } - } - } -} - -impl_cmp!(usize); -impl_cmp!(u64); - -macro_rules! impl_from { - ($ty:ty) => { - impl From<$ty> for Addr { - fn from(other: $ty) -> Self { - Addr(other as u64) - } - } - } -} - -impl_from!(usize); -impl_from!(u64); diff --git a/src/vm/disassemble.rs b/src/vm/disassemble.rs deleted file mode 100644 index 942e583..0000000 --- a/src/vm/disassemble.rs +++ /dev/null @@ -1,294 +0,0 @@ -use crate::vm::{ - error::*, - inst::*, - mem::MemCursor, - reg::*, - visit::*, - vm::{Addr, HalfWord, Word}, -}; -use std::io::Write; - -const WIDTH: usize = 60; - -pub struct Disassemble<'w, 'o> { - writer: &'w mut dyn Write, - cursor: MemCursor<'o>, - addr_offset: Addr, -} - -impl<'w, 'o> Disassemble<'w, 'o> { - pub fn new(writer: &'w mut dyn Write, content: &'o [u8], addr_offset: Addr) -> Self { - Disassemble { - writer, - cursor: MemCursor::new(content), - addr_offset, - } - } - - pub fn is_done(&self) -> bool { - self.cursor.position() >= (self.cursor.get_ref().len() as u64) - } - - fn adv(&mut self) -> Result<()> { - // note the () - this explicitly clones the cursor - let op = self.cursor().next_u16()?; - let next = self.cursor.position() + (inst_len(op) as u64); - self.cursor.set_position(next); - Ok(()) - } - - fn write_addr(&mut self, addr: Addr) { - write!(self.writer, "{:06x} | ", self.addr_offset + addr).unwrap(); - } - - fn write_bytes(&mut self, bytes: &[u8]) { - for b in bytes { - write!(self.writer, "{:02x} ", b).unwrap(); - } - } - - fn write_inst_bytes(&mut self, op: InstOp) { - let len = inst_len(op); - let start = self.cursor.position() as usize; - let end = start + len; - let bytes = &self.cursor.get_ref()[start..end]; - self.write_bytes(bytes); - } - - fn write_r1_r2_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, r2: Reg) { - let len = inst_len(op); - let line_width = 6 + 3 + (3 * len); - let line_offset = WIDTH - line_width; - self.write_addr(addr); - self.write_inst_bytes(op); - - let iname = inst_name(op).unwrap(); - let r1name = reg_name(r1).unwrap().to_lowercase(); - let r2name = reg_name(r2).unwrap().to_lowercase(); - - writeln!( - self.writer, - "{}| {:>10} %{} %{}", - " ".repeat(line_offset), - iname, - r1name, - r2name - ) - .unwrap(); - } - - fn write_r1_inst(&mut self, addr: Addr, op: InstOp, r1: Reg) { - let line_width = 6 + 3 + (3 * inst_len(op)); - let line_offset = WIDTH - line_width; - self.write_addr(addr); - self.write_inst_bytes(op); - - let iname = inst_name(op).unwrap(); - let r1name = reg_name(r1).unwrap().to_lowercase(); - - writeln!( - self.writer, - "{}| {:>10} %{}", - " ".repeat(line_offset), - iname, - r1name, - ) - .unwrap(); - } - - fn write_r1_imm_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, imm: Word) { - let line_width = 6 + 3 + (3 * inst_len(op)); - let line_offset = WIDTH - line_width; - self.write_addr(addr); - self.write_inst_bytes(op); - - let iname = inst_name(op).unwrap(); - let r1name = reg_name(r1).unwrap().to_lowercase(); - - writeln!( - self.writer, - "{}| {:>10} %{} {:#X}", - " ".repeat(line_offset), - iname, - r1name, - imm, - ) - .unwrap(); - } -} - -impl VisitInst for Disassemble<'_, '_> { - type Out = (); - - fn cursor(&self) -> MemCursor { - self.cursor.clone() - } - - fn add(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), ADD, r1, r2); - self.adv()?; - Ok(()) - } - - fn mul(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), MUL, r1, r2); - self.adv()?; - Ok(()) - } - - fn div(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), DIV, r1, r2); - self.adv()?; - Ok(()) - } - - fn mod_(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), MOD, r1, r2); - self.adv()?; - Ok(()) - } - - fn ineg(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), INEG, r1); - self.adv()?; - Ok(()) - } - - fn and(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), AND, r1, r2); - self.adv()?; - Ok(()) - } - - fn or(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), OR, r1, r2); - self.adv()?; - Ok(()) - } - - fn inv(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), INV, r1); - self.adv()?; - Ok(()) - } - - fn not(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), NOT, r1); - self.adv()?; - Ok(()) - } - - fn xor(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), XOR, r1, r2); - self.adv()?; - Ok(()) - } - - fn shl(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), SHL, r1, r2); - self.adv()?; - Ok(()) - } - - fn shr(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), SHR, r1, r2); - self.adv()?; - Ok(()) - } - - fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), CMPEQ, r1, r2); - self.adv()?; - Ok(()) - } - - fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), CMPLT, r1, r2); - self.adv()?; - Ok(()) - } - - fn jmp(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), JMP, r1); - self.adv()?; - Ok(()) - } - - fn jz(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), JZ, r1); - self.adv()?; - Ok(()) - } - - fn jnz(&mut self, r1: Reg) -> Result { - self.write_r1_inst(self.cursor.position(), JNZ, r1); - self.adv()?; - Ok(()) - } - - fn load(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), LOAD, r1, r2); - self.adv()?; - Ok(()) - } - - fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), REGCOPY, r1, r2); - self.adv()?; - Ok(()) - } - - fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result { - self.write_r1_imm_inst(self.cursor.position(), STOREIMM64, r1, w1); - self.adv()?; - Ok(()) - } - - fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result { - self.write_r1_imm_inst(self.cursor.position(), STOREIMM32, r1, w1 as u64); - self.adv()?; - Ok(()) - } - - fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), MEMCOPY, r1, r2); - self.adv()?; - Ok(()) - } - - fn store(&mut self, r1: Reg, r2: Reg) -> Result { - self.write_r1_r2_inst(self.cursor.position(), STORE, r1, r2); - self.adv()?; - Ok(()) - } - - fn halt(&mut self) -> Result { - let line_width = 6 + 3 + 3 + 3; - let line_offset = WIDTH - line_width; - self.write_addr(self.cursor.position()); - self.write_inst_bytes(HALT); - writeln!( - self.writer, - "{}| {:>10}", - " ".repeat(line_offset), - "HALT", - ).unwrap(); - self.adv()?; - Ok(()) - } - - fn nop(&mut self) -> Result { - let line_width = 6 + 3 + 3 + 3; - let line_offset = WIDTH - line_width; - self.write_addr(self.cursor.position()); - self.write_inst_bytes(NOP); - writeln!( - self.writer, - "{}| {:>10}", - " ".repeat(line_offset), - "NOP", - ).unwrap(); - self.adv()?; - Ok(()) - } -} diff --git a/src/vm/error.rs b/src/vm/error.rs deleted file mode 100644 index 3eeb6fd..0000000 --- a/src/vm/error.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::vm::{inst::InstOp, reg::Reg, addr::*,}; -use snafu::Snafu; - -#[derive(Snafu, Debug, Clone)] -pub enum VmError { - #[snafu(display("illegal register: 0x{:02x}", reg))] - IllegalReg { reg: Reg }, - - #[snafu(display("memory address out of bounds: 0x{:016x}", addr))] - MemOutOfBounds { addr: Addr }, - - #[snafu(display("illegal instruction opcode: 0x{:04x}", op))] - IllegalOp { op: InstOp }, - - #[snafu(display("illegal destination specification: 0b{:08b}", spec))] - IllegalDestSpec { spec: u8 }, - - #[snafu(display("illegal source specification: 0b{:08b}", spec))] - IllegalSourceSpec { spec: u8 }, - - #[snafu(display("object to load spans too much memory"))] - ObjectTooLarge { object_size: usize, max_mem: usize }, -} - -pub type Result = std::result::Result; diff --git a/src/vm/flags.rs b/src/vm/flags.rs deleted file mode 100644 index e35bbfd..0000000 --- a/src/vm/flags.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bitflags::bitflags; - -bitflags! { - pub struct Flags: u64 { - const HALT = 1; - const COMPARE = 1 << 1; - } -} diff --git a/src/vm/inst.rs b/src/vm/inst.rs deleted file mode 100644 index 9610985..0000000 --- a/src/vm/inst.rs +++ /dev/null @@ -1,263 +0,0 @@ -use crate::vm::{addr::Addr, reg::Reg}; - -macro_rules! instructions { - { - $($variant:ident = $value:expr),* $(,)? - } => { - - $( - #[allow(dead_code)] - pub const $variant: InstOp = $value; - )* - - pub fn inst_name(op: InstOp) -> Option<&'static str> { - match op { - $( - $value => Some(stringify!($variant)), - )* - _ => None, - } - } - }; -} -pub type InstOp = u16; - -instructions! { - ADD = 0x0000, - SUB = 0x0001, - MUL = 0x0002, - DIV = 0x0003, - IDIV = 0x0004, - MOD = 0x0005, - AND = 0x0006, - OR = 0x0007, - XOR = 0x0008, - SHL = 0x0009, - SHR = 0x000a, - INEG = 0x000b, - INV = 0x000c, - NOT = 0x000d, - CMPEQ = 0x1000, - CMPLT = 0x1001, - JMP = 0x1002, - JZ = 0x1003, - JNZ = 0x1004, - CALL = 0x2000, - RET = 0x2001, - PUSH = 0x2002, - POP = 0x2003, - MOV = 0x3000, - HALT = 0xF000, - NOP = 0xF001, - DUMP = 0xF002, -} - -#[derive(Debug, Clone, Copy)] -pub enum Inst { - Add(Dest, Source), - Sub(Dest, Source), - Mul(Dest, Source), - Div(Dest, Source), - IDiv(Dest, Source), - Mod(Dest, Source), - And(Dest, Source), - Or(Dest, Source), - Xor(Dest, Source), - Shl(Dest, Source), - Shr(Dest, Source), - INeg(Dest, Source), - Inv(Dest, Source), - Not(Dest, Source), - CmpEq(Source, Source), - CmpLt(Source, Source), - Jmp(Source), - Jz(Source), - Jnz(Source), - Call(Source), - Ret, - Push(Source), - Pop(Dest), - Mov(Dest, Source), - Halt, - Nop, - Dump, -} - -impl Inst { - pub fn op(&self) -> InstOp { - match self { - Inst::Add(_, _) => ADD, - Inst::Sub(_, _) => SUB, - Inst::Mul(_, _) => MUL, - Inst::Div(_, _) => DIV, - Inst::IDiv(_, _) => IDIV, - Inst::Mod(_, _) => MOD, - Inst::And(_, _) => AND, - Inst::Or(_, _) => OR, - Inst::Xor(_, _) => XOR, - Inst::Shl(_, _) => SHL, - Inst::Shr(_, _) => SHL, - Inst::INeg(_, _) => INEG, - Inst::Inv(_, _) => INV, - Inst::Not(_, _) => NOT, - Inst::CmpEq(_, _) => CMPEQ, - Inst::CmpLt(_, _) => CMPLT, - Inst::Jmp(_) => JMP, - Inst::Jz(_) => JZ, - Inst::Jnz(_) => JNZ, - Inst::Mov(_, _) => MOV, - Inst::Call(_) => CALL, - Inst::Ret => RET, - Inst::Push(_) => PUSH, - Inst::Pop(_) => POP, - Inst::Halt => HALT, - Inst::Nop => NOP, - Inst::Dump => DUMP, - } - } - - pub fn len(&self) -> usize { - match self { - Inst::Add(dest, source) - | Inst::Sub(dest, source) - | Inst::Mul(dest, source) - | Inst::Div(dest, source) - | Inst::IDiv(dest, source) - | Inst::Mod(dest, source) - | Inst::And(dest, source) - | Inst::Or(dest, source) - | Inst::Xor(dest, source) - | Inst::Shl(dest, source) - | Inst::Shr(dest, source) - | Inst::INeg(dest, source) - | Inst::Inv(dest, source) - | Inst::Not(dest, source) - | Inst::Mov(dest, source) => { 3 + dest.len() + source.len() } - Inst::CmpEq(s1, s2) - | Inst::CmpLt(s1, s2) => { 3 + s1.len() + s2.len() } - Inst::Jmp(v) - | Inst::Jz(v) - | Inst::Jnz(v) - | Inst::Call(v) - | Inst::Push(v) => { 3 + v.len() } - Inst::Pop(v) => { 3 + v.len() } - Inst::Ret - | Inst::Halt - | Inst::Nop - | Inst::Dump => { 2 } - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Source { - Addr64(Addr), - Addr32(Addr), - Addr16(Addr), - Addr8(Addr), - RegAddr64(Reg), - RegAddr32(Reg), - RegAddr16(Reg), - RegAddr8(Reg), - Reg(Reg), - Imm(u64), -} - -impl Source { - /// The length of this source in its instruction. - pub fn len(&self) -> usize { - match self { - Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8, - Source::RegAddr64(_) | Source::RegAddr32(_) | Source::RegAddr16(_) | Source::RegAddr8(_) => 1, - Source::Reg(_) => 1, - Source::Imm(_) => 8, - } - } - - /// The length of the value that this source points to. - pub fn value_len(&self) -> usize { - match self { - Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => 8, - Source::Addr32(_) | Source::RegAddr32(_) => 4, - Source::Addr16(_) | Source::RegAddr16(_) => 2, - Source::Addr8(_) | Source::RegAddr8(_) => 1, - } - } -} - -impl From for Source { - fn from(other: Dest) -> Self { - match other { - Dest::Addr64(a) => Source::Addr64(a), - Dest::Addr32(a) => Source::Addr32(a), - Dest::Addr16(a) => Source::Addr16(a), - Dest::Addr8(a) => Source::Addr8(a), - Dest::RegAddr64(r) => Source::RegAddr64(r), - Dest::RegAddr32(r) => Source::RegAddr32(r), - Dest::RegAddr16(r) => Source::RegAddr16(r), - Dest::RegAddr8(r) => Source::RegAddr8(r), - Dest::Reg(r) => Source::Reg(r), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Dest { - Addr64(Addr), - Addr32(Addr), - Addr16(Addr), - Addr8(Addr), - RegAddr64(Reg), - RegAddr32(Reg), - RegAddr16(Reg), - RegAddr8(Reg), - Reg(Reg), -} - -impl Dest { - /// The length of this destination in its instruction. - pub fn len(&self) -> usize { - match self { - Dest::Addr64(_) | Dest::Addr32(_) | Dest::Addr16(_) | Dest::Addr8(_) => 8, - Dest::RegAddr64(_) | Dest::RegAddr32(_) | Dest::RegAddr16(_) | Dest::RegAddr8(_) => 1, - Dest::Reg(_) => 1, - } - } - - /// The length of the value that this destination points to. - pub fn value_len(&self) -> usize { - match self { - Dest::Addr64(_) | Dest::RegAddr64(_) | Dest::Reg(_) => 8, - Dest::Addr32(_) | Dest::RegAddr32(_) => 4, - Dest::Addr16(_) | Dest::RegAddr16(_) => 2, - Dest::Addr8(_) | Dest::RegAddr8(_) => 1, - } - } -} - -// TODO : make this an enum - -pub const DEST_ADDR64: u8 = 0b0000; -pub const DEST_ADDR32: u8 = 0b0001; -pub const DEST_ADDR16: u8 = 0b0010; -pub const DEST_ADDR8: u8 = 0b0011; -pub const DEST_REG_ADDR64: u8 = 0b0100; -pub const DEST_REG_ADDR32: u8 = 0b0101; -pub const DEST_REG_ADDR16: u8 = 0b0110; -pub const DEST_REG_ADDR8: u8 = 0b0111; -/* immediates - not used, invalid */ -pub const DEST_REG: u8 = 0b1100; - -pub const SOURCE_ADDR64: u8 = 0b0000; -pub const SOURCE_ADDR32: u8 = 0b0001; -pub const SOURCE_ADDR16: u8 = 0b0010; -pub const SOURCE_ADDR8: u8 = 0b0011; -pub const SOURCE_REG_ADDR64: u8 = 0b0100; -pub const SOURCE_REG_ADDR32: u8 = 0b0101; -pub const SOURCE_REG_ADDR16: u8 = 0b0110; -pub const SOURCE_REG_ADDR8: u8 = 0b0111; -pub const SOURCE_IMM64: u8 = 0b1000; -pub const SOURCE_IMM32: u8 = 0b1001; -pub const SOURCE_IMM16: u8 = 0b1010; -pub const SOURCE_IMM8: u8 = 0b1011; -pub const SOURCE_REG: u8 = 0b1100; diff --git a/src/vm/mem.rs b/src/vm/mem.rs deleted file mode 100644 index 37a4c2e..0000000 --- a/src/vm/mem.rs +++ /dev/null @@ -1,278 +0,0 @@ -use crate::vm::{addr::*, error::*, inst::*, reg::*}; -use byteorder::{ReadBytesExt, WriteBytesExt, LE}; -use std::io::Cursor; - -pub struct MemCursor { - cursor: Cursor, -} - -impl MemCursor - where Cursor: ReadBytesExt, - T: AsRef<[u8]> -{ - pub fn new(mem: T) -> Self { - MemCursor { cursor: Cursor::new(mem) } - } - - pub fn position(&self) -> u64 { - self.cursor.position() - } - - pub fn set_position>(&mut self, position: P) { - self.cursor.set_position((position.into()).0) - } - - pub fn next_u8_unchecked(&mut self) -> u8 { - self.cursor.read_u8().unwrap() - } - - pub fn next_u8(&mut self) -> Result { - self.check_addr(self.position()) - .map(|_| self.next_u8_unchecked()) - } - - pub fn next_u16_unchecked(&mut self) -> u16 { - self.cursor.read_u16::().unwrap() - } - - pub fn next_u16(&mut self) -> Result { - self.check_addr(self.position()) - .map(|_| self.next_u16_unchecked()) - } - - pub fn next_u32_unchecked(&mut self) -> u32 { - self.cursor.read_u32::().unwrap() - } - - pub fn next_u32(&mut self) -> Result { - self.check_addr(self.position()) - .map(|_| self.next_u32_unchecked()) - } - - pub fn next_u64_unchecked(&mut self) -> u64 { - self.cursor.read_u64::().unwrap() - } - - pub fn next_u64(&mut self) -> Result { - self.check_addr(self.position()) - .map(|_| self.next_u64_unchecked()) - } - - pub fn next_addr(&mut self) -> Result { - self.check_addr(self.position()) - .map(|_| self.next_addr_unchecked()) - } - - pub fn next_addr_unchecked(&mut self) -> Addr { - Addr(self.next_u64_unchecked()) - } - - pub fn next_inst(&mut self) -> Result { - let start = self.position(); - let op = self.next_u16()?; - - macro_rules! dest_source { - ($variant:ident) => {{ - let (d, s) = self.next_dest_source()?; - Ok(Inst::$variant(d, s)) - }}; - } - macro_rules! source_source { - ($variant:ident) => {{ - let (s1, s2) = self.next_source_source()?; - Ok(Inst::$variant(s1, s2)) - }}; - } - macro_rules! source { - ($variant:ident) => {{ - let spec = (self.next_u8()? & 0xF0) >> 4; - let source = self.next_source(spec)?; - Ok(Inst::$variant(source)) - }}; - } - macro_rules! dest { - ($variant:ident) => {{ - let spec = (self.next_u8()? & 0xF0) >> 4; - let dest = self.next_dest(spec)?; - Ok(Inst::$variant(dest)) - }}; - } - let inst = match op { - ADD => dest_source!(Add), - SUB => dest_source!(Sub), - MUL => dest_source!(Mul), - DIV => dest_source!(Div), - IDIV => dest_source!(IDiv), - MOD => dest_source!(Mod), - AND => dest_source!(And), - OR => dest_source!(Or), - XOR => dest_source!(Xor), - SHL => dest_source!(Shl), - SHR => dest_source!(Shr), - INEG => dest_source!(INeg), - INV => dest_source!(Inv), - NOT => dest_source!(Not), - CMPEQ => source_source!(CmpEq), - CMPLT => source_source!(CmpLt), - JMP => source!(Jmp), - JZ => source!(Jz), - JNZ => source!(Jnz), - CALL => source!(Call), - RET => Ok(Inst::Ret), - PUSH => source!(Push), - POP => dest!(Pop), - MOV => dest_source!(Mov), - HALT => Ok(Inst::Halt), - NOP => Ok(Inst::Nop), - DUMP => Ok(Inst::Dump), - _ => Err(VmError::IllegalOp { op }), - }?; - let end = self.position(); - let len = (end - start) as usize; - assert_eq!(len, inst.len()); - Ok(inst) - } - - fn next_source_source(&mut self) -> Result<(Source, Source)> { - let spec = self.next_u8()?; - let s1_spec = (spec & 0xF0) >> 4; - let s2_spec = spec & 0x0F; - let s1 = self.next_source(s1_spec)?; - let s2 = self.next_source(s2_spec)?; - Ok((s1, s2)) - } - - fn next_dest_source(&mut self) -> Result<(Dest, Source)> { - let spec = self.next_u8()?; - let dest_spec = (spec & 0xF0) >> 4; - let source_spec = spec & 0x0F; - let dest = self.next_dest(dest_spec)?; - let source = self.next_source(source_spec)?; - Ok((dest, source)) - } - - fn next_dest(&mut self, spec: u8) -> Result { - match spec { - DEST_ADDR64 => Ok(Dest::Addr64(self.next_addr()?)), - DEST_ADDR32 => Ok(Dest::Addr32(self.next_addr()?)), - DEST_ADDR16 => Ok(Dest::Addr16(self.next_addr()?)), - DEST_ADDR8 => Ok(Dest::Addr8(self.next_addr()?)), - DEST_REG_ADDR64 => Ok(Dest::RegAddr64(self.next_reg()?)), - DEST_REG_ADDR32 => Ok(Dest::RegAddr32(self.next_reg()?)), - DEST_REG_ADDR16 => Ok(Dest::RegAddr16(self.next_reg()?)), - DEST_REG_ADDR8 => Ok(Dest::RegAddr8(self.next_reg()?)), - DEST_REG => Ok(Dest::Reg(self.next_reg()?)), - _ => Err(VmError::IllegalDestSpec { spec }), - } - } - - fn next_source(&mut self, spec: u8) -> Result { - match spec { - SOURCE_ADDR64 => Ok(Source::Addr64(self.next_addr()?)), - SOURCE_ADDR32 => Ok(Source::Addr32(self.next_addr()?)), - SOURCE_ADDR16 => Ok(Source::Addr16(self.next_addr()?)), - SOURCE_ADDR8 => Ok(Source::Addr8(self.next_addr()?)), - SOURCE_REG_ADDR64 => Ok(Source::RegAddr64(self.next_reg()?)), - SOURCE_REG_ADDR32 => Ok(Source::RegAddr32(self.next_reg()?)), - SOURCE_REG_ADDR16 => Ok(Source::RegAddr16(self.next_reg()?)), - SOURCE_REG_ADDR8 => Ok(Source::RegAddr8(self.next_reg()?)), - SOURCE_REG => Ok(Source::Reg(self.next_reg()?)), - SOURCE_IMM64 => Ok(Source::Imm(self.next_u64()?)), - SOURCE_IMM32 => Ok(Source::Imm(self.next_u32()? as u64)), - SOURCE_IMM16 => Ok(Source::Imm(self.next_u16()? as u64)), - SOURCE_IMM8 => Ok(Source::Imm(self.next_u8()? as u64)), - _ => Err(VmError::IllegalSourceSpec { spec }), - } - } - - fn next_reg(&mut self) -> Result { - let reg = self.next_u8()?; - if (reg as usize) >= NUM_REGS { - Err(VmError::IllegalReg { reg }) - } else { - Ok(reg) - } - } -} - -impl MemCursor - where T: AsRef<[u8]> -{ - fn check_addr(&self, addr: u64) -> Result<()> { - if addr > (self.cursor.get_ref().as_ref().len() as u64) { - Err(VmError::MemOutOfBounds { addr: Addr(addr) }) - } else { - Ok(()) - } - } -} - -impl MemCursor - where Cursor: WriteBytesExt, - T: AsRef<[u8]> -{ - pub fn write_u8_unchecked(&mut self, value: u8) { - self.cursor.write_u8(value).unwrap(); - } - - pub fn write_u8(&mut self, value: u8) -> Result<()> { - self.check_addr(self.position()) - .map(|_| self.write_u8_unchecked(value)) - } - - pub fn write_u16_unchecked(&mut self, value: u16) { - self.cursor.write_u16::(value).unwrap(); - } - - pub fn write_u16(&mut self, value: u16) -> Result<()> { - self.check_addr(self.position()) - .map(|_| self.write_u16_unchecked(value)) - } - - pub fn write_u32_unchecked(&mut self, value: u32) { - self.cursor.write_u32::(value).unwrap(); - } - - pub fn write_u32(&mut self, value: u32) -> Result<()> { - self.check_addr(self.position()) - .map(|_| self.write_u32_unchecked(value)) - } - - pub fn write_u64_unchecked(&mut self, value: u64) { - self.cursor.write_u64::(value).unwrap(); - } - - pub fn write_u64(&mut self, value: u64) -> Result<()> { - self.check_addr(self.position()) - .map(|_| self.write_u64_unchecked(value)) - } -} - -/* -//////////////////////////////////////////////////////////////////////////////// -// Index impl -//////////////////////////////////////////////////////////////////////////////// -impl> Index for MemCursor { - type Output = u8; - - fn index(&self, addr: usize) -> &Self::Output { - self.mem.as_ref().index(addr) - } -} - -impl> Index for MemCursor { - type Output = u8; - - fn index(&self, addr: u64) -> &Self::Output { - self.index(addr as usize) - } -} - -impl> Index for MemCursor { - type Output = u8; - - fn index(&self, addr: Addr) -> &Self::Output { - self.index(addr.0) - } -} -*/ diff --git a/src/vm/mod.rs b/src/vm/mod.rs deleted file mode 100644 index dc4270d..0000000 --- a/src/vm/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod addr; -pub mod error; -pub mod flags; -pub mod inst; -pub mod mem; -pub mod obj; -pub mod reg; -pub mod state; diff --git a/src/vm/obj/assemble.rs b/src/vm/obj/assemble.rs deleted file mode 100644 index 1a62f47..0000000 --- a/src/vm/obj/assemble.rs +++ /dev/null @@ -1,360 +0,0 @@ -pub mod error; -pub mod session; -mod includes; -mod names; - -use self::{error::*, session::AsmSession}; -use crate::vm::{ - addr::Addr, - inst, - obj::{ - obj::{self, Object}, - syn::ast::*, - } -}; -use byteorder::{WriteBytesExt, LE}; -use std::{collections::HashMap, path::Path}; - -pub trait Asm { - type Out; - fn assemble(&self, asm: &mut AsmSession) -> Result; -} - -pub fn assemble_path(path: impl AsRef) -> Result { - let mut session = AsmSession::default(); - session.include_path(path)?; - session.assemble() -} - -impl Asm for Vec<&'_ Directive> { - type Out = obj::Object; - fn assemble(&self, asm: &mut AsmSession) -> Result { - let sections = self - .iter() - .filter_map(|section| section.assemble(asm).transpose()) - .collect::>()?; - Ok(obj::Object { - version: obj::OBJ_VERSION, - sections, - }) - } -} - -impl Asm for Directive { - type Out = Option; - - fn assemble(&self, asm: &mut AsmSession) -> Result { - match self { - Directive::Data(section) => Ok(Some(obj::Section::Data(section.assemble(asm)?))), - Directive::Meta(section) => section.assemble(asm).map(Some), - Directive::Include(_) => { Ok(None) } - } - } -} - -impl Asm for DataSection { - type Out = obj::DataSection; - - fn assemble(&self, session: &mut AsmSession) -> Result { - let names = names::get_section_names(self)?; - session.name_stack.push(names); - let section_len = self.len() as u64; - let (start, end) = match self.org { - SectionOrg::Start(start) => (start, start + (section_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 { - return Err(AsmError::SectionTooShort { - section_end: end, - section_size: start + section_len, - }); - } - - let mut contents = Vec::with_capacity(section_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, - "in section {}", - self.name - ); - session.name_stack.pop(); - Ok(obj::DataSection { - name: self.name.clone(), - start, - len: section_len, - contents, - }) - } -} - -impl Asm for MetaSection { - type Out = obj::Section; - - fn assemble(&self, session: &mut AsmSession) -> Result { - let mut entries = HashMap::new(); - for line in self.lines.iter() { - if entries.contains_key(&line.name) { - return Err(AsmError::DuplicateMetaName { - name: line.name.to_string(), - }); - } - let value = match &line.value { - Value::Int(i) => *i, - Value::Name(s) => session.lookup_name(s.as_str()) - .ok_or_else(|| AsmError::UnknownName { name: s.to_string() })?.addr.0, - Value::Reg(_) | Value::Here | Value::Addr(_, _) => { - return Err(AsmError::IllegalMetaValue { - name: line.name.to_string(), - value: line.value.clone(), - }) - } // TODO : - // * deref constexpr? - // * pre-startup static init? - }; - entries.insert(line.name.to_string(), value); - } - Ok(obj::Section::Meta(obj::MetaSection { entries })) - } -} - -impl Asm for DataLine { - type Out = Vec; - - fn assemble(&self, session: &mut AsmSession) -> Result { - match self { - DataLine::ValueDef(v) => v.assemble(session), - DataLine::Inst(i) => i.assemble(session), - DataLine::Export(_) | DataLine::Label(_) => Ok(Vec::new()), - } - } -} - -impl Asm for ValueDef { - type Out = Vec; - - fn assemble(&self, _: &mut AsmSession) -> Result { - match self { - ValueDef::Int(x, s) => Ok(x.to_le_bytes().iter().copied().take(s.len()).collect()), - ValueDef::String(s) => { - let bytes = s.bytes(); - let mut out = s.len().to_le_bytes().to_vec(); - out.extend(bytes); - Ok(out) - } - ValueDef::ZString(z) => { - let bytes = z.bytes(); - let mut out = z.len().to_le_bytes().to_vec(); - out.extend(bytes); - Ok(out) - } - } - } -} - -impl Asm for Inst { - type Out = Vec; - - fn assemble(&self, session: &mut AsmSession) -> Result { - let len = self.len(); - - macro_rules! map_inst { - ($op:expr, $dest:expr, $source:expr) => {{ - let mut bytes = Vec::with_capacity(len); - bytes.write_u16::($op).unwrap(); - let dest = $dest; - let dest_encoding = - dest.dest_encoding() - .ok_or_else(|| AsmError::IllegalDestValue { - value: dest.clone(), - })?; - let source = $source; - let source_encoding = source.source_encoding(); - bytes - .write_u8((dest_encoding << 4) | source_encoding) - .unwrap(); - bytes.extend(dest.assemble(session)?); - bytes.extend(source.assemble(session)?); - assert_eq!( - self.len(), - bytes.len(), - "instruction size mismatch in {} instruction - {:?} produces these bytes {:?}", - stringify!($op), - self, - bytes - ); - Ok(bytes) - }}; - - ($op:expr, $source:expr) => {{ - let mut bytes = Vec::with_capacity(len); - bytes.write_u16::($op).unwrap(); - let source = $source; - let source_encoding = source.source_encoding() << 4; - bytes.write_u8(source_encoding).unwrap(); - bytes.extend(source.assemble(session)?); - assert_eq!( - self.len(), - bytes.len(), - "instruction size mismatch in {} instruction - {:?} produces these bytes {:?}", - stringify!($op), - self, - bytes - ); - Ok(bytes) - }}; - - ($op:expr) => {{ - let mut bytes = Vec::with_capacity(len); - bytes.write_u16::($op).unwrap(); - assert_eq!( - self.len(), - bytes.len(), - "instruction size mismatch in {} instruction - {:?} produces these bytes {:?}", - stringify!($op), - self, - bytes - ); - Ok(bytes) - }}; - } - match self { - Inst::Add(v1, v2) => map_inst!(inst::ADD, v1, v2), - Inst::Sub(v1, v2) => map_inst!(inst::SUB, v1, v2), - Inst::Mul(v1, v2) => map_inst!(inst::MUL, v1, v2), - Inst::Div(v1, v2) => map_inst!(inst::DIV, v1, v2), - Inst::IDiv(v1, v2) => map_inst!(inst::IDIV, v1, v2), - Inst::Mod(v1, v2) => map_inst!(inst::MOD, v1, v2), - Inst::And(v1, v2) => map_inst!(inst::AND, v1, v2), - Inst::Or(v1, v2) => map_inst!(inst::OR, v1, v2), - Inst::Xor(v1, v2) => map_inst!(inst::XOR, v1, v2), - Inst::Shl(v1, v2) => map_inst!(inst::SHL, v1, v2), - Inst::Shr(v1, v2) => map_inst!(inst::SHR, v1, v2), - Inst::INeg(v1, v2) => map_inst!(inst::INEG, v1, v2), - Inst::Inv(v1, v2) => map_inst!(inst::INV, v1, v2), - Inst::Not(v1, v2) => map_inst!(inst::NOT, v1, v2), - // TODO/BUG: CmpEq and CmpLt both take two sources instead of a source and destination - Inst::CmpEq(v1, v2) => map_inst!(inst::CMPEQ, v1, v2), - Inst::CmpLt(v1, v2) => map_inst!(inst::CMPLT, v1, v2), - Inst::Jmp(v) => map_inst!(inst::JMP, v), - Inst::Jz(v) => map_inst!(inst::JZ, v), - Inst::Jnz(v) => map_inst!(inst::JNZ, v), - Inst::Call(v) => map_inst!(inst::CALL, v), - Inst::Ret => map_inst!(inst::RET), - Inst::Push(v) => map_inst!(inst::PUSH, v), - Inst::Pop(dest) => { - let mut bytes = Vec::with_capacity(len); - bytes.write_u16::(inst::POP).unwrap(); - let dest_encoding = dest.source_encoding() << 4; - bytes.write_u8(dest_encoding).unwrap(); - bytes.extend(dest.assemble(session)?); - assert_eq!( - self.len(), - bytes.len(), - "instruction size mismatch in inst::PUSH instruction - {:?} produces these bytes {:?}", - self, - bytes - ); - Ok(bytes) - } - Inst::Mov(v1, v2) => map_inst!(inst::MOV, v1, v2), - Inst::Halt => map_inst!(inst::HALT), - Inst::Nop => map_inst!(inst::NOP), - Inst::Dump => map_inst!(inst::DUMP), - } - } -} - -impl Asm for Value { - type Out = Vec; - - fn assemble(&self, session: &mut AsmSession) -> Result { - match self { - Value::Int(i) => Ok(i.to_le_bytes().to_vec()), - Value::Reg(r) => Ok(vec![*r]), - Value::Name(name) => { - let value = session.lookup_name(name.as_str()) - .ok_or_else(|| AsmError::UnknownName { name: name.to_string() })?; - Ok(value.addr.0.to_le_bytes().to_vec()) - } - Value::Here => Ok(session.pos.0.to_le_bytes().to_vec()), - Value::Addr(v, _) => { - if let Value::Addr(_, _) = &**v { - // double deref is not allowed - todo!() - } else { - v.assemble(session) - } - } - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_inst_len() { - let mut session = AsmSession::default(); - //asm.names - //.push(vec![("test".to_string(), Addr(0u64))].into_iter().collect()); - - macro_rules! assert_len { - ($inst:expr) => {{ - let inst = $inst; - let asm_size = $inst.assemble(&mut session).unwrap().len(); - assert_eq!(inst.len(), asm_size, "Instruction {:?}.len() indicates it should be {} bytes long but was assembled as {} bytes", inst, inst.len(), asm_size); - }} - } - - use Inst::*; - - let dummy_dests = &[ - Value::Reg(0), - Value::Addr(Box::new(Value::Reg(0)), IntSize::U8), - Value::Addr(Box::new(Value::Here), IntSize::U16), - //Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32), - Value::Addr(Box::new(Value::Int(0)), IntSize::U64), - ]; - - let dummy_sources = &[ - Value::Int(0), - Value::Reg(0), - //Value::Name("test".to_string()), - Value::Here, - Value::Addr(Box::new(Value::Reg(0)), IntSize::U8), - Value::Addr(Box::new(Value::Here), IntSize::U16), - //Value::Addr(Box::new(Value::Name("test".to_string())), IntSize::U32), - Value::Addr(Box::new(Value::Int(0)), IntSize::U32), - ]; - - for v1 in dummy_dests { - for v2 in dummy_sources { - assert_len!(Add(v1.clone(), v2.clone())); - assert_len!(Sub(v1.clone(), v2.clone())); - assert_len!(Mul(v1.clone(), v2.clone())); - assert_len!(Div(v1.clone(), v2.clone())); - assert_len!(Mod(v1.clone(), v2.clone())); - assert_len!(And(v1.clone(), v2.clone())); - assert_len!(Or(v1.clone(), v2.clone())); - assert_len!(Xor(v1.clone(), v2.clone())); - assert_len!(Shl(v1.clone(), v2.clone())); - assert_len!(Shr(v1.clone(), v2.clone())); - assert_len!(INeg(v1.clone(), v2.clone())); - assert_len!(Inv(v1.clone(), v2.clone())); - assert_len!(Not(v1.clone(), v2.clone())); - assert_len!(Mov(v1.clone(), v2.clone())); - // TODO more length tests - } - } - } -} diff --git a/src/vm/obj/assemble/error.rs b/src/vm/obj/assemble/error.rs deleted file mode 100644 index 3a5ad91..0000000 --- a/src/vm/obj/assemble/error.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::vm::obj::syn::ast::*; -use snafu::Snafu; -use std::path::PathBuf; - -pub type LexError = lrpar::LexError; -pub type ParseError = lrpar::ParseError; -pub type LexParseError = lrpar::LexParseError; - -#[derive(Debug, Snafu)] -pub enum AsmError { - #[snafu(display("unknown name: {}", name))] - UnknownName { - name: String, - }, - - #[snafu(display("unknown export name: {}", name))] - UnknownExport { - name: String, - }, - - #[snafu(display("duplicate label definition: {}", name))] - DuplicateLabel { - name: String, - }, - - #[snafu(display("duplicate meta entry name: {}", name))] - DuplicateMetaName { - name: String, - }, - - #[snafu(display("illegal meta value for entry name {}: {:?}", name, value))] - IllegalMetaValue { - name: String, - value: Value, - }, - - #[snafu(display("duplicate exported name: {}", name))] - DuplicateExport { - name: String, - }, - - #[snafu(display("section start ({:#x}) is greater than end ({:#x})", start, end))] - StartGreaterThanEnd { - start: u64, - end: u64, - }, - - #[snafu(display( - "section end ({:#x}) too short for section content size ({:#x})", - section_end, - section_size - ))] - SectionTooShort { - section_end: u64, - section_size: u64, - }, - - #[snafu(display("illegal instruction destination value: {:?}", value))] - IllegalDestValue { - value: Value, - }, - - #[snafu(display("deref of a deref value is not allowed"))] - DoubleDeref { - value: Value, - }, - - // TODO(asm) : Path error wrapper for assembling things - #[snafu(display("could not read path: {}", path.display()))] - BadPath { - path: PathBuf, - }, - - Syntax { - source: SyntaxError, - }, -} - -#[derive(Debug, Snafu)] -pub enum SyntaxError { - Lex { source: LexError }, - Parse { source: ParseError }, - Multi { errors: Vec }, -} - -impl From for SyntaxError { - fn from(source: LexError) -> Self { - SyntaxError::Lex { source } - } -} - -impl From for SyntaxError { - fn from(source: ParseError) -> Self { - SyntaxError::Parse { source } - } -} - -impl From> for SyntaxError { - fn from(errors: Vec) -> Self { - SyntaxError::Multi { errors } - } -} - -impl From for SyntaxError { - fn from(source: LexParseError) -> Self { - match source { - LexParseError::LexError(e) => SyntaxError::Lex { source: e }, - LexParseError::ParseError(e) => SyntaxError::Parse { source: e }, - } - } -} - -pub type Result = std::result::Result; - diff --git a/src/vm/obj/assemble/includes.rs b/src/vm/obj/assemble/includes.rs deleted file mode 100644 index c67a807..0000000 --- a/src/vm/obj/assemble/includes.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::vm::obj::{ - assemble::{error::*, session::AsmSession, Asm}, - syn::{ast::Directive, lexer, parser}, -}; -use std::{path::PathBuf, rc::Rc}; - -#[derive(Debug, Clone)] -pub struct GetIncludes { - path: PathBuf, -} - -impl GetIncludes { - pub fn assemble_from_path(path: PathBuf, session: &mut AsmSession) -> Result<()> { - let path = path - .canonicalize() - .map_err(|_| AsmError::BadPath { path })?; - GetIncludes { path }.assemble(session) - } -} - -impl Asm for GetIncludes { - type Out = (); - - fn assemble(&self, session: &mut AsmSession) -> Result { - assert!(self.path.is_absolute()); - if session.includes.contains_key(&self.path) { - return Ok(()); - } - - let text = std::fs::read_to_string(&self.path).map_err(|_| AsmError::BadPath { - path: self.path.clone(), - })?; - - let lexerdef = lexer::lexerdef(); - let lexer = lexerdef.lexer(&text); - let (res, errors) = parser::parse(&lexer); - - if !errors.is_empty() { - return Err(AsmError::Syntax { - source: errors.into(), - }); - } - - // insert a dummy AST in the includes and replace it when we're done with the actual AST - Rc::get_mut(&mut session.includes) - .unwrap() - .insert(self.path.clone(), Default::default()); - session.include_stack.push(self.path.clone()); - let ast = res.unwrap(); - for directive in ast.iter() { - if let Directive::Include(include_path) = directive { - GetIncludes::assemble_from_path(PathBuf::from(include_path), session)?; - } - } - session.include_stack.pop(); - - let dummy = Rc::get_mut(&mut session.includes) - .unwrap() - .insert(self.path.clone(), ast) - .expect("ast was removed after its inclusion (why did you do that?)"); - assert!( - dummy.is_empty(), - "ast was modified after its inclusion (why did you do that?)" - ); - - Ok(()) - } -} diff --git a/src/vm/obj/assemble/names.rs b/src/vm/obj/assemble/names.rs deleted file mode 100644 index 8f75052..0000000 --- a/src/vm/obj/assemble/names.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::vm::{ - addr::Addr, - obj::{ - assemble::{ - session::AsmSession, - error::*, - }, - syn::ast::{DataSection, DataLine, Directive}, - }, -}; -use std::{collections::{HashMap, HashSet}, rc::Rc}; - -// TODO(asm) make custom Names type that has "merge" that will catch errors with duplicate names -pub type Names = HashMap; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Name { - pub name: String, - pub addr: Addr, - pub export: bool, -} - -pub fn get_section_names(section: &DataSection) -> Result { - let mut pos = Addr(section.org.start()); - let mut names = HashMap::new(); - let mut exports = HashSet::new(); - - // This isn't immediately straightforward in code, so this is what's happening. - // - // A name may be specified exactly once. It is added to the "names" mapping. If the name is - // specified again, it is a duplicate error and handled as such. A name may be flagged as - // being exported. - // - // Exports are gathered at the beginning into a set. Afterwards, as name definitions - // are gathered, exports are removed from their set if they exist. Since duplicate names - // cause an error, export names will only be removed once. - // - // At the end of name gathering, if any exports have not been removed, then we know those - // are exports whose names are undefined and we can return an UnknownExport error. - - // get exported names - for line in section.lines.iter() { - if let DataLine::Export(name) = line { - exports.insert(name); - } - } - - // get names - for line in section.lines.iter() { - if let DataLine::Label(name) = line { - if names.contains_key(name) { - return Err(AsmError::DuplicateLabel { name: name.clone() }); - } - let export = exports.remove(name); - - names.insert(name.clone(), Name { - name: name.clone(), - addr: pos, - export, - }); - } - pos += line.len(); - } - - // all exports map 1:1 with names - if exports.is_empty() { - Ok(names) - } else { - Err(AsmError::UnknownExport { name: exports.iter().next().unwrap().to_string() }) - } -} - -pub fn get_exports(session: &mut AsmSession) -> Result { - let includes = Rc::clone(&session.includes); - let mut all_exports = Vec::new(); - - // get *all* exports first - for (_, ast) in includes.iter() { - for directive in ast.iter() { - if let Directive::Data(section) = directive { - let names: HashMap<_, _> = get_section_names(section)? - .into_iter() - .filter(|(_, name)| name.export) - .collect(); - all_exports.push(names); - } - } - } - - let mut exports = HashSet::new(); - - // make a set of all export names, erroring on duplicate export - for name_map in all_exports.iter() { - let names_set: HashSet<_> = name_map.keys().collect(); - if let Some(dupe) = exports.intersection(&names_set).next() { - return Err(AsmError::DuplicateExport { name: dupe.to_string() }); - } - exports.extend(names_set); - } - - // NOTE: this can probably be done with a fancy combinator chain - Ok(all_exports.into_iter() - .fold(Names::new(), |mut acc, val| { acc.extend(val); acc })) -} diff --git a/src/vm/obj/assemble/session.rs b/src/vm/obj/assemble/session.rs deleted file mode 100644 index 80e8d16..0000000 --- a/src/vm/obj/assemble/session.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::vm::{ - addr::Addr, - obj::{ - assemble::{ - Asm, - includes::GetIncludes, - names::{self, Name, Names}, - error::*, - }, - obj::Object, - syn::ast::Ast, - }, -}; -use std::{ - collections::BTreeMap, - path::{Path, PathBuf}, - rc::Rc, -}; - -/// A shared session for the assembler. -#[derive(Debug, Default)] -pub struct AsmSession { - pub (in super) includes: Rc>, - pub (in super) include_search_paths: Vec, - pub (in super) include_stack: Vec, - pub (in super) name_stack: Vec, - pub (in super) pos: Addr, -} - -impl AsmSession { - pub fn assemble(&mut self) -> Result { - let includes = Rc::clone(&self.includes); - let sections: Vec<_> = includes.iter() - .flat_map(|(_, ast)| ast) - .collect(); - sections.assemble(self) - } - - pub fn include_path(&mut self, path: impl AsRef) -> Result<()> { - self.include_stack.clear(); - let path = path.as_ref().to_path_buf(); - - GetIncludes::assemble_from_path(path, self)?; - let exports = names::get_exports(self)?; - // TODO(asm) - merge exports - self.name_stack.push(exports); - Ok(()) - } - - pub (in super) fn current_include_path(&self) -> Option<&Path> { - self.include_stack.last().map(PathBuf::as_path) - } - - pub (in super) fn resolve_include_path(&self, path: impl AsRef) -> Option { - let path = path.as_ref(); - self.current_include_path() - .and_then(|last_path| last_path.parent()) - .map(|last_dir| last_dir.join(path)) - .or_else(|| self.include_search_paths - .iter() - .filter_map(|include| include.join(path).canonicalize().ok()) - .next()) - } - - pub fn lookup_name(&self, name: &str) -> Option<&Name> { - self.name_stack - .iter() - .rev() - .filter_map(|names| names.get(name)) - .next() - } -} diff --git a/src/vm/obj/error.rs b/src/vm/obj/error.rs deleted file mode 100644 index ed45922..0000000 --- a/src/vm/obj/error.rs +++ /dev/null @@ -1,45 +0,0 @@ -use snafu::Snafu; -use std::{fmt::Debug, io}; - -#[derive(Debug, Snafu)] -pub enum ParseError { - #[snafu(display("IO error: {}", source))] - Io { source: io::Error }, - - #[snafu(display("wrong magic number"))] - WrongMagic, - - #[snafu(display("unknown section kind: 0x{:02x}", kind))] - UnknownSectionKind { kind: u8 }, - - #[snafu(display("invalid UTF-8 string: {}", source))] - InvalidUtf8String { source: std::string::FromUtf8Error }, - - #[snafu(display("duplicate symbol name: {}", name))] - DuplicateName { name: String }, - - #[snafu(display("duplicate exported symbol name: {}", name))] - DuplicateExportName { name: String }, -} - -macro_rules! into_parse_error { - ( - $($type:ty : $variant:ident),* $(,)? - ) => { - $( - impl From<$type> for ParseError { - fn from(other: $type) -> Self { - ParseError::$variant { source: other } - } - } - )* - } -} - -into_parse_error! { - io::Error: Io, - std::string::FromUtf8Error: InvalidUtf8String, -} - -pub type Result = std::result::Result; - diff --git a/src/vm/obj/mod.rs b/src/vm/obj/mod.rs deleted file mode 100644 index b7c4760..0000000 --- a/src/vm/obj/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod assemble; -pub mod error; -pub mod obj; -pub mod syn; diff --git a/src/vm/obj/obj.rs b/src/vm/obj/obj.rs deleted file mode 100644 index 9c35a4c..0000000 --- a/src/vm/obj/obj.rs +++ /dev/null @@ -1,269 +0,0 @@ -use crate::vm::obj::error::{ParseError, Result}; -use byteorder::{ReadBytesExt, WriteBytesExt, LE}; -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - fmt::Debug, - io::{Cursor, Read, Write}, -}; - -pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11; -pub const OBJ_VERSION: u32 = 0; -const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4 - -#[derive(Debug, Clone, PartialEq)] -pub struct Object { - pub version: u32, - pub sections: Vec
, -} - -impl Object { - pub fn to_bytes(&self) -> Vec { - let mut cursor = Cursor::new(Vec::new()); - cursor.write_u64::(MAGIC).unwrap(); - cursor.write_u32::(OBJ_VERSION).unwrap(); - cursor.write_u32::(self.sections.len() as u32).unwrap(); - for section in self.sections.iter() { - cursor.write(§ion.to_bytes()).unwrap(); - } - cursor.into_inner() - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - let magic = cursor.read_u64::()?; - if magic != MAGIC { - return Err(ParseError::WrongMagic); - } - let version = cursor.read_u32::()?; - let section_count = cursor.read_u32::()?; - - let mut sections = Vec::new(); - for _ in 0..section_count { - let start = cursor.position() as usize; - let section = Section::from_bytes(&bytes[start..])?; - cursor.set_position((start + section.len()) as u64); - sections.push(section); - } - Ok(Object { version, sections }) - } - - pub fn virtual_len(&self) -> usize { - self.sections - .iter() - .map(|s| match s { - Section::Data(DataSection { start, len, .. }) => (start + len) as usize, - Section::Meta { .. } => 0, - }) - .max() - .unwrap_or(0) - } -} - -macro_rules! section_kind { - ( - pub enum $enum_name:ident { - $($name:ident = $value:expr),* $(,)? - } - ) => { - - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - #[repr(u8)] - pub enum $enum_name { - $($name = $value),* - } - - impl TryFrom for SectionKind { - type Error = ParseError; - - fn try_from(other: u8) -> std::result::Result { - match other { - $( - $value => Ok($enum_name::$name), - )* - _ => Err(ParseError::UnknownSectionKind { kind: other }), - } - } - } - - impl From for u8 { - fn from(other: SectionKind) -> Self { - match other { - $( - $enum_name::$name => $value, - )* - } - } - } - }; -} - -section_kind! { - pub enum SectionKind { - Data = 0x00, - Meta = 0xFF, - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum Section { - Data(DataSection), - Meta(MetaSection), -} - -impl Section { - pub fn len(&self) -> usize { - match self { - Section::Data(s) => { 1 + 8 + s.len() }, - Section::Meta(s) => { 1 + 8 + s.len() }, - } - } - - pub fn to_bytes(&self) -> Vec { - let mut cursor = Cursor::new(Vec::new()); - let bytes = match self { - Section::Data(s) => { - cursor.write_u8(SectionKind::Data.into()).unwrap(); - s.to_bytes() - } - Section::Meta(s) => { - cursor.write_u8(SectionKind::Meta.into()).unwrap(); - s.to_bytes() - }, - }; - cursor.write_u64::(bytes.len() as u64).unwrap(); - cursor.write(&bytes).unwrap(); - cursor.into_inner() - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - let kind: SectionKind = cursor.read_u8()?.try_into()?; - let len = cursor.read_u64::()?; - let start = cursor.position() as usize; - let end = start + len as usize; - - let bytes = &cursor.get_ref()[start..end]; - match kind { - SectionKind::Data => Ok(Section::Data(DataSection::from_bytes(bytes)?)), - SectionKind::Meta => Ok(Section::Meta(MetaSection::from_bytes(bytes)?)), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct DataSection { - pub name: String, - pub start: u64, - pub len: u64, - pub contents: Vec, -} - -impl DataSection { - pub fn len(&self) -> usize { - 2 + self.name.as_bytes().len() + 8 + 8 + self.contents.len() - } - - pub fn to_bytes(&self) -> Vec { - let mut cursor = Cursor::new(Vec::new()); - assert!(self.name.len() < u16::max_value() as usize); - cursor.write_u16::(self.name.len() as u16).unwrap(); - cursor.write(self.name.as_bytes()).unwrap(); - cursor.write_u64::(self.start).unwrap(); - cursor.write_u64::(self.len).unwrap(); - cursor.write(&self.contents).unwrap(); - cursor.into_inner() - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - - let name_len = cursor.read_u16::()? as usize; - let name_start = cursor.position() as usize; - let name_end = name_start + name_len; - let name_bytes = &bytes[name_start .. name_end]; - let name_string = String::from_utf8(name_bytes.to_vec())?; - cursor.set_position(name_end as u64); - - let start = cursor.read_u64::()?; - let len = cursor.read_u64::()?; - - let contents = &bytes[cursor.position() as usize..]; - Ok(DataSection { - name: name_string, - start, - len, - contents: From::from(contents), - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct MetaSection { - pub entries: HashMap, -} - -impl MetaSection { - pub fn len(&self) -> usize { - 8 + self.entries.iter() - .map(|(k, _)| 8 + k.as_bytes().len() + 8) - .sum::() - } - - pub fn to_bytes(&self) -> Vec { - let mut cursor = Cursor::new(Vec::new()); - cursor.write_u64::(self.entries.len() as u64).unwrap(); - for (k, v) in self.entries.iter() { - let key_len = k.as_bytes().len(); - cursor.write_u64::(key_len as u64).unwrap(); - cursor.write(k.as_bytes()).unwrap(); - cursor.write_u64::(*v).unwrap(); - } - cursor.into_inner() - } - - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - let entry_count = cursor.read_u64::()?; - let mut entries = HashMap::new(); - for _ in 0..entry_count { - // key - let key_len = cursor.read_u64::()?; - let mut key_bytes = vec![0u8; key_len as usize]; - cursor.read_exact(&mut key_bytes)?; - let key = String::from_utf8(key_bytes)?; - - // value - let value = cursor.read_u64::()?; - entries.insert(key, value); - } - Ok(MetaSection { entries }) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_to_from_bytes() { - let obj = Object { - version: OBJ_VERSION, - sections: vec![ - Section::Data(DataSection { - name: "data".to_string(), - start: 0, - len: 16, - contents: vec!(0u8; 16), - }), - Section::Meta(MetaSection { - entries: Default::default(), - }) - ], - }; - - let obj_bytes = obj.to_bytes(); - let converted = Object::from_bytes(&obj_bytes).unwrap(); - assert_eq!(obj, converted); - } -} diff --git a/src/vm/obj/syn/ast.rs b/src/vm/obj/syn/ast.rs deleted file mode 100644 index 2280b64..0000000 --- a/src/vm/obj/syn/ast.rs +++ /dev/null @@ -1,255 +0,0 @@ -use crate::vm::{ - inst, - reg::Reg, -}; - -pub type Ast = Vec; - -#[derive(Debug, Clone)] -pub enum Directive { - Meta(MetaSection), - Data(DataSection), - Include(String), -} - -#[derive(Debug, Clone)] -pub struct MetaSection { - pub lines: Vec, -} - -#[derive(Debug, Clone)] -pub struct MetaLine { - pub name: String, - pub value: Value, -} - -#[derive(Debug, Clone)] -pub struct DataSection { - pub name: String, - pub org: SectionOrg, - pub lines: Vec, -} - -impl DataSection { - pub fn exports(&self) -> impl Iterator { - self.lines.iter() - .filter_map(|line| if let DataLine::Export(s) = line { - Some(s.as_str()) - } else { - None - }) - } - - pub fn len(&self) -> usize { - self.lines.iter() - .map(DataLine::len) - .sum() - } -} - -#[derive(Debug, Clone)] -pub enum SectionOrg { - Start(u64), - StartEnd(u64, u64), -} - -impl SectionOrg { - pub fn start(&self) -> u64 { - match self { - SectionOrg::Start(start) | SectionOrg::StartEnd(start, _) => *start, - } - } -} - -#[derive(Debug, Clone)] -pub enum DataLine { - ValueDef(ValueDef), - Inst(Inst), - Export(String), - Label(String), -} - -impl DataLine { - pub fn len(&self) -> usize { - match self { - DataLine::ValueDef(v) => v.len(), - DataLine::Inst(i) => i.len(), - DataLine::Export(_) | DataLine::Label(_) => 0, - } - } -} - -#[derive(Debug, Clone)] -pub enum ValueDef { - Int(u64, IntSize), - String(String), - ZString(String), -} - -impl ValueDef { - pub fn len(&self) -> usize { - match self { - ValueDef::Int(_, s) => s.len(), - ValueDef::String(s) => 8 + s.as_bytes().len(), - ValueDef::ZString(s) => s.as_bytes().len() + 1, - } - } -} - -#[derive(Debug, Clone)] -pub enum Value { - // TODO : immediate int sizes - // Int(u64, IntSize) - Int(u64), - Reg(Reg), - Name(String), - Here, - Addr(Box, IntSize), -} - -impl Value { - pub fn len(&self) -> usize { - match self { - Value::Int(_) => 8, - Value::Reg(_) => 1, - Value::Name(_) => 8, - Value::Here => 8, - Value::Addr(v, _) => v.len(), - } - } - - pub fn dest_encoding(&self) -> Option { - match self { - Value::Int(_) | Value::Name(_) | Value::Here => None, - Value::Reg(_) => Some(inst::DEST_REG), - // TODO : check reg vs int value, and use dest_reg_addr8/16/32/64 values - Value::Addr(v, size) => { - if let Value::Reg(_) = &**v { - match size { - IntSize::U64 => Some(inst::DEST_REG_ADDR64), - IntSize::U32 => Some(inst::DEST_REG_ADDR32), - IntSize::U16 => Some(inst::DEST_REG_ADDR16), - IntSize::U8 => Some(inst::DEST_REG_ADDR8), - } - } else { - match size { - IntSize::U64 => Some(inst::DEST_ADDR64), - IntSize::U32 => Some(inst::DEST_ADDR32), - IntSize::U16 => Some(inst::DEST_ADDR16), - IntSize::U8 => Some(inst::DEST_ADDR8), - } - } - } - } - } - - pub fn source_encoding(&self) -> u8 { - match self { - Value::Int(_) => inst::SOURCE_IMM64, - Value::Reg(_) => inst::SOURCE_REG, - // TODO : check reg vs int value, and use source_reg_addr8/16/32/64 values - Value::Name(_) | Value::Here => inst::SOURCE_IMM64, - Value::Addr(v, size) => { - if let Value::Reg(_) = &**v { - match size { - IntSize::U64 => inst::SOURCE_REG_ADDR64, - IntSize::U32 => inst::SOURCE_REG_ADDR32, - IntSize::U16 => inst::SOURCE_REG_ADDR16, - IntSize::U8 => inst::SOURCE_REG_ADDR8, - } - } else { - match size { - IntSize::U64 => inst::SOURCE_ADDR64, - IntSize::U32 => inst::SOURCE_ADDR32, - IntSize::U16 => inst::SOURCE_ADDR16, - IntSize::U8 => inst::SOURCE_ADDR8, - } - } - } - } - } -} - -#[derive(Debug, Clone)] -pub enum IntSize { - U8, - U16, - U32, - U64, -} - -impl IntSize { - pub fn len(&self) -> usize { - match self { - IntSize::U8 => 1, - IntSize::U16 => 2, - IntSize::U32 => 4, - IntSize::U64 => 8, - } - } -} - -#[derive(Debug, Clone)] -pub enum Inst { - Add(Value, Value), - Sub(Value, Value), - Mul(Value, Value), - Div(Value, Value), - IDiv(Value, Value), - Mod(Value, Value), - And(Value, Value), - Or(Value, Value), - Xor(Value, Value), - Shl(Value, Value), - Shr(Value, Value), - INeg(Value, Value), - Inv(Value, Value), - Not(Value, Value), - CmpEq(Value, Value), - CmpLt(Value, Value), - Jmp(Value), - Jz(Value), - Jnz(Value), - Call(Value), - Ret, - Push(Value), - Pop(Value), - Mov(Value, Value), - Halt, - Nop, - Dump, -} - -impl Inst { - pub fn len(&self) -> usize { - match self { - Inst::Add(v1, v2) - | Inst::Sub(v1, v2) - | Inst::Mul(v1, v2) - | Inst::Div(v1, v2) - | Inst::IDiv(v1, v2) - | Inst::Mod(v1, v2) - | Inst::And(v1, v2) - | Inst::Or(v1, v2) - | Inst::Xor(v1, v2) - | Inst::Shl(v1, v2) - | Inst::Shr(v1, v2) - | Inst::INeg(v1, v2) - | Inst::Inv(v1, v2) - | Inst::Not(v1, v2) - | Inst::CmpEq(v1, v2) - | Inst::CmpLt(v1, v2) - | Inst::Mov(v1, v2) => { 3 + v1.len() + v2.len() } - Inst::Jmp(v) - | Inst::Jz(v) - | Inst::Jnz(v) - | Inst::Call(v) - | Inst::Push(v) - | Inst::Pop(v) => { 3 + v.len() } - Inst::Ret - | Inst::Halt - | Inst::Nop - | Inst::Dump => { 2 } - } - } -} diff --git a/src/vm/obj/syn/convert.rs b/src/vm/obj/syn/convert.rs deleted file mode 100644 index ad913b7..0000000 --- a/src/vm/obj/syn/convert.rs +++ /dev/null @@ -1,2 +0,0 @@ -struct GetLayout { -} diff --git a/src/vm/obj/syn/lexer.l b/src/vm/obj/syn/lexer.l deleted file mode 100644 index 1f1c497..0000000 --- a/src/vm/obj/syn/lexer.l +++ /dev/null @@ -1,67 +0,0 @@ -%% -\$[0-9]+ "DEC_INT" -\$0[Xx][0-9a-fA-F]+ "HEX_INT" -\$0[Bb][01]+ "BIN_INT" -\.meta "DIR_META" -\.section "DIR_SECTION" -\.export "DIR_EXPORT" -\.include "DIR_INCLUDE" -\( "LPAREN" -\) "RPAREN" -\{ "LBRACE" -\} "RBRACE" -\[ "LBRACKET" -\] "RBRACKET" -\.\. "DOTDOT" -: "COLON" -, "COMMA" -\$\$ "BUCKBUCK" -u8 "U8" -u16 "U16" -u32 "U32" -u64 "U64" -\.u8 "U8_DEF" -\.u16 "U16_DEF" -\.u32 "U32_DEF" -\.u64 "U64_DEF" -\.[iu](8|16|32|64) "INT_DEF" -\.string "STR_DEF" -\.zstring "ZSTR_DEF" -"([^"]|\\[\\nt0"'])*" "STRING" -add "ADD" -sub "SUB" -mul "MUL" -div "DIV" -idiv "IDIV" -mod "MOD" -and "AND" -or "OR" -xor "XOR" -shl "SHL" -shr "SHR" -ineg "INEG" -inv "INV" -not "NOT" -cmpeq "CMPEQ" -cmplt "CMPLT" -jmp "JMP" -jz "JZ" -jnz "JNZ" -call "CALL" -ret "RET" -push "PUSH" -pop "POP" -mov "MOV" -halt "HALT" -nop "NOP" -dump "DUMP" -%ip "REG_IP" -%sp "REG_SP" -%fp "REG_FP" -%flags "REG_FLAGS" -%null "REG_NULL" -%status "REG_STATUS" -%r[0-9]{1,2} "REG_GENERAL" -[a-zA-Z_][a-zA-Z0-9_]* "NAME" -;[^\n]* ; -[ \n\t]+ ; diff --git a/src/vm/obj/syn/mod.rs b/src/vm/obj/syn/mod.rs deleted file mode 100644 index 033263a..0000000 --- a/src/vm/obj/syn/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub mod ast; - -pub mod parser { - use lrpar::lrpar_mod; - lrpar_mod!("vm/obj/syn/parser.y"); - - pub use self::parser_y::*; -} - -pub mod lexer { - use lrlex::lrlex_mod; - lrlex_mod!("vm/obj/syn/lexer.l"); - - pub use self::lexer_l::*; -} diff --git a/src/vm/obj/syn/parser.y b/src/vm/obj/syn/parser.y deleted file mode 100644 index eb313c3..0000000 --- a/src/vm/obj/syn/parser.y +++ /dev/null @@ -1,221 +0,0 @@ -%start Top -%% - -Top -> Vec: - Top Directive { $1.push($2); $1 } - | { Vec::new() } - ; - -Directive -> Directive: - 'DIR_META' MetaBlock { Directive::Meta(MetaSection { lines: $2 }) } - | 'DIR_SECTION' Name SectionOrg DataBlock { - Directive::Data(DataSection { - name: $2, - org: $3, - lines: $4, - }) - } - | 'DIR_INCLUDE' String { Directive::Include($2) } - ; - -MetaBlock -> Vec: 'LBRACE' MetaLines 'RBRACE' { $2 }; - -MetaLines -> Vec: - MetaLines MetaLine { $1.push($2); $1 } - | { Vec::new() } - ; - - -MetaLine -> MetaLine: Name 'COLON' Value { MetaLine { name: $1, value: $3 } }; - -SectionOrg -> SectionOrg: - Int { SectionOrg::Start($1) } - | Int 'DOTDOT' Int { SectionOrg::StartEnd($1, $3) } - ; - -DataBlock -> Vec: 'LBRACE' DataLines 'RBRACE' { $2 }; - -DataLines -> Vec: - DataLines DataLine { $1.push($2); $1 } - | { Vec::new() } - ; - -DataLine -> DataLine: - ValueDef { DataLine::ValueDef($1) } - | Inst { DataLine::Inst($1) } - | 'DIR_EXPORT' Name { DataLine::Export($2) } - | Name 'COLON' { DataLine::Label($1) } - ; - -ValueDef -> ValueDef: - 'U8_DEF' Int { ValueDef::Int($2, IntSize::U8) } - | 'U16_DEF' Int { ValueDef::Int($2, IntSize::U16) } - | 'U32_DEF' Int { ValueDef::Int($2, IntSize::U32) } - | 'U64_DEF' Int { ValueDef::Int($2, IntSize::U64) } - | 'STR_DEF' String { ValueDef::String($2) } - | 'ZSTR_DEF' String { ValueDef::ZString($2) } - ; - -Value -> Value: - Int { Value::Int($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' 'U8' { Value::Addr(Box::new($2), IntSize::U8) } - | 'LPAREN' Value 'RPAREN' 'U16' { Value::Addr(Box::new($2), IntSize::U16) } - | 'LPAREN' Value 'RPAREN' 'U32' { Value::Addr(Box::new($2), IntSize::U32) } - | 'LPAREN' Value 'RPAREN' 'U64' { Value::Addr(Box::new($2), IntSize::U64) } - //| 'LBRACKET' ArrayValues 'RBRACKET' { Value::Array($2) } - ; - -/* -ArrayValues -> Vec: - ArrayValues Value { $1.push($2); $1 } - | { Vec::new() } - ; -*/ - -Inst -> Inst: - 'ADD' Value 'COMMA' Value { Inst::Add($2, $4) } - | 'SUB' Value 'COMMA' Value { Inst::Sub($2, $4) } - | 'MUL' Value 'COMMA' Value { Inst::Mul($2, $4) } - | 'DIV' Value 'COMMA' Value { Inst::Div($2, $4) } - | 'IDIV' Value 'COMMA' Value { Inst::IDiv($2, $4) } - | 'MOD' Value 'COMMA' Value { Inst::Mod($2, $4) } - | 'AND' Value 'COMMA' Value { Inst::And($2, $4) } - | 'OR' Value 'COMMA' Value { Inst::Or($2, $4) } - | 'XOR' Value 'COMMA' Value { Inst::Xor($2, $4) } - | 'SHL' Value 'COMMA' Value { Inst::Shl($2, $4) } - | 'SHR' Value 'COMMA' Value { Inst::Shr($2, $4) } - | 'INEG' Value 'COMMA' Value { Inst::INeg($2, $4) } - | 'INV' Value 'COMMA' Value { Inst::Inv($2, $4) } - | 'NOT' Value 'COMMA' Value { Inst::Not($2, $4) } - | 'CMPEQ' Value 'COMMA' Value { Inst::CmpEq($2, $4) } - | 'CMPLT' Value 'COMMA' Value { Inst::CmpLt($2, $4) } - | 'JMP' Value { Inst::Jmp($2) } - | 'JZ' Value { Inst::Jz($2) } - | 'JNZ' Value { Inst::Jnz($2) } - | 'CALL' Value { Inst::Call($2) } - | 'RET' { Inst::Ret } - | 'PUSH' Value { Inst::Push($2) } - | 'POP' Value { Inst::Pop($2) } - | 'MOV' Value 'COMMA' Value { Inst::Mov($2, $4) } - | 'HALT' { Inst::Halt } - | 'NOP' { Inst::Nop } - | 'DUMP' { Inst::Dump } - ; - -Name -> String: - 'NAME' { - let v = $1.expect("could not parse name"); - $lexer.span_str(v.span()).to_string() - } - ; - -Int -> u64: - 'DEC_INT' { - let span = $1.expect("could not parse dec_int").span(); - let s = &$lexer.span_str(span)[1..]; - s.parse().unwrap() - } - | 'HEX_INT' { - let span = $1.expect("could not parse hex_int").span(); - let s = &$lexer.span_str(span)[3..]; - u64::from_str_radix(s, 16).unwrap() - } - | 'BIN_INT' { - let span = $1.expect("could not parse bin_int").span(); - let s = &$lexer.span_str(span)[3..]; - u64::from_str_radix(s, 2).unwrap() - } - ; - -Reg -> Reg: - 'REG_IP' { IP } - | 'REG_SP' { SP } - | 'REG_FP' { FP } - | 'REG_FLAGS' { FLAGS } - | 'REG_NULL' { NULL } - | 'REG_STATUS' { STATUS } - | 'REG_GENERAL' { - let v = $1.expect("could not parse reg"); - parse_reg($lexer.span_str(v.span())).unwrap() - } - ; - -String -> String: - 'STRING' { - let v = $1.expect("could not parse string"); - parse_string($lexer.span_str(v.span())) - } - ; -%% - -use crate::vm::{ - obj::syn::ast::*, - reg::*, -}; - -fn parse_string(input: &str) -> String { - let mut s = String::new(); - let input = &input[1..input.bytes().len() - 1]; - let mut chars = input.chars(); - while let Some(c) = chars.next() { - if c == '\\' { - let next = chars.next().unwrap(); - let c = match next { - '\\' => '\\', - 'n' => '\n', - 't' => '\t', - '"' => '"', - '\'' => '\'', - '0' => '\0', - _ => unreachable!(), - }; - s.push(c); - } else { - s.push(c); - } - } - s -} - -fn parse_reg(input: &str) -> Option { - use regex::Regex; - use lazy_static::lazy_static; - lazy_static! { - static ref REG_RE: Regex = Regex::new(r"^%r([0-9]{1,2})$").unwrap(); - } - let captures = REG_RE.captures(input)?; - let reg_no: Reg = captures.get(1)? - .as_str() - .parse() - .unwrap(); - let reg = R00 + reg_no; - if reg > R31 { - None - } else { - Some(reg) - } -} - -#[cfg(test)] -mod test { - use crate::vm::reg::*; - use super::parse_reg; - #[test] - fn test_parse_reg() { - assert_eq!(parse_reg("%r00"), Some(R00)); - assert_eq!(parse_reg("%r0"), Some(R00)); - assert_eq!(parse_reg("%r1"), Some(R01)); - assert_eq!(parse_reg("%r01"), Some(R01)); - - assert_eq!(parse_reg("%r31"), Some(R31)); - assert_eq!(parse_reg("%r32"), None); - assert_eq!(parse_reg("%r0000"), None); - assert_eq!(parse_reg("%r9"), Some(R09)); - assert_eq!(parse_reg("%r"), None); - assert_eq!(parse_reg("%r12"), Some(R12)); - } -} diff --git a/src/vm/reg.rs b/src/vm/reg.rs deleted file mode 100644 index 5edd911..0000000 --- a/src/vm/reg.rs +++ /dev/null @@ -1,77 +0,0 @@ -macro_rules! registers { - { - $($variant:ident = $value:expr),* $(,)? - } => { - pub type Reg = u8; - - $( - #[allow(dead_code)] - pub const $variant: Reg = $value; - )* - - pub fn reg_name(reg: Reg) -> Option<&'static str> { - match reg { - $( - $value => Some(stringify!($variant)), - )* - _ => None, - } - } - }; -} - -registers! { - // Instruction pointer - IP = 0, - - // Stack pointer - SP = 1, - - // Frame pointer - FP = 2, - - // Flags - FLAGS = 3, - - // Zero - NULL = 4, - - // General status code - STATUS = 5, - - R00 = 6, - R01 = 7, - R02 = 8, - R03 = 9, - R04 = 10, - R05 = 11, - R06 = 12, - R07 = 13, - R08 = 14, - R09 = 15, - R10 = 16, - R11 = 17, - R12 = 18, - R13 = 19, - R14 = 20, - R15 = 21, - R16 = 22, - R17 = 23, - R18 = 24, - R19 = 25, - R20 = 26, - R21 = 27, - R22 = 28, - R23 = 29, - R24 = 30, - R25 = 31, - R26 = 32, - R27 = 33, - R28 = 34, - R29 = 35, - R30 = 36, - R31 = 37, -} - -pub const LAST_REG: Reg = 63; -pub const NUM_REGS: usize = 64; diff --git a/src/vm/state.rs b/src/vm/state.rs deleted file mode 100644 index 264f1e8..0000000 --- a/src/vm/state.rs +++ /dev/null @@ -1,387 +0,0 @@ -use crate::vm::{addr::*, error::*, flags::*, inst::*, mem::*, obj::obj::*, reg::*}; - -pub struct State { - regs: [u64; NUM_REGS], - mem: Vec, -} - -impl State { - pub fn new() -> Self { - State { - regs: [0; NUM_REGS], - mem: Default::default(), - } - } - - pub fn load_object(&mut self, object: Object, max_mem: usize) -> Result<()> { - // TODO : detecting section overlap - let mem_len = object.virtual_len(); - if mem_len > max_mem { - return Err(VmError::ObjectTooLarge { - object_size: mem_len, - max_mem, - }); - } - let mut mem = vec![0u8; max_mem]; - for section in object.sections { - match section { - Section::Data(DataSection { - name: _, - start, - len, - contents, - }) => { - for offset in 0..len { - mem[(start + offset) as usize] = contents[offset as usize]; - } - } - Section::Meta(MetaSection { entries }) => { - if let Some(addr) = entries.get("entry") { - self.set_reg_unchecked(IP, *addr); - } - } - } - } - self.mem = mem; - - Ok(()) - } - - pub fn mem_cursor(&self, addr: Addr) -> MemCursor<&[u8]> { - let mut cursor = MemCursor::new(self.mem.as_slice()); - cursor.set_position(addr); - cursor - } - - pub fn mem_cursor_mut(&mut self, addr: Addr) -> MemCursor<&mut [u8]> { - let mut cursor = MemCursor::new(self.mem.as_mut_slice()); - cursor.set_position(addr); - cursor - } - - //////////////////////////////////////////////////////////////////////////////// - // Registers - //////////////////////////////////////////////////////////////////////////////// - pub fn get_reg_unchecked(&self, reg: Reg) -> u64 { - self.regs[reg as usize] - } - - pub fn get_reg(&self, reg: Reg) -> Result { - if (reg as usize) >= NUM_REGS { - Err(VmError::IllegalReg { reg }) - } else { - Ok(self.get_reg_unchecked(reg)) - } - } - - pub fn set_reg_unchecked(&mut self, reg: Reg, value: u64) { - self.regs[reg as usize] = value; - } - - pub fn set_reg(&mut self, reg: Reg, value: u64) -> Result<()> { - if (reg as usize) >= NUM_REGS { - Err(VmError::IllegalReg { reg }) - } else { - Ok(self.set_reg_unchecked(reg, value)) - } - } - - //////////////////////////////////////////////////////////////////////////////// - // Registers - //////////////////////////////////////////////////////////////////////////////// - - pub fn ip(&self) -> u64 { - self.get_reg_unchecked(IP) - } - - pub fn sp(&self) -> u64 { - self.get_reg_unchecked(SP) - } - - pub fn fp(&self) -> u64 { - self.get_reg_unchecked(FP) - } - - //////////////////////////////////////////////////////////////////////////////// - // Flags - //////////////////////////////////////////////////////////////////////////////// - pub fn flags(&self) -> Flags { - // this is safe because it's OK if there are random bits flipped - this shouldn't happen - // anyway, but if it does, they're ignored - unsafe { Flags::from_bits_unchecked(self.get_reg_unchecked(FLAGS)) } - } - - pub fn contains_flags(&self, flags: Flags) -> bool { - self.flags().contains(flags) - } - - pub fn insert_flags(&mut self, flags: Flags) { - let mut new_flags = self.flags(); - new_flags.insert(flags); - self.set_flags(new_flags); - } - - pub fn remove_flags(&mut self, flags: Flags) { - let mut new_flags = self.flags(); - new_flags.remove(flags); - self.set_flags(new_flags); - } - - pub fn set_flags(&mut self, flags: Flags) { - self.set_reg_unchecked(FLAGS, flags.bits()); - } - - //////////////////////////////////////////////////////////////////////////////// - // Execution - //////////////////////////////////////////////////////////////////////////////// - pub fn is_halted(&self) -> bool { - self.contains_flags(Flags::HALT) - } - - pub fn exec(&mut self) -> Result { - while !self.is_halted() { - self.tick()?; - } - - Ok(self.get_reg_unchecked(STATUS)) - } - - fn tick(&mut self) -> Result<()> { - let mut cursor = self.mem_cursor(Addr(self.ip())); - let inst = cursor.next_inst()?; - let mut next_ip = self.ip() + (inst.len() as u64); - match inst { - Inst::Add(d, s) => { - let value = self.load_dest(d)?.wrapping_add(self.load_source(s)?); - self.store_dest(d, value)?; - } - Inst::Sub(d, s) => { - let value = self.load_dest(d)?.wrapping_sub(self.load_source(s)?); - self.store_dest(d, value)?; - } - Inst::Mul(d, s) => { - let value = self.load_dest(d)?.wrapping_mul(self.load_source(s)?); - 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)?; - } - Inst::IDiv(d, s) => { - // TODO : catch divide by zero - let dest = self.load_dest(d)? as i64; - let source = self.load_source(s)? as i64; - let value = dest.wrapping_div(source); - self.store_dest(d, value as u64)?; - } - Inst::Mod(d, s) => { - let value = self.load_dest(d)? % self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::And(d, s) => { - let value = self.load_dest(d)? & self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Or(d, s) => { - let value = self.load_dest(d)? | self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Xor(d, s) => { - let value = self.load_dest(d)? ^ self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Shl(d, s) => { - let value = self.load_dest(d)? << self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Shr(d, s) => { - let value = self.load_dest(d)? >> self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::INeg(d, s) => { - let value = (!self.load_source(s)?).wrapping_add(1); - self.store_dest(d, value)?; - } - Inst::Inv(d, s) => { - let value = !self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Not(d, s) => { - let value = (self.load_source(s)? == 0) as u64; - self.store_dest(d, value)?; - } - Inst::CmpEq(s1, s2) => { - let cmp = self.load_source(s1)? == self.load_source(s2)?; - if cmp { - self.insert_flags(Flags::COMPARE); - } else { - self.remove_flags(Flags::COMPARE); - } - } - Inst::CmpLt(s1, s2) => { - let cmp = self.load_source(s1)? < self.load_source(s2)?; - if cmp { - self.insert_flags(Flags::COMPARE); - } else { - self.remove_flags(Flags::COMPARE); - } - } - Inst::Jmp(s) => { - next_ip = self.load_source(s)?; - } - Inst::Jz(s) => { - if !self.contains_flags(Flags::COMPARE) { - next_ip = self.load_source(s)?; - } - } - Inst::Jnz(s) => { - if self.contains_flags(Flags::COMPARE) { - next_ip = self.load_source(s)?; - } - } - Inst::Call(s) => { - { - let fp = self.fp(); - let ip = next_ip; - self.push(Source::Imm(fp))?; - self.push(Source::Imm(ip))?; - } - - { - let sp = self.sp(); - self.set_reg_unchecked(FP, sp - 16); - - next_ip = self.load_source(s)?; - } - } - Inst::Ret => { - let fp = self.fp(); - let sp = fp + 16; - self.set_reg_unchecked(SP, sp); - - self.pop(Dest::Reg(IP))?; - self.pop(Dest::Reg(FP))?; - - next_ip = self.ip(); - } - Inst::Push(s) => { - self.push(s)?; - } - Inst::Pop(d) => { - self.pop(d)?; - } - Inst::Mov(d, s) => { - let value = self.load_source(s)?; - self.store_dest(d, value)?; - } - Inst::Halt => { - self.insert_flags(Flags::HALT); - } - Inst::Nop => {} - Inst::Dump => { - // TODO - dump - } - } - self.set_reg_unchecked(IP, next_ip); - Ok(()) - } - - fn push(&mut self, source: Source) -> Result<()> { - let value = self.load_source(source)?; - let mut stack_addr = self.sp(); - - // create a destination based on the size of the source - let dest = match source { - Source::Addr64(_) | Source::RegAddr64(_) | Source::Reg(_) | Source::Imm(_) => Dest::Addr64(Addr(stack_addr)), - Source::Addr32(_) | Source::RegAddr32(_) => Dest::Addr32(Addr(stack_addr)), - Source::Addr16(_) | Source::RegAddr16(_) => Dest::Addr16(Addr(stack_addr)), - Source::Addr8(_) | Source::RegAddr8(_) => Dest::Addr8(Addr(stack_addr)), - }; - self.store_dest(dest, value)?; - assert_eq!(source.value_len(), dest.value_len()); - - stack_addr += source.value_len() as u64; - self.set_reg_unchecked(SP, stack_addr); - Ok(()) - } - - fn pop(&mut self, dest: Dest) -> Result<()> { - let sp = self.sp() - (dest.value_len() as u64); - - let sp_source = match dest { - Dest::Addr64(_) | Dest::RegAddr64(_) | Dest::Reg(_) => Source::Addr64(Addr(sp)), - Dest::Addr32(_) | Dest::RegAddr32(_) => Source::Addr32(Addr(sp)), - Dest::Addr16(_) | Dest::RegAddr16(_) => Source::Addr16(Addr(sp)), - Dest::Addr8(_) | Dest::RegAddr8(_) => Source::Addr8(Addr(sp)), - }; - - let value = self.load_source(sp_source)?; - - // Set the SP first, because the destination may be the SP itself - self.set_reg_unchecked(SP, sp); - self.store_dest(dest, value)?; - - Ok(()) - } - - fn store_dest(&mut self, dest: Dest, value: u64) -> Result<()> { - match dest { - Dest::Addr64(a) => self.mem_cursor_mut(a).write_u64(value), - Dest::Addr32(a) => self - .mem_cursor_mut(a) - .write_u32((value & 0xffff_ffff) as u32), - Dest::Addr16(a) => self.mem_cursor_mut(a).write_u16((value & 0xffff) as u16), - Dest::Addr8(a) => self.mem_cursor_mut(a).write_u8((value & 0xff) as u8), - Dest::RegAddr64(r) => { - let addr = Addr(self.get_reg(r)?); - self.mem_cursor_mut(addr).write_u64(value) - } - Dest::RegAddr32(r) => { - let addr = Addr(self.get_reg(r)?); - self.mem_cursor_mut(addr) - .write_u32((value & 0xffff_ffff) as u32) - } - Dest::RegAddr16(r) => { - let addr = Addr(self.get_reg(r)?); - self.mem_cursor_mut(addr).write_u16((value & 0xffff) as u16) - } - Dest::RegAddr8(r) => { - let addr = Addr(self.get_reg(r)?); - self.mem_cursor_mut(addr).write_u8((value & 0xff) as u8) - } - Dest::Reg(reg) => self.set_reg(reg, value), - } - } - - fn load_source(&self, source: Source) -> Result { - let value = match source { - Source::Addr64(a) => self.mem_cursor(a).next_u64()?, - Source::Addr32(a) => self.mem_cursor(a).next_u32()? as u64, - Source::Addr16(a) => self.mem_cursor(a).next_u16()? as u64, - Source::Addr8(a) => self.mem_cursor(a).next_u8()? as u64, - Source::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?, - Source::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64, - Source::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64, - Source::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64, - Source::Reg(reg) => self.get_reg(reg)?, - Source::Imm(u) => u, - }; - Ok(value) - } - - fn load_dest(&self, dest: Dest) -> Result { - let value = match dest { - Dest::Addr64(a) => self.mem_cursor(a).next_u64()?, - Dest::Addr32(a) => self.mem_cursor(a).next_u32()? as u64, - Dest::Addr16(a) => self.mem_cursor(a).next_u16()? as u64, - Dest::Addr8(a) => self.mem_cursor(a).next_u8()? as u64, - Dest::RegAddr64(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u64()?, - Dest::RegAddr32(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u32()? as u64, - Dest::RegAddr16(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u16()? as u64, - Dest::RegAddr8(r) => self.mem_cursor(Addr(self.get_reg(r)?)).next_u8()? as u64, - Dest::Reg(reg) => self.get_reg(reg)?, - }; - Ok(value) - } -} diff --git a/src/vm/tick.rs b/src/vm/tick.rs deleted file mode 100644 index ae3e8d7..0000000 --- a/src/vm/tick.rs +++ /dev/null @@ -1,189 +0,0 @@ -use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*, visit::*, mem::MemCursor}; - -impl Vm { - pub fn tick(&mut self) -> Result<()> { - let next_ip = self.visit_inst()?; - self.set_reg(IP, next_ip); - Ok(()) - } - - fn next_ip(&self) -> Result { - let ip = self.ip(); - let op = self.get_inst_op(ip)?; - Ok(ip + (inst_len(op) as u64)) - } - - fn with_regs(&mut self, r1: Reg, r2: Reg, mapping: F) -> B - where F: FnOnce(Word, Word) -> B - { - let w1 = self.get_reg(r1); - let w2 = self.get_reg(r2); - (mapping)(w1, w2) - } -} - -impl VisitInst for Vm { - type Out = Addr; - - fn cursor(&self) -> MemCursor { - self.mem_cursor(self.ip() as usize) - } - - fn add(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_add(w2)); - self.set_reg(r1, out); - self.next_ip() - } - - fn mul(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_mul(w2)); - self.set_reg(r1, out); - self.next_ip() - } - - fn div(&mut self, r1: Reg, r2: Reg) -> Result { - // TODO : check w2 == 0 and throw error/exception - let out = self.with_regs(r1, r2, |w1, w2| w1 / w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn mod_(&mut self, r1: Reg, r2: Reg) -> Result { - // TODO : check w2 == 0 and throw error/exception - let out = self.with_regs(r1, r2, |w1, w2| w1 % w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn ineg(&mut self, r1: Reg) -> Result { - let w1 = self.get_reg(r1); - self.set_reg(r1, (!w1).wrapping_add(1)); - self.next_ip() - } - - fn and(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1 & w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn or(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1 | w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn inv(&mut self, r1: Reg) -> Result { - let w1 = self.get_reg(r1); - self.set_reg(r1, !w1); - self.next_ip() - } - - fn not(&mut self, r1: Reg) -> Result { - let w1 = self.get_reg(r1); - self.set_reg(r1, (w1 == 0) as Word); - self.next_ip() - } - - fn xor(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1 ^ w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn shl(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1 << w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn shr(&mut self, r1: Reg, r2: Reg) -> Result { - let out = self.with_regs(r1, r2, |w1, w2| w1 >> w2); - self.set_reg(r1, out); - self.next_ip() - } - - fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result { - let cmp = self.with_regs(r1, r2, |w1, w2| w1 == w2); - if cmp { - self.insert_flags(Flags::COMPARE); - } else { - self.remove_flags(Flags::COMPARE); - } - self.next_ip() - } - - fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result { - let cmp = self.with_regs(r1, r2, |w1, w2| w1 < w2); - if cmp { - self.insert_flags(Flags::COMPARE); - } else { - self.remove_flags(Flags::COMPARE); - } - self.next_ip() - } - - fn jmp(&mut self, r1: Reg) -> Result { - let addr = self.get_reg(r1); - Ok(addr) - } - - fn jz(&mut self, r1: Reg) -> Result { - if !self.flags().contains(Flags::COMPARE) { - Ok(self.get_reg(r1)) - } else { - self.next_ip() - } - } - - fn jnz(&mut self, r1: Reg) -> Result { - if self.flags().contains(Flags::COMPARE) { - Ok(self.get_reg(r1)) - } else { - self.next_ip() - } - } - - fn load(&mut self, r1: Reg, r2: Reg) -> Result { - let value = Vm::load(self, r2)?; - self.set_reg_checked(r1, value)?; - self.next_ip() - } - - fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result { - let value = self.get_reg_checked(r2)?; - self.set_reg_checked(r1, value)?; - self.next_ip() - } - - fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result { - self.set_reg_checked(r1, w1)?; - self.next_ip() - } - - fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result { - self.set_reg_checked(r1, w1 as Word)?; - self.next_ip() - } - - fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result { - let value = Vm::load(self, r2)?; - self.store(r1, value)?; - self.next_ip() - } - - fn store(&mut self, r1: Reg, r2: Reg) -> Result { - let value = self.get_reg_checked(r1)?; - self.store(r2, value)?; - self.next_ip() - } - - fn halt(&mut self) -> Result { - self.insert_flags(Flags::HALT); - self.next_ip() - } - - fn nop(&mut self) -> Result { - self.next_ip() - } -} diff --git a/src/vm/visit.rs b/src/vm/visit.rs deleted file mode 100644 index bc19725..0000000 --- a/src/vm/visit.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::vm::{ - error::*, - inst::*, - mem::MemCursor, - reg::Reg, - vm::{HalfWord, Word}, -}; - -pub trait VisitInst { - type Out; - - fn cursor(&self) -> MemCursor; - fn add(&mut self, r1: Reg, r2: Reg) -> Result; - fn mul(&mut self, r1: Reg, r2: Reg) -> Result; - fn div(&mut self, r1: Reg, r2: Reg) -> Result; - fn mod_(&mut self, r1: Reg, r2: Reg) -> Result; - fn ineg(&mut self, r1: Reg) -> Result; - fn and(&mut self, r1: Reg, r2: Reg) -> Result; - fn or(&mut self, r1: Reg, r2: Reg) -> Result; - fn inv(&mut self, r1: Reg) -> Result; - fn not(&mut self, r1: Reg) -> Result; - fn xor(&mut self, r1: Reg, r2: Reg) -> Result; - fn shl(&mut self, r1: Reg, r2: Reg) -> Result; - fn shr(&mut self, r1: Reg, r2: Reg) -> Result; - fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result; - fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result; - fn jmp(&mut self, r1: Reg) -> Result; - fn jz(&mut self, r1: Reg) -> Result; - fn jnz(&mut self, r1: Reg) -> Result; - fn load(&mut self, r1: Reg, r2: Reg) -> Result; - fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result; - fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result; - fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result; - fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result; - fn store(&mut self, r1: Reg, r2: Reg) -> Result; - fn halt(&mut self) -> Result; - fn nop(&mut self) -> Result; - - fn visit_inst(&mut self) -> Result { - let mut cursor = self.cursor(); - //panic!("cursor pos: {}", cursor.position()); - let op = cursor.next_u16()?; - - macro_rules! r1_r2_inst { - ($fun:ident) => {{ - let (r1, r2) = cursor.next_regs()?; - self.$fun(r1, r2) - }}; - } - macro_rules! r1_inst { - ($fun:ident) => {{ - let r1 = cursor.next_reg()?; - self.$fun(r1) - }}; - } - - match op { - ADD => r1_r2_inst!(add), - MUL => r1_r2_inst!(mul), - DIV => r1_r2_inst!(div), - MOD => r1_r2_inst!(mod_), - INEG => r1_inst!(ineg), - AND => r1_r2_inst!(and), - OR => r1_r2_inst!(or), - INV => r1_inst!(inv), - NOT => r1_inst!(not), - XOR => r1_r2_inst!(xor), - SHL => r1_r2_inst!(shl), - SHR => r1_r2_inst!(shr), - CMPEQ => r1_r2_inst!(cmpeq), - CMPLT => r1_r2_inst!(cmplt), - JMP => r1_inst!(jmp), - JZ => r1_inst!(jz), - JNZ => r1_inst!(jnz), - LOAD => r1_r2_inst!(load), - REGCOPY => r1_r2_inst!(regcopy), - STOREIMM64 => { - let r1 = cursor.next_reg()?; - // skip - cursor.next_u32()?; - let imm = cursor.next_u64()?; - self.storeimm64(r1, imm) - } - STOREIMM32 => { - let r1 = cursor.next_reg()?; - let imm = cursor.next_u32()?; - self.storeimm32(r1, imm) - } - MEMCOPY => r1_r2_inst!(memcopy), - STORE => r1_r2_inst!(store), - HALT => self.halt(), - NOP => self.nop(), - _ => Err(VmError::IllegalOp { op }), - } - } -}