M extension for RV64
This commit is contained in:
		
							parent
							
								
									56b00aecd8
								
							
						
					
					
						commit
						643b880be3
					
				|  | @ -25,7 +25,11 @@ namespace riscv_tlm { | |||
|         OP_M_DIVU, | ||||
|         OP_M_REM, | ||||
|         OP_M_REMU, | ||||
| 
 | ||||
|         OP_M_MULW, | ||||
|         OP_M_DIVW, | ||||
|         OP_M_DIVUW, | ||||
|         OP_M_REMW, | ||||
|         OP_M_REMUW, | ||||
|         OP_M_ERROR | ||||
|     } op_M_Codes; | ||||
| 
 | ||||
|  | @ -38,6 +42,11 @@ namespace riscv_tlm { | |||
|         M_DIVU = 0b101, | ||||
|         M_REM = 0b110, | ||||
|         M_REMU = 0b111, | ||||
|         M_MULW = 0b000, | ||||
|         M_DIVW = 0b100, | ||||
|         M_DIVUW = 0b101, | ||||
|         M_REMW = 0b110, | ||||
|         M_REMUW = 0b111, | ||||
|     } M_Codes; | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -61,34 +70,58 @@ namespace riscv_tlm { | |||
|          */ | ||||
|         [[nodiscard]] op_M_Codes decode() const { | ||||
| 
 | ||||
|             switch (opcode()) { | ||||
|                 case M_MUL: | ||||
|                     return OP_M_MUL; | ||||
|                     break; | ||||
|                 case M_MULH: | ||||
|                     return OP_M_MULH; | ||||
|                     break; | ||||
|                 case M_MULHSU: | ||||
|                     return OP_M_MULHSU; | ||||
|                     break; | ||||
|                 case M_MULHU: | ||||
|                     return OP_M_MULHU; | ||||
|                     break; | ||||
|                 case M_DIV: | ||||
|                     return OP_M_DIV; | ||||
|                     break; | ||||
|                 case M_DIVU: | ||||
|                     return OP_M_DIVU; | ||||
|                     break; | ||||
|                 case M_REM: | ||||
|                     return OP_M_REM; | ||||
|                     break; | ||||
|                 case M_REMU: | ||||
|                     return OP_M_REMU; | ||||
|                     break; | ||||
|             if (this->m_instr.range(6,0) == 0b110011) { | ||||
|                 switch (opcode()) { | ||||
|                     case M_MUL: | ||||
|                         return OP_M_MUL; | ||||
|                         break; | ||||
|                     case M_MULH: | ||||
|                         return OP_M_MULH; | ||||
|                         break; | ||||
|                     case M_MULHSU: | ||||
|                         return OP_M_MULHSU; | ||||
|                         break; | ||||
|                     case M_MULHU: | ||||
|                         return OP_M_MULHU; | ||||
|                         break; | ||||
|                     case M_DIV: | ||||
|                         return OP_M_DIV; | ||||
|                         break; | ||||
|                     case M_DIVU: | ||||
|                         return OP_M_DIVU; | ||||
|                         break; | ||||
|                     case M_REM: | ||||
|                         return OP_M_REM; | ||||
|                         break; | ||||
|                     case M_REMU: | ||||
|                         return OP_M_REMU; | ||||
|                         break; | ||||
|                         [[unlikely]] default: | ||||
|                         return OP_M_ERROR; | ||||
|                         break; | ||||
|                 } | ||||
|             } else { | ||||
|                 switch (opcode()) { | ||||
|                     case M_MULW: | ||||
|                         return OP_M_MULW; | ||||
|                         break; | ||||
|                     case M_DIVW: | ||||
|                         return OP_M_DIVW; | ||||
|                         break; | ||||
|                     case M_DIVUW: | ||||
|                         return OP_M_DIVUW; | ||||
|                         break; | ||||
|                     case M_REMW: | ||||
|                         return OP_M_REMW; | ||||
|                         break; | ||||
|                     case M_REMUW: | ||||
|                         return OP_M_REMUW; | ||||
|                         break; | ||||
|                     [[unlikely]] default: | ||||
|                     return OP_M_ERROR; | ||||
|                     break; | ||||
|                         return OP_M_ERROR; | ||||
|                         break; | ||||
| 
 | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return OP_M_ERROR; | ||||
|  | @ -100,107 +133,42 @@ namespace riscv_tlm { | |||
| 
 | ||||
|         void Exec_M_MUL() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t multiplier, multiplicand; | ||||
|             signed_T multiplier, multiplicand; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             multiplier = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs1)); | ||||
|             multiplicand = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs2)); | ||||
| 
 | ||||
|             multiplier = static_cast<signed_T>(this->regs->getValue(rs1)); | ||||
|             multiplicand = static_cast<signed_T>(this->regs->getValue(rs2)); | ||||
|             result = static_cast<std::int64_t>(multiplier * multiplicand); | ||||
|             result = result & 0x00000000FFFFFFFF; | ||||
|             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 extension_base<T>::regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
|             this->regs->setValue(rd, static_cast<signed_T>(result)); | ||||
| 
 | ||||
|         void Exec_M_MULH() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t multiplier, multiplicand; | ||||
|             std::int64_t result; | ||||
|             std::int32_t ret_value; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
| 
 | ||||
|             result = static_cast<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand); | ||||
| 
 | ||||
|             ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF); | ||||
|             this->regs->setValue(rd, ret_value); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|                                 rs1, rs2, multiplier, multiplicand, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_MULHSU() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t multiplier; | ||||
|             std::uint32_t multiplicand; | ||||
|             std::int64_t result; | ||||
|         void Exec_M_MULH() const; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
|         void Exec_M_MULHSU() const; | ||||
| 
 | ||||
