From 417047806bc91cfe349e528e6705026b41ecc6d5 Mon Sep 17 00:00:00 2001 From: Erin Date: Fri, 9 Jun 2023 00:10:46 +0200 Subject: [PATCH] Program interrupts, immediate binary ops and bitshifts. --- hbasm/src/lib.rs | 12 +++---- hbbytecode/src/lib.rs | 75 +++++++++++++++++++++++++------------------ hbvm/src/main.rs | 2 +- hbvm/src/validate.rs | 4 +-- hbvm/src/vm/mod.rs | 57 +++++++++++++++++++++++++------- hbvm/src/vm/value.rs | 1 + 6 files changed, 99 insertions(+), 52 deletions(-) diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs index 34e2088..63dd76f 100644 --- a/hbasm/src/lib.rs +++ b/hbasm/src/lib.rs @@ -43,10 +43,10 @@ macro_rules! tokendef { #[rustfmt::skip] tokendef![ - "nop", "add", "sub", "mul", "rem", "and", "or", "xor", "not", - "addf", "subf", "mulf", "divf", "cp", "li", "lb", "ld", "lq", - "lo", "sb", "sd", "sq", "so", "pagemap", "pageunmap", "pagemp", - "jmp", "jmpcond", "ret", "ecall", + "nop", "add", "sub", "mul", "rem", "and", "or", "xor", "sl", "sr", "srs", + "not", "addf", "subf", "mulf", "divf", "addi", "muli", "remi", "andi", + "ori", "xori", "sli", "sri", "srsi", "addfi", "mulfi", "cp", "li", "lb", + "ld", "lq", "lo", "sb", "sd", "sq", "so", "jmp", "jmpcond", "ret", "ecall", ]; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -100,10 +100,10 @@ pub fn assembly(code: &str, buf: &mut Vec) -> Result<(), Error> { self.buf.push(op); match op { NOP | RET | ECALL => Ok(()), - ADD..=XOR | ADDF..=DIVF => self.rrr(), + ADD..=SRS | ADDF..=DIVF => self.rrr(), NOT | CP => self.rr(), LI | JMP => self.ri(), - LB..=SO => self.rri(), + ADDI..=MULFI | LB..=SO => self.rri(), _ => unreachable!(), }?; match self.next() { diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index e213b6f..06c24e6 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -10,43 +10,54 @@ macro_rules! constmod { constmod!(pub opcode(u8) { NOP = 0, // N; Do nothing - ADD = 1, // RRR; #0 ← #1 + #2 - SUB = 2, // RRR; #0 ← #1 - #2 - MUL = 3, // RRR; #0 ← #1 × #2 - DIV = 4, // RRR; #0 ← #1 ÷ #2 - REM = 5, // RRR; #0 ← #1 % #2 - AND = 6, // RRR; #0 ← #1 & #2 - OR = 7, // RRR; #0 ← #1 | #2 - XOR = 8, // RRR; #0 ← #1 ^ #2 - NOT = 9, // RR; #0 ← !#1 - // TODO: Add instruction for integer and float - // reg ← reg + imm instructions + ADD = 1, // RRR; #0 ← #1 + #2 + SUB = 2, // RRR; #0 ← #1 - #2 + MUL = 3, // RRR; #0 ← #1 × #2 + DIV = 4, // RRR; #0 ← #1 ÷ #2 + REM = 5, // RRR; #0 ← #1 % #2 + AND = 6, // RRR; #0 ← #1 & #2 + OR = 7, // RRR; #0 ← #1 | #2 + XOR = 8, // RRR; #0 ← #1 ^ #2 + SL = 9, // RRR; #0 ← #1 « #2 + SR = 10, // RRR; #0 ← #1 » #2 + SRS = 11, // RRR; #0 ← #1 » #2 (signed) + NOT = 12, // RR; #0 ← !#1 - ADDF = 10, // RRR; #0 ← #1 +. #2 - SUBF = 11, // RRR; #0 ← #1 +. #2 - MULF = 12, // RRR; #0 ← #1 +. #2 - DIVF = 13, // RRR; #0 ← #1 +. #2 + ADDF = 13, // RRR; #0 ← #1 +. #2 + SUBF = 14, // RRR; #0 ← #1 +. #2 + MULF = 15, // RRR; #0 ← #1 +. #2 + DIVF = 16, // RRR; #0 ← #1 +. #2 - CP = 14, // RR; Copy #0 ← #1 - LI = 15, // RI; Load immediate, #0 ← imm #1 - LB = 16, // RRI; Load byte (8 bits), #0 ← [#1 + imm #2] - LD = 17, // RRI; Load doublet (16 bits) - LQ = 18, // RRI; Load quadlet (32 bits) - LO = 19, // RRI; Load octlet (64 bits) - SB = 20, // RRI; Store byte, [#1 + imm #2] ← #0 - SD = 21, // RRI; Store doublet - SQ = 22, // RRI; Store quadlet - SO = 23, // RRI; Store octlet + ADDI = 17, // RRI; #0 ← #1 + imm #2 + MULI = 18, // RRI; #0 ← #1 × imm #2 + REMI = 19, // RRI; #0 ← #1 % imm #2 + ANDI = 20, // RRI; #0 ← #1 & imm #2 + ORI = 21, // RRI; #0 ← #1 | imm #2 + XORI = 22, // RRI; #0 ← #1 ^ imm #2 - PAGEMAP = 24, // ?; Map a page - PAGEUNMAP = 25, // ?; Unmap a page - PAGEMP = 26, // ?; Page modify protection flags + SLI = 23, // RRI; #0 ← #1 « imm #2 + SRI = 24, // RRI; #0 ← #1 » imm #2 + SRSI = 25, // RRI; #0 ← #1 » imm #2 (signed) - JMP = 27, // RI; Unconditional jump [#0 + imm #1] - JMPCOND = 28, // ?; Conditional jump - RET = 29, // N; Return - ECALL = 30, // N; Issue system call + ADDFI = 26, // RRI; #0 ← #1 +. imm #2 + MULFI = 27, // RRI; #0 ← #1 *. imm #2 + + CP = 28, // RR; Copy #0 ← #1 + LI = 29, // RI; Load immediate, #0 ← imm #1 + LB = 30, // RRI; Load byte (8 bits), #0 ← [#1 + imm #2] + LD = 31, // RRI; Load doublet (16 bits) + LQ = 32, // RRI; Load quadlet (32 bits) + LO = 33, // RRI; Load octlet (64 bits) + SB = 34, // RRI; Store byte, [#1 + imm #2] ← #0 + SD = 35, // RRI; Store doublet + SQ = 36, // RRI; Store quadlet + SO = 37, // RRI; Store octlet + + JMP = 38, // RI; Unconditional jump [#0 + imm #1] + JMPCOND = 39, // ?; Conditional jump + RET = 40, // N; Return + ECALL = 42, // N; Issue system call }); #[repr(packed)] diff --git a/hbvm/src/main.rs b/hbvm/src/main.rs index a463ee3..3eac6c7 100644 --- a/hbvm/src/main.rs +++ b/hbvm/src/main.rs @@ -14,7 +14,7 @@ fn main() -> Result<(), Box> { unsafe { let mut vm = Vm::new_unchecked(&prog); vm.memory.insert_test_page(); - vm.run(); + println!("Program interrupt: {:?}", vm.run()); println!("{:?}", vm.registers); } } diff --git a/hbvm/src/validate.rs b/hbvm/src/validate.rs index 802e029..6866eb3 100644 --- a/hbvm/src/validate.rs +++ b/hbvm/src/validate.rs @@ -41,7 +41,7 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> { // N [NOP | RET | ECALL, rest @ ..] => rest, // RRR - [ADD..=XOR | ADDF..=DIVF, _, _, _, rest @ ..] => { + [ADD..=SRS | ADDF..=DIVF, _, _, _, rest @ ..] => { if let Some(n) = reg(&program[1..=3]) { bail!(InvalidRegister, start, program, n + 1); } @@ -62,7 +62,7 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> { rest } // RRI - [LB..=SO, _, _, _, _, _, _, _, _, _, _, rest @ ..] => { + [ADDI..=MULFI | LB..=SO, _, _, _, _, _, _, _, _, _, _, rest @ ..] => { if let Some(n) = reg(&program[1..=2]) { bail!(InvalidRegister, start, program, n + 1); } diff --git a/hbvm/src/vm/mod.rs b/hbvm/src/vm/mod.rs index 0870737..1ad0007 100644 --- a/hbvm/src/vm/mod.rs +++ b/hbvm/src/vm/mod.rs @@ -37,15 +37,28 @@ macro_rules! binary_op { }}; } +macro_rules! binary_op_imm { + ($self:expr, $ty:ident, $handler:expr) => {{ + let ParamRRI(tg, a0, imm) = param!($self, ParamRRI); + $self.write_reg( + tg, + $handler(Value::$ty(&$self.read_reg(a0)), Value::$ty(&imm.into())).into(), + ); + }}; +} + macro_rules! load { ($self:expr, $size:ty) => {{ let ParamRRI(tg, a0, offset) = param!($self, ParamRRI); $self.write_reg( tg, - $self + match $self .memory .load::<$size>($self.read_reg(a0).int() + offset) - .ok_or(Exception::LoadAccess)?, + { + Some(x) => x, + None => return HaltReason::LoadAccessEx, + }, ); }}; } @@ -53,10 +66,12 @@ macro_rules! load { macro_rules! store { ($self:expr, $size:ty) => {{ let ParamRRI(src, a0, offset) = param!($self, ParamRRI); - $self + if let Err(()) = $self .memory .store::<$size>($self.read_reg(a0).int() + offset, $self.read_reg(src)) - .map_err(|_| Exception::StoreAccess)?; + { + return HaltReason::StoreAccessEx; + } }}; } @@ -72,7 +87,7 @@ impl<'a> Vm<'a> { /// Program code has to be validated pub unsafe fn new_unchecked(program: &'a [u8]) -> Self { Self { - registers: [Value::from(0); 60], + registers: [Value::from(0_u64); 60], memory: Default::default(), pc: 0, program, @@ -84,11 +99,11 @@ impl<'a> Vm<'a> { Ok(unsafe { Self::new_unchecked(program) }) } - pub fn run(&mut self) -> Result<(), Exception> { + pub fn run(&mut self) -> HaltReason { use hbbytecode::opcode::*; loop { let Some(&opcode) = self.program.get(self.pc) - else { return Ok(()) }; + else { return HaltReason::ProgramEnd }; unsafe { match opcode { @@ -101,6 +116,9 @@ impl<'a> Vm<'a> { AND => binary_op!(self, int, ops::BitAnd::bitand), OR => binary_op!(self, int, ops::BitOr::bitor), XOR => binary_op!(self, int, ops::BitXor::bitxor), + SL => binary_op!(self, int, ops::Shl::shl), + SR => binary_op!(self, int, ops::Shr::shr), + SRS => binary_op!(self, sint, ops::Shr::shr), NOT => { let param = param!(self, ParamRR); self.write_reg(param.0, (!self.read_reg(param.1).int()).into()); @@ -109,6 +127,17 @@ impl<'a> Vm<'a> { SUBF => binary_op!(self, float, ops::Sub::sub), MULF => binary_op!(self, float, ops::Mul::mul), DIVF => binary_op!(self, float, ops::Div::div), + ADDI => binary_op_imm!(self, int, ops::Add::add), + MULI => binary_op_imm!(self, int, ops::Mul::mul), + REMI => binary_op_imm!(self, int, ops::Rem::rem), + ANDI => binary_op_imm!(self, int, ops::BitAnd::bitand), + ORI => binary_op_imm!(self, int, ops::BitOr::bitor), + XORI => binary_op_imm!(self, int, ops::BitXor::bitxor), + SLI => binary_op_imm!(self, int, ops::Shl::shl), + SRI => binary_op_imm!(self, int, ops::Shr::shr), + SRSI => binary_op_imm!(self, sint, ops::Shr::shr), + ADDFI => binary_op_imm!(self, float, ops::Add::add), + MULFI => binary_op_imm!(self, float, ops::Mul::mul), CP => { let param = param!(self, ParamRR); self.write_reg(param.0, self.read_reg(param.1)); @@ -129,6 +158,10 @@ impl<'a> Vm<'a> { let ParamRI(reg, offset) = param!(self, ParamRI); self.pc = (self.read_reg(reg).int() + offset) as usize; } + ECALL => { + param!(self, ()); + return HaltReason::Ecall; + } _ => core::hint::unreachable_unchecked(), } } @@ -138,7 +171,7 @@ impl<'a> Vm<'a> { #[inline] unsafe fn read_reg(&self, n: u8) -> Value { if n == 0 { - 0.into() + 0_u64.into() } else { *self.registers.get_unchecked(n as usize) } @@ -154,7 +187,9 @@ impl<'a> Vm<'a> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u8)] -pub enum Exception { - LoadAccess, - StoreAccess, +pub enum HaltReason { + ProgramEnd, + Ecall, + LoadAccessEx, + StoreAccessEx, } diff --git a/hbvm/src/vm/value.rs b/hbvm/src/vm/value.rs index 3b95c0f..870439a 100644 --- a/hbvm/src/vm/value.rs +++ b/hbvm/src/vm/value.rs @@ -28,6 +28,7 @@ macro_rules! value_def { value_def! { i: u64, int; + s: i64, sint; f: f64, float; }