Changed to template classe to prepare for 64bits version
This commit is contained in:
		
							parent
							
								
									d1fa3c752e
								
							
						
					
					
						commit
						10ed1fa653
					
				|  | @ -52,59 +52,465 @@ namespace riscv_tlm { | ||||||
| /**
 | /**
 | ||||||
|  * @brief Instruction decoding and fields access |  * @brief Instruction decoding and fields access | ||||||
|  */ |  */ | ||||||
|     class A_extension : public extension_base<std::uint32_t> { |     template<typename T> | ||||||
|  |     class A_extension : public extension_base<T> { | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * @brief Constructor, same as base class |          * @brief Constructor, same as base class | ||||||
|          */ |          */ | ||||||
|         using extension_base::extension_base; |         using extension_base<T>::extension_base; | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * @brief Access to opcode field |          * @brief Access to opcode field | ||||||
|          * @return return opcode field |          * @return return opcode field | ||||||
|          */ |          */ | ||||||
|         inline int32_t opcode() const override { |         inline std::uint32_t opcode() const override { | ||||||
|             return static_cast<int32_t>(m_instr.range(31, 27)); |             return static_cast<std::uint32_t>(this->m_instr.range(31, 27)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * @brief Decodes opcode of instruction |          * @brief Decodes opcode of instruction | ||||||
|          * @return opcode of instruction |          * @return opcode of instruction | ||||||
|          */ |          */ | ||||||
|         op_A_Codes decode() const; |         op_A_Codes decode() const { | ||||||
|  | 
 | ||||||
|  |             switch (opcode()) { | ||||||
|  |                 case A_LR: | ||||||
|  |                     return OP_A_LR; | ||||||
|  |                     break; | ||||||
|  |                 case A_SC: | ||||||
|  |                     return OP_A_SC; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOSWAP: | ||||||
|  |                     return OP_A_AMOSWAP; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOADD: | ||||||
|  |                     return OP_A_AMOADD; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOXOR: | ||||||
|  |                     return OP_A_AMOXOR; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOAND: | ||||||
|  |                     return OP_A_AMOAND; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOOR: | ||||||
|  |                     return OP_A_AMOOR; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOMIN: | ||||||
|  |                     return OP_A_AMOMIN; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOMAX: | ||||||
|  |                     return OP_A_AMOMAX; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOMINU: | ||||||
|  |                     return OP_A_AMOMINU; | ||||||
|  |                     break; | ||||||
|  |                 case A_AMOMAXU: | ||||||
|  |                     return OP_A_AMOMAXU; | ||||||
|  |                     break; | ||||||
|  |                     [[unlikely]] default: | ||||||
|  |                     return OP_A_ERROR; | ||||||
|  |                     break; | ||||||
| 
 | 
 | ||||||
|         inline void dump() const override { |  | ||||||
|             std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_LR(); |             return OP_A_ERROR; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_SC(); |         inline void dump() const override { | ||||||
|  |             std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOSWAP() const; |         bool Exec_A_LR() { | ||||||
|  |             std::uint32_t mem_addr = 0; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOADD() const; |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOXOR() const; |             if (rs2 != 0) { | ||||||
|  |                 std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; | ||||||
|  |                 this->RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, this->m_instr); | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOAND() const; |                 return false; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOOR() const; |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOMIN() const; |             TLB_reserve(mem_addr); | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOMAX() const; |             this->logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", | ||||||
|  |                                 sc_core::sc_time_stamp().value(), | ||||||
|  |                                 this->regs->getPC(), | ||||||
|  |                                 rs1, mem_addr, rd, data); | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOMINU() const; |             return true; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_A_AMOMAXU() const; |         bool Exec_A_SC() { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
| 
 | 
 | ||||||
|         bool process_instruction(Instruction &inst); |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
| 
 | 
 | ||||||
|         void TLB_reserve(std::uint32_t address); |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->regs->getValue(rs2); | ||||||
| 
 | 
 | ||||||
|         bool TLB_reserved(std::uint32_t address); |             if (TLB_reserved(mem_addr)) { | ||||||
|  |                 this->mem_intf->writeDataMem(mem_addr, data, 4); | ||||||
|  |                 this->perf->dataMemoryWrite(); | ||||||
|  |                 this->regs->setValue(rd, 0);  // SC writes 0 to rd on success
 | ||||||
|  |             } else { | ||||||
|  |                 this->regs->setValue(rd, 1);  // SC writes nonzero on failure
 | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", | ||||||
|  |                                 sc_core::sc_time_stamp().value(), | ||||||
|  |                                 this->regs->getPC(), | ||||||
|  |                                 mem_addr, rs2, data); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOSWAP() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  |             std::uint32_t aux; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // swap
 | ||||||
|  |             aux = this->regs->getValue(rs2); | ||||||
|  |             this->regs->setValue(rs2, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, aux, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOADD() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // add
 | ||||||
|  |             data = data + this->regs->getValue(rs2); | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, data, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOXOR() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // add
 | ||||||
|  |             data = data ^ this->regs->getValue(rs2); | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, data, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOAND() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // add
 | ||||||
|  |             data = data & this->regs->getValue(rs2); | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, data, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOOR() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // add
 | ||||||
|  |             data = data | this->regs->getValue(rs2); | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, data, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOMIN() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  |             std::uint32_t aux; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // min
 | ||||||
|  |             aux = this->regs->getValue(rs2); | ||||||
|  |             if ((int32_t) data < (int32_t) aux) { | ||||||
|  |                 aux = data; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, aux, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOMAX() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  |             std::uint32_t aux; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // >
 | ||||||
|  |             aux = this->regs->getValue(rs2); | ||||||
|  |             if ((int32_t) data > (int32_t) aux) { | ||||||
|  |                 aux = data; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, aux, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOMINU() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  |             std::uint32_t aux; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // min
 | ||||||
|  |             aux = this->regs->getValue(rs2); | ||||||
|  |             if (data < aux) { | ||||||
|  |                 aux = data; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, aux, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool Exec_A_AMOMAXU() const { | ||||||
|  |             std::uint32_t mem_addr; | ||||||
|  |             int rd, rs1, rs2; | ||||||
|  |             std::uint32_t data; | ||||||
|  |             std::uint32_t aux; | ||||||
|  | 
 | ||||||
|  |             /* These instructions must be atomic */ | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             mem_addr = this->regs->getValue(rs1); | ||||||
|  |             data = this->mem_intf->readDataMem(mem_addr, 4); | ||||||
|  |             this->perf->dataMemoryRead(); | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<int32_t>(data)); | ||||||
|  | 
 | ||||||
|  |             // max
 | ||||||
|  |             aux = this->regs->getValue(rs2); | ||||||
|  |             if (data > aux) { | ||||||
|  |                 aux = data; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->mem_intf->writeDataMem(mem_addr, aux, 4); | ||||||
|  |             this->perf->dataMemoryWrite(); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void TLB_reserve(std::uint32_t address) { | ||||||
|  |             TLB_A_Entries.insert(address); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool TLB_reserved(std::uint32_t address) { | ||||||
|  |             if (TLB_A_Entries.count(address) == 1) { | ||||||
|  |                 TLB_A_Entries.erase(address); | ||||||
|  |                 return true; | ||||||
|  |             } else { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool process_instruction(Instruction &inst) { | ||||||
|  |             bool PC_not_affected = true; | ||||||
|  | 
 | ||||||
|  |             this->setInstr(inst.getInstr()); | ||||||
|  | 
 | ||||||
|  |             switch (decode()) { | ||||||
|  |                 case OP_A_LR: | ||||||
|  |                     Exec_A_LR(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_SC: | ||||||
|  |                     Exec_A_SC(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOSWAP: | ||||||
|  |                     Exec_A_AMOSWAP(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOADD: | ||||||
|  |                     Exec_A_AMOADD(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOXOR: | ||||||
|  |                     Exec_A_AMOXOR(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOAND: | ||||||
|  |                     Exec_A_AMOAND(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOOR: | ||||||
|  |                     Exec_A_AMOOR(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOMIN: | ||||||
|  |                     Exec_A_AMOMIN(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOMAX: | ||||||
|  |                     Exec_A_AMOMAX(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOMINU: | ||||||
|  |                     Exec_A_AMOMINU(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_A_AMOMAXU: | ||||||
|  |                     Exec_A_AMOMAXU(); | ||||||
|  |                     break; | ||||||
|  |                     [[unlikely]] default: | ||||||
|  |                     std::cout << "A instruction not implemented yet" << std::endl; | ||||||
|  |                     inst.dump(); | ||||||
|  |                     this->NOP(); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return PC_not_affected; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
|         std::unordered_set<std::uint32_t> TLB_A_Entries; |         std::unordered_set<std::uint32_t> TLB_A_Entries; | ||||||
|  |  | ||||||
							
								
								
									
										1578
									
								
								inc/BASE_ISA.h
								
								
								
								
							
							
						
						
									
										1578
									
								
								inc/BASE_ISA.h
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -73,10 +73,10 @@ namespace riscv_tlm { | ||||||
|         Registers<std::uint32_t> *register_bank; |         Registers<std::uint32_t> *register_bank; | ||||||
|         Performance *perf; |         Performance *perf; | ||||||
|         std::shared_ptr<spdlog::logger> logger; |         std::shared_ptr<spdlog::logger> logger; | ||||||
|         C_extension *c_inst; |         C_extension<std::uint32_t> *c_inst; | ||||||
|         M_extension *m_inst; |         M_extension<std::uint32_t> *m_inst; | ||||||
|         A_extension *a_inst; |         A_extension<std::uint32_t> *a_inst; | ||||||
|         BASE_ISA *exec; |         BASE_ISA<std::uint32_t> *exec; | ||||||
|         tlm_utils::tlm_quantumkeeper *m_qk; |         tlm_utils::tlm_quantumkeeper *m_qk; | ||||||
| 
 | 
 | ||||||
|         Instruction inst; |         Instruction inst; | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -43,41 +43,298 @@ namespace riscv_tlm { | ||||||
| /**
 | /**
 | ||||||
|  * @brief Instruction decoding and fields access |  * @brief Instruction decoding and fields access | ||||||
|  */ |  */ | ||||||
|     class M_extension : public extension_base<std::uint32_t> { |     template<typename T> | ||||||
|  |     class M_extension : public extension_base<T> { | ||||||
|     public: |     public: | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * @brief Constructor, same as base clase |          * @brief Constructor, same as base clase | ||||||
|          */ |          */ | ||||||
|         using extension_base::extension_base; |         using extension_base<T>::extension_base; | ||||||
| 
 | 
 | ||||||
|         /**
 |         /**
 | ||||||
|          * @brief Decodes opcode of instruction |          * @brief Decodes opcode of instruction | ||||||
|          * @return opcode of instruction |          * @return opcode of instruction | ||||||
|          */ |          */ | ||||||
|         op_M_Codes decode() const; |         [[nodiscard]] op_M_Codes decode() const { | ||||||
| 
 | 
 | ||||||
|         inline void dump() const override { |             switch (opcode()) { | ||||||
|             std::cout << std::hex << "0x" << m_instr << std::dec << std::endl; |                 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; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_MUL() const; |             return OP_M_ERROR; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_MULH() const; |         inline void dump() const override { | ||||||
|  |             std::cout << std::hex << "0x" << this->m_instr << std::dec << std::endl; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_MULHSU() const; |         void Exec_M_MUL() const { | ||||||
|  |             unsigned int rd, rs1, rs2; | ||||||
|  |             std::int32_t multiplier, multiplicand; | ||||||
|  |             std::int64_t result; | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_MULHU() const; |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_DIV() const; |             multiplier = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs1)); | ||||||
|  |             multiplicand = static_cast<std::int32_t>(extension_base<T>::regs->getValue(rs2)); | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_DIVU() const; |             result = static_cast<std::int64_t>(multiplier * multiplicand); | ||||||
|  |             result = result & 0x00000000FFFFFFFF; | ||||||
|  |             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_REM() const; |             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); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         bool Exec_M_REMU() const; |         void Exec_M_MULH() const { | ||||||
|  |             unsigned int rd, rs1, rs2; | ||||||
|  |             std::int32_t multiplier, multiplicand; | ||||||
|  |             std::int64_t result; | ||||||
|  |             std::int32_t ret_value; | ||||||
| 
 | 
 | ||||||
|         bool process_instruction(Instruction &inst); |             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})", | ||||||
|  |                                 sc_core::sc_time_stamp().value(), | ||||||
|  |                                 this->regs->getPC(), | ||||||
|  |                                 rs1, rs2, rd, result); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void 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); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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_DIV() 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)); | ||||||
|  |             divisor = static_cast<std::int32_t>(this->regs->getValue(rs2)); | ||||||
|  | 
 | ||||||
|  |             if (divisor == 0) { | ||||||
|  |                 result = -1; | ||||||
|  |             } else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) { | ||||||
|  |                 result = 0x0000000080000000; | ||||||
|  |             } else { | ||||||
|  |                 result = dividend / divisor; | ||||||
|  |                 result = result & 0x00000000FFFFFFFF; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", | ||||||
|  |                                 sc_core::sc_time_stamp().value(), | ||||||
|  |                                 this->regs->getPC(), | ||||||
|  |                                 rs1, rs2, rd, result); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void Exec_M_DIVU() const { | ||||||
|  |             unsigned int rd, rs1, rs2; | ||||||
|  |             std::uint32_t divisor, dividend; | ||||||
|  |             std::uint64_t result; | ||||||
|  | 
 | ||||||
|  |             rd = this->get_rd(); | ||||||
|  |             rs1 = this->get_rs1(); | ||||||
|  |             rs2 = this->get_rs2(); | ||||||
|  | 
 | ||||||
|  |             dividend = this->regs->getValue(rs1); | ||||||
|  |             divisor = this->regs->getValue(rs2); | ||||||
|  | 
 | ||||||
|  |             if (divisor == 0) { | ||||||
|  |                 result = -1; | ||||||
|  |             } else { | ||||||
|  |                 result = dividend / divisor; | ||||||
|  |                 result = result & 0x00000000FFFFFFFF; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||||
|  | 
 | ||||||
|  |             this->logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", | ||||||
|  |                                 sc_core::sc_time_stamp().value(), | ||||||
|  |                                 this->regs->getPC(), | ||||||
|  |                                 rs1, rs2, rd, result); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void Exec_M_REM() const { | ||||||
|  |             unsigned int rd, rs1, rs2; | ||||||
|  |             std::int32_t divisor, dividend; | ||||||
|  |             std::int32_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)); | ||||||
|  | 
 | ||||||
|  |             if (divisor == 0) { | ||||||
|  |                 result = dividend; | ||||||
|  |             } else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) { | ||||||
|  |                 result = 0; | ||||||
|  |             } else { | ||||||
|  |                 result = dividend % divisor; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, result); | ||||||
|  | 
 | ||||||
|  |             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); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void Exec_M_REMU() const { | ||||||
|  |             unsigned int rd, rs1, rs2; | ||||||
|  |             std::uint32_t divisor, dividend; | ||||||
|  |             std::uint32_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)); | ||||||
|  | 
 | ||||||
|  |             if (divisor == 0) { | ||||||
|  |                 result = dividend; | ||||||
|  |             } else { | ||||||
|  |                 result = dividend % divisor; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             this->regs->setValue(rd, static_cast<std::int32_t>(result)); | ||||||
|  | 
 | ||||||
|  |             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); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bool process_instruction(Instruction &inst) { | ||||||
|  |             this->setInstr(inst.getInstr()); | ||||||
|  | 
 | ||||||
|  |             switch (decode()) { | ||||||
|  |                 case OP_M_MUL: | ||||||
|  |                     Exec_M_MUL(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_MULH: | ||||||
|  |                     Exec_M_MULH(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_MULHSU: | ||||||
|  |                     Exec_M_MULHSU(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_MULHU: | ||||||
|  |                     Exec_M_MULHU(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_DIV: | ||||||
|  |                     Exec_M_DIV(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_DIVU: | ||||||
|  |                     Exec_M_DIVU(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_REM: | ||||||
|  |                     Exec_M_REM(); | ||||||
|  |                     break; | ||||||
|  |                 case OP_M_REMU: | ||||||
|  |                     Exec_M_REMU(); | ||||||
|  |                     break; | ||||||
|  |                     [[unlikely]] default: | ||||||
|  |                     std::cout << "M instruction not implemented yet" << "\n"; | ||||||
|  |                     inst.dump(); | ||||||
|  |                     //NOP(inst);
 | ||||||
|  |                     sc_core::sc_stop(); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|     private: |     private: | ||||||
| 
 | 
 | ||||||
|  | @ -85,8 +342,8 @@ namespace riscv_tlm { | ||||||
|          * @brief Access to opcode field |          * @brief Access to opcode field | ||||||
|          * @return return opcode field |          * @return return opcode field | ||||||
|          */ |          */ | ||||||
|         inline std::int32_t opcode() const override { |         [[nodiscard]] inline std::uint32_t opcode() const override { | ||||||
|             return static_cast<std::int32_t>(m_instr.range(14, 12)); |             return static_cast<std::uint32_t>(this->m_instr.range(14, 12)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #define REGISTERS_H | #define REGISTERS_H | ||||||
| 
 | 
 | ||||||
| #define SC_INCLUDE_DYNAMIC_PROCESSES | #define SC_INCLUDE_DYNAMIC_PROCESSES | ||||||
|  | 
 | ||||||
| #include <iomanip> | #include <iomanip> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| 
 | 
 | ||||||
|  | @ -200,7 +201,7 @@ namespace riscv_tlm { | ||||||
|          * @param reg_num register number |          * @param reg_num register number | ||||||
|          * @param value   register value |          * @param value   register value | ||||||
|          */ |          */ | ||||||
|         void setValue(int reg_num, T value) { |         void setValue(unsigned int reg_num, T value) { | ||||||
|             if ((reg_num != 0) && (reg_num < 32)) { |             if ((reg_num != 0) && (reg_num < 32)) { | ||||||
|                 register_bank[reg_num] = value; |                 register_bank[reg_num] = value; | ||||||
|                 perf->registerWrite(); |                 perf->registerWrite(); | ||||||
|  | @ -212,13 +213,13 @@ namespace riscv_tlm { | ||||||
|          * @param  reg_num register number |          * @param  reg_num register number | ||||||
|          * @return         register value |          * @return         register value | ||||||
|          */ |          */ | ||||||
|         T getValue(int reg_num) const { |         T getValue(unsigned int reg_num) const { | ||||||
|           if ((reg_num >= 0) && (reg_num < 32)) { |             if (reg_num < 32) { | ||||||
|                 perf->registerRead(); |                 perf->registerRead(); | ||||||
|                 return register_bank[reg_num]; |                 return register_bank[reg_num]; | ||||||
|             } else { |             } else { | ||||||
|               /* TODO Exten sign for any possible T type */ |                 /* Extend sign for any possible T type */ | ||||||
|               return static_cast<T>(0xFFFFFFFF); |                 return static_cast<T>(std::numeric_limits<T>::max()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -68,7 +68,8 @@ namespace riscv_tlm { | ||||||
| 
 | 
 | ||||||
|             regs->setPC(new_pc); |             regs->setPC(new_pc); | ||||||
| 
 | 
 | ||||||
|           logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), regs->getPC(), |             logger->debug("{} ns. PC: 0x{:x}. Exception! new PC 0x{:x} ", sc_core::sc_time_stamp().value(), | ||||||
|  |                           regs->getPC(), | ||||||
|                           new_pc); |                           new_pc); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -79,37 +80,37 @@ namespace riscv_tlm { | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /* pure virtual functions */ |         /* pure virtual functions */ | ||||||
|         virtual std::int32_t opcode() const = 0; |         virtual T opcode() const = 0; | ||||||
| 
 | 
 | ||||||
|         virtual std::int32_t get_rd() const { |         virtual unsigned int get_rd() const { | ||||||
|             return m_instr.range(11, 7); |             return m_instr.range(11, 7); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual void set_rd(std::int32_t value) { |         virtual void set_rd(unsigned int value) { | ||||||
|             m_instr.range(11, 7) = value; |             m_instr.range(11, 7) = value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual std::int32_t get_rs1() const { |         virtual unsigned int get_rs1() const { | ||||||
|             return m_instr.range(19, 15); |             return m_instr.range(19, 15); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual void set_rs1(std::int32_t value) { |         virtual void set_rs1(unsigned int value) { | ||||||
|             m_instr.range(19, 15) = value; |             m_instr.range(19, 15) = value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual std::int32_t get_rs2() const { |         virtual unsigned int get_rs2() const { | ||||||
|             return m_instr.range(24, 20); |             return m_instr.range(24, 20); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual void set_rs2(std::int32_t value) { |         virtual void set_rs2(unsigned int value) { | ||||||
|             m_instr.range(24, 20) = value; |             m_instr.range(24, 20) = value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual std::int32_t get_funct3() const { |         virtual unsigned int get_funct3() const { | ||||||
|             return m_instr.range(14, 12); |             return m_instr.range(14, 12); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         virtual void set_funct3(std::int32_t value) { |         virtual void set_funct3(unsigned int value) { | ||||||
|             m_instr.range(14, 12) = value; |             m_instr.range(14, 12) = value; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -7,439 +7,3 @@ | ||||||
| // SPDX-License-Identifier: GPL-3.0-or-later
 | // SPDX-License-Identifier: GPL-3.0-or-later
 | ||||||
| 
 | 
 | ||||||
| #include "A_extension.h" | #include "A_extension.h" | ||||||
| 
 |  | ||||||
| namespace riscv_tlm { |  | ||||||
| 
 |  | ||||||
|     op_A_Codes A_extension::decode() const { |  | ||||||
| 
 |  | ||||||
|         switch (opcode()) { |  | ||||||
|             case A_LR: |  | ||||||
|                 return OP_A_LR; |  | ||||||
|                 break; |  | ||||||
|             case A_SC: |  | ||||||
|                 return OP_A_SC; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOSWAP: |  | ||||||
|                 return OP_A_AMOSWAP; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOADD: |  | ||||||
|                 return OP_A_AMOADD; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOXOR: |  | ||||||
|                 return OP_A_AMOXOR; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOAND: |  | ||||||
|                 return OP_A_AMOAND; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOOR: |  | ||||||
|                 return OP_A_AMOOR; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOMIN: |  | ||||||
|                 return OP_A_AMOMIN; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOMAX: |  | ||||||
|                 return OP_A_AMOMAX; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOMINU: |  | ||||||
|                 return OP_A_AMOMINU; |  | ||||||
|                 break; |  | ||||||
|             case A_AMOMAXU: |  | ||||||
|                 return OP_A_AMOMAXU; |  | ||||||
|                 break; |  | ||||||
|                 [[unlikely]] default: |  | ||||||
|                 return OP_A_ERROR; |  | ||||||
|                 break; |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return OP_A_ERROR; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_LR() { |  | ||||||
|         std::uint32_t mem_addr = 0; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         if (rs2 != 0) { |  | ||||||
|             std::cout << "ILEGAL INSTRUCTION, LR.W: rs2 != 0" << std::endl; |  | ||||||
|             RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); |  | ||||||
| 
 |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         TLB_reserve(mem_addr); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.LR.W: x{:d}(0x{:x}) -> x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, mem_addr, rd, data); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_SC() { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         if (TLB_reserved(mem_addr)) { |  | ||||||
|             mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|             perf->dataMemoryWrite(); |  | ||||||
|             regs->setValue(rd, 0);  // SC writes 0 to rd on success
 |  | ||||||
|         } else { |  | ||||||
|             regs->setValue(rd, 1);  // SC writes nonzero on failure
 |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.SC.W: (0x{:x}) <- x{:d}(0x{:x}) ", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       mem_addr, rs2, data); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOSWAP() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
|         std::uint32_t aux; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // swap
 |  | ||||||
|         aux = regs->getValue(rs2); |  | ||||||
|         regs->setValue(rs2, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, aux, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOSWAP"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOADD() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // add
 |  | ||||||
|         data = data + regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOADD"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOXOR() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // add
 |  | ||||||
|         data = data ^ regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOXOR"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOAND() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // add
 |  | ||||||
|         data = data & regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOAND"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOOR() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // add
 |  | ||||||
|         data = data | regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOOR"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOMIN() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
|         std::uint32_t aux; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // min
 |  | ||||||
|         aux = regs->getValue(rs2); |  | ||||||
|         if ((int32_t) data < (int32_t) aux) { |  | ||||||
|             aux = data; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, aux, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOMIN"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOMAX() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
|         std::uint32_t aux; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // >
 |  | ||||||
|         aux = regs->getValue(rs2); |  | ||||||
|         if ((int32_t) data > (int32_t) aux) { |  | ||||||
|             aux = data; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, aux, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOMAX"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOMINU() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
|         std::uint32_t aux; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // min
 |  | ||||||
|         aux = regs->getValue(rs2); |  | ||||||
|         if (data < aux) { |  | ||||||
|             aux = data; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, aux, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOMINU"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::Exec_A_AMOMAXU() const { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t data; |  | ||||||
|         std::uint32_t aux; |  | ||||||
| 
 |  | ||||||
|         /* These instructions must be atomic */ |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         // max
 |  | ||||||
|         aux = regs->getValue(rs2); |  | ||||||
|         if (data > aux) { |  | ||||||
|             aux = data; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, aux, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. A.AMOMAXU"); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     void A_extension::TLB_reserve(std::uint32_t address) { |  | ||||||
|         TLB_A_Entries.insert(address); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::TLB_reserved(std::uint32_t address) { |  | ||||||
|         if (TLB_A_Entries.count(address) == 1) { |  | ||||||
|             TLB_A_Entries.erase(address); |  | ||||||
|             return true; |  | ||||||
|         } else { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool A_extension::process_instruction(Instruction &inst) { |  | ||||||
|         bool PC_not_affected = true; |  | ||||||
| 
 |  | ||||||
|         setInstr(inst.getInstr()); |  | ||||||
| 
 |  | ||||||
|         switch (decode()) { |  | ||||||
|             case OP_A_LR: |  | ||||||
|                 Exec_A_LR(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_SC: |  | ||||||
|                 Exec_A_SC(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOSWAP: |  | ||||||
|                 Exec_A_AMOSWAP(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOADD: |  | ||||||
|                 Exec_A_AMOADD(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOXOR: |  | ||||||
|                 Exec_A_AMOXOR(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOAND: |  | ||||||
|                 Exec_A_AMOAND(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOOR: |  | ||||||
|                 Exec_A_AMOOR(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOMIN: |  | ||||||
|                 Exec_A_AMOMIN(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOMAX: |  | ||||||
|                 Exec_A_AMOMAX(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOMINU: |  | ||||||
|                 Exec_A_AMOMINU(); |  | ||||||
|                 break; |  | ||||||
|             case OP_A_AMOMAXU: |  | ||||||
|                 Exec_A_AMOMAXU(); |  | ||||||
|                 break; |  | ||||||
|                 [[unlikely]] default: |  | ||||||
|                 std::cout << "A instruction not implemented yet" << std::endl; |  | ||||||
|                 inst.dump(); |  | ||||||
|                 NOP(); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return PC_not_affected; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										1475
									
								
								src/BASE_ISA.cpp
								
								
								
								
							
							
						
						
									
										1475
									
								
								src/BASE_ISA.cpp
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								src/CPU.cpp
								
								
								
								
							
							
						
						
									
										12
									
								
								src/CPU.cpp
								
								
								
								
							|  | @ -12,8 +12,8 @@ namespace riscv_tlm { | ||||||
|     SC_HAS_PROCESS(CPU); |     SC_HAS_PROCESS(CPU); | ||||||
| 
 | 
 | ||||||
|     CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : |     CPU::CPU(sc_core::sc_module_name const &name, std::uint32_t PC, bool debug) : | ||||||
|             sc_module(name), instr_bus("instr_bus"), inst(0), default_time(10, |             sc_module(name), instr_bus("instr_bus"), inst(0), | ||||||
|                                                                            sc_core::SC_NS), INSTR(0) { |             default_time(10, sc_core::SC_NS), INSTR(0) { | ||||||
|         register_bank = new Registers<std::uint32_t>(); |         register_bank = new Registers<std::uint32_t>(); | ||||||
|         mem_intf = new MemoryInterface(); |         mem_intf = new MemoryInterface(); | ||||||
| 
 | 
 | ||||||
|  | @ -32,10 +32,10 @@ namespace riscv_tlm { | ||||||
|         instr_bus.register_invalidate_direct_mem_ptr(this, |         instr_bus.register_invalidate_direct_mem_ptr(this, | ||||||
|                                                      &CPU::invalidate_direct_mem_ptr); |                                                      &CPU::invalidate_direct_mem_ptr); | ||||||
| 
 | 
 | ||||||
|         exec = new BASE_ISA(0, register_bank, mem_intf); |         exec = new BASE_ISA<std::uint32_t>(0, register_bank, mem_intf); | ||||||
|         c_inst = new C_extension(0, register_bank, mem_intf); |         c_inst = new C_extension<std::uint32_t>(0, register_bank, mem_intf); | ||||||
|         m_inst = new M_extension(0, register_bank, mem_intf); |         m_inst = new M_extension<std::uint32_t>(0, register_bank, mem_intf); | ||||||
|         a_inst = new A_extension(0, register_bank, mem_intf); |         a_inst = new A_extension<std::uint32_t>(0, register_bank, mem_intf); | ||||||
| 
 | 
 | ||||||
|         m_qk = new tlm_utils::tlm_quantumkeeper(); |         m_qk = new tlm_utils::tlm_quantumkeeper(); | ||||||
|         m_qk->reset(); |         m_qk->reset(); | ||||||
|  |  | ||||||
|  | @ -5,749 +5,3 @@ | ||||||
|  \date August 2018 |  \date August 2018 | ||||||
| */ | */ | ||||||
| #include "C_extension.h" | #include "C_extension.h" | ||||||
| 
 |  | ||||||
| namespace riscv_tlm { |  | ||||||
| 
 |  | ||||||
|     op_C_Codes C_extension::decode() const { |  | ||||||
| 
 |  | ||||||
|         switch (opcode()) { |  | ||||||
| 
 |  | ||||||
|             case 0b00: |  | ||||||
|                 switch (get_funct3()) { |  | ||||||
|                     case C_ADDI4SPN: |  | ||||||
|                         return OP_C_ADDI4SPN; |  | ||||||
|                         break; |  | ||||||
|                     case C_FLD: |  | ||||||
|                         return OP_C_FLD; |  | ||||||
|                         break; |  | ||||||
|                     case C_LW: |  | ||||||
|                         return OP_C_LW; |  | ||||||
|                         break; |  | ||||||
|                     case C_FLW: |  | ||||||
|                         return OP_C_FLW; |  | ||||||
|                         break; |  | ||||||
|                     case C_FSD: |  | ||||||
|                         return OP_C_FSD; |  | ||||||
|                         break; |  | ||||||
|                     case C_SW: |  | ||||||
|                         return OP_C_SW; |  | ||||||
|                         break; |  | ||||||
|                     case C_FSW: |  | ||||||
|                         return OP_C_FSW; |  | ||||||
|                         break; |  | ||||||
|                         [[unlikely]] default: |  | ||||||
|                         return OP_C_ERROR; |  | ||||||
|                         break; |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
| 
 |  | ||||||
|             case 0b01: |  | ||||||
|                 switch (get_funct3()) { |  | ||||||
|                     case C_ADDI: |  | ||||||
|                         return OP_C_ADDI; |  | ||||||
|                         break; |  | ||||||
|                     case C_JAL: |  | ||||||
|                         return OP_C_JAL; |  | ||||||
|                         break; |  | ||||||
|                     case C_LI: |  | ||||||
|                         return OP_C_LI; |  | ||||||
|                         break; |  | ||||||
|                     case C_ADDI16SP: |  | ||||||
|                         return OP_C_ADDI16SP; |  | ||||||
|                         break; |  | ||||||
|                     case C_SRLI: |  | ||||||
|                         switch (m_instr.range(11, 10)) { |  | ||||||
|                             case C_2_SRLI: |  | ||||||
|                                 return OP_C_SRLI; |  | ||||||
|                                 break; |  | ||||||
|                             case C_2_SRAI: |  | ||||||
|                                 return OP_C_SRAI; |  | ||||||
|                                 break; |  | ||||||
|                             case C_2_ANDI: |  | ||||||
|                                 return OP_C_ANDI; |  | ||||||
|                                 break; |  | ||||||
|                             case C_2_SUB: |  | ||||||
|                                 switch (m_instr.range(6, 5)) { |  | ||||||
|                                     case C_3_SUB: |  | ||||||
|                                         return OP_C_SUB; |  | ||||||
|                                         break; |  | ||||||
|                                     case C_3_XOR: |  | ||||||
|                                         return OP_C_XOR; |  | ||||||
|                                         break; |  | ||||||
|                                     case C_3_OR: |  | ||||||
|                                         return OP_C_OR; |  | ||||||
|                                         break; |  | ||||||
|                                     case C_3_AND: |  | ||||||
|                                         return OP_C_AND; |  | ||||||
|                                         break; |  | ||||||
|                                 } |  | ||||||
|                         } |  | ||||||
|                         break; |  | ||||||
|                     case C_J: |  | ||||||
|                         return OP_C_J; |  | ||||||
|                         break; |  | ||||||
|                     case C_BEQZ: |  | ||||||
|                         return OP_C_BEQZ; |  | ||||||
|                         break; |  | ||||||
|                     case C_BNEZ: |  | ||||||
|                         return OP_C_BNEZ; |  | ||||||
|                         break; |  | ||||||
|                         [[unlikely]] default: |  | ||||||
|                         return OP_C_ERROR; |  | ||||||
|                         break; |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
| 
 |  | ||||||
|             case 0b10: |  | ||||||
|                 switch (get_funct3()) { |  | ||||||
|                     case C_SLLI: |  | ||||||
|                         return OP_C_SLLI; |  | ||||||
|                         break; |  | ||||||
|                     case C_FLDSP: |  | ||||||
|                     case C_LWSP: |  | ||||||
|                         return OP_C_LWSP; |  | ||||||
|                         break; |  | ||||||
|                     case C_FLWSP: |  | ||||||
|                         return OP_C_FLWSP; |  | ||||||
|                         break; |  | ||||||
|                     case C_JR: |  | ||||||
|                         if (m_instr[12] == 0) { |  | ||||||
|                             if (m_instr.range(6, 2) == 0) { |  | ||||||
|                                 return OP_C_JR; |  | ||||||
|                             } else { |  | ||||||
|                                 return OP_C_MV; |  | ||||||
|                             } |  | ||||||
|                         } else { |  | ||||||
|                             if (m_instr.range(11, 2) == 0) { |  | ||||||
|                                 return OP_C_EBREAK; |  | ||||||
|                             } else if (m_instr.range(6, 2) == 0) { |  | ||||||
|                                 return OP_C_JALR; |  | ||||||
|                             } else { |  | ||||||
|                                 return OP_C_ADD; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                         break; |  | ||||||
|                     case C_FDSP: |  | ||||||
|                         break; |  | ||||||
|                     case C_SWSP: |  | ||||||
|                         return OP_C_SWSP; |  | ||||||
|                         break; |  | ||||||
|                     case C_FWWSP: |  | ||||||
|                         [[unlikely]] |  | ||||||
|                     default: |  | ||||||
|                         return OP_C_ERROR; |  | ||||||
|                         break; |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
| 
 |  | ||||||
|                 [[unlikely]] default: |  | ||||||
| 
 |  | ||||||
|                 return OP_C_ERROR; |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
|         return OP_C_ERROR; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_JR() { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rs1; |  | ||||||
|         int new_pc; |  | ||||||
| 
 |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         mem_addr = 0; |  | ||||||
| 
 |  | ||||||
|         new_pc = static_cast<std::int32_t>( |  | ||||||
|                 static_cast<std::int32_t>((regs->getValue(rs1)) + static_cast<std::int32_t>(mem_addr)) & 0xFFFFFFFE); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.JR: PC <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), new_pc); |  | ||||||
| 
 |  | ||||||
|         regs->setPC(new_pc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_MV() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = 0; |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) + regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.MV: x{:d}(0x{:x}) + x{:d}(0x{:x}) -> x{:d}(0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, regs->getValue(rs1), rs2, regs->getValue(rs2), rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_ADD() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) + regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.ADD: x{:d} + x{} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_LWSP() { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         // lw rd, offset[7:2](x2)
 |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = 2; |  | ||||||
|         imm = get_imm_LWSP(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = imm + regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, data); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.LWSP: x{:d} + {:d}(@0x{:x}) -> x{:d}({:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, imm, mem_addr, rd, data); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_ADDI4SPN() { |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::int32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rdp(); |  | ||||||
|         rs1 = 2; |  | ||||||
|         imm = get_imm_ADDI4SPN(); |  | ||||||
| 
 |  | ||||||
|         if (imm == 0) { |  | ||||||
|             RaiseException(EXCEPTION_CAUSE_ILLEGAL_INSTRUCTION, m_instr); |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm; |  | ||||||
|         regs->setValue(rd, calc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.ADDI4SN: x{:d} + (0x{:x}) + {:d} -> x{:d}(0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, regs->getValue(rs1), imm, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_ADDI16SP() { |  | ||||||
|         // addi x2, x2, nzimm[9:4]
 |  | ||||||
|         int rd; |  | ||||||
|         std::int32_t imm; |  | ||||||
| 
 |  | ||||||
|         if (get_rd() == 2) { |  | ||||||
|             int rs1; |  | ||||||
|             std::int32_t calc; |  | ||||||
| 
 |  | ||||||
|             rd = 2; |  | ||||||
|             rs1 = 2; |  | ||||||
|             imm = get_imm_ADDI16SP(); |  | ||||||
| 
 |  | ||||||
|             calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm; |  | ||||||
|             regs->setValue(rd, calc); |  | ||||||
| 
 |  | ||||||
|             logger->debug("{} ns. PC: 0x{:x}. C.ADDI16SP: x{:d} + {:d} -> x{:d} (0x{:x})", |  | ||||||
|                           sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                           rs1, imm, rd, calc); |  | ||||||
|         } else { |  | ||||||
|             /* C.LUI OPCODE */ |  | ||||||
|             rd = get_rd(); |  | ||||||
|             imm = get_imm_LUI(); |  | ||||||
|             regs->setValue(rd, imm); |  | ||||||
| 
 |  | ||||||
|             logger->debug("{} ns. PC: 0x{:x}. C.LUI: x{:d} <- 0x{:x}", sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                           rd, imm); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SWSP() { |  | ||||||
|         // sw rs2, offset(x2)
 |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rs1, rs2; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         rs1 = 2; |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
|         imm = get_imm_CSS(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = imm + regs->getValue(rs1); |  | ||||||
|         data = regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SWSP: x{:d}(0x{:x}) -> x{:d} + {} (@0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs2, data, rs1, imm, mem_addr); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_BEQZ() { |  | ||||||
|         int rs1; |  | ||||||
|         int new_pc; |  | ||||||
|         std::uint32_t val1; |  | ||||||
| 
 |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         val1 = regs->getValue(rs1); |  | ||||||
| 
 |  | ||||||
|         if (val1 == 0) { |  | ||||||
|             new_pc = static_cast<std::int32_t>(regs->getPC()) + get_imm_CB(); |  | ||||||
|             regs->setPC(new_pc); |  | ||||||
|         } else { |  | ||||||
|             regs->incPCby2(); |  | ||||||
|             new_pc = static_cast<std::int32_t>(regs->getPC()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.BEQZ: x{:d}(0x{:x}) == 0? -> PC (0xx{:d})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, val1, new_pc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_BNEZ() { |  | ||||||
|         int rs1; |  | ||||||
|         int new_pc; |  | ||||||
|         std::uint32_t val1; |  | ||||||
| 
 |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         val1 = regs->getValue(rs1); |  | ||||||
| 
 |  | ||||||
|         if (val1 != 0) { |  | ||||||
|             new_pc = static_cast<std::int32_t>(regs->getPC()) + get_imm_CB(); |  | ||||||
|             regs->setPC(new_pc); |  | ||||||
|         } else { |  | ||||||
|             regs->incPCby2(); //PC <- PC +2
 |  | ||||||
|             new_pc = static_cast<std::int32_t>(regs->getPC()); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.BNEZ: x{:d}(0x{:x}) != 0? -> PC (0xx{:d})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, val1, new_pc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_LI() { |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::int32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = 0; |  | ||||||
|         imm = get_imm_ADDI(); |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm; |  | ||||||
|         regs->setValue(rd, calc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.LI: x{:d} ({:d}) + {:d} -> x{:d}(0x{:x}) ", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, regs->getValue(rs1), imm, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SRLI() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t shift; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         shift = rs2 & 0x1F; |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::uint32_t>(regs->getValue(rs1)) >> shift; |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SRLI: x{:d} >> {} -> x{:d}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, shift, rd); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SRAI() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t shift; |  | ||||||
|         std::int32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         shift = rs2 & 0x1F; |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::int32_t>(regs->getValue(rs1)) >> shift; |  | ||||||
|         regs->setValue(rd, calc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SRAI: x{:d} >> {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, shift, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SLLI() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t shift; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_imm_ADDI(); |  | ||||||
| 
 |  | ||||||
|         shift = rs2 & 0x1F; |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::uint32_t>(regs->getValue(rs1)) << shift; |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SLLI: x{:d} << {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, shift, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_ANDI() { |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::uint32_t imm; |  | ||||||
|         std::uint32_t aux; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         imm = get_imm_ADDI(); |  | ||||||
| 
 |  | ||||||
|         aux = regs->getValue(rs1); |  | ||||||
|         calc = aux & imm; |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.ANDI: x{:d}(0x{:x}) AND 0x{:x} -> x{:d}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, aux, imm, rd); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SUB() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2p(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) - regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SUB: x{:d} - x{:d} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_XOR() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2p(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) ^ regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.XOR: x{:d} XOR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_OR() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2p(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) | regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.OR: x{:d} OR x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_AND() { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rs1p(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2p(); |  | ||||||
| 
 |  | ||||||
|         calc = regs->getValue(rs1) & regs->getValue(rs2); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(calc)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.AND: x{:d} AND x{:d} -> x{:d}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_ADDI() const { |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::int32_t calc; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = rd; |  | ||||||
|         imm = get_imm_ADDI(); |  | ||||||
| 
 |  | ||||||
|         calc = static_cast<std::int32_t>(regs->getValue(rs1)) + imm; |  | ||||||
|         regs->setValue(rd, calc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.ADDI: x{:d} + {} -> x{:d}(0x{:x})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), rs1, imm, rd, calc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_JALR() { |  | ||||||
|         std::uint32_t mem_addr = 0; |  | ||||||
|         int rd, rs1; |  | ||||||
|         int new_pc, old_pc; |  | ||||||
| 
 |  | ||||||
|         rd = 1; |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
| 
 |  | ||||||
|         old_pc = static_cast<std::int32_t>(regs->getPC()); |  | ||||||
|         regs->setValue(rd, old_pc + 2); |  | ||||||
| 
 |  | ||||||
|         new_pc = static_cast<std::int32_t>((regs->getValue(rs1) + mem_addr) & 0xFFFFFFFE); |  | ||||||
|         regs->setPC(new_pc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.JALR: x{:d} <- 0x{:x} PC <- 0xx{:x}", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rd, old_pc + 4, new_pc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_LW() { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rd, rs1; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         rd = get_rdp(); |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         imm = get_imm_L(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = imm + regs->getValue(rs1); |  | ||||||
|         data = mem_intf->readDataMem(mem_addr, 4); |  | ||||||
|         perf->dataMemoryRead(); |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(data)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.LW: x{:d}(0x{:x}) + {:d} (@0x{:x}) -> {:d} (0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs1, regs->getValue(rs1), imm, mem_addr, rd, data); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_SW() { |  | ||||||
|         std::uint32_t mem_addr; |  | ||||||
|         int rs1, rs2; |  | ||||||
|         std::int32_t imm; |  | ||||||
|         std::uint32_t data; |  | ||||||
| 
 |  | ||||||
|         rs1 = get_rs1p(); |  | ||||||
|         rs2 = get_rs2p(); |  | ||||||
|         imm = get_imm_L(); |  | ||||||
| 
 |  | ||||||
|         mem_addr = imm + regs->getValue(rs1); |  | ||||||
|         data = regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         mem_intf->writeDataMem(mem_addr, data, 4); |  | ||||||
|         perf->dataMemoryWrite(); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.SW: x{:d}(0x{:x}) -> x{:d} + 0x{:x}(@0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rs2, data, rs1, imm, mem_addr); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_JAL(int m_rd) { |  | ||||||
|         std::int32_t mem_addr; |  | ||||||
|         int rd; |  | ||||||
|         int new_pc, old_pc; |  | ||||||
| 
 |  | ||||||
|         rd = m_rd; |  | ||||||
|         mem_addr = get_imm_J(); |  | ||||||
|         old_pc = static_cast<std::int32_t>(regs->getPC()); |  | ||||||
| 
 |  | ||||||
|         new_pc = old_pc + mem_addr; |  | ||||||
|         regs->setPC(new_pc); |  | ||||||
| 
 |  | ||||||
|         old_pc = old_pc + 2; |  | ||||||
|         regs->setValue(rd, old_pc); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. C.JAL: x{:d} <- 0x{:x}. PC + 0x{:x} -> PC (0x{:x})", |  | ||||||
|                       sc_core::sc_time_stamp().value(), regs->getPC(), |  | ||||||
|                       rd, old_pc, mem_addr, new_pc); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::Exec_C_EBREAK() { |  | ||||||
| 
 |  | ||||||
|         logger->debug("C.EBREAK"); |  | ||||||
|         std::cout << "\n" << "C.EBRAK  Instruction called, dumping information" |  | ||||||
|                   << "\n"; |  | ||||||
|         regs->dump(); |  | ||||||
|         std::cout << "Simulation time " << sc_core::sc_time_stamp() << "\n"; |  | ||||||
|         perf->dump(); |  | ||||||
| 
 |  | ||||||
|         sc_core::sc_stop(); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool C_extension::process_instruction(Instruction &inst, bool *breakpoint) { |  | ||||||
|         bool PC_not_affected = true; |  | ||||||
| 
 |  | ||||||
|         *breakpoint = false; |  | ||||||
| 
 |  | ||||||
|         setInstr(inst.getInstr()); |  | ||||||
| 
 |  | ||||||
|         switch (decode()) { |  | ||||||
|             case OP_C_ADDI4SPN: |  | ||||||
|                 PC_not_affected = Exec_C_ADDI4SPN(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_LW: |  | ||||||
|                 Exec_C_LW(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SW: |  | ||||||
|                 Exec_C_SW(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_ADDI: |  | ||||||
|                 Exec_C_ADDI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_JAL: |  | ||||||
|                 Exec_C_JAL(1); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_J: |  | ||||||
|                 Exec_C_JAL(0); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_LI: |  | ||||||
|                 Exec_C_LI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SLLI: |  | ||||||
|                 Exec_C_SLLI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_LWSP: |  | ||||||
|                 Exec_C_LWSP(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_JR: |  | ||||||
|                 Exec_C_JR(); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_MV: |  | ||||||
|                 Exec_C_MV(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_JALR: |  | ||||||
|                 Exec_C_JALR(); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_ADD: |  | ||||||
|                 Exec_C_ADD(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SWSP: |  | ||||||
|                 Exec_C_SWSP(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_ADDI16SP: |  | ||||||
|                 Exec_C_ADDI16SP(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_BEQZ: |  | ||||||
|                 Exec_C_BEQZ(); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_BNEZ: |  | ||||||
|                 Exec_C_BNEZ(); |  | ||||||
|                 PC_not_affected = false; |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SRLI: |  | ||||||
|                 Exec_C_SRLI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SRAI: |  | ||||||
|                 Exec_C_SRAI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_ANDI: |  | ||||||
|                 Exec_C_ANDI(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_SUB: |  | ||||||
|                 Exec_C_SUB(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_XOR: |  | ||||||
|                 Exec_C_XOR(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_OR: |  | ||||||
|                 Exec_C_OR(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_AND: |  | ||||||
|                 Exec_C_AND(); |  | ||||||
|                 break; |  | ||||||
|             case OP_C_EBREAK: |  | ||||||
|                 Exec_C_EBREAK(); |  | ||||||
|                 std::cout << "C_EBREAK" << std::endl; |  | ||||||
|                 *breakpoint = true; |  | ||||||
|                 break; |  | ||||||
|                 [[unlikely]] default: |  | ||||||
|                 std::cout << "C instruction not implemented yet" << "\n"; |  | ||||||
|                 inst.dump(); |  | ||||||
|                 NOP(); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return PC_not_affected; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -8,292 +8,3 @@ | ||||||
| 
 | 
 | ||||||
| #include "M_extension.h" | #include "M_extension.h" | ||||||
| 
 | 
 | ||||||
| namespace riscv_tlm { |  | ||||||
| 
 |  | ||||||
|     op_M_Codes M_extension::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; |  | ||||||
|                 [[unlikely]] default: |  | ||||||
|                 return OP_M_ERROR; |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return OP_M_ERROR; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_MUL() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::int32_t multiplier, multiplicand; |  | ||||||
|         std::int64_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         multiplier = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         multiplicand = static_cast<std::int32_t>(regs->getValue(rs2)); |  | ||||||
| 
 |  | ||||||
|         result = static_cast<std::int64_t>(multiplier * multiplicand); |  | ||||||
|         result = result & 0x00000000FFFFFFFF; |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(result)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.MUL: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_MULH() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::int32_t multiplier, multiplicand; |  | ||||||
|         std::int64_t result; |  | ||||||
|         std::int32_t ret_value; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         multiplier = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         multiplicand = static_cast<std::int32_t>(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); |  | ||||||
|         regs->setValue(rd, ret_value); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.MULH: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_MULHSU() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::int32_t multiplier; |  | ||||||
|         std::uint32_t multiplicand; |  | ||||||
|         std::int64_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         multiplier = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         multiplicand = regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         result = static_cast<std::int64_t>(multiplier * static_cast<std::uint64_t>(multiplicand)); |  | ||||||
|         result = (result >> 32) & 0x00000000FFFFFFFF; |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(result)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.MULHSU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_MULHU() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t multiplier, multiplicand; |  | ||||||
|         std::uint64_t result; |  | ||||||
|         std::int32_t ret_value; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         multiplier = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         multiplicand = static_cast<std::int32_t>(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); |  | ||||||
|         regs->setValue(rd, ret_value); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.MULHU: x{:d} * x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_DIV() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::int32_t divisor, dividend; |  | ||||||
|         std::int64_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         dividend = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         divisor = static_cast<std::int32_t>(regs->getValue(rs2)); |  | ||||||
| 
 |  | ||||||
|         if (divisor == 0) { |  | ||||||
|             result = -1; |  | ||||||
|         } else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) { |  | ||||||
|             result = 0x0000000080000000; |  | ||||||
|         } else { |  | ||||||
|             result = dividend / divisor; |  | ||||||
|             result = result & 0x00000000FFFFFFFF; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(result)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.DIV: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_DIVU() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t divisor, dividend; |  | ||||||
|         std::uint64_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         dividend = regs->getValue(rs1); |  | ||||||
|         divisor = regs->getValue(rs2); |  | ||||||
| 
 |  | ||||||
|         if (divisor == 0) { |  | ||||||
|             result = -1; |  | ||||||
|         } else { |  | ||||||
|             result = dividend / divisor; |  | ||||||
|             result = result & 0x00000000FFFFFFFF; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(result)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.DIVU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_REM() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::int32_t divisor, dividend; |  | ||||||
|         std::int32_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         dividend = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         divisor = static_cast<std::int32_t>(regs->getValue(rs2)); |  | ||||||
| 
 |  | ||||||
|         if (divisor == 0) { |  | ||||||
|             result = dividend; |  | ||||||
|         } else if ((divisor == -1) && (dividend == static_cast<std::int32_t>(0x80000000))) { |  | ||||||
|             result = 0; |  | ||||||
|         } else { |  | ||||||
|             result = dividend % divisor; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, result); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.REM: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::Exec_M_REMU() const { |  | ||||||
|         int rd, rs1, rs2; |  | ||||||
|         std::uint32_t divisor, dividend; |  | ||||||
|         std::uint32_t result; |  | ||||||
| 
 |  | ||||||
|         rd = get_rd(); |  | ||||||
|         rs1 = get_rs1(); |  | ||||||
|         rs2 = get_rs2(); |  | ||||||
| 
 |  | ||||||
|         dividend = static_cast<std::int32_t>(regs->getValue(rs1)); |  | ||||||
|         divisor = static_cast<std::int32_t>(regs->getValue(rs2)); |  | ||||||
| 
 |  | ||||||
|         if (divisor == 0) { |  | ||||||
|             result = dividend; |  | ||||||
|         } else { |  | ||||||
|             result = dividend % divisor; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         regs->setValue(rd, static_cast<std::int32_t>(result)); |  | ||||||
| 
 |  | ||||||
|         logger->debug("{} ns. PC: 0x{:x}. M.REMU: x{:d} / x{:d} -> x{:d}({:d})", sc_core::sc_time_stamp().value(), |  | ||||||
|                       regs->getPC(), |  | ||||||
|                       rs1, rs2, rd, result); |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool M_extension::process_instruction(Instruction &inst) { |  | ||||||
|         bool PC_not_affected = true; |  | ||||||
| 
 |  | ||||||
|         setInstr(inst.getInstr()); |  | ||||||
| 
 |  | ||||||
|         switch (decode()) { |  | ||||||
|             case OP_M_MUL: |  | ||||||
|                 Exec_M_MUL(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_MULH: |  | ||||||
|                 Exec_M_MULH(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_MULHSU: |  | ||||||
|                 Exec_M_MULHSU(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_MULHU: |  | ||||||
|                 Exec_M_MULHU(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_DIV: |  | ||||||
|                 Exec_M_DIV(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_DIVU: |  | ||||||
|                 Exec_M_DIVU(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_REM: |  | ||||||
|                 Exec_M_REM(); |  | ||||||
|                 break; |  | ||||||
|             case OP_M_REMU: |  | ||||||
|                 Exec_M_REMU(); |  | ||||||
|                 break; |  | ||||||
|                 [[unlikely]] default: |  | ||||||
|                 std::cout << "M instruction not implemented yet" << "\n"; |  | ||||||
|                 inst.dump(); |  | ||||||
|                 //NOP(inst);
 |  | ||||||
|                 sc_core::sc_stop(); |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return PC_not_affected; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
		Loading…
	
		Reference in New Issue