Add instruction visitor, which traverses memory and choosing instructions
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use crate::vm::{vm::*, reg::Reg};
|
use crate::vm::{inst::InstOp, reg::Reg, vm::*};
|
||||||
use snafu::Snafu;
|
use snafu::Snafu;
|
||||||
|
|
||||||
#[derive(Snafu, Debug, Clone)]
|
#[derive(Snafu, Debug, Clone)]
|
||||||
@@ -7,6 +7,8 @@ pub enum VmError {
|
|||||||
IllegalReg { reg: Reg },
|
IllegalReg { reg: Reg },
|
||||||
#[snafu(display("memory address out of bounds: 0x{:016x}", addr))]
|
#[snafu(display("memory address out of bounds: 0x{:016x}", addr))]
|
||||||
MemOutOfBounds { addr: Addr },
|
MemOutOfBounds { addr: Addr },
|
||||||
|
#[snafu(display("illegal instruction opcode: 0x{:04x}", op))]
|
||||||
|
IllegalOp { op: InstOp },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T, E = VmError> = std::result::Result<T, E>;
|
pub type Result<T, E = VmError> = std::result::Result<T, E>;
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ pub mod mem;
|
|||||||
pub mod obj;
|
pub mod obj;
|
||||||
pub mod reg;
|
pub mod reg;
|
||||||
mod tick;
|
mod tick;
|
||||||
|
pub mod visit;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|||||||
308
src/vm/tick.rs
308
src/vm/tick.rs
@@ -1,134 +1,190 @@
|
|||||||
use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*};
|
use crate::vm::{error::*, flags::Flags, inst::*, reg::*, vm::*, visit::*, mem::MemCursor};
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
pub fn tick(&mut self) -> Result<()> {
|
pub fn tick(&mut self) -> Result<()> {
|
||||||
let mut cursor = self.mem_cursor(self.ip() as usize);
|
let next_ip = visit_inst(self)?;
|
||||||
let op = cursor.next_u16()?;
|
|
||||||
let next_ip;
|
|
||||||
|
|
||||||
macro_rules! math_inst {
|
|
||||||
($mapping:expr) => {{
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = ($mapping)(self.get_reg_checked(r1)?, self.get_reg_checked(r2)?);
|
|
||||||
self.set_reg(r1, value);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
match op {
|
|
||||||
ADD => math_inst!(|w1: u64, w2: u64| w1.wrapping_add(w2)),
|
|
||||||
MUL => math_inst!(|w1: u64, w2: u64| w1.wrapping_mul(w2)),
|
|
||||||
DIV => math_inst!(|w1: u64, w2: u64| w1.wrapping_div(w2)),
|
|
||||||
MOD => math_inst!(|w1: u64, w2: u64| w1 % w2),
|
|
||||||
INEG => todo!(),
|
|
||||||
AND => math_inst!(|w1: u64, w2: u64| w1 & w2),
|
|
||||||
OR => math_inst!(|w1: u64, w2: u64| w1 | w2),
|
|
||||||
INV => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = self.get_reg_checked(r1)?;
|
|
||||||
self.set_reg(r1, !value);
|
|
||||||
}
|
|
||||||
NOT => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = self.get_reg(r1);
|
|
||||||
self.set_reg(r1, (value == 0) as Word);
|
|
||||||
}
|
|
||||||
XOR => math_inst!(|w1: u64, w2: u64| w1 ^ w2),
|
|
||||||
SHL => math_inst!(|w1: u64, w2: u64| w1 << w2),
|
|
||||||
SHR => math_inst!(|w1: u64, w2: u64| w1 >> w2),
|
|
||||||
CMPEQ => {
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let cmp = self.get_reg(r1) == self.get_reg(r2);
|
|
||||||
if cmp {
|
|
||||||
self.insert_flags(Flags::COMPARE);
|
|
||||||
} else {
|
|
||||||
self.remove_flags(Flags::COMPARE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CMPLT => {
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let cmp = self.get_reg(r1) < self.get_reg(r2);
|
|
||||||
if cmp {
|
|
||||||
self.insert_flags(Flags::COMPARE);
|
|
||||||
} else {
|
|
||||||
self.remove_flags(Flags::COMPARE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JMP => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
next_ip = self.get_reg(r1);
|
|
||||||
}
|
|
||||||
JZ => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
if !self.flags().contains(Flags::COMPARE) {
|
|
||||||
next_ip = self.get_reg(r1);
|
|
||||||
} else {
|
|
||||||
next_ip = cursor.position();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JNZ => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
if self.flags().contains(Flags::COMPARE) {
|
|
||||||
next_ip = self.get_reg(r1);
|
|
||||||
} else {
|
|
||||||
next_ip = cursor.position();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LOAD => {
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = self.load(r2)?;
|
|
||||||
self.set_reg_checked(r1, value)?;
|
|
||||||
}
|
|
||||||
REGCOPY => math_inst!(|_: u64, w2: u64| w2),
|
|
||||||
STOREIMM64 => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
// skip
|
|
||||||
cursor.next_u32()?;
|
|
||||||
let imm = cursor.next_u64()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
self.set_reg(r1, imm);
|
|
||||||
}
|
|
||||||
STOREIMM32 => {
|
|
||||||
let r1 = cursor.next_reg()?;
|
|
||||||
let imm = cursor.next_u32()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
self.set_reg(r1, imm as u64);
|
|
||||||
}
|
|
||||||
MEMCOPY => {
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = self.load(r2)?;
|
|
||||||
self.store(r1, value)?;
|
|
||||||
}
|
|
||||||
STORE => {
|
|
||||||
let (r1, r2) = cursor.next_regs()?;
|
|
||||||
next_ip = cursor.position();
|
|
||||||
let value = self.get_reg(r1);
|
|
||||||
self.store(r2, value)?;
|
|
||||||
}
|
|
||||||
HALT => {
|
|
||||||
next_ip = cursor.position();
|
|
||||||
self.insert_flags(Flags::HALT);
|
|
||||||
}
|
|
||||||
NOP => {
|
|
||||||
next_ip = cursor.position();
|
|
||||||
}
|
|
||||||
_ => panic!("unknown instruction opcode: 0x{:04x}", op),
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("op: {:04x} {}", op, inst_name(op).unwrap());
|
|
||||||
println!("ip: {:05x}", self.ip());
|
|
||||||
println!("next_ip: {:05x}", next_ip);
|
|
||||||
let mut _line = String::new();
|
|
||||||
stdin().read_line(&mut _line).unwrap();
|
|
||||||
|
|
||||||
self.set_reg(IP, next_ip);
|
self.set_reg(IP, next_ip);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_ip(&self) -> Result<Addr> {
|
||||||
|
let ip = self.ip();
|
||||||
|
let op = self.get_inst_op(ip)?;
|
||||||
|
Ok(ip + (inst_len(op) as u64))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_regs<F, B>(&mut self, r1: Reg, r2: Reg, mapping: F) -> B
|
||||||
|
where F: FnOnce(Word, Word) -> B
|
||||||
|
{
|
||||||
|
let w1 = self.get_reg(r1);
|
||||||
|
let w2 = self.get_reg(r2);
|
||||||
|
(mapping)(w1, w2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstAcceptor for Vm {
|
||||||
|
type Out = Addr;
|
||||||
|
|
||||||
|
fn cursor(&self) -> MemCursor {
|
||||||
|
self.mem_cursor(self.ip() as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_add(w2));
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1.wrapping_mul(w2));
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
// TODO : check w2 == 0 and throw error/exception
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 / w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
// TODO : check w2 == 0 and throw error/exception
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 % w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ineg(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
let w1 = self.get_reg(r1);
|
||||||
|
self.set_reg(r1, (!w1).wrapping_add(1));
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 & w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 | w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inv(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
let w1 = self.get_reg(r1);
|
||||||
|
self.set_reg(r1, !w1);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
let w1 = self.get_reg(r1);
|
||||||
|
self.set_reg(r1, (w1 == 0) as Word);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 ^ w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 << w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let out = self.with_regs(r1, r2, |w1, w2| w1 >> w2);
|
||||||
|
self.set_reg(r1, out);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let cmp = self.with_regs(r1, r2, |w1, w2| w1 == w2);
|
||||||
|
if cmp {
|
||||||
|
self.insert_flags(Flags::COMPARE);
|
||||||
|
} else {
|
||||||
|
self.remove_flags(Flags::COMPARE);
|
||||||
|
}
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let cmp = self.with_regs(r1, r2, |w1, w2| w1 < w2);
|
||||||
|
if cmp {
|
||||||
|
self.insert_flags(Flags::COMPARE);
|
||||||
|
} else {
|
||||||
|
self.remove_flags(Flags::COMPARE);
|
||||||
|
}
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jmp(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
let addr = self.get_reg(r1);
|
||||||
|
Ok(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jz(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
if !self.flags().contains(Flags::COMPARE) {
|
||||||
|
Ok(self.get_reg(r1))
|
||||||
|
} else {
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jnz(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
if self.flags().contains(Flags::COMPARE) {
|
||||||
|
Ok(self.get_reg(r1))
|
||||||
|
} else {
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let value = Vm::load(self, r2)?;
|
||||||
|
self.set_reg_checked(r1, value)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let value = self.get_reg_checked(r2)?;
|
||||||
|
self.set_reg_checked(r1, value)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out> {
|
||||||
|
self.set_reg_checked(r1, w1)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out> {
|
||||||
|
self.set_reg_checked(r1, w1 as Word)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let value = Vm::load(self, r2)?;
|
||||||
|
self.store(r1, value)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
let value = self.get_reg_checked(r1)?;
|
||||||
|
self.store(r2, value)?;
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn halt(&mut self) -> Result<Self::Out> {
|
||||||
|
self.insert_flags(Flags::HALT);
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nop(&mut self) -> Result<Self::Out> {
|
||||||
|
self.next_ip()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
95
src/vm/visit.rs
Normal file
95
src/vm/visit.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use crate::vm::{
|
||||||
|
error::*,
|
||||||
|
inst::*,
|
||||||
|
mem::MemCursor,
|
||||||
|
reg::Reg,
|
||||||
|
vm::{HalfWord, Word},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait InstAcceptor {
|
||||||
|
type Out;
|
||||||
|
|
||||||
|
fn cursor(&self) -> MemCursor;
|
||||||
|
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn ineg(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn inv(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn not(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn jmp(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn jz(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn jnz(&mut self, r1: Reg) -> Result<Self::Out>;
|
||||||
|
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out>;
|
||||||
|
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out>;
|
||||||
|
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out>;
|
||||||
|
fn halt(&mut self) -> Result<Self::Out>;
|
||||||
|
fn nop(&mut self) -> Result<Self::Out>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn visit_inst<A: InstAcceptor>(acceptor: &mut A) -> Result<A::Out> {
|
||||||
|
let mut cursor = acceptor.cursor();
|
||||||
|
let op = cursor.next_u16()?;
|
||||||
|
|
||||||
|
macro_rules! r1_r2_inst {
|
||||||
|
($fun:ident) => {{
|
||||||
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
|
acceptor.$fun(r1, r2)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! r1_inst {
|
||||||
|
($fun:ident) => {{
|
||||||
|
let r1 = cursor.next_reg()?;
|
||||||
|
acceptor.$fun(r1)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
match op {
|
||||||
|
ADD => r1_r2_inst!(add),
|
||||||
|
MUL => r1_r2_inst!(mul),
|
||||||
|
DIV => r1_r2_inst!(div),
|
||||||
|
MOD => r1_r2_inst!(mod_),
|
||||||
|
INEG => r1_inst!(ineg),
|
||||||
|
AND => r1_r2_inst!(and),
|
||||||
|
OR => r1_r2_inst!(or),
|
||||||
|
INV => r1_inst!(inv),
|
||||||
|
NOT => r1_inst!(not),
|
||||||
|
XOR => r1_r2_inst!(xor),
|
||||||
|
SHL => r1_r2_inst!(shl),
|
||||||
|
SHR => r1_r2_inst!(shr),
|
||||||
|
CMPEQ => r1_r2_inst!(cmpeq),
|
||||||
|
CMPLT => r1_r2_inst!(cmplt),
|
||||||
|
JMP => r1_inst!(jmp),
|
||||||
|
JZ => r1_inst!(jz),
|
||||||
|
JNZ => r1_inst!(jnz),
|
||||||
|
LOAD => r1_r2_inst!(load),
|
||||||
|
REGCOPY => r1_r2_inst!(regcopy),
|
||||||
|
STOREIMM64 => {
|
||||||
|
let r1 = cursor.next_reg()?;
|
||||||
|
// skip
|
||||||
|
cursor.next_u32()?;
|
||||||
|
let imm = cursor.next_u64()?;
|
||||||
|
acceptor.storeimm64(r1, imm)
|
||||||
|
}
|
||||||
|
STOREIMM32 => {
|
||||||
|
let r1 = cursor.next_reg()?;
|
||||||
|
let imm = cursor.next_u32()?;
|
||||||
|
acceptor.storeimm32(r1, imm)
|
||||||
|
}
|
||||||
|
MEMCOPY => r1_r2_inst!(memcopy),
|
||||||
|
STORE => r1_r2_inst!(store),
|
||||||
|
HALT => acceptor.halt(),
|
||||||
|
NOP => acceptor.nop(),
|
||||||
|
_ => Err(VmError::IllegalOp { op }),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::vm::{error::*, flags::*, mem::*, obj::obj::*, reg::*};
|
use crate::vm::{error::*, flags::*, inst::InstOp, mem::*, obj::obj::*, reg::*};
|
||||||
use byteorder::{WriteBytesExt, LE};
|
use byteorder::{WriteBytesExt, LE};
|
||||||
use std::{io::Cursor, mem};
|
use std::{io::Cursor, mem};
|
||||||
|
|
||||||
@@ -101,6 +101,11 @@ impl Vm {
|
|||||||
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
|
Ok(self.mem_cursor(addr as usize).next_u32().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_inst_op(&self, addr: Addr) -> Result<InstOp> {
|
||||||
|
self.check_read(addr, 2)?;
|
||||||
|
Ok(self.mem_cursor(addr as usize).next_u16().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
|
pub fn get_byte(&self, addr: Addr) -> Result<u8> {
|
||||||
self.check_addr(addr)?;
|
self.check_addr(addr)?;
|
||||||
Ok(self.mem_cursor(addr as usize).next_u8().unwrap())
|
Ok(self.mem_cursor(addr as usize).next_u8().unwrap())
|
||||||
|
|||||||
Reference in New Issue
Block a user