forked from AbleOS/holey-bytes
asdasdasdasdasdasdasdasd
This commit is contained in:
parent
36f4d31fb2
commit
f832f6a04a
|
@ -1,83 +1,99 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
macro_rules! constmod {
|
macro_rules! constmod {
|
||||||
($vis:vis $mname:ident($repr:ty) { $($cname:ident = $val:expr),* $(,)? }) => {
|
($vis:vis $mname:ident($repr:ty) {
|
||||||
|
$(#![doc = $mdoc:literal])?
|
||||||
|
$($cname:ident = $val:expr $(,$doc:literal)?;)*
|
||||||
|
}) => {
|
||||||
|
$(#[doc = $mdoc])?
|
||||||
$vis mod $mname {
|
$vis mod $mname {
|
||||||
$(pub const $cname: $repr = $val;)*
|
$(
|
||||||
|
$(#[doc = $doc])?
|
||||||
|
pub const $cname: $repr = $val;
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
constmod!(pub opcode(u8) {
|
constmod!(pub opcode(u8) {
|
||||||
NOP = 0, // N; Do nothing
|
//! Opcode constant module
|
||||||
|
|
||||||
ADD = 1, // RRR; #0 ← #1 + #2
|
NOP = 0, "N; Do nothing";
|
||||||
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)
|
|
||||||
CMP = 12, // RRR; #0 ← #1 <=> #2
|
|
||||||
CMPU = 13, // RRR; #0 ← #1 <=> #2 (unsigned)
|
|
||||||
NOT = 14, // RR; #0 ← !#1
|
|
||||||
|
|
||||||
ADDF = 15, // RRR; #0 ← #1 +. #2
|
ADD = 1, "RRR; #0 ← #1 + #2";
|
||||||
SUBF = 16, // RRR; #0 ← #1 +. #2
|
SUB = 2, "RRR; #0 ← #1 - #2";
|
||||||
MULF = 17, // RRR; #0 ← #1 +. #2
|
MUL = 3, "RRR; #0 ← #1 × #2";
|
||||||
DIVF = 18, // RRR; #0 ← #1 +. #2
|
DIV = 4, "RRR; #0 ← #1 ÷ #2";
|
||||||
ADDI = 19, // RRI; #0 ← #1 + imm #2
|
REM = 5, "RRR; #0 ← #1 % #2";
|
||||||
MULI = 20, // RRI; #0 ← #1 × imm #2
|
AND = 6, "RRR; #0 ← #1 & #2";
|
||||||
REMI = 21, // RRI; #0 ← #1 % imm #2
|
OR = 7, "RRR; #0 ← #1 | #2";
|
||||||
ANDI = 22, // RRI; #0 ← #1 & imm #2
|
XOR = 8, "RRR; #0 ← #1 ^ #2";
|
||||||
ORI = 23, // RRI; #0 ← #1 | imm #2
|
SL = 9, "RRR; #0 ← #1 « #2";
|
||||||
XORI = 24, // RRI; #0 ← #1 ^ imm #2
|
SR = 10, "RRR; #0 ← #1 » #2";
|
||||||
SLI = 25, // RRI; #0 ← #1 « imm #2
|
SRS = 11, "RRR; #0 ← #1 » #2 (signed)";
|
||||||
SRI = 26, // RRI; #0 ← #1 » imm #2
|
CMP = 12, "RRR; #0 ← #1 <=> #2";
|
||||||
SRSI = 27, // RRI; #0 ← #1 » imm #2 (signed)
|
CMPU = 13, "RRR; #0 ← #1 <=> #2 (unsigned)";
|
||||||
CMPI = 28, // RRI; #0 ← #1 <=> imm #2
|
NOT = 14, "RR; #0 ← !#1";
|
||||||
CMPUI = 29, // RRI; #0 ← #1 <=> imm #2 (unsigned)
|
|
||||||
|
|
||||||
ADDFI = 30, // RRI; #0 ← #1 +. imm #2
|
ADDF = 15, "RRR; #0 ← #1 +. #2";
|
||||||
MULFI = 31, // RRI; #0 ← #1 *. imm #2
|
SUBF = 16, "RRR; #0 ← #1 +. #2";
|
||||||
|
MULF = 17, "RRR; #0 ← #1 +. #2";
|
||||||
|
DIVF = 18, "RRR; #0 ← #1 +. #2";
|
||||||
|
ADDI = 19, "RRI; #0 ← #1 + imm #2";
|
||||||
|
MULI = 20, "RRI; #0 ← #1 × imm #2";
|
||||||
|
REMI = 21, "RRI; #0 ← #1 % imm #2";
|
||||||
|
ANDI = 22, "RRI; #0 ← #1 & imm #2";
|
||||||
|
ORI = 23, "RRI; #0 ← #1 | imm #2";
|
||||||
|
XORI = 24, "RRI; #0 ← #1 ^ imm #2";
|
||||||
|
SLI = 25, "RRI; #0 ← #1 « imm #2";
|
||||||
|
SRI = 26, "RRI; #0 ← #1 » imm #2";
|
||||||
|
SRSI = 27, "RRI; #0 ← #1 » imm #2 (signed)";
|
||||||
|
CMPI = 28, "RRI; #0 ← #1 <=> imm #2";
|
||||||
|
CMPUI = 29, "RRI; #0 ← #1 <=> imm #2 (unsigned)";
|
||||||
|
|
||||||
CP = 32, // RR; Copy #0 ← #1
|
ADDFI = 30, "RRI; #0 ← #1 +. imm #2";
|
||||||
LI = 33, // RI; Load immediate, #0 ← imm #1
|
MULFI = 31, "RRI; #0 ← #1 *. imm #2";
|
||||||
LB = 34, // RRI; Load byte (8 bits), #0 ← [#1 + imm #2]
|
|
||||||
LD = 35, // RRI; Load doublet (16 bits)
|
|
||||||
LQ = 36, // RRI; Load quadlet (32 bits)
|
|
||||||
LO = 37, // RRI; Load octlet (64 bits)
|
|
||||||
SB = 38, // RRI; Store byte, [#1 + imm #2] ← #0
|
|
||||||
SD = 39, // RRI; Store doublet
|
|
||||||
SQ = 40, // RRI; Store quadlet
|
|
||||||
SO = 41, // RRI; Store octlet
|
|
||||||
|
|
||||||
JMP = 42, // RI; Unconditional jump [#0 + imm #1]
|
CP = 32, "RR; Copy #0 ← #1";
|
||||||
JEQ = 43, // RRI; if #0 = #1 → jump imm #2
|
LI = 33, "RI; Load immediate, #0 ← imm #1";
|
||||||
JNE = 44, // RRI; if #0 ≠ #1 → jump imm #2
|
LB = 34, "RRI; Load byte (8 bits), #0 ← [#1 + imm #2]";
|
||||||
JLT = 45, // RRI; if #0 < #1 → jump imm #2
|
LD = 35, "RRI; Load doublet (16 bits)";
|
||||||
JGT = 46, // RRI; if #0 > #1 → jump imm #2
|
LQ = 36, "RRI; Load quadlet (32 bits)";
|
||||||
JLTU = 47, // RRI; if #0 < #1 → jump imm #2 (unsigned)
|
LO = 37, "RRI; Load octlet (64 bits)";
|
||||||
JGTU = 48, // RRI; if #0 > #1 → jump imm #2 (unsigned)
|
SB = 38, "RRI; Store byte, [#1 + imm #2] ← #0";
|
||||||
RET = 49, // N; Return
|
SD = 39, "RRI; Store doublet";
|
||||||
ECALL = 50, // N; Issue system call
|
SQ = 40, "RRI; Store quadlet";
|
||||||
|
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 instruction parameter
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ParamRRR(pub u8, pub u8, pub u8);
|
pub struct ParamRRR(pub u8, pub u8, pub u8);
|
||||||
|
|
||||||
|
/// Register-register-immediate intruction parameter
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ParamRRI(pub u8, pub u8, pub u64);
|
pub struct ParamRRI(pub u8, pub u8, pub u64);
|
||||||
|
|
||||||
|
/// Register-register instruction parameter
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ParamRR(pub u8, pub u8);
|
pub struct ParamRR(pub u8, pub u8);
|
||||||
|
|
||||||
|
/// Register-immediate instruction parameter
|
||||||
#[repr(packed)]
|
#[repr(packed)]
|
||||||
pub struct ParamRI(pub u8, pub u64);
|
pub struct ParamRI(pub u8, pub u64);
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// TODO.
|
/// Has to be valid to be decoded from bytecode.
|
||||||
pub unsafe trait OpParam {}
|
pub unsafe trait OpParam {}
|
||||||
unsafe impl OpParam for ParamRRR {}
|
unsafe impl OpParam for ParamRRR {}
|
||||||
unsafe impl OpParam for ParamRRI {}
|
unsafe impl OpParam for ParamRRI {}
|
||||||
|
|
|
@ -19,8 +19,8 @@ pub enum ErrorKind {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
kind: ErrorKind,
|
pub kind: ErrorKind,
|
||||||
index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
pub fn validate(mut program: &[u8]) -> Result<(), Error> {
|
||||||
|
|
|
@ -27,8 +27,11 @@ impl Memory {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load value from an address
|
||||||
pub fn load<S: MemAccessSize>(&self, addr: u64) -> Option<Value> {
|
pub fn load<S: MemAccessSize>(&self, addr: u64) -> Option<Value> {
|
||||||
let (page, offset) = split_addr(addr);
|
let (page, offset) = split_addr(addr);
|
||||||
|
|
||||||
|
// Check if copy won't get over page boundary (TODO: make it go over)
|
||||||
if offset + S::BYTES <= PAGE_SIZE - 1 {
|
if offset + S::BYTES <= PAGE_SIZE - 1 {
|
||||||
let mut value = MaybeUninit::<Value>::zeroed();
|
let mut value = MaybeUninit::<Value>::zeroed();
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -37,6 +40,9 @@ impl Memory {
|
||||||
value.as_mut_ptr().cast(),
|
value.as_mut_ptr().cast(),
|
||||||
S::BYTES,
|
S::BYTES,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Even zeroed [`Value`] if holding valid variants as defined is valid,
|
||||||
|
// this is always valid.
|
||||||
Some(value.assume_init())
|
Some(value.assume_init())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,8 +50,12 @@ impl Memory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Store value to an address
|
||||||
pub fn store<S: MemAccessSize>(&mut self, addr: u64, value: Value) -> Result<(), ()> {
|
pub fn store<S: MemAccessSize>(&mut self, addr: u64, value: Value) -> Result<(), ()> {
|
||||||
let (page, offset) = split_addr(addr);
|
let (page, offset) = split_addr(addr);
|
||||||
|
|
||||||
|
// Check if copy won't get over page boundary (TODO: make it go over)
|
||||||
if offset + S::BYTES <= PAGE_SIZE - 1 {
|
if offset + S::BYTES <= PAGE_SIZE - 1 {
|
||||||
unsafe {
|
unsafe {
|
||||||
core::ptr::copy_nonoverlapping(
|
core::ptr::copy_nonoverlapping(
|
||||||
|
@ -65,6 +75,7 @@ impl Memory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split address into page number and in-page offset
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn split_addr(addr: u64) -> (u64, usize) {
|
pub const fn split_addr(addr: u64) -> (u64, usize) {
|
||||||
(addr >> PAGE_SIZE.count_ones(), (addr as usize & PAGE_SIZE))
|
(addr >> PAGE_SIZE.count_ones(), (addr as usize & PAGE_SIZE))
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
|
//! HoleyBytes Virtual Machine
|
||||||
|
//!
|
||||||
|
//! All unsafe code here should be sound, if input bytecode passes validation.
|
||||||
|
|
||||||
|
// # General safety notice:
|
||||||
|
// - Validation has to assure there is 60 registers (r0 - r59)
|
||||||
|
// - Instructions has to be valid as specified (values and sizes)
|
||||||
|
// - Mapped pages should be at least 8 KiB
|
||||||
|
|
||||||
|
mod mem;
|
||||||
|
mod value;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
|
crate::validate,
|
||||||
core::ops,
|
core::ops,
|
||||||
hbbytecode::{OpParam, ParamRI, ParamRR, ParamRRI, ParamRRR},
|
hbbytecode::{OpParam, ParamRI, ParamRR, ParamRRI, ParamRRR},
|
||||||
mem::{ma_size, Memory},
|
mem::{ma_size, Memory},
|
||||||
|
@ -6,11 +19,6 @@ use {
|
||||||
value::Value,
|
value::Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::validate;
|
|
||||||
|
|
||||||
mod mem;
|
|
||||||
mod value;
|
|
||||||
|
|
||||||
macro_rules! param {
|
macro_rules! param {
|
||||||
($self:expr, $ty:ty) => {{
|
($self:expr, $ty:ty) => {{
|
||||||
assert_impl_one!($ty: OpParam);
|
assert_impl_one!($ty: OpParam);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use core::fmt::Debug;
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The macro invoker shall make sure that byte reinterpret-cast
|
/// The macro invoker shall make sure that byte reinterpret-cast
|
||||||
/// won't cause undefined behaviour.
|
/// or zero-init won't cause undefined behaviour.
|
||||||
macro_rules! value_def {
|
macro_rules! value_def {
|
||||||
($($fname:ident : $fty:ident, $getter:ident);* $(;)?) => {
|
($($fname:ident : $fty:ident, $getter:ident);* $(;)?) => {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
Loading…
Reference in a new issue