Program interrupts, immediate binary ops and bitshifts.
This commit is contained in:
parent
da6ad6d2c7
commit
417047806b
|
@ -43,10 +43,10 @@ macro_rules! tokendef {
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
tokendef![
|
tokendef![
|
||||||
"nop", "add", "sub", "mul", "rem", "and", "or", "xor", "not",
|
"nop", "add", "sub", "mul", "rem", "and", "or", "xor", "sl", "sr", "srs",
|
||||||
"addf", "subf", "mulf", "divf", "cp", "li", "lb", "ld", "lq",
|
"not", "addf", "subf", "mulf", "divf", "addi", "muli", "remi", "andi",
|
||||||
"lo", "sb", "sd", "sq", "so", "pagemap", "pageunmap", "pagemp",
|
"ori", "xori", "sli", "sri", "srsi", "addfi", "mulfi", "cp", "li", "lb",
|
||||||
"jmp", "jmpcond", "ret", "ecall",
|
"ld", "lq", "lo", "sb", "sd", "sq", "so", "jmp", "jmpcond", "ret", "ecall",
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
@ -100,10 +100,10 @@ pub fn assembly(code: &str, buf: &mut Vec<u8>) -> Result<(), Error> {
|
||||||
self.buf.push(op);
|
self.buf.push(op);
|
||||||
match op {
|
match op {
|
||||||
NOP | RET | ECALL => Ok(()),
|
NOP | RET | ECALL => Ok(()),
|
||||||
ADD..=XOR | ADDF..=DIVF => self.rrr(),
|
ADD..=SRS | ADDF..=DIVF => self.rrr(),
|
||||||
NOT | CP => self.rr(),
|
NOT | CP => self.rr(),
|
||||||
LI | JMP => self.ri(),
|
LI | JMP => self.ri(),
|
||||||
LB..=SO => self.rri(),
|
ADDI..=MULFI | LB..=SO => self.rri(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}?;
|
}?;
|
||||||
match self.next() {
|
match self.next() {
|
||||||
|
|
|
@ -10,43 +10,54 @@ macro_rules! constmod {
|
||||||
|
|
||||||
constmod!(pub opcode(u8) {
|
constmod!(pub opcode(u8) {
|
||||||
NOP = 0, // N; Do nothing
|
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
|
ADD = 1, // RRR; #0 ← #1 + #2
|
||||||
// reg ← reg + imm instructions
|
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
|
ADDF = 13, // RRR; #0 ← #1 +. #2
|
||||||
SUBF = 11, // RRR; #0 ← #1 +. #2
|
SUBF = 14, // RRR; #0 ← #1 +. #2
|
||||||
MULF = 12, // RRR; #0 ← #1 +. #2
|
MULF = 15, // RRR; #0 ← #1 +. #2
|
||||||
DIVF = 13, // RRR; #0 ← #1 +. #2
|
DIVF = 16, // RRR; #0 ← #1 +. #2
|
||||||
|
|
||||||
CP = 14, // RR; Copy #0 ← #1
|
ADDI = 17, // RRI; #0 ← #1 + imm #2
|
||||||
LI = 15, // RI; Load immediate, #0 ← imm #1
|
MULI = 18, // RRI; #0 ← #1 × imm #2
|
||||||
LB = 16, // RRI; Load byte (8 bits), #0 ← [#1 + imm #2]
|
REMI = 19, // RRI; #0 ← #1 % imm #2
|
||||||
LD = 17, // RRI; Load doublet (16 bits)
|
ANDI = 20, // RRI; #0 ← #1 & imm #2
|
||||||
LQ = 18, // RRI; Load quadlet (32 bits)
|
ORI = 21, // RRI; #0 ← #1 | imm #2
|
||||||
LO = 19, // RRI; Load octlet (64 bits)
|
XORI = 22, // RRI; #0 ← #1 ^ imm #2
|
||||||
SB = 20, // RRI; Store byte, [#1 + imm #2] ← #0
|
|
||||||
SD = 21, // RRI; Store doublet
|
|
||||||
SQ = 22, // RRI; Store quadlet
|
|
||||||
SO = 23, // RRI; Store octlet
|
|
||||||
|
|
||||||
PAGEMAP = 24, // ?; Map a page
|
SLI = 23, // RRI; #0 ← #1 « imm #2
|
||||||
PAGEUNMAP = 25, // ?; Unmap a page
|
SRI = 24, // RRI; #0 ← #1 » imm #2
|
||||||
PAGEMP = 26, // ?; Page modify protection flags
|
SRSI = 25, // RRI; #0 ← #1 » imm #2 (signed)
|
||||||
|
|
||||||
JMP = 27, // RI; Unconditional jump [#0 + imm #1]
|
ADDFI = 26, // RRI; #0 ← #1 +. imm #2
|
||||||
JMPCOND = 28, // ?; Conditional jump
|
MULFI = 27, // RRI; #0 ← #1 *. imm #2
|
||||||
RET = 29, // N; Return
|
|
||||||
ECALL = 30, // N; Issue system call
|
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)]
|
#[repr(packed)]
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut vm = Vm::new_unchecked(&prog);
|
let mut vm = Vm::new_unchecked(&prog);
|
||||||
vm.memory.insert_test_page();
|
vm.memory.insert_test_page();
|
||||||
vm.run();
|
println!("Program interrupt: {:?}", vm.run());
|
||||||
println!("{:?}", vm.registers);
|
println!("{:?}", vm.registers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
||||||
// N
|
// N
|
||||||
[NOP | RET | ECALL, rest @ ..] => rest,
|
[NOP | RET | ECALL, rest @ ..] => rest,
|
||||||
// RRR
|
// RRR
|
||||||
[ADD..=XOR | ADDF..=DIVF, _, _, _, rest @ ..] => {
|
[ADD..=SRS | ADDF..=DIVF, _, _, _, rest @ ..] => {
|
||||||
if let Some(n) = reg(&program[1..=3]) {
|
if let Some(n) = reg(&program[1..=3]) {
|
||||||
bail!(InvalidRegister, start, program, n + 1);
|
bail!(InvalidRegister, start, program, n + 1);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
||||||
rest
|
rest
|
||||||
}
|
}
|
||||||
// RRI
|
// RRI
|
||||||
[LB..=SO, _, _, _, _, _, _, _, _, _, _, rest @ ..] => {
|
[ADDI..=MULFI | LB..=SO, _, _, _, _, _, _, _, _, _, _, rest @ ..] => {
|
||||||
if let Some(n) = reg(&program[1..=2]) {
|
if let Some(n) = reg(&program[1..=2]) {
|
||||||
bail!(InvalidRegister, start, program, n + 1);
|
bail!(InvalidRegister, start, program, n + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
macro_rules! load {
|
||||||
($self:expr, $size:ty) => {{
|
($self:expr, $size:ty) => {{
|
||||||
let ParamRRI(tg, a0, offset) = param!($self, ParamRRI);
|
let ParamRRI(tg, a0, offset) = param!($self, ParamRRI);
|
||||||
$self.write_reg(
|
$self.write_reg(
|
||||||
tg,
|
tg,
|
||||||
$self
|
match $self
|
||||||
.memory
|
.memory
|
||||||
.load::<$size>($self.read_reg(a0).int() + offset)
|
.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 {
|
macro_rules! store {
|
||||||
($self:expr, $size:ty) => {{
|
($self:expr, $size:ty) => {{
|
||||||
let ParamRRI(src, a0, offset) = param!($self, ParamRRI);
|
let ParamRRI(src, a0, offset) = param!($self, ParamRRI);
|
||||||
$self
|
if let Err(()) = $self
|
||||||
.memory
|
.memory
|
||||||
.store::<$size>($self.read_reg(a0).int() + offset, $self.read_reg(src))
|
.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
|
/// Program code has to be validated
|
||||||
pub unsafe fn new_unchecked(program: &'a [u8]) -> Self {
|
pub unsafe fn new_unchecked(program: &'a [u8]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
registers: [Value::from(0); 60],
|
registers: [Value::from(0_u64); 60],
|
||||||
memory: Default::default(),
|
memory: Default::default(),
|
||||||
pc: 0,
|
pc: 0,
|
||||||
program,
|
program,
|
||||||
|
@ -84,11 +99,11 @@ impl<'a> Vm<'a> {
|
||||||
Ok(unsafe { Self::new_unchecked(program) })
|
Ok(unsafe { Self::new_unchecked(program) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<(), Exception> {
|
pub fn run(&mut self) -> HaltReason {
|
||||||
use hbbytecode::opcode::*;
|
use hbbytecode::opcode::*;
|
||||||
loop {
|
loop {
|
||||||
let Some(&opcode) = self.program.get(self.pc)
|
let Some(&opcode) = self.program.get(self.pc)
|
||||||
else { return Ok(()) };
|
else { return HaltReason::ProgramEnd };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match opcode {
|
match opcode {
|
||||||
|
@ -101,6 +116,9 @@ impl<'a> Vm<'a> {
|
||||||
AND => binary_op!(self, int, ops::BitAnd::bitand),
|
AND => binary_op!(self, int, ops::BitAnd::bitand),
|
||||||
OR => binary_op!(self, int, ops::BitOr::bitor),
|
OR => binary_op!(self, int, ops::BitOr::bitor),
|
||||||
XOR => binary_op!(self, int, ops::BitXor::bitxor),
|
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 => {
|
NOT => {
|
||||||
let param = param!(self, ParamRR);
|
let param = param!(self, ParamRR);
|
||||||
self.write_reg(param.0, (!self.read_reg(param.1).int()).into());
|
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),
|
SUBF => binary_op!(self, float, ops::Sub::sub),
|
||||||
MULF => binary_op!(self, float, ops::Mul::mul),
|
MULF => binary_op!(self, float, ops::Mul::mul),
|
||||||
DIVF => binary_op!(self, float, ops::Div::div),
|
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 => {
|
CP => {
|
||||||
let param = param!(self, ParamRR);
|
let param = param!(self, ParamRR);
|
||||||
self.write_reg(param.0, self.read_reg(param.1));
|
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);
|
let ParamRI(reg, offset) = param!(self, ParamRI);
|
||||||
self.pc = (self.read_reg(reg).int() + offset) as usize;
|
self.pc = (self.read_reg(reg).int() + offset) as usize;
|
||||||
}
|
}
|
||||||
|
ECALL => {
|
||||||
|
param!(self, ());
|
||||||
|
return HaltReason::Ecall;
|
||||||
|
}
|
||||||
_ => core::hint::unreachable_unchecked(),
|
_ => core::hint::unreachable_unchecked(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +171,7 @@ impl<'a> Vm<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn read_reg(&self, n: u8) -> Value {
|
unsafe fn read_reg(&self, n: u8) -> Value {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
0.into()
|
0_u64.into()
|
||||||
} else {
|
} else {
|
||||||
*self.registers.get_unchecked(n as usize)
|
*self.registers.get_unchecked(n as usize)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +187,9 @@ impl<'a> Vm<'a> {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Exception {
|
pub enum HaltReason {
|
||||||
LoadAccess,
|
ProgramEnd,
|
||||||
StoreAccess,
|
Ecall,
|
||||||
|
LoadAccessEx,
|
||||||
|
StoreAccessEx,
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ macro_rules! value_def {
|
||||||
|
|
||||||
value_def! {
|
value_def! {
|
||||||
i: u64, int;
|
i: u64, int;
|
||||||
|
s: i64, sint;
|
||||||
f: f64, float;
|
f: f64, float;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue