aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qtmips_machine/alu.cpp83
-rw-r--r--qtmips_machine/instruction.cpp20
-rw-r--r--qtmips_machine/machinedefs.h6
3 files changed, 98 insertions, 11 deletions
diff --git a/qtmips_machine/alu.cpp b/qtmips_machine/alu.cpp
index 79194c9..c86331b 100644
--- a/qtmips_machine/alu.cpp
+++ b/qtmips_machine/alu.cpp
@@ -39,6 +39,59 @@
using namespace machine;
+#if defined(__GNUC__) && __GNUC__ >= 4
+
+static inline std::uint32_t alu_op_clz(std::uint32_t n)
+{
+ int intbits = sizeof(int) * CHAR_BIT;
+ if (n == 0)
+ return 32;
+ return __builtin_clz(n) - (intbits - 32);
+}
+
+#else /* Fallback for generic compiler */
+
+// see https://en.wikipedia.org/wiki/Find_first_set#CLZ
+static const std::uint8_t sig_table_4bit[16] =
+ { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 };
+
+static inline std::uint32_t alu_op_clz(std::uint32_t n)
+{
+ int len = 32;
+
+ if (n & 0xFFFF0000) {
+ len -= 16;
+ n >>= 16;
+ }
+ if (n & 0xFF00) {
+ len -= 8;
+ n >>= 8;
+ }
+ if (n & 0xF0) {
+ len -= 4;
+ n >>= 4;
+ }
+ len -= sig_table_4bit[n];
+ return len;
+}
+
+#endif /* end of mips_clz */
+
+static inline std::uint64_t alu_read_hi_lo_64bit(Registers *regs)
+{
+ std::uint64_t val;
+ val = regs->read_hi_lo(false);
+ val |= (std::uint64_t)regs->read_hi_lo(true) << 32;
+ return val;
+}
+
+static inline void alu_write_hi_lo_64bit(Registers *regs, std::uint64_t val)
+{
+ regs->write_hi_lo(false, (std::uint32_t)(val & 0xffffffff));
+ regs->write_hi_lo(true, (std::uint32_t)(val >> 32));
+}
+
+
std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::uint32_t t,
std::uint8_t sa, std::uint8_t sz, Registers *regs,
bool &discard) {
@@ -83,13 +136,11 @@ std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::u
return 0x0;
case ALU_OP_MULT:
s64_val = (std::int64_t)(std::int32_t)s * (std::int32_t)t;
- regs->write_hi_lo(false, (std::uint32_t)(s64_val & 0xffffffff));
- regs->write_hi_lo(true, (std::uint32_t)(s64_val >> 32));
+ alu_write_hi_lo_64bit(regs, (std::uint64_t)s64_val);
return 0x0;
case ALU_OP_MULTU:
u64_val = (std::uint64_t)s * t;
- regs->write_hi_lo(false, (std::uint32_t)(u64_val & 0xffffffff));
- regs->write_hi_lo(true, (std::uint32_t)(u64_val >> 32));
+ alu_write_hi_lo_64bit(regs, u64_val);
return 0x0;
case ALU_OP_DIV:
regs->write_hi_lo(false, (std::uint32_t)((std::int32_t)s / (std::int32_t)t));
@@ -130,12 +181,36 @@ std::uint32_t machine::alu_operate(enum AluOp operation, std::uint32_t s, std::u
return (s < t) ? 1 : 0;
case ALU_OP_MUL:
return (std::uint32_t)((std::int32_t)s * (std::int32_t)t);
+ case ALU_OP_MADD:
+ s64_val = (std::int64_t)alu_read_hi_lo_64bit(regs);
+ s64_val += (std::int64_t)(std::int32_t)s * (std::int32_t)t;
+ alu_write_hi_lo_64bit(regs, (std::uint64_t)s64_val);
+ return 0x0;
+ case ALU_OP_MADDU:
+ u64_val = alu_read_hi_lo_64bit(regs);
+ u64_val += (std::uint64_t)s * t;
+ alu_write_hi_lo_64bit(regs, u64_val);
+ return 0x0;
+ case ALU_OP_MSUB:
+ s64_val = (std::int64_t)alu_read_hi_lo_64bit(regs);
+ s64_val -= (std::int64_t)(std::int32_t)s * (std::int32_t)t;
+ alu_write_hi_lo_64bit(regs, (std::uint64_t)s64_val);
+ return 0x0;
+ case ALU_OP_MSUBU:
+ u64_val = alu_read_hi_lo_64bit(regs);
+ u64_val -= (std::uint64_t)s * t;
+ alu_write_hi_lo_64bit(regs, u64_val);
+ return 0x0;
case ALU_OP_LUI:
return t << 16;
case ALU_OP_BSHFL:
return (uint32_t)(int32_t)(int8_t)t;
case ALU_OP_EXT:
return (s >> sa) & ((1 << sz) - 1);
+ case ALU_OP_CLZ:
+ return alu_op_clz(s);
+ case ALU_OP_CLO:
+ return alu_op_clz(~s);
case ALU_OP_PASS_T: // Pass s argument without change for JAL
return t;
case ALU_OP_BREAK:
diff --git a/qtmips_machine/instruction.cpp b/qtmips_machine/instruction.cpp
index b26cc9b..68956b6 100644
--- a/qtmips_machine/instruction.cpp
+++ b/qtmips_machine/instruction.cpp
@@ -184,13 +184,17 @@ static const struct InstructionMap alu_instruction_map[] = {
};
static const struct InstructionMap special2_instruction_map[] = {
- IM_UNKNOWN, // 0
- IM_UNKNOWN, // 1
- {"MUL", IT_R, ALU_OP_MUL, NOMEM, nullptr,
+ {"MADD", IT_R, ALU_OP_MADD, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_ST | IMF_READ_HILO | IMF_WRITE_HILO},
+ {"MADD", IT_R, ALU_OP_MADDU, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_ST | IMF_READ_HILO | IMF_WRITE_HILO},
+ {"MUL", IT_R, ALU_OP_MUL, NOMEM, nullptr,
.flags = FLAGS_ALU_T_R_STD}, // 32
IM_UNKNOWN, // 3
- IM_UNKNOWN, // 4
- IM_UNKNOWN, // 5
+ {"MSUB", IT_R, ALU_OP_MSUB, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_ST | IMF_READ_HILO | IMF_WRITE_HILO},
+ {"MSUBU", IT_R, ALU_OP_MSUBU, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_ST | IMF_READ_HILO | IMF_WRITE_HILO},
IM_UNKNOWN, // 6
IM_UNKNOWN, // 7
IM_UNKNOWN, // 8
@@ -217,8 +221,10 @@ static const struct InstructionMap special2_instruction_map[] = {
IM_UNKNOWN, // 29
IM_UNKNOWN, // 30
IM_UNKNOWN, // 31
- IM_UNKNOWN, // 32
- IM_UNKNOWN, // 33
+ {"CLZ", IT_R, ALU_OP_CLZ, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_SD},
+ {"CLO", IT_R, ALU_OP_CLO, NOMEM, nullptr,
+ .flags = FLAGS_ALU_T_R_SD},
IM_UNKNOWN, // 34
IM_UNKNOWN, // 35
IM_UNKNOWN, // 36
diff --git a/qtmips_machine/machinedefs.h b/qtmips_machine/machinedefs.h
index a44aa75..8481540 100644
--- a/qtmips_machine/machinedefs.h
+++ b/qtmips_machine/machinedefs.h
@@ -93,9 +93,15 @@ enum AluOp : std::uint8_t {
ALU_OP_SLT,
ALU_OP_SLTU,
ALU_OP_MUL,
+ ALU_OP_MADD,
+ ALU_OP_MADDU,
+ ALU_OP_MSUB,
+ ALU_OP_MSUBU,
ALU_OP_LUI,
ALU_OP_BSHFL,
ALU_OP_EXT,
+ ALU_OP_CLZ,
+ ALU_OP_CLO,
ALU_OP_PASS_T, // Pass t argument without change for JAL
ALU_OP_BREAK,
ALU_OP_SYSCALL,