From 054225612d13e9a32b7900e423590367b5969b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= Date: Tue, 21 Nov 2017 23:37:09 +0100 Subject: Implement some immediate arithmetic instructions --- instructions.md | 8 +-- qtmips_machine/core.cpp | 102 +++++++++++++++++++------------------- qtmips_machine/core.h | 6 +-- qtmips_machine/tests/testcore.cpp | 16 ++++-- 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/instructions.md b/instructions.md index a3ee0a0..81a0d76 100644 --- a/instructions.md +++ b/instructions.md @@ -11,8 +11,8 @@ Explanation of checkboxes: CPU Arithmetic Instruction -------------------------- * [-] ADD -* [ ] ADDI -* [ ] ADDIU +* [-] ADDI +* [-] ADDIU * [-] ADDU * [ ] CLO * [ ] CLZ @@ -26,8 +26,8 @@ CPU Arithmetic Instruction * [ ] MULT * [ ] MULTU * [-] SLT -* [ ] SLTI -* [ ] SLTIU +* [-] SLTI +* [-] SLTIU * [?] SLTU * [-] SUB * [-] SUBU diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp index a7c5d20..c79801c 100644 --- a/qtmips_machine/core.cpp +++ b/qtmips_machine/core.cpp @@ -1,33 +1,41 @@ #include "core.h" #include "programloader.h" +#define DM_SUPPORTED (1L<<0) +#define DM_MEM2REG (1L<<1) +#define DM_MEMWRITE (1L<<2) +#define DM_ALUSRC (1L<<3) +#define DM_REGD (1L<<4) +#define DM_REGWRITE (1L<<5) +#define DM_BRANCH (1L<<6) + struct DecodeMap { - bool supported, mem2reg, memwrite, alubimm, regd, regwrite, branch; + long flags; + enum AluOp alu; }; // This is temporally operation place holder -#define NOPE { .supported = false } +#define NOPE { .flags = 0, .alu = ALU_OP_SLL } // This is map from opcode to signals. static const struct DecodeMap dmap[] = { - { .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 - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // JAL - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BEQ - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BNE - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BLEZ - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // BGTZ - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDI - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ADDIU - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTI - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SLTIU - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ANDI - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // ORI - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // XORI - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LUI + { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, .alu = ALU_OP_SLL }, // Alu operations + NOPE, // Branch on alu operations + NOPE, // J + NOPE, // JAL + NOPE, // BEQ + NOPE, // BNE + NOPE, // BLEZ + NOPE, // BGTZ + { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_ADD }, // ADDI + { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_ADDU }, // ADDIU + { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_SLT }, // SLTI + { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE, .alu = ALU_OP_SLTU }, // SLTIU + NOPE, // ANDI + NOPE, // ORI + NOPE, // XORI + NOPE, // LUI NOPE, // 16 NOPE, // 17 NOPE, // 18 @@ -44,21 +52,21 @@ static const struct DecodeMap dmap[] = { NOPE, // 29 NOPE, // 30 NOPE, // 31 - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LB - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LH - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWL - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LW - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LBU - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LHU - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // LWR + NOPE, // LB + NOPE, // LH + NOPE, // LWL + NOPE, // LW + NOPE, // LBU + NOPE, // LHU + NOPE, // LWR NOPE, // 39 - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SB - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SH - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWL - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SW + NOPE, // SB + NOPE, // SH + NOPE, // SWL + NOPE, // SW NOPE, // 44 NOPE, // 45 - { .supported = true, .mem2reg = false, .memwrite = false, .alubimm = false, .regd = true, .regwrite = true, .branch = false }, // SWR + NOPE, // SWR NOPE, // 47 NOPE, // 48 NOPE, // 49 @@ -94,27 +102,19 @@ struct Core::dtFetch Core::fetch() { struct Core::dtDecode Core::decode(struct dtFetch dt) { struct DecodeMap dec = dmap[dt.inst.opcode()]; - if (!dec.supported) + if (!dec.flags & DM_SUPPORTED) // TODO message throw QTMIPS_EXCEPTION(UnsupportedInstruction, "", ""); - // 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, - .regd = dec.regd, - .regwrite = dec.regwrite, - .branch = dec.branch, - .aluop = d_alu, + .mem2reg = dec.flags & DM_MEM2REG, + .memwrite = dec.flags & DM_MEMWRITE, + .alusrc = dec.flags & DM_ALUSRC, + .regd = dec.flags & DM_REGD, + .regwrite = dec.flags & DM_REGWRITE, + .branch = dec.flags & DM_BRANCH, + .aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : dec.alu, .val_rs = regs->read_gp(dt.inst.rs()), .val_rt = regs->read_gp(dt.inst.rt()), }; @@ -125,23 +125,23 @@ struct Core::dtExecute Core::execute(struct dtDecode dt) { // TODO signals return { - .mem2reg = dt.mem2reg, + .regwrite = dt.regwrite, .rwrite = dt.regd ? dt.inst.rd() : dt.inst.rt(), - .alu_val = alu_operate(dt.aluop, dt.val_rs, 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()), }; } struct Core::dtMemory Core::memory(struct dtExecute dt) { // TODO signals return { - .mem2reg = dt.mem2reg, + .regwrite = dt.regwrite, .rwrite = dt.rwrite, .alu_val = dt.alu_val, }; } void Core::writeback(struct dtMemory dt) { - if (dt.mem2reg) { + if (dt.regwrite) { regs->write_gp(dt.rwrite, dt.alu_val); } } diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h index 5dd5726..9829741 100644 --- a/qtmips_machine/core.h +++ b/qtmips_machine/core.h @@ -28,7 +28,7 @@ protected: 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) + 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) bool branch; // If this is branch instruction @@ -37,13 +37,13 @@ protected: std::uint32_t val_rt; // Value from register rt }; struct dtExecute { - bool mem2reg; + bool regwrite; 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; + bool regwrite; std::uint8_t rwrite; std::uint32_t alu_val; // TODO diff --git a/qtmips_machine/tests/testcore.cpp b/qtmips_machine/tests/testcore.cpp index f4a3e4b..3a48f1d 100644 --- a/qtmips_machine/tests/testcore.cpp +++ b/qtmips_machine/tests/testcore.cpp @@ -20,6 +20,12 @@ void MachineTests::core_regs_data() { QTest::newRow("ADDU") << Instruction(0, 24, 25, 26, 0, 33) \ << regs_init \ << regs_res; + QTest::newRow("ADDI") << Instruction(8, 24, 26, 12) \ + << regs_init \ + << regs_res; + QTest::newRow("ADDIU") << Instruction(9, 24, 26, 12) \ + << regs_init \ + << regs_res; regs_res.write_gp(26, 12); QTest::newRow("SUB") << Instruction(0, 24, 25, 26, 0, 34) \ << regs_init \ @@ -40,6 +46,12 @@ void MachineTests::core_regs_data() { QTest::newRow("SLTU") << Instruction(0, 24, 25, 26, 0, 43) \ << regs_init \ << regs_res; + QTest::newRow("SLTI") << Instruction(10, 24, 26, 24) \ + << regs_init \ + << regs_res; + QTest::newRow("SLTIU") << Instruction(11, 24, 26, 24) \ + << regs_init \ + << regs_res; } // Shift instructions @@ -79,10 +91,8 @@ void MachineTests::core_regs_data() { // TODO test other operations } -/* #include using namespace std; -*/ void MachineTests::core_regs() { QFETCH(Instruction, i); @@ -98,7 +108,7 @@ void MachineTests::core_regs() { 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 - //cout << "well:" << hex << regs_single.read_gp(26) << endl; + cout << "well:" << regs_single.read_gp(26) << endl; 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 -- cgit v1.2.3