add emitting, start commenting

This commit is contained in:
coolcoder613eb 2024-03-20 18:40:36 +11:00
parent 18e3721a08
commit c8bf7fd8c9
5 changed files with 87 additions and 18 deletions

View File

@ -1,2 +1,13 @@
# oxvm
A virtual machine written in Rust
## binary format
```Rust
const MAGIC_NUMBER: u16 = 0xBADFAD;
struct Executable {
magic_number: u16
load_addr: u32
}
```

View File

@ -1,12 +1,12 @@
use crate::opcodes::Opcodes;
use std::u32;
use std::{collections::HashMap, u32};
// Registers are u8
// Memory addresses are u32
#[derive(Debug)]
enum Instruction {
Jmp(JmpInstr),
Goto(LabelJmpInstr),
Math(MathInstr),
Goto(GotoInstr),
Op(OpInstr),
Label(LabelInstr),
}
#[derive(Debug)]
@ -15,12 +15,12 @@ struct JmpInstr {
target: u32,
}
#[derive(Debug)]
struct LabelJmpInstr {
struct GotoInstr {
op_type: Opcodes,
target: LabelInstr,
}
#[derive(Debug)]
struct MathInstr {
struct OpInstr {
op_type: Opcodes,
target: u8,
src1: u8,
@ -67,7 +67,7 @@ impl Assembler {
match tokens.next() {
Some(token) => match token {
".start" => {
let straddr = tokens.next().expect("No address for .start!");
let straddr = tokens.next().expect("FATAL: No address for .start!");
let addr = u32::from_str_radix(
match straddr.strip_prefix("0x") {
Some(stripped) => stripped,
@ -91,21 +91,19 @@ impl Assembler {
}
fn code(&mut self, line: &str) {
let mut op = line.splitn(2, ' ');
let op_type = op
.next()
.expect("Empty lines should already be handled. THIS IS A BUG.");
let op_type = op.next().unwrap();
match op_type {
"goto" => {
let label = op.next().expect("No address for goto!");
self.instructions.push(Instruction::Goto(LabelJmpInstr {
op_type: Opcodes::Goto,
let label = op.next().expect("FATAL: No label for goto!");
self.instructions.push(Instruction::Goto(GotoInstr {
op_type: Opcodes::Jmp,
target: LabelInstr {
name: String::from(label),
},
}))
}
"jmp" => {
let straddr = op.next().expect("No address for jmp!");
let straddr = op.next().expect("FATAL: No address for jmp!");
let addr = u32::from_str_radix(
match straddr.strip_prefix("0x") {
Some(stripped) => stripped,
@ -113,9 +111,9 @@ impl Assembler {
},
16,
)
.expect("Error parsing address!");
.expect("FATAL: Error parsing address for jmp!");
self.instructions.push(Instruction::Jmp(JmpInstr {
op_type: Opcodes::Goto,
op_type: Opcodes::Jmp,
target: addr,
}));
}
@ -123,4 +121,62 @@ impl Assembler {
_ => println!("Unknown instruction: {}", op_type),
}
}
pub fn emit(self) -> Vec<u8> {
let mut instructions: Vec<Vec<u8>> = vec![];
let mut labels_srcs: HashMap<usize, String> = HashMap::new();
let mut labels_targets: HashMap<String, usize> = HashMap::new();
for instr in self.instructions {
match instr {
Instruction::Label(label_instr) => {
instructions.push(vec![]);
labels_targets.insert(label_instr.name, instructions.len());
}
Instruction::Op(op_instr) => instructions.push(vec![
op_instr.op_type as u8,
op_instr.target,
op_instr.src1,
op_instr.src2,
]),
Instruction::Jmp(jmp_instr) => {
let mut code = vec![jmp_instr.op_type as u8];
code.append(&mut jmp_instr.target.to_le_bytes().to_vec());
instructions.push(code);
}
Instruction::Goto(goto_instr) => {
// push placeholder
instructions.push(vec![goto_instr.op_type as u8, 255, 255, 255, 255]);
// add index of goto to table
labels_srcs.insert(instructions.len() - 1, goto_instr.target.name);
}
}
}
// a bit ugly, but makes rust happy
let mut mutations = Vec::new();
// resolve gotos
for (index, mut instr) in instructions.iter().enumerate() {
// check for placeholder
if instr == &vec![Opcodes::Jmp as u8, 255, 255, 255, 255] {
let label_name = labels_srcs.get(&index);
match label_name {
Some(label) => {
let label_target =
labels_targets.get(label).expect("FATAL: Unknown label!");
let mut code = vec![Opcodes::Jmp as u8];
let target_addr: u32 = instructions[..*label_target]
.iter()
.map(|v| v.len())
.sum::<usize>() as u32;
code.append(&mut target_addr.to_le_bytes().to_vec());
mutations.push((index, code));
} // if there is no jump target
None => println!("Why would you jump to 0xFFFFFFFF?"),
}
}
}
for (index, code) in mutations {
instructions[index] = code;
}
println!("{:#?}", instructions);
instructions.into_iter().flatten().collect()
}
}

View File

@ -17,6 +17,8 @@ fn main() {
let mut asmb = Assembler::new();
asmb.assemble(read_to_string(filename).expect("Failed to read file!"));
println!("{:#?}", asmb);
let code = asmb.emit();
println!("{:#?}", code);
}
None => println!("No file specified"),
}

View File

@ -1,4 +1,4 @@
#[derive(Debug)]
pub enum Opcodes {
Goto,
Jmp,
}

View File

@ -1,9 +1,9 @@
# start memory address
.start 0x00ff
.start 0x01020304
.label loop
# label jump
goto loop
# absolute jump
jmp 0xff00
jmp 0xfafbfcfd