Compiler and binary runner
This commit is contained in:
@@ -24,3 +24,5 @@ target
|
||||
# Added by cargo
|
||||
|
||||
/target
|
||||
|
||||
out.bin
|
||||
@@ -5,13 +5,17 @@ A flash emulator with my own stuff
|
||||
## Opcodes
|
||||
|
||||
| OP | INST | Action |
|
||||
| --- | ----------------- | -------------------------------------- |
|
||||
| 0 | \n | Goes to the next instruction |
|
||||
| 1 | HLT | Stops further emulation of the program |
|
||||
| 2 | REG (r), (n) | Sets a registry to a number |
|
||||
| 3 | ADD (r), (r), (r) | Adds |
|
||||
| 4 | SUB (r), (r), (r) | Subtracts |
|
||||
| 5 | MUL (r), (r), (r) | Multiplies |
|
||||
| 6 | DIV (r), (r), (r) | Divides |
|
||||
| 7 | LABEL (s) | Creates a label |
|
||||
| 8 | JMP (s) | Jumps into a label |
|
||||
| ---- | ----------------- | -------------------------------------- |
|
||||
| 0x01 | HLT | Stops further emulation of the program |
|
||||
| 0x02 | REG (r), (n) | Sets a registry to a number |
|
||||
| 0x03 | ADD (r), (r), (r) | Adds |
|
||||
| 0x04 | SUB (r), (r), (r) | Subtracts |
|
||||
| 0x05 | MUL (r), (r), (r) | Multiplies |
|
||||
| 0x06 | DIV (r), (r), (r) | Divides |
|
||||
| 0x07 | LABEL (s) | Creates a label |
|
||||
| 0x08 | JMP (s) | Jumps into a label |
|
||||
| 0x09 | RA | Registry |
|
||||
| 0x0A | RB | Registry |
|
||||
| 0x0B | RC | Registry |
|
||||
| 0x0C | RD | Registry |
|
||||
| 0x0D | \n | Goes to the next instruction |
|
||||
|
||||
@@ -52,6 +52,111 @@ impl Instruction {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Instruction::Hlt => vec![0x1],
|
||||
|
||||
// Register instruction
|
||||
Instruction::Reg(r, a) => {
|
||||
let mut bytes = vec![0x02, *r];
|
||||
bytes.extend_from_slice(&(*a as u64).to_le_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
// Arithmetic: opcode + 3 registers
|
||||
Instruction::Add(a, b, c) => vec![0x03, *a, *b, *c],
|
||||
Instruction::Sub(a, b, c) => vec![0x04, *a, *b, *c],
|
||||
Instruction::Mul(a, b, c) => vec![0x05, *a, *b, *c],
|
||||
Instruction::Div(a, b, c) => vec![0x06, *a, *b, *c],
|
||||
|
||||
// Label: opcode + length + UTF-8 bytes
|
||||
Instruction::Label(name) => {
|
||||
let mut bytes = vec![0x07];
|
||||
let name_bytes = name.as_bytes();
|
||||
let len = name_bytes.len() as u16;
|
||||
bytes.extend_from_slice(&len.to_le_bytes());
|
||||
bytes.extend_from_slice(name_bytes);
|
||||
bytes
|
||||
}
|
||||
|
||||
// Jump: opcode + length + UTF-8 bytes
|
||||
Instruction::Jmp(target) => {
|
||||
let mut bytes = vec![0x08];
|
||||
let name_bytes = target.as_bytes();
|
||||
let len = name_bytes.len() as u16;
|
||||
bytes.extend_from_slice(&len.to_le_bytes());
|
||||
bytes.extend_from_slice(name_bytes);
|
||||
bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(bytes: &[u8]) -> Option<Self> {
|
||||
let opcode = *bytes.get(0)?;
|
||||
match opcode {
|
||||
// Hlt
|
||||
0x01 => Some(Instruction::Hlt),
|
||||
|
||||
// Reg(u8, usize)
|
||||
0x02 => {
|
||||
let r = *bytes.get(1)?;
|
||||
if bytes.len() < 10 {
|
||||
return None;
|
||||
}
|
||||
let mut a_bytes = [0u8; 8];
|
||||
a_bytes.copy_from_slice(&bytes[2..10]);
|
||||
let a = u64::from_le_bytes(a_bytes) as usize;
|
||||
Some(Instruction::Reg(r, a))
|
||||
}
|
||||
|
||||
// 3-register arithmetic
|
||||
0x03 => Some(Instruction::Add(
|
||||
*bytes.get(1)?,
|
||||
*bytes.get(2)?,
|
||||
*bytes.get(3)?,
|
||||
)),
|
||||
0x04 => Some(Instruction::Sub(
|
||||
*bytes.get(1)?,
|
||||
*bytes.get(2)?,
|
||||
*bytes.get(3)?,
|
||||
)),
|
||||
0x05 => Some(Instruction::Mul(
|
||||
*bytes.get(1)?,
|
||||
*bytes.get(2)?,
|
||||
*bytes.get(3)?,
|
||||
)),
|
||||
0x06 => Some(Instruction::Div(
|
||||
*bytes.get(1)?,
|
||||
*bytes.get(2)?,
|
||||
*bytes.get(3)?,
|
||||
)),
|
||||
|
||||
// Label(String)
|
||||
0x07 => {
|
||||
if bytes.len() < 3 {
|
||||
return None;
|
||||
}
|
||||
let len = u16::from_le_bytes([bytes[1], bytes[2]]) as usize;
|
||||
let text_bytes = &bytes[3..3 + len];
|
||||
let text = String::from_utf8(text_bytes.to_vec()).ok()?;
|
||||
Some(Instruction::Label(text))
|
||||
}
|
||||
|
||||
// Jmp(String)
|
||||
0x08 => {
|
||||
if bytes.len() < 3 {
|
||||
return None;
|
||||
}
|
||||
let len = u16::from_le_bytes([bytes[1], bytes[2]]) as usize;
|
||||
let text_bytes = &bytes[3..3 + len];
|
||||
let text = String::from_utf8(text_bytes.to_vec()).ok()?;
|
||||
Some(Instruction::Jmp(text))
|
||||
}
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reg(r: &str) -> u8 {
|
||||
|
||||
+39
-5
@@ -1,19 +1,53 @@
|
||||
mod binary;
|
||||
mod emulator;
|
||||
|
||||
use std::{collections::HashMap, fs, sync::Arc};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
env,
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use osui::prelude::*;
|
||||
|
||||
use crate::emulator::{instruction::Instruction, registry::Registry};
|
||||
|
||||
fn main() {
|
||||
let screen = Screen::new();
|
||||
let s = fs::read_to_string("input.fg").unwrap();
|
||||
let args: Vec<_> = env::args().collect();
|
||||
if let Some(file) = args.get(1) {
|
||||
if file.ends_with(".fg") {
|
||||
let s = fs::read_to_string(file).unwrap();
|
||||
let instructions = Instruction::from_text(&s);
|
||||
let mut bytes = Vec::new();
|
||||
for (i, instr) in instructions.iter().enumerate() {
|
||||
bytes.extend(instr.encode());
|
||||
if i != instructions.len() - 1 {
|
||||
bytes.push(0x0D);
|
||||
}
|
||||
}
|
||||
let mut file = File::create("out.bin").unwrap();
|
||||
file.write_all(&bytes).unwrap();
|
||||
|
||||
app(&screen, Instruction::from_text(&s)).draw(&screen);
|
||||
println!("Compiled successfully");
|
||||
} else {
|
||||
let bytes = fs::read(file).unwrap();
|
||||
|
||||
let mut instructions = Vec::new();
|
||||
for chunk in bytes.split(|b| *b == 0x0D) {
|
||||
if let Some(instr) = Instruction::decode(chunk) {
|
||||
instructions.push(instr);
|
||||
}
|
||||
}
|
||||
|
||||
let screen = Screen::new();
|
||||
|
||||
app(&screen, instructions).draw(&screen);
|
||||
|
||||
screen.run().unwrap();
|
||||
}
|
||||
} else {
|
||||
eprintln!("\x1b[31mERR: Please enter a file\x1b[0m")
|
||||
}
|
||||
}
|
||||
|
||||
fn app(_screen: &Arc<Screen>, instructions: Vec<Instruction>) -> Rsx {
|
||||
|
||||
Reference in New Issue
Block a user