diff options
author | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-02-04 18:13:58 +0100 |
---|---|---|
committer | Pavel Pisa <pisa@cmp.felk.cvut.cz> | 2019-02-04 18:13:58 +0100 |
commit | 40580e24e7a7b2e774d001878dc493216e75b936 (patch) | |
tree | d5fd0e60a09c35111fabe9d8975a8cb2a087b431 /qtmips_machine | |
parent | 36492497ba7096fb20c417941d426e01870d213d (diff) | |
download | qtmips-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>
Diffstat (limited to 'qtmips_machine')
-rw-r--r-- | qtmips_machine/alu.h | 37 | ||||
-rw-r--r-- | qtmips_machine/core.cpp | 136 | ||||
-rw-r--r-- | qtmips_machine/core.h | 4 | ||||
-rw-r--r-- | qtmips_machine/instruction.cpp | 202 | ||||
-rw-r--r-- | qtmips_machine/instruction.h | 26 | ||||
-rw-r--r-- | qtmips_machine/machinedefs.h | 91 | ||||
-rw-r--r-- | qtmips_machine/memory.cpp | 4 | ||||
-rw-r--r-- | qtmips_machine/memory.h | 12 | ||||
-rw-r--r-- | qtmips_machine/qtmips_machine.pro | 3 | ||||
-rw-r--r-- | qtmips_machine/tests/testmemory.cpp | 32 |
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; |