aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2017-11-21 23:37:09 +0100
committerKarel Kočí <cynerd@email.cz>2017-11-21 23:37:09 +0100
commit054225612d13e9a32b7900e423590367b5969b6e (patch)
treeb5ea0b5ea8cb6417f855803ec4fc71d0cb79bc99
parentc4efaa81d4bf498c721db5cdbf932e7a3bcb0cae (diff)
downloadqtmips-054225612d13e9a32b7900e423590367b5969b6e.tar.gz
qtmips-054225612d13e9a32b7900e423590367b5969b6e.tar.bz2
qtmips-054225612d13e9a32b7900e423590367b5969b6e.zip
Implement some immediate arithmetic instructions
-rw-r--r--instructions.md8
-rw-r--r--qtmips_machine/core.cpp102
-rw-r--r--qtmips_machine/core.h6
-rw-r--r--qtmips_machine/tests/testcore.cpp16
4 files changed, 71 insertions, 61 deletions
diff --git a/instructions.md b/instructions.md
index a3ee0a0..81a0d76 100644
--- a/instructions.md
+++ b/instructions.md
@@ -11,8 +11,8 @@ Explanation of checkboxes:
CPU Arithmetic Instruction
--------------------------
* [-] ADD
-* [ ] ADDI
-* [ ] ADDIU
+* [-] ADDI
+* [-] ADDIU
* [-] ADDU
* [ ] CLO
* [ ] CLZ
@@ -26,8 +26,8 @@ CPU Arithmetic Instruction
* [ ] MULT
* [ ] MULTU
* [-] SLT
-* [ ] SLTI
-* [ ] SLTIU
+* [-] SLTI
+* [-] SLTIU
* [?] SLTU
* [-] SUB
* [-] SUBU
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index a7c5d20..c79801c 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -1,33 +1,41 @@
#include "core.h"
#include "programloader.h"
+#define DM_SUPPORTED (1L<<0)
+#define DM_MEM2REG (1L<<1)
+#define DM_MEMWRITE (1L<<2)
+#define DM_ALUSRC (1L<<3)
+#define DM_REGD (1L<<4)
+#define DM_REGWRITE (1L<<5)
+#define DM_BRANCH (1L<<6)
+
struct DecodeMap {
- bool supported, mem2reg, memwrite, alubimm, regd, regwrite, branch;
+ long flags;
+ enum AluOp alu;
};
// This is temporally operation place holder
-#define NOPE { .supported = false }
+#define NOPE { .flags = 0, .alu = ALU_OP_SLL }
// This is map from opcode to signals.
static const struct DecodeMap dmap[] = {
- { .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
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // JAL
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BEQ
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BNE
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BLEZ
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BGTZ
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDI
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDIU
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTI
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTIU
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ANDI
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ORI
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // XORI
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LUI
+ { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, .alu = ALU_OP_SLL }, // Alu operations
+ NOPE, // Branch on alu operations
+ NOPE, // J
+ NOPE, // JAL
+ NOPE, // BEQ
+ NOPE, // BNE
+ NOPE, // BLEZ
+ NOPE, // BGTZ
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_ADD }, // ADDI
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_ADDU }, // ADDIU
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_SLT }, // SLTI
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_SLTU }, // SLTIU
+ NOPE, // ANDI
+ NOPE, // ORI
+ NOPE, // XORI
+ NOPE, // LUI
NOPE, // 16
NOPE, // 17
NOPE, // 18
@@ -44,21 +52,21 @@ static const struct DecodeMap dmap[] = {
NOPE, // 29
NOPE, // 30
NOPE, // 31
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LB
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LH
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWL
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LW
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LBU
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LHU
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWR
+ NOPE, // LB
+ NOPE, // LH
+ NOPE, // LWL
+ NOPE, // LW
+ NOPE, // LBU
+ NOPE, // LHU
+ NOPE, // LWR
NOPE, // 39
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SB
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SH
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWL
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SW
+ NOPE, // SB
+ NOPE, // SH
+ NOPE, // SWL
+ NOPE, // SW
NOPE, // 44
NOPE, // 45
- { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWR
+ NOPE, // SWR
NOPE, // 47
NOPE, // 48
NOPE, // 49
@@ -94,27 +102,19 @@ struct Core::dtFetch Core::fetch() {
struct Core::dtDecode Core::decode(struct dtFetch dt) {
struct DecodeMap dec = dmap[dt.inst.opcode()];
- if (!dec.supported)
+ if (!dec.flags & DM_SUPPORTED)
// TODO message
throw QTMIPS_EXCEPTION(UnsupportedInstruction, "", "");
- // 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,
- .regd = dec.regd,
- .regwrite = dec.regwrite,
- .branch = dec.branch,
- .aluop = d_alu,
+ .mem2reg = dec.flags & DM_MEM2REG,
+ .memwrite = dec.flags & DM_MEMWRITE,
+ .alusrc = dec.flags & DM_ALUSRC,
+ .regd = dec.flags & DM_REGD,
+ .regwrite = dec.flags & DM_REGWRITE,
+ .branch = dec.flags & DM_BRANCH,
+ .aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : dec.alu,
.val_rs = regs->read_gp(dt.inst.rs()),
.val_rt = regs->read_gp(dt.inst.rt()),
};
@@ -125,23 +125,23 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {
// TODO signals
return {
- .mem2reg = dt.mem2reg,
+ .regwrite = dt.regwrite,
.rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(),
- .alu_val = alu_operate(dt.aluop, dt.val_rs, 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()),
};
}
struct Core::dtMemory Core::memory(struct dtExecute dt) {
// TODO signals
return {
- .mem2reg = dt.mem2reg,
+ .regwrite = dt.regwrite,
.rwrite = dt.rwrite,
.alu_val = dt.alu_val,
};
}
void Core::writeback(struct dtMemory dt) {
- if (dt.mem2reg) {
+ if (dt.regwrite) {
regs->write_gp(dt.rwrite, dt.alu_val);
}
}
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index 5dd5726..9829741 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -28,7 +28,7 @@ protected:
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)
+ bool alusrc; // If second value to alu is immediate value (rt used otherwise)
bool regd; // If rd is used (otherwise rt is used for write target)
bool regwrite; // If output should be written back to register (which one depends on regd)
bool branch; // If this is branch instruction
@@ -37,13 +37,13 @@ protected:
std::uint32_t val_rt; // Value from register rt
};
struct dtExecute {
- bool mem2reg;
+ bool regwrite;
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;
+ bool regwrite;
std::uint8_t rwrite;
std::uint32_t alu_val;
// TODO
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index f4a3e4b..3a48f1d 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -20,6 +20,12 @@ void MachineTests::core_regs_data() {
QTest::newRow("ADDU") << Instruction(0, 24, 25, 26, 0, 33) \
<< regs_init \
<< regs_res;
+ QTest::newRow("ADDI") << Instruction(8, 24, 26, 12) \
+ << regs_init \
+ << regs_res;
+ QTest::newRow("ADDIU") << Instruction(9, 24, 26, 12) \
+ << regs_init \
+ << regs_res;
regs_res.write_gp(26, 12);
QTest::newRow("SUB") << Instruction(0, 24, 25, 26, 0, 34) \
<< regs_init \
@@ -40,6 +46,12 @@ void MachineTests::core_regs_data() {
QTest::newRow("SLTU") << Instruction(0, 24, 25, 26, 0, 43) \
<< regs_init \
<< regs_res;
+ QTest::newRow("SLTI") << Instruction(10, 24, 26, 24) \
+ << regs_init \
+ << regs_res;
+ QTest::newRow("SLTIU") << Instruction(11, 24, 26, 24) \
+ << regs_init \
+ << regs_res;
}
// Shift instructions
@@ -79,10 +91,8 @@ void MachineTests::core_regs_data() {
// TODO test other operations
}
-/*
#include <iostream>
using namespace std;
-*/
void MachineTests::core_regs() {
QFETCH(Instruction, i);
@@ -98,7 +108,7 @@ void MachineTests::core_regs() {
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
- //cout << "well:" << hex << regs_single.read_gp(26) << endl;
+ cout << "well:" << regs_single.read_gp(26) << endl;
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