From 054225612d13e9a32b7900e423590367b5969b6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Karel=20Ko=C4=8D=C3=AD?= <cynerd@email.cz>
Date: Tue, 21 Nov 2017 23:37:09 +0100
Subject: Implement some immediate arithmetic instructions

---
 qtmips_machine/core.cpp           | 102 +++++++++++++++++++-------------------
 qtmips_machine/core.h             |   6 +--
 qtmips_machine/tests/testcore.cpp |  16 ++++--
 3 files changed, 67 insertions(+), 57 deletions(-)

(limited to 'qtmips_machine')

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 <iostream>
 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(&regs_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