From cd9e572b6523fac483ce1695ae1785fca075cc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 21 Nov 2017 22:01:52 +0100 Subject: Implement and test ADD --- instructions.md | 7 ++++++- qtmips_machine/core.cpp | 24 +++++++++++++++++------- qtmips_machine/core.h | 9 +++++---- qtmips_machine/registers.cpp | 12 ++++++++---- qtmips_machine/registers.h | 1 + qtmips_machine/tests/testcore.cpp | 10 +++++----- qtmips_machine/tests/testregisters.cpp | 27 +++++++++++++++++++++++++++ qtmips_machine/tests/tst_machine.h | 1 + 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("i"); QTest::addColumn("init"); QTest::addColumn("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("i"); - QTest::addColumn("init"); - QTest::addColumn("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(®s_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(); -- cgit v1.2.3