From a7402461e8d3a59d0e7e2a4698d74ba42a10f129 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sun, 24 Nov 2024 22:03:13 +0100 Subject: [PATCH] assembler --- Cargo.lock | 47 +++++++++++++++++++++++++++ Cargo.toml | 1 + src/assembler.rs | 58 ++++++++++++++++++++++++++++++++++ src/{devices/mod.rs => cpu.rs} | 24 ++++++++------ src/main.rs | 21 +++++++++--- 5 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 src/assembler.rs rename src/{devices/mod.rs => cpu.rs} (84%) diff --git a/Cargo.lock b/Cargo.lock index 2be5c12..b7e4a9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,53 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "sysforge" version = "0.1.0" +dependencies = [ + "regex", +] diff --git a/Cargo.toml b/Cargo.toml index 3ceaf50..f8812a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +regex = "1.11.1" diff --git a/src/assembler.rs b/src/assembler.rs new file mode 100644 index 0000000..52c4892 --- /dev/null +++ b/src/assembler.rs @@ -0,0 +1,58 @@ +use regex::Regex; +use std::{collections::HashMap, str::FromStr}; + +pub struct Opcode { + pub key: String, + pub value: T, +} + +impl Opcode { + pub fn create(key: &str, value: T) -> Opcode { + return Opcode { + key: key.to_string(), + value: value, + }; + } +} + +pub struct Assembler { + opcodes: Vec>, +} + +impl Assembler { + pub fn create(opcodes: Vec>) -> Assembler { + return Assembler { opcodes: opcodes }; + } + + pub fn assemble(&mut self, source: &mut String) -> Vec { + let mut map: HashMap = HashMap::new(); + + for opcode in &self.opcodes { + map.insert(opcode.key.clone(), opcode.value.clone()); + } + + return Regex::new(r"[\s]+") // create regex + .unwrap() + .split(source) // split by regex + .filter(|s: &&str| !s.is_empty()) // remove empty entries + .map(|s| match map.get(&s.to_lowercase()) { + Some(opcode) => opcode.to_string(), + None => s.to_string(), + }) // converts opcode strings to numbers + .filter_map(|s| { + if s.starts_with("0x") { + // converts hexadecimals to decimal, then parses them + u128::from_str_radix(&s[2..], 16) + .ok() + .unwrap() + .to_string() + .parse::() + .ok() + } else { + // parses all other decimals + s.parse::().ok() + } + }) + .collect(); + } +} diff --git a/src/devices/mod.rs b/src/cpu.rs similarity index 84% rename from src/devices/mod.rs rename to src/cpu.rs index 2fa6b12..981cd0c 100644 --- a/src/devices/mod.rs +++ b/src/cpu.rs @@ -12,7 +12,7 @@ pub struct ExampleCPU { impl ExampleCPU { // Here is where you can create your own CPU Instance. - pub fn create_instance(debug: bool, initial_state: [u8; 256]) -> ExampleCPU { + pub fn create(debug: bool, initial_state: [u8; 256]) -> ExampleCPU { return ExampleCPU { debug: debug, execution_pointer: 0, @@ -22,8 +22,14 @@ impl ExampleCPU { }; } + pub fn start(&mut self) { + loop { + self.fetch_and_decode() + } + } + // This fetches the operands, based on the position of the execution_pointer, then runs the selected instruction. - pub fn fetch_and_decode(&mut self) { + fn fetch_and_decode(&mut self) { self.operands[0] = self.ram[self.execution_pointer as usize]; self.operands[1] = self.ram[(self.execution_pointer + 1) as usize]; self.operands[2] = self.ram[(self.execution_pointer + 2) as usize]; @@ -34,13 +40,13 @@ impl ExampleCPU { ); } match self.operands[0] { - 0x00 => self.nop(), - 0x01 => self.load(), - 0x02 => self.store(), - 0x03 => self.add(), - 0x04 => self.sub(), - 0x05 => self.jump(), - 0x06 => self.jpiz(), + 0 => self.nop(), + 1 => self.load(), + 2 => self.store(), + 3 => self.add(), + 4 => self.sub(), + 5 => self.jump(), + 6 => self.jpiz(), _ => self.nop(), }; } diff --git a/src/main.rs b/src/main.rs index b9a9e6c..670410e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,23 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // Copyright (c) 2024 Patrick_Pluto -mod devices; +mod assembler; +mod cpu; fn main() { - let mut instance: devices::ExampleCPU = devices::ExampleCPU::create_instance(true, [0; 256]); + let mut assembler: assembler::Assembler = assembler::Assembler::create(vec![ + assembler::Opcode::create("nop", 0), + assembler::Opcode::create("load", 1), + assembler::Opcode::create("store", 2), + assembler::Opcode::create("add", 3), + assembler::Opcode::create("sub", 4), + assembler::Opcode::create("jump", 5), + assembler::Opcode::create("jpiz", 6), + ]); + + let final_result: Vec = assembler.assemble(&mut "nop 0x00 0x22".to_string()); + dbg!(final_result); + // let mut instance: cpu::ExampleCPU = cpu::ExampleCPU::create_instance(true, [0; 256]); // change the instructions here - loop { - instance.fetch_and_decode(); - } + // instance.start_emulation(); }