From 10fa419862f57ab46290e34779404845bdcefee8 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Fri, 15 Feb 2019 21:46:45 +0100 Subject: Multiply and accumulate and CLZ/CLO operations added. Signed-off-by: Pavel Pisa --- qtmips_machine/alu.cpp | 83 ++++++++++++++++++++++++++++++++++++++++-- qtmips_machine/instruction.cpp | 20 ++++++---- qtmips_machine/machinedefs.h | 6 +++ 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, -- cgit v1.2.3