From 6236d20dfdd8e21c31fa474de3d34d6e0f195983 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Wed, 29 Oct 2025 20:19:39 +0100 Subject: [PATCH] Compiler and binary runner --- .gitignore | 2 + README.md | 26 +++++---- src/binary.rs | 0 src/emulator/instruction.rs | 105 ++++++++++++++++++++++++++++++++++++ src/main.rs | 46 +++++++++++++--- 5 files changed, 162 insertions(+), 17 deletions(-) delete mode 100644 src/binary.rs diff --git a/.gitignore b/.gitignore index 0728338..0c03572 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ target # Added by cargo /target + +out.bin \ No newline at end of file diff --git a/README.md b/README.md index fb801d7..e5ad87b 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,18 @@ 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 | +| OP | INST | Action | +| ---- | ----------------- | -------------------------------------- | +| 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 | diff --git a/src/binary.rs b/src/binary.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/emulator/instruction.rs b/src/emulator/instruction.rs index d77a35a..a12e95f 100644 --- a/src/emulator/instruction.rs +++ b/src/emulator/instruction.rs @@ -52,6 +52,111 @@ impl Instruction { }) .collect() } + + pub fn encode(&self) -> Vec { + 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 { + 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 { diff --git a/src/main.rs b/src/main.rs index 618b618..66a1809 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(); - screen.run().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, instructions: Vec) -> Rsx {