From a6be6683287d82d1a9ee215cdea3ef3730fe6818 Mon Sep 17 00:00:00 2001 From: "J. Hinchliffe" Date: Tue, 17 Jun 2025 19:19:49 +0100 Subject: [PATCH 1/3] emulator: just saving my changes --- .vscode/settings.json | 3 +- Cargo.lock | 177 +++++++++++++++++++++++++++++- emulator/Cargo.toml | 6 + emulator/src/emulator/config.rs | 2 + emulator/src/emulator/misc/mod.rs | 2 + emulator/src/emulator/misc/rpc.rs | 56 ++++++++++ emulator/src/emulator/mod.rs | 3 + 7 files changed, 247 insertions(+), 2 deletions(-) create mode 100644 emulator/src/emulator/config.rs create mode 100644 emulator/src/emulator/misc/mod.rs create mode 100644 emulator/src/emulator/misc/rpc.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 9281181..a4566e9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "rust-analyzer.check.command": "clippy", - "editor.formatOnSave": true + "editor.formatOnSave": true, + "rust-analyzer.cargo.features": "all" } diff --git a/Cargo.lock b/Cargo.lock index 6afd181..e77f9c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,6 +558,12 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "byteorder-lite" version = "0.1.0" @@ -744,6 +750,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -794,7 +809,29 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.60.2", +] + +[[package]] +name = "discord-presence" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91d7c2fc01ffdc327e2b66d65dd59b8bd3f31a17e88811ce0540412fa0b84c1" +dependencies = [ + "byteorder", + "bytes", + "cfg-if", + "crossbeam-channel", + "log", + "num-derive", + "num-traits", + "parking_lot", + "paste", + "quork", + "serde", + "serde_json", + "thiserror 2.0.12", + "uuid", ] [[package]] @@ -1002,9 +1039,11 @@ dependencies = [ "assembler", "common", "dirs", + "discord-presence", "eframe", "egui", "rfd", + "toml", ] [[package]] @@ -1585,6 +1624,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + [[package]] name = "jni" version = "0.21.1" @@ -1868,6 +1913,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2379,6 +2435,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -2413,6 +2491,32 @@ dependencies = [ "memchr", ] +[[package]] +name = "quork" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd9640e0addc098a3481fd53bdc23970e5dd0edf6b349403aa680fb576c8f83" +dependencies = [ + "cfg-if", + "nix 0.29.0", + "quork-proc", + "thiserror 2.0.12", + "windows-sys 0.59.0", +] + +[[package]] +name = "quork-proc" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "860d36740d9412e39fff90f57010e9870b15c2b48e5325295a6f5a824a480439" +dependencies = [ + "proc-macro-crate", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.40" @@ -2596,6 +2700,12 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "same-file" version = "1.0.6" @@ -2650,6 +2760,18 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.20" @@ -2661,6 +2783,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2938,11 +3069,26 @@ dependencies = [ "zerovec", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -2951,10 +3097,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tracing" version = "0.1.41" @@ -3066,6 +3221,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +dependencies = [ + "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "version_check" version = "0.9.5" @@ -3544,6 +3710,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", +] + [[package]] name = "windows-targets" version = "0.42.2" diff --git a/emulator/Cargo.toml b/emulator/Cargo.toml index 4921fbb..e79fe90 100644 --- a/emulator/Cargo.toml +++ b/emulator/Cargo.toml @@ -14,3 +14,9 @@ eframe = "0.31.1" egui = "0.31.1" rfd = "0.15.3" dirs = "6.0.0" +discord-presence = { version = "1.6.0", optional = true } +toml = { version = "0.8.23", optional = true } + +[features] +discord-rpc = ["dep:discord-presence"] +config = ["dep:toml"] diff --git a/emulator/src/emulator/config.rs b/emulator/src/emulator/config.rs new file mode 100644 index 0000000..534ce40 --- /dev/null +++ b/emulator/src/emulator/config.rs @@ -0,0 +1,2 @@ +//! Loads configuration information from a TOML file in the current working directory. +//! Currently doesn't do much but this may be expanded. diff --git a/emulator/src/emulator/misc/mod.rs b/emulator/src/emulator/misc/mod.rs new file mode 100644 index 0000000..7689ddb --- /dev/null +++ b/emulator/src/emulator/misc/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "discord-rpc")] +pub mod rpc; diff --git a/emulator/src/emulator/misc/rpc.rs b/emulator/src/emulator/misc/rpc.rs new file mode 100644 index 0000000..94d2f9c --- /dev/null +++ b/emulator/src/emulator/misc/rpc.rs @@ -0,0 +1,56 @@ +//! Just for fun I thought I would add a Discord RPC client to the emulator. +//! +//! This will display information like the current value of PCX, architecture name and +//! GitHub repo links to show off the ISA. Perhaps in the future if we cross-compile to +//! WASM we could include a link to run this software in the browser. +//! +//! +//! # Configuration +//! +//! This may be disabled like so in your `.dsarc.toml` file: +//! +//! ```toml +//! [misc] +//! use_discord_rpc = false +//! ``` +//! +//! Alternatively, you can hide this in your Discord settings. + +use discord_presence::{Client, DiscordError}; + +#[derive(Debug)] +pub enum DiscordRpcError { + Client(DiscordError), +} + +impl std::fmt::Display for DiscordRpcError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Client(why) => write!(f, "discord RPC error: {why}"), + } + } +} + +impl std::error::Error for DiscordRpcError {} + +impl From for DiscordRpcError { + fn from(err: DiscordError) -> Self { + Self::Client(err) + } +} + +/// Sets up the Discord RPC client. +#[expect(clippy::unreadable_literal)] +pub fn start_rpc() -> Result { + let mut client = discord_presence::Client::new(1384303074088190042); + + _ = client.on_ready(|ctx| { + eprintln!("The discord RPC client is ready. Got event {:?}", ctx.event); + }); + + client.start(); + + client.set_activity(|act| act)?; + + Ok(client) +} diff --git a/emulator/src/emulator/mod.rs b/emulator/src/emulator/mod.rs index 140dea3..9d6cc6f 100644 --- a/emulator/src/emulator/mod.rs +++ b/emulator/src/emulator/mod.rs @@ -1,2 +1,5 @@ +#[cfg(feature = "config")] +pub mod config; +pub mod misc; pub mod system; pub mod ui; From 0b16246dd2dabb6bb2bb864e2c7c2fcacbce3b8d Mon Sep 17 00:00:00 2001 From: "J. Hinchliffe" Date: Tue, 17 Jun 2025 19:43:35 +0100 Subject: [PATCH 2/3] misc: applied some clippy lints --- Cargo.lock | 25 +++++-------- assembler/src/lib.rs | 27 +++++++------- assembler/src/main.rs | 5 +-- assembler/src/model.rs | 59 +++++++++++++++++++++++++++--- assembler/src/parser.rs | 12 ++++-- emulator/Cargo.toml | 2 +- emulator/src/emulator/ui/editor.rs | 42 +++++++++++++-------- 7 files changed, 114 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 700d79f..3d4ee0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -659,12 +659,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "colorful" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb474a9c3219a8254ead020421ecf1b90427f29b55f6aae9a2471fa62c126ef" - [[package]] name = "combine" version = "4.6.7" @@ -909,16 +903,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" -[[package]] -name = "dsa_editor" -version = "0.1.0" -dependencies = [ - "colorful", - "eframe", - "egui", - "serde", -] - [[package]] name = "ecolor" version = "0.31.1" @@ -1021,6 +1005,14 @@ dependencies = [ "winit", ] +[[package]] +name = "egui_code_editor" +version = "0.2.13" +source = "git+https://github.com/zxq5-dev/egui_code_editor?rev=5eb313e#5eb313e38504410ce0a6b27231cda28842f542fe" +dependencies = [ + "egui", +] + [[package]] name = "egui_glow" version = "0.31.1" @@ -1058,6 +1050,7 @@ dependencies = [ "discord-presence", "eframe", "egui", + "egui_code_editor", "rfd", "toml", ] diff --git a/assembler/src/lib.rs b/assembler/src/lib.rs index d7fdb55..a3fa315 100644 --- a/assembler/src/lib.rs +++ b/assembler/src/lib.rs @@ -3,7 +3,7 @@ use std::{ collections::HashSet, fs, hash::{DefaultHasher, Hash, Hasher}, - path::PathBuf, + path::{Path, PathBuf}, }; use common::prelude::Instruction; @@ -17,27 +17,27 @@ pub mod lexer; pub mod model; pub mod parser; -pub fn assemble(src: &PathBuf) -> Vec { +pub fn assemble(src: &Path) -> Vec { let mut modules = HashSet::::new(); let mut program = Program::new(); let hash = quick_hash(src); modules.insert(hash); - match prepare_dependency(src.clone(), &mut modules, &mut program) { + match prepare_dependency(src, &mut modules, &mut program) { Ok(_) => {} - Err(err) => println!("BIG ERROR {:?}", err), + Err(err) => println!("BIG ERROR {err:?}"), } for node in program.nodes { - println!("{:?}", node); + println!("{node:?}"); } vec![] } fn prepare_dependency( - path: PathBuf, + path: &Path, modules: &mut HashSet, program: &mut Program, ) -> Result<(), AssembleError> { @@ -51,9 +51,9 @@ fn prepare_dependency( )); } - let src = fs::read_to_string(&path) - .map_err(|_| AssembleError::InvalidFile(path.clone()))?; - let file_hash = quick_hash(&path); + let src = fs::read_to_string(path) + .map_err(|_| AssembleError::InvalidFile(path.to_path_buf()))?; + let file_hash = quick_hash(path); log(&format!("{:20} {:20}", "Tokenising", filename)); let tokens = lexer::lexer(src, file_hash)?; @@ -77,14 +77,14 @@ fn prepare_dependency( if !modules.contains(&quick_hash(&dep)) { modules.insert(quick_hash(&dep)); - prepare_dependency(dep, modules, program)? + prepare_dependency(dep.as_path(), modules, program)? } } Ok(()) } -fn build(src: Vec) -> Result, AssembleError> { +fn _build(_src: Vec) -> Result, AssembleError> { Ok(vec![]) } @@ -116,12 +116,13 @@ impl fmt::Display for AssembleError { } } -fn quick_hash(value: &PathBuf) -> u64 { +fn quick_hash(value: &Path) -> u64 { let mut hasher = DefaultHasher::new(); value.canonicalize().unwrap().to_str().hash(&mut hasher); hasher.finish() } +// TODO: Use an actual logging or tracing library for pretty (scoped) output. fn log(message: &str) { - println!("\x1b[32mINFO:\x1b[0m {}", message); + println!("\x1b[32mINFO:\x1b[0m {message}"); } diff --git a/assembler/src/main.rs b/assembler/src/main.rs index 7645a1a..b01f13a 100644 --- a/assembler/src/main.rs +++ b/assembler/src/main.rs @@ -1,8 +1,5 @@ use std::{fs, io::Write, path::PathBuf}; -use assembler::{lexer, parser::Parser}; -use common::prelude::{ITypeArgs, Instruction, RTypeArgs, Register}; - fn main() { // parse args: let args: Vec = std::env::args().collect(); @@ -16,7 +13,7 @@ fn main() { let src = PathBuf::from(input_path); let mut output_file = fs::File::create(output_path).unwrap(); - let res = assembler::assemble(&src) + assembler::assemble(&src) .iter() .map(|i| i.encode()) .for_each(|i| { diff --git a/assembler/src/model.rs b/assembler/src/model.rs index dd5aeae..dc8a9cd 100644 --- a/assembler/src/model.rs +++ b/assembler/src/model.rs @@ -3,13 +3,12 @@ use std::{fmt, str::FromStr}; use common::prelude::Register; #[derive(Debug, Clone)] -#[expect(dead_code)] pub struct Node(pub Option, pub Opcode, pub Vec); impl fmt::Display for Node { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let symbol = match &self.0 { - Some(symbol) => format!("{}", symbol), + Some(symbol) => format!("{symbol}"), None => "".to_string(), }; @@ -26,15 +25,65 @@ impl fmt::Display for Symbol { impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Module::Unresolved(name) => write!(f, "{}", name), - Module::Resolved(name) => write!(f, "{}", name), + Module::Unresolved(name) => write!(f, "{name}"), + Module::Resolved(name) => write!(f, "{name}"), } } } impl fmt::Display for Opcode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self) + match self { + Opcode::Nop => write!(f, "nop"), + Opcode::Mov => write!(f, "mov"), + Opcode::Movs => write!(f, "movs"), + Opcode::Ldb => write!(f, "ldb"), + Opcode::Ldbs => write!(f, "ldbs"), + Opcode::Ldh => write!(f, "ldh"), + Opcode::Ldhs => write!(f, "ldhs"), + Opcode::Ldw => write!(f, "ldw"), + Opcode::Stb => write!(f, "stb"), + Opcode::Sth => write!(f, "sth"), + Opcode::Stw => write!(f, "stw"), + Opcode::Lli => write!(f, "lli"), + Opcode::Lui => write!(f, "lui"), + Opcode::Jmp => write!(f, "jmp"), + Opcode::Jeq => write!(f, "jeq"), + Opcode::Jne => write!(f, "jne"), + Opcode::Jgt => write!(f, "jgt"), + Opcode::Jge => write!(f, "jge"), + Opcode::Jlt => write!(f, "jlt"), + Opcode::Jle => write!(f, "jle"), + Opcode::Cmp => write!(f, "cmp"), + Opcode::Inc => write!(f, "inc"), + Opcode::Dec => write!(f, "dec"), + Opcode::Shl => write!(f, "shl"), + Opcode::Shr => write!(f, "shr"), + Opcode::Add => write!(f, "add"), + Opcode::Sub => write!(f, "sub"), + Opcode::And => write!(f, "and"), + Opcode::Or => write!(f, "or"), + Opcode::Not => write!(f, "not"), + Opcode::Xor => write!(f, "xor"), + Opcode::Nand => write!(f, "nand"), + Opcode::Nor => write!(f, "nor"), + Opcode::Xnor => write!(f, "xnor"), + Opcode::Int => write!(f, "int"), + Opcode::Irt => write!(f, "irt"), + Opcode::Hlt => write!(f, "hlt"), + Opcode::Iadd => write!(f, "iadd"), + Opcode::Isub => write!(f, "isub"), + Opcode::Db => write!(f, "db"), + Opcode::Dh => write!(f, "dh"), + Opcode::Dw => write!(f, "dw"), + Opcode::Resb => write!(f, "resb"), + Opcode::Resh => write!(f, "resh"), + Opcode::Resw => write!(f, "resw"), + Opcode::Push => write!(f, "push"), + Opcode::Pop => write!(f, "pop"), + Opcode::Lwi => write!(f, "lwi"), + Opcode::Include => write!(f, "include"), + } } } diff --git a/assembler/src/parser.rs b/assembler/src/parser.rs index eb1457e..53ff115 100644 --- a/assembler/src/parser.rs +++ b/assembler/src/parser.rs @@ -1,6 +1,4 @@ -use core::fmt; use std::path::PathBuf; -use std::str::FromStr; use common::prelude::{Instruction, Register}; @@ -33,6 +31,12 @@ impl Program { } } +impl Default for Program { + fn default() -> Self { + Self::new() + } +} + impl Parser { pub fn new(tokens: Vec) -> Parser { Parser { @@ -68,7 +72,7 @@ impl Parser { for node in &self.nodes { if let Opcode::Include = node.1 { // we want the path, and the name - let name = if let Token::Symbol(name) = node.2.get(0).unwrap() { + let name = if let Token::Symbol(name) = node.2.first().unwrap() { name.name.clone() } else { unreachable!() @@ -129,7 +133,7 @@ impl Parser { // inc SPR // STW reg, SPR let label = node.0.clone(); - let reg = node.2.get(0).unwrap(); + let reg = node.2.first().unwrap(); vec![ Node( diff --git a/emulator/Cargo.toml b/emulator/Cargo.toml index b8bd3e0..4c1796a 100644 --- a/emulator/Cargo.toml +++ b/emulator/Cargo.toml @@ -10,7 +10,7 @@ path = "src/lib.rs" [dependencies] common = { path = "../common" } assembler = { path = "../assembler" } -dsa_editor = { path = "../dsa_editor" } +dsa_editor = { git = "https://github.com/zxq5-dev/egui_code_editor", package = "egui_code_editor", rev = "5eb313e" } eframe = "0.31.1" egui = "0.31.1" rfd = "0.15.3" diff --git a/emulator/src/emulator/ui/editor.rs b/emulator/src/emulator/ui/editor.rs index 70343c7..5fd7096 100644 --- a/emulator/src/emulator/ui/editor.rs +++ b/emulator/src/emulator/ui/editor.rs @@ -43,7 +43,7 @@ impl Component for Editor { if ui.input(|i| i.key_pressed(Key::S) && i.modifiers.ctrl) { self.save(); - }; + } self.render_toolbar(state, ui, ctx); @@ -87,17 +87,23 @@ impl Editor { fn filename(&self) -> &str { self.path .file_name() - .unwrap_or(OsStr::new("Unnamed!")) + .unwrap_or_else(|| OsStr::new("Unnamed!")) .to_str() - .unwrap() + .map_or_else( + || unreachable!("File name should be valid UTF-8."), + |ext| ext, + ) } fn extension(&self) -> &str { self.path .extension() - .unwrap_or(OsStr::new("Unknown!")) + .unwrap_or_else(|| OsStr::new("Unknown!")) .to_str() - .unwrap() + .map_or_else( + || unreachable!("File name should be valid UTF-8."), + |ext| ext, + ) } fn save(&mut self) { @@ -210,10 +216,10 @@ impl Editor { ); // Instruction column - let instruction = match Instruction::decode(value) { - Ok(instruction) => instruction.to_string(), - Err(_) => format!("{value:10}"), - }; + let instruction = Instruction::decode(value).map_or_else( + |_| format!("{value:10}"), + |instruction| instruction.to_string(), + ); ui.label( egui::RichText::new(instruction) @@ -230,19 +236,25 @@ impl Editor { fn render_editor(&mut self, _state: &mut State, ui: &mut Ui, _ctx: &Context) { let available_width = ui.available_width(); let syntax = match self.extension() { - "dsa" => Syntax::dsa(), - _ => Syntax::dsa(), + "dsa" => Some(Syntax::new("dsa")), + _ => None, }; - CodeEditor::default() + let ed = CodeEditor::default() .id_source("editor") .with_fontsize(12.0) .with_rows(0) .with_theme(ColorTheme::default()) - .with_syntax(syntax) .with_numlines(true) - .desired_width(available_width - 450.0) - .show(ui, &mut self.text); + .desired_width(available_width - 450.0); + + let mut editor = ed.clone(); + + if let Some(syntax) = syntax { + editor = ed.with_syntax(syntax); + } + + editor.show(ui, &mut self.text); } fn render_toolbar(&mut self, _state: &mut State, ui: &mut Ui, _ctx: &Context) { From 3a40719e54a56ae348ce3834032504f9774685a3 Mon Sep 17 00:00:00 2001 From: "J. Hinchliffe" Date: Tue, 17 Jun 2025 19:51:16 +0100 Subject: [PATCH 3/3] misc: back to little endian because I am evil --- assembler/src/main.rs | 2 +- emulator/src/emulator/system/memory.rs | 2 +- emulator/src/emulator/system/processor/mod.rs | 92 ++++++++++++------- emulator/src/emulator/ui/editor.rs | 2 +- 4 files changed, 63 insertions(+), 35 deletions(-) diff --git a/assembler/src/main.rs b/assembler/src/main.rs index b01f13a..012f777 100644 --- a/assembler/src/main.rs +++ b/assembler/src/main.rs @@ -17,6 +17,6 @@ fn main() { .iter() .map(|i| i.encode()) .for_each(|i| { - output_file.write_all(&i.to_be_bytes()).unwrap(); + output_file.write_all(&i.to_le_bytes()).unwrap(); }); } diff --git a/emulator/src/emulator/system/memory.rs b/emulator/src/emulator/system/memory.rs index aa655e7..5382542 100644 --- a/emulator/src/emulator/system/memory.rs +++ b/emulator/src/emulator/system/memory.rs @@ -78,7 +78,7 @@ impl MemoryUnit for MainStore { bytes[1] = block.data[(offset + 1) as usize]; bytes[2] = block.data[(offset + 2) as usize]; bytes[3] = block.data[(offset + 3) as usize]; - u32::from_be_bytes(bytes) + u32::from_le_bytes(bytes) } fn read_range(&mut self, addr: u32, size: u32) -> Vec { diff --git a/emulator/src/emulator/system/processor/mod.rs b/emulator/src/emulator/system/processor/mod.rs index 8d31427..f1e93bc 100644 --- a/emulator/src/emulator/system/processor/mod.rs +++ b/emulator/src/emulator/system/processor/mod.rs @@ -8,7 +8,9 @@ use crate::emulator::system::{ model::{IODevice, RegFile}, }; -use common::instructions::{Instruction, Interrupt, Register, errors::InstructionDecodeError}; +use common::instructions::{ + Instruction, Interrupt, Register, errors::InstructionDecodeError, +}; pub struct Processor { pub memory: Box, @@ -168,71 +170,90 @@ impl Executable for Instruction { *cpu.reg(a.dr) = cpu.get(a.sr1); } - // Copies from SrcReg to a.drReg, sign extending the value to take up a full word. + // Copies from SrcReg to a.drReg, sign extending the value to take up a full + // word. Self::MovSigned(a) => { *cpu.reg(a.dr) = sign_extend(cpu.get(a.sr1)); } - // Loads a byte from memory address (base + offset) into a.drReg. The effective address must be byte-aligned. + // Loads a byte from memory address (base + offset) into a.drReg. The + // effective address must be byte-aligned. Self::LoadByte(a) => { - *cpu.reg(a.r2) = - u32::from(cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate))); + *cpu.reg(a.r2) = u32::from( + cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)), + ); } - // Loads a sign-extended byte from memory address (base + offset) into a.drReg. The effective address must be byte-aligned. + // Loads a sign-extended byte from memory address (base + offset) into + // a.drReg. The effective address must be byte-aligned. Self::LoadByteSigned(a) => { *cpu.reg(a.r2) = sign_extend(u32::from( cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)), )); } - // Loads a half-word from memory address (base + offset) into a.drReg. The effective address must be 2-byte-aligned. + // Loads a half-word from memory address (base + offset) into a.drReg. The + // effective address must be 2-byte-aligned. Self::LoadHalfword(a) => { - // we read an entire word, then right shift so we only get the first half of the word - *cpu.reg(a.r2) = cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16; - } - - // Loads a sign-extended half-word from memory address (base + offset) into a.drReg. The effective address must be 2-byte-aligned. - Self::LoadHalfwordSigned(a) => { + // we read an entire word, then right shift so we only get the first half + // of the word *cpu.reg(a.r2) = - sign_extend(cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16); + cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16; } - // Loads a word from memory address (base + offset) into a.drReg. The effective address must be 4-byte-aligned. + // Loads a sign-extended half-word from memory address (base + offset) into + // a.drReg. The effective address must be 2-byte-aligned. + Self::LoadHalfwordSigned(a) => { + *cpu.reg(a.r2) = sign_extend( + cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16, + ); + } + + // Loads a word from memory address (base + offset) into a.drReg. The + // effective address must be 4-byte-aligned. Self::LoadWord(a) => { - *cpu.reg(a.r2) = cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)); + *cpu.reg(a.r2) = + cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)); } - // Stores a byte from SrcReg in memory address (base + offset) The effective address must be byte-aligned. + // Stores a byte from SrcReg in memory address (base + offset) The effective + // address must be byte-aligned. Self::StoreByte(a) => { - cpu.memory - .write_byte(cpu.get(a.r1) + u32::from(a.immediate), cpu.get(a.r2) as u8); + cpu.memory.write_byte( + cpu.get(a.r1) + u32::from(a.immediate), + cpu.get(a.r2) as u8, + ); } - // Stores a half-word from SrcReg in memory address (base + offset) The effective address must be 2-byte-aligned. + // Stores a half-word from SrcReg in memory address (base + offset) The + // effective address must be 2-byte-aligned. Self::StoreHalfword(a) => { // split the value into bytes and then write two bytes - let bytes = (cpu.get(a.r1) as u16).to_be_bytes(); + let bytes = (cpu.get(a.r1) as u16).to_le_bytes(); cpu.memory .write_byte(cpu.get(a.r1) + u32::from(a.immediate), bytes[0]); cpu.memory .write_byte(cpu.get(a.r1) + u32::from(a.immediate) + 1, bytes[1]); } - // Stores a word from SrcReg in memory address (base + offset) The effective address must be 4-byte-aligned. + // Stores a word from SrcReg in memory address (base + offset) The effective + // address must be 4-byte-aligned. Self::StoreWord(a) => { cpu.memory .write_word(cpu.get(a.r1) + u32::from(a.immediate), cpu.get(a.r2)); } - // Loads a 16-bit literal value into reg, setting the bottom 16 bits of the word. To populate the upper 16 bits, see LUI. + // Loads a 16-bit literal value into reg, setting the bottom 16 bits of the + // word. To populate the upper 16 bits, see LUI. Self::LoadLowerImmediate(a) => { *cpu.reg(a.r1) = u32::from(a.immediate); } - // Loads a 16-bit literal value into reg, setting the top 16 bits of the word. To populate the lower 16 bits, see LLI. + // Loads a 16-bit literal value into reg, setting the top 16 bits of the word. + // To populate the lower 16 bits, see LLI. Self::LoadUpperImmediate(a) => { - *cpu.reg(a.r1) = (cpu.get(a.r1) & 0x0000_FFFF) | u32::from(a.immediate) << 16; + *cpu.reg(a.r1) = + (cpu.get(a.r1) & 0x0000_FFFF) | u32::from(a.immediate) << 16; } // Unconditionally jumps to the calculated address or direct address @@ -259,7 +280,8 @@ impl Executable for Instruction { } } - // Jumps to the calculated address or direct address if greater than flag or equal flag set. + // Jumps to the calculated address or direct address if greater than flag or + // equal flag set. Self::JumpGe(a) => { if cpu.get_flag(Flag::GreaterThan) || cpu.get_flag(Flag::Equal) { cpu.jump(a.r1, a.immediate); @@ -273,7 +295,8 @@ impl Executable for Instruction { } } - // Jumps to the calculated address or direct address if less than flag or equal flag set. + // Jumps to the calculated address or direct address if less than flag or + // equal flag set. Self::JumpLe(a) => { if cpu.get_flag(Flag::LessThan) || cpu.get_flag(Flag::Equal) { cpu.jump(a.r1, a.immediate); @@ -286,20 +309,24 @@ impl Executable for Instruction { // Decrements the value in the given register Self::Decrement(a) => *cpu.reg(a.sr1) = dec(cpu.get(a.sr1)), - // Left shifts the value in Reg by the given amount (either a register, or a literal value) + // Left shifts the value in Reg by the given amount (either a register, or a + // literal value) Self::ShiftLeft(a) => { let regval = cpu.get(a.sr2); let val = cpu.get(a.sr1); - *cpu.reg(a.sr1) = shl(val, if regval != 0 { regval as u8 } else { a.shamt }); + *cpu.reg(a.sr1) = + shl(val, if regval != 0 { regval as u8 } else { a.shamt }); } - // Right shifts the value in Reg by the given amount (either a register, or a literal value). + // Right shifts the value in Reg by the given amount (either a register, or a + // literal value). Self::ShiftRight(a) => { let regval = cpu.get(a.sr2); let val = cpu.get(a.sr1); - *cpu.reg(a.sr1) = shr(val, if regval != 0 { regval as u8 } else { a.shamt }); + *cpu.reg(a.sr1) = + shr(val, if regval != 0 { regval as u8 } else { a.shamt }); } // Adds the value of Src2 to Src1 and writes the result to a.dr @@ -333,7 +360,8 @@ impl Executable for Instruction { // Performs bitwise XNOR on Src1 and Src2 storing the result in a.dr Self::Xnor(a) => *cpu.reg(a.dr) = xnor(cpu.get(a.sr1), cpu.get(a.sr2)), - // Compares the value of Reg1 to the value in Reg2. The results of the comparisons are set in the Status register. + // Compares the value of Reg1 to the value in Reg2. The results of the + // comparisons are set in the Status register. Self::Compare(a) => { cpu.cmp(cpu.get(a.sr1), cpu.get(a.sr2)); } diff --git a/emulator/src/emulator/ui/editor.rs b/emulator/src/emulator/ui/editor.rs index 5fd7096..703aaea 100644 --- a/emulator/src/emulator/ui/editor.rs +++ b/emulator/src/emulator/ui/editor.rs @@ -178,7 +178,7 @@ impl Editor { bytes[i] = byte; } } - let value = u32::from_be_bytes(bytes); + let value = u32::from_le_bytes(bytes); // Address column ui.with_layout(