From 1101331f7054d6bd33d8685b9c33c2d55384d333 Mon Sep 17 00:00:00 2001 From: zxq5 Date: Wed, 25 Jun 2025 16:22:32 +0100 Subject: [PATCH] fixed a couple of emulator bugs, including fixing shift instructions. finished implementing lib/io/print/print_hex_byte and print_hex_word --- .vscode/settings.json | 2 +- emulator/src/emulator/system/emulator.rs | 8 +- emulator/src/emulator/system/model.rs | 16 +- emulator/src/emulator/system/processor/mod.rs | 177 +++++++++--------- emulator/src/emulator/ui/control_unit.rs | 20 +- emulator/src/emulator/ui/stack_inspector.rs | 2 +- resources/dsa/lib/io/print.dsa | 57 ++++-- resources/dsa/test.dsa | 4 +- resources/dsb/test.dsb | Bin 4 -> 4 bytes 9 files changed, 162 insertions(+), 124 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0d3ac28..43cbdae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,5 @@ "files.eol": "\n", "files.insertFinalNewline": true, "files.trimFinalNewlines": true, - "files.trimTrailingWhitespace": true + "files.trimTrailingWhitespace": true, } diff --git a/emulator/src/emulator/system/emulator.rs b/emulator/src/emulator/system/emulator.rs index 376659f..f6e5c0c 100644 --- a/emulator/src/emulator/system/emulator.rs +++ b/emulator/src/emulator/system/emulator.rs @@ -190,7 +190,9 @@ pub fn run_emulator( history.push((addr, instruction)); } Err(why) => { - let pcx = processor.get(Register::Pcx); + let pcx = processor + .get(Register::Pcx) + .expect("SPR should never be invalid"); report_err( state_tx, &format!( @@ -211,7 +213,9 @@ pub fn run_emulator( let instruction = match processor.cycle() { Ok(instruction) => instruction, Err(why) => { - let pcx = processor.get(Register::Pcx); + let pcx = processor + .get(Register::Pcx) + .expect("PCX should never be invalid"); report_err( state_tx, &format!( diff --git a/emulator/src/emulator/system/model.rs b/emulator/src/emulator/system/model.rs index e674b2a..2d49a94 100644 --- a/emulator/src/emulator/system/model.rs +++ b/emulator/src/emulator/system/model.rs @@ -257,8 +257,8 @@ impl RegFile { self.pcx = 0; } - pub fn reg(&mut self, reg: Register) -> &mut u32 { - match reg { + pub const fn reg(&mut self, reg: Register) -> Result<&mut u32, ProcessorError> { + Ok(match reg { Register::Rg0 => &mut self.rg0, Register::Rg1 => &mut self.rg1, Register::Rg2 => &mut self.rg2, @@ -286,13 +286,13 @@ impl RegFile { Register::Sts => &mut self.sts, Register::Cir => &mut self.cir, Register::Pcx => &mut self.pcx, - _ => panic!("Invalid register."), - } + _ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)), + }) } #[must_use] - pub fn get(&self, reg: Register) -> u32 { - match reg { + pub const fn get(&self, reg: Register) -> Result { + Ok(match reg { Register::Rg0 => self.rg0, Register::Rg1 => self.rg1, Register::Rg2 => self.rg2, @@ -321,7 +321,7 @@ impl RegFile { Register::Cir => self.cir, Register::Pcx => self.pcx, Register::Zero => 0, - _ => panic!("Invalid register."), - } + _ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)), + }) } } diff --git a/emulator/src/emulator/system/processor/mod.rs b/emulator/src/emulator/system/processor/mod.rs index e3997dc..d48b80d 100644 --- a/emulator/src/emulator/system/processor/mod.rs +++ b/emulator/src/emulator/system/processor/mod.rs @@ -16,7 +16,7 @@ pub struct Processor { pub halted: bool, pub io_devices: Vec>, - pub dustbin: u32, + pub void: u32, } fn log(message: &str) { @@ -31,7 +31,7 @@ impl Processor { registers: RegFile::default(), halted: false, io_devices, - dustbin: 0, + void: 0, } } @@ -49,16 +49,16 @@ impl Processor { self.halted = false; // Get value from PCX. - let addr = self.fetch(); + let addr = self.fetch()?; // Increment PCX. self.advance(); // Set MAR to the previous value of PCX. - *self.reg(Register::Mar) = addr; + *self.reg(Register::Mar)? = addr; let val = self.memory.read_word(addr)?; // Set CIR to the value of RAM[MAR]. - *self.reg(Register::Mar) = val; + *self.reg(Register::Mar)? = val; // Decode and execute the instruction. let instruction = Instruction::decode(val) @@ -68,18 +68,17 @@ impl Processor { Ok((addr, instruction)) } - fn fetch(&self) -> u32 { + const fn fetch(&self) -> Result { self.get(Register::Pcx) } - #[must_use] - pub fn get(&self, reg: Register) -> u32 { + pub const fn get(&self, reg: Register) -> Result { self.registers.get(reg) } - pub fn reg(&mut self, reg: Register) -> &mut u32 { + pub const fn reg(&mut self, reg: Register) -> Result<&mut u32, ProcessorError> { match reg { - Register::Zero => &mut self.dustbin, + Register::Zero => Ok(&mut self.void), _ => self.registers.reg(reg), } } @@ -97,51 +96,57 @@ impl Processor { // functions to set new state fn set_flag(&mut self, flag: Flag, value: bool) { if value { - *self.reg(Register::Sts) |= flag as u32; + *self + .reg(Register::Sts) + .expect("STS should never be invalid") |= flag as u32; } else { - *self.reg(Register::Sts) &= !(flag as u32); + *self + .reg(Register::Sts) + .expect("STS should never be invalid") &= !(flag as u32); } } - fn get_flag(&self, flag: Flag) -> bool { - self.get(Register::Sts) & (flag as u32) != 0 + fn get_flag(&self, flag: Flag) -> Result { + Ok(self.get(Register::Sts)? & (flag as u32) != 0) } - fn advance(&mut self) { + fn advance(&mut self) -> Result<(), ProcessorError> { // increment PCX - *self.reg(Register::Pcx) += 4; + *self.reg(Register::Pcx)? += 4; + Ok(()) } - fn jump(&mut self, reg: Register, offset: u16) { - *self.reg(Register::Pcx) = self.get(reg) + u32::from(offset); + fn jump(&mut self, reg: Register, offset: u16) -> Result<(), ProcessorError> { + *self.reg(Register::Pcx)? = self.get(reg)? + u32::from(offset); + Ok(()) } pub fn begin_interrupt( &mut self, interrupt: Interrupt, ) -> Result<(), ProcessorError> { - let idt = self.get(Register::Idr); + let idt = self.get(Register::Idr)?; let addr = self .memory .read_word(idt + u32::from(interrupt.as_u8()) * 4)?; println!("INFO: Interrupt {interrupt:?} addr: {addr}"); - self.push(self.get(Register::Pcx))?; - *self.reg(Register::Pcx) = addr; + self.push(self.get(Register::Pcx)?)?; + *self.reg(Register::Pcx)? = addr; Ok(()) } fn push(&mut self, val: u32) -> Result<(), ProcessorError> { - *self.reg(Register::Spr) -= 4; - let reg = *self.reg(Register::Spr); + *self.reg(Register::Spr)? -= 4; + let reg = *self.reg(Register::Spr)?; self.memory.write_word(reg, val) } fn pop(&mut self) -> Result { - let reg = *self.reg(Register::Spr); + let reg = *self.reg(Register::Spr)?; let val = self.memory.read_word(reg)?; - *self.reg(Register::Spr) += 4; + *self.reg(Register::Spr)? += 4; Ok(val) } @@ -149,13 +154,13 @@ impl Processor { #[allow(clippy::needless_pass_by_ref_mut)] fn end_interrupt(&mut self) -> Result<(), ProcessorError> { let ret = self.pop()?; - *self.reg(Register::Ret) = ret; - *self.reg(Register::Pcx) = ret; + *self.reg(Register::Ret)? = ret; + *self.reg(Register::Pcx)? = ret; Ok(()) } pub fn get_stack(&mut self, n: u32) -> Result, ProcessorError> { - let addr = self.get(Register::Spr); + let addr = self.get(Register::Spr)?; let size = n * 4; // returns the stack self.memory.read_range( @@ -190,30 +195,30 @@ impl Executable for Instruction { // No operation - a blank line. // Copies from SrcReg to a.drReg. Self::Mov(a) => { - *cpu.reg(a.dr) = cpu.get(a.sr1); + *cpu.reg(a.dr)? = cpu.get(a.sr1)?; } // Copies from SrcReg to a.drReg, sign extending the value to take up a full // word. Self::MovSigned(a) => { - *cpu.reg(a.dr) = sign_extend(cpu.get(a.sr1)); + *cpu.reg(a.dr)? = sign_extend(cpu.get(a.sr1)?); } // Loads a byte from memory address (base + offset) into a.drReg. The // effective address must be byte-aligned. Self::LoadByte(a) => { - *cpu.reg(a.r2) = u32::from( + *cpu.reg(a.r2)? = u32::from( cpu.memory - .read_byte(cpu.get(a.r1) + u32::from(a.immediate))?, + .read_byte(cpu.get(a.r1)? + u32::from(a.immediate))?, ); } // Loads a sign-extended byte from memory address (base + offset) into // a.drReg. The effective address must be byte-aligned. Self::LoadByteSigned(a) => { - *cpu.reg(a.r2) = sign_extend(u32::from( + *cpu.reg(a.r2)? = sign_extend(u32::from( cpu.memory - .read_byte(cpu.get(a.r1) + u32::from(a.immediate))?, + .read_byte(cpu.get(a.r1)? + u32::from(a.immediate))?, )); } @@ -222,18 +227,18 @@ impl Executable for Instruction { Self::LoadHalfword(a) => { // we read an entire word, then right shift so we only get the first half // of the word - *cpu.reg(a.r2) = cpu + *cpu.reg(a.r2)? = cpu .memory - .read_word(cpu.get(a.r1) + u32::from(a.immediate))? + .read_word(cpu.get(a.r1)? + u32::from(a.immediate))? >> 16; } // Loads a sign-extended half-word from memory address (base + offset) into // a.drReg. The effective address must be 2-byte-aligned. Self::LoadHalfwordSigned(a) => { - *cpu.reg(a.r2) = sign_extend( + *cpu.reg(a.r2)? = sign_extend( cpu.memory - .read_word(cpu.get(a.r1) + u32::from(a.immediate))? + .read_word(cpu.get(a.r1)? + u32::from(a.immediate))? >> 16, ); } @@ -241,17 +246,17 @@ impl Executable for Instruction { // Loads a word from memory address (base + offset) into a.drReg. The // effective address must be 4-byte-aligned. Self::LoadWord(a) => { - *cpu.reg(a.r2) = cpu + *cpu.reg(a.r2)? = cpu .memory - .read_word(cpu.get(a.r1) + u32::from(a.immediate))?; + .read_word(cpu.get(a.r1)? + u32::from(a.immediate))?; } // Stores a byte from SrcReg in memory address (base + offset) The effective // address must be byte-aligned. Self::StoreByte(a) => { cpu.memory.write_byte( - cpu.get(a.r2) + u32::from(a.immediate), - cpu.get(a.r1) as u8, + cpu.get(a.r2)? + u32::from(a.immediate), + cpu.get(a.r1)? as u8, )?; } @@ -259,149 +264,147 @@ impl Executable for Instruction { // effective address must be 2-byte-aligned. Self::StoreHalfword(a) => { // split the value into bytes and then write two bytes - let bytes = (cpu.get(a.r1) as u16).to_le_bytes(); + let bytes = (cpu.get(a.r1)? as u16).to_le_bytes(); cpu.memory - .write_byte(cpu.get(a.r2) + u32::from(a.immediate), bytes[0])?; + .write_byte(cpu.get(a.r2)? + u32::from(a.immediate), bytes[0])?; cpu.memory - .write_byte(cpu.get(a.r2) + u32::from(a.immediate) + 1, bytes[1])?; + .write_byte(cpu.get(a.r2)? + u32::from(a.immediate) + 1, bytes[1])?; } // Stores a word from SrcReg in memory address (base + offset) The effective // address must be 4-byte-aligned. Self::StoreWord(a) => { - cpu.memory - .write_word(cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r1))?; + cpu.memory.write_word( + cpu.get(a.r2)? + u32::from(a.immediate), + cpu.get(a.r1)?, + )?; } // Loads a 16-bit literal value into reg, setting the bottom 16 bits of the // word. To populate the upper 16 bits, see LUI. Self::LoadLowerImmediate(a) => { - *cpu.reg(a.r1) = u32::from(a.immediate); + *cpu.reg(a.r1)? = u32::from(a.immediate); } // Loads a 16-bit literal value into reg, setting the top 16 bits of the word. // To populate the lower 16 bits, see LLI. Self::LoadUpperImmediate(a) => { - *cpu.reg(a.r1) = - (cpu.get(a.r1) & 0x0000_FFFF) | (u32::from(a.immediate) << 16); + *cpu.reg(a.r1)? = + (cpu.get(a.r1)? & 0x0000_FFFF) | (u32::from(a.immediate) << 16); } // Unconditionally jumps to the calculated address or direct address - Self::Jump(a) => cpu.jump(a.r1, a.immediate), + Self::Jump(a) => cpu.jump(a.r1, a.immediate)?, // Jumps to the calculated address or direct address if equal flag set. Self::JumpEq(a) => { - if cpu.get_flag(Flag::Equal) { - cpu.jump(a.r1, a.immediate); + if cpu.get_flag(Flag::Equal)? { + cpu.jump(a.r1, a.immediate)?; } } // Jumps to the calculated address or direct address if equal flag not set. Self::JumpNeq(a) => { - if !cpu.get_flag(Flag::Equal) { - cpu.jump(a.r1, a.immediate); + if !cpu.get_flag(Flag::Equal)? { + cpu.jump(a.r1, a.immediate)?; } } // Jumps to the calculated address or direct address if greater than flag set. Self::JumpGt(a) => { - if cpu.get_flag(Flag::GreaterThan) { - cpu.jump(a.r1, a.immediate); + if cpu.get_flag(Flag::GreaterThan)? { + cpu.jump(a.r1, a.immediate)?; } } // Jumps to the calculated address or direct address if greater than flag or // equal flag set. Self::JumpGe(a) => { - if cpu.get_flag(Flag::GreaterThan) || cpu.get_flag(Flag::Equal) { - cpu.jump(a.r1, a.immediate); + if cpu.get_flag(Flag::GreaterThan)? || cpu.get_flag(Flag::Equal)? { + cpu.jump(a.r1, a.immediate)?; } } // Jumps to the calculated address or direct address if less than flag set. Self::JumpLt(a) => { - if cpu.get_flag(Flag::LessThan) { - cpu.jump(a.r1, a.immediate); + if cpu.get_flag(Flag::LessThan)? { + cpu.jump(a.r1, a.immediate)?; } } // Jumps to the calculated address or direct address if less than flag or // equal flag set. Self::JumpLe(a) => { - if cpu.get_flag(Flag::LessThan) || cpu.get_flag(Flag::Equal) { - cpu.jump(a.r1, a.immediate); + if cpu.get_flag(Flag::LessThan)? || cpu.get_flag(Flag::Equal)? { + cpu.jump(a.r1, a.immediate)?; } } // Increments the value in the given register - Self::Increment(a) => *cpu.reg(a.sr1) = inc(cpu.get(a.sr1)), + Self::Increment(a) => *cpu.reg(a.sr1)? = inc(cpu.get(a.sr1)?), // Decrements the value in the given register - Self::Decrement(a) => *cpu.reg(a.sr1) = dec(cpu.get(a.sr1)), + Self::Decrement(a) => *cpu.reg(a.sr1)? = dec(cpu.get(a.sr1)?), // Left shifts the value in Reg by the given amount (either a register, or a // literal value) Self::ShiftLeft(a) => { - let regval = cpu.get(a.sr2); - let val = cpu.get(a.sr1); - - *cpu.reg(a.sr1) = - shl(val, if regval != 0 { regval as u8 } else { a.shamt }); + let reg = cpu.get(a.sr1)?; + let val = a.shamt; + *cpu.reg(a.sr1)? = shl(reg, val); } // Right shifts the value in Reg by the given amount (either a register, or a // literal value). Self::ShiftRight(a) => { - let regval = cpu.get(a.sr2); - let val = cpu.get(a.sr1); - - *cpu.reg(a.sr1) = - shr(val, if regval != 0 { regval as u8 } else { a.shamt }); + let regval = cpu.get(a.sr1)?; + let val = a.shamt; + *cpu.reg(a.sr1)? = shr(regval, val); } // Adds the value of Src2 to Src1 and writes the result to a.dr Self::Add(a) => { - *cpu.reg(a.dr) = add(cpu.get(a.sr1), cpu.get(a.sr2)); + *cpu.reg(a.dr)? = add(cpu.get(a.sr1)?, cpu.get(a.sr2)?); } // Subtracts the value of Src2 from Src1 and writes the result to a.dr Self::Sub(a) => { - *cpu.reg(a.dr) = sub(cpu.get(a.sr1), cpu.get(a.sr2)); + *cpu.reg(a.dr)? = sub(cpu.get(a.sr1)?, cpu.get(a.sr2)?); } Self::AddImmediate(a) => { - *cpu.reg(a.r2) = add(cpu.get(a.r1), u32::from(a.immediate)); + *cpu.reg(a.r2)? = add(cpu.get(a.r1)?, u32::from(a.immediate)); } Self::SubImmediate(a) => { - *cpu.reg(a.r2) = sub(cpu.get(a.r1), u32::from(a.immediate)); + *cpu.reg(a.r2)? = sub(cpu.get(a.r1)?, u32::from(a.immediate)); } // Performs bitwise AND on Src1 and Src2 storing the result in a.dr - Self::And(a) => *cpu.reg(a.dr) = and(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::And(a) => *cpu.reg(a.dr)? = and(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Performs bitwise OR on Src1 and Src2 storing the result in a.dr - Self::Or(a) => *cpu.reg(a.dr) = or(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::Or(a) => *cpu.reg(a.dr)? = or(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Performs bitwise NOT on Src storing the result in a.dr - Self::Not(a) => *cpu.reg(a.dr) = not(cpu.get(a.sr1)), + Self::Not(a) => *cpu.reg(a.dr)? = not(cpu.get(a.sr1)?), // Performs bitwise XOR on Src1 and Src2 storing the result in a.dr - Self::Xor(a) => *cpu.reg(a.dr) = xor(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::Xor(a) => *cpu.reg(a.dr)? = xor(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Performs bitwise NAND on Src1 and Src2 storing the result in a.dr - Self::Nand(a) => *cpu.reg(a.dr) = nand(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::Nand(a) => *cpu.reg(a.dr)? = nand(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Performs bitwise NOR on Src1 and Src2 storing the result in a.dr - Self::Nor(a) => *cpu.reg(a.dr) = nor(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::Nor(a) => *cpu.reg(a.dr)? = nor(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Performs bitwise XNOR on Src1 and Src2 storing the result in a.dr - Self::Xnor(a) => *cpu.reg(a.dr) = xnor(cpu.get(a.sr1), cpu.get(a.sr2)), + Self::Xnor(a) => *cpu.reg(a.dr)? = xnor(cpu.get(a.sr1)?, cpu.get(a.sr2)?), // Compares the value of Reg1 to the value in Reg2. The results of the // comparisons are set in the Status register. Self::Compare(a) => { - cpu.cmp(cpu.get(a.sr1), cpu.get(a.sr2)); + cpu.cmp(cpu.get(a.sr1)?, cpu.get(a.sr2)?); } // Initiates an interrupt with the given 8 bit interrupt code. diff --git a/emulator/src/emulator/ui/control_unit.rs b/emulator/src/emulator/ui/control_unit.rs index bb32679..2cee3bb 100644 --- a/emulator/src/emulator/ui/control_unit.rs +++ b/emulator/src/emulator/ui/control_unit.rs @@ -133,17 +133,25 @@ impl Component for ControlPanel { } )); - let pcx = state.reg_file.get(Register::Pcx); + let pcx = state + .reg_file + .get(Register::Pcx) + .expect("PCX should never be invalid"); let instructions = state.instructions; ui.label(format!("Instructions: {instructions}")); ui.label(format!("PC: 0x{pcx:08X}")); - let instruction = Instruction::decode(state.reg_file.get(Register::Cir)) - .map_or_else( - |_| "Invalid Instruction".to_string(), - |instruction| instruction.to_string(), - ); + let instruction = Instruction::decode( + state + .reg_file + .get(Register::Cir) + .expect("CIR should never be invalid"), + ) + .map_or_else( + |_| "Invalid Instruction".to_string(), + |instruction| instruction.to_string(), + ); ui.label(format!("Instruction: {instruction}")); }); diff --git a/emulator/src/emulator/ui/stack_inspector.rs b/emulator/src/emulator/ui/stack_inspector.rs index e15ac5a..b89f4f0 100644 --- a/emulator/src/emulator/ui/stack_inspector.rs +++ b/emulator/src/emulator/ui/stack_inspector.rs @@ -61,7 +61,7 @@ impl Component for StackInspector { ui.label(format!( "{} [{}]", i, - state.reg_file.get(Register::Spr) - i as u32 * 4 + state.reg_file.get(Register::Spr).expect("SPR should never be invalid") - i as u32 * 4 )); ui.label(format!("0x{value:08X} ({value})")); ui.end_row(); diff --git a/resources/dsa/lib/io/print.dsa b/resources/dsa/lib/io/print.dsa index efa6325..1946fa9 100644 --- a/resources/dsa/lib/io/print.dsa +++ b/resources/dsa/lib/io/print.dsa @@ -82,14 +82,48 @@ print_byte: // ------------------------------------------ // prints the value of arg[0] to the screen in hex. +print_hex_word: + push bpr + mov spr, bpr + + ldw current, rg1 + + ldb bpr, rg0, 8 + push rg0 + call _print_hex_byte + addi spr, 4 + + ldb bpr, rg0, 9 + push rg0 + call _print_hex_byte + addi spr, 4 + + ldb bpr, rg0, 10 + push rg0 + call _print_hex_byte + addi spr, 4 + + ldb bpr, rg0, 11 + push rg0 + call _print_hex_byte + addi spr, 4 + + jmp _end + +// ------------------------------------------ +// prints the last byte of arg[0] to the screen in hex. print_hex_byte: push bpr mov spr, bpr - // put arg byte in rg0 ldw bpr, rg0, 8 ldw current, rg1 + call _print_hex_byte + jmp _end + +// function body +_print_hex_byte: // mask to get lower nibble lli 0xF, rg2 // save rg0 state @@ -102,8 +136,9 @@ print_hex_byte: and rg0, rg2, rg0 call _print_hex_nibble - jmp _end + return +// print a hex digit _print_hex_nibble: lli 10, rg3 cmp rg0, rg3 @@ -111,26 +146,14 @@ _print_hex_nibble: addi rg0, 0x37, rg0 stb rg0, rg1 addi rg1, 1 - jmp _end + return +// helper function. _print_hex_nibble_number: addi rg0, 0x30, rg0 stb rg0, rg1 addi rg1, 1 - jmp _end - -// ------------------------------------------ -// prints the value of arg[0] to the screen in hex. -print_hex_word: - push bpr - mov spr, bpr - - ldw bpr, rg0, 8 - ldw current, rg1 - - stw rg0, rg1 - addi rg1, 4 - jmp _end + return // ------------------------------------------ // resets the cursor position on the screen to 0x20000. (0,0) diff --git a/resources/dsa/test.dsa b/resources/dsa/test.dsa index 4dcbf94..67d82c6 100644 --- a/resources/dsa/test.dsa +++ b/resources/dsa/test.dsa @@ -16,9 +16,9 @@ start: stw rg0, idr, 4 - lli 0x20, rg0 + lwi 0x1234abcd, rg0 push rg0 - call print::print_hex_byte + call print::print_hex_word pop zero hlt diff --git a/resources/dsb/test.dsb b/resources/dsb/test.dsb index 9c515159fa4544f73596b79601a5078d1bdaf772..2b831a14e46872a7943b9adcac710ba835e160b8 100644 GIT binary patch literal 4 LcmXpjXJ7#U0!09_ literal 4 LcmXrJ&aeOg1OWlA