|             multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
|             result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand)); | ||||
|             result = (result >> 32) & 0x00000000FFFFFFFF; | ||||
|             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_MULHU() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t multiplier, multiplicand; | ||||
|             std::uint64_t result; | ||||
|             std::int32_t ret_value; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
| 
 | ||||
|             result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand); | ||||
|             ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF); | ||||
|             this->regs->setValue(rd, ret_value); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
|         void Exec_M_MULHU() const; | ||||
| 
 | ||||
|         void Exec_M_DIV() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t divisor, dividend; | ||||
|             signed_T divisor, dividend; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
|             dividend = this->regs->getValue(rs1); | ||||
|             divisor = this->regs->getValue(rs2); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = -1; | ||||
|  | @ -208,10 +176,9 @@ namespace riscv_tlm { | |||
|                 result = 0x0000000080000000; | ||||
|             } else { | ||||
|                 result = dividend / divisor; | ||||
|                 result = result & 0x00000000FFFFFFFF; | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|  | @ -221,7 +188,7 @@ namespace riscv_tlm { | |||
| 
 | ||||
|         void Exec_M_DIVU() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t divisor, dividend; | ||||
|             unsigned_T divisor, dividend; | ||||
|             std::uint64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|  | @ -235,10 +202,9 @@ namespace riscv_tlm { | |||
|                 result = -1; | ||||
|             } else { | ||||
|                 result = dividend / divisor; | ||||
|                 result = result & 0x00000000FFFFFFFF; | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|  | @ -248,15 +214,15 @@ namespace riscv_tlm { | |||
| 
 | ||||
|         void Exec_M_REM() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t divisor, dividend; | ||||
|             std::int32_t result; | ||||
|             signed_T divisor, dividend; | ||||
|             signed_T result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
|             dividend = this->regs->getValue(rs1); | ||||
|             divisor = this->regs->getValue(rs2); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = dividend; | ||||
|  | @ -268,7 +234,7 @@ namespace riscv_tlm { | |||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} % x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|  | @ -276,15 +242,15 @@ namespace riscv_tlm { | |||
| 
 | ||||
|         void Exec_M_REMU() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t divisor, dividend; | ||||
|             std::uint32_t result; | ||||
|             unsigned_T divisor, dividend; | ||||
|             unsigned_T result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
|             dividend = this->regs->getValue(rs1); | ||||
|             divisor = this->regs->getValue(rs2); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = dividend; | ||||
|  | @ -292,14 +258,145 @@ namespace riscv_tlm { | |||
|                 result = dividend % divisor; | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} % x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_MULW() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t multiplier, multiplicand; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             multiplier = static_cast<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); | ||||
|             multiplicand = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); | ||||
|             result = static_cast<std::int32_t>((multiplier * multiplicand) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.MULW: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, multiplier, multiplicand, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_DIVW() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t divisor, dividend; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::int32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); | ||||
|             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = -1; | ||||
|             } else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) { | ||||
|                 result = 0x0000000080000000; | ||||
|             } else { | ||||
|                 result = dividend / divisor; | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.DIVW: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_DIVUW() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t divisor, dividend; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); | ||||
|             divisor = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = -1; | ||||
|             } else if ((divisor == 0xFFFFFFFF) && (dividend == static_cast<std::uint32_t>(0x80000000))) { | ||||
|                 result = 0x0000000080000000; | ||||
|             } else { | ||||
|                 result = static_cast<std::int32_t>(dividend / divisor); | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.DIVUW: x{:d} / x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_REMW() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::int32_t divisor, dividend; | ||||
|             signed_T result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::int32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); | ||||
|             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = dividend; | ||||
|             } else if (divisor == -1) { | ||||
|                 result = 0; | ||||
|             } else { | ||||
|                 result = dividend % divisor; | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REMW: x{:d} % x{:d} -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, rs2, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         void Exec_M_REMUW() const { | ||||
|             unsigned int rd, rs1, rs2; | ||||
|             std::uint32_t divisor, dividend; | ||||
|             std::int64_t result; | ||||
| 
 | ||||
|             rd = this->get_rd(); | ||||
|             rs1 = this->get_rs1(); | ||||
|             rs2 = this->get_rs2(); | ||||
| 
 | ||||
|             dividend = static_cast<std::uint32_t>(this->regs->getValue(rs1) & 0x00000000FFFFFFFF); | ||||
|             divisor = static_cast<std::uint32_t>(this->regs->getValue(rs2) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|             if (divisor == 0) { | ||||
|                 result = static_cast<std::int32_t>(dividend); | ||||
|             } else { | ||||
|                 result = static_cast<std::int32_t>(dividend % divisor); | ||||
|             } | ||||
| 
 | ||||
|             this->regs->setValue(rd, result); | ||||
| 
 | ||||
|             this->logger->debug("{} ns. PC: 0x{:x}. M.REMUW: x{:d}({:d}) % x{:d}({:d}) -> x{:d}({:d})", | ||||
|                                 sc_core::sc_time_stamp().value(), | ||||
|                                 this->regs->getPC(), | ||||
|                                 rs1, dividend, rs2, divisor, rd, result); | ||||
|         } | ||||
| 
 | ||||
|         bool process_instruction(Instruction &inst) { | ||||
|             this->setInstr(inst.getInstr()); | ||||
| 
 | ||||
|  | @ -328,7 +425,22 @@ namespace riscv_tlm { | |||
|                 case OP_M_REMU: | ||||
|                     Exec_M_REMU(); | ||||
|                     break; | ||||
|                     [[unlikely]] default: | ||||
|                 case OP_M_MULW: | ||||
|                     Exec_M_MULW(); | ||||
|                     break; | ||||
|                 case OP_M_DIVW: | ||||
|                     Exec_M_DIVW(); | ||||
|                     break; | ||||
|                 case OP_M_DIVUW: | ||||
|                     Exec_M_DIVUW(); | ||||
|                     break; | ||||
|                 case OP_M_REMW: | ||||
|                     Exec_M_REMW(); | ||||
|                     break; | ||||
|                 case OP_M_REMUW: | ||||
|                     Exec_M_REMUW(); | ||||
|                     break; | ||||
|                 [[unlikely]] default: | ||||
|                     std::cout << "M instruction not implemented yet" << "\n"; | ||||
|                     inst.dump(); | ||||
|                     //NOP(inst);
 | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ namespace riscv_tlm { | |||
|     } | ||||
| 
 | ||||
|     extension_t Instruction::check_extension() const { | ||||
|         if (((m_instr & 0x0000007F) == 0b0110011) | ||||
|         if ((((m_instr & 0x0000007F) == 0b0110011) || ((m_instr & 0x0000007F) == 0b0111011)) | ||||
|             && (((m_instr & 0x7F000000) >> 25) == 0b0000001)) { | ||||
|             return M_EXTENSION; | ||||
|         } else if ((m_instr & 0x0000007F) == 0b0101111) { | ||||
|  |  | |||
|  | @ -7,4 +7,162 @@ | |||
| // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||
| 
 | ||||
| #include "M_extension.h" | ||||
| namespace riscv_tlm { | ||||
|     // RV32
 | ||||
|     template<> | ||||
|     void M_extension<std::uint32_t>::Exec_M_MULH() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         signed_T multiplier, multiplicand; | ||||
|         std::int64_t result; | ||||
|         signed_T ret_value; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = this->regs->getValue(rs1); | ||||
|         multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
| 
 | ||||
|         result = static_cast<std::int64_t>(multiplier) * static_cast<std::int64_t>(multiplicand); | ||||
|         ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF); | ||||
| 
 | ||||
|         this->regs->setValue(rd, ret_value); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, multiplier, rs2, multiplicand, rd, result); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     void M_extension<std::uint32_t>::Exec_M_MULHSU() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         std::int32_t multiplier; | ||||
|         std::uint32_t multiplicand; | ||||
|         std::int64_t result; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|         multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
|         result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand)); | ||||
|         result = (result >> 32) & 0x00000000FFFFFFFF; | ||||
|         this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, rs2, rd, result); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     void M_extension<std::uint32_t>::Exec_M_MULHU() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         std::uint32_t multiplier, multiplicand; | ||||
|         std::uint64_t result; | ||||
|         std::int32_t ret_value; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = static_cast<std::int32_t>(this->regs->getValue(rs1)); | ||||
|         multiplicand = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||
| 
 | ||||
|         result = static_cast<std::uint64_t>(multiplier) * static_cast<std::uint64_t>(multiplicand); | ||||
|         ret_value = static_cast<std::int32_t>((result >> 32) & 0x00000000FFFFFFFF); | ||||
|         this->regs->setValue(rd, ret_value); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, rs2, rd, result); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // RV64
 | ||||
|     // I need to use SystemC bigint with 128 bits to perform 64 x 64 bits multiplication and keep the high half
 | ||||
|     template<> | ||||
|     void M_extension<std::uint64_t>::Exec_M_MULH() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         signed_T multiplier, multiplicand; | ||||
|         signed_T result; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = this->regs->getValue(rs1); | ||||
|         multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
|         sc_dt::sc_bigint<128> mul = multiplier; | ||||
|         sc_dt::sc_bigint<128> muld = multiplicand; | ||||
|         sc_dt::sc_bigint<128> res = mul * muld; | ||||
|         result = res.range(127, 64).to_int64(); | ||||
| 
 | ||||
|         this->regs->setValue(rd, result); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d}({:d}) * x{:d}({:d}) -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, multiplier, rs2, multiplicand, rd, result); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     void M_extension<std::uint64_t>::Exec_M_MULHSU() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         signed_T multiplier; | ||||
|         unsigned_T multiplicand; | ||||
|         signed_T result; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = this->regs->getValue(rs1); | ||||
|         multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
|         sc_dt::sc_bigint<128> mul = multiplier; | ||||
|         sc_dt::sc_bigint<128> muld = multiplicand; | ||||
|         sc_dt::sc_bigint<128> res = mul * muld; | ||||
|         result = res.range(127, 64).to_int64(); | ||||
| 
 | ||||
