From e310b901c36e57293f1cda6620bfbc340f09ab2e Mon Sep 17 00:00:00 2001 From: Ava Affine Date: Sat, 9 Aug 2025 04:45:56 +0000 Subject: [PATCH] Add Bool and Char addressing modes This commit adds addressing modes for boolean and character data. The Address enum is extended, along with its TryFrom implementation and its operand_size function. The access macro is extended to handle the new modes. The CONST instruction can now create Char and Bool data. The instructions.toml has information on the new addressing modes. Unit tests have been added to test new CONST logic. fixes: #41 Signed-off-by: Ava Affine --- hyphae/instructions.toml | 17 ++++++++++++--- hyphae/src/util.rs | 38 +++++++++++++++++++-------------- hyphae/src/vm.rs | 46 ++++++++++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 25 deletions(-) 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() {