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:
Vendored
+1
-1
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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!(
|
||||||
|
|||||||
@@ -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)),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -133,13 +133,21 @@ 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(
|
||||||
|
state
|
||||||
|
.reg_file
|
||||||
|
.get(Register::Cir)
|
||||||
|
.expect("CIR should never be invalid"),
|
||||||
|
)
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|_| "Invalid Instruction".to_string(),
|
|_| "Invalid Instruction".to_string(),
|
||||||
|instruction| instruction.to_string(),
|
|instruction| instruction.to_string(),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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.
Reference in New Issue
Block a user