Compiler and binary runner
This commit is contained in:
@@ -24,3 +24,5 @@ target
|
|||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
out.bin
|
||||||
@@ -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 |
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user