From 04ea2670be26291a17808bd704ce3549795953a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 5 Sep 2017 00:31:13 +0200 Subject: Add some more instructions to be decoded and arithmetic I test --- qtmips_machine/instruction.cpp | 63 +++++++++++-- qtmips_machine/instruction.h | 27 +++++- qtmips_machine/instructions/arithmetic.cpp | 90 +++++++++++++++++- qtmips_machine/instructions/arithmetic.h | 14 +++ qtmips_machine/programmemory.cpp | 145 ++++++++++++++++++++++++++--- qtmips_machine/programmemory.h | 4 +- qtmips_machine/tests/testinstruction.cpp | 76 +++++++++++++++ qtmips_machine/tests/testprogrammemory.cpp | 100 ++++++++++++++++++-- qtmips_machine/tests/tests.pro | 3 +- qtmips_machine/tests/tst_machine.h | 5 + 10 files changed, 491 insertions(+), 36 deletions(-) create mode 100644 qtmips_machine/tests/testinstruction.cpp diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp index e03f794..1771afb 100644 --- a/qtmips_machine/instruction.cpp +++ b/qtmips_machine/instruction.cpp @@ -1,6 +1,51 @@ #include "instruction.h" +#include "qtmipsexception.h" -InstructionR::InstructionR(std::uint8_t rs, std::uint8_t rd, std::uint8_t rt, std::uint8_t sa) { +Instruction::Instruction() { + this->st = IS_FETCH; +} + +void Instruction::decode(Registers *regs) { + if (this->st != IS_FETCH) + // TODO other exception + throw std::exception(); + this->st = IS_DECODE; +} + +void Instruction::execute() { + if (this->st != IS_DECODE) + // TODO other exception + throw std::exception(); + this->st = IS_EXECUTE; +} + +void Instruction::memory(Memory *mem) { + if (this->st != IS_EXECUTE) + // TODO other exception + throw std::exception(); + this->st = IS_MEMORY; +} + +void Instruction::write_back(Registers *regs) { + if (this->st != IS_MEMORY) + // TODO other exception + throw std::exception(); + this->st = IS_WRITE_BACK; +} + +enum InstructionState Instruction::state() { + return this->st; +} + +bool Instruction::running() { + return this->st > IS_FETCH && this->st < IS_WRITE_BACK; +} + +bool Instruction::done() { + return this->st >= IS_WRITE_BACK; +} + +InstructionR::InstructionR(std::uint8_t rs, std::uint8_t rd, std::uint8_t rt, std::uint8_t sa) : Instruction() { this->rs = rs; this->rd = rd; this->rt = rt; @@ -14,17 +59,17 @@ QVector InstructionR::to_strs() { // Instruction name str << "unknown"; // unknown instruction, should be replaced by child // Source register - str << QString::number((unsigned)this->rs, 16); + str << QString::number((unsigned)this->rs, 10); // Target register - str << QString::number((unsigned)this->rt, 16); + str << QString::number((unsigned)this->rt, 10); // Destination register - str << QString::number((unsigned)this->rd, 16); + str << QString::number((unsigned)this->rd, 10); // Shift amount - str << QString::number((unsigned)this->sa, 16); + str << QString::number((unsigned)this->sa, 10); return str; } -InstructionI::InstructionI(std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate) { +InstructionI::InstructionI(std::uint8_t rs, std::uint8_t rt, std::uint16_t immediate) : Instruction() { this->rs = rs; this->rt = rt; this->immediate = immediate; @@ -35,15 +80,15 @@ QVector InstructionI::to_strs() { // Instruction name str << "unknown"; // unknown instruction, should be replaced by child // Source register - str << QString::number((unsigned)this->rs, 16); + str << QString::number((unsigned)this->rs, 10); // Target register - str << QString::number((unsigned)this->rt, 16); + str << QString::number((unsigned)this->rt, 10); // Immediate value str << QString::number((unsigned)this->immediate, 16); return str; } -InstructionJ::InstructionJ(std::uint32_t address) { +InstructionJ::InstructionJ(std::uint32_t address) : Instruction() { this->address = address; } diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h index 99a3ba4..8c5ede9 100644 --- a/qtmips_machine/instruction.h +++ b/qtmips_machine/instruction.h @@ -6,15 +6,32 @@ #include "registers.h" #include "memory.h" +enum InstructionState { + IS_FETCH, + IS_DECODE, + IS_EXECUTE, + IS_MEMORY, + IS_WRITE_BACK, +}; + class Instruction { public: - // TODO return types should be according to what instruction can pass from this stage - //virtual void decode(Registers *regs) = 0; // Read and prepare instructions - //virtual void execute() = 0; // ALU operations - //virtual void memory(Memory *mem) = 0; // Read or write to memory - //virtual void write_back(Registers *regs) = 0; // Write results to registers + Instruction(); + + // TODO return some info for forwarding, stall, flush + virtual void decode(Registers *regs); // Read and prepare instructions + virtual void execute(); // ALU operations + virtual void memory(Memory *mem); // Read or write to memory + virtual void write_back(Registers *regs); // Write results to registers + + enum InstructionState state(); + bool running(); + bool done(); virtual QVector to_strs() = 0; // Returns all fields of instructions in string + +private: + enum InstructionState st; }; class InstructionR : public Instruction { diff --git a/qtmips_machine/instructions/arithmetic.cpp b/qtmips_machine/instructions/arithmetic.cpp index a620436..f3cad86 100644 --- a/qtmips_machine/instructions/arithmetic.cpp +++ b/qtmips_machine/instructions/arithmetic.cpp @@ -5,6 +5,58 @@ InstructionArithmetic::InstructionArithmetic(enum InstructionArithmeticT type, s this->type = type; } +void InstructionArithmetic::decode(Registers *regs) { + Instruction::decode(regs); + this->rs_d = regs->read_gp(this->rs); + this->rd_d = regs->read_gp(this->rd); +} + +void InstructionArithmetic::execute() { + Instruction::execute(); + switch (this->type) { + case IAT_ADD: + this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d + (std::int32_t)this->rd_d); + break; + case IAT_ADDU: + this->rt_d = this->rs_d + this->rd_d; + break; + case IAT_SUB: + this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d - (std::int32_t)this->rd_d); + break; + case IAT_SUBU: + this->rt_d = this->rs_d - this->rd_d; + break; + case IAT_AND: + this->rt_d = this->rs_d & this->rd_d; + break; + case IAT_OR: + this->rt_d = this->rs_d | this->rd_d; + break; + case IAT_XOR: + this->rt_d = this->rs_d ^ this->rd_d; + break; + case IAT_NOR: + // TODO + break; + case IAT_SLT: + // TODO + break; + case IAT_SLTU: + // TODO + break; + } +} + +void InstructionArithmetic::memory(Memory *mem) { + Instruction::memory(mem); + // pass +} + +void InstructionArithmetic::write_back(Registers *regs) { + Instruction::write_back(regs); + regs->write_gp(this->rt, this->rt_d); +} + QVector InstructionArithmetic::to_strs() { QVector str = this->InstructionR::to_strs(); str.erase(str.begin() + 4); // Drop sa field @@ -51,6 +103,42 @@ InstructionArithmeticImmediate::InstructionArithmeticImmediate(enum InstructionA this->type = type; } +void InstructionArithmeticImmediate::decode(Registers *regs) { + Instruction::decode(regs); + this->rs_d = regs->read_gp(this->rs); +} + +void InstructionArithmeticImmediate::execute() { + Instruction::execute(); + switch (this->type) { + case IAT_ADDI: + this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d + (std::int32_t)this->immediate); + break; + case IAT_ADDIU: + this->rt_d = this->rs_d + this->immediate; + break; + case IAT_ANDI: + this->rt_d = (std::uint32_t)((std::int32_t)this->rs_d - (std::int32_t)this->immediate); + break; + case IAT_ORI: + this->rt_d = this->rs_d - this->immediate; + break; + case IAT_XORI: + this->rt_d = this->rs_d & this->immediate; + break; + } +} + +void InstructionArithmeticImmediate::memory(Memory *mem) { + Instruction::memory(mem); + // pass +} + +void InstructionArithmeticImmediate::write_back(Registers *regs) { + Instruction::write_back(regs); + regs->write_gp(this->rt, this->rt_d); +} + QVector InstructionArithmeticImmediate::to_strs() { QVector str = this->InstructionI::to_strs(); switch (this->type) { @@ -76,7 +164,7 @@ QVector InstructionArithmeticImmediate::to_strs() { str[0] = "sltiu"; break; case IAT_LUI: - str[0] = "lu"; + str[0] = "lui"; break; default: // TODO different exception diff --git a/qtmips_machine/instructions/arithmetic.h b/qtmips_machine/instructions/arithmetic.h index 19f1df5..185ed95 100644 --- a/qtmips_machine/instructions/arithmetic.h +++ b/qtmips_machine/instructions/arithmetic.h @@ -19,9 +19,16 @@ enum InstructionArithmeticT { class InstructionArithmetic : public InstructionR { public: InstructionArithmetic(enum InstructionArithmeticT type, std::uint8_t rs, std::uint8_t rd, std::uint8_t rt); + + void decode(Registers *regs); + void execute(); + void memory(Memory *mem); + void write_back(Registers *regs); + QVector to_strs(); private: enum InstructionArithmeticT type; + std::uint32_t rs_d, rd_d, rt_d; }; enum InstructionArithmeticImmediateT { @@ -38,9 +45,16 @@ enum InstructionArithmeticImmediateT { class InstructionArithmeticImmediate : public InstructionI { public: InstructionArithmeticImmediate(enum InstructionArithmeticImmediateT type, std::uint8_t rs, std::uint8_t rt, std::uint16_t value); + + void decode(Registers *regs); + void execute(); + void memory(Memory *mem); + void write_back(Registers *regs); + QVector to_strs(); private: enum InstructionArithmeticImmediateT type; + std::uint32_t rs_d, rt_d; }; #endif // ARITHMETIC_H diff --git a/qtmips_machine/programmemory.cpp b/qtmips_machine/programmemory.cpp index 74b16a8..2f0e19e 100644 --- a/qtmips_machine/programmemory.cpp +++ b/qtmips_machine/programmemory.cpp @@ -5,6 +5,7 @@ #include "instructions/loadstore.h" #include "instructions/nop.h" #include "instructions/shift.h" +#include ProgramMemory::ProgramMemory(MemoryAccess *memory) { this->memory = memory; @@ -12,7 +13,7 @@ ProgramMemory::ProgramMemory(MemoryAccess *memory) { void ProgramMemory::load(ProgramLoader *loader) { // Load program to memory (just dump it byte by byte, decode is done on demand) - for (int i = 0; i < loader->get_nsec(); i++) { + for (unsigned i = 0; i < loader->get_nsec(); i++) { std::uint32_t base_address = loader->get_address(i); QVector data = loader->get_data(i); for (auto it = data.begin(); it < data.end(); it++) { @@ -21,7 +22,7 @@ void ProgramMemory::load(ProgramLoader *loader) { } } -#define MASKSUB(VAR, LEN, OFFSET) ((VAR & ~((1 << (LEN+OFFSET+1)) - 1)) >> OFFSET) +#define MASKSUB(VAR, LEN, OFFSET) (((VAR) >> (OFFSET)) & ((1 << (LEN)) - 1)) Instruction *ProgramMemory::at(std::uint32_t address) { if (address % 4) @@ -31,14 +32,15 @@ Instruction *ProgramMemory::at(std::uint32_t address) { std::uint32_t dt = this->memory->read_word(address); // Decode instruction - Instruction *inst; + if (dt == 0) + return new InstructionNop(); std::uint8_t opcode = dt >> 26; // upper 6 bits if (opcode == 0) { // Arithmetic and shift instructions return this->decode_r(dt); } else if (opcode == 2 || opcode == 3) { // Jump instructions - return decode_j(dt); + return decode_j(dt, opcode); } else { - return decode_i(dt); + return decode_i(dt, opcode); } } @@ -47,8 +49,6 @@ Instruction *ProgramMemory::at(std::uint32_t address) { Instruction *ProgramMemory::decode_r(std::uint32_t dt) { std::uint8_t func = MASKSUB(dt, 6, 0); - if (!func) - return new InstructionNop(); std::uint8_t rs, rt, rd, sa; rs = MASKSUB(dt, 5, 21); @@ -91,23 +91,146 @@ Instruction *ProgramMemory::decode_r(std::uint32_t dt) { } else if (func < 10) { // Jump instructions // TODO I_UNKNOWN(dt); + } else if (func > 31 && func < 44) { + enum InstructionArithmeticT type; + switch (func) { + case 32: + type = IAT_ADD; + break; + case 33: + type = IAT_ADDU; + break; + case 34: + type = IAT_SUB; + break; + case 35: + type = IAT_SUBU; + break; + case 36: + type = IAT_AND; + break; + case 37: + type = IAT_OR; + break; + case 38: + type = IAT_XOR; + break; + case 39: + type = IAT_NOR; + break; + case 42: + type = IAT_SLT; + break; + case 43: + type = IAT_SLTU; + break; + default: + I_UNKNOWN(dt); + } + return new InstructionArithmetic(type, rs, rd, rt); } else { // TODO filter rest I_UNKNOWN(dt); } } -Instruction *ProgramMemory::decode_j(std::uint32_t dt) { +Instruction *ProgramMemory::decode_j(std::uint32_t dt, std::uint8_t opcode) { std::uint32_t address = MASKSUB(dt, 26, 0); // TODO I_UNKNOWN(dt); } -Instruction *ProgramMemory::decode_i(std::uint32_t dt) { +Instruction *ProgramMemory::decode_i(std::uint32_t dt, std::uint8_t opcode) { // InstructionI std::uint8_t rs, rt; rs = MASKSUB(dt, 5, 21); rt = MASKSUB(dt, 5, 16); std::uint16_t immediate = MASKSUB(dt, 16, 0); - // TODO - I_UNKNOWN(dt); + + if (opcode > 7 && opcode < 16) { + enum InstructionArithmeticImmediateT type; + switch (opcode) { + case 8: + type = IAT_ADDI; + break; + case 9: + type = IAT_ADDIU; + break; + case 10: + type = IAT_SLTI; + break; + case 11: + type = IAT_SLTIU; + break; + case 12: + type = IAT_ANDI; + break; + case 13: + type = IAT_ORI; + break; + case 14: + type = IAT_XORI; + break; + case 15: + type = IAT_LUI; + break; + default: + I_UNKNOWN(dt); + } + return new InstructionArithmeticImmediate(type, rs, rt, immediate); + } else if (opcode > 31 && opcode < 47) { + enum InstructionLoadStoreT type; + bool isload = false; + switch (opcode) { + case 32: + type = ILST_B; + isload = true; + break; + case 33: + type = ILST_HW; + isload = true; + break; + case 34: + type = ILST_WL; + isload = true; + break; + case 35: + type = ILST_W; + isload = true; + break; + case 36: + type = ILST_BU; + isload = true; + break; + case 37: + type = ILST_HU; + isload = true; + break; + case 38: + type = ILST_WR; + isload = true; + break; + case 40: + type = ILST_B; + break; + case 41: + type = ILST_HW; + break; + case 42: + type = ILST_WL; + break; + case 43: + type = ILST_W; + break; + case 46: + type = ILST_WR; + break; + default: + I_UNKNOWN(dt); + } + if (isload) + return new InstructionLoad(type, rs, rt, immediate); + else + return new InstructionStore(type, rs, rt, immediate); + } else + I_UNKNOWN(dt); } diff --git a/qtmips_machine/programmemory.h b/qtmips_machine/programmemory.h index 158adb1..14187c5 100644 --- a/qtmips_machine/programmemory.h +++ b/qtmips_machine/programmemory.h @@ -16,8 +16,8 @@ public: private: MemoryAccess *memory; Instruction *decode_r(std::uint32_t dt); - Instruction *decode_j(std::uint32_t dt); - Instruction *decode_i(std::uint32_t dt); + Instruction *decode_j(std::uint32_t dt, std::uint8_t opcode); + Instruction *decode_i(std::uint32_t dt, std::uint8_t opcode); }; #endif // PROGRAMMEMORY_H diff --git a/qtmips_machine/tests/testinstruction.cpp b/qtmips_machine/tests/testinstruction.cpp new file mode 100644 index 0000000..a299bcf --- /dev/null +++ b/qtmips_machine/tests/testinstruction.cpp @@ -0,0 +1,76 @@ +#include "tst_machine.h" +#include "instructions/arithmetic.h" +#include "instructions/jumpbranch.h" +#include "instructions/loadstore.h" +#include "instructions/nop.h" +#include "instructions/shift.h" +#include + +void MachineTests::instruction_arithmetic_data() { + QTest::addColumn("type"); + QTest::addColumn("res"); + + QTest::newRow("ADD") << (size_t)IAT_ADD << (unsigned)749; + QTest::newRow("ADDU") << (size_t)IAT_ADDU << (unsigned)749; + QTest::newRow("SUB") << (size_t)IAT_SUB << (unsigned)-665; + QTest::newRow("SUBU") << (size_t)IAT_SUBU << (unsigned)-665; + QTest::newRow("AND") << (size_t)IAT_AND << (unsigned)2; + QTest::newRow("OR") << (size_t)IAT_OR << (unsigned)747; + QTest::newRow("XOR") << (size_t)IAT_XOR << (unsigned)745; + // TODO others +} + +void MachineTests::instruction_arithmetic() { + Registers regs; + + QFETCH(size_t, type); + QFETCH(std::uint32_t, res); + + // TODO meaby one more dataset? + + regs.write_gp(12, 42); + regs.write_gp(8, 707); + regs.write_gp(5, 0); + + Instruction *i = new InstructionArithmetic((enum InstructionArithmeticT)type, 12, 8, 5); + + i->decode(®s); + i->execute(); + i->memory(nullptr); // We should not work with memory so segfault here is basically a test + i->write_back(®s); + + QCOMPARE(regs.read_gp(5), (std::uint32_t)res); +} + +void MachineTests::instruction_arithmetic_immediate_data() { + QTest::addColumn("type"); + QTest::addColumn("res"); + + QTest::newRow("ADDI") << (size_t)IAT_ADDI << (unsigned)749; + QTest::newRow("ADDIU") << (size_t)IAT_ADDIU << (unsigned)749; + QTest::newRow("ANDI") << (size_t)IAT_ANDI << (unsigned)-665; + QTest::newRow("ORI") << (size_t)IAT_ORI << (unsigned)-665; + QTest::newRow("XORI") << (size_t)IAT_XORI << (unsigned)2; + // TODO others +} + +void MachineTests::instruction_arithmetic_immediate() { + Registers regs; + + QFETCH(size_t, type); + QFETCH(std::uint32_t, res); + + // TODO meaby one more dataset? + + regs.write_gp(9, 42); + regs.write_gp(3, 0); + + Instruction *i = new InstructionArithmeticImmediate((enum InstructionArithmeticImmediateT)type, 9, 3, 707); + + i->decode(®s); + i->execute(); + i->memory(nullptr); // We should not work with memory so segfault here is basically a test + i->write_back(®s); + + QCOMPARE(regs.read_gp(3), (std::uint32_t)res); +} diff --git a/qtmips_machine/tests/testprogrammemory.cpp b/qtmips_machine/tests/testprogrammemory.cpp index a08bbab..220b463 100644 --- a/qtmips_machine/tests/testprogrammemory.cpp +++ b/qtmips_machine/tests/testprogrammemory.cpp @@ -2,6 +2,7 @@ #include "programmemory.h" #include #include +#include QVector str_inst_r(const char *inst, const char *rs, const char *rd, const char *rt, const char *sa) { QVector ret; @@ -17,15 +18,91 @@ QVector str_inst_r(const char *inst, const char *rs, const char *rd, co return ret; } +QVector str_inst_i(const char *inst, const char *rs, const char *rt, const char *immediate) { + QVector ret; + ret << inst; + if (rs) + ret << rs; + if (rt) + ret << rt; + ret << immediate; + return ret; +} + +QVector str_inst_j(const char *inst, const char *address) { + QVector ret; + ret << inst; + ret << address; + return ret; +} + #define I(II) ((std::uint32_t) II) +#define I_R(OP, RS, RD, RT, SA, F) ((std::uint32_t)(((OP) << 26) | ((RS) << 21) | ((RT) << 16) | ((RD) << 11) | ((SA) << 6) | (F))) +#define I_I(OP, RS, RT, IMM) ((std::uint32_t)(((OP) << 26) | ((RS) << 21) | ((RT) << 16) | (IMM))) +#define I_J(OP, ADDR) ((std::uint32_t)(((OP) << 26) | (ADDR))) void MachineTests::program_memory_data() { QTest::addColumn("bin"); QTest::addColumn>("str"); - // TODO correct instruction - QTest::newRow("NOP") << I(0x000000) << str_inst_r("nop", nullptr, nullptr, nullptr, nullptr); - //QTest::newRow("SLL") << I(0x000000) << str_inst_r("sll", "", "", nullptr, nullptr); + /* NOP */ + QTest::newRow("NOP") << I(0) << str_inst_r("nop", nullptr, nullptr, nullptr, nullptr); + /* ALU */ + QTest::newRow("ADD") << I_R(0, 12, 14, 13, 0, 32) << str_inst_r("add", "12", "13", "14", nullptr); + QTest::newRow("ADDU") << I_R(0, 12, 14, 13, 0, 33) << str_inst_r("addu", "12", "13", "14", nullptr); + QTest::newRow("SUB") << I_R(0, 12, 14, 13, 0, 34) << str_inst_r("sub", "12", "13", "14", nullptr); + QTest::newRow("SUBU") << I_R(0, 12, 14, 13, 0, 35) << str_inst_r("subu", "12", "13", "14", nullptr); + QTest::newRow("AND") << I_R(0, 12, 14, 13, 0, 36) << str_inst_r("and", "12", "13", "14", nullptr); + QTest::newRow("OR") << I_R(0, 12, 14, 13, 0, 37) << str_inst_r("or", "12", "13", "14", nullptr); + QTest::newRow("XOR") << I_R(0, 12, 14, 13, 0, 38) << str_inst_r("xor", "12", "13", "14", nullptr); + QTest::newRow("NOR") << I_R(0, 12, 14, 13, 0, 39) << str_inst_r("nor", "12", "13", "14", nullptr); + // TODO missing + QTest::newRow("SLT") << I_R(0, 12, 14, 13, 0, 42) << str_inst_r("slt", "12", "13", "14", nullptr); + QTest::newRow("SLTU") << I_R(0, 12, 14, 13, 0, 43) << str_inst_r("sltu", "12", "13", "14", nullptr); + QTest::newRow("ADDI") << I_I(8, 12, 13, 42) << str_inst_i("addi", "12", "13", "2a"); + QTest::newRow("ADDIU") << I_I(9, 12, 13, 42) << str_inst_i("addiu", "12", "13", "2a"); + QTest::newRow("SLTI") << I_I(10, 12, 13, 42) << str_inst_i("slti", "12", "13", "2a"); + QTest::newRow("SLTIU") << I_I(11, 12, 13, 42) << str_inst_i("sltiu", "12", "13", "2a"); + QTest::newRow("ANDI") << I_I(12, 12, 13, 42) << str_inst_i("andi", "12", "13", "2a"); + QTest::newRow("ORI") << I_I(13, 12, 13, 42) << str_inst_i("ori", "12", "13", "2a"); + QTest::newRow("XORI") << I_I(14, 12, 13, 42) << str_inst_i("xori", "12", "13", "2a"); + QTest::newRow("LUI") << I_I(15, 12, 13, 42) << str_inst_i("lui", "12", "13", "2a"); + /* Load and store */ + QTest::newRow("LB") << I_I(32, 12, 13, 42) << str_inst_i("lb", "12", "13", "2a"); + QTest::newRow("LH") << I_I(33, 12, 13, 42) << str_inst_i("lh", "12", "13", "2a"); + QTest::newRow("LWL") << I_I(34, 12, 13, 42) << str_inst_i("lwl", "12", "13", "2a"); + QTest::newRow("LW") << I_I(35, 12, 13, 42) << str_inst_i("lw", "12", "13", "2a"); + QTest::newRow("LBU") << I_I(36, 12, 13, 42) << str_inst_i("lbu", "12", "13", "2a"); + QTest::newRow("LHU") << I_I(37, 12, 13, 42) << str_inst_i("lhu", "12", "13", "2a"); + QTest::newRow("LWR") << I_I(38, 12, 13, 42) << str_inst_i("lwr", "12", "13", "2a"); + // TODO missing + QTest::newRow("SB") << I_I(40, 12, 13, 42) << str_inst_i("sb", "12", "13", "2a"); + QTest::newRow("SH") << I_I(41, 12, 13, 42) << str_inst_i("sh", "12", "13", "2a"); + QTest::newRow("SWL") << I_I(42, 12, 13, 42) << str_inst_i("swl", "12", "13", "2a"); + QTest::newRow("SW") << I_I(43, 12, 13, 42) << str_inst_i("sw", "12", "13", "2a"); + // TODO missing + QTest::newRow("SWR") << I_I(46, 12, 13, 42) << str_inst_i("swr", "12", "13", "2a"); + /* Shifts */ + QTest::newRow("SLL") << I_R(0, 0, 13, 14, 12, 0) << str_inst_r("sll", nullptr, "13", "14", "12"); + // TODO missing + QTest::newRow("SRL") << I_R(0, 0, 13, 14, 12, 2) << str_inst_r("srl", nullptr, "13", "14", "12"); + QTest::newRow("SRA") << I_R(0, 0, 13, 14, 12, 3) << str_inst_r("sra", nullptr, "13", "14", "12"); + QTest::newRow("SLLV") << I_R(0, 12, 13, 14, 0, 4) << str_inst_r("sllv", "12", "13", "14", nullptr); + // TODO missing + QTest::newRow("SRLV") << I_R(0, 12, 13, 14, 0, 6) << str_inst_r("srlv", "12", "13", "14", nullptr); + QTest::newRow("SRAV") << I_R(0, 12, 13, 14, 0, 7) << str_inst_r("srav", "12", "13", "14", nullptr); + /* Jump and branch */ + //QTest::newRow("JR") << I_R(0, 12, 13, 14, 0, 8) << str_inst_r("jr", "12", "13", "14", nullptr); + //QTest::newRow("JALR") << I_R(0, 12, 13, 14, 0, 9) << str_inst_r("jalr", "12", "13", "14", nullptr); + //QTest::newRow("BLTZ") << I_I(1, 12, 0, 42) << str_inst_i("bltz", "12", nullptr, "2a"); + //QTest::newRow("BGEZ") << I_I(1, 12, 1, 42) << str_inst_i("bltz", "12", nullptr, "2a"); + // TODO missing + //QTest::newRow("BLTZAL") << I_I(1, 12, 16, 42) << str_inst_i("bltzal", "12", nullptr, "2a"); + //QTest::newRow("BGEZAL") << I_I(1, 12, 17, 42) << str_inst_i("bgezal", "12", nullptr, "2a"); + // TODO missing? + //QTest::newRow("J") << I_J(1, 4242) << str_inst_j("j", "1092"); + //QTest::newRow("JAL") << I_J(2, 4242) << str_inst_j("jal", "1092"); + // TODO other instructions } @@ -33,9 +110,18 @@ void MachineTests::program_memory() { Memory m; ProgramMemory pm(&m); - QFETCH(std::uint32_t, bin); - QFETCH(QVector, str); + QFETCH(std::uint32_t, bin); + QFETCH(QVector, str); - m.write_word(0x00, bin); - QCOMPARE(pm.at(0x00)->to_strs(), str); + m.write_word(0x00, bin); + /* + Instruction *i = pm.at(0x00); + QVector s = i->to_strs(); + for (int i = 0; i < str.size(); i++) { + std::cout << s[i].toStdString() << " "; + } + std::cout << std::endl; + std::cout.flush(); + */ + QCOMPARE(pm.at(0x00)->to_strs(), str); } diff --git a/qtmips_machine/tests/tests.pro b/qtmips_machine/tests/tests.pro index b9f1497..287d1e8 100644 --- a/qtmips_machine/tests/tests.pro +++ b/qtmips_machine/tests/tests.pro @@ -18,7 +18,8 @@ DEFINES += QT_DEPRECATED_WARNINGS SOURCES += tst_machine.cpp \ testmemory.cpp \ testregisters.cpp \ - testprogrammemory.cpp + testprogrammemory.cpp \ + testinstruction.cpp HEADERS += tst_machine.h diff --git a/qtmips_machine/tests/tst_machine.h b/qtmips_machine/tests/tst_machine.h index 50915f5..c05e8ad 100644 --- a/qtmips_machine/tests/tst_machine.h +++ b/qtmips_machine/tests/tst_machine.h @@ -20,6 +20,11 @@ private Q_SLOTS: // ProgramMemory void program_memory(); void program_memory_data(); + // Instruction + void instruction_arithmetic(); + void instruction_arithmetic_data(); + void instruction_arithmetic_immediate(); + void instruction_arithmetic_immediate_data(); }; #endif // TST_MACHINE_H -- cgit v1.2.3