aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-04 18:13:58 +0100
committerPavel Pisa <pisa@cmp.felk.cvut.cz>2019-02-04 18:13:58 +0100
commit40580e24e7a7b2e774d001878dc493216e75b936 (patch)
treed5fd0e60a09c35111fabe9d8975a8cb2a087b431
parent36492497ba7096fb20c417941d426e01870d213d (diff)
downloadqtmips-40580e24e7a7b2e774d001878dc493216e75b936.tar.gz
qtmips-40580e24e7a7b2e774d001878dc493216e75b936.tar.bz2
qtmips-40580e24e7a7b2e774d001878dc493216e75b936.zip
Unified instructions table and access type move to machinedefs.h .
This allows to specify requirement for RS and RD on instruction basis even for T_R / ALU instructions. Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
-rw-r--r--qtmips_machine/alu.h37
-rw-r--r--qtmips_machine/core.cpp136
-rw-r--r--qtmips_machine/core.h4
-rw-r--r--qtmips_machine/instruction.cpp202
-rw-r--r--qtmips_machine/instruction.h26
-rw-r--r--qtmips_machine/machinedefs.h91
-rw-r--r--qtmips_machine/memory.cpp4
-rw-r--r--qtmips_machine/memory.h12
-rw-r--r--qtmips_machine/qtmips_machine.pro3
-rw-r--r--qtmips_machine/tests/testmemory.cpp32
10 files changed, 299 insertions, 248 deletions
diff --git a/qtmips_machine/alu.h b/qtmips_machine/alu.h
index bc12666..efadbe0 100644
--- a/qtmips_machine/alu.h
+++ b/qtmips_machine/alu.h
@@ -41,42 +41,9 @@
#include <QObject>
#include <registers.h>
-namespace machine {
+#include "machinedefs.h"
-enum AluOp : std::uint8_t {
- ALU_OP_SLL = 0,
- ALU_OP_SRL = 2,
- ALU_OP_SRA,
- ALU_OP_SLLV,
- ALU_OP_SRLV = 6,
- ALU_OP_SRAV,
- ALU_OP_JR,
- ALU_OP_JALR,
- ALU_OP_MOVZ,
- ALU_OP_MOVN,
- ALU_OP_BREAK = 13,
- ALU_OP_MFHI = 16,
- ALU_OP_MTHI,
- ALU_OP_MFLO,
- ALU_OP_MTLO,
- ALU_OP_MULT = 24,
- ALU_OP_MULTU = 25,
- ALU_OP_DIV = 26,
- ALU_OP_DIVU = 27,
- ALU_OP_ADD = 32,
- ALU_OP_ADDU,
- ALU_OP_SUB,
- ALU_OP_SUBU,
- ALU_OP_AND,
- ALU_OP_OR,
- ALU_OP_XOR,
- ALU_OP_NOR,
- ALU_OP_SLT = 42,
- ALU_OP_SLTU,
- ALU_OP_LUI = 64, // We don't care about exact index for this one
- ALU_OP_PASS_S, // Pass s argument without change for JAL
- ALU_OP_LAST // First impossible operation (just to be sure that we don't overflow)
-};
+namespace machine {
// Do ALU operation.
// operation: This is function field from instruction or shifted opcode for immediate instructions
diff --git a/qtmips_machine/core.cpp b/qtmips_machine/core.cpp
index 839def2..fd37d6b 100644
--- a/qtmips_machine/core.cpp
+++ b/qtmips_machine/core.cpp
@@ -39,98 +39,6 @@
using namespace machine;
-#define DM_SUPPORTED (1L<<0)
-#define DM_MEMWRITE (1L<<1)
-#define DM_MEMREAD (1L<<2)
-#define DM_ALUSRC (1L<<3)
-#define DM_REGD (1L<<4)
-#define DM_REGWRITE (1L<<5)
-#define DM_ZERO_EXTEND (1L<<6)
-#define DM_PC_TO_R31 (1L<<7)
-#define DM_BJR_REQ_RS (1L<<8)
-#define DM_BJR_REQ_RT (1L<<9)
-
-struct DecodeMap {
- long flags;
- enum AluOp alu;
- enum MemoryAccess::AccessControl mem_ctl;
-};
-
-#define NOALU .alu = ALU_OP_SLL
-#define NOMEM .mem_ctl = MemoryAccess::AC_NONE
-#define NOPE { .flags = 0, NOALU, NOMEM }
-
-#define FLAGS_ALU_I (DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE)
-#define FLAGS_ALU_I_ZE (DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_ZERO_EXTEND)
-
-// This is map from opcode to signals.
-static const struct DecodeMap dmap[] = {
- { .flags = DM_SUPPORTED | DM_REGD | DM_REGWRITE, NOALU, NOMEM }, // Alu operations (aluop is decoded from function explicitly)
- { .flags = DM_SUPPORTED | DM_BJR_REQ_RS, NOALU, NOMEM }, // REGIMM (BLTZ, BGEZ)
- { .flags = DM_SUPPORTED, NOALU, NOMEM }, // J
- { .flags = DM_SUPPORTED | DM_PC_TO_R31 | DM_REGWRITE, .alu = ALU_OP_PASS_S, NOMEM }, // JAL
- { .flags = DM_SUPPORTED | DM_BJR_REQ_RS | DM_BJR_REQ_RT, NOALU, NOMEM }, // BEQ
- { .flags = DM_SUPPORTED | DM_BJR_REQ_RS | DM_BJR_REQ_RT, NOALU, NOMEM }, // BNE
- { .flags = DM_SUPPORTED | DM_BJR_REQ_RS, NOALU, NOMEM }, // BLEZ
- { .flags = DM_SUPPORTED | DM_BJR_REQ_RS, NOALU, NOMEM }, // BGTZ
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADD, NOMEM }, // ADDI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_ADDU, NOMEM }, // ADDIU
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLT, NOMEM }, // SLTI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_SLTU, NOMEM }, // SLTIU
- { .flags = FLAGS_ALU_I_ZE, .alu = ALU_OP_AND, NOMEM }, // ANDI
- { .flags = FLAGS_ALU_I_ZE, .alu = ALU_OP_OR, NOMEM }, // ORI
- { .flags = FLAGS_ALU_I_ZE, .alu = ALU_OP_XOR, NOMEM }, // XORI
- { .flags = FLAGS_ALU_I, .alu = ALU_OP_LUI, NOMEM}, // LUI
- NOPE, // 16
- NOPE, // 17
- NOPE, // 18
- NOPE, // 19
- NOPE, // 20
- NOPE, // 21
- NOPE, // 22
- NOPE, // 23
- NOPE, // 24
- NOPE, // 25
- NOPE, // 26
- NOPE, // 27
- NOPE, // 28
- NOPE, // 29
- NOPE, // 30
- NOPE, // 31
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_BYTE }, // LB
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_HALFWORD }, // LH
- NOPE, // LWL
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_WORD }, // LW
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_BYTE_UNSIGNED }, // LBU
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_REGWRITE | DM_MEMREAD, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_HALFWORD_UNSIGNED }, // LHU
- NOPE, // LWR
- NOPE, // 39
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_BYTE }, // SB
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_HALFWORD }, // SH
- NOPE, // SWL
- { .flags = DM_SUPPORTED | DM_ALUSRC | DM_MEMWRITE, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_WORD }, // SW
- NOPE, // 44
- NOPE, // 45
- NOPE, // SWR
- { .flags = DM_SUPPORTED | DM_ALUSRC, .alu = ALU_OP_ADDU, .mem_ctl = MemoryAccess::AC_CACHE_OP }, // CACHE
- NOPE, // 48
- NOPE, // 49
- NOPE, // 50
- NOPE, // 51
- NOPE, // 52
- NOPE, // 53
- NOPE, // 54
- NOPE, // 55
- NOPE, // 56
- NOPE, // 57
- NOPE, // 58
- NOPE, // 59
- NOPE, // 60
- NOPE, // 61
- NOPE, // 62
- NOPE // 63
-};
-
Core::Core(Registers *regs, MemoryAccess *mem_program, MemoryAccess *mem_data) {
cycle_c = 0;
this->regs = regs;
@@ -165,20 +73,22 @@ struct Core::dtFetch Core::fetch() {
struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
uint8_t rwrite;
emit instruction_decoded(dt.inst);
- const struct DecodeMap &dec = dmap[dt.inst.opcode()];
+ enum InstructionFlags flags = dt.inst.flags();
+ enum AluOp alu_op = dt.inst.alu_op();
+ enum AccessControl mem_ctl = dt.inst.mem_ctl();
- if (!(dec.flags & DM_SUPPORTED))
+ if (!(flags & IMF_SUPPORTED))
throw QTMIPS_EXCEPTION(UnsupportedInstruction, "Instruction with following opcode is not supported", QString::number(dt.inst.opcode(), 16));
std::uint32_t val_rs = regs->read_gp(dt.inst.rs());
std::uint32_t val_rt = regs->read_gp(dt.inst.rt());
std::uint32_t immediate_val;
- bool regwrite = dec.flags & DM_REGWRITE;
- bool regd = dec.flags & DM_REGD;
- bool regd31 = dec.flags & DM_PC_TO_R31;
+ bool regwrite = flags & IMF_REGWRITE;
+ bool regd = flags & IMF_REGD;
+ bool regd31 = flags & IMF_PC_TO_R31;
// requires rs for beq, bne, blez, bgtz, jr nad jalr
- bool bjr_req_rs = dec.flags & DM_BJR_REQ_RS;
+ bool bjr_req_rs = flags & IMF_BJR_REQ_RS;
if (dt.inst.opcode() == 0) {
switch (dt.inst.funct()) {
case ALU_OP_BREAK:
@@ -207,9 +117,9 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
}
}
// requires rt for beq, bne
- bool bjr_req_rt = dec.flags & DM_BJR_REQ_RT;
+ bool bjr_req_rt = flags & IMF_BJR_REQ_RT;
- if (dec.flags & DM_ZERO_EXTEND)
+ if (flags & IMF_ZERO_EXTEND)
immediate_val = dt.inst.immediate();
else
immediate_val = sign_extend(dt.inst.immediate());
@@ -218,12 +128,12 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
emit decode_reg1_value(val_rs);
emit decode_reg2_value(val_rt);
emit decode_immediate_value(immediate_val);
- emit decode_regw_value((bool)(dec.flags & DM_REGWRITE));
- emit decode_memtoreg_value((bool)(dec.flags & DM_MEMREAD));
- emit decode_memwrite_value((bool)(dec.flags & DM_MEMWRITE));
- emit decode_memread_value((bool)(dec.flags & DM_MEMREAD));
- emit decode_alusrc_value((bool)(dec.flags & DM_ALUSRC));
- emit decode_regdest_value((bool)(dec.flags & DM_REGD));
+ emit decode_regw_value((bool)(flags & IMF_REGWRITE));
+ emit decode_memtoreg_value((bool)(flags & IMF_MEMREAD));
+ emit decode_memwrite_value((bool)(flags & IMF_MEMWRITE));
+ emit decode_memread_value((bool)(flags & IMF_MEMREAD));
+ emit decode_alusrc_value((bool)(flags & IMF_ALUSRC));
+ emit decode_regdest_value((bool)(flags & IMF_REGD));
emit decode_rs_num_value(dt.inst.rs());
emit decode_rt_num_value(dt.inst.rt());
emit decode_rd_num_value(dt.inst.rd());
@@ -237,9 +147,9 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
return {
.inst = dt.inst,
- .memread = dec.flags & DM_MEMREAD,
- .memwrite = dec.flags & DM_MEMWRITE,
- .alusrc = dec.flags & DM_ALUSRC,
+ .memread = flags & IMF_MEMREAD,
+ .memwrite = flags & IMF_MEMWRITE,
+ .alusrc = flags & IMF_ALUSRC,
.regd = regd,
.regd31 = regd31,
.regwrite = regwrite,
@@ -247,8 +157,8 @@ struct Core::dtDecode Core::decode(const struct dtFetch &dt) {
.bjr_req_rt = bjr_req_rt,
.forward_m_d_rs = false,
.forward_m_d_rt = false,
- .aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : dec.alu,
- .memctl = dec.mem_ctl,
+ .aluop = dt.inst.opcode() == 0 ? (enum AluOp)dt.inst.funct() : alu_op,
+ .memctl = mem_ctl,
.val_rs = val_rs,
.val_rt = val_rt,
.immediate_val = immediate_val,
@@ -302,7 +212,7 @@ struct Core::dtMemory Core::memory(const struct dtExecute &dt) {
emit instruction_memory(dt.inst);
std::uint32_t towrite_val = dt.alu_val;
- if (dt.memctl == MemoryAccess::AC_CACHE_OP)
+ if (dt.memctl == AC_CACHE_OP)
mem_data->sync();
else if (dt.memwrite)
mem_data->write_ctl(dt.memctl, dt.alu_val, dt.val_rt);
@@ -423,7 +333,7 @@ void Core::dtExecuteInit(struct dtExecute &dt) {
dt.memread = false;
dt.memwrite = false;
dt.regwrite = false;
- dt.memctl = MemoryAccess::AC_NONE;
+ dt.memctl = AC_NONE;
dt.val_rt = 0;
dt.rwrite = 0;
dt.alu_val = 0;
diff --git a/qtmips_machine/core.h b/qtmips_machine/core.h
index bc78c68..3a27f55 100644
--- a/qtmips_machine/core.h
+++ b/qtmips_machine/core.h
@@ -137,7 +137,7 @@ protected:
bool forward_m_d_rs; // forwarding required for beq, bne, blez, bgtz, jr nad jalr
bool forward_m_d_rt; // forwarding required for beq, bne
enum AluOp aluop; // Decoded ALU operation
- enum MemoryAccess::AccessControl memctl; // Decoded memory access type
+ enum AccessControl memctl; // Decoded memory access type
std::uint32_t val_rs; // Value from register rs
std::uint32_t val_rt; // Value from register rt
std::uint32_t immediate_val; // zero or sign-extended immediate value
@@ -150,7 +150,7 @@ protected:
bool memread;
bool memwrite;
bool regwrite;
- enum MemoryAccess::AccessControl memctl;
+ enum AccessControl memctl;
std::uint32_t val_rt;
std::uint8_t rwrite; // Writeback register (multiplexed between rt and rd according to regd)
std::uint32_t alu_val; // Result of ALU execution
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index 5743c69..9a7b9c9 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -35,43 +35,73 @@
#include "instruction.h"
#include "alu.h"
+#include "memory.h"
#include "qtmipsexception.h"
using namespace machine;
-#define IMF_NO_RS (1<<0) // This instruction doesn't have rs field
-#define IMF_MEM (1<<1) // This instruction is memory access instruction
+#define FLAGS_ALU_I (IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE)
+#define FLAGS_ALU_I_ZE (IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_ZERO_EXTEND)
+
+#define FLAGS_ALU_T_R (IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE)
+#define FLAGS_ALU_T_R_STD (IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE \
+ | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT)
+#define FLAGS_ALU_T_R_ST (IMF_SUPPORTED | IMF_ALU_REQ_RS | IMF_ALU_REQ_RT)
+#define FLAGS_ALU_T_R_S (IMF_SUPPORTED | IMF_ALU_REQ_RS)
+#define FLAGS_ALU_T_R_D (IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE )
+#define FLAGS_ALU_T_R_SD (IMF_SUPPORTED | IMF_REGD | IMF_REGWRITE | IMF_ALU_REQ_RS)
+
+#define NOALU .alu = ALU_OP_SLL
+#define NOMEM .mem_ctl = AC_NONE
+
+#define IM_UNKNOWN {"UNKNOWN", Instruction::T_UNKNOWN, NOALU, NOMEM, .flags = 0}
struct InstructionMap {
const char *name;
enum Instruction::Type type;
- bool is_store;
- unsigned flags;
+ enum AluOp alu;
+ enum AccessControl mem_ctl;
+ unsigned int flags;
};
#define IT_R Instruction::T_R
#define IT_I Instruction::T_I
#define IT_J Instruction::T_J
-#define IM_UNKNOWN {"UNKNOWN", Instruction::T_UNKNOWN, false, .flags = 0}
// This table is indexed by opcode
static const struct InstructionMap instruction_map[] = {
- {"ALU", IT_R, false, .flags = 0}, // Alu operations
- {"REGIMM", IT_I, false, .flags = 0}, // REGIMM (BLTZ, BGEZ)
- {"J", IT_J, false, .flags = 0},
- {"JAL", IT_J, false, .flags = 0},
- {"BEQ", IT_I, false, .flags = 0},
- {"BNE", IT_I, false, .flags = 0},
- {"BLEZ", IT_I, false, .flags = 0},
- {"BGTZ", IT_I, false, .flags = 0},
- {"ADDI", IT_I, false, .flags = 0},
- {"ADDIU", IT_I, false, .flags = 0},
- {"SLTI", IT_I, false, .flags = 0},
- {"SLTIU", IT_I, false, .flags = 0},
- {"ANDI", IT_I, false, .flags = 0},
- {"ORI", IT_I, false, .flags = 0},
- {"XORI", IT_I, false, .flags = 0},
- {"LUI", IT_I, false, .flags = IMF_NO_RS},
+ {"ALU", IT_R, NOALU, NOMEM, // Alu operations
+ .flags = 0},
+ {"REGIMM", IT_I, NOALU, NOMEM, // REGIMM (BLTZ, BGEZ)
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ {"J", IT_J, NOALU, NOMEM, // J
+ .flags = IMF_SUPPORTED},
+ {"JAL", IT_J, ALU_OP_PASS_S, NOMEM, // JAL
+ .flags = IMF_SUPPORTED | IMF_PC_TO_R31 | IMF_REGWRITE},
+ {"BEQ", IT_I, NOALU, NOMEM, // BEQ
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT},
+ {"BNE", IT_I, NOALU, NOMEM, // BNE
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS | IMF_BJR_REQ_RT},
+ {"BLEZ", IT_I, NOALU, NOMEM, // BLEZ
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ {"BGTZ", IT_I, NOALU, NOMEM, // BGTZ
+ .flags = IMF_SUPPORTED | IMF_BJR_REQ_RS},
+ {"ADDI", IT_I, ALU_OP_ADD, NOMEM, // ADDI
+ .flags = FLAGS_ALU_I},
+ {"ADDIU", IT_I, ALU_OP_ADDU, NOMEM, // ADDIU
+ .flags = FLAGS_ALU_I},
+ {"SLTI", IT_I, ALU_OP_SLT, NOMEM, // SLTI
+ .flags = FLAGS_ALU_I},
+ {"SLTIU", IT_I, ALU_OP_SLTU, NOMEM, // SLTIU
+ .flags = FLAGS_ALU_I},
+ {"ANDI", IT_I, ALU_OP_AND, NOMEM, // ANDI
+ .flags = FLAGS_ALU_I_ZE},
+ {"ORI", IT_I, ALU_OP_OR, NOMEM, // ORI
+ .flags = FLAGS_ALU_I_ZE},
+ {"XORI", IT_I, ALU_OP_XOR, NOMEM, // XORI
+ .flags = FLAGS_ALU_I_ZE},
+ {"LUI", IT_I, ALU_OP_LUI, NOMEM, // LUI
+ .flags = FLAGS_ALU_I},
IM_UNKNOWN, // 16
IM_UNKNOWN, // 17
IM_UNKNOWN, // 18
@@ -88,22 +118,35 @@ static const struct InstructionMap instruction_map[] = {
IM_UNKNOWN, // 29
IM_UNKNOWN, // 30
IM_UNKNOWN, // 31
- {"LB", IT_I, false, .flags = IMF_MEM},
- {"LH", IT_I, false, .flags = IMF_MEM},
- {"LWL", IT_I, false, .flags = IMF_MEM},
- {"LW", IT_I, false, .flags = IMF_MEM},
- {"LBU", IT_I, false, .flags = IMF_MEM},
- {"LHU", IT_I, false, .flags = IMF_MEM},
- {"LWR", IT_I, false, .flags = IMF_MEM},
+ {"LB", IT_I, ALU_OP_ADDU, AC_BYTE, // LB
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM},
+ {"LH", IT_I, ALU_OP_ADDU, AC_HALFWORD, // LH
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM},
+ {"LWL", IT_I, ALU_OP_ADDU, NOMEM, // LWL - unsupported
+ .flags = IMF_MEM},
+ {"LW", IT_I, ALU_OP_ADDU, AC_WORD, // LW
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM},
+ {"LBU", IT_I, ALU_OP_ADDU, AC_BYTE_UNSIGNED, // LBU
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM },
+ {"LHU", IT_I, ALU_OP_ADDU, AC_HALFWORD_UNSIGNED, // LHU
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_MEMREAD | IMF_MEM,},
+ {"LWR", IT_I, ALU_OP_ADDU, NOMEM, // LWR - unsupported
+ .flags = IMF_MEM},
IM_UNKNOWN, // 39
- {"SB", IT_I, true, .flags = IMF_MEM},
- {"SH", IT_I, true, .flags = IMF_MEM},
- {"SWL", IT_I, true, .flags = IMF_MEM},
- {"SW", IT_I, true, .flags = IMF_MEM},
- IM_UNKNOWN, // 44
- IM_UNKNOWN, // 45
- {"SWR", IT_I, true, .flags = IMF_MEM},
- {"CACHE", IT_I, true, .flags = IMF_MEM}, // 47
+ {"SB", IT_I, ALU_OP_ADDU, AC_BYTE, // SB
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_MEMWRITE | IMF_MEM | IMF_MEM_STORE},
+ {"SH", IT_I, ALU_OP_ADDU, AC_HALFWORD, // SH
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_MEMWRITE | IMF_MEM | IMF_MEM_STORE},
+ {"SWL", IT_I, ALU_OP_ADDU, NOMEM, // SWL
+ .flags = IMF_MEM | IMF_MEM_STORE},
+ {"SW", IT_I, ALU_OP_ADDU, AC_WORD, // SW
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_MEMWRITE | IMF_MEM | IMF_MEM_STORE},
+ IM_UNKNOWN, // 44,NOPE, // 44
+ IM_UNKNOWN, // 45,NOPE, // 45
+ {"SWR", IT_I, ALU_OP_ADDU, NOMEM, // SWR
+ .flags = IMF_MEM | IMF_MEM_STORE},
+ {"CACHE", IT_I, ALU_OP_ADDU, AC_CACHE_OP, // CACHE
+ .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_MEM| IMF_MEM_STORE},
IM_UNKNOWN, // 48
IM_UNKNOWN, // 49
IM_UNKNOWN, // 50
@@ -118,63 +161,63 @@ static const struct InstructionMap instruction_map[] = {
IM_UNKNOWN, // 59
IM_UNKNOWN, // 60
IM_UNKNOWN, // 61
- IM_UNKNOWN, // 61
IM_UNKNOWN, // 62
- IM_UNKNOWN // 63
+ IM_UNKNOWN, // 63
};
#undef IM_UNKNOWN
struct AluInstructionMap {
const char *name;
+ unsigned int flags;
};
#define AIM_UNKNOWN {"UNKNOWN"}
// This table is indexed by funct
static const struct AluInstructionMap alu_instruction_map[] = {
- {"SLL"},
+ {"SLL", FLAGS_ALU_T_R_STD},
AIM_UNKNOWN,
- {"SRL"},
- {"SRA"},
- {"SLLV"},
+ {"SRL", FLAGS_ALU_T_R_SD},
+ {"SRA", FLAGS_ALU_T_R_SD},
+ {"SLLV", FLAGS_ALU_T_R_STD},
AIM_UNKNOWN,
- {"SRLV"},
- {"SRAV"},
- {"JR"},
- {"JALR"},
- {"MOVZ"},
- {"MOVN"},
+ {"SRLV", FLAGS_ALU_T_R_STD},
+ {"SRAV", FLAGS_ALU_T_R_STD},
+ {"JR", FLAGS_ALU_T_R_S},
+ {"JALR", FLAGS_ALU_T_R_SD},
+ {"MOVZ", FLAGS_ALU_T_R_STD},
+ {"MOVN", FLAGS_ALU_T_R_STD},
AIM_UNKNOWN,
- {"BREAK"},
+ {"BREAK", IMF_SUPPORTED},
AIM_UNKNOWN,
AIM_UNKNOWN,
- {"MFHI"},
- {"MTHI"},
- {"MFLO"},
- {"MTLO"},
+ {"MFHI", FLAGS_ALU_T_R_D | IMF_READ_HILO},
+ {"MTHI", FLAGS_ALU_T_R_S | IMF_WRITE_HILO},
+ {"MFLO", FLAGS_ALU_T_R_D | IMF_READ_HILO},
+ {"MTLO", FLAGS_ALU_T_R_S | IMF_WRITE_HILO},
AIM_UNKNOWN,
AIM_UNKNOWN,
AIM_UNKNOWN,
AIM_UNKNOWN,
- {"MULT"}, // 24
- {"MULTU"}, // 25
- {"DIV"}, // 26
- {"DIVU"}, // 27
+ {"MULT", FLAGS_ALU_T_R_ST | IMF_WRITE_HILO}, // 24
+ {"MULTU", FLAGS_ALU_T_R_ST | IMF_WRITE_HILO}, // 25
+ {"DIV", FLAGS_ALU_T_R_ST | IMF_WRITE_HILO}, // 26
+ {"DIVU", FLAGS_ALU_T_R_ST | IMF_WRITE_HILO}, // 27
AIM_UNKNOWN, // 28
AIM_UNKNOWN, // 29
AIM_UNKNOWN, // 30
AIM_UNKNOWN, // 31
- {"ADD"}, // 32
- {"ADDU"},
- {"SUB"},
- {"SUBU"},
- {"AND"},
- {"OR"},
- {"XOR"},
- {"NOR"},
+ {"ADD", FLAGS_ALU_T_R_STD}, // 32
+ {"ADDU", FLAGS_ALU_T_R_STD},
+ {"SUB", FLAGS_ALU_T_R_STD},
+ {"SUBU", FLAGS_ALU_T_R_STD},
+ {"AND", FLAGS_ALU_T_R_STD},
+ {"OR", FLAGS_ALU_T_R_STD},
+ {"XOR", FLAGS_ALU_T_R_STD},
+ {"NOR", FLAGS_ALU_T_R_STD},
AIM_UNKNOWN,
AIM_UNKNOWN,
- {"SLT"},
- {"SLTU"}
+ {"SLT", FLAGS_ALU_T_R_STD},
+ {"SLTU", FLAGS_ALU_T_R_STD}
};
#undef AIM_UNKNOWN
@@ -260,11 +303,33 @@ enum Instruction::Type Instruction::type() const {
return im.type;
}
+enum InstructionFlags Instruction::flags() const {
+ if (opcode() >= (sizeof(instruction_map) / sizeof(struct InstructionMap)))
+ return (enum InstructionFlags)0;
+ if (opcode() == 0) {
+ return (enum InstructionFlags)alu_instruction_map[funct()].flags;
+ }
+ const struct InstructionMap &im = instruction_map[opcode()];
+ return (enum InstructionFlags)im.flags;
+}
+enum AluOp Instruction::alu_op() const {
+ if (opcode() >= (sizeof(instruction_map) / sizeof(struct InstructionMap)))
+ return ALU_OP_UNKNOWN;
+ const struct InstructionMap &im = instruction_map[opcode()];
+ return im.alu;
+}
+enum AccessControl Instruction::mem_ctl() const {
+ if (opcode() >= (sizeof(instruction_map) / sizeof(struct InstructionMap)))
+ return AC_NONE;
+ const struct InstructionMap &im = instruction_map[opcode()];
+ return im.mem_ctl;
+}
+
bool Instruction::is_store() const {
if (opcode() >= (sizeof(instruction_map) / sizeof(struct InstructionMap)))
return false;
const struct InstructionMap &im = instruction_map[opcode()];
- return im.is_store;
+ return im.flags & IMF_MEM_STORE;
}
bool Instruction::is_break() const {
@@ -285,7 +350,6 @@ Instruction &Instruction::operator=(const Instruction &c) {
return *this;
}
-
QString Instruction::to_str() const {
// TODO there are exception where some fields are zero and such so we should not print them in such case
if (opcode() >= (sizeof(instruction_map) / sizeof(struct InstructionMap)))
diff --git a/qtmips_machine/instruction.h b/qtmips_machine/instruction.h
index 09ea535..8286679 100644
--- a/qtmips_machine/instruction.h
+++ b/qtmips_machine/instruction.h
@@ -39,8 +39,30 @@
#include <QObject>
#include <qstring.h>
+#include "machinedefs.h"
+
namespace machine {
+enum InstructionFlags {
+ IMF_SUPPORTED = 1L<<0,
+ IMF_MEMWRITE = 1L<<1,
+ IMF_MEMREAD = 1L<<2,
+ IMF_ALUSRC = 1L<<3,
+ IMF_REGD = 1L<<4,
+ IMF_REGWRITE = 1L<<5,
+ IMF_ZERO_EXTEND= 1L<<6,
+ IMF_PC_TO_R31 = 1L<<7,
+ IMF_BJR_REQ_RS = 1L<<8,
+ IMF_BJR_REQ_RT = 1L<<9,
+ IMF_NO_RS = 1L<<10, // This instruction doesn't have rs field,
+ IMF_MEM = 1L<<11, // This instruction is memory access instruction,
+ IMF_MEM_STORE = 1L<<12,
+ IMF_ALU_REQ_RS = 1L<<13,
+ IMF_ALU_REQ_RT = 1L<<14,
+ IMF_READ_HILO = 1L<<15,
+ IMF_WRITE_HILO = 1L<<16,
+};
+
class Instruction {
public:
Instruction();
@@ -67,6 +89,10 @@ public:
std::uint32_t address() const;
std::uint32_t data() const;
enum Type type() const;
+ enum InstructionFlags flags() const;
+ enum AluOp alu_op() const;
+ enum AccessControl mem_ctl() const;
+
bool is_store() const; // Store instructions requires some additional handling so identify them
bool is_break() const;
diff --git a/qtmips_machine/machinedefs.h b/qtmips_machine/machinedefs.h
new file mode 100644
index 0000000..0629f3e
--- /dev/null
+++ b/qtmips_machine/machinedefs.h
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*******************************************************************************
+ * QtMips - MIPS 32-bit Architecture Subset Simulator
+ *
+ * Implemented to support following courses:
+ *
+ * B35APO - Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b35apo
+ *
+ * B4M35PAP - Advanced Computer Architectures
+ * https://cw.fel.cvut.cz/wiki/courses/b4m35pap/start
+ *
+ * Copyright (c) 2017-2019 Karel Koci<cynerd@email.cz>
+ * Copyright (c) 2019 Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ *
+ * Faculty of Electrical Engineering (http://www.fel.cvut.cz)
+ * Czech Technical University (http://www.cvut.cz/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ ******************************************************************************/
+
+#ifndef MACHINEDEFS_H
+#define MACHINEDEFS_H
+
+#include <stdint.h>
+
+namespace machine {
+
+enum AccessControl {
+ AC_NONE,
+ AC_BYTE,
+ AC_HALFWORD,
+ AC_WORD,
+ AC_BYTE_UNSIGNED,
+ AC_HALFWORD_UNSIGNED,
+ AC_CACHE_OP,
+};
+
+enum AluOp : std::uint8_t {
+ ALU_OP_SLL = 0,
+ ALU_OP_SRL = 2,
+ ALU_OP_SRA,
+ ALU_OP_SLLV,
+ ALU_OP_SRLV = 6,
+ ALU_OP_SRAV,
+ ALU_OP_JR,
+ ALU_OP_JALR,
+ ALU_OP_MOVZ,
+ ALU_OP_MOVN,
+ ALU_OP_BREAK = 13,
+ ALU_OP_MFHI = 16,
+ ALU_OP_MTHI,
+ ALU_OP_MFLO,
+ ALU_OP_MTLO,
+ ALU_OP_MULT = 24,
+ ALU_OP_MULTU = 25,
+ ALU_OP_DIV = 26,
+ ALU_OP_DIVU = 27,
+ ALU_OP_ADD = 32,
+ ALU_OP_ADDU,
+ ALU_OP_SUB,
+ ALU_OP_SUBU,
+ ALU_OP_AND,
+ ALU_OP_OR,
+ ALU_OP_XOR,
+ ALU_OP_NOR,
+ ALU_OP_SLT = 42,
+ ALU_OP_SLTU,
+ ALU_OP_LUI = 64, // We don't care about exact index for this one
+ ALU_OP_PASS_S, // Pass s argument without change for JAL
+ ALU_OP_UNKNOWN, // Pass s argument without change for JAL
+ ALU_OP_LAST // First impossible operation (just to be sure that we don't overflow)
+};
+
+}
+
+#endif // MACHINEDEFS_H
diff --git a/qtmips_machine/memory.cpp b/qtmips_machine/memory.cpp
index 2df0193..338835d 100644
--- a/qtmips_machine/memory.cpp
+++ b/qtmips_machine/memory.cpp
@@ -75,7 +75,7 @@ std::uint32_t MemoryAccess::read_word(std::uint32_t offset) const {
return rword(offset);
}
-void MemoryAccess::write_ctl(enum MemoryAccess::AccessControl ctl, std::uint32_t offset, std::uint32_t value) {
+void MemoryAccess::write_ctl(enum AccessControl ctl, std::uint32_t offset, std::uint32_t value) {
switch (ctl) {
case AC_NONE:
break;
@@ -95,7 +95,7 @@ void MemoryAccess::write_ctl(enum MemoryAccess::AccessControl ctl, std::uint32_t
}
}
-std::uint32_t MemoryAccess::read_ctl(enum MemoryAccess::AccessControl ctl, std::uint32_t offset) const {
+std::uint32_t MemoryAccess::read_ctl(enum AccessControl ctl, std::uint32_t offset) const {
switch (ctl) {
case AC_NONE:
return 0;
diff --git a/qtmips_machine/memory.h b/qtmips_machine/memory.h
index aa75b18..bbcbd13 100644
--- a/qtmips_machine/memory.h
+++ b/qtmips_machine/memory.h
@@ -39,6 +39,7 @@
#include <QObject>
#include <cstdint>
#include <qtmipsexception.h>
+#include "machinedefs.h"
namespace machine {
@@ -55,15 +56,6 @@ public:
std::uint16_t read_hword(std::uint32_t offset) const;
std::uint32_t read_word(std::uint32_t offset) const;
- enum AccessControl {
- AC_NONE,
- AC_BYTE,
- AC_HALFWORD,
- AC_WORD,
- AC_BYTE_UNSIGNED,
- AC_HALFWORD_UNSIGNED,
- AC_CACHE_OP,
- };
void write_ctl(enum AccessControl ctl, std::uint32_t offset, std::uint32_t value);
std::uint32_t read_ctl(enum AccessControl ctl, std::uint32_t offset) const;
@@ -138,7 +130,7 @@ private:
}
-Q_DECLARE_METATYPE(machine::MemoryAccess::AccessControl)
+Q_DECLARE_METATYPE(machine::AccessControl)
Q_DECLARE_METATYPE(machine::Memory)
#endif // MEMORY_H
diff --git a/qtmips_machine/qtmips_machine.pro b/qtmips_machine/qtmips_machine.pro
index 503832e..eae7b6e 100644
--- a/qtmips_machine/qtmips_machine.pro
+++ b/qtmips_machine/qtmips_machine.pro
@@ -36,4 +36,5 @@ HEADERS += \
cache.h \
alu.h \
machineconfig.h \
- utils.h
+ utils.h \
+ machinedefs.h
diff --git a/qtmips_machine/tests/testmemory.cpp b/qtmips_machine/tests/testmemory.cpp
index 29ad2bc..d24ec54 100644
--- a/qtmips_machine/tests/testmemory.cpp
+++ b/qtmips_machine/tests/testmemory.cpp
@@ -142,29 +142,29 @@ void MachineTests::memory_compare() {
}
void MachineTests::memory_write_ctl_data() {
- QTest::addColumn<MemoryAccess::AccessControl>("ctl");
+ QTest::addColumn<AccessControl>("ctl");
QTest::addColumn<Memory>("result");
Memory mem;
- QTest::newRow("none") << MemoryAccess::AC_NONE \
+ QTest::newRow("none") << AC_NONE \
<< mem;
mem.write_byte(0x20, 0x26);
- QTest::newRow("byte") << MemoryAccess::AC_BYTE \
+ QTest::newRow("byte") << AC_BYTE \
<< mem;
- QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \
+ QTest::newRow("byte-unsigned") << AC_BYTE_UNSIGNED \
<< mem;
mem.write_hword(0x20, 0x2526);
- QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \
+ QTest::newRow("halfword") << AC_HALFWORD \
<< mem;
- QTest::newRow("haldword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \
+ QTest::newRow("haldword-unsigned") << AC_HALFWORD_UNSIGNED \
<< mem;
mem.write_word(0x20, 0x23242526);
- QTest::newRow("word") << MemoryAccess::AC_WORD \
+ QTest::newRow("word") << AC_WORD \
<< mem;
}
void MachineTests::memory_write_ctl() {
- QFETCH(MemoryAccess::AccessControl, ctl);
+ QFETCH(AccessControl, ctl);
QFETCH(Memory, result);
Memory mem;
@@ -173,25 +173,25 @@ void MachineTests::memory_write_ctl() {
}
void MachineTests::memory_read_ctl_data() {
- QTest::addColumn<MemoryAccess::AccessControl>("ctl");
+ QTest::addColumn<AccessControl>("ctl");
QTest::addColumn<std::uint32_t>("result");
- QTest::newRow("none") << MemoryAccess::AC_NONE \
+ QTest::newRow("none") << AC_NONE \
<< (std::uint32_t)0;
- QTest::newRow("byte") << MemoryAccess::AC_BYTE \
+ QTest::newRow("byte") << AC_BYTE \
<< (std::uint32_t)0x80000023;
- QTest::newRow("halfword") << MemoryAccess::AC_HALFWORD \
+ QTest::newRow("halfword") << AC_HALFWORD \
<< (std::uint32_t)0x80002324;
- QTest::newRow("word") << MemoryAccess::AC_WORD \
+ QTest::newRow("word") << AC_WORD \
<< (std::uint32_t)0xA3242526;
- QTest::newRow("byte-unsigned") << MemoryAccess::AC_BYTE_UNSIGNED \
+ QTest::newRow("byte-unsigned") << AC_BYTE_UNSIGNED \
<< (std::uint32_t)0xA3;
- QTest::newRow("halfword-unsigned") << MemoryAccess::AC_HALFWORD_UNSIGNED \
+ QTest::newRow("halfword-unsigned") << AC_HALFWORD_UNSIGNED \
<< (std::uint32_t)0xA324;
}
void MachineTests::memory_read_ctl() {
- QFETCH(MemoryAccess::AccessControl, ctl);
+ QFETCH(AccessControl, ctl);
QFETCH(std::uint32_t, result);
Memory mem;