diff --git a/hyphae/instructions.toml b/hyphae/instructions.toml index 0a8775e..2f8d3e2 100644 --- a/hyphae/instructions.toml +++ b/hyphae/instructions.toml @@ -1,6 +1,3 @@ -# NOTE: keep libc out of this, thats what trap vector is for -# NOTE: to programmers: only registers allow mutable acess - [[addressing_modes]] name = "expr" mutable = true @@ -36,6 +33,20 @@ symbol = "N" example = "const $expr, 100" description = "Numeric addressing mode provides read only integer constants to instructions" +[[addressing_modes]] +name = "char" +mutable = false +symbol = "'N'" +example = "const $expr, 'c'" +description = "Char addressing mode provides read only character constants to instructions" + +[[addressing_modes]] +name = "boolean" +mutable = false +symbol = "{true|false}" +example = "const $expr, true" +description = "Boolean addressing mode provides read only booleans to instructions" + [[instructions]] name = "trap" args = ["index"] diff --git a/hyphae/src/util.rs b/hyphae/src/util.rs index c7d6957..e699424 100644 --- a/hyphae/src/util.rs +++ b/hyphae/src/util.rs @@ -26,14 +26,16 @@ use core::mem::transmute; #[repr(u8)] #[derive(Debug, Clone, PartialEq)] pub enum Address { - Stack = 0xf0, // immutable access only - Instr = 0xf1, // immutable access only - Expr = 0xf2, // mutable access allowed - Oper1 = 0xf3, // mutable access allowed - Oper2 = 0xf4, // mutable access allowed - Oper3 = 0xf5, // mutable access allowed - Oper4 = 0xf6, // mutable access allowed - Numer = 0xf8, // immutable access only + Stack = 0xf0, // immutable access only + Instr = 0xf1, // immutable access only + Expr = 0xf2, // mutable access allowed + Oper1 = 0xf3, // mutable access allowed + Oper2 = 0xf4, // mutable access allowed + Oper3 = 0xf5, // mutable access allowed + Oper4 = 0xf6, // mutable access allowed + Numer = 0xf8, // immutable access only + Bool = 0xf9, // immutable access only + Char = 0xfa, // immutable access only } #[derive(Debug, Clone, PartialEq)] @@ -55,14 +57,16 @@ impl TryFrom for Address { type Error = &'static str; fn try_from(val: u8) -> Result { match val { - _ if val == Address::Stack as u8 => Ok(Address::Stack), - _ if val == Address::Instr as u8 => Ok(Address::Instr), - _ if val == Address::Expr as u8 => Ok(Address::Expr), - _ if val == Address::Oper1 as u8 => Ok(Address::Oper1), - _ if val == Address::Oper2 as u8 => Ok(Address::Oper2), - _ if val == Address::Oper3 as u8 => Ok(Address::Oper3), - _ if val == Address::Oper4 as u8 => Ok(Address::Oper4), - _ if val == Address::Numer as u8 => Ok(Address::Numer), + _ if val == Address::Stack as u8 => Ok(Address::Stack), + _ if val == Address::Instr as u8 => Ok(Address::Instr), + _ if val == Address::Expr as u8 => Ok(Address::Expr), + _ if val == Address::Oper1 as u8 => Ok(Address::Oper1), + _ if val == Address::Oper2 as u8 => Ok(Address::Oper2), + _ if val == Address::Oper3 as u8 => Ok(Address::Oper3), + _ if val == Address::Oper4 as u8 => Ok(Address::Oper4), + _ if val == Address::Numer as u8 => Ok(Address::Numer), + _ if val == Address::Bool as u8 => Ok(Address::Bool), + _ if val == Address::Char as u8 => Ok(Address::Char), _ => Err("illegal addressing mode") } } @@ -74,6 +78,8 @@ impl Address { Address::Stack => (usize::BITS / 8) as u8, Address::Instr => (usize::BITS / 8) as u8, Address::Numer => (usize::BITS / 8) as u8, + Address::Bool => 1, + Address::Char => 1, _ => 0, } } diff --git a/hyphae/src/vm.rs b/hyphae/src/vm.rs index 7ed5c1d..ffa9fbd 100644 --- a/hyphae/src/vm.rs +++ b/hyphae/src/vm.rs @@ -170,6 +170,8 @@ impl VM { Address::Oper4 => &self.oper[3], Address::Stack => &self.stack[$oper.1], Address::Numer => e!("cannot access constant numeric data"), + Address::Char => e!("cannot access constant char data"), + Address::Bool => e!("cannot access constant bool data"), Address::Instr => e!("bad access to instruction data"), } }; @@ -405,11 +407,14 @@ impl VM { }, i::CONST => access!(&instr.1[0], { - let Operand(Address::Numer, num) = instr.1[1] else { - e!("illegal argument to CONST instruction"); - }; - - Datum::Number(Number::Fra(Fraction(num as isize, 1))).into() + match instr.1[1].0 { + Address::Numer => + Datum::Number(Number::Fra(Fraction(instr.1[1].1 as isize, 1))) + .into(), + Address::Bool => Datum::Bool(instr.1[1].1 > 0).into(), + Address::Char => Datum::Char(instr.1[1].1 as u8).into(), + _ => e!("illegal argument to CONST instruction"), + } }), i::MKVEC => self.expr = Datum::Vector(vec![]).into(), @@ -629,7 +634,7 @@ mod tests { fn chk_err(&self, state: &VM) -> bool { if let Datum::String(ref msg) = *state.errr { let msg = unsafe { str::from_utf8_unchecked(msg) }; - if msg == self.errr.unwrap() { + if self.errr.is_some() && msg == self.errr.unwrap() { true } else { print!("expected error {:?}, got {:?}\n", self.errr, msg); @@ -1117,6 +1122,35 @@ mod tests { assert!(case.test_passes(&vm)); } + #[test] + fn isa_consts() { + let mut vm = VM::from(Program(vec![ + Instruction(i::CONST, vec![Operand(Address::Expr, 0), + Operand(Address::Numer, 1)]), + Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]), + Instruction(i::CONST, vec![Operand(Address::Expr, 0), + Operand(Address::Char, 'a' as u8 as usize)]), + Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]), + Instruction(i::CONST, vec![Operand(Address::Expr, 0), + Operand(Address::Bool, 1)]), + Instruction(i::PUSH, vec![Operand(Address::Expr, 0)]), + ])); + + let case = TestResult{ + expr: None, + stack: vec![ + (0, Datum::Bool(true).into()), + (1, Datum::Char('a' as u8).into()), + (2, Datum::Number(Number::Fra(Fraction(1, 1))).into()), + ], + syms: vec![], + errr: None, + }; + + vm.run_program(); + assert!(case.test_passes(&vm)); + } + /* #[test] fn isa_index() {