|         this->regs->setValue(rd, result); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, rs2, rd, result); | ||||
|     } | ||||
| 
 | ||||
|     template<> | ||||
|     void M_extension<std::uint64_t>::Exec_M_MULHU() const { | ||||
|         unsigned int rd, rs1, rs2; | ||||
|         unsigned_T multiplier, multiplicand; | ||||
|         unsigned_T result; | ||||
| 
 | ||||
|         rd = this->get_rd(); | ||||
|         rs1 = this->get_rs1(); | ||||
|         rs2 = this->get_rs2(); | ||||
| 
 | ||||
|         multiplier = this->regs->getValue(rs1); | ||||
|         multiplicand = this->regs->getValue(rs2); | ||||
| 
 | ||||
|         sc_dt::sc_bigint<128> mul = multiplier; | ||||
|         sc_dt::sc_bigint<128> muld = multiplicand; | ||||
|         sc_dt::sc_bigint<128> res = mul * muld; | ||||
|         result = res.range(127, 64).to_uint64(); | ||||
| 
 | ||||
|         this->regs->setValue(rd, result); | ||||
| 
 | ||||
|         this->logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", | ||||
|                             sc_core::sc_time_stamp().value(), | ||||
|                             this->regs->getPC(), | ||||
|                             rs1, rs2, rd, result); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue