aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine')
-rw-r--r--qtmips_machine/core.cpp82
-rw-r--r--qtmips_machine/core.h9
-rw-r--r--qtmips_machine/tests/testcore.cpp116
-rw-r--r--qtmips_machine/tests/testmemory.cpp58
-rw-r--r--qtmips_machine/tests/tst_machine.h10
5 files changed, 236 insertions, 39 deletions
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index 5f8321d..eba423f 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -2,41 +2,41 @@
#include "programloader.h"
#define DM_SUPPORTED (1L<<0)
-#define DM_MEM2REG (1L<<1)
-#define DM_MEMWRITE (1L<<2)
+#define DM_MEMWRITE (1L<<1)
+#define DM_MEMREAD (1L<<2)
#define DM_ALUSRC (1L<<3)
#define DM_REGD (1L<<4)
#define DM_REGWRITE (1L<<5)
- struct DecodeMap {
+struct DecodeMap {
long flags;
enum AluOp alu;
+ enum MemoryAccess::AccessControl mem_ctl;
};
-
-// This is temporally operation place holder
#define NOALU .alu = ALU_OP_SLL
-#define NOPE { .flags = 0, NOALU }
+#define NOMEM .mem_ctl = MemoryAccess::AC_NONE
+#define NOPE { .flags = 0, NOALU, NOMEM }
#define FLAGS_ALU_I (DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE)
// This is map from opcode to signals.
static const struct DecodeMap dmap[] = {
- { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, NOALU }, // Alu operations (aluop is decoded from function explicitly)
- { .flags = DM_SUPPORTED, NOALU }, // REGIMM (BLTZ, BGEZ, )
- { .flags = DM_SUPPORTED, NOALU }, // J
+ { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, NOALU, NOMEM }, // Alu operations (aluop is decoded from function explicitly)
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // REGIMM (BLTZ, BGEZ, )
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // J
NOPE, // JAL
- { .flags = DM_SUPPORTED, NOALU }, // BEQ
- { .flags = DM_SUPPORTED, NOALU }, // BNE
- { .flags = DM_SUPPORTED, NOALU }, // BLEZ
- { .flags = DM_SUPPORTED, NOALU }, // BGTZ
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADD }, // ADDI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADDU }, // ADDIU
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLT }, // SLTI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLTU }, // SLTIU
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_AND }, // ANDI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_OR }, // ORI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_XOR }, // XORI
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BEQ
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BNE
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BLEZ
+ { .flags = DM_SUPPORTED, NOALU, NOMEM }, // BGTZ
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADD, NOMEM }, // ADDI
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADDU, NOMEM }, // ADDIU
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLT, NOMEM }, // SLTI
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLTU, NOMEM }, // SLTIU
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_AND, NOMEM }, // ANDI
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_OR, NOMEM }, // ORI
+ { .flags = FLAGS_ALU_I, .alu = ALU_OP_XOR, NOMEM }, // XORI
NOPE, // LUI
NOPE, // 16
NOPE, // 17
@@ -54,18 +54,18 @@ static const struct DecodeMap dmap[] = {
NOPE, // 29
NOPE, // 30
NOPE, // 31
- NOPE, // LB
- NOPE, // LH
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE }, // LB
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD }, // LH
NOPE, // LWL
- NOPE, // LW
- NOPE, // LBU
- NOPE, // LHU
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_WORD }, // LW
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE_UNSIGNED }, // LBU
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD_UNSIGNED }, // LHU
NOPE, // LWR
NOPE, // 39
- NOPE, // SB
- NOPE, // SH
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_BYTE }, // SB
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_HALFWORD }, // SH
NOPE, // SWL
- NOPE, // SW
+ { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADD, .mem_ctl = MemoryAccess::AC_WORD }, // SW
NOPE, // 44
NOPE, // 45
NOPE, // SWR
@@ -113,12 +113,13 @@ struct Core::dtDecode Core::decode(struct dtFetch dt) {
return {
.inst = dt.inst,
- .mem2reg = dec.flags & DM_MEM2REG,
+ .memread = dec.flags & DM_MEMREAD,
.memwrite = dec.flags & DM_MEMWRITE,
.alusrc = dec.flags & DM_ALUSRC,
.regd = dec.flags & DM_REGD,
.regwrite = dec.flags & DM_REGWRITE,
.aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : dec.alu,
+ .memctl = dec.mem_ctl,
.val_rs = rs,
.val_rt = rt,
};
@@ -139,7 +140,11 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {
alu_sec = ((dt.inst.immediate() & 0x8000) << 16) | (dt.inst.immediate() & 0x7FFF); // Sign extend to 32bit
return {
+ .memread = dt.memread,
+ .memwrite = dt.memwrite,
.regwrite = regwrite,
+ .memctl = dt.memctl,
+ .val_rt = dt.val_rt,
.rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(),
.alu_val = alu_operate(dt.aluop, dt.val_rs, alu_sec, dt.inst.shamt(), regs),
};
@@ -147,16 +152,23 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) {
struct Core::dtMemory Core::memory(struct dtExecute dt) {
// TODO signals
+ std::uint32_t towrite_val = dt.alu_val;
+
+ if (dt.memwrite)
+ mem->write_ctl(dt.memctl, dt.alu_val, dt.val_rt);
+ else if (dt.memread)
+ towrite_val = mem->read_ctl(dt.memctl, dt.alu_val);
+
return {
.regwrite = dt.regwrite,
.rwrite = dt.rwrite,
- .alu_val = dt.alu_val,
+ .towrite_val = towrite_val,
};
}
void Core::writeback(struct dtMemory dt) {
if (dt.regwrite) {
- regs->write_gp(dt.rwrite, dt.alu_val);
+ regs->write_gp(dt.rwrite, dt.towrite_val);
}
}
@@ -217,7 +229,7 @@ void Core::dtFetchInit(struct dtFetch &dt) {
void Core::dtDecodeInit(struct dtDecode &dt) {
dt.inst = Instruction(0x00);
- dt.mem2reg = false;
+ dt.memread = false;
dt.memwrite = false;
dt.alusrc = false;
dt.regd = false;
@@ -228,7 +240,11 @@ void Core::dtDecodeInit(struct dtDecode &dt) {
}
void Core::dtExecuteInit(struct dtExecute &dt) {
+ dt.memread = false;
+ dt.memwrite = false;
dt.regwrite = false;
+ dt.memctl = MemoryAccess::AC_NONE;
+ dt.val_rt = 0;
dt.rwrite = false;
dt.alu_val = 0;
}
@@ -236,7 +252,7 @@ void Core::dtExecuteInit(struct dtExecute &dt) {
void Core::dtMemoryInit(struct dtMemory &dt) {
dt.regwrite = false;
dt.rwrite = false;
- dt.alu_val = 0;
+ dt.towrite_val = 0;
}
CoreSingle::CoreSingle(Registers *regs, MemoryAccess *mem) : \
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index e583235..07933ab 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -26,24 +26,29 @@ protected:
};
struct dtDecode {
Instruction inst;
- bool mem2reg; // Write memory output to register (instead alu output)
+ bool memread; // If memory should be read
bool memwrite; // If memory should write input
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)
enum AluOp aluop; // Decoded ALU operation
+ enum MemoryAccess::AccessControl memctl; // Decoded memory access type
std::uint32_t val_rs; // Value from register rs
std::uint32_t val_rt; // Value from register rt
};
struct dtExecute {
+ bool memread;
+ bool memwrite;
bool regwrite;
+ enum MemoryAccess::AccessControl memctl;
+ std::uint32_t val_rt;
std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd)
std::uint32_t alu_val; // Result of ALU execution
};
struct dtMemory {
bool regwrite;
std::uint8_t rwrite;
- std::uint32_t alu_val;
+ std::uint32_t towrite_val;
};
struct dtFetch fetch();
diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp
index 593483a..c8f1a17 100644
--- a/qtmips_machine/tests/testcore.cpp
+++ b/qtmips_machine/tests/testcore.cpp
@@ -247,6 +247,7 @@ static void core_jmp_data() {
<< regs \
<< 0x80000000 + (24 << 2);
/*
+ * TODO
QTest::newRow("JR") << Instruction(1, 15, 0, 61) \
<< regs \
<< regs.read_pc() + (24 << 2);
@@ -305,10 +306,121 @@ void MachineTests::pipecore_jmp() {
QCOMPARE(regs, regs_used); // There should be no change in registers now (except pc)
}
-void MachineTests::core_mem_data() {
+static void core_mem_data() {
+ QTest::addColumn<Instruction>("i");
+ QTest::addColumn<Registers>("regs_init");
+ QTest::addColumn<Registers>("regs_res");
+ QTest::addColumn<Memory>("mem_init");
+ QTest::addColumn<Memory>("mem_res");
+
+ // Load
+ {
+ Memory mem;
+ mem.write_word(0x24, 0xA3242526);
+ Registers regs;
+ regs.write_gp(1, 0x22);
+ Registers regs_res(regs);
+ regs_res.write_gp(21, 0x80000023);
+ QTest::newRow("LB") << Instruction(32, 1, 21, 0x2) \
+ << regs \
+ << regs_res \
+ << mem \
+ << mem;
+ regs_res.write_gp(21, 0x80002324);
+ QTest::newRow("LH") << Instruction(33, 1, 21, 0x2) \
+ << regs \
+ << regs_res \
+ << mem \
+ << mem;
+ regs_res.write_gp(21, 0xA3242526);
+ QTest::newRow("LW") << Instruction(35, 1, 21, 0x2) \
+ << regs \
+ << regs_res \
+ << mem \
+ << mem;
+ regs_res.write_gp(21, 0x000000A3);
+ QTest::newRow("LBU") << Instruction(36, 1, 21, 0x2) \
+ << regs \
+ << regs_res \
+ << mem \
+ << mem;
+ regs_res.write_gp(21, 0x0000A324);
+ QTest::newRow("LHU") << Instruction(37, 1, 21, 0x2) \
+ << regs \
+ << regs_res \
+ << mem \
+ << mem;
+ }
+ // Store
+ {
+ Registers regs;
+ regs.write_gp(1, 0x22);
+ regs.write_gp(21, 0x23242526);
+ Memory mem;
+ mem.write_byte(0x24, 0x26); // Note: store least significant byte
+ QTest::newRow("SB") << Instruction(40, 1, 21, 0x2) \
+ << regs \
+ << regs \
+ << Memory() \
+ << mem;
+ mem.write_hword(0x24, 0x2526);
+ QTest::newRow("SH") << Instruction(41, 1, 21, 0x2) \
+ << regs \
+ << regs \
+ << Memory() \
+ << mem;
+ mem.write_word(0x24, 0x23242526);
+ QTest::newRow("SH") << Instruction(43, 1, 21, 0x2) \
+ << regs \
+ << regs \
+ << Memory() \
+ << mem;
+ }
+}
+
+void MachineTests::singlecore_mem_data() {
+ core_mem_data();
+}
+
+void MachineTests::pipecore_mem_data() {
+ core_mem_data();
+}
+
+void MachineTests::singlecore_mem() {
+ QFETCH(Instruction, i);
+ QFETCH(Registers, regs_init);
+ QFETCH(Registers, regs_res);
+ QFETCH(Memory, mem_init);
+ QFETCH(Memory, mem_res);
+
+ // Write instruction to both memories
+ mem_init.write_word(regs_init.read_pc(), i.data());
+ mem_res.write_word(regs_init.read_pc(), i.data());
+ CoreSingle core(&regs_init, &mem_init);
+ core.step();
+
+ regs_res.pc_inc();
+ QCOMPARE(regs_init, regs_res);
+ QCOMPARE(mem_init, mem_res);
}
-void MachineTests::core_mem() {
+void MachineTests::pipecore_mem() {
+ QFETCH(Instruction, i);
+ QFETCH(Registers, regs_init);
+ QFETCH(Registers, regs_res);
+ QFETCH(Memory, mem_init);
+ QFETCH(Memory, mem_res);
+
+ // Write instruction to both memories
+ mem_init.write_word(regs_init.read_pc(), i.data());
+ mem_res.write_word(regs_init.read_pc(), i.data());
+
+ CorePipelined core(&regs_init, &mem_init);
+ for (int i = 0; i < 5; i++)
+ core.step(); // Fire steps for five pipelines stages
+ regs_res.pc_jmp(20);
+ QCOMPARE(regs_init, regs_res);
+ QCOMPARE(mem_init, mem_res);
}
diff --git a/qtmips_machine/tests/testmemory.cpp b/qtmips_machine/tests/testmemory.cpp
index 091c26d..f1c6b80 100644
--- a/qtmips_machine/tests/testmemory.cpp
+++ b/qtmips_machine/tests/testmemory.cpp
@@ -103,3 +103,61 @@ void MachineTests::memory_compare() {
m3.write_byte(0x18, 0x22);
QVERIFY(m1 != m3);
}
+
+void MachineTests::memory_write_ctl_data() {
+ QTest::addColumn<MemoryAccess::AccessControl>("ctl");
+ QTest::addColumn<Memory>("result");
+
+ Memory mem;
+ QTest::newRow("none") << MemoryAccess::AC_NONE \
+ << mem;
+ mem.write_byte(0x20, 0x26);
+ QTest::newRow("byte") << MemoryAccess::AC_BYTE \
+ << mem;
+ QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \
+ << mem;
+ mem.write_hword(0x20, 0x2526);
+ QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \
+ << mem;
+ QTest::newRow("haldword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \
+ << mem;
+ mem.write_word(0x20, 0x23242526);
+ QTest::newRow("word") << MemoryAccess::AC_WORD \
+ << mem;
+}
+
+void MachineTests::memory_write_ctl() {
+ QFETCH(MemoryAccess::AccessControl, ctl);
+ QFETCH(Memory, result);
+
+ Memory mem;
+ mem.write_ctl(ctl, 0x20, 0x23242526);
+ QCOMPARE(mem, result);
+}
+
+void MachineTests::memory_read_ctl_data() {
+ QTest::addColumn<MemoryAccess::AccessControl>("ctl");
+ QTest::addColumn<std::uint32_t>("result");
+
+ QTest::newRow("none") << MemoryAccess::AC_NONE \
+ << (std::uint32_t)0;
+ QTest::newRow("byte") << MemoryAccess::AC_BYTE \
+ << (std::uint32_t)0x80000023;
+ QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \
+ << (std::uint32_t)0x80002324;
+ QTest::newRow("word") << MemoryAccess::AC_WORD \
+ << (std::uint32_t)0xA3242526;
+ QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \
+ << (std::uint32_t)0xA3;
+ QTest::newRow("halfword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \
+ << (std::uint32_t)0xA324;
+}
+
+void MachineTests::memory_read_ctl() {
+ QFETCH(MemoryAccess::AccessControl, ctl);
+ QFETCH(std::uint32_t, result);
+
+ Memory mem;
+ mem.write_word(0x20, 0xA3242526);
+ QCOMPARE(mem.read_ctl(ctl, 0x20), result);
+}
diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h
index 9b33e68..ad3112c 100644
--- a/qtmips_machine/tests/tst_machine.h
+++ b/qtmips_machine/tests/tst_machine.h
@@ -19,6 +19,10 @@ private Q_SLOTS:
void memory_section_data();
void memory_endian();
void memory_compare();
+ void memory_write_ctl();
+ void memory_write_ctl_data();
+ void memory_read_ctl();
+ void memory_read_ctl_data();
// Program loader
void program_loader();
// Instruction
@@ -38,8 +42,10 @@ private Q_SLOTS:
void singlecore_jmp_data();
void pipecore_jmp();
void pipecore_jmp_data();
- void core_mem();
- void core_mem_data();
+ void singlecore_mem();
+ void singlecore_mem_data();
+ void pipecore_mem();
+ void pipecore_mem_data();
};
#endif // TST_MACHINE_H