Compare commits
2 commits
0e47e5658a
...
e310b901c3
| Author | SHA1 | Date | |
|---|---|---|---|
| e310b901c3 | |||
| 4fb7e78c2a |
3 changed files with 112 additions and 24 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,16 @@ use core::mem::transmute;
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Address {
|
pub enum Address {
|
||||||
Stack = 0xf0, // immutable access only
|
Stack = 0xf0, // immutable access only
|
||||||
Instr = 0xf1, // immutable access only
|
Instr = 0xf1, // immutable access only
|
||||||
Expr = 0xf2, // mutable access allowed
|
Expr = 0xf2, // mutable access allowed
|
||||||
Oper1 = 0xf3, // mutable access allowed
|
Oper1 = 0xf3, // mutable access allowed
|
||||||
Oper2 = 0xf4, // mutable access allowed
|
Oper2 = 0xf4, // mutable access allowed
|
||||||
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)]
|
||||||
|
|
@ -55,14 +57,16 @@ impl TryFrom<u8> for Address {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
fn try_from(val: u8) -> Result<Self, Self::Error> {
|
fn try_from(val: u8) -> Result<Self, Self::Error> {
|
||||||
match val {
|
match val {
|
||||||
_ if val == Address::Stack as u8 => Ok(Address::Stack),
|
_ if val == Address::Stack as u8 => Ok(Address::Stack),
|
||||||
_ if val == Address::Instr as u8 => Ok(Address::Instr),
|
_ if val == Address::Instr as u8 => Ok(Address::Instr),
|
||||||
_ if val == Address::Expr as u8 => Ok(Address::Expr),
|
_ if val == Address::Expr as u8 => Ok(Address::Expr),
|
||||||
_ if val == Address::Oper1 as u8 => Ok(Address::Oper1),
|
_ if val == Address::Oper1 as u8 => Ok(Address::Oper1),
|
||||||
_ if val == Address::Oper2 as u8 => Ok(Address::Oper2),
|
_ if val == Address::Oper2 as u8 => Ok(Address::Oper2),
|
||||||
_ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue