From 010194187d86041697f1e0e03edfc914940bd2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 12 Dec 2017 21:18:45 +0100 Subject: Implement some store and load instructions --- qtmips_machine/core.cpp | 82 +++++++++++++++---------- qtmips_machine/core.h | 9 ++- qtmips_machine/tests/testcore.cpp | 116 +++++++++++++++++++++++++++++++++++- qtmips_machine/tests/testmemory.cpp | 58 ++++++++++++++++++ qtmips_machine/tests/tst_machine.h | 10 +++- 5 files changed, 236 insertions(+), 39 deletions(-) (limited to 'qtmips_machine') 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("i"); + QTest::addColumn("regs_init"); + QTest::addColumn("regs_res"); + QTest::addColumn("mem_init"); + QTest::addColumn("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(®s_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(®s_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("ctl"); + QTest::addColumn("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("ctl"); + QTest::addColumn("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 -- cgit v1.2.3