From a4d42bdad62f79ecd9610a9ce2299b264a7e11d2 Mon Sep 17 00:00:00 2001 From: zxq5 Date: Thu, 16 Jul 2026 00:34:13 +0100 Subject: [PATCH] rewrote assembler backend to support custom executable format (DSE) and also refactored (moving crates around) --- .idea/dsa2.iml | 10 +- Cargo.toml | 2 +- dsa/assembler/Cargo.toml | 1 + dsa/assembler/src/assembler/codegen.rs | 30 +- dsa/assembler/src/assembler/mod.rs | 153 ++- dsa/assembler/src/assembler/resolver2.rs | 168 +++ dsa/assembler/src/assemblerv2/context.rs | 24 + dsa/assembler/src/assemblerv2/lexer.rs | 5 +- dsa/assembler/src/assemblerv2/mod.rs | 59 +- dsa/assembler/src/assemblerv2/parser.rs | 4 +- dsa/assembler/src/disassembler.rs | 158 --- dsa/assembler/src/main.rs | 9 +- dsa/common/Cargo.toml | 1 + dsa/common/src/formats/binary_dse.rs | 264 ++++ .../common/src/formats/binary_dso.rs | 0 dsa/common/src/formats/mod.rs | 2 + dsa/common/src/lib.rs | 1 + dsa/disassembler/Cargo.toml | 17 + dsa/disassembler/src/internal.rs | 350 ++++++ dsa/disassembler/src/lib.rs | 15 + dsa/disassembler/src/main.rs | 27 + .../{backend => emulator_core}/Cargo.toml | 4 +- .../src/config/default/dsa.iomap.ron | 0 .../src/config/default/dsa.mmap.ron | 0 .../src/config/default/mod.rs | 0 .../src/config/mod.rs | 0 .../{backend => emulator_core}/src/lib.rs | 0 .../src/memory/cache.rs | 0 .../src/memory/mmu.rs | 0 .../src/memory/mod.rs | 0 .../src/memory/ram.rs | 0 .../src/memory/tlb.rs | 0 .../src/processor/interrupts.rs | 0 .../src/processor/mod.rs | 0 .../src/processor/processor.rs | 5 + .../src/processor/state.rs | 4 +- .../{frontend => emulator_ui}/Cargo.toml | 18 +- .../JetBrainsMonoNerdFontMono_Regular.ttf | Bin .../{frontend => emulator_ui}/src/args.rs | 2 +- .../{frontend => emulator_ui}/src/lib.rs | 0 .../{frontend => emulator_ui}/src/main.rs | 6 +- .../src/ui/components/controller.rs | 8 +- .../src/ui/components/display.rs | 8 +- .../src/ui/components/editor/mod.rs | 211 +--- .../src/ui/components/editor/syntax/mod.rs | 6 +- .../src/ui/components/framebuffer.rs | 10 +- .../emulator_ui/src/ui/components/memory.rs | 264 ++++ .../src/ui/components/mod.rs | 2 +- .../src/ui/components/registers.rs | 11 +- .../src/ui/components/serial.rs | 16 +- .../{frontend => emulator_ui}/src/ui/mod.rs | 23 +- .../frontend/src/ui/components/memory.rs | 138 --- dsa_resources/bf.dsa | 6 +- dsx/dsx_client/Cargo.toml | 7 + dsx/dsx_client/src/main.rs | 3 + dsx/dsx_common/Cargo.toml | 7 + dsx/dsx_common/src/lib.rs | 14 + dsx/dsx_server/Cargo.toml | 7 + dsx/dsx_server/src/main.rs | 3 + e.txt | 1072 ----------------- 60 files changed, 1486 insertions(+), 1669 deletions(-) create mode 100644 dsa/assembler/src/assembler/resolver2.rs create mode 100644 dsa/assembler/src/assemblerv2/context.rs delete mode 100644 dsa/assembler/src/disassembler.rs create mode 100644 dsa/common/src/formats/binary_dse.rs rename decomp2.txt => dsa/common/src/formats/binary_dso.rs (100%) create mode 100644 dsa/common/src/formats/mod.rs create mode 100644 dsa/disassembler/Cargo.toml create mode 100644 dsa/disassembler/src/internal.rs create mode 100644 dsa/disassembler/src/lib.rs create mode 100644 dsa/disassembler/src/main.rs rename dsa/emulator/{backend => emulator_core}/Cargo.toml (85%) rename dsa/emulator/{backend => emulator_core}/src/config/default/dsa.iomap.ron (100%) rename dsa/emulator/{backend => emulator_core}/src/config/default/dsa.mmap.ron (100%) rename dsa/emulator/{backend => emulator_core}/src/config/default/mod.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/config/mod.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/lib.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/memory/cache.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/memory/mmu.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/memory/mod.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/memory/ram.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/memory/tlb.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/processor/interrupts.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/processor/mod.rs (100%) rename dsa/emulator/{backend => emulator_core}/src/processor/processor.rs (98%) rename dsa/emulator/{backend => emulator_core}/src/processor/state.rs (87%) rename dsa/emulator/{frontend => emulator_ui}/Cargo.toml (74%) rename dsa/emulator/{frontend => emulator_ui}/font/JetBrainsMonoNerdFontMono_Regular.ttf (100%) rename dsa/emulator/{frontend => emulator_ui}/src/args.rs (95%) rename dsa/emulator/{frontend => emulator_ui}/src/lib.rs (100%) rename dsa/emulator/{frontend => emulator_ui}/src/main.rs (95%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/controller.rs (95%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/display.rs (95%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/editor/mod.rs (75%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/editor/syntax/mod.rs (91%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/framebuffer.rs (95%) create mode 100644 dsa/emulator/emulator_ui/src/ui/components/memory.rs rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/mod.rs (84%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/registers.rs (92%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/components/serial.rs (93%) rename dsa/emulator/{frontend => emulator_ui}/src/ui/mod.rs (90%) delete mode 100644 dsa/emulator/frontend/src/ui/components/memory.rs create mode 100644 dsx/dsx_client/Cargo.toml create mode 100644 dsx/dsx_client/src/main.rs create mode 100644 dsx/dsx_common/Cargo.toml create mode 100644 dsx/dsx_common/src/lib.rs create mode 100644 dsx/dsx_server/Cargo.toml create mode 100644 dsx/dsx_server/src/main.rs delete mode 100644 e.txt diff --git a/.idea/dsa2.iml b/.idea/dsa2.iml index 433611a..0a6f00f 100644 --- a/.idea/dsa2.iml +++ b/.idea/dsa2.iml @@ -7,9 +7,13 @@ - - - + + + + + + + diff --git a/Cargo.toml b/Cargo.toml index 1b5ed0a..a5bd01b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["dsa/common", "dsa/assembler", "dsa/emulator/frontend", "dsa/linker", "dsa/compiler", "dsa/emulator/backend"] +members = ["dsa/common", "dsa/assembler", "dsa/emulator/emulator_ui", "dsa/linker", "dsa/compiler", "dsa/emulator/emulator_core", "dsx/dsx_common", "dsx/dsx_server", "dsx/dsx_client", "dsa/disassembler"] resolver = "3" [workspace.package] diff --git a/dsa/assembler/Cargo.toml b/dsa/assembler/Cargo.toml index 6165c2d..f5f1547 100644 --- a/dsa/assembler/Cargo.toml +++ b/dsa/assembler/Cargo.toml @@ -13,6 +13,7 @@ name = "assembler" path = "src/lib.rs" [dependencies] +binrw = "0.15.1" clap = { version = "4.6.0", features = ["derive"] } common = { path = "../common" } diff --git a/dsa/assembler/src/assembler/codegen.rs b/dsa/assembler/src/assembler/codegen.rs index 78ddadf..f08dcb5 100644 --- a/dsa/assembler/src/assembler/codegen.rs +++ b/dsa/assembler/src/assembler/codegen.rs @@ -78,7 +78,7 @@ fn build_instruction(node: &Node) -> Result { fn ins_mov( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(src_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -98,7 +98,7 @@ fn ins_mov( fn ins_cmov( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(src_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -122,7 +122,7 @@ fn ins_cmov( fn ins_ldx_stx( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(src_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -153,7 +153,7 @@ fn ins_ldx_stx( fn ins_stack( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(reg_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -169,7 +169,7 @@ fn ins_stack( fn ins_load_imm( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(value_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -190,7 +190,7 @@ fn ins_load_imm( fn ins_jump_unconditional( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(addr_imm_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -212,7 +212,7 @@ fn ins_jump_unconditional( fn ins_jump_conditional( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(condition_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -239,7 +239,7 @@ fn ins_jump_conditional( fn ins_comparison( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(left_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -267,7 +267,7 @@ fn ins_comparison( fn ins_bitshift( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(src_reg) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -296,7 +296,7 @@ fn ins_bitshift( fn ins_arithmetic( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(left_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -327,7 +327,7 @@ fn ins_arithmetic( fn ins_imm_arithmetic( opcode: Opcode, - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(reg_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -350,7 +350,7 @@ fn ins_imm_arithmetic( }) } -fn ins_not(args: &[crate::assembler::model::Token]) -> Result { +fn ins_not(args: &[Token]) -> Result { let Some(reg_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); }; @@ -363,7 +363,7 @@ fn ins_not(args: &[crate::assembler::model::Token]) -> Result Result { +fn ins_interrupt(args: &[Token]) -> Result { let Some(code_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); }; @@ -373,7 +373,7 @@ fn ins_interrupt(args: &[crate::assembler::model::Token]) -> Result Result { let Some(immediate_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); @@ -384,7 +384,7 @@ fn build_data_instruction( } fn build_segment_instruction( - args: &[crate::assembler::model::Token], + args: &[Token], ) -> Result { let Some(immediate_token) = args.first() else { return Err(AssembleError::MissingArgument(0)); diff --git a/dsa/assembler/src/assembler/mod.rs b/dsa/assembler/src/assembler/mod.rs index 9f3d8a7..f1ab0ad 100644 --- a/dsa/assembler/src/assembler/mod.rs +++ b/dsa/assembler/src/assembler/mod.rs @@ -11,8 +11,11 @@ use std::{ }, thread, }; - +use std::collections::HashMap; +use std::io::Cursor; +use common::formats::binary_dse::{DseExecutable, SymbolEntry}; use common::prelude::Instruction; +use crate::assembler::resolver2::{resolve_address, resolve_dependencies, resolve_symbols, split_sections, SectionId}; // Module declarations #[macro_use] @@ -21,12 +24,14 @@ pub mod macros; #[allow(clippy::module_inception)] pub mod codegen; pub mod expand; -pub mod lexer; -pub mod model; -pub mod parser; -pub mod resolver; -use crate::assemblerv2::lexer::Lexer; +mod lexer; +mod model; +pub mod parser; +// pub mod resolver; +pub mod resolver2; + + // Re-exports pub use self::{ @@ -35,7 +40,7 @@ pub use self::{ lexer::lexer, model::{Module, Node, Opcode, Symbol, Token, TokenType}, parser::{Parser, Program}, - resolver::{create_sections, resolve_dependencies, resolve_symbols}, + // resolver::{create_sections, resolve_dependencies, resolve_symbols}, }; pub struct Assembler { @@ -67,23 +72,33 @@ impl Assembler { let tx = self.result_tx.clone(); thread::spawn(move || match assemble(&src) { - Ok(res) => { - let buffer: Vec = res - .iter() - .flat_map(|instruction| instruction.to_le_bytes()) - .collect(); - tx.send(Ok(buffer)) - .expect("Failed to send compilation result from worker thread"); - } - Err(err) => { - tx.send(Err(err)) - .expect("Failed to send compilation error from worker thread"); + Ok(exe) => { + let mut buffer = Cursor::new(Vec::new()); + match exe.write(&mut buffer) { + Ok(()) => { + tx.send(Ok(buffer.into_inner())) + .expect("Failed to send compilation result from worker thread"); + } + Err(e) => { + tx.send(Err(AssembleError::Generic)) + .expect("..."); + } + } } + Err(err) => { /* unchanged */ } }); self.is_running = true; } + /// Polls the result channel to check if a compilation result is ready. + /// + /// This method attempts a non-blocking read (`try_recv`) from the result receiver. + /// It returns `Some(Ok(Vec))` if the compilation successfully finished and + /// the binary output is available, or `None` if no result was received yet. + /// + /// If it receives an error via `mpsc::TryRecvError::Disconnected`, it indicates that + /// the worker thread terminated unexpectedly, returning a specific error string. pub fn poll(&mut self) -> Option, String>> { if !self.is_running { return None; @@ -130,36 +145,114 @@ impl Assembler { impl Assembler {} -fn assemble(src: &Path) -> Result, AssembleError> { +// fn assemble(src: &Path) -> Result, AssembleError> { +// let mut modules = HashSet::new(); +// let mut program = Program::new(); +// +// let hash = quick_hash(src); +// +// if modules.contains(&hash) { +// return Ok(vec![]); +// } +// +// prepare_dependency(src, &mut modules, &mut program)?; +// +// let mut nodes = program.nodes.clone(); +// +// println!("PRE LINK"); +// for node in &nodes { +// println!("{:?}", node); +// } +// +// create_sections(&mut nodes)?; +// resolve_symbols(&mut nodes)?; +// +// println!("Generating assembly output..."); +// +// let instructions = codegen(nodes)?; +// +// println!("Compilation Successful"); +// Ok(instructions) +// } + +fn assemble(src: &Path) -> Result { let mut modules = HashSet::new(); let mut program = Program::new(); - let hash = quick_hash(src); - - if modules.contains(&hash) { - return Ok(vec![]); - } - prepare_dependency(src, &mut modules, &mut program)?; - let mut nodes = program.nodes.clone(); + let nodes = program.nodes.clone(); println!("PRE LINK"); for node in &nodes { println!("{:?}", node); } - create_sections(&mut nodes)?; - resolve_symbols(&mut nodes)?; + let (data_nodes, mut text_nodes) = split_sections(nodes); + let symbol_table = resolve_symbols(&data_nodes, &mut text_nodes)?; + let text_len = text_nodes.len() as u32; println!("Generating assembly output..."); + let instructions = codegen(text_nodes)?; + let text: Vec = instructions + .iter() + .map(|i| i.0).collect(); - let instructions = codegen(nodes)?; + let data = build_data_bytes(&data_nodes)?; + + // Build string table + SymbolEntry list from the resolved symbol table + let mut string_table = Vec::new(); + let mut symbols = Vec::new(); + for (symbol, entry) in &symbol_table { + let name_offset = string_table.len() as u32; + string_table.extend_from_slice(symbol.name.as_bytes()); + string_table.push(0); // null terminator + + symbols.push(SymbolEntry { + name_offset, + value: resolve_address(*entry, text_len), + section: match entry.1 { + SectionId::Text => 2, + SectionId::Data => 1, + }, + binding: 1, // global — refine later if adding local/weak + _pad: 0, + }); + } + + // Entry point: first symbol to jump to is '_init' + let entry_point = symbol_table + .iter() + .find(|(sym, _)| sym.name == "_init") + .map(|(_, entry)| resolve_address(*entry, text_len)) + .ok_or(AssembleError::UndefinedSymbol(Symbol { + name: "_init".to_string(), + module: Module::Resolved(0), + }))?; println!("Compilation Successful"); - Ok(instructions) + + Ok(DseExecutable::new( + symbols.as_slice(), + &string_table, + &data, + &text, + entry_point, + ).unwrap()) } +fn build_data_bytes(data_nodes: &[Node]) -> Result, AssembleError> { + let mut bytes = Vec::with_capacity(data_nodes.len() * 4); + for node in data_nodes { + let Token::Immediate(value) = node.arg(0)? else { + return Err(AssembleError::InvalidArg); + }; + bytes.extend_from_slice(&value.to_le_bytes()); + } + Ok(bytes) +} + + fn prepare_dependency( path: &Path, modules: &mut HashSet, diff --git a/dsa/assembler/src/assembler/resolver2.rs b/dsa/assembler/src/assembler/resolver2.rs new file mode 100644 index 0000000..e19510f --- /dev/null +++ b/dsa/assembler/src/assembler/resolver2.rs @@ -0,0 +1,168 @@ +use std::collections::HashMap; +use std::path::Path; + +use crate::assembler::model::{Module, Node, Opcode, Symbol, Token}; +use crate::assembler::{quick_hash, AssembleError}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SectionId { + Data, + Text, +} + +/// Splits a flat (possibly multi-module) node list into separate data and +/// text streams. Segment/Include markers are dropped here — module +/// disambiguation lives on `Symbol.module`, not node position, so we don't +/// need them past this point. +pub fn split_sections(nodes: Vec) -> (Vec, Vec) { + let mut data = Vec::new(); + let mut text = Vec::new(); + + for node in nodes { + match node.opcode() { + Opcode::Data => data.push(node), + Opcode::Segment | Opcode::Include => {} + _ => text.push(node), + } + } + + (data, text) +} + +pub fn generate_symbol_table( + data_nodes: &[Node], + text_nodes: &[Node], +) -> HashMap { + let mut table = HashMap::new(); + + for (i, node) in data_nodes.iter().enumerate() { + if let Some(symbol) = node.label() { + table.insert(symbol, (4 * i as u32, SectionId::Data)); + } + } + for (i, node) in text_nodes.iter().enumerate() { + if let Some(symbol) = node.label() { + table.insert(symbol, (4 * i as u32, SectionId::Text)); + } + } + + table +} + +/// v1 loader convention: TEXT is placed at address 0, DATA immediately +/// follows it. This is a stopgap until real relocations exist — it's the +/// same assumption your current jmp-hack already makes, just explicit now. +pub fn resolve_address((offset, section): (u32, SectionId), text_len_words: u32) -> u32 { + match section { + SectionId::Text => offset, + SectionId::Data => (text_len_words * 4) + offset, + } +} + +/// Patches every symbol reference in `text_nodes` with its resolved absolute +/// address, and returns the symbol table so the caller can build the +/// executable's symbol/string tables from it. +pub fn resolve_symbols( + data_nodes: &[Node], + text_nodes: &mut [Node], +) -> Result, AssembleError> { + let symbol_table = generate_symbol_table(data_nodes, text_nodes); + let text_len = text_nodes.len() as u32; + + for node in text_nodes.iter_mut() { + match node.opcode() { + Opcode::Jmp | Opcode::Call | Opcode::Jic | Opcode::Jnc | Opcode::Lli | Opcode::Lui => { + if let Token::Symbol(symbol) = node + .arg(0) + .expect("Expected argument 0 for jump-like opcode") + { + let Some(entry) = symbol_table.get(&symbol) else { + return Err(AssembleError::UndefinedSymbol(symbol)); + }; + node.tokens[0] = Token::Immediate(resolve_address(*entry, text_len)); + } + } + Opcode::Jez | Opcode::Jnz => { + if let Token::Symbol(symbol) = node + .arg(1) + .expect("Expected argument 1 for jump-like opcode") + { + let Some(entry) = symbol_table.get(&symbol) else { + return Err(AssembleError::UndefinedSymbol(symbol)); + }; + node.tokens[1] = Token::Immediate(resolve_address(*entry, text_len)); + } + } + _ => (), + } + } + + Ok(symbol_table) +} + +// resolve_dependencies is unchanged — keep exactly as you have it. +pub fn resolve_dependencies( + mut nodes: Vec, + base_dir: &Path, +) -> Result, AssembleError> { + // First we get a list of imports. + let mut dependencies = Vec::new(); + for node in &nodes { + if node.opcode() == Opcode::Include { + // we want the path, and the name + let name = if let Token::Symbol(name) = node + .arg(0) + .expect("Expected argument #0 for Include directive.") + { + name.name.clone() + } else { + unreachable!() + }; //node.2.get(0).unwrap() + + let Ok(Token::StringLit(path)) = node.arg(1) else { + unreachable!() + }; + + let full_path = base_dir.join(path); + let canonical_path = full_path + .canonicalize() + .map_err(|_| AssembleError::InvalidFile(full_path.clone()))?; + + let hash = quick_hash(&canonical_path); + + dependencies.push((name, hash)); + } + } + + let mut changes = Vec::<(u32, u32, Symbol)>::new(); + // now we resolve the symbols on all the nodes + // we need to check all operands for unresolved signals + for (i, node) in nodes.clone().iter().enumerate() { + let Node { + tokens: operands, .. + } = node; + for (j, token) in operands.iter().enumerate() { + if let Token::Symbol(symbol) = token { + for d in &dependencies { + if let Module::Unresolved(name) = symbol.module.clone() { + if name != d.0 { + continue; + } + + let symbol = Symbol { + name: symbol.name.clone(), + module: Module::Resolved(d.1), + }; + changes.push((i as u32, j as u32, symbol)); + } + } + } + } + } + + for (i, j, symbol) in changes { + nodes[i as usize].tokens[j as usize] = Token::Symbol(symbol); + } + + Ok(nodes) +} diff --git a/dsa/assembler/src/assemblerv2/context.rs b/dsa/assembler/src/assemblerv2/context.rs new file mode 100644 index 0000000..e1c2b28 --- /dev/null +++ b/dsa/assembler/src/assemblerv2/context.rs @@ -0,0 +1,24 @@ +use std::path::PathBuf; + +pub struct BuildContext { + filename: PathBuf, + stage: BuildStage, + // Logging +} + +impl BuildContext { + pub fn new(filename: PathBuf) -> Self { + Self { + filename, + stage: BuildStage::Lexing, + } + } +} + +pub enum BuildStage { + Lexing, + Parsing, + PseudoExpansion, + Linking, + CodeGeneration, +} diff --git a/dsa/assembler/src/assemblerv2/lexer.rs b/dsa/assembler/src/assemblerv2/lexer.rs index f280404..71c09cd 100644 --- a/dsa/assembler/src/assemblerv2/lexer.rs +++ b/dsa/assembler/src/assemblerv2/lexer.rs @@ -2,7 +2,8 @@ use std::{str::FromStr, thread, time::Duration}; use common::{asm::AsmOpcode, prelude::Register}; -use crate::assembler::{AssembleError, Module, Opcode, Symbol, Token, lexer::parse_opcode}; +use crate::assembler::{AssembleError, Module, Symbol}; +use crate::assemblerv2::Token; pub struct Lexer { src: Vec, @@ -75,7 +76,7 @@ impl Lexer { buffer.push(self.src.pop().unwrap() as char); } - if let Ok(opcode) = Opcode::from_str(&buffer) { + if let Ok(opcode) = AsmOpcode::from_str(&buffer) { tokens.push(Token::Opcode(opcode)); continue; } diff --git a/dsa/assembler/src/assemblerv2/mod.rs b/dsa/assembler/src/assemblerv2/mod.rs index ac38c29..e038948 100644 --- a/dsa/assembler/src/assemblerv2/mod.rs +++ b/dsa/assembler/src/assemblerv2/mod.rs @@ -1,46 +1,43 @@ -// mod error; -pub mod lexer; -// pub mod parser; +mod error; +mod lexer; +mod parser; use core::fmt; - use crate::assembler::{AssembleError, Symbol}; -// use common::{asm::AsmOpcode, prelude::Register}; +use common::{asm::AsmOpcode, prelude::Register}; use lexer::Lexer; -// use parser::Parser; +use parser::Parser; pub fn asm(input: &str) -> Result, AssembleError> { let mut lexer = Lexer::new(input.to_string(), 0); let tokens = lexer.run()?; - // let ast = Parser::new(tokens).parse().unwrap(); + let ast = Parser::new(tokens).parse().unwrap(); - // println!("{:#?}", ast); - - // let ast = parser::parse(tokens)?; + println!("{:#?}", ast); Ok(vec![]) } -// #[derive(Debug, Clone)] -// pub enum Token { -// Symbol(Symbol), -// Register(Register), -// Immediate(u32), -// StringLit(String), -// CharLit(char), -// Opcode(AsmOpcode), -// } +#[derive(Debug, Clone)] +pub enum Token { + Symbol(Symbol), + Register(Register), + Immediate(u32), + StringLit(String), + CharLit(char), + Opcode(AsmOpcode), +} -// impl fmt::Display for Token { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// match self { -// Self::Symbol(symbol) => write!(f, "{symbol}"), -// Self::Register(register) => write!(f, "{register}",), -// Self::Immediate(immediate) => write!(f, "{immediate}",), -// Self::StringLit(string_lit) => write!(f, "{string_lit}",), -// Self::CharLit(char_lit) => write!(f, "{char_lit}",), -// Self::Opcode(opcode) => write!(f, "{opcode}",), -// } -// } -// } +impl fmt::Display for Token { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Symbol(symbol) => write!(f, "{symbol}"), + Self::Register(register) => write!(f, "{register}",), + Self::Immediate(immediate) => write!(f, "{immediate}",), + Self::StringLit(string_lit) => write!(f, "{string_lit}",), + Self::CharLit(char_lit) => write!(f, "{char_lit}",), + Self::Opcode(opcode) => write!(f, "{opcode}",), + } + } +} diff --git a/dsa/assembler/src/assemblerv2/parser.rs b/dsa/assembler/src/assemblerv2/parser.rs index c77d978..1aca47b 100644 --- a/dsa/assembler/src/assemblerv2/parser.rs +++ b/dsa/assembler/src/assemblerv2/parser.rs @@ -2,11 +2,11 @@ use std::path::PathBuf; use common::asm::{AsmInstruction, AsmOpcode}; -use crate::assembler::Symbol; +use crate::assembler::{Symbol}; use crate::{expect_tt, expect_value}; -use super::{Token, error::AssembleError}; +use super::{error::AssembleError, Token}; pub struct AsmNode { pub label: Option, diff --git a/dsa/assembler/src/disassembler.rs b/dsa/assembler/src/disassembler.rs deleted file mode 100644 index 457489a..0000000 --- a/dsa/assembler/src/disassembler.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use std::io::{Cursor, Read, Seek, SeekFrom, Write}; -use std::fs::File; -use binrw::{binrw, BinRead, binwrite, NullString, BinReaderExt, BinWriterExt, BinWrite}; - -use common::prelude::Instruction; -use crate::assembler::Symbol; - -pub fn disassemble(in_path: PathBuf, out_path: PathBuf) -> Result<(), String> { - - let Ok(content) = fs::read(in_path) else { - return Err(String::new()) - }; - - for (line_num, chunk) in content.chunks(4).enumerate() { - let address = line_num * 4; - - let value = u32::from_le_bytes(*chunk.as_array().unwrap()); - println!("{:#?}", Instruction(value)); - } - Ok(()) -} - - -#[binrw] -#[brw(magic = b"DSAX", little)] -#[derive(Debug, Clone)] -struct DseHeader { - version: u16, - flags: u16, - entry_point: u32, - - symbol_table_offset: u32, - symbol_table_size: u32, - - string_table_offset: u32, - string_table_size: u32, - - data_offset: u32, - data_size: u32, - - text_offset: u32, - text_size: u32 -} - -#[binrw] -#[brw(little)] -#[derive(Debug, Clone)] -struct SymbolEntry { - name_offset: u32, - value: u32, - section: u8, - binding: u8, - _pad: u16 -} - -#[derive(Debug, Clone)] -struct DseExecutable { - header: DseHeader, - symbols: Vec, - string_table: Vec, - data: Vec, - text: Vec -} - -impl DseExecutable { - fn load(path: PathBuf) -> binrw::BinResult { - let mut file = File::open(path).map_err(|e| binrw::Error::Io(e))?; - Self::read(&mut file) - } - - fn read(reader: &mut R) -> binrw::BinResult { - let header = DseHeader::read(reader)?; - - reader.seek(SeekFrom::Start(header.symbol_table_offset as u64))?; - let symbols: Vec = (0..header.symbol_table_size) - .map(|_| SymbolEntry::read(reader)) - .collect::>()?; - - reader.seek(SeekFrom::Start(header.string_table_offset as u64))?; - let mut string_table = vec![0u8; header.string_table_size as usize]; - reader.read_exact(&mut string_table).map_err(|e| binrw::Error::Io(e))?; - - reader.seek(SeekFrom::Start(header.data_offset as u64))?; - let mut data = vec![0u8; header.data_size as usize]; - reader.read_exact(&mut data).map_err(|e| binrw::Error::Io(e))?; - - reader.seek(SeekFrom::Start(header.text_offset as u64))?; - let text: Vec = (0..header.text_size) - .map(|_| reader.read_le::()) - .collect::>()?; - - Ok(DseExecutable { header, symbols, string_table, data, text }) - } - - fn save(&self, path: PathBuf) -> binrw::BinResult<()> { - let mut file = File::create(path) - .map_err(|e| binrw::Error::Io(e))?; - self.write(&mut file) - } - - fn write(&self, writer: &mut W) -> binrw::BinResult<()> { - self.header.write(writer)?; - - for symbol in &self.symbols { - symbol.write(writer)?; - } - - writer.write_all(&self.string_table)?; - writer.write_all(&self.data)?; - - for word in &self.text { - writer.write_le(word)?; - } - - Ok(()) - } - - fn new( - symbols: &[SymbolEntry], - string_table: &[u8], - data: &[u8], - text: &[u32], - entry_point: u32, - ) -> DseExecutable { - const HEADER_SIZE: u32 = 4 + 2 + 2 + 4 + 4*2 + 4*2 + 4*2 + 4*2; // adjust to actual packed size - - let symbol_table_offset = HEADER_SIZE; - let symbol_table_size = symbols.len() as u32 * 8; // 4+4+1+1+2 padded = 8 bytes each - let string_table_offset = symbol_table_offset + symbol_table_size; - let data_offset = string_table_offset + string_table.len() as u32; - let text_offset = data_offset + data.len() as u32; - - let header = DseHeader { - version: 1, - flags: 0, - entry_point, - symbol_table_offset, - symbol_table_size: symbols.len() as u32, - string_table_offset, - string_table_size: string_table.len() as u32, - data_offset, - data_size: data.len() as u32, - text_offset, - text_size: text.len() as u32, - }; - - DseExecutable { - header, - symbols: symbols.to_vec(), - string_table: string_table.to_vec(), - data: data.to_vec(), - text: text.to_vec(), - } - } -} - diff --git a/dsa/assembler/src/main.rs b/dsa/assembler/src/main.rs index 06f58eb..80bb7ba 100644 --- a/dsa/assembler/src/main.rs +++ b/dsa/assembler/src/main.rs @@ -1,5 +1,5 @@ use assembler::prelude::*; -use clap::{Parser, arg, command}; +use clap::{Parser, arg}; use std::{fs, path::PathBuf}; #[derive(Parser, Debug, Clone)] @@ -23,11 +23,4 @@ fn main() { eprintln!("Failed to write to output file: {e}"); std::process::exit(1); } - - // let input = fs::read_to_string("../../dsa_resources/framebuffer.dsa").unwrap(); - // let output = asm(&input).unwrap(); - - // for token in output { - // println!("{:?}", token); - // } } diff --git a/dsa/common/Cargo.toml b/dsa/common/Cargo.toml index c2431e4..e3b39c1 100644 --- a/dsa/common/Cargo.toml +++ b/dsa/common/Cargo.toml @@ -7,4 +7,5 @@ edition = "2024" path = "src/lib.rs" [dependencies] +binrw = "0.15.1" strum = { version = "0.28.0", features = ["derive"] } diff --git a/dsa/common/src/formats/binary_dse.rs b/dsa/common/src/formats/binary_dse.rs new file mode 100644 index 0000000..41ad4ea --- /dev/null +++ b/dsa/common/src/formats/binary_dse.rs @@ -0,0 +1,264 @@ + +use std::fs::File; +use std::io::{Cursor, Read, Seek, SeekFrom, Write}; +use std::path::PathBuf; +use binrw::{binrw, BinRead, binwrite, NullString, BinReaderExt, BinWriterExt, BinWrite}; +use std::fmt; +use crate::prelude::Instruction; + +#[binrw] +#[brw(magic = b"DSAX", little)] +#[derive(Debug, Clone)] +pub struct DseHeader { + version: u16, + flags: u16, + pub entry_point: u32, + + symbol_table_offset: u32, + symbol_table_size: u32, + + string_table_offset: u32, + string_table_size: u32, + + data_offset: u32, + data_size: u32, + + pub text_offset: u32, + text_size: u32 +} + +#[binrw] +#[brw(little)] +#[derive(Debug, Clone)] +pub struct SymbolEntry { + pub name_offset: u32, + pub value: u32, + pub section: u8, + pub binding: u8, + pub _pad: u16 +} + +#[derive(Debug, Clone)] +pub struct DseExecutable { + pub header: DseHeader, + pub symbols: Vec, + pub string_table: Vec, + pub data: Vec, + pub text: Vec +} + +impl DseExecutable { + pub fn load(path: PathBuf) -> binrw::BinResult { + let mut file = File::open(path).map_err(|e| binrw::Error::Io(e))?; + Self::read(&mut file) + } + + pub fn read(reader: &mut R) -> binrw::BinResult { + let header = DseHeader::read(reader)?; + + reader.seek(SeekFrom::Start(header.symbol_table_offset as u64))?; + let symbols: Vec = (0..header.symbol_table_size) + .map(|_| SymbolEntry::read(reader)) + .collect::>()?; + + reader.seek(SeekFrom::Start(header.string_table_offset as u64))?; + let mut string_table = vec![0u8; header.string_table_size as usize]; + reader.read_exact(&mut string_table).map_err(|e| binrw::Error::Io(e))?; + + reader.seek(SeekFrom::Start(header.data_offset as u64))?; + let mut data = vec![0u8; header.data_size as usize]; + reader.read_exact(&mut data).map_err(|e| binrw::Error::Io(e))?; + + reader.seek(SeekFrom::Start(header.text_offset as u64))?; + let text: Vec = (0..header.text_size) + .map(|_| reader.read_le::()) + .collect::>()?; + + Ok(DseExecutable { header, symbols, string_table, data, text }) + } + + pub fn save(&self, path: PathBuf) -> binrw::BinResult<()> { + let mut file = File::create(path) + .map_err(|e| binrw::Error::Io(e))?; + self.write(&mut file) + } + + pub fn write(&self, writer: &mut W) -> binrw::BinResult<()> { + self.header.write(writer)?; + + for symbol in &self.symbols { + symbol.write(writer)?; + } + + writer.write_all(&self.string_table)?; + writer.write_all(&self.data)?; + + for word in &self.text { + writer.write_le(word)?; + } + + Ok(()) + } + + pub fn new( + symbols: &[SymbolEntry], + string_table: &[u8], + data: &[u8], + text: &[u32], + entry_point: u32, + ) -> binrw::BinResult { + // Derive sizes from real serialization instead of hand-counted constants. + let header_size = { + let mut buf = Cursor::new(Vec::new()); + // dummy header just to measure length; fields' values don't matter here + let dummy = DseHeader { + version: 0, flags: 0, entry_point: 0, + symbol_table_offset: 0, symbol_table_size: 0, + string_table_offset: 0, string_table_size: 0, + data_offset: 0, data_size: 0, + text_offset: 0, text_size: 0, + }; + dummy.write(&mut buf)?; + buf.into_inner().len() as u32 + }; + + let symbol_entry_size = if symbols.is_empty() { + // measure using a zeroed entry even if symbols is empty + let mut buf = Cursor::new(Vec::new()); + SymbolEntry { name_offset: 0, value: 0, section: 0, binding: 0, _pad: 0 } + .write(&mut buf)?; + buf.into_inner().len() as u32 + } else { + let mut buf = Cursor::new(Vec::new()); + symbols[0].write(&mut buf)?; + buf.into_inner().len() as u32 + }; + + let symbol_table_offset = header_size; + let symbol_table_bytes = symbols.len() as u32 * symbol_entry_size; + let string_table_offset = symbol_table_offset + symbol_table_bytes; + let data_offset = string_table_offset + string_table.len() as u32; + let text_offset = data_offset + data.len() as u32; + + let header = DseHeader { + version: 1, + flags: 0, + entry_point, + symbol_table_offset, + symbol_table_size: symbols.len() as u32, + string_table_offset, + string_table_size: string_table.len() as u32, + data_offset, + data_size: data.len() as u32, + text_offset, + text_size: text.len() as u32, + }; + + Ok(DseExecutable { + header, + symbols: symbols.to_vec(), + string_table: string_table.to_vec(), + data: data.to_vec(), + text: text.to_vec(), + }) + } + + /// Produces the runtime memory image: TEXT followed immediately by DATA, + /// matching the exact layout `resolve_address` assumed when the assembler + /// resolved symbol addresses. This is NOT the same as the on-disk file + /// layout (header/symtab/strtab/data/text) — this is what actually needs + /// to end up in emulator memory. + pub fn to_memory_image(&self) -> Vec { + let mut image = Vec::with_capacity(self.text.len() * 4 + self.data.len()); + + for word in &self.text { + image.extend_from_slice(&word.to_le_bytes()); + } + image.extend_from_slice(&self.data); + + image + } + + /// Runtime address where DATA begins, given TEXT is loaded at `text_base`. + /// Matches the assembler's `resolve_address` convention exactly. + pub fn data_base(&self, text_base: u32) -> u32 { + text_base + (self.text.len() as u32 * 4) + } + + /// Absolute runtime entry point address, given TEXT is loaded at `text_base`. + /// `self.header.entry_point` is already an absolute address under the + /// assumption text_base == 0, so this just re-bases it if you're loading + /// somewhere other than address 0. + pub fn entry_point(&self, text_base: u32) -> u32 { + text_base + self.header.entry_point + } +} + +// Display implementations for dumping binary contents +impl fmt::Display for DseHeader { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "DseHeader {{ version: {}, flags: {}, entry_point: 0x{:08X}, symbol_table_offset: 0x{:08X}, symbol_table_size: {}, string_table_offset: 0x{:08X}, string_table_size: {}, data_offset: 0x{:08X}, data_size: {}, text_offset: 0x{:08X}, text_size: {} }}", + self.version, + self.flags, + self.entry_point, + self.symbol_table_offset, + self.symbol_table_size, + self.string_table_offset, + self.string_table_size, + self.data_offset, + self.data_size, + self.text_offset, + self.text_size) + } +} + +impl fmt::Display for SymbolEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "SymbolEntry {{ name_offset: 0x{:08X}, value: 0x{:08X}, section: {}, binding: {} }}", + self.name_offset, + self.value, + self.section, + self.binding) + } +} + +impl fmt::Display for DseExecutable { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Header + writeln!(f, "{}", self.header)?; + // Symbols + writeln!(f, "Symbols:")?; + for s in &self.symbols { + writeln!(f, " {}", s)?; + } + // String table as hex dump + writeln!(f, "String Table ({} bytes):", self.string_table.len())?; + for chunk in self.string_table.chunks(16) { + write!(f, "{}", String::from_utf8_lossy(chunk))?; + // for byte in chunk { write!(f, "{:02X} ", byte)?; } + writeln!(f)?; + } + // Data section + writeln!(f, "Data ({} bytes):", self.data.len())?; + for chunk in self.data.chunks(16) { + write!(f, " ")?; + for byte in chunk { write!(f, "{:02X} ", byte)?; } + for byte in chunk { write!(f, "{} ", *byte as char)?; } + writeln!(f)?; + } + // Text section as Instructions + writeln!(f, "Text ({} words):", self.text.len())?; + for word in &self.text { + writeln!(f, " {:#010X} {:?}", word, Instruction(*word))?; + } + Ok(()) + } +} + +#[test] +fn symbol_entry_size_is_12_bytes() { + let mut buf = Cursor::new(Vec::new()); + SymbolEntry { name_offset: 0, value: 0, section: 0, binding: 0, _pad: 0 } + .write(&mut buf).unwrap(); + assert_eq!(buf.into_inner().len(), 12); +} \ No newline at end of file diff --git a/decomp2.txt b/dsa/common/src/formats/binary_dso.rs similarity index 100% rename from decomp2.txt rename to dsa/common/src/formats/binary_dso.rs diff --git a/dsa/common/src/formats/mod.rs b/dsa/common/src/formats/mod.rs new file mode 100644 index 0000000..2c88e30 --- /dev/null +++ b/dsa/common/src/formats/mod.rs @@ -0,0 +1,2 @@ +pub mod binary_dse; +pub mod binary_dso; \ No newline at end of file diff --git a/dsa/common/src/lib.rs b/dsa/common/src/lib.rs index be900cf..6e0d694 100644 --- a/dsa/common/src/lib.rs +++ b/dsa/common/src/lib.rs @@ -1,5 +1,6 @@ pub mod asm; pub mod isa; +pub mod formats; pub mod prelude { pub use crate::isa::instructions::Instruction; diff --git a/dsa/disassembler/Cargo.toml b/dsa/disassembler/Cargo.toml new file mode 100644 index 0000000..af7dce3 --- /dev/null +++ b/dsa/disassembler/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "disassembler" +edition.workspace = true +version.workspace = true +authors.workspace = true + +[[bin]] +name = "dsa-a" +path = "src/main.rs" + +[lib] +name = "disassembler" +path = "src/lib.rs" + +[dependencies] +clap = { version = "4.6.0", features = ["derive"] } +common = { path = "../common" } \ No newline at end of file diff --git a/dsa/disassembler/src/internal.rs b/dsa/disassembler/src/internal.rs new file mode 100644 index 0000000..cd986d8 --- /dev/null +++ b/dsa/disassembler/src/internal.rs @@ -0,0 +1,350 @@ +use std::collections::HashMap; +use std::fmt; +use common::formats::binary_dse::DseExecutable; +use common::isa::instructions::Opcode; +use common::prelude::{Instruction, Register}; + +#[derive(Debug)] +pub struct Disassembly { + pub symbols: Vec, + pub text_lines: Vec, + pub data_lines: Vec, +} + +#[derive(Debug)] +pub struct SymbolLine { + pub name: String, + pub address: u32, + pub section: SectionKind, + pub binding: BindingKind, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SectionKind { Data, Text, Abs, Undef } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum BindingKind { Local, Global, Weak } + +impl SectionKind { + fn from_raw(v: u8) -> Self { + match v { 1 => Self::Data, 2 => Self::Text, 0 => Self::Abs, _ => Self::Undef } + } +} +impl BindingKind { + fn from_raw(v: u8) -> Self { + match v { 1 => Self::Global, 2 => Self::Weak, _ => Self::Local } + } +} + +pub fn disassemble(exe: &DseExecutable) -> Disassembly { + let symbols = build_symbol_lines(exe); + + let mut text_labels: HashMap = HashMap::new(); + let mut data_labels: HashMap = HashMap::new(); + for sym in &symbols { + match sym.section { + SectionKind::Text => { text_labels.insert(sym.address, sym.name.clone()); } + SectionKind::Data => { data_labels.insert(sym.address, sym.name.clone()); } + _ => {} + } + } + // symbols can refer to either section by full resolved address (per your + // v1 loader convention: data lives right after text), so a single combined + // map is actually what address-resolution needs — keep both, but merge + // for lookups against full 32-bit addresses. + let mut all_labels = text_labels.clone(); + all_labels.extend(data_labels.clone()); + + let text_lines = build_text_lines(&exe.text, &all_labels); + let data_lines = build_data_lines(&exe.data, &data_labels); + + Disassembly { symbols, text_lines, data_lines } +} + +fn build_symbol_lines(exe: &DseExecutable) -> Vec { + exe.symbols + .iter() + .map(|s| SymbolLine { + name: read_string(&exe.string_table, s.name_offset), + address: s.value, + section: SectionKind::from_raw(s.section), + binding: BindingKind::from_raw(s.binding), + }) + .collect() +} + +fn read_string(strtab: &[u8], offset: u32) -> String { + let start = offset as usize; + let end = strtab[start..].iter().position(|&b| b == 0).map(|p| start + p).unwrap_or(strtab.len()); + String::from_utf8_lossy(&strtab[start..end]).into_owned() +} + +/// Address a jump-like instruction actually targets, if statically known. +/// Returns None when the jump is register-relative (addr reg != Zero) since +/// that depends on runtime state and can't be resolved here. +fn static_jump_target(addr_reg: Register, imm: u16) -> Option { + (addr_reg == Register::Zero).then_some(imm as u32) +} + +fn build_text_lines(words: &[u32], labels: &HashMap) -> Vec { + let mut out = Vec::new(); + let mut i = 0; + + while i < words.len() { + let addr = 4 * i as u32; + if let Some(label) = labels.get(&addr) { + out.push(format!("{label}:")); + } + + let instr = Instruction(words[i]); + let opcode = Opcode::from_u8(instr.opcode()); + + // Collapse Lli+Lui address-load pairs back into `lwi` (or a full + // ldx/stx pseudo-op if a matching mem instruction follows), mirroring + // what expand_ldx/expand_stx/expand_lwi originally expanded from. + if let Some(Opcode::Lli) = opcode { + if let Some(collapsed) = try_collapse_addr_load(words, i, labels) { + out.push(format!(" {}", collapsed.text)); + i += collapsed.consumed; + continue; + } + } + + out.push(format!(" {}", render_instruction(instr, opcode, labels))); + i += 1; + } + + out +} + +struct Collapsed { + text: String, + consumed: usize, +} + +fn try_collapse_addr_load( + words: &[u32], + i: usize, + labels: &HashMap, +) -> Option { + let lli = Instruction(words[i]); + let lui = Instruction(*words.get(i + 1)?); + + if Opcode::from_u8(lui.opcode())? as u8 != Opcode::Lui as u8 { + return None; + } + if lui.dest_checked() != lli.dest_checked() { + return None; + } + + let dest = lli.dest_checked(); + let full_addr = (lli.imm16() as u32) | ((lui.imm16() as u32) << 16); + let addr_text = labels.get(&full_addr).cloned().unwrap_or_else(|| format!("{full_addr:#010x}")); + + // Check whether a mem op immediately follows, referencing `dest` — + // that's the ldb/ldh/ldw/stb/sth/stw expansion pattern, not a bare lwi. + if let Some(&mem_word) = words.get(i + 2) { + let mem = Instruction(mem_word); + if let Some(mem_op) = Opcode::from_u8(mem.opcode()) { + let is_mem_op = matches!( + mem_op, + Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw + | Opcode::Stb | Opcode::Sth | Opcode::Stw + ); + if is_mem_op && (mem.src1_checked() == dest || mem.dest_checked() == dest) { + let mnemonic = format!("{mem_op:?}").to_lowercase(); + let other = if mem.src1_checked() == dest { mem.dest_checked() } else { mem.src1_checked() }; + return Some(Collapsed { + text: format!("{mnemonic} {addr_text}, {other:?}, {:#06x}", mem.imm16()), + consumed: 3, + }); + } + } + } + + Some(Collapsed { + text: format!("lwi {addr_text}, {dest:?}"), + consumed: 2, + }) +} + +fn render_instruction(instr: Instruction, opcode: Option, labels: &HashMap) -> String { + let Some(op) = opcode else { + return format!("; INVALID OPCODE {:#04x} (word {:#010x})", instr.opcode(), instr.0); + }; + + let mnemonic = format!("{op:?}").to_lowercase(); + + match op { + Opcode::Nop | Opcode::Hlt | Opcode::Ret | Opcode::IRet => mnemonic, + + Opcode::Push => format!("{mnemonic} {:?}", instr.src1_checked()), + Opcode::Pop => format!("{mnemonic} {:?}", instr.dest_checked()), + + Opcode::Lli | Opcode::Lui => { + format!("{mnemonic} {:?}, {:#06x}", instr.dest_checked(), instr.imm16()) + } + + Opcode::Int => format!("{mnemonic} {:#06x}", instr.imm16()), + + Opcode::Ldb | Opcode::Ldbs | Opcode::Ldh | Opcode::Ldhs | Opcode::Ldw + | Opcode::Stb | Opcode::Sth | Opcode::Stw | Opcode::Addi | Opcode::Subi => format!( + "{mnemonic} {:?}, {:?}, {:#06x}", + instr.src1_checked(), instr.dest_checked(), instr.imm16() + ), + + Opcode::Jez | Opcode::Jnz => { + let addr_reg = instr.dest_checked(); + let target = static_jump_target(addr_reg, instr.imm16()) + .and_then(|a| labels.get(&a).cloned()); + match target { + Some(label) => format!("{mnemonic} {:?}, {label}", instr.src1_checked()), + None if addr_reg == Register::Zero => { + format!("{mnemonic} {:?}, {:#06x}", instr.src1_checked(), instr.imm16()) + } + None => format!( + "{mnemonic} {:?}, {:#06x}, {addr_reg:?}", + instr.src1_checked(), instr.imm16() + ), + } + } + + Opcode::Jmp | Opcode::Call | Opcode::Jic | Opcode::Jnc => { + let addr_reg = instr.dest_checked(); + let target = static_jump_target(addr_reg, instr.imm16()) + .and_then(|a| labels.get(&a).cloned()); + match target { + Some(label) => format!("{mnemonic} {label}"), + None if addr_reg == Register::Zero => format!("{mnemonic} {:#06x}", instr.imm16()), + None => format!("{mnemonic} {:#06x}, {addr_reg:?}", instr.imm16()), + } + } + + Opcode::Mov | Opcode::Not => { + format!("{mnemonic} {:?}, {:?}", instr.src1_checked(), instr.dest_checked()) + } + + Opcode::CMov => format!( + "{mnemonic} {:?}, {:?}, {:?}", + instr.src1_checked(), instr.dest_checked(), instr.src2_checked() + ), + + Opcode::Add | Opcode::Sub | Opcode::And | Opcode::Nand | Opcode::Or | Opcode::Nor + | Opcode::Xor | Opcode::Xnor | Opcode::Ieq | Opcode::Ine | Opcode::Ilt | Opcode::Ile + | Opcode::Igt | Opcode::Ige => format!( + "{mnemonic} {:?}, {:?}, {:?}", + instr.src1_checked(), instr.src2_checked(), instr.dest_checked() + ), + + Opcode::Shl | Opcode::Shr => format!( + "{mnemonic} {:?}, {:?}, {:?}, {}", + instr.src1_checked(), instr.dest_checked(), instr.src2_checked(), instr.shamt() + ), + } +} + +fn build_data_lines(data: &[u8], data_labels: &HashMap) -> Vec { + let mut out = Vec::new(); + let mut i = 0; + + while i < data.len() { + let addr = i as u32; + if let Some(label) = data_labels.get(&addr) { + out.push(format!("{label}:")); + } + + // Try string detection only when this byte could actually start one. + if data[i] != 0 { + if let Some(end) = data[i..].iter().position(|&b| b == 0) { + let slice = &data[i..i + end]; + if slice.iter().all(|&b| b.is_ascii_graphic() || b == b' ') { + out.push(format!(" db \"{}\"", String::from_utf8_lossy(slice).escape_default())); + i += end + 1; // skip the null terminator too + continue; + } + } + } + + // Not a string start: consume only the run of zero bytes here, + // grouped into 4-byte words, stopping the instant a non-zero byte + // appears so we never swallow the start of the next string/value. + let run_end = data[i..] + .iter() + .position(|&b| b != 0) + .map(|p| i + p) + .unwrap_or(data.len()); + + if run_end == i { + // data[i] is non-zero but didn't form a printable/terminated + // string (e.g. binary constant) — dump one raw word. + let mut buf = [0u8; 4]; + let take = (data.len() - i).min(4); + buf[..take].copy_from_slice(&data[i..i + take]); + out.push(format!(" dw {:#010x}", u32::from_le_bytes(buf))); + i += take; + } else { + let mut j = i; + while j < run_end { + let take = (run_end - j).min(4); + let mut buf = [0u8; 4]; + buf[..take].copy_from_slice(&data[j..j + take]); + out.push(format!(" dw {:#010x}", u32::from_le_bytes(buf))); + j += take; + } + i = j; + } + } + + out +} + +impl fmt::Display for SectionKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Data => write!(f, "DATA"), + Self::Text => write!(f, "TEXT"), + Self::Abs => write!(f, "ABS"), + Self::Undef => write!(f, "UNDEF"), + } + } +} + +impl fmt::Display for BindingKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Local => write!(f, "local"), + Self::Global => write!(f, "global"), + Self::Weak => write!(f, "weak"), + } + } +} + +impl fmt::Display for SymbolLine { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "; {:<24} {:#010x} {:<5} {}", + self.name, self.address, self.section, self.binding + ) + } +} + +impl fmt::Display for Disassembly { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "; ==== symbols ====")?; + for sym in &self.symbols { + writeln!(f, "{sym}")?; + } + + writeln!(f, "\n; ==== data ====")?; + for line in &self.data_lines { + writeln!(f, "{line}")?; + } + + writeln!(f, "\n; ==== text ====")?; + for line in &self.text_lines { + writeln!(f, "{line}")?; + } + + Ok(()) + } +} \ No newline at end of file diff --git a/dsa/disassembler/src/lib.rs b/dsa/disassembler/src/lib.rs new file mode 100644 index 0000000..bf72fc0 --- /dev/null +++ b/dsa/disassembler/src/lib.rs @@ -0,0 +1,15 @@ +mod internal; + +use std::fs; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +use std::collections::HashMap; +use common::formats::binary_dse::DseExecutable; +use common::isa::instructions::{Instruction, Opcode}; +use common::isa::register::Register; + +pub use internal::{ + disassemble, Disassembly, BindingKind, SectionKind, SymbolLine +}; diff --git a/dsa/disassembler/src/main.rs b/dsa/disassembler/src/main.rs new file mode 100644 index 0000000..a526d13 --- /dev/null +++ b/dsa/disassembler/src/main.rs @@ -0,0 +1,27 @@ +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use clap::Parser; +use disassembler::disassemble; +use common::formats::binary_dse::DseExecutable; + +#[derive(Parser, Debug, Clone)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short = 'i')] + pub input_path: PathBuf, + #[arg(short = 'o')] + pub output_path: PathBuf, +} + +fn main() { + let args = Args::parse(); + + let Ok(exec) = DseExecutable::load(args.input_path) else { + panic!("Failed to load the input file") + }; + + let result = disassemble(&exec); + File::create(args.output_path).unwrap() + .write(result.to_string().as_bytes()).unwrap(); +} diff --git a/dsa/emulator/backend/Cargo.toml b/dsa/emulator/emulator_core/Cargo.toml similarity index 85% rename from dsa/emulator/backend/Cargo.toml rename to dsa/emulator/emulator_core/Cargo.toml index a19d96d..f701668 100644 --- a/dsa/emulator/backend/Cargo.toml +++ b/dsa/emulator/emulator_core/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "emu_core" +name = "emulator_core" edition.workspace = true version.workspace = true authors.workspace = true [lib] -name = "emu_core" +name = "emulator_core" path = "src/lib.rs" [dependencies] diff --git a/dsa/emulator/backend/src/config/default/dsa.iomap.ron b/dsa/emulator/emulator_core/src/config/default/dsa.iomap.ron similarity index 100% rename from dsa/emulator/backend/src/config/default/dsa.iomap.ron rename to dsa/emulator/emulator_core/src/config/default/dsa.iomap.ron diff --git a/dsa/emulator/backend/src/config/default/dsa.mmap.ron b/dsa/emulator/emulator_core/src/config/default/dsa.mmap.ron similarity index 100% rename from dsa/emulator/backend/src/config/default/dsa.mmap.ron rename to dsa/emulator/emulator_core/src/config/default/dsa.mmap.ron diff --git a/dsa/emulator/backend/src/config/default/mod.rs b/dsa/emulator/emulator_core/src/config/default/mod.rs similarity index 100% rename from dsa/emulator/backend/src/config/default/mod.rs rename to dsa/emulator/emulator_core/src/config/default/mod.rs diff --git a/dsa/emulator/backend/src/config/mod.rs b/dsa/emulator/emulator_core/src/config/mod.rs similarity index 100% rename from dsa/emulator/backend/src/config/mod.rs rename to dsa/emulator/emulator_core/src/config/mod.rs diff --git a/dsa/emulator/backend/src/lib.rs b/dsa/emulator/emulator_core/src/lib.rs similarity index 100% rename from dsa/emulator/backend/src/lib.rs rename to dsa/emulator/emulator_core/src/lib.rs diff --git a/dsa/emulator/backend/src/memory/cache.rs b/dsa/emulator/emulator_core/src/memory/cache.rs similarity index 100% rename from dsa/emulator/backend/src/memory/cache.rs rename to dsa/emulator/emulator_core/src/memory/cache.rs diff --git a/dsa/emulator/backend/src/memory/mmu.rs b/dsa/emulator/emulator_core/src/memory/mmu.rs similarity index 100% rename from dsa/emulator/backend/src/memory/mmu.rs rename to dsa/emulator/emulator_core/src/memory/mmu.rs diff --git a/dsa/emulator/backend/src/memory/mod.rs b/dsa/emulator/emulator_core/src/memory/mod.rs similarity index 100% rename from dsa/emulator/backend/src/memory/mod.rs rename to dsa/emulator/emulator_core/src/memory/mod.rs diff --git a/dsa/emulator/backend/src/memory/ram.rs b/dsa/emulator/emulator_core/src/memory/ram.rs similarity index 100% rename from dsa/emulator/backend/src/memory/ram.rs rename to dsa/emulator/emulator_core/src/memory/ram.rs diff --git a/dsa/emulator/backend/src/memory/tlb.rs b/dsa/emulator/emulator_core/src/memory/tlb.rs similarity index 100% rename from dsa/emulator/backend/src/memory/tlb.rs rename to dsa/emulator/emulator_core/src/memory/tlb.rs diff --git a/dsa/emulator/backend/src/processor/interrupts.rs b/dsa/emulator/emulator_core/src/processor/interrupts.rs similarity index 100% rename from dsa/emulator/backend/src/processor/interrupts.rs rename to dsa/emulator/emulator_core/src/processor/interrupts.rs diff --git a/dsa/emulator/backend/src/processor/mod.rs b/dsa/emulator/emulator_core/src/processor/mod.rs similarity index 100% rename from dsa/emulator/backend/src/processor/mod.rs rename to dsa/emulator/emulator_core/src/processor/mod.rs diff --git a/dsa/emulator/backend/src/processor/processor.rs b/dsa/emulator/emulator_core/src/processor/processor.rs similarity index 98% rename from dsa/emulator/backend/src/processor/processor.rs rename to dsa/emulator/emulator_core/src/processor/processor.rs index f2c75b5..5ae070e 100644 --- a/dsa/emulator/backend/src/processor/processor.rs +++ b/dsa/emulator/emulator_core/src/processor/processor.rs @@ -164,6 +164,11 @@ impl Emulator { self.update(); } + if let x = self.shared_state.goto.load(Ordering::Relaxed) && x != -1 { + *self.mut_reg(Register::Pcx) = x as u32; + self.shared_state.goto.store(-1, Ordering::Relaxed); + } + if self.shared_state.reseting.load(Ordering::Relaxed) { self.internal_state.registers = [0; Register::COUNT as usize]; self.internal_state.clock = 0; diff --git a/dsa/emulator/backend/src/processor/state.rs b/dsa/emulator/emulator_core/src/processor/state.rs similarity index 87% rename from dsa/emulator/backend/src/processor/state.rs rename to dsa/emulator/emulator_core/src/processor/state.rs index 839a15e..0cb4165 100644 --- a/dsa/emulator/backend/src/processor/state.rs +++ b/dsa/emulator/emulator_core/src/processor/state.rs @@ -1,5 +1,5 @@ use std::sync::{Arc, atomic::AtomicBool, mpsc}; - +use std::sync::atomic::AtomicIsize; use arc_swap::ArcSwap; use crate::processor::processor::ProcessorSnapshot; @@ -9,6 +9,7 @@ use super::interrupts::Interrupt; pub struct SharedState { pub proc: ArcSwap, + pub goto: AtomicIsize, pub reseting: AtomicBool, pub paused: AtomicBool, pub update_req: AtomicBool, @@ -21,6 +22,7 @@ impl SharedState { reseting: AtomicBool::new(false), proc: ArcSwap::new(Arc::new(ProcessorSnapshot::default())), + goto: AtomicIsize::new(-1), paused: AtomicBool::new(true), interrupt_queue: sender, update_req: AtomicBool::new(false), diff --git a/dsa/emulator/frontend/Cargo.toml b/dsa/emulator/emulator_ui/Cargo.toml similarity index 74% rename from dsa/emulator/frontend/Cargo.toml rename to dsa/emulator/emulator_ui/Cargo.toml index 7bbcac8..1c5c75d 100644 --- a/dsa/emulator/frontend/Cargo.toml +++ b/dsa/emulator/emulator_ui/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "emulator" +name = "emulator_ui" version = "0.3.0" edition.workspace = true authors.workspace = true @@ -13,7 +13,7 @@ name = "dsa" path = "src/lib.rs" [dev-dependencies] -criterion = { version = "0.5.0", features = ["html_reports"] } +criterion = { version = "0.8.2", features = ["html_reports"] } [dependencies] arc-swap = "1.8.2" @@ -23,15 +23,15 @@ ron = "0.12.0" serde = { version = "1.0.228", features = ["derive"] } common = { path = "../../common" } -egui = "0.33.3" -eframe = "0.33.3" -egui_tiles = "0.14.1" -egui_code_editor = "0.2.21" -egui_file = "0.25.0" +egui = "0.35.0" +eframe = "0.35.0" +egui_tiles = "0.16.0" +egui_code_editor = "0.3.7" +egui_file = "0.27.0" dirs = "6.0.0" assembler = { path = "../../assembler" } -egui_extras = "0.33.3" -emu_core = { version = "0.3.0", path = "../backend" } +egui_extras = "0.35.0" +emulator_core = { version = "0.3.0", path = "../emulator_core" } [features] default = ["mainstore-prealloc"] diff --git a/dsa/emulator/frontend/font/JetBrainsMonoNerdFontMono_Regular.ttf b/dsa/emulator/emulator_ui/font/JetBrainsMonoNerdFontMono_Regular.ttf similarity index 100% rename from dsa/emulator/frontend/font/JetBrainsMonoNerdFontMono_Regular.ttf rename to dsa/emulator/emulator_ui/font/JetBrainsMonoNerdFontMono_Regular.ttf diff --git a/dsa/emulator/frontend/src/args.rs b/dsa/emulator/emulator_ui/src/args.rs similarity index 95% rename from dsa/emulator/frontend/src/args.rs rename to dsa/emulator/emulator_ui/src/args.rs index a1f3f41..5fe0124 100644 --- a/dsa/emulator/frontend/src/args.rs +++ b/dsa/emulator/emulator_ui/src/args.rs @@ -2,7 +2,7 @@ use std::{fs, path::PathBuf}; use clap::Parser; -use emu_core::config::{IoMap, IoMapping, MemoryMap}; +use emulator_core::config::{IoMap, IoMapping, MemoryMap}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] diff --git a/dsa/emulator/frontend/src/lib.rs b/dsa/emulator/emulator_ui/src/lib.rs similarity index 100% rename from dsa/emulator/frontend/src/lib.rs rename to dsa/emulator/emulator_ui/src/lib.rs diff --git a/dsa/emulator/frontend/src/main.rs b/dsa/emulator/emulator_ui/src/main.rs similarity index 95% rename from dsa/emulator/frontend/src/main.rs rename to dsa/emulator/emulator_ui/src/main.rs index fec9a96..58184f1 100644 --- a/dsa/emulator/frontend/src/main.rs +++ b/dsa/emulator/emulator_ui/src/main.rs @@ -4,8 +4,10 @@ use common::prelude::Instruction; use std::thread; use dsa::args::DsaArgs; use dsa::ui::run_app; -use emu_core::memory::ram::Page; -use emu_core::processor::processor::Emulator; +use emulator_core::{ + memory::ram::Page, + processor::processor::Emulator +}; const STACK_SIZE: usize = 1024 * 1024 * 16; diff --git a/dsa/emulator/frontend/src/ui/components/controller.rs b/dsa/emulator/emulator_ui/src/ui/components/controller.rs similarity index 95% rename from dsa/emulator/frontend/src/ui/components/controller.rs rename to dsa/emulator/emulator_ui/src/ui/components/controller.rs index 4a17b3e..0a9ba63 100644 --- a/dsa/emulator/frontend/src/ui/components/controller.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/controller.rs @@ -2,8 +2,10 @@ use std::sync::{Arc, atomic::Ordering}; use super::Component; use common::prelude::Register; -use emu_core::memory::ram::MemoryBank; -use emu_core::processor::state::SharedState; +use emulator_core::{ + memory::ram::MemoryBank, + processor::state::SharedState +}; pub struct Controller { state: Arc, @@ -30,7 +32,7 @@ impl Component for Controller { &mut self.visible } - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) { + fn ui(&mut self, ui: &mut egui::Ui) { let state = self.state.proc.load(); let paused = self.state.paused.load(Ordering::Relaxed); diff --git a/dsa/emulator/frontend/src/ui/components/display.rs b/dsa/emulator/emulator_ui/src/ui/components/display.rs similarity index 95% rename from dsa/emulator/frontend/src/ui/components/display.rs rename to dsa/emulator/emulator_ui/src/ui/components/display.rs index d303c95..e9360eb 100644 --- a/dsa/emulator/frontend/src/ui/components/display.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/display.rs @@ -1,6 +1,8 @@ use egui::{Color32, FontId, Vec2}; -use emu_core::memory::PhysAddr; -use emu_core::memory::ram::{MemoryBank, Page}; +use emulator_core::{ + memory::PhysAddr, + memory::ram::{MemoryBank, Page} +}; use super::Component; pub struct Display { @@ -72,7 +74,7 @@ impl Component for Display { self.visible() } - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) { + fn ui(&mut self, ui: &mut egui::Ui) { let display_w = self.width(); let display_h = self.height(); let data = self.read(); diff --git a/dsa/emulator/frontend/src/ui/components/editor/mod.rs b/dsa/emulator/emulator_ui/src/ui/components/editor/mod.rs similarity index 75% rename from dsa/emulator/frontend/src/ui/components/editor/mod.rs rename to dsa/emulator/emulator_ui/src/ui/components/editor/mod.rs index db5e7e4..e5da6cd 100644 --- a/dsa/emulator/frontend/src/ui/components/editor/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/editor/mod.rs @@ -1,7 +1,8 @@ use std::fmt::Write; -use std::fs::{self, File}; -use std::sync::Arc; +use std::fs::{self}; +use std::io::Cursor; use std::sync::atomic::Ordering; +use std::sync::Arc; use std::{ ffi::OsStr, path::{Path, PathBuf}, @@ -9,15 +10,18 @@ use std::{ pub mod syntax; +use super::Component; use assembler::prelude::Assembler; +use common::formats::binary_dse::DseExecutable; use common::prelude::Instruction; use egui::{Align, Context, Key, Layout, Ui}; use egui_code_editor::{CodeEditor, ColorTheme, Completer, Syntax}; use egui_extras::{Column, TableBuilder}; use egui_file::FileDialog; -use emu_core::memory::ram::{MemoryBank, Page}; -use emu_core::processor::state::SharedState; -use super::Component; +use emulator_core::{ + memory::ram::{MemoryBank, Page}, + processor::state::SharedState +}; pub struct Editor { state: Arc, @@ -32,16 +36,13 @@ pub struct Editor { // editor widget editor: CodeEditor, completer: Completer, + syntax: Syntax, // output / loading output: Output, load_offset: u32, offset_str: String, - // cursor - currently unused - cursor_col: usize, - cursor_line: usize, - // file dialogs open_file_dialog: Option, save_file_dialog: Option, @@ -61,7 +62,7 @@ impl Component for Editor { &mut self.visible } - fn ui(&mut self, ui: &mut Ui, ctx: &Context) { + fn ui(&mut self, ui: &mut Ui) { if self.buffer != self.text { self.unsaved = true; } @@ -73,7 +74,7 @@ impl Component for Editor { self.save(); } - self.render_toolbar(ui, ctx); + self.render_toolbar(ui); ui.add_space(4.0); // Add some spacing instead of just a separator ui.separator(); @@ -85,15 +86,15 @@ impl Component for Editor { Layout::left_to_right(Align::Min), |ui| { if self.show_output { - egui::SidePanel::right("Editor Output").resizable(false).show_inside(ui, |ui| { - self.output.ui(ui, ctx); + egui::Panel::right("Editor Output").resizable(false).show_inside(ui, |ui| { + self.output.ui(ui); }); } - self.render_editor(ui, ctx); + self.render_editor(ui); }, ); - self.render_bottom_bar(ui, ctx); + self.render_bottom_bar(ui); }); } } @@ -108,17 +109,15 @@ impl Editor { text: String::new(), buffer: String::new(), completer: Completer::new_with_syntax(&Syntax::default()).with_user_words(), + syntax: Syntax::default(), editor: CodeEditor::default() .id_source("editor") .with_fontsize(12.0) .with_rows(0) .with_theme(THEME) - .with_syntax(Syntax::default()) .with_numlines(true), output: Output::new(), unsaved: true, - cursor_col: 1, - cursor_line: 1, visible: false, load_offset: 0, offset_str: String::new(), @@ -226,21 +225,20 @@ impl Editor { self.open_file_dialog = Some(dialog); } - let syntax = match self.extension() { + self.syntax = match self.extension() { "dsa" => syntax::dsa(), "dsc" => syntax::dsc(), "rs" => Syntax::rust(), _ => Syntax::default(), }; - self.completer = Completer::new_with_syntax(&syntax).with_user_words(); - self.editor = self.editor.clone().with_syntax(syntax); + self.completer = Completer::new_with_syntax(&self.syntax).with_user_words(); } - fn handle_file_dialogs(&mut self, ctx: &egui::Context) { + fn handle_file_dialogs(&mut self, ui: &Ui) { // Handle open dialog if let Some(dialog) = &mut self.open_file_dialog - && dialog.show(ctx).selected() + && dialog.show(ui).selected() { if let Some(file) = dialog.path() { // check if the file is a binary file @@ -284,7 +282,7 @@ impl Editor { // Handle save dialog if let Some(dialog) = &mut self.save_file_dialog - && dialog.show(ctx).selected() + && dialog.show(ui).selected() { if let Some(file) = dialog.path() { self.buffer = self.text.clone(); @@ -324,24 +322,19 @@ impl Editor { } } - fn render_editor(&mut self, ui: &mut Ui, _ctx: &Context) { + fn render_editor(&mut self, ui: &mut Ui) { let available_width = ui.available_width(); let mut editor = self.editor.clone().desired_width(available_width); - editor.show_with_completer(ui, &mut self.text, &mut self.completer); + editor.show_with_completer(ui, &mut self.text, &self.syntax, &mut self.completer); } - fn render_bottom_bar(&self, ui: &mut Ui, _ctx: &Context) { + fn render_bottom_bar(&self, ui: &mut Ui) { ui.horizontal(|ui| { // error display ui.label( egui::RichText::new(self.error.clone().unwrap_or_default()) .color(egui::Color32::RED), ); - - // line and col - ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { - ui.label(format!("Ln {}, Col {}", self.cursor_line, self.cursor_col)); - }); }); } @@ -399,8 +392,8 @@ impl Editor { } } - fn render_toolbar(&mut self, ui: &mut Ui, ctx: &Context) { - self.handle_file_dialogs(ctx); + fn render_toolbar(&mut self, ui: &mut Ui) { + self.handle_file_dialogs(ui); ui.horizontal(|ui| { ui.label(format!("File type: {}", self.extension())); @@ -443,13 +436,21 @@ impl Editor { self.error = Some("Can't load program at invalid offset!".to_string()); } - let program: Vec = Page::paginate(self.output.data()).collect(); + let mut reader = Cursor::new(self.output.data().clone()); + let Ok(executable) = DseExecutable::read(&mut reader) else { + self.error = Some("Failed to read program!".to_string()); + return + }; + + let image: Vec = Page::paginate(&executable.to_memory_image()).collect(); self.state.reseting.store(true, Ordering::Relaxed); + self.memory.clear(); - for (i, page) in program.iter().enumerate() { + for (i, page) in image.iter().enumerate() { self.memory.write_page(i as u32 * 4096, &page); } + self.state.goto.store(executable.entry_point(0) as isize, Ordering::Relaxed); self.state.reseting.store(false, Ordering::Relaxed); } @@ -463,7 +464,7 @@ impl Editor { } } - ui.checkbox(&mut self.show_output, "Show Output") + ui.checkbox(&mut self.show_output, "Show Output"); }); } } @@ -488,18 +489,18 @@ fn parse_address(address: &str) -> Option { pub const THEME: ColorTheme = ColorTheme { name: "Theme", dark: true, - bg: "#1b1b1b", - cursor: "#de5252", // fg4 - selection: "#28323B", // bg2 - comments: "#444444", // gray1 - functions: "#7CCCC7", // green1 - keywords: "#6C81E0", // red1 - literals: "#A3ABFF", // fg1 - numerics: "#8A46CF", // purple1 - punctuation: "#99C9C9", // orange1 - strs: "#618c84", // aqua1 - types: "#B8B9D4", // yellow1 - special: "#de5252", // blue1 + bg: "1b1b1b", + cursor: "de5252", // fg4 + selection: "28323B", // bg2 + comments: "444444", // gray1 + functions: "7CCCC7", // green1 + keywords: "6C81E0", // red1 + literals: "A3ABFF", // fg1 + numerics: "8A46CF", // purple1 + punctuation: "99C9C9", // orange1 + strs: "618c84", // aqua1 + types: "B8B9D4", // yellow1 + special: "de5252", // blue1 }; struct Output { @@ -532,7 +533,7 @@ impl Output { &self.data } - fn ui(&mut self, ui: &mut Ui, _ctx: &Context) { + fn ui(&mut self, ui: &mut Ui) { // Output area with synchronized scrolling egui::ScrollArea::vertical() .id_salt("output_scroll") @@ -613,8 +614,9 @@ impl Output { for (line_num, chunk) in self.data.chunks(4).enumerate() { body.row(18.0, |mut row| { let address = line_num * 4; - - let value = u32::from_le_bytes(*chunk.as_array().unwrap()); + let mut buf = [0u8; 4]; + buf[..chunk.len()].copy_from_slice(chunk); + let value = u32::from_le_bytes(buf); // Address column row.col(|ui| { @@ -688,111 +690,6 @@ impl Output { }) } }); - - // egui::Grid::new("output_grid") - // .spacing([5.0, 2.0]) // Horizontal and vertical spacing - // .num_columns(4) - // .striped(false) - // .show(ui, |ui| { - // ui.label("Address"); - - // if self.show_bytes { - // ui.label("Bytes"); - // } - // if self.show_words { - // ui.label("Word"); - // } - // if self.show_decimal { - // ui.label("Decimal"); - // } - // if self.show_ascii { - // ui.label("Ascii"); - // } - // if self.show_instruction { - // ui.label("Hex"); - // } - // ui.end_row(); - - // // Process bytes in chunks of 4 - // for (line_num, chunk) in self.data.chunks(4).enumerate() { - // let address = line_num * 4; - - // // Convert chunk to u32 (little-endian) - // let mut bytes = [0u8; 4]; - // for (i, &byte) in chunk.iter().enumerate() { - // if i < 4 { - // bytes[i] = byte; - // } - // } - // let value = u32::from_le_bytes(bytes); - - // // Address column - // ui.with_layout( - // egui::Layout::left_to_right(egui::Align::Center), - // |ui| { - // ui.set_min_width(80.0); - // let style = ui.style_mut(); - // style.visuals.widgets.inactive.bg_fill = - // egui::Color32::from_gray(30); - // ui.label( - // egui::RichText::new(format!("0x{address:04X}")) - // .font(egui::FontId::monospace(12.0)), - // ); - // }, - // ); - - // // Individual bytes column - // let byte_str = chunk - // .iter() - // .map(|b| format!("{b:02X}")) - // .collect::>() - // .join(" "); - - // if self.show_bytes { - // ui.label( - // egui::RichText::new(format!("{byte_str:<11}")) - // .font(egui::FontId::monospace(12.0)) - // .color(egui::Color32::from_rgb(200, 200, 255)), - // ); - // } - - // if self.show_words { - // // Hex column - // ui.label( - // egui::RichText::new(format!("0x{value:08X}")) - // .font(egui::FontId::monospace(12.0)) - // .color(egui::Color32::from_rgb(255, 100, 100)), - // ); - // } - - // if self.show_decimal { - // ui.label( - // egui::RichText::new(format!("{value}")) - // .font(egui::FontId::monospace(12.0)) - // .color(egui::Color32::from_rgb(100, 255, 100)), - // ); - // } - - // if self.show_ascii { - // let ascii = value.to_le_bytes(); - // ui.label( - // egui::RichText::new(String::from_utf8_lossy(&ascii)) - // .font(egui::FontId::monospace(12.0)) - // .color(egui::Color32::from_rgb(100, 255, 255)), - // ); - // } - - // if self.show_instruction { - // ui.label( - // egui::RichText::new(format!("{:?}", Instruction(value))) - // .font(egui::FontId::monospace(12.0)) - // .color(egui::Color32::from_rgb(255, 100, 255)), - // ); - // } - - // ui.end_row(); - // } - // }); }); } } diff --git a/dsa/emulator/frontend/src/ui/components/editor/syntax/mod.rs b/dsa/emulator/emulator_ui/src/ui/components/editor/syntax/mod.rs similarity index 91% rename from dsa/emulator/frontend/src/ui/components/editor/syntax/mod.rs rename to dsa/emulator/emulator_ui/src/ui/components/editor/syntax/mod.rs index e388fd7..8583a7a 100644 --- a/dsa/emulator/frontend/src/ui/components/editor/syntax/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/editor/syntax/mod.rs @@ -1,9 +1,10 @@ use std::collections::BTreeSet; -use egui_code_editor::Syntax; +use egui_code_editor::{Patch, Syntax}; pub fn dsa() -> Syntax { Syntax { + word_start: BTreeSet::new(), quotes: BTreeSet::from(['"', '\'']), language: "Assembly", case_sensitive: false, @@ -22,11 +23,13 @@ pub fn dsa() -> Syntax { "RGC", "RGD", "RGE", "RGF", "ACC", "SPR", "BPR", "IDR", "MMR", "ZERO", "PCX", "STS", "CIR", ]), + patch: Patch::default(), } } pub fn dsc() -> Syntax { Syntax { + word_start: BTreeSet::from(['_']), quotes: BTreeSet::from(['"', '\'', '`']), language: "Damn Simple Code", case_sensitive: false, @@ -44,5 +47,6 @@ pub fn dsc() -> Syntax { ",", ";", ".", ":", "=", "+", "-", "*", "/", "%", "&", "|", "^", "~", "!", "?", "<", ">", "<<", ">>", "==", "!=", "<=", ">=", "&&", "||", ]), + patch: Patch::default(), } } diff --git a/dsa/emulator/frontend/src/ui/components/framebuffer.rs b/dsa/emulator/emulator_ui/src/ui/components/framebuffer.rs similarity index 95% rename from dsa/emulator/frontend/src/ui/components/framebuffer.rs rename to dsa/emulator/emulator_ui/src/ui/components/framebuffer.rs index c916a91..2536a02 100644 --- a/dsa/emulator/frontend/src/ui/components/framebuffer.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/framebuffer.rs @@ -1,6 +1,8 @@ use egui::Vec2; -use emu_core::memory::PhysAddr; -use emu_core::memory::ram::{MemoryBank, Page}; +use emulator_core::{ + memory::PhysAddr, + memory::ram::{MemoryBank, Page} +}; use super::Component; pub struct FrameBuffer { @@ -86,12 +88,12 @@ impl Component for FrameBuffer { &mut self.visible } - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) { + fn ui(&mut self, ui: &mut egui::Ui) { let changed = self.changed(); // get or create the texture let texture = self.texture.get_or_insert_with(|| { - ctx.load_texture( + ui.load_texture( "framebuffer", egui::ColorImage { size: [self.width, self.height], diff --git a/dsa/emulator/emulator_ui/src/ui/components/memory.rs b/dsa/emulator/emulator_ui/src/ui/components/memory.rs new file mode 100644 index 0000000..612cc29 --- /dev/null +++ b/dsa/emulator/emulator_ui/src/ui/components/memory.rs @@ -0,0 +1,264 @@ +use std::num::ParseIntError; +use egui_extras::{Column, TableBuilder}; +use common::prelude::Instruction; +use emulator_core::memory::ram::MemoryBank; +use super::Component; + +pub struct MemoryInspector { + memory: MemoryBank, + + view_size: u32, + view_addr: u32, + visible: bool, + addr_input: String, + + // settings + show_bytes: bool, + show_words: bool, + show_ascii: bool, + show_instruction: bool, + show_decimal: bool, +} + +impl MemoryInspector { + #[must_use] + pub fn new(memory: MemoryBank) -> Self { + Self { + memory, + view_size: 1024, + view_addr: 0, + visible: false, + addr_input: String::from("0x00"), + + show_bytes: true, + show_words: true, + show_ascii: true, + show_instruction: true, + show_decimal: true, + } + } +} + +impl Component for MemoryInspector { + fn title(&self) -> &'static str { + "Memory Inspector" + } + + fn visible(&mut self) -> &mut bool { + &mut self.visible + } + + fn ui(&mut self, ui: &mut egui::Ui) { + // Right column - Memory + // ui.vertical(|ui| { + // ui.add_space(10.0); + // }); + // Memory table + + egui::ScrollArea::vertical() + .auto_shrink([false; 2]) + .id_salt("memory_inspector_scroll") + .show(ui, |ui| { + + // ui.heading("Memory Inspector"); + // ui.add_space(10.0); + // + // // Address input section + ui.horizontal(|ui| { + ui.label("Address:"); + + let address_response = ui.add( + egui::TextEdit::singleline(&mut self.addr_input) + .hint_text("0x1000 or 4096") + .desired_width(150.0), + ); + + ui.add_space(10.0); + + // Search button + let search_clicked = ui.button("🔍 Search").clicked(); + + // Handle Enter key in text field + let enter_pressed = + address_response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)); + + if search_clicked || enter_pressed { + if let Ok(new) = parse_address(&self.addr_input) { + if new % 4 == 0 { + self.view_addr = new; + } else { + println!("Address must be 4-byte aligned"); + } + } else { + println!("Invalid address"); + // state.error_log.push("Invalid address".to_string()); + } + } + + ui.label("(hex or decimal)"); + }); + + + ui.horizontal(|ui| { + ui.toggle_value(&mut self.show_bytes, "Bytes"); + ui.toggle_value(&mut self.show_words, "Words"); + ui.toggle_value(&mut self.show_decimal, "Decimal"); + ui.toggle_value(&mut self.show_ascii, "Ascii"); + ui.toggle_value(&mut self.show_instruction, "Instructions"); + }); + + ui.separator(); + + let mut table = TableBuilder::new(ui) + .resizable(false) // makes all columns resizable at once + .column(Column::initial(75.0)); // addr + + if self.show_bytes { + table = table.column(Column::initial(90.0)); + } + if self.show_words { + table = table.column(Column::initial(75.0)); + } + if self.show_decimal { + table = table.column(Column::initial(80.0)); + } + if self.show_ascii { + table = table.column(Column::initial(50.0)); + } + if self.show_instruction { + table = table.column(Column::initial(200.0).clip(true)); + } + + table + .header(20.0, |mut header| { + header.col(|ui| { + ui.label("Addr"); + }); + if self.show_bytes { + header.col(|ui| { + ui.label("Bytes"); + }); + } + if self.show_words { + header.col(|ui| { + ui.label("Word"); + }); + } + if self.show_decimal { + header.col(|ui| { + ui.label("Decimal"); + }); + } + if self.show_ascii { + header.col(|ui| { + ui.label("Ascii"); + }); + } + if self.show_instruction { + header.col(|ui| { + ui.label("Instruction"); + }); + } + }) + .body(|mut body| { + // Process bytes in chunks of 4 + for (line_num, value) in (0..self.view_size / 4) + .map(|i| (i, self.memory.read_word(self.view_addr + i * 4))) { + body.row(18.0, |mut row| { + let address = line_num * 4 * self.view_addr; + + let chunk = value.to_le_bytes(); + + // Address column + row.col(|ui| { + ui.label( + egui::RichText::new(format!("0x{address:08X}")) + .font(egui::FontId::monospace(12.0)), + ); + }); + + if self.show_bytes { + row.col(|ui| { + // Individual bytes column + ui.label( + egui::RichText::new( + chunk + .iter() + .map(|b| format!("{b:02X}")) + .collect::>() + .join(" "), + ) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(200, 200, 255)), + ); + }); + } + + if self.show_words { + row.col(|ui| { + // Hex column + ui.label( + egui::RichText::new(format!("0x{value:08X}")) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(255, 100, 100)), + ); + }); + } + + if self.show_decimal { + row.col(|ui| { + ui.label( + egui::RichText::new(format!("{value}")) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(100, 255, 100)), + ); + }); + } + + if self.show_ascii { + let ascii = value.to_le_bytes(); + row.col(|ui| { + ui.label( + egui::RichText::new(String::from_utf8_lossy(&ascii)) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(100, 255, 255)), + ); + }); + } + + if self.show_instruction { + row.col(|ui| { + ui.label( + egui::RichText::new(format!( + "{:?}", + Instruction(value) + )) + .font(egui::FontId::monospace(12.0)) + .color(egui::Color32::from_rgb(255, 100, 255)), + ); + }); + } + }) + } + }); + }); + + } +} + +fn parse_address(address: &str) -> Result { + if let Some(hex_part) = address.strip_prefix("0x") { + return u32::from_str_radix(hex_part, 16); + } + + if let Some(bin_part) = address.strip_prefix("0b") { + return u32::from_str_radix(bin_part, 2); + } + + if let Some(oct_part) = address.strip_prefix("0o") { + return u32::from_str_radix(oct_part, 8); + } + + address.parse::() +} + diff --git a/dsa/emulator/frontend/src/ui/components/mod.rs b/dsa/emulator/emulator_ui/src/ui/components/mod.rs similarity index 84% rename from dsa/emulator/frontend/src/ui/components/mod.rs rename to dsa/emulator/emulator_ui/src/ui/components/mod.rs index 68ca1b2..a5b6c95 100644 --- a/dsa/emulator/frontend/src/ui/components/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/mod.rs @@ -13,5 +13,5 @@ pub trait Component { fn visible(&mut self) -> &mut bool; /// Draw the component's UI inside the provided `Ui`. - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context); + fn ui(&mut self, ui: &mut egui::Ui); } diff --git a/dsa/emulator/frontend/src/ui/components/registers.rs b/dsa/emulator/emulator_ui/src/ui/components/registers.rs similarity index 92% rename from dsa/emulator/frontend/src/ui/components/registers.rs rename to dsa/emulator/emulator_ui/src/ui/components/registers.rs index fe71745..067606e 100644 --- a/dsa/emulator/frontend/src/ui/components/registers.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/registers.rs @@ -1,7 +1,7 @@ use std::{f32, sync::Arc}; use common::prelude::Register; -use emu_core::processor::state::SharedState; +use emulator_core::processor::state::SharedState; use super::Component; @@ -14,7 +14,6 @@ impl Registers { fn section( &mut self, ui: &mut egui::Ui, - ctx: &egui::Context, registers: Vec<(Register, u32)>, col_pairs: usize, name: &str, @@ -67,7 +66,7 @@ impl Component for Registers { &mut self.visible } - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) { + fn ui(&mut self, ui: &mut egui::Ui) { ui.set_min_width(200.0); let state = self.state.proc.load(); @@ -87,7 +86,6 @@ impl Component for Registers { .collect(); self.section( ui, - ctx, gp_registers, col_pairs, "General Purpose Registers", @@ -99,7 +97,7 @@ impl Component for Registers { (Register::Spr, state.registers[Register::Spr as usize]), (Register::Bpr, state.registers[Register::Bpr as usize]), ]; - self.section(ui, ctx, stack_registers, col_pairs, "Stack Registers"); + self.section(ui, stack_registers, col_pairs, "Stack Registers"); ui.separator(); // ── Special Purpose ─────────────────────────────────────── @@ -111,7 +109,6 @@ impl Component for Registers { ]; self.section( ui, - ctx, special_registers, col_pairs, "Special Purpose Registers", @@ -124,7 +121,7 @@ impl Component for Registers { (Register::Sts, state.registers[Register::Sts as usize]), (Register::Cir, state.registers[Register::Cir as usize]), ]; - self.section(ui, ctx, system_registers, col_pairs, "System Registers"); + self.section(ui, system_registers, col_pairs, "System Registers"); }); } } diff --git a/dsa/emulator/frontend/src/ui/components/serial.rs b/dsa/emulator/emulator_ui/src/ui/components/serial.rs similarity index 93% rename from dsa/emulator/frontend/src/ui/components/serial.rs rename to dsa/emulator/emulator_ui/src/ui/components/serial.rs index 6bffda7..f383b6b 100644 --- a/dsa/emulator/frontend/src/ui/components/serial.rs +++ b/dsa/emulator/emulator_ui/src/ui/components/serial.rs @@ -6,10 +6,16 @@ use std::{ mpsc::{Receiver, Sender}, }, }; -use emu_core::memory::PhysAddr; -use emu_core::memory::ram::MemoryBank; -use emu_core::processor::interrupts::Interrupt; -use emu_core::processor::state::SharedState; +use emulator_core::{ + memory::{ + PhysAddr, + ram::MemoryBank + }, + processor::{ + interrupts::Interrupt, + state::SharedState + } +}; use super::Component; /// ## SERIAL LAYOUT: (from the perspective of code inside the ui) @@ -100,7 +106,7 @@ impl Component for Serial { &mut self.visible } - fn ui(&mut self, ui: &mut egui::Ui, _ctx: &egui::Context) { + fn ui(&mut self, ui: &mut egui::Ui) { self.update(); // Text field for input and a send button diff --git a/dsa/emulator/frontend/src/ui/mod.rs b/dsa/emulator/emulator_ui/src/ui/mod.rs similarity index 90% rename from dsa/emulator/frontend/src/ui/mod.rs rename to dsa/emulator/emulator_ui/src/ui/mod.rs index b898655..aae8e8d 100644 --- a/dsa/emulator/frontend/src/ui/mod.rs +++ b/dsa/emulator/emulator_ui/src/ui/mod.rs @@ -8,9 +8,11 @@ use components::{ controller::Controller, display::Display, editor::Editor, framebuffer::FrameBuffer, memory::MemoryInspector, registers::Registers, serial::Serial, Component, }; -use emu_core::config::VERSION; -use emu_core::memory::ram::MemoryBank; -use emu_core::processor::state::SharedState; +use emulator_core::{ + config::VERSION, + memory::ram::MemoryBank, + processor::state::SharedState +}; pub fn run_app(state: Arc, mem_handle: MemoryBank) -> eframe::Result<()> { eframe::run_native( @@ -21,12 +23,13 @@ pub fn run_app(state: Arc, mem_handle: MemoryBank) -> eframe::Resul } impl eframe::App for DsaUi { - fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + + fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) { // request an update from ui every cycle self.state.update_req.store(true, Ordering::Relaxed); // title panel with dsa title - egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { + egui::containers::Panel::top("top_panel").show(ui, |ui| { ui.with_layout( egui::Layout::top_down_justified(egui::Align::Center) .with_main_align(egui::Align::Min), @@ -39,7 +42,7 @@ impl eframe::App for DsaUi { }); // menu bar. - egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| { + egui::Panel::top("menu_bar").show(ui, |ui| { egui::MenuBar::new().ui(ui, |ui| { ui.menu_button("Panels", |ui| { ui.set_max_width(300.0); @@ -54,21 +57,21 @@ impl eframe::App for DsaUi { }); }); - egui::CentralPanel::default().show(ctx, |ui| { + egui::CentralPanel::default().show(ui, |ui| { for c in &mut self.components { let mut visible = *c.visible(); if visible { egui::Window::new(c.title()) .open(&mut visible) - .show(ctx, |ui| { - c.ui(ui, ctx); + .show(ui, |ui| { + c.ui(ui); }); } *c.visible() = visible; } }); - ctx.request_repaint_after(std::time::Duration::from_millis(16)); // ~60fps + ui.request_repaint_after(std::time::Duration::from_millis(16)); // ~60fps } } diff --git a/dsa/emulator/frontend/src/ui/components/memory.rs b/dsa/emulator/frontend/src/ui/components/memory.rs deleted file mode 100644 index 557f18d..0000000 --- a/dsa/emulator/frontend/src/ui/components/memory.rs +++ /dev/null @@ -1,138 +0,0 @@ -use std::num::ParseIntError; - -use common::prelude::Instruction; -use emu_core::memory::ram::MemoryBank; -use super::Component; - -pub struct MemoryInspector { - memory: MemoryBank, - - view_size: u32, - view_addr: u32, - visible: bool, - addr_input: String, -} - -impl MemoryInspector { - #[must_use] - pub fn new(memory: MemoryBank) -> Self { - Self { - memory, - view_size: 1024, - view_addr: 0, - visible: false, - addr_input: String::from("0x00"), - } - } -} - -impl Component for MemoryInspector { - fn title(&self) -> &'static str { - "Memory Inspector" - } - - fn visible(&mut self) -> &mut bool { - &mut self.visible - } - - fn ui(&mut self, ui: &mut egui::Ui, ctx: &egui::Context) { - // Right column - Memory - ui.vertical(|ui| { - ui.heading("Memory Inspector"); - ui.add_space(10.0); - - // Address input section - ui.horizontal(|ui| { - ui.label("Address:"); - - let address_response = ui.add( - egui::TextEdit::singleline(&mut self.addr_input) - .hint_text("0x1000 or 4096") - .desired_width(150.0), - ); - - ui.add_space(10.0); - - // Search button - let search_clicked = ui.button("🔍 Search").clicked(); - - // Handle Enter key in text field - let enter_pressed = - address_response.lost_focus() && ctx.input(|i| i.key_pressed(egui::Key::Enter)); - - if search_clicked || enter_pressed { - if let Ok(new) = parse_address(&self.addr_input) { - if new % 4 == 0 { - self.view_addr = new; - } else { - println!("Address must be 4-byte aligned"); - } - } else { - println!("Invalid address"); - // state.error_log.push("Invalid address".to_string()); - } - } - - ui.label("(hex or decimal)"); - }); - - ui.add_space(10.0); - - // Memory table - egui::ScrollArea::vertical() - .auto_shrink(true) - .id_salt("memory_inspector_scroll") - .show(ui, |ui| { - egui::Grid::new("memory_grid") - .spacing([12.0, 2.0]) - .min_col_width(5.0) - .striped(true) - .show(ui, |ui| { - // Header - ui.strong("Address"); - - for i in 0..4 { - ui.strong(format!("{i:X}")); - } - - ui.strong("Decimal"); - ui.strong("Instruction"); - - ui.end_row(); - - // Memory data (8 bytes per row) - for (offset, word) in (0..self.view_size / 4) - .map(|i| i * 4) - .map(|i| (i, self.memory.read_word(self.view_addr + i))) - { - let row_address = self.view_addr + offset; - ui.monospace(format!("0x{row_address:08X} ({row_address})")); - for byte in word.to_le_bytes() { - ui.monospace(format!("{byte:02X}")); - } - - ui.monospace(format!("{word}")); - ui.monospace(format!("{:?}", Instruction(word))); - ui.end_row(); - } - }); - }); - }); - } -} - -fn parse_address(address: &str) -> Result { - if let Some(hex_part) = address.strip_prefix("0x") { - return u32::from_str_radix(hex_part, 16); - } - - if let Some(bin_part) = address.strip_prefix("0b") { - return u32::from_str_radix(bin_part, 2); - } - - if let Some(oct_part) = address.strip_prefix("0o") { - return u32::from_str_radix(oct_part, 8); - } - - address.parse::() -} diff --git a/dsa_resources/bf.dsa b/dsa_resources/bf.dsa index 2d0272a..fcc2b35 100644 --- a/dsa_resources/bf.dsa +++ b/dsa_resources/bf.dsa @@ -37,11 +37,11 @@ db program: "++++++++++++++++++++++++++++++++++++++++++++ db error: "Invalid Instruction!" dh counter: 0xFF dw stack: 0x10000 -dw input: 0x30000 +dw input_addr: 0x30000 resb data: 1024 // set up a stack so we can call functions -_init_stack: +_init: ldw stack, bpr mov bpr, spr @@ -162,7 +162,7 @@ output: // ------------------------------------------ // read a byte into the current cell input: - ldw input, rg2 + ldw input_addr, rg2 jmp loop_end // ------------------------------------------ diff --git a/dsx/dsx_client/Cargo.toml b/dsx/dsx_client/Cargo.toml new file mode 100644 index 0000000..1010d4b --- /dev/null +++ b/dsx/dsx_client/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dsx_client" +edition.workspace = true +version.workspace = true +authors.workspace = true + +[dependencies] diff --git a/dsx/dsx_client/src/main.rs b/dsx/dsx_client/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/dsx/dsx_client/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/dsx/dsx_common/Cargo.toml b/dsx/dsx_common/Cargo.toml new file mode 100644 index 0000000..b67cd8f --- /dev/null +++ b/dsx/dsx_common/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dsx_common" +edition.workspace = true +version.workspace = true +authors.workspace = true + +[dependencies] diff --git a/dsx/dsx_common/src/lib.rs b/dsx/dsx_common/src/lib.rs new file mode 100644 index 0000000..b93cf3f --- /dev/null +++ b/dsx/dsx_common/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/dsx/dsx_server/Cargo.toml b/dsx/dsx_server/Cargo.toml new file mode 100644 index 0000000..4f821b7 --- /dev/null +++ b/dsx/dsx_server/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "dsx_server" +edition.workspace = true +version.workspace = true +authors.workspace = true + +[dependencies] diff --git a/dsx/dsx_server/src/main.rs b/dsx/dsx_server/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/dsx/dsx_server/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/e.txt b/e.txt deleted file mode 100644 index 6f3a5d1..0000000 --- a/e.txt +++ /dev/null @@ -1,1072 +0,0 @@ -Building serialtest.dsa [/home/zxq5/Projects/HardwareDev/dsa2/dsa_resources/serialtest.dsa] -Tokenising serialtest.dsa -Parsing serialtest.dsa -Resolving Deps serialtest.dsa -Expanding Pseudo-ops serialtest.dsa -Including serial.dsa -Building serial.dsa [/home/zxq5/Projects/HardwareDev/dsa2/dsa_resources/serial.dsa] -Tokenising serial.dsa -Parsing serial.dsa -Resolving Deps serial.dsa -Expanding Pseudo-ops serial.dsa -Including idt.dsa -Building idt.dsa [/home/zxq5/Projects/HardwareDev/dsa2/dsa_resources/idt.dsa] -Tokenising idt.dsa -Parsing idt.dsa -Resolving Deps idt.dsa -Expanding Pseudo-ops idt.dsa -Including print.dsa -Building print.dsa [/home/zxq5/Projects/HardwareDev/dsa2/dsa_resources/print.dsa] -Tokenising print.dsa -Parsing print.dsa -Resolving Deps print.dsa -Expanding Pseudo-ops print.dsa -Including serial.dsa -Including print.dsa -PRE LINK -Node { symbol: None, opcode: Segment, tokens: [Immediate(3193829041)] } -Node { symbol: None, opcode: Include, tokens: [Symbol(Symbol { name: "serial", module: Resolved(10077013596335634097) }), StringLit("./serial.dsa")] } -Node { symbol: None, opcode: Include, tokens: [Symbol(Symbol { name: "idt", module: Resolved(10077013596335634097) }), StringLit("./idt.dsa")] } -Node { symbol: None, opcode: Include, tokens: [Symbol(Symbol { name: "print", module: Resolved(10077013596335634097) }), StringLit("./print.dsa")] } -Node { symbol: Some(Symbol { name: "stack", module: Resolved(10077013596335634097) }), opcode: Data, tokens: [Immediate(65536)] } -Node { symbol: Some(Symbol { name: "_init", module: Resolved(10077013596335634097) }), opcode: Lli, tokens: [Symbol(Symbol { name: "stack", module: Resolved(10077013596335634097) }), Register(Bpr)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "stack", module: Resolved(10077013596335634097) }), Register(Bpr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Bpr), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "setup_base", module: Resolved(2519286859380657757) })] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "setup_io", module: Resolved(2519286859380657757) })] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "serial_init", module: Resolved(12290222962602515901) })] } -Node { symbol: Some(Symbol { name: "hello", module: Resolved(10077013596335634097) }), opcode: Data, tokens: [Immediate(1953719636)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1936026912)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1701273971)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1701322796)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(544173164)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1819438967)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952784484)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952784483)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(11875)] } -Node { symbol: Some(Symbol { name: "main", module: Resolved(10077013596335634097) }), opcode: Lli, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "print", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "main", module: Resolved(10077013596335634097) }), Register(Zero)] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(138780093)] } -Node { symbol: Some(Symbol { name: "UART", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(262144)] } -Node { symbol: Some(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "SER_READ_PTR", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "serial_init", module: Resolved(12290222962602515901) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SER_READ_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SER_READ_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "serial_isr", module: Resolved(12290222962602515901) }), opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "UART", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "UART", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg0), Register(Rg0), Immediate(0)] } -Node { symbol: None, opcode: Ldb, tokens: [Register(Rg0), Register(Rg1), Immediate(2)] } -Node { symbol: None, opcode: Jez, tokens: [Register(Rg1), Symbol(Symbol { name: "_serial_isr_end", module: Resolved(12290222962602515901) }), Register(Zero)] } -Node { symbol: None, opcode: Ldb, tokens: [Register(Rg0), Register(Rg1), Immediate(3)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Zero), Register(Rg0), Immediate(2)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Rg2)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Rg2)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg2), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg1), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg2), Immediate(1), Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(1024), Register(Rg1)] } -Node { symbol: None, opcode: Ine, tokens: [Register(Rg1), Register(Rg2), Register(Rg1)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg1), Symbol(Symbol { name: "_serial_isr_nowrap", module: Resolved(12290222962602515901) }), Register(Zero)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg2)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), Register(Rg2)] } -Node { symbol: Some(Symbol { name: "_serial_isr_nowrap", module: Resolved(12290222962602515901) }), opcode: Lli, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg2), Register(Acc), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_serial_isr_end", module: Resolved(12290222962602515901) }), opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: IRet, tokens: [] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(78745181)] } -Node { symbol: None, opcode: Include, tokens: [Symbol(Symbol { name: "print", module: Resolved(2519286859380657757) }), StringLit("./print.dsa")] } -Node { symbol: None, opcode: Include, tokens: [Symbol(Symbol { name: "serial", module: Resolved(2519286859380657757) }), StringLit("./serial.dsa")] } -Node { symbol: Some(Symbol { name: "idt", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(4294901760)] } -Node { symbol: Some(Symbol { name: "setup_base", module: Resolved(2519286859380657757) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "idt", module: Resolved(2519286859380657757) }), Register(Idr)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "idt", module: Resolved(2519286859380657757) }), Register(Idr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Idr), Register(Idr), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "_guard", module: Resolved(2519286859380657757) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "_guard", module: Resolved(2519286859380657757) }), Register(Rg1)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Idr), Immediate(1024), Register(Rg2)] } -Node { symbol: Some(Symbol { name: "_loop_start", module: Resolved(2519286859380657757) }), opcode: Stw, tokens: [Register(Rg1), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: SubI, tokens: [Register(Rg2), Immediate(4), Register(Rg2)] } -Node { symbol: None, opcode: Ieq, tokens: [Register(Rg2), Register(Idr), Register(Rg3)] } -Node { symbol: None, opcode: Jez, tokens: [Register(Rg3), Symbol(Symbol { name: "_loop_start", module: Resolved(2519286859380657757) }), Register(Zero)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "_handle_invalid_interrupt", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "_handle_invalid_interrupt", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Idr), Immediate(0)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "setup_io", module: Resolved(2519286859380657757) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "serial_isr", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "serial_isr", module: Resolved(12290222962602515901) }), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Idr), Immediate(128)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_invalid_int", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(1096040774)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226848844)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1818326638)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226859625)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919251566)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953527154)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(33)] } -Node { symbol: Some(Symbol { name: "_handle_invalid_interrupt", module: Resolved(2519286859380657757) }), opcode: Call, tokens: [Symbol(Symbol { name: "reset", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "_invalid_int", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "_invalid_int", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "print", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: Some(Symbol { name: "_err", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(1096040774)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226848844)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919251566)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953527154)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1851877408)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919249508)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1935767328)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953459744)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952805664)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(33)] } -Node { symbol: Some(Symbol { name: "_guard", module: Resolved(2519286859380657757) }), opcode: Call, tokens: [Symbol(Symbol { name: "reset", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "_err", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "_err", module: Resolved(2519286859380657757) }), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "print", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(1648034676)] } -Node { symbol: Some(Symbol { name: "display", module: Resolved(11993558320162734964) }), opcode: Data, tokens: [Immediate(131072)] } -Node { symbol: Some(Symbol { name: "current", module: Resolved(11993558320162734964) }), opcode: Data, tokens: [Immediate(131072)] } -Node { symbol: Some(Symbol { name: "print", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_print_loop", module: Resolved(11993558320162734964) }), opcode: Ldb, tokens: [Register(Rg0), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: Ieq, tokens: [Register(Rg2), Register(Zero), Register(Rg3)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg3), Symbol(Symbol { name: "_print_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg2), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(1), Register(Rg0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_print_loop", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_print_end", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg1), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "print_byte", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "print_hex_byte", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "_print_hex_byte", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_print_hex_byte", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(15), Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Shr, tokens: [Register(Rg0), Register(Zero), Immediate(4), Register(Rg0)] } -Node { symbol: None, opcode: And, tokens: [Register(Rg0), Register(Rg2), Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "_print_hex_nibble", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: And, tokens: [Register(Rg0), Register(Rg2), Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Symbol(Symbol { name: "_print_hex_nibble", module: Resolved(11993558320162734964) })] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_print_hex_nibble", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(10), Register(Rg3)] } -Node { symbol: None, opcode: Ilt, tokens: [Register(Rg0), Register(Rg3), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Symbol(Symbol { name: "_print_hex_nibble_number", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(55), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_print_hex_nibble_number", module: Resolved(11993558320162734964) }), opcode: AddI, tokens: [Register(Rg0), Immediate(48), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "print_whitespace", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(32), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "newline", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg0)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg0), Register(Rg0), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Sub, tokens: [Register(Rg1), Register(Rg0), Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(80), Register(Rg3)] } -Node { symbol: Some(Symbol { name: "_newline_mod", module: Resolved(11993558320162734964) }), opcode: Ilt, tokens: [Register(Rg2), Register(Rg3), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Symbol(Symbol { name: "_newline_done", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: None, opcode: Sub, tokens: [Register(Rg2), Register(Rg3), Register(Rg2)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_newline_mod", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_newline_done", module: Resolved(11993558320162734964) }), opcode: Sub, tokens: [Register(Rg1), Register(Rg2), Register(Rg1)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(80), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "reset", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "clear", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(500), Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "display", module: Resolved(11993558320162734964) }), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_clear_loop", module: Resolved(11993558320162734964) }), opcode: SubI, tokens: [Register(Rg0), Immediate(1), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Zero), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(4), Register(Rg1)] } -Node { symbol: None, opcode: Igt, tokens: [Register(Rg0), Register(Zero), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Symbol(Symbol { name: "_clear_loop", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: None, opcode: Jmp, tokens: [Symbol(Symbol { name: "_end", module: Resolved(11993558320162734964) }), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_end", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Symbol(Symbol { name: "current", module: Resolved(11993558320162734964) }), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg1), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Generating assembly output... -Node { symbol: None, opcode: Jmp, tokens: [Immediate(1172), Register(Zero)] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "stack", module: Resolved(10077013596335634097) }), opcode: Data, tokens: [Immediate(65536)] } -Node { symbol: Some(Symbol { name: "hello", module: Resolved(10077013596335634097) }), opcode: Data, tokens: [Immediate(1953719636)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1936026912)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1701273971)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1701322796)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(544173164)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1819438967)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952784484)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952784483)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(11875)] } -Node { symbol: Some(Symbol { name: "UART", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(262144)] } -Node { symbol: Some(Symbol { name: "SERIAL_BUFFER", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "SER_READ_PTR", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "SER_WRITE_PTR", module: Resolved(12290222962602515901) }), opcode: Data, tokens: [Immediate(0)] } -Node { symbol: Some(Symbol { name: "idt", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(4294901760)] } -Node { symbol: Some(Symbol { name: "_invalid_int", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(1096040774)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226848844)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1818326638)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226859625)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919251566)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953527154)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(33)] } -Node { symbol: Some(Symbol { name: "_err", module: Resolved(2519286859380657757) }), opcode: Data, tokens: [Immediate(1096040774)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1226848844)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919251566)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953527154)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1851877408)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1919249508)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1935767328)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1953459744)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(1952805664)] } -Node { symbol: None, opcode: Data, tokens: [Immediate(33)] } -Node { symbol: Some(Symbol { name: "display", module: Resolved(11993558320162734964) }), opcode: Data, tokens: [Immediate(131072)] } -Node { symbol: Some(Symbol { name: "current", module: Resolved(11993558320162734964) }), opcode: Data, tokens: [Immediate(131072)] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(3193829041)] } -Node { symbol: Some(Symbol { name: "_init", module: Resolved(10077013596335634097) }), opcode: Lli, tokens: [Immediate(8), Register(Bpr)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(8), Register(Bpr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Bpr), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1404)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1508)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1232)] } -Node { symbol: Some(Symbol { name: "main", module: Resolved(10077013596335634097) }), opcode: Lli, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1608)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(1200), Register(Zero)] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(138780093)] } -Node { symbol: Some(Symbol { name: "serial_init", module: Resolved(12290222962602515901) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1080), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1080), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1084), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1084), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "serial_isr", module: Resolved(12290222962602515901) }), opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(48), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(48), Register(Rg0)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg0), Register(Rg0), Immediate(0)] } -Node { symbol: None, opcode: Ldb, tokens: [Register(Rg0), Register(Rg1), Immediate(2)] } -Node { symbol: None, opcode: Jez, tokens: [Register(Rg1), Immediate(1384), Register(Zero)] } -Node { symbol: None, opcode: Ldb, tokens: [Register(Rg0), Register(Rg1), Immediate(3)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Zero), Register(Rg0), Immediate(2)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1084), Register(Rg2)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1084), Register(Rg2)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg2), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg1), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg2), Immediate(1), Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(52), Register(Rg0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(1024), Register(Rg1)] } -Node { symbol: None, opcode: Ine, tokens: [Register(Rg1), Register(Rg2), Register(Rg1)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg1), Immediate(1372), Register(Zero)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(52), Register(Rg2)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(52), Register(Rg2)] } -Node { symbol: Some(Symbol { name: "_serial_isr_nowrap", module: Resolved(12290222962602515901) }), opcode: Lli, tokens: [Immediate(1084), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1084), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg2), Register(Acc), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_serial_isr_end", module: Resolved(12290222962602515901) }), opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: IRet, tokens: [] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(78745181)] } -Node { symbol: Some(Symbol { name: "setup_base", module: Resolved(2519286859380657757) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1088), Register(Idr)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1088), Register(Idr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Idr), Register(Idr), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1576), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1576), Register(Rg1)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Idr), Immediate(1024), Register(Rg2)] } -Node { symbol: Some(Symbol { name: "_loop_start", module: Resolved(2519286859380657757) }), opcode: Stw, tokens: [Register(Rg1), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: SubI, tokens: [Register(Rg2), Immediate(4), Register(Rg2)] } -Node { symbol: None, opcode: Ieq, tokens: [Register(Rg2), Register(Idr), Register(Rg3)] } -Node { symbol: None, opcode: Jez, tokens: [Register(Rg3), Immediate(1452), Register(Zero)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1548), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1548), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Idr), Immediate(0)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "setup_io", module: Resolved(2519286859380657757) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1284), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1284), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg0), Register(Idr), Immediate(128)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_handle_invalid_interrupt", module: Resolved(2519286859380657757) }), opcode: Call, tokens: [Immediate(1984)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1092), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1092), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1608)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: Some(Symbol { name: "_guard", module: Resolved(2519286859380657757) }), opcode: Call, tokens: [Immediate(1984)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1120), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1120), Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1608)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Zero)] } -Node { symbol: None, opcode: Hlt, tokens: [] } -Node { symbol: None, opcode: Segment, tokens: [Immediate(1648034676)] } -Node { symbol: Some(Symbol { name: "print", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_print_loop", module: Resolved(11993558320162734964) }), opcode: Ldb, tokens: [Register(Rg0), Register(Rg2), Immediate(0)] } -Node { symbol: None, opcode: Ieq, tokens: [Register(Rg2), Register(Zero), Register(Rg3)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg3), Immediate(1676), Register(Zero)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg2), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(1), Register(Rg0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(1648), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_print_end", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(1164), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg1), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg3)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg2)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "print_byte", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg1)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "print_hex_byte", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Bpr), Register(Rg0), Immediate(8)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1800)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_print_hex_byte", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(15), Register(Rg2)] } -Node { symbol: None, opcode: Push, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: Shr, tokens: [Register(Rg0), Register(Zero), Immediate(4), Register(Rg0)] } -Node { symbol: None, opcode: And, tokens: [Register(Rg0), Register(Rg2), Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1836)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Rg0)] } -Node { symbol: None, opcode: And, tokens: [Register(Rg0), Register(Rg2), Register(Rg0)] } -Node { symbol: None, opcode: Call, tokens: [Immediate(1836)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_print_hex_nibble", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(10), Register(Rg3)] } -Node { symbol: None, opcode: Ilt, tokens: [Register(Rg0), Register(Rg3), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Immediate(1864), Register(Zero)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg0), Immediate(55), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "_print_hex_nibble_number", module: Resolved(11993558320162734964) }), opcode: AddI, tokens: [Register(Rg0), Immediate(48), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Ret, tokens: [] } -Node { symbol: Some(Symbol { name: "print_whitespace", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(32), Register(Rg0)] } -Node { symbol: None, opcode: Stb, tokens: [Register(Rg0), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(1), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "newline", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1160), Register(Rg0)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1160), Register(Rg0)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg0), Register(Rg0), Immediate(0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Sub, tokens: [Register(Rg1), Register(Rg0), Register(Rg2)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(80), Register(Rg3)] } -Node { symbol: Some(Symbol { name: "_newline_mod", module: Resolved(11993558320162734964) }), opcode: Ilt, tokens: [Register(Rg2), Register(Rg3), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Immediate(1972), Register(Zero)] } -Node { symbol: None, opcode: Sub, tokens: [Register(Rg2), Register(Rg3), Register(Rg2)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(1956), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_newline_done", module: Resolved(11993558320162734964) }), opcode: Sub, tokens: [Register(Rg1), Register(Rg2), Register(Rg1)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(80), Register(Rg1)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "reset", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1160), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1160), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "clear", module: Resolved(11993558320162734964) }), opcode: Push, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Spr), Register(Bpr)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(500), Register(Rg0)] } -Node { symbol: None, opcode: Lli, tokens: [Immediate(1160), Register(Rg1)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1160), Register(Rg1)] } -Node { symbol: None, opcode: Ldw, tokens: [Register(Rg1), Register(Rg1), Immediate(0)] } -Node { symbol: Some(Symbol { name: "_clear_loop", module: Resolved(11993558320162734964) }), opcode: SubI, tokens: [Register(Rg0), Immediate(1), Register(Rg0)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Zero), Register(Rg1), Immediate(0)] } -Node { symbol: None, opcode: AddI, tokens: [Register(Rg1), Immediate(4), Register(Rg1)] } -Node { symbol: None, opcode: Igt, tokens: [Register(Rg0), Register(Zero), Register(Rg4)] } -Node { symbol: None, opcode: Jnz, tokens: [Register(Rg4), Immediate(2032), Register(Zero)] } -Node { symbol: None, opcode: Jmp, tokens: [Immediate(2056), Register(Zero)] } -Node { symbol: Some(Symbol { name: "_end", module: Resolved(11993558320162734964) }), opcode: Lli, tokens: [Immediate(1164), Register(Acc)] } -Node { symbol: None, opcode: Lui, tokens: [Immediate(1164), Register(Acc)] } -Node { symbol: None, opcode: Stw, tokens: [Register(Rg1), Register(Acc), Immediate(0)] } -Node { symbol: None, opcode: Mov, tokens: [Register(Bpr), Register(Spr)] } -Node { symbol: None, opcode: Pop, tokens: [Register(Bpr)] } -Node { symbol: None, opcode: Ret, tokens: [] } -INFO: Assembly Successful ✅ -Compilation Successful