Merged division with remainder
This commit is contained in:
parent
b7ff456808
commit
059e2b4b66
|
@ -52,9 +52,9 @@ macro_rules! tokendef {
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
tokendef![
|
tokendef![
|
||||||
"nop", "add", "sub", "mul", "rem", "and", "or", "xor", "sl", "sr", "srs",
|
"nop", "add", "sub", "mul", "and", "or", "xor", "sl", "sr", "srs", "cmp", "cmpu", "not",
|
||||||
"cmp", "cmpu", "not", "addf", "subf", "mulf", "divf", "addi", "muli", "remi", "andi",
|
"dir", "addf", "subf", "mulf", "dirf", "addi", "muli", "andi", "ori",
|
||||||
"ori", "xori", "sli", "sri", "srsi", "cmpi", "cmpui", "addfi", "mulfi", "cp", "li", "lb",
|
"xori", "sli", "sri", "srsi", "cmpi", "cmpui", "addfi", "mulfi", "cp", "li", "lb",
|
||||||
"ld", "lq", "lo", "sb", "sd", "sq", "so", "jmp", "jeq", "jne", "jlt", "jgt",
|
"ld", "lq", "lo", "sb", "sd", "sq", "so", "jmp", "jeq", "jne", "jlt", "jgt",
|
||||||
"jltu", "jgtu", "ret", "ecall",
|
"jltu", "jgtu", "ret", "ecall",
|
||||||
];
|
];
|
||||||
|
@ -113,7 +113,8 @@ 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..=CMPU | ADDF..=DIVF => self.rrr(),
|
DIR | DIRF => self.rrrr(),
|
||||||
|
ADD..=CMPU | ADDF..=MULF => self.rrr(),
|
||||||
NOT | CP => self.rr(),
|
NOT | CP => self.rr(),
|
||||||
LI | JMP => self.ri(),
|
LI | JMP => self.ri(),
|
||||||
ADDI..=MULFI | LB..=SO | JEQ..=JGTU => self.rri(),
|
ADDI..=MULFI | LB..=SO | JEQ..=JGTU => self.rri(),
|
||||||
|
@ -192,6 +193,21 @@ pub fn assembly(code: &str, buf: &mut Vec<u8>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rrrr(&mut self) -> Result<(), ErrorKind> {
|
||||||
|
expect_matches!(
|
||||||
|
self,
|
||||||
|
Token::Register(r0),
|
||||||
|
Token::PSep,
|
||||||
|
Token::Register(r1),
|
||||||
|
Token::PSep,
|
||||||
|
Token::Register(r2),
|
||||||
|
Token::PSep,
|
||||||
|
Token::Register(r3),
|
||||||
|
);
|
||||||
|
self.buf.extend([r0, r1, r2, r3]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn insert_imm(&mut self) -> Result<(), ErrorKind> {
|
fn insert_imm(&mut self) -> Result<(), ErrorKind> {
|
||||||
let imm = match self.next()? {
|
let imm = match self.next()? {
|
||||||
Token::Integer(i) => i.to_le_bytes(),
|
Token::Integer(i) => i.to_le_bytes(),
|
||||||
|
|
|
@ -23,59 +23,62 @@ constmod!(pub opcode(u8) {
|
||||||
ADD = 1, "RRR; #0 ← #1 + #2";
|
ADD = 1, "RRR; #0 ← #1 + #2";
|
||||||
SUB = 2, "RRR; #0 ← #1 - #2";
|
SUB = 2, "RRR; #0 ← #1 - #2";
|
||||||
MUL = 3, "RRR; #0 ← #1 × #2";
|
MUL = 3, "RRR; #0 ← #1 × #2";
|
||||||
DIV = 4, "RRR; #0 ← #1 ÷ #2";
|
AND = 4, "RRR; #0 ← #1 & #2";
|
||||||
REM = 5, "RRR; #0 ← #1 % #2";
|
OR = 5, "RRR; #0 ← #1 | #2";
|
||||||
AND = 6, "RRR; #0 ← #1 & #2";
|
XOR = 6, "RRR; #0 ← #1 ^ #2";
|
||||||
OR = 7, "RRR; #0 ← #1 | #2";
|
SL = 7, "RRR; #0 ← #1 « #2";
|
||||||
XOR = 8, "RRR; #0 ← #1 ^ #2";
|
SR = 8, "RRR; #0 ← #1 » #2";
|
||||||
SL = 9, "RRR; #0 ← #1 « #2";
|
SRS = 9, "RRR; #0 ← #1 » #2 (signed)";
|
||||||
SR = 10, "RRR; #0 ← #1 » #2";
|
CMP = 10, "RRR; #0 ← #1 <=> #2";
|
||||||
SRS = 11, "RRR; #0 ← #1 » #2 (signed)";
|
CMPU = 11, "RRR; #0 ← #1 <=> #2 (unsigned)";
|
||||||
CMP = 12, "RRR; #0 ← #1 <=> #2";
|
DIR = 12, "RRRR; #0 ← #2 / #3, #1 ← #2 % #3";
|
||||||
CMPU = 13, "RRR; #0 ← #1 <=> #2 (unsigned)";
|
NOT = 13, "RR; #0 ← !#1";
|
||||||
NOT = 14, "RR; #0 ← !#1";
|
|
||||||
|
|
||||||
ADDF = 15, "RRR; #0 ← #1 +. #2";
|
ADDF = 14, "RRR; #0 ← #1 +. #2";
|
||||||
SUBF = 16, "RRR; #0 ← #1 +. #2";
|
SUBF = 15, "RRR; #0 ← #1 +. #2";
|
||||||
MULF = 17, "RRR; #0 ← #1 +. #2";
|
MULF = 16, "RRR; #0 ← #1 +. #2";
|
||||||
DIVF = 18, "RRR; #0 ← #1 +. #2";
|
ADDI = 17, "RRI; #0 ← #1 + imm #2";
|
||||||
ADDI = 19, "RRI; #0 ← #1 + imm #2";
|
MULI = 18, "RRI; #0 ← #1 × imm #2";
|
||||||
MULI = 20, "RRI; #0 ← #1 × imm #2";
|
ANDI = 19, "RRI; #0 ← #1 & imm #2";
|
||||||
REMI = 21, "RRI; #0 ← #1 % imm #2";
|
ORI = 20, "RRI; #0 ← #1 | imm #2";
|
||||||
ANDI = 22, "RRI; #0 ← #1 & imm #2";
|
XORI = 21, "RRI; #0 ← #1 ^ imm #2";
|
||||||
ORI = 23, "RRI; #0 ← #1 | imm #2";
|
SLI = 22, "RRI; #0 ← #1 « imm #2";
|
||||||
XORI = 24, "RRI; #0 ← #1 ^ imm #2";
|
SRI = 23, "RRI; #0 ← #1 » imm #2";
|
||||||
SLI = 25, "RRI; #0 ← #1 « imm #2";
|
SRSI = 24, "RRI; #0 ← #1 » imm #2 (signed)";
|
||||||
SRI = 26, "RRI; #0 ← #1 » imm #2";
|
CMPI = 25, "RRI; #0 ← #1 <=> imm #2";
|
||||||
SRSI = 27, "RRI; #0 ← #1 » imm #2 (signed)";
|
CMPUI = 26, "RRI; #0 ← #1 <=> imm #2 (unsigned)";
|
||||||
CMPI = 28, "RRI; #0 ← #1 <=> imm #2";
|
DIRF = 27, "RRRR; #0 ← #2 / #3, #1 ← #2 % #3";
|
||||||
CMPUI = 29, "RRI; #0 ← #1 <=> imm #2 (unsigned)";
|
|
||||||
|
ADDFI = 28, "RRI; #0 ← #1 +. imm #2";
|
||||||
|
MULFI = 29, "RRI; #0 ← #1 *. imm #2";
|
||||||
|
|
||||||
ADDFI = 30, "RRI; #0 ← #1 +. imm #2";
|
CP = 30, "RR; Copy #0 ← #1";
|
||||||
MULFI = 31, "RRI; #0 ← #1 *. imm #2";
|
LI = 31, "RI; Load immediate, #0 ← imm #1";
|
||||||
|
LB = 32, "RRI; Load byte (8 bits), #0 ← [#1 + imm #2]";
|
||||||
|
LD = 33, "RRI; Load doublet (16 bits)";
|
||||||
|
LQ = 34, "RRI; Load quadlet (32 bits)";
|
||||||
|
LO = 35, "RRI; Load octlet (64 bits)";
|
||||||
|
SB = 36, "RRI; Store byte, [#1 + imm #2] ← #0";
|
||||||
|
SD = 37, "RRI; Store doublet";
|
||||||
|
SQ = 38, "RRI; Store quadlet";
|
||||||
|
SO = 39, "RRI; Store octlet";
|
||||||
|
|
||||||
CP = 32, "RR; Copy #0 ← #1";
|
JMP = 40, "RI; Unconditional jump [#0 + imm #1]";
|
||||||
LI = 33, "RI; Load immediate, #0 ← imm #1";
|
JEQ = 41, "RRI; if #0 = #1 → jump imm #2";
|
||||||
LB = 34, "RRI; Load byte (8 bits), #0 ← [#1 + imm #2]";
|
JNE = 42, "RRI; if #0 ≠ #1 → jump imm #2";
|
||||||
LD = 35, "RRI; Load doublet (16 bits)";
|
JLT = 43, "RRI; if #0 < #1 → jump imm #2";
|
||||||
LQ = 36, "RRI; Load quadlet (32 bits)";
|
JGT = 44, "RRI; if #0 > #1 → jump imm #2";
|
||||||
LO = 37, "RRI; Load octlet (64 bits)";
|
JLTU = 45, "RRI; if #0 < #1 → jump imm #2 (unsigned)";
|
||||||
SB = 38, "RRI; Store byte, [#1 + imm #2] ← #0";
|
JGTU = 46, "RRI; if #0 > #1 → jump imm #2 (unsigned)";
|
||||||
SD = 39, "RRI; Store doublet";
|
RET = 47, "N; Return";
|
||||||
SQ = 40, "RRI; Store quadlet";
|
ECALL = 48, "N; Issue system call";
|
||||||
SO = 41, "RRI; Store octlet";
|
|
||||||
|
|
||||||
JMP = 42, "RI; Unconditional jump [#0 + imm #1]";
|
|
||||||
JEQ = 43, "RRI; if #0 = #1 → jump imm #2";
|
|
||||||
JNE = 44, "RRI; if #0 ≠ #1 → jump imm #2";
|
|
||||||
JLT = 45, "RRI; if #0 < #1 → jump imm #2";
|
|
||||||
JGT = 46, "RRI; if #0 > #1 → jump imm #2";
|
|
||||||
JLTU = 47, "RRI; if #0 < #1 → jump imm #2 (unsigned)";
|
|
||||||
JGTU = 48, "RRI; if #0 > #1 → jump imm #2 (unsigned)";
|
|
||||||
RET = 49, "N; Return";
|
|
||||||
ECALL = 50, "N; Issue system call";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/// Register-register-register-register instruction parameter
|
||||||
|
#[repr(packed)]
|
||||||
|
pub struct ParamRRRR(pub u8, pub u8, pub u8, pub u8);
|
||||||
|
|
||||||
/// Register-register-register instruction parameter
|
/// Register-register-register instruction parameter
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ParamRRR(pub u8, pub u8, pub u8);
|
pub struct ParamRRR(pub u8, pub u8, pub u8);
|
||||||
|
@ -95,6 +98,7 @@ pub struct ParamRI(pub u8, pub u64);
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Has to be valid to be decoded from bytecode.
|
/// Has to be valid to be decoded from bytecode.
|
||||||
pub unsafe trait OpParam {}
|
pub unsafe trait OpParam {}
|
||||||
|
unsafe impl OpParam for ParamRRRR {}
|
||||||
unsafe impl OpParam for ParamRRR {}
|
unsafe impl OpParam for ParamRRR {}
|
||||||
unsafe impl OpParam for ParamRRI {}
|
unsafe impl OpParam for ParamRRI {}
|
||||||
unsafe impl OpParam for ParamRR {}
|
unsafe impl OpParam for ParamRR {}
|
||||||
|
|
|
@ -40,8 +40,15 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
||||||
[] => return Ok(()),
|
[] => return Ok(()),
|
||||||
// N
|
// N
|
||||||
[NOP | RET | ECALL, rest @ ..] => rest,
|
[NOP | RET | ECALL, rest @ ..] => rest,
|
||||||
|
// RRRR
|
||||||
|
[DIR | DIRF, _, _, _, _, rest @ ..] => {
|
||||||
|
if let Some(n) = reg(&program[1..=4]) {
|
||||||
|
bail!(InvalidRegister, start, program, n + 1);
|
||||||
|
}
|
||||||
|
rest
|
||||||
|
}
|
||||||
// RRR
|
// RRR
|
||||||
[ADD..=CMPU | ADDF..=DIVF, _, _, _, rest @ ..] => {
|
[ADD..=CMPU | ADDF..=MULF, _, _, _, 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! HoleyBytes Virtual Machine
|
//! HoleyBytes Virtual Machine
|
||||||
//!
|
//!
|
||||||
//! All unsafe code here should be sound, if input bytecode passes validation.
|
//! All unsafe code here should be sound, if input bytecode passes validation.
|
||||||
|
|
||||||
// # General safety notice:
|
// # General safety notice:
|
||||||
|
@ -11,6 +11,8 @@
|
||||||
// program size. If you are (rightfully) worried about the UB, for now just
|
// program size. If you are (rightfully) worried about the UB, for now just
|
||||||
// append your program with 11 zeroes.
|
// append your program with 11 zeroes.
|
||||||
|
|
||||||
|
use hbbytecode::ParamRRRR;
|
||||||
|
|
||||||
mod mem;
|
mod mem;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
|
@ -136,8 +138,6 @@ impl<'a> Vm<'a> {
|
||||||
ADD => binary_op!(self, int, u64::wrapping_add),
|
ADD => binary_op!(self, int, u64::wrapping_add),
|
||||||
SUB => binary_op!(self, int, u64::wrapping_sub),
|
SUB => binary_op!(self, int, u64::wrapping_sub),
|
||||||
MUL => binary_op!(self, int, u64::wrapping_mul),
|
MUL => binary_op!(self, int, u64::wrapping_mul),
|
||||||
DIV => binary_op!(self, int, u64::wrapping_div),
|
|
||||||
REM => binary_op!(self, int, u64::wrapping_rem),
|
|
||||||
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),
|
||||||
|
@ -162,13 +162,25 @@ impl<'a> Vm<'a> {
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
DIR => {
|
||||||
|
let ParamRRRR(dt, rt, a0, a1) = param!(self, ParamRRRR);
|
||||||
|
let a0 = self.read_reg(a0).int();
|
||||||
|
let a1 = self.read_reg(a1).int();
|
||||||
|
self.write_reg(dt, (a0.checked_div(a1).unwrap_or(u64::MAX)).into());
|
||||||
|
self.write_reg(rt, (a0.checked_rem(a1).unwrap_or(u64::MAX)).into());
|
||||||
|
}
|
||||||
ADDF => binary_op!(self, float, ops::Add::add),
|
ADDF => binary_op!(self, float, ops::Add::add),
|
||||||
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),
|
DIRF => {
|
||||||
|
let ParamRRRR(dt, rt, a0, a1) = param!(self, ParamRRRR);
|
||||||
|
let a0 = self.read_reg(a0).float();
|
||||||
|
let a1 = self.read_reg(a1).float();
|
||||||
|
self.write_reg(dt, (a0 / a1).into());
|
||||||
|
self.write_reg(rt, (a0 % a1).into());
|
||||||
|
}
|
||||||
ADDI => binary_op_imm!(self, int, ops::Add::add),
|
ADDI => binary_op_imm!(self, int, ops::Add::add),
|
||||||
MULI => binary_op_imm!(self, int, ops::Mul::mul),
|
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),
|
ANDI => binary_op_imm!(self, int, ops::BitAnd::bitand),
|
||||||
ORI => binary_op_imm!(self, int, ops::BitOr::bitor),
|
ORI => binary_op_imm!(self, int, ops::BitOr::bitor),
|
||||||
XORI => binary_op_imm!(self, int, ops::BitXor::bitxor),
|
XORI => binary_op_imm!(self, int, ops::BitXor::bitxor),
|
||||||
|
|
Loading…
Reference in a new issue