Compiler and binary runner

This commit is contained in:
2025-10-29 20:19:39 +01:00
parent 844d3a060f
commit 6236d20dfd
5 changed files with 162 additions and 17 deletions
+2
View File
@@ -24,3 +24,5 @@ target
# Added by cargo # Added by cargo
/target /target
out.bin
+14 -10
View File
@@ -5,13 +5,17 @@ A flash emulator with my own stuff
## Opcodes ## Opcodes
| OP | INST | Action | | OP | INST | Action |
| --- | ----------------- | -------------------------------------- | | ---- | ----------------- | -------------------------------------- |
| 0 | \n | Goes to the next instruction | | 0x01 | HLT | Stops further emulation of the program |
| 1 | HLT | Stops further emulation of the program | | 0x02 | REG (r), (n) | Sets a registry to a number |
| 2 | REG (r), (n) | Sets a registry to a number | | 0x03 | ADD (r), (r), (r) | Adds |
| 3 | ADD (r), (r), (r) | Adds | | 0x04 | SUB (r), (r), (r) | Subtracts |
| 4 | SUB (r), (r), (r) | Subtracts | | 0x05 | MUL (r), (r), (r) | Multiplies |
| 5 | MUL (r), (r), (r) | Multiplies | | 0x06 | DIV (r), (r), (r) | Divides |
| 6 | DIV (r), (r), (r) | Divides | | 0x07 | LABEL (s) | Creates a label |
| 7 | LABEL (s) | Creates a label | | 0x08 | JMP (s) | Jumps into a label |
| 8 | 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 |
View File
+105
View File
@@ -52,6 +52,111 @@ impl Instruction {
}) })
.collect() .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 { fn reg(r: &str) -> u8 {
+39 -5
View File
@@ -1,20 +1,54 @@
mod binary;
mod emulator; 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 osui::prelude::*;
use crate::emulator::{instruction::Instruction, registry::Registry}; use crate::emulator::{instruction::Instruction, registry::Registry};
fn main() { fn main() {
let screen = Screen::new(); let args: Vec<_> = env::args().collect();
let s = fs::read_to_string("input.fg").unwrap(); 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(); screen.run().unwrap();
} }
} else {
eprintln!("\x1b[31mERR: Please enter a file\x1b[0m")
}
}
fn app(_screen: &Arc<Screen>, instructions: Vec<Instruction>) -> Rsx { fn app(_screen: &Arc<Screen>, instructions: Vec<Instruction>) -> Rsx {
let pc = use_state::<usize>(0); let pc = use_state::<usize>(0);