Compare commits
6 Commits
vm-bin-for
...
vm-strings
| Author | SHA1 | Date | |
|---|---|---|---|
| 6feeeea028 | |||
| 0ea3406b71 | |||
| 15423502f3 | |||
| 7504b81b2d | |||
| a4a37b5a27 | |||
| 6c352396fa |
25
src/main.rs
25
src/main.rs
@@ -1,7 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
//mod syn;
|
|
||||||
mod vm;
|
mod vm;
|
||||||
|
|
||||||
use std::{convert::TryFrom, env, fs, io, process};
|
use std::{convert::TryFrom, env, fs, io, process};
|
||||||
@@ -32,10 +31,30 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let obj = vm::obj::obj::Object::try_from(&ast)?;
|
let obj = vm::obj::obj::Object::try_from(&ast)?;
|
||||||
//println!("{:#?}", obj);
|
//dump(&obj)?;
|
||||||
let mut vm = vm::vm::Vm::new();
|
let mut vm = vm::vm::Vm::new();
|
||||||
vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb
|
vm.load_object(obj, 1024 * 1024 * 64)?; // 64mb
|
||||||
let status = vm.run()?;
|
let status = vm.run()?;
|
||||||
println!("status: {}", status);
|
println!("{}", status);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn dump(obj: &vm::obj::obj::Object) -> Result<()> {
|
||||||
|
use vm::obj::obj::Section;
|
||||||
|
use vm::visit::VisitInst;
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
for section in &obj.sections {
|
||||||
|
let mut disasm = match section {
|
||||||
|
Section::Code { start, contents, .. } => {
|
||||||
|
vm::disassemble::Disassemble::new(&mut stdout, contents, *start)
|
||||||
|
}
|
||||||
|
Section::Meta { .. } | Section::Data { .. } => continue,
|
||||||
|
};
|
||||||
|
while !disasm.is_done() {
|
||||||
|
disasm.visit_inst()?;
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
294
src/vm/disassemble.rs
Normal file
294
src/vm/disassemble.rs
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
use crate::vm::{
|
||||||
|
error::*,
|
||||||
|
inst::*,
|
||||||
|
mem::MemCursor,
|
||||||
|
reg::*,
|
||||||
|
visit::*,
|
||||||
|
vm::{Addr, HalfWord, Word},
|
||||||
|
};
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
const WIDTH: usize = 60;
|
||||||
|
|
||||||
|
pub struct Disassemble<'w, 'o> {
|
||||||
|
writer: &'w mut dyn Write,
|
||||||
|
cursor: MemCursor<'o>,
|
||||||
|
addr_offset: Addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'w, 'o> Disassemble<'w, 'o> {
|
||||||
|
pub fn new(writer: &'w mut dyn Write, content: &'o [u8], addr_offset: Addr) -> Self {
|
||||||
|
Disassemble {
|
||||||
|
writer,
|
||||||
|
cursor: MemCursor::new(content),
|
||||||
|
addr_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_done(&self) -> bool {
|
||||||
|
self.cursor.position() >= (self.cursor.get_ref().len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn adv(&mut self) -> Result<()> {
|
||||||
|
// note the () - this explicitly clones the cursor
|
||||||
|
let op = self.cursor().next_u16()?;
|
||||||
|
let next = self.cursor.position() + (inst_len(op) as u64);
|
||||||
|
self.cursor.set_position(next);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_addr(&mut self, addr: Addr) {
|
||||||
|
write!(self.writer, "{:06x} | ", self.addr_offset + addr).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_bytes(&mut self, bytes: &[u8]) {
|
||||||
|
for b in bytes {
|
||||||
|
write!(self.writer, "{:02x} ", b).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_inst_bytes(&mut self, op: InstOp) {
|
||||||
|
let len = inst_len(op);
|
||||||
|
let start = self.cursor.position() as usize;
|
||||||
|
let end = start + len;
|
||||||
|
let bytes = &self.cursor.get_ref()[start..end];
|
||||||
|
self.write_bytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_r1_r2_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, r2: Reg) {
|
||||||
|
let len = inst_len(op);
|
||||||
|
let line_width = 6 + 3 + (3 * len);
|
||||||
|
let line_offset = WIDTH - line_width;
|
||||||
|
self.write_addr(addr);
|
||||||
|
self.write_inst_bytes(op);
|
||||||
|
|
||||||
|
let iname = inst_name(op).unwrap();
|
||||||
|
let r1name = reg_name(r1).unwrap().to_lowercase();
|
||||||
|
let r2name = reg_name(r2).unwrap().to_lowercase();
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{}| {:>10} %{} %{}",
|
||||||
|
" ".repeat(line_offset),
|
||||||
|
iname,
|
||||||
|
r1name,
|
||||||
|
r2name
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_r1_inst(&mut self, addr: Addr, op: InstOp, r1: Reg) {
|
||||||
|
let line_width = 6 + 3 + (3 * inst_len(op));
|
||||||
|
let line_offset = WIDTH - line_width;
|
||||||
|
self.write_addr(addr);
|
||||||
|
self.write_inst_bytes(op);
|
||||||
|
|
||||||
|
let iname = inst_name(op).unwrap();
|
||||||
|
let r1name = reg_name(r1).unwrap().to_lowercase();
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{}| {:>10} %{}",
|
||||||
|
" ".repeat(line_offset),
|
||||||
|
iname,
|
||||||
|
r1name,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_r1_imm_inst(&mut self, addr: Addr, op: InstOp, r1: Reg, imm: Word) {
|
||||||
|
let line_width = 6 + 3 + (3 * inst_len(op));
|
||||||
|
let line_offset = WIDTH - line_width;
|
||||||
|
self.write_addr(addr);
|
||||||
|
self.write_inst_bytes(op);
|
||||||
|
|
||||||
|
let iname = inst_name(op).unwrap();
|
||||||
|
let r1name = reg_name(r1).unwrap().to_lowercase();
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{}| {:>10} %{} {:#X}",
|
||||||
|
" ".repeat(line_offset),
|
||||||
|
iname,
|
||||||
|
r1name,
|
||||||
|
imm,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitInst for Disassemble<'_, '_> {
|
||||||
|
type Out = ();
|
||||||
|
|
||||||
|
fn cursor(&self) -> MemCursor {
|
||||||
|
self.cursor.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), ADD, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mul(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), MUL, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn div(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), DIV, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mod_(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), MOD, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ineg(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), INEG, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn and(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), AND, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), OR, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inv(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), INV, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), NOT, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xor(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), XOR, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shl(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), SHL, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shr(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), SHR, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmpeq(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), CMPEQ, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmplt(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), CMPLT, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jmp(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), JMP, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jz(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), JZ, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jnz(&mut self, r1: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_inst(self.cursor.position(), JNZ, r1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), LOAD, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), REGCOPY, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storeimm64(&mut self, r1: Reg, w1: Word) -> Result<Self::Out> {
|
||||||
|
self.write_r1_imm_inst(self.cursor.position(), STOREIMM64, r1, w1);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn storeimm32(&mut self, r1: Reg, w1: HalfWord) -> Result<Self::Out> {
|
||||||
|
self.write_r1_imm_inst(self.cursor.position(), STOREIMM32, r1, w1 as u64);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memcopy(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), MEMCOPY, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn store(&mut self, r1: Reg, r2: Reg) -> Result<Self::Out> {
|
||||||
|
self.write_r1_r2_inst(self.cursor.position(), STORE, r1, r2);
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn halt(&mut self) -> Result<Self::Out> {
|
||||||
|
let line_width = 6 + 3 + 3 + 3;
|
||||||
|
let line_offset = WIDTH - line_width;
|
||||||
|
self.write_addr(self.cursor.position());
|
||||||
|
self.write_inst_bytes(HALT);
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{}| {:>10}",
|
||||||
|
" ".repeat(line_offset),
|
||||||
|
"HALT",
|
||||||
|
).unwrap();
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nop(&mut self) -> Result<Self::Out> {
|
||||||
|
let line_width = 6 + 3 + 3 + 3;
|
||||||
|
let line_offset = WIDTH - line_width;
|
||||||
|
self.write_addr(self.cursor.position());
|
||||||
|
self.write_inst_bytes(NOP);
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{}| {:>10}",
|
||||||
|
" ".repeat(line_offset),
|
||||||
|
"NOP",
|
||||||
|
).unwrap();
|
||||||
|
self.adv()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::{
|
|||||||
const R1_MASK: u16 = 0b1111_1100_0000_0000;
|
const R1_MASK: u16 = 0b1111_1100_0000_0000;
|
||||||
const R2_MASK: u16 = 0b0000_0011_1111_0000;
|
const R2_MASK: u16 = 0b0000_0011_1111_0000;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct MemCursor<'mem> {
|
pub struct MemCursor<'mem> {
|
||||||
cursor: Cursor<&'mem [u8]>,
|
cursor: Cursor<&'mem [u8]>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
pub mod disassemble;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod flags;
|
pub mod flags;
|
||||||
pub mod inst;
|
pub mod inst;
|
||||||
@@ -5,4 +6,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;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ impl<'a> Assemble<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(&mut self) -> Result<Object> {
|
pub fn assemble(&mut self) -> Result<Object> {
|
||||||
let mut pos = 0;
|
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
|
|
||||||
// gather global symbols
|
// gather global symbols
|
||||||
@@ -60,7 +59,6 @@ impl<'a> Assemble<'a> {
|
|||||||
for block in self.ast.iter() {
|
for block in self.ast.iter() {
|
||||||
let locals = Self::gather_symbols(block, false)?;
|
let locals = Self::gather_symbols(block, false)?;
|
||||||
self.symbols.replace_locals(locals);
|
self.symbols.replace_locals(locals);
|
||||||
|
|
||||||
match block {
|
match block {
|
||||||
SectionBlock::Data { org, body } | SectionBlock::Code { org, body } => {
|
SectionBlock::Data { org, body } | SectionBlock::Code { org, body } => {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
@@ -79,11 +77,9 @@ impl<'a> Assemble<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (start, end) = match org {
|
let (start, end) = match org {
|
||||||
Some(SectionOrg::Start(start)) => (*start, start + bytes.len() as u64),
|
SectionOrg::Start(start) => (*start, start + bytes.len() as u64),
|
||||||
Some(SectionOrg::Range(start, end)) => (*start, *end),
|
SectionOrg::Range(start, end) => (*start, *end),
|
||||||
None => (pos, pos + bytes.len() as u64),
|
|
||||||
};
|
};
|
||||||
pos = end;
|
|
||||||
|
|
||||||
let section = match block {
|
let section = match block {
|
||||||
SectionBlock::Data { .. } => Section::Data {
|
SectionBlock::Data { .. } => Section::Data {
|
||||||
@@ -122,10 +118,12 @@ impl<'a> Assemble<'a> {
|
|||||||
|
|
||||||
fn gather_symbols(block: &SectionBlock, export: bool) -> Result<HashMap<String, u64>> {
|
fn gather_symbols(block: &SectionBlock, export: bool) -> Result<HashMap<String, u64>> {
|
||||||
match block {
|
match block {
|
||||||
SectionBlock::Data { body, .. } | SectionBlock::Code { body, .. } => {
|
SectionBlock::Data { org, body, .. } | SectionBlock::Code { org, body, .. } => {
|
||||||
let mut exports = HashSet::new();
|
let mut exports = HashSet::new();
|
||||||
let mut labels = HashMap::new();
|
let mut labels = HashMap::new();
|
||||||
let mut pos = 0;
|
let mut pos = match org {
|
||||||
|
SectionOrg::Start(start) | SectionOrg::Range(start, _) => (*start) as usize,
|
||||||
|
};
|
||||||
for line in body.iter() {
|
for line in body.iter() {
|
||||||
match line {
|
match line {
|
||||||
Line::Inst(inst) => {
|
Line::Inst(inst) => {
|
||||||
@@ -191,19 +189,36 @@ impl<'a> Assemble<'a> {
|
|||||||
Inst::Jnz(r1) => builder.op(JNZ).r1(*r1),
|
Inst::Jnz(r1) => builder.op(JNZ).r1(*r1),
|
||||||
Inst::Load(r1, r2) => builder.op(LOAD).r1(*r1).r2(*r2),
|
Inst::Load(r1, r2) => builder.op(LOAD).r1(*r1).r2(*r2),
|
||||||
Inst::Store(r1, r2) => builder.op(STORE).r1(*r1).r2(*r2),
|
Inst::Store(r1, r2) => builder.op(STORE).r1(*r1).r2(*r2),
|
||||||
Inst::StoreImm(r1, imm) => {
|
Inst::StoreImm(r1, imm) => match imm {
|
||||||
let imm = match imm {
|
ImmValue::Number(num) => {
|
||||||
ImmValue::Number(num) => *num,
|
if *num > (u32::max_value() as u64) {
|
||||||
ImmValue::Label(name) => {
|
builder.op(STOREIMM64).imm64(*num)
|
||||||
self.symbols.get(name).expect("TODO: value label not found")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if imm <= (u32::max_value() as u64) {
|
|
||||||
builder.op(STOREIMM32).r1(*r1).imm32(imm as u32)
|
|
||||||
} else {
|
} else {
|
||||||
builder.op(STOREIMM64).r1(*r1).imm64(imm)
|
builder.op(STOREIMM32).imm32(*num as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImmValue::Label(name) => {
|
||||||
|
let imm = self.symbols.get(name).expect("TODO: value label not found");
|
||||||
|
builder.op(STOREIMM64).imm64(imm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.r1(*r1),
|
||||||
|
Inst::StoreImm32(r1, imm) => {
|
||||||
|
let imm = self.get_value(imm).expect("TODO : value label not found");
|
||||||
|
let imm_truncated = (imm & 0xFFFFFFFF) as u32;
|
||||||
|
// TODO compile-time warnings
|
||||||
|
if imm != (imm_truncated as u64) {
|
||||||
|
eprintln!(
|
||||||
|
"WARNING: immediate 32 bit value being truncated ({:#x} to {:#x})",
|
||||||
|
imm, imm_truncated
|
||||||
|
)
|
||||||
|
}
|
||||||
|
builder.op(STOREIMM32).imm32(imm_truncated).r1(*r1)
|
||||||
|
}
|
||||||
|
Inst::StoreImm64(r1, imm) => {
|
||||||
|
let imm = self.get_value(imm).expect("TODO : value label not found");
|
||||||
|
builder.op(STOREIMM64).imm64(imm).r1(*r1)
|
||||||
|
}
|
||||||
Inst::MemCopy(r1, r2) => builder.op(MEMCOPY).r1(*r1).r2(*r2),
|
Inst::MemCopy(r1, r2) => builder.op(MEMCOPY).r1(*r1).r2(*r2),
|
||||||
Inst::RegCopy(r1, r2) => builder.op(REGCOPY).r1(*r1).r2(*r2),
|
Inst::RegCopy(r1, r2) => builder.op(REGCOPY).r1(*r1).r2(*r2),
|
||||||
Inst::Nop => builder.op(NOP),
|
Inst::Nop => builder.op(NOP),
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ use crate::vm::{inst::*, reg::Reg};
|
|||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum SectionBlock {
|
pub enum SectionBlock {
|
||||||
Data {
|
Data {
|
||||||
org: Option<SectionOrg>,
|
org: SectionOrg,
|
||||||
body: Vec<Line>,
|
body: Vec<Line>,
|
||||||
},
|
},
|
||||||
Code {
|
Code {
|
||||||
org: Option<SectionOrg>,
|
org: SectionOrg,
|
||||||
body: Vec<Line>,
|
body: Vec<Line>,
|
||||||
},
|
},
|
||||||
Meta {
|
Meta {
|
||||||
@@ -59,6 +59,8 @@ pub enum Inst {
|
|||||||
Load(Reg, Reg),
|
Load(Reg, Reg),
|
||||||
Store(Reg, Reg),
|
Store(Reg, Reg),
|
||||||
StoreImm(Reg, ImmValue),
|
StoreImm(Reg, ImmValue),
|
||||||
|
StoreImm32(Reg, ImmValue),
|
||||||
|
StoreImm64(Reg, ImmValue),
|
||||||
MemCopy(Reg, Reg),
|
MemCopy(Reg, Reg),
|
||||||
RegCopy(Reg, Reg),
|
RegCopy(Reg, Reg),
|
||||||
|
|
||||||
@@ -101,6 +103,8 @@ impl Inst {
|
|||||||
STOREIMM64
|
STOREIMM64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Inst::StoreImm32(_, _) => STOREIMM32,
|
||||||
|
Inst::StoreImm64(_, _) => STOREIMM64,
|
||||||
Inst::MemCopy(_, _) => MEMCOPY,
|
Inst::MemCopy(_, _) => MEMCOPY,
|
||||||
Inst::RegCopy(_, _) => REGCOPY,
|
Inst::RegCopy(_, _) => REGCOPY,
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ Label: String = {
|
|||||||
|
|
||||||
Number: u64 = {
|
Number: u64 = {
|
||||||
<s:r"\$[0-9]+"> => u64::from_str(&s[1..]).unwrap(),
|
<s:r"\$[0-9]+"> => u64::from_str(&s[1..]).unwrap(),
|
||||||
<s:r"\$0x[0-9a-fA-F]+"> => u64::from_str_radix(&s[3..], 16).unwrap()
|
<s:r"\$0x[0-9a-fA-F]+"> => u64::from_str_radix(&s[3..], 16).unwrap(),
|
||||||
|
<s:r"\$0b[01]+"> => u64::from_str_radix(&s[3..], 2).unwrap(),
|
||||||
}
|
}
|
||||||
|
|
||||||
Reg: Reg = {
|
Reg: Reg = {
|
||||||
@@ -59,6 +60,8 @@ Inst: Inst = {
|
|||||||
"load" <d:Reg> "," <s:Reg> => Inst::Load(d, s),
|
"load" <d:Reg> "," <s:Reg> => Inst::Load(d, s),
|
||||||
"store" <d:Reg> "," <s:Reg> => Inst::Store(d, s),
|
"store" <d:Reg> "," <s:Reg> => Inst::Store(d, s),
|
||||||
"storeimm" <d:Reg> "," <s:ImmValue> => Inst::StoreImm(d, s),
|
"storeimm" <d:Reg> "," <s:ImmValue> => Inst::StoreImm(d, s),
|
||||||
|
"storeimm32" <d:Reg> "," <s:ImmValue> => Inst::StoreImm32(d, s),
|
||||||
|
"storeimm64" <d:Reg> "," <s:ImmValue> => Inst::StoreImm64(d, s),
|
||||||
"memcopy" <d:Reg> "," <s:Reg> => Inst::MemCopy(d, s),
|
"memcopy" <d:Reg> "," <s:Reg> => Inst::MemCopy(d, s),
|
||||||
"regcopy" <d:Reg> "," <s:Reg> => Inst::RegCopy(d, s),
|
"regcopy" <d:Reg> "," <s:Reg> => Inst::RegCopy(d, s),
|
||||||
"nop" => Inst::Nop,
|
"nop" => Inst::Nop,
|
||||||
@@ -82,11 +85,11 @@ SectionOrg: SectionOrg = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Section: SectionBlock = {
|
Section: SectionBlock = {
|
||||||
"data" <org:SectionOrg?> "{" <body:Line*> "}" => {
|
"data" <org:SectionOrg> "{" <body:Line*> "}" => {
|
||||||
SectionBlock::Data { org, body }
|
SectionBlock::Data { org, body }
|
||||||
},
|
},
|
||||||
|
|
||||||
"code" <org:SectionOrg?> "{" <body:Line*> "}" => {
|
"code" <org:SectionOrg> "{" <body:Line*> "}" => {
|
||||||
SectionBlock::Code { org, body }
|
SectionBlock::Code { org, body }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ macro_rules! registers {
|
|||||||
$(
|
$(
|
||||||
pub const $variant: Reg = $value;
|
pub const $variant: Reg = $value;
|
||||||
)*
|
)*
|
||||||
|
|
||||||
|
pub fn reg_name(reg: Reg) -> Option<&'static str> {
|
||||||
|
match reg {
|
||||||
|
$(
|
||||||
|
$value => Some(stringify!($variant)),
|
||||||
|
)*
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,5 +100,6 @@ registers! {
|
|||||||
R47 = 61,
|
R47 = 61,
|
||||||
R48 = 62,
|
R48 = 62,
|
||||||
R49 = 63,
|
R49 = 63,
|
||||||
LAST_REG = R49,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const LAST_REG: Reg = R49;
|
||||||
|
|||||||
309
src/vm/tick.rs
309
src/vm/tick.rs
@@ -1,134 +1,189 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
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 = self.visit_inst()?;
|
||||||
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 VisitInst 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
96
src/vm/visit.rs
Normal file
96
src/vm/visit.rs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
use crate::vm::{
|
||||||
|
error::*,
|
||||||
|
inst::*,
|
||||||
|
mem::MemCursor,
|
||||||
|
reg::Reg,
|
||||||
|
vm::{HalfWord, Word},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait VisitInst {
|
||||||
|
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>;
|
||||||
|
|
||||||
|
fn visit_inst(&mut self) -> Result<Self::Out> {
|
||||||
|
let mut cursor = self.cursor();
|
||||||
|
//panic!("cursor pos: {}", cursor.position());
|
||||||
|
let op = cursor.next_u16()?;
|
||||||
|
|
||||||
|
macro_rules! r1_r2_inst {
|
||||||
|
($fun:ident) => {{
|
||||||
|
let (r1, r2) = cursor.next_regs()?;
|
||||||
|
self.$fun(r1, r2)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
macro_rules! r1_inst {
|
||||||
|
($fun:ident) => {{
|
||||||
|
let r1 = cursor.next_reg()?;
|
||||||
|
self.$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()?;
|
||||||
|
self.storeimm64(r1, imm)
|
||||||
|
}
|
||||||
|
STOREIMM32 => {
|
||||||
|
let r1 = cursor.next_reg()?;
|
||||||
|
let imm = cursor.next_u32()?;
|
||||||
|
self.storeimm32(r1, imm)
|
||||||
|
}
|
||||||
|
MEMCOPY => r1_r2_inst!(memcopy),
|
||||||
|
STORE => r1_r2_inst!(store),
|
||||||
|
HALT => self.halt(),
|
||||||
|
NOP => self.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())
|
||||||
|
|||||||
17
test.asm
17
test.asm
@@ -1,28 +1,25 @@
|
|||||||
data $0x1000 .. $0x2000 {
|
|
||||||
}
|
|
||||||
|
|
||||||
code $0x0 {
|
code $0x0 {
|
||||||
main:
|
main:
|
||||||
storeimm %r00, $0xDEAD
|
storeimm32 %r00, $0xDEAD
|
||||||
storeimm %r01, $16
|
storeimm64 %r01, $16
|
||||||
|
|
||||||
shl %r00, %r01
|
shl %r00, %r01
|
||||||
|
|
||||||
storeimm %r01, $0xBEEF
|
storeimm32 %r01, $0xBEEF
|
||||||
or %r00, %r01
|
or %r00, %r01
|
||||||
|
|
||||||
storeimm %r01, $0xDEADBEEF
|
storeimm64 %r01, $0xDEADBEEF
|
||||||
|
|
||||||
cmpeq %r00, %r01
|
cmpeq %r00, %r01
|
||||||
storeimm %r00, failure
|
storeimm32 %r00, failure
|
||||||
storeimm %r01, ok
|
storeimm64 %r01, ok
|
||||||
|
|
||||||
jz %r00
|
jz %r00
|
||||||
|
|
||||||
jmp %r01
|
jmp %r01
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
storeimm %status, $1
|
storeimm32 %status, $1
|
||||||
|
|
||||||
ok: halt
|
ok: halt
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user