From 8f6d939e8d0fdec39c53da65cfb89f288d99eb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Sat, 25 Nov 2017 16:14:19 +0100 Subject: Implement instructions for moving from and to HI and LO registers --- instructions.md | 8 ++--- qtmips_machine/alu.cpp | 12 ++++++- qtmips_machine/alu.h | 8 ++++- qtmips_machine/core.cpp | 2 +- qtmips_machine/tests/testalu.cpp | 67 +++++++++++++++++++++++++++++++++++++-- qtmips_machine/tests/testcore.cpp | 35 +++++++++++++++++--- 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 #include #include +#include // 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("s"); QTest::addColumn("t"); QTest::addColumn("sa"); + QTest::addColumn("regs_init"); + QTest::addColumn("regs_res"); QTest::addColumn("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, ®s_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, ®s), 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(®s_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 } -- cgit v1.2.3