aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--instructions.md7
-rw-r--r--qtmips_machine/core.cpp24
-rw-r--r--qtmips_machine/core.h9
-rw-r--r--qtmips_machine/registers.cpp12
-rw-r--r--qtmips_machine/registers.h1
-rw-r--r--qtmips_machine/tests/testcore.cpp10
-rw-r--r--qtmips_machine/tests/testregisters.cpp27
-rw-r--r--qtmips_machine/tests/tst_machine.h1
8 files changed, 70 insertions, 21 deletions
diff --git a/instructions.md b/instructions.md
index ccc16bc..bbeac20 100644
--- a/instructions.md
+++ b/instructions.md
@@ -2,9 +2,14 @@ Instructions
============
This is list of all MIPS1 instructions and their implementation status in QtMips.
+Explanation of checkboxes:
+* [ ] Not tested
+* [-] Tested non-pipelined core
+* [x] Tested on non-pipelined and pipelined core
+
CPU Arithmetic Instruction
--------------------------
-* [ ] ADD
+* [-] ADD
* [ ] ADDI
* [ ] ADDIU
* [ ] ADDU
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index 1edcc97..a7c5d20 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -11,7 +11,7 @@
// This is map from opcode to signals.
static const struct DecodeMap dmap[] = {
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = false, .regwrite = true, .branch = false }, // Alu operations and more
+ { .supported = true, .mem2reg = true, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // Alu operations
// TODO These are just copies of first one
{ .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = false, .regwrite = false, .branch = true }, // Branch on alu operations
{ .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // J
@@ -97,8 +97,17 @@ struct Core::dtDecode Core::decode(struct dtFetch dt) {
if (!dec.supported)
// TODO message
throw QTMIPS_EXCEPTION(UnsupportedInstruction, "", "");
- enum AluOp d_alu = ALU_OP_SLL; // TODO decode for real
+
+ // Prepare alu operation
+ enum AluOp d_alu;
+ if (dt.inst.opcode() == 0) {
+ d_alu = (enum AluOp)dt.inst.funct();
+ } else
+ // TODO can't we ignore this?
+ d_alu = ALU_OP_SLL; // Just set it to zero so we won't do something stupid like throw exception
+
return {
+ .inst = dt.inst,
.mem2reg = dec.mem2reg,
.memwrite = dec.memwrite,
.alubimm = dec.alubimm,
@@ -108,17 +117,17 @@ struct Core::dtDecode Core::decode(struct dtFetch dt) {
.aluop = d_alu,
.val_rs = regs->read_gp(dt.inst.rs()),
.val_rt = regs->read_gp(dt.inst.rt()),
- .val_sa = dt.inst.shamt(),
- .val_immediate = dt.inst.immediate(),
};
// TODO on jump there should be delay slot. Does processor addes it or compiler. And do we care?
}
struct Core::dtExecute Core::execute(struct dtDecode dt) {
// TODO signals
+
return {
.mem2reg = dt.mem2reg,
- .val = alu_operate(dt.aluop, dt.val_rs, dt.val_rt, dt.val_sa)
+ .rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(),
+ .alu_val = alu_operate(dt.aluop, dt.val_rs, dt.val_rt, dt.inst.shamt()),
};
}
@@ -126,13 +135,14 @@ struct Core::dtMemory Core::memory(struct dtExecute dt) {
// TODO signals
return {
.mem2reg = dt.mem2reg,
- .val = dt.val,
+ .rwrite = dt.rwrite,
+ .alu_val = dt.alu_val,
};
}
void Core::writeback(struct dtMemory dt) {
if (dt.mem2reg) {
-
+ regs->write_gp(dt.rwrite, dt.alu_val);
}
}
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index d4523c3..5dd5726 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -25,6 +25,7 @@ protected:
Instruction inst; // Loaded instruction
};
struct dtDecode {
+ Instruction inst;
bool mem2reg; // Write memory output to register (instead alu output)
bool memwrite; // If memory should write input
bool alubimm; // If b value to alu is immediate value (rt used otherwise)
@@ -34,18 +35,18 @@ protected:
enum AluOp aluop; // Decoded ALU operation
std::uint32_t val_rs; // Value from register rs
std::uint32_t val_rt; // Value from register rt
- std::uint8_t val_sa; // Value of sa in instruction it self
- std::uint16_t val_immediate; // Value of immediate in instruction it self
};
struct dtExecute {
bool mem2reg;
- std::uint32_t val;
+ std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd)
+ std::uint32_t alu_val; // Result of ALU execution
// TODO
};
struct dtMemory {
bool mem2reg;
+ std::uint8_t rwrite;
+ std::uint32_t alu_val;
// TODO
- std::uint32_t val;
};
struct dtFetch fetch();
diff --git a/qtmips_machine/registers.cpp b/qtmips_machine/registers.cpp
index 6b4ddd3..5bb852e 100644
--- a/qtmips_machine/registers.cpp
+++ b/qtmips_machine/registers.cpp
@@ -7,17 +7,17 @@
#define PC_INIT 0x80020000
//////////////////////////////////////////////////////////////////////////////
-Registers::Registers() {
+Registers::Registers() : QObject() {
this->pc = PC_INIT; // Initialize to beginning program section
for (int i = 0; i < 31; i++)
this->gp[i] = 0;
this->hi = this->lo = 0;
}
-Registers::Registers(const Registers &orig) : Registers() {
+Registers::Registers(const Registers &orig) : QObject() {
this->pc = orig.read_pc();
for (int i = 0; i < 31; i++)
- this->gp[i] = orig.read_gp(i);
+ this->gp[i] = orig.read_gp(i + 1);
this->lo = orig.read_hi_lo(false);
this->hi = orig.read_hi_lo(true);
}
@@ -74,7 +74,7 @@ void Registers::write_hi_lo(bool hi, std::uint32_t value) {
this->lo = value;
}
-bool Registers::operator ==(const Registers &c) const {
+bool Registers::operator==(const Registers &c) const {
if (read_pc() != c.read_pc())
return false;
for (int i = 0; i < 31; i++)
@@ -86,3 +86,7 @@ bool Registers::operator ==(const Registers &c) const {
return false;
return true;
}
+
+bool Registers::operator!=(const Registers &c) const {
+ return ! this->operator==(c);
+}
diff --git a/qtmips_machine/registers.h b/qtmips_machine/registers.h
index 49b4cad..387b59d 100644
--- a/qtmips_machine/registers.h
+++ b/qtmips_machine/registers.h
@@ -21,6 +21,7 @@ public:
void write_hi_lo(bool hi, std::uint32_t value);
bool operator ==(const Registers &c) const;
+ bool operator !=(const Registers &c) const;
signals:
void pc_update(std::uint32_t val);
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index 33bf07e..5320a6b 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -5,6 +5,7 @@ void MachineTests::core_regs_data() {
QTest::addColumn<Instruction>("i");
QTest::addColumn<Registers>("init");
QTest::addColumn<Registers>("res");
+ // Note that we shouldn't be touching program counter as that is handled automatically and differs if we use pipelining
// Test arithmetic instructions
{
@@ -21,9 +22,6 @@ void MachineTests::core_regs_data() {
}
void MachineTests::core_regs() {
- QTest::addColumn<Instruction>("i");
- QTest::addColumn<Registers>("init");
- QTest::addColumn<Registers>("res");
QFETCH(Instruction, i);
QFETCH(Registers, init);
QFETCH(Registers, res);
@@ -32,10 +30,12 @@ void MachineTests::core_regs() {
mem.write_word(res.read_pc(), i.data()); // Store single instruction (anything else should be 0 so NOP effectively)
// Test on non-piplined
+ res.pc_inc(); // We did single step so increment program counter accordingly
Memory mem_single(mem); // Create memory copy
- CoreSingle core_single(&init, &mem_single);
+ Registers regs_single(init); // Create registers copy
+ CoreSingle core_single(&regs_single, &mem_single);
core_single.step(); // Single step should be enought as this is risc without pipeline
- //QCOMPARE(init, res); // After doing changes from initial state this should be same state as in case of passed expected result
+ QCOMPARE(regs_single, res); // After doing changes from initial state this should be same state as in case of passed expected result
QCOMPARE(mem, mem_single); // There should be no change in memory
// TODO on pipelined core
diff --git a/qtmips_machine/tests/testregisters.cpp b/qtmips_machine/tests/testregisters.cpp
index 4430beb..b498c11 100644
--- a/qtmips_machine/tests/testregisters.cpp
+++ b/qtmips_machine/tests/testregisters.cpp
@@ -37,3 +37,30 @@ void MachineTests::registers_pc() {
QVERIFY_EXCEPTION_THROWN(r.pc_jmp(0x1), QtMipsExceptionUnalignedJump);
QVERIFY_EXCEPTION_THROWN(r.pc_abs_jmp(0x80020101), QtMipsExceptionUnalignedJump);
}
+
+void MachineTests::registers_compare() {
+ Registers r1, r2;
+ QCOMPARE(r1, r2);
+ // General purpose register
+ r1.write_gp(1, 24);
+ QVERIFY(r1 != r2);
+ r2.write_gp(1, 24);
+ QCOMPARE(r1, r2);
+ // Program counter
+ r1.pc_inc();
+ QVERIFY(r1 != r2);
+ r2.pc_inc();
+ QCOMPARE(r1, r2);
+ // LO/HI (testing just one as they have common codepath)
+ r1.write_hi_lo(false, 18);
+ QVERIFY(r1 != r2);
+ r2.write_hi_lo(false, 18);
+ QCOMPARE(r1, r2);
+ // Now let's try copy (and verify only with gp this time)
+ Registers r3(r1);
+ QCOMPARE(r3, r1);
+ r3.write_gp(12, 19);
+ QVERIFY(r1 != r3);
+ r1.write_gp(12, 19);
+ QCOMPARE(r3, r1);
+}
diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h
index b509bed..35104c4 100644
--- a/qtmips_machine/tests/tst_machine.h
+++ b/qtmips_machine/tests/tst_machine.h
@@ -11,6 +11,7 @@ private Q_SLOTS:
void registers_rw_gp();
void registers_rw_hi_lo();
void registers_pc();
+ void registers_compare();
// Memory
void memory();
void memory_data();