Program interrupts, immediate binary ops and bitshifts.

This commit is contained in:
Erin 2023-06-09 00:10:46 +02:00 committed by ondra05
parent da6ad6d2c7
commit 417047806b
6 changed files with 99 additions and 52 deletions

View file

@ -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() {

View file

@ -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)]

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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,
} }

View file

@ -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;
} }