fixed a couple of emulator bugs, including fixing shift instructions. finished implementing lib/io/print/print_hex_byte and print_hex_word

This commit is contained in:
2025-06-25 16:22:32 +01:00
parent c171b0db89
commit 1101331f70
9 changed files with 162 additions and 124 deletions
+1 -1
View File
@@ -5,5 +5,5 @@
"files.eol": "\n", "files.eol": "\n",
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"files.trimFinalNewlines": true, "files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true "files.trimTrailingWhitespace": true,
} }
+6 -2
View File
@@ -190,7 +190,9 @@ pub fn run_emulator(
history.push((addr, instruction)); history.push((addr, instruction));
} }
Err(why) => { Err(why) => {
let pcx = processor.get(Register::Pcx); let pcx = processor
.get(Register::Pcx)
.expect("SPR should never be invalid");
report_err( report_err(
state_tx, state_tx,
&format!( &format!(
@@ -211,7 +213,9 @@ pub fn run_emulator(
let instruction = match processor.cycle() { let instruction = match processor.cycle() {
Ok(instruction) => instruction, Ok(instruction) => instruction,
Err(why) => { Err(why) => {
let pcx = processor.get(Register::Pcx); let pcx = processor
.get(Register::Pcx)
.expect("PCX should never be invalid");
report_err( report_err(
state_tx, state_tx,
&format!( &format!(
+8 -8
View File
@@ -257,8 +257,8 @@ impl RegFile {
self.pcx = 0; self.pcx = 0;
} }
pub fn reg(&mut self, reg: Register) -> &mut u32 { pub const fn reg(&mut self, reg: Register) -> Result<&mut u32, ProcessorError> {
match reg { Ok(match reg {
Register::Rg0 => &mut self.rg0, Register::Rg0 => &mut self.rg0,
Register::Rg1 => &mut self.rg1, Register::Rg1 => &mut self.rg1,
Register::Rg2 => &mut self.rg2, Register::Rg2 => &mut self.rg2,
@@ -286,13 +286,13 @@ impl RegFile {
Register::Sts => &mut self.sts, Register::Sts => &mut self.sts,
Register::Cir => &mut self.cir, Register::Cir => &mut self.cir,
Register::Pcx => &mut self.pcx, Register::Pcx => &mut self.pcx,
_ => panic!("Invalid register."), _ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)),
} })
} }
#[must_use] #[must_use]
pub fn get(&self, reg: Register) -> u32 { pub const fn get(&self, reg: Register) -> Result<u32, ProcessorError> {
match reg { Ok(match reg {
Register::Rg0 => self.rg0, Register::Rg0 => self.rg0,
Register::Rg1 => self.rg1, Register::Rg1 => self.rg1,
Register::Rg2 => self.rg2, Register::Rg2 => self.rg2,
@@ -321,7 +321,7 @@ impl RegFile {
Register::Cir => self.cir, Register::Cir => self.cir,
Register::Pcx => self.pcx, Register::Pcx => self.pcx,
Register::Zero => 0, Register::Zero => 0,
_ => panic!("Invalid register."), _ => return Err(ProcessorError::InvalidRegister(Register::NoReg as u8)),
} })
} }
} }
+90 -87
View File
@@ -16,7 +16,7 @@ pub struct Processor {
pub halted: bool, pub halted: bool,
pub io_devices: Vec<Arc<dyn IODevice>>, pub io_devices: Vec<Arc<dyn IODevice>>,
pub dustbin: u32, pub void: u32,
} }
fn log(message: &str) { fn log(message: &str) {
@@ -31,7 +31,7 @@ impl Processor {
registers: RegFile::default(), registers: RegFile::default(),
halted: false, halted: false,
io_devices, io_devices,
dustbin: 0, void: 0,
} }
} }
@@ -49,16 +49,16 @@ impl Processor {
self.halted = false; self.halted = false;
// Get value from PCX. // Get value from PCX.
let addr = self.fetch(); let addr = self.fetch()?;
// Increment PCX. // Increment PCX.
self.advance(); self.advance();
// Set MAR to the previous value of PCX. // 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)?; let val = self.memory.read_word(addr)?;
// Set CIR to the value of RAM[MAR]. // Set CIR to the value of RAM[MAR].
*self.reg(Register::Mar) = val; *self.reg(Register::Mar)? = val;
// Decode and execute the instruction. // Decode and execute the instruction.
let instruction = Instruction::decode(val) let instruction = Instruction::decode(val)
@@ -68,18 +68,17 @@ impl Processor {
Ok((addr, instruction)) Ok((addr, instruction))
} }
fn fetch(&self) -> u32 { const fn fetch(&self) -> Result<u32, ProcessorError> {
self.get(Register::Pcx) self.get(Register::Pcx)
} }
#[must_use] pub const fn get(&self, reg: Register) -> Result<u32, ProcessorError> {
pub fn get(&self, reg: Register) -> u32 {
self.registers.get(reg) 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 { match reg {
Register::Zero => &mut self.dustbin, Register::Zero => Ok(&mut self.void),
_ => self.registers.reg(reg), _ => self.registers.reg(reg),
} }
} }
@@ -97,51 +96,57 @@ impl Processor {
// functions to set new state // functions to set new state
fn set_flag(&mut self, flag: Flag, value: bool) { fn set_flag(&mut self, flag: Flag, value: bool) {
if value { if value {
*self.reg(Register::Sts) |= flag as u32; *self
.reg(Register::Sts)
.expect("STS should never be invalid") |= flag as u32;
} else { } 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 { fn get_flag(&self, flag: Flag) -> Result<bool, ProcessorError> {
self.get(Register::Sts) & (flag as u32) != 0 Ok(self.get(Register::Sts)? & (flag as u32) != 0)
} }
fn advance(&mut self) { fn advance(&mut self) -> Result<(), ProcessorError> {
// increment PCX // increment PCX
*self.reg(Register::Pcx) += 4; *self.reg(Register::Pcx)? += 4;
Ok(())
} }
fn jump(&mut self, reg: Register, offset: u16) { fn jump(&mut self, reg: Register, offset: u16) -> Result<(), ProcessorError> {
*self.reg(Register::Pcx) = self.get(reg) + u32::from(offset); *self.reg(Register::Pcx)? = self.get(reg)? + u32::from(offset);
Ok(())
} }
pub fn begin_interrupt( pub fn begin_interrupt(
&mut self, &mut self,
interrupt: Interrupt, interrupt: Interrupt,
) -> Result<(), ProcessorError> { ) -> Result<(), ProcessorError> {
let idt = self.get(Register::Idr); let idt = self.get(Register::Idr)?;
let addr = self let addr = self
.memory .memory
.read_word(idt + u32::from(interrupt.as_u8()) * 4)?; .read_word(idt + u32::from(interrupt.as_u8()) * 4)?;
println!("INFO: Interrupt {interrupt:?} addr: {addr}"); println!("INFO: Interrupt {interrupt:?} addr: {addr}");
self.push(self.get(Register::Pcx))?; self.push(self.get(Register::Pcx)?)?;
*self.reg(Register::Pcx) = addr; *self.reg(Register::Pcx)? = addr;
Ok(()) Ok(())
} }
fn push(&mut self, val: u32) -> Result<(), ProcessorError> { fn push(&mut self, val: u32) -> Result<(), ProcessorError> {
*self.reg(Register::Spr) -= 4; *self.reg(Register::Spr)? -= 4;
let reg = *self.reg(Register::Spr); let reg = *self.reg(Register::Spr)?;
self.memory.write_word(reg, val) self.memory.write_word(reg, val)
} }
fn pop(&mut self) -> Result<u32, ProcessorError> { fn pop(&mut self) -> Result<u32, ProcessorError> {
let reg = *self.reg(Register::Spr); let reg = *self.reg(Register::Spr)?;
let val = self.memory.read_word(reg)?; let val = self.memory.read_word(reg)?;
*self.reg(Register::Spr) += 4; *self.reg(Register::Spr)? += 4;
Ok(val) Ok(val)
} }
@@ -149,13 +154,13 @@ impl Processor {
#[allow(clippy::needless_pass_by_ref_mut)] #[allow(clippy::needless_pass_by_ref_mut)]
fn end_interrupt(&mut self) -> Result<(), ProcessorError> { fn end_interrupt(&mut self) -> Result<(), ProcessorError> {
let ret = self.pop()?; let ret = self.pop()?;
*self.reg(Register::Ret) = ret; *self.reg(Register::Ret)? = ret;
*self.reg(Register::Pcx) = ret; *self.reg(Register::Pcx)? = ret;
Ok(()) Ok(())
} }
pub fn get_stack(&mut self, n: u32) -> Result<Vec<u8>, ProcessorError> { pub fn get_stack(&mut self, n: u32) -> Result<Vec<u8>, ProcessorError> {
let addr = self.get(Register::Spr); let addr = self.get(Register::Spr)?;
let size = n * 4; let size = n * 4;
// returns the stack // returns the stack
self.memory.read_range( self.memory.read_range(
@@ -190,30 +195,30 @@ impl Executable for Instruction {
// No operation - a blank line. // No operation - a blank line.
// Copies from SrcReg to a.drReg. // Copies from SrcReg to a.drReg.
Self::Mov(a) => { 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 // Copies from SrcReg to a.drReg, sign extending the value to take up a full
// word. // word.
Self::MovSigned(a) => { 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 // Loads a byte from memory address (base + offset) into a.drReg. The
// effective address must be byte-aligned. // effective address must be byte-aligned.
Self::LoadByte(a) => { Self::LoadByte(a) => {
*cpu.reg(a.r2) = u32::from( *cpu.reg(a.r2)? = u32::from(
cpu.memory 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 // Loads a sign-extended byte from memory address (base + offset) into
// a.drReg. The effective address must be byte-aligned. // a.drReg. The effective address must be byte-aligned.
Self::LoadByteSigned(a) => { Self::LoadByteSigned(a) => {
*cpu.reg(a.r2) = sign_extend(u32::from( *cpu.reg(a.r2)? = sign_extend(u32::from(
cpu.memory 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) => { Self::LoadHalfword(a) => {
// we read an entire word, then right shift so we only get the first half // we read an entire word, then right shift so we only get the first half
// of the word // of the word
*cpu.reg(a.r2) = cpu *cpu.reg(a.r2)? = cpu
.memory .memory
.read_word(cpu.get(a.r1) + u32::from(a.immediate))? .read_word(cpu.get(a.r1)? + u32::from(a.immediate))?
>> 16; >> 16;
} }
// Loads a sign-extended half-word from memory address (base + offset) into // Loads a sign-extended half-word from memory address (base + offset) into
// a.drReg. The effective address must be 2-byte-aligned. // a.drReg. The effective address must be 2-byte-aligned.
Self::LoadHalfwordSigned(a) => { Self::LoadHalfwordSigned(a) => {
*cpu.reg(a.r2) = sign_extend( *cpu.reg(a.r2)? = sign_extend(
cpu.memory cpu.memory
.read_word(cpu.get(a.r1) + u32::from(a.immediate))? .read_word(cpu.get(a.r1)? + u32::from(a.immediate))?
>> 16, >> 16,
); );
} }
@@ -241,17 +246,17 @@ impl Executable for Instruction {
// Loads a word from memory address (base + offset) into a.drReg. The // Loads a word from memory address (base + offset) into a.drReg. The
// effective address must be 4-byte-aligned. // effective address must be 4-byte-aligned.
Self::LoadWord(a) => { Self::LoadWord(a) => {
*cpu.reg(a.r2) = cpu *cpu.reg(a.r2)? = cpu
.memory .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 // Stores a byte from SrcReg in memory address (base + offset) The effective
// address must be byte-aligned. // address must be byte-aligned.
Self::StoreByte(a) => { Self::StoreByte(a) => {
cpu.memory.write_byte( cpu.memory.write_byte(
cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r2)? + u32::from(a.immediate),
cpu.get(a.r1) as u8, cpu.get(a.r1)? as u8,
)?; )?;
} }
@@ -259,149 +264,147 @@ impl Executable for Instruction {
// effective address must be 2-byte-aligned. // effective address must be 2-byte-aligned.
Self::StoreHalfword(a) => { Self::StoreHalfword(a) => {
// split the value into bytes and then write two bytes // 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 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 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 // Stores a word from SrcReg in memory address (base + offset) The effective
// address must be 4-byte-aligned. // address must be 4-byte-aligned.
Self::StoreWord(a) => { Self::StoreWord(a) => {
cpu.memory cpu.memory.write_word(
.write_word(cpu.get(a.r2) + u32::from(a.immediate), cpu.get(a.r1))?; 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 // Loads a 16-bit literal value into reg, setting the bottom 16 bits of the
// word. To populate the upper 16 bits, see LUI. // word. To populate the upper 16 bits, see LUI.
Self::LoadLowerImmediate(a) => { 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. // Loads a 16-bit literal value into reg, setting the top 16 bits of the word.
// To populate the lower 16 bits, see LLI. // To populate the lower 16 bits, see LLI.
Self::LoadUpperImmediate(a) => { Self::LoadUpperImmediate(a) => {
*cpu.reg(a.r1) = *cpu.reg(a.r1)? =
(cpu.get(a.r1) & 0x0000_FFFF) | (u32::from(a.immediate) << 16); (cpu.get(a.r1)? & 0x0000_FFFF) | (u32::from(a.immediate) << 16);
} }
// Unconditionally jumps to the calculated address or direct address // 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. // Jumps to the calculated address or direct address if equal flag set.
Self::JumpEq(a) => { Self::JumpEq(a) => {
if cpu.get_flag(Flag::Equal) { if cpu.get_flag(Flag::Equal)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Jumps to the calculated address or direct address if equal flag not set. // Jumps to the calculated address or direct address if equal flag not set.
Self::JumpNeq(a) => { Self::JumpNeq(a) => {
if !cpu.get_flag(Flag::Equal) { if !cpu.get_flag(Flag::Equal)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Jumps to the calculated address or direct address if greater than flag set. // Jumps to the calculated address or direct address if greater than flag set.
Self::JumpGt(a) => { Self::JumpGt(a) => {
if cpu.get_flag(Flag::GreaterThan) { if cpu.get_flag(Flag::GreaterThan)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Jumps to the calculated address or direct address if greater than flag or // Jumps to the calculated address or direct address if greater than flag or
// equal flag set. // equal flag set.
Self::JumpGe(a) => { Self::JumpGe(a) => {
if cpu.get_flag(Flag::GreaterThan) || cpu.get_flag(Flag::Equal) { if cpu.get_flag(Flag::GreaterThan)? || cpu.get_flag(Flag::Equal)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Jumps to the calculated address or direct address if less than flag set. // Jumps to the calculated address or direct address if less than flag set.
Self::JumpLt(a) => { Self::JumpLt(a) => {
if cpu.get_flag(Flag::LessThan) { if cpu.get_flag(Flag::LessThan)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Jumps to the calculated address or direct address if less than flag or // Jumps to the calculated address or direct address if less than flag or
// equal flag set. // equal flag set.
Self::JumpLe(a) => { Self::JumpLe(a) => {
if cpu.get_flag(Flag::LessThan) || cpu.get_flag(Flag::Equal) { if cpu.get_flag(Flag::LessThan)? || cpu.get_flag(Flag::Equal)? {
cpu.jump(a.r1, a.immediate); cpu.jump(a.r1, a.immediate)?;
} }
} }
// Increments the value in the given register // 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 // 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 // Left shifts the value in Reg by the given amount (either a register, or a
// literal value) // literal value)
Self::ShiftLeft(a) => { Self::ShiftLeft(a) => {
let regval = cpu.get(a.sr2); let reg = cpu.get(a.sr1)?;
let val = cpu.get(a.sr1); let val = a.shamt;
*cpu.reg(a.sr1)? = shl(reg, val);
*cpu.reg(a.sr1) =
shl(val, if regval != 0 { regval as u8 } else { a.shamt });
} }
// Right shifts the value in Reg by the given amount (either a register, or a // Right shifts the value in Reg by the given amount (either a register, or a
// literal value). // literal value).
Self::ShiftRight(a) => { Self::ShiftRight(a) => {
let regval = cpu.get(a.sr2); let regval = cpu.get(a.sr1)?;
let val = cpu.get(a.sr1); let val = a.shamt;
*cpu.reg(a.sr1)? = shr(regval, val);
*cpu.reg(a.sr1) =
shr(val, if regval != 0 { regval as u8 } else { a.shamt });
} }
// Adds the value of Src2 to Src1 and writes the result to a.dr // Adds the value of Src2 to Src1 and writes the result to a.dr
Self::Add(a) => { 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 // Subtracts the value of Src2 from Src1 and writes the result to a.dr
Self::Sub(a) => { 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) => { 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) => { 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 // 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 // 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 // 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 // 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 // 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 // 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 // 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 // Compares the value of Reg1 to the value in Reg2. The results of the
// comparisons are set in the Status register. // comparisons are set in the Status register.
Self::Compare(a) => { 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. // Initiates an interrupt with the given 8 bit interrupt code.
+14 -6
View File
@@ -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; let instructions = state.instructions;
ui.label(format!("Instructions: {instructions}")); ui.label(format!("Instructions: {instructions}"));
ui.label(format!("PC: 0x{pcx:08X}")); ui.label(format!("PC: 0x{pcx:08X}"));
let instruction = Instruction::decode(state.reg_file.get(Register::Cir)) let instruction = Instruction::decode(
.map_or_else( state
|_| "Invalid Instruction".to_string(), .reg_file
|instruction| instruction.to_string(), .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}")); ui.label(format!("Instruction: {instruction}"));
}); });
+1 -1
View File
@@ -61,7 +61,7 @@ impl Component for StackInspector {
ui.label(format!( ui.label(format!(
"{} [{}]", "{} [{}]",
i, 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.label(format!("0x{value:08X} ({value})"));
ui.end_row(); ui.end_row();
+40 -17
View File
@@ -82,14 +82,48 @@ print_byte:
// ------------------------------------------ // ------------------------------------------
// prints the value of arg[0] to the screen in hex. // 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: print_hex_byte:
push bpr push bpr
mov spr, bpr mov spr, bpr
// put arg byte in rg0
ldw bpr, rg0, 8 ldw bpr, rg0, 8
ldw current, rg1 ldw current, rg1
call _print_hex_byte
jmp _end
// function body
_print_hex_byte:
// mask to get lower nibble // mask to get lower nibble
lli 0xF, rg2 lli 0xF, rg2
// save rg0 state // save rg0 state
@@ -102,8 +136,9 @@ print_hex_byte:
and rg0, rg2, rg0 and rg0, rg2, rg0
call _print_hex_nibble call _print_hex_nibble
jmp _end return
// print a hex digit
_print_hex_nibble: _print_hex_nibble:
lli 10, rg3 lli 10, rg3
cmp rg0, rg3 cmp rg0, rg3
@@ -111,26 +146,14 @@ _print_hex_nibble:
addi rg0, 0x37, rg0 addi rg0, 0x37, rg0
stb rg0, rg1 stb rg0, rg1
addi rg1, 1 addi rg1, 1
jmp _end return
// helper function.
_print_hex_nibble_number: _print_hex_nibble_number:
addi rg0, 0x30, rg0 addi rg0, 0x30, rg0
stb rg0, rg1 stb rg0, rg1
addi rg1, 1 addi rg1, 1
jmp _end return
// ------------------------------------------
// 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
// ------------------------------------------ // ------------------------------------------
// resets the cursor position on the screen to 0x20000. (0,0) // resets the cursor position on the screen to 0x20000. (0,0)
+2 -2
View File
@@ -16,9 +16,9 @@ start:
stw rg0, idr, 4 stw rg0, idr, 4
lli 0x20, rg0 lwi 0x1234abcd, rg0
push rg0 push rg0
call print::print_hex_byte call print::print_hex_word
pop zero pop zero
hlt hlt
Binary file not shown.