Compare commits

...

2 commits

Author SHA1 Message Date
e310b901c3 Add Bool and Char addressing modes
All checks were successful
per-push tests / build (push) Successful in 1m45s
per-push tests / test-frontend (push) Successful in 2m5s
per-push tests / test-utility (push) Successful in 2m12s
per-push tests / timed-decomposer-parse (push) Successful in 1m8s
per-push tests / test-backend (push) Successful in 1m17s
This commit adds addressing modes for boolean and character data.
The Address enum is extended, along with its TryFrom<u8> 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 <ava@sunnypup.io>
2025-08-09 04:48:00 +00:00
4fb7e78c2a add documentation for current addressing modes to instructions.toml
Signed-off-by: Ava Affine <ava@sunnypup.io>
2025-08-09 04:45:21 +00:00
3 changed files with 112 additions and 24 deletions

View file

@ -1,5 +1,51 @@
# NOTE: keep libc out of this, thats what trap vector is for [[addressing_modes]]
# NOTE: to programmers: only registers allow mutable acess name = "expr"
mutable = true
symbol = "$expr"
example = "inc $expr"
description = "The expression register is used as a default output, or input by many instructions."
[[addressing_modes]]
name = "operand"
mutable = true
symbol = "$oper<N>"
example = "add $oper1, $oper2"
description = "There are four operand registers N=(0, 1, 2, 3, and 4). They are for storing mutable data."
[[addressing_modes]]
name = "stack"
mutable = false
symbol = "%N"
example = "dupl %0, $expr"
description = "Stack addressing mode takes an index in to the stack to read from."
[[addressing_modes]]
name = "instruction"
mutable = false
symbol = "@N"
example = "jmp @100"
description = "Instruction addressing mode indexes by instruction into the program."
[[addressing_modes]]
name = "numeric"
mutable = false
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]] [[instructions]]
name = "trap" name = "trap"

View file

@ -34,6 +34,8 @@ pub enum Address {
Oper3 = 0xf5, // mutable access allowed Oper3 = 0xf5, // mutable access allowed
Oper4 = 0xf6, // mutable access allowed Oper4 = 0xf6, // mutable access allowed
Numer = 0xf8, // immutable access only Numer = 0xf8, // immutable access only
Bool = 0xf9, // immutable access only
Char = 0xfa, // immutable access only
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -63,6 +65,8 @@ impl TryFrom<u8> for Address {
_ if val == Address::Oper3 as u8 => Ok(Address::Oper3), _ if val == Address::Oper3 as u8 => Ok(Address::Oper3),
_ if val == Address::Oper4 as u8 => Ok(Address::Oper4), _ if val == Address::Oper4 as u8 => Ok(Address::Oper4),
_ if val == Address::Numer as u8 => Ok(Address::Numer), _ 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") _ => Err("illegal addressing mode")
} }
} }
@ -74,6 +78,8 @@ impl Address {
Address::Stack => (usize::BITS / 8) as u8, Address::Stack => (usize::BITS / 8) as u8,
Address::Instr => (usize::BITS / 8) as u8, Address::Instr => (usize::BITS / 8) as u8,
Address::Numer => (usize::BITS / 8) as u8, Address::Numer => (usize::BITS / 8) as u8,
Address::Bool => 1,
Address::Char => 1,
_ => 0, _ => 0,
} }
} }

View file

@ -170,6 +170,8 @@ impl VM {
Address::Oper4 => &self.oper[3], Address::Oper4 => &self.oper[3],
Address::Stack => &self.stack[$oper.1], Address::Stack => &self.stack[$oper.1],
Address::Numer => e!("cannot access constant numeric data"), 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"), Address::Instr => e!("bad access to instruction data"),
} }
}; };
@ -405,11 +407,14 @@ impl VM {
}, },
i::CONST => access!(&instr.1[0], { i::CONST => access!(&instr.1[0], {
let Operand(Address::Numer, num) = instr.1[1] else { match instr.1[1].0 {
e!("illegal argument to CONST instruction"); Address::Numer =>
}; Datum::Number(Number::Fra(Fraction(instr.1[1].1 as isize, 1)))
.into(),
Datum::Number(Number::Fra(Fraction(num 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(), i::MKVEC => self.expr = Datum::Vector(vec![]).into(),
@ -629,7 +634,7 @@ mod tests {
fn chk_err(&self, state: &VM) -> bool { fn chk_err(&self, state: &VM) -> bool {
if let Datum::String(ref msg) = *state.errr { if let Datum::String(ref msg) = *state.errr {
let msg = unsafe { str::from_utf8_unchecked(msg) }; let msg = unsafe { str::from_utf8_unchecked(msg) };
if msg == self.errr.unwrap() { if self.errr.is_some() && msg == self.errr.unwrap() {
true true
} else { } else {
print!("expected error {:?}, got {:?}\n", self.errr, msg); print!("expected error {:?}, got {:?}\n", self.errr, msg);
@ -1117,6 +1122,36 @@ mod tests {
assert!(case.test_passes(&vm)); 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] #[test]
fn isa_index() { fn isa_index() {
// TODO INDEX on V, BV, S, L // TODO INDEX on V, BV, S, L
@ -1146,4 +1181,5 @@ mod tests {
fn isa_string_ops() { fn isa_string_ops() {
// TODO CONCAT and S_APPEND // TODO CONCAT and S_APPEND
} }
*/
} }