|
|
|
@@ -8,7 +8,9 @@ use crate::emulator::system::{
|
|
|
|
|
model::{IODevice, RegFile},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use common::instructions::{Instruction, Interrupt, Register, errors::InstructionDecodeError};
|
|
|
|
|
use common::instructions::{
|
|
|
|
|
Instruction, Interrupt, Register, errors::InstructionDecodeError,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub struct Processor {
|
|
|
|
|
pub memory: Box<dyn MemoryUnit>,
|
|
|
|
@@ -168,71 +170,90 @@ impl Executable for Instruction {
|
|
|
|
|
*cpu.reg(a.dr) = cpu.get(a.sr1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copies from SrcReg to a.drReg, sign extending the value to take up a full word.
|
|
|
|
|
// Copies from SrcReg to a.drReg, sign extending the value to take up a full
|
|
|
|
|
// word.
|
|
|
|
|
Self::MovSigned(a) => {
|
|
|
|
|
*cpu.reg(a.dr) = sign_extend(cpu.get(a.sr1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a byte from memory address (base + offset) into a.drReg. The effective address must be byte-aligned.
|
|
|
|
|
// Loads a byte from memory address (base + offset) into a.drReg. The
|
|
|
|
|
// effective address must be byte-aligned.
|
|
|
|
|
Self::LoadByte(a) => {
|
|
|
|
|
*cpu.reg(a.r2) =
|
|
|
|
|
u32::from(cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)));
|
|
|
|
|
*cpu.reg(a.r2) = u32::from(
|
|
|
|
|
cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a sign-extended byte from memory address (base + offset) into a.drReg. The effective address must be byte-aligned.
|
|
|
|
|
// Loads a sign-extended byte from memory address (base + offset) into
|
|
|
|
|
// a.drReg. The effective address must be byte-aligned.
|
|
|
|
|
Self::LoadByteSigned(a) => {
|
|
|
|
|
*cpu.reg(a.r2) = sign_extend(u32::from(
|
|
|
|
|
cpu.memory.read_byte(cpu.get(a.r1) + u32::from(a.immediate)),
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a half-word from memory address (base + offset) into a.drReg. The effective address must be 2-byte-aligned.
|
|
|
|
|
// Loads a half-word from memory address (base + offset) into a.drReg. The
|
|
|
|
|
// effective address must be 2-byte-aligned.
|
|
|
|
|
Self::LoadHalfword(a) => {
|
|
|
|
|
// we read an entire word, then right shift so we only get the first half of the word
|
|
|
|
|
*cpu.reg(a.r2) = cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a sign-extended half-word from memory address (base + offset) into a.drReg. The effective address must be 2-byte-aligned.
|
|
|
|
|
Self::LoadHalfwordSigned(a) => {
|
|
|
|
|
// we read an entire word, then right shift so we only get the first half
|
|
|
|
|
// of the word
|
|
|
|
|
*cpu.reg(a.r2) =
|
|
|
|
|
sign_extend(cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16);
|
|
|
|
|
cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a word from memory address (base + offset) into a.drReg. The effective address must be 4-byte-aligned.
|
|
|
|
|
// Loads a sign-extended half-word from memory address (base + offset) into
|
|
|
|
|
// a.drReg. The effective address must be 2-byte-aligned.
|
|
|
|
|
Self::LoadHalfwordSigned(a) => {
|
|
|
|
|
*cpu.reg(a.r2) = sign_extend(
|
|
|
|
|
cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate)) >> 16,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a word from memory address (base + offset) into a.drReg. The
|
|
|
|
|
// effective address must be 4-byte-aligned.
|
|
|
|
|
Self::LoadWord(a) => {
|
|
|
|
|
*cpu.reg(a.r2) = cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate));
|
|
|
|
|
*cpu.reg(a.r2) =
|
|
|
|
|
cpu.memory.read_word(cpu.get(a.r1) + u32::from(a.immediate));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stores a byte from SrcReg in memory address (base + offset) The effective address must be byte-aligned.
|
|
|
|
|
// Stores a byte from SrcReg in memory address (base + offset) The effective
|
|
|
|
|
// address must be byte-aligned.
|
|
|
|
|
Self::StoreByte(a) => {
|
|
|
|
|
cpu.memory
|
|
|
|
|
.write_byte(cpu.get(a.r1) + u32::from(a.immediate), cpu.get(a.r2) as u8);
|
|
|
|
|
cpu.memory.write_byte(
|
|
|
|
|
cpu.get(a.r1) + u32::from(a.immediate),
|
|
|
|
|
cpu.get(a.r2) as u8,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stores a half-word from SrcReg in memory address (base + offset) The effective address must be 2-byte-aligned.
|
|
|
|
|
// Stores a half-word from SrcReg in memory address (base + offset) The
|
|
|
|
|
// effective address must be 2-byte-aligned.
|
|
|
|
|
Self::StoreHalfword(a) => {
|
|
|
|
|
// split the value into bytes and then write two bytes
|
|
|
|
|
let bytes = (cpu.get(a.r1) as u16).to_be_bytes();
|
|
|
|
|
let bytes = (cpu.get(a.r1) as u16).to_le_bytes();
|
|
|
|
|
cpu.memory
|
|
|
|
|
.write_byte(cpu.get(a.r1) + u32::from(a.immediate), bytes[0]);
|
|
|
|
|
cpu.memory
|
|
|
|
|
.write_byte(cpu.get(a.r1) + u32::from(a.immediate) + 1, bytes[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stores a word from SrcReg in memory address (base + offset) The effective address must be 4-byte-aligned.
|
|
|
|
|
// Stores a word from SrcReg in memory address (base + offset) The effective
|
|
|
|
|
// address must be 4-byte-aligned.
|
|
|
|
|
Self::StoreWord(a) => {
|
|
|
|
|
cpu.memory
|
|
|
|
|
.write_word(cpu.get(a.r1) + u32::from(a.immediate), cpu.get(a.r2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a 16-bit literal value into reg, setting the bottom 16 bits of the word. To populate the upper 16 bits, see LUI.
|
|
|
|
|
// Loads a 16-bit literal value into reg, setting the bottom 16 bits of the
|
|
|
|
|
// word. To populate the upper 16 bits, see LUI.
|
|
|
|
|
Self::LoadLowerImmediate(a) => {
|
|
|
|
|
*cpu.reg(a.r1) = u32::from(a.immediate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Loads a 16-bit literal value into reg, setting the top 16 bits of the word. To populate the lower 16 bits, see LLI.
|
|
|
|
|
// Loads a 16-bit literal value into reg, setting the top 16 bits of the word.
|
|
|
|
|
// To populate the lower 16 bits, see LLI.
|
|
|
|
|
Self::LoadUpperImmediate(a) => {
|
|
|
|
|
*cpu.reg(a.r1) = (cpu.get(a.r1) & 0x0000_FFFF) | u32::from(a.immediate) << 16;
|
|
|
|
|
*cpu.reg(a.r1) =
|
|
|
|
|
(cpu.get(a.r1) & 0x0000_FFFF) | u32::from(a.immediate) << 16;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unconditionally jumps to the calculated address or direct address
|
|
|
|
@@ -259,7 +280,8 @@ impl Executable for Instruction {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jumps to the calculated address or direct address if greater than flag or equal flag set.
|
|
|
|
|
// Jumps to the calculated address or direct address if greater than flag or
|
|
|
|
|
// equal flag set.
|
|
|
|
|
Self::JumpGe(a) => {
|
|
|
|
|
if cpu.get_flag(Flag::GreaterThan) || cpu.get_flag(Flag::Equal) {
|
|
|
|
|
cpu.jump(a.r1, a.immediate);
|
|
|
|
@@ -273,7 +295,8 @@ impl Executable for Instruction {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Jumps to the calculated address or direct address if less than flag or equal flag set.
|
|
|
|
|
// Jumps to the calculated address or direct address if less than flag or
|
|
|
|
|
// equal flag set.
|
|
|
|
|
Self::JumpLe(a) => {
|
|
|
|
|
if cpu.get_flag(Flag::LessThan) || cpu.get_flag(Flag::Equal) {
|
|
|
|
|
cpu.jump(a.r1, a.immediate);
|
|
|
|
@@ -286,20 +309,24 @@ impl Executable for Instruction {
|
|
|
|
|
// Decrements the value in the given register
|
|
|
|
|
Self::Decrement(a) => *cpu.reg(a.sr1) = dec(cpu.get(a.sr1)),
|
|
|
|
|
|
|
|
|
|
// Left shifts the value in Reg by the given amount (either a register, or a literal value)
|
|
|
|
|
// Left shifts the value in Reg by the given amount (either a register, or a
|
|
|
|
|
// literal value)
|
|
|
|
|
Self::ShiftLeft(a) => {
|
|
|
|
|
let regval = cpu.get(a.sr2);
|
|
|
|
|
let val = cpu.get(a.sr1);
|
|
|
|
|
|
|
|
|
|
*cpu.reg(a.sr1) = shl(val, if regval != 0 { regval as u8 } else { a.shamt });
|
|
|
|
|
*cpu.reg(a.sr1) =
|
|
|
|
|
shl(val, if regval != 0 { regval as u8 } else { a.shamt });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Right shifts the value in Reg by the given amount (either a register, or a literal value).
|
|
|
|
|
// Right shifts the value in Reg by the given amount (either a register, or a
|
|
|
|
|
// literal value).
|
|
|
|
|
Self::ShiftRight(a) => {
|
|
|
|
|
let regval = cpu.get(a.sr2);
|
|
|
|
|
let val = cpu.get(a.sr1);
|
|
|
|
|
|
|
|
|
|
*cpu.reg(a.sr1) = shr(val, if regval != 0 { regval as u8 } else { a.shamt });
|
|
|
|
|
*cpu.reg(a.sr1) =
|
|
|
|
|
shr(val, if regval != 0 { regval as u8 } else { a.shamt });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Adds the value of Src2 to Src1 and writes the result to a.dr
|
|
|
|
@@ -333,7 +360,8 @@ impl Executable for Instruction {
|
|
|
|
|
// Performs bitwise XNOR on Src1 and Src2 storing the result in a.dr
|
|
|
|
|
Self::Xnor(a) => *cpu.reg(a.dr) = xnor(cpu.get(a.sr1), cpu.get(a.sr2)),
|
|
|
|
|
|
|
|
|
|
// Compares the value of Reg1 to the value in Reg2. The results of the comparisons are set in the Status register.
|
|
|
|
|
// Compares the value of Reg1 to the value in Reg2. The results of the
|
|
|
|
|
// comparisons are set in the Status register.
|
|
|
|
|
Self::Compare(a) => {
|
|
|
|
|
cpu.cmp(cpu.get(a.sr1), cpu.get(a.sr2));
|
|
|
|
|
}
|
|
|
|
|