aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2017-11-25 16:14:19 +0100
committerKarel Kočí <cynerd@email.cz>2017-11-25 16:14:19 +0100
commit8f6d939e8d0fdec39c53da65cfb89f288d99eb82 (patch)
treecadb68d5720dd7d682e9492f72fea7239248862c
parentafa9e930255b3c380ad37fccc0767508534bad13 (diff)
downloadqtmips-8f6d939e8d0fdec39c53da65cfb89f288d99eb82.tar.gz
qtmips-8f6d939e8d0fdec39c53da65cfb89f288d99eb82.tar.bz2
qtmips-8f6d939e8d0fdec39c53da65cfb89f288d99eb82.zip
Implement instructions for moving from and to HI and LO registers
-rw-r--r--instructions.md8
-rw-r--r--qtmips_machine/alu.cpp12
-rw-r--r--qtmips_machine/alu.h8
-rw-r--r--qtmips_machine/core.cpp2
-rw-r--r--qtmips_machine/tests/testalu.cpp67
-rw-r--r--qtmips_machine/tests/testcore.cpp35
6 files changed, 118 insertions, 14 deletions
diff --git a/instructions.md b/instructions.md
index bfd936e..7682226 100644
--- a/instructions.md
+++ b/instructions.md
@@ -86,10 +86,10 @@ CPU Logical Instructions
CPU Move Instruction
--------------------
-* [ ] MFHI
-* [ ] MFLO
-* [ ] MTHI
-* [ ] MTHO
+* [x] MFHI
+* [x] MFLO
+* [x] MTHI
+* [x] MTHO
* [ ] MOVN
* [ ] MOVZ
* MOVF, MOVT won't be implemented as floating coprocessor won't be implemented
diff --git a/qtmips_machine/alu.cpp b/qtmips_machine/alu.cpp
index 554874a..07e174e 100644
--- a/qtmips_machine/alu.cpp
+++ b/qtmips_machine/alu.cpp
@@ -1,7 +1,7 @@
#include "alu.h"
#include "qtmipsexception.h"
-std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa) {
+std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa, Registers *regs) {
switch(operation) {
case ALU_OP_SLL:
return t << sa;
@@ -17,6 +17,16 @@ std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t
case ALU_OP_SRAV:
// TODO is this correct implementation? (Should we be masking top most bit?)
return ((t & 0x7fffffff) >> s) | (t & 0x80000000);
+ case ALU_OP_MFHI:
+ return regs->read_hi_lo(true);
+ case ALU_OP_MTHI:
+ regs->write_hi_lo(true, s);
+ return 0x0;
+ case ALU_OP_MFLO:
+ return regs->read_hi_lo(false);
+ case ALU_OP_MTLO:
+ regs->write_hi_lo(false, s);
+ return 0x0;
case ALU_OP_ADD:
if (s > (0xFFFFFFFF - t))
throw QTMIPS_EXCEPTION(Overflow, "ADD operation overflow/underflow", QString::number(s) + QString(" + ") + QString::number(t));
diff --git a/qtmips_machine/alu.h b/qtmips_machine/alu.h
index 2e30ee9..2c311d2 100644
--- a/qtmips_machine/alu.h
+++ b/qtmips_machine/alu.h
@@ -4,6 +4,7 @@
#include <cstdint>
#include <QString>
#include <QObject>
+#include <registers.h>
// TODO Any other operations? We seems to be missing a lot of them.
enum AluOp : std::uint8_t {
@@ -13,6 +14,10 @@ enum AluOp : std::uint8_t {
ALU_OP_SLLV,
ALU_OP_SRLV = 6,
ALU_OP_SRAV,
+ ALU_OP_MFHI = 16,
+ ALU_OP_MTHI,
+ ALU_OP_MFLO,
+ ALU_OP_MTLO,
ALU_OP_ADD = 32,
ALU_OP_ADDU,
ALU_OP_SUB,
@@ -31,8 +36,9 @@ enum AluOp : std::uint8_t {
// s: Loaded from rs. Also calles as source.
// t: Loaded from rt or immediate field from instruction it self. Also called as target.
// sa: This is value directly from instruction it self (sa section) used for shift operations
+// regs: Registers used. We need direct access to lo and hi registers (those are not accessed from core it self but from alu directly
// Returned value is commonly saved to rt/rd or any other way passed trough core
-std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa);
+std::uint32_t alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa, Registers *regs);
// Returns string representation of ALU instruction (internally used by Instruction::to_str)
QString alu_str(enum AluOp operation, std::uint32_t s, std::uint32_t t, std::uint8_t sa);
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index 75690a3..1008886 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -129,7 +129,7 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {
return {
.regwrite = dt.regwrite,
.rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(),
- .alu_val = alu_operate(dt.aluop, dt.val_rs, dt.alusrc ? dt.inst.immediate() : dt.val_rt, dt.inst.shamt()),
+ .alu_val = alu_operate(dt.aluop, dt.val_rs, dt.alusrc ? dt.inst.immediate() : dt.val_rt, dt.inst.shamt(), regs),
};
}
diff --git a/qtmips_machine/tests/testalu.cpp b/qtmips_machine/tests/testalu.cpp
index aad101f..b45a317 100644
--- a/qtmips_machine/tests/testalu.cpp
+++ b/qtmips_machine/tests/testalu.cpp
@@ -7,58 +7,117 @@ void MachineTests::alu_data() {
QTest::addColumn<std::uint32_t>("s");
QTest::addColumn<std::uint32_t>("t");
QTest::addColumn<std::uint8_t>("sa");
+ QTest::addColumn<Registers>("regs_init");
+ QTest::addColumn<Registers>("regs_res");
QTest::addColumn<std::uint32_t>("res");
// TODO SLL-SRAV
+ {
+ Registers init;
+ init.write_hi_lo(true, 42);
+ init.write_hi_lo(false, 24);
+ Registers res(init);
+ QTest::newRow("MFHI") << ALU_OP_MFHI \
+ << (std::uint32_t)0 \
+ << (std::uint32_t)0 \
+ << (std::uint8_t)0 \
+ << init \
+ << res \
+ << (std::uint32_t)42;
+ QTest::newRow("MFLO") << ALU_OP_MFLO \
+ << (std::uint32_t)0 \
+ << (std::uint32_t)0 \
+ << (std::uint8_t)0 \
+ << init \
+ << res \
+ << (std::uint32_t)24;
+ res.write_hi_lo(true, 43);
+ QTest::newRow("MTHI") << ALU_OP_MTHI \
+ << (std::uint32_t)43 \
+ << (std::uint32_t)0 \
+ << (std::uint8_t)0 \
+ << init \
+ << res \
+ << (std::uint32_t)0;
+ res.write_hi_lo(true, 42);
+ res.write_hi_lo(false, 23);
+ QTest::newRow("MTLO") << ALU_OP_MTLO \
+ << (std::uint32_t)23 \
+ << (std::uint32_t)0 \
+ << (std::uint8_t)0 \
+ << init \
+ << res \
+ << (std::uint32_t)0;
+ }
QTest::newRow("ADD") << ALU_OP_ADD \
<< (std::uint32_t)24 \
<< (std::uint32_t)66 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)90;
QTest::newRow("ADDU") << ALU_OP_ADDU \
<< (std::uint32_t)24 \
<< (std::uint32_t)66 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)90;
QTest::newRow("SUB") << ALU_OP_SUB \
<< (std::uint32_t)66 \
<< (std::uint32_t)24 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)42;
QTest::newRow("SUBU") << ALU_OP_SUBU \
<< (std::uint32_t)24 \
<< (std::uint32_t)66 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)-42;
QTest::newRow("AND") << ALU_OP_AND \
<< (std::uint32_t)0xA81 \
<< (std::uint32_t)0x603 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)0x201;
QTest::newRow("OR") << ALU_OP_OR \
<< (std::uint32_t)0xA81 \
<< (std::uint32_t)0x603 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)0xE83;
QTest::newRow("XOR") << ALU_OP_XOR \
<< (std::uint32_t)0xA81 \
<< (std::uint32_t)0x603 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)0xC82;
QTest::newRow("NOR") << ALU_OP_NOR \
<< (std::uint32_t)0xA81 \
<< (std::uint32_t)0x603 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)0xFFFFF17C;
QTest::newRow("SLT") << ALU_OP_SLT \
<< (std::uint32_t)-31 \
<< (std::uint32_t)24 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)1;
QTest::newRow("SLTU") << ALU_OP_SLTU \
<< (std::uint32_t)24 \
<< (std::uint32_t)32 \
<< (std::uint8_t)0 \
+ << Registers() \
+ << Registers() \
<< (std::uint32_t)1;
}
@@ -67,9 +126,12 @@ void MachineTests::alu() {
QFETCH(std::uint32_t, s);
QFETCH(std::uint32_t, t);
QFETCH(std::uint8_t, sa);
+ QFETCH(Registers, regs_init);
+ QFETCH(Registers, regs_res);
QFETCH(std::uint32_t, res);
- QCOMPARE(alu_operate(op, s , t, sa), res);
+ QCOMPARE(alu_operate(op, s , t, sa, &regs_init), res);
+ QCOMPARE(regs_res, regs_init);
}
void MachineTests::alu_except_data() {
@@ -94,7 +156,8 @@ void MachineTests::alu_except() {
QFETCH(std::uint8_t, op);
QFETCH(std::uint32_t, s);
QFETCH(std::uint32_t, t);
+ Registers regs;
// Only runtime exception is expected as any other exception is a bug
- QVERIFY_EXCEPTION_THROWN(alu_operate((enum AluOp)op, s , t, 0), QtMipsExceptionRuntime);
+ QVERIFY_EXCEPTION_THROWN(alu_operate((enum AluOp)op, s , t, 0, &regs), QtMipsExceptionRuntime);
}
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index 31f61ab..835dd2c 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -121,6 +121,34 @@ static void core_regs_data() {
<< regs_init \
<< regs_res;
}
+
+ // Move instructions
+ {
+ Registers regs_init;
+ regs_init.write_hi_lo(true, 24);
+ regs_init.write_hi_lo(false, 28);
+ regs_init.write_gp(27, 21);
+ regs_init.write_gp(28, 22);
+ Registers regs_res(regs_init);
+ regs_res.write_gp(26, 24);
+ QTest::newRow("MFHI") << Instruction(0, 0, 0, 26, 0, 16) \
+ << regs_init \
+ << regs_res;
+ regs_res.write_gp(26, 28);
+ QTest::newRow("MFLO") << Instruction(0, 0, 0, 26, 0, 18) \
+ << regs_init \
+ << regs_res;
+ regs_res.write_gp(26, 0);
+ regs_res.write_hi_lo(true, 21);
+ QTest::newRow("MTHI") << Instruction(0, 27, 0, 0, 0, 17) \
+ << regs_init \
+ << regs_res;
+ regs_res.write_hi_lo(true, 24);
+ regs_res.write_hi_lo(false, 22);
+ QTest::newRow("MTLO") << Instruction(0, 28, 0, 0, 0, 19) \
+ << regs_init \
+ << regs_res;
+ }
}
void MachineTests::singlecore_regs_data() {
@@ -160,20 +188,17 @@ void MachineTests::pipecore_regs() {
mem.write_word(res.read_pc(), i.data()); // Store single instruction (anything else should be 0 so NOP effectively)
Memory mem_used(mem);
- Registers regs_used(init);
res.pc_jmp(0x14);
- CorePipelined core(&regs_used, &mem_used);
+ CorePipelined core(&init, &mem_used);
for (int i = 0; i < 4; i++) {
core.step(); // Fire steps for five pipelines stages
- init.pc_inc();
- QCOMPARE(init, regs_used); // Untill writeback there should be no change in registers
}
core.step();
//cout << "well:" << init.read_gp(26) << ":" << regs_used.read_gp(26) << endl;
- QCOMPARE(regs_used, res); // After doing changes from initial state this should be same state as in case of passed expected result
+ QCOMPARE(init, res); // After doing changes from initial state this should be same state as in case of passed expected result
QCOMPARE(mem, mem_used); // There should be no change in memory
}