Compare commits
	
		
			9 Commits
		
	
	
		
			featture/i
			...
			f57f9f9177
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f57f9f9177 | |||
| 6f08f4010c | |||
| c9c47673d9 | |||
| c1aed64a41 | |||
| d5d195845c | |||
| 9fcbeb478b | |||
| a768bde7f2 | |||
| cd866fd74d | |||
| 67f364049c | 
| @@ -12,7 +12,6 @@ include(flink) | |||||||
| find_package(elfio QUIET) | find_package(elfio QUIET) | ||||||
| find_package(jsoncpp) | find_package(jsoncpp) | ||||||
| find_package(Boost COMPONENTS coroutine REQUIRED) | find_package(Boost COMPONENTS coroutine REQUIRED) | ||||||
| find_package(absl REQUIRED) |  | ||||||
|  |  | ||||||
| add_subdirectory(softfloat) | add_subdirectory(softfloat) | ||||||
|  |  | ||||||
| @@ -105,7 +104,7 @@ if(NOT(DBT_CORE_DEFS STREQUAL DBT_CORE_DEFS-NOTFOUND)) | |||||||
|     target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS}) |     target_compile_definitions(${PROJECT_NAME} INTERFACE ${DBT_CORE_DEFS}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine abseil::abseil) | target_link_libraries(${PROJECT_NAME} PUBLIC elfio::elfio softfloat scc-util Boost::coroutine) | ||||||
|  |  | ||||||
| if(TARGET yaml-cpp::yaml-cpp) | if(TARGET yaml-cpp::yaml-cpp) | ||||||
|     target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS) |     target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_PLUGINS) | ||||||
|   | |||||||
| @@ -962,6 +962,74 @@ if(vector != null) {%> | |||||||
|                 throw new std::runtime_error("Unsupported sew bit value"); |                 throw new std::runtime_error("Unsupported sew bit value"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     void vector_unary_op(uint8_t* V, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t sew_val){ | ||||||
|  |         switch(sew_val){ | ||||||
|  |             case 0b000: | ||||||
|  |                 return softvector::vector_unary_op<${vlen}, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2); | ||||||
|  |             case 0b001: | ||||||
|  |                 return softvector::vector_unary_op<${vlen}, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2); | ||||||
|  |             case 0b010: | ||||||
|  |                 return softvector::vector_unary_op<${vlen}, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2); | ||||||
|  |             case 0b011: | ||||||
|  |                 return softvector::vector_unary_op<${vlen}, uint64_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2); | ||||||
|  |             default:  | ||||||
|  |                 throw new std::runtime_error("Unsupported sew_val"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     void vector_vector_crypto(uint8_t* V, uint8_t funct6, uint64_t eg_len, uint64_t eg_start, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t egs){ | ||||||
|  |         switch(egs){ | ||||||
|  |             case 4: | ||||||
|  |                 return softvector::vector_vector_crypto<${vlen}, 4>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |             case 8: | ||||||
|  |                 return softvector::vector_vector_crypto<${vlen}, 8>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |             default:  | ||||||
|  |                 throw new std::runtime_error("Unsupported egs"); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  |     void vector_scalar_crypto(uint8_t* V, uint8_t funct6, uint64_t eg_len, uint64_t eg_start, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t egs){ | ||||||
|  |         switch(egs){ | ||||||
|  |             case 4: | ||||||
|  |                 return softvector::vector_scalar_crypto<${vlen}, 4>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |             case 8: | ||||||
|  |                 return softvector::vector_scalar_crypto<${vlen}, 8>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |             default:  | ||||||
|  |                 throw new std::runtime_error("Unsupported egs"); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  |     void vector_imm_crypto(uint8_t* V, uint8_t funct6, uint64_t eg_len, uint64_t eg_start, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t imm, uint8_t egs){ | ||||||
|  |         switch(egs){ | ||||||
|  |             case 4: | ||||||
|  |                 return softvector::vector_imm_crypto<${vlen}, 4>(V, funct6, eg_len, eg_start, vtype, vd, vs2, imm); | ||||||
|  |             case 8: | ||||||
|  |                 return softvector::vector_imm_crypto<${vlen}, 8>(V, funct6, eg_len, eg_start, vtype, vd, vs2, imm); | ||||||
|  |             default:  | ||||||
|  |                 throw new std::runtime_error("Unsupported egs"); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  |     void vector_crypto(uint8_t* V, uint8_t funct6, uint64_t eg_len, uint64_t eg_start, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t egs, uint8_t sew){ | ||||||
|  |         switch(egs){ | ||||||
|  |             case 4: | ||||||
|  |                 switch(sew){ | ||||||
|  |                     case 32: | ||||||
|  |                         return softvector::vector_crypto<${vlen}, 4, uint32_t>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |                     case 64: | ||||||
|  |                         return softvector::vector_crypto<${vlen}, 4, uint64_t>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |                     default:  | ||||||
|  |                         throw new std::runtime_error("Unsupported sew"); | ||||||
|  |                 } | ||||||
|  |             case 8: | ||||||
|  |                 switch(sew){ | ||||||
|  |                     case 32: | ||||||
|  |                         return softvector::vector_crypto<${vlen}, 8, uint32_t>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |                     case 64: | ||||||
|  |                         return softvector::vector_crypto<${vlen}, 8, uint64_t>(V, funct6, eg_len, eg_start, vtype, vd, vs2, vs1); | ||||||
|  |                     default:  | ||||||
|  |                         throw new std::runtime_error("Unsupported sew"); | ||||||
|  |                 }             | ||||||
|  |             default:  | ||||||
|  |                 throw new std::runtime_error("Unsupported egs"); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
| <%}%> | <%}%> | ||||||
|     uint64_t fetch_count{0}; |     uint64_t fetch_count{0}; | ||||||
|     uint64_t tval{0}; |     uint64_t tval{0}; | ||||||
|   | |||||||
| @@ -37,7 +37,6 @@ | |||||||
|  |  | ||||||
| #include "mstatus.h" | #include "mstatus.h" | ||||||
| #include "util/delegate.h" | #include "util/delegate.h" | ||||||
| #include <absl/container/flat_hash_map.h> |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
| #include <elfio/elfio.hpp> | #include <elfio/elfio.hpp> | ||||||
| @@ -231,11 +230,6 @@ public: | |||||||
|     trap_load_access_fault(uint64_t badaddr) |     trap_load_access_fault(uint64_t badaddr) | ||||||
|     : trap_access(5 << 16, badaddr) {} |     : trap_access(5 << 16, badaddr) {} | ||||||
| }; | }; | ||||||
| class illegal_instruction_fault : public trap_access { |  | ||||||
| public: |  | ||||||
|     illegal_instruction_fault(uint64_t badaddr) |  | ||||||
|     : trap_access(2 << 16, badaddr) {} |  | ||||||
| }; |  | ||||||
| class trap_instruction_page_fault : public trap_access { | class trap_instruction_page_fault : public trap_access { | ||||||
| public: | public: | ||||||
|     trap_instruction_page_fault(uint64_t badaddr) |     trap_instruction_page_fault(uint64_t badaddr) | ||||||
| @@ -260,8 +254,8 @@ template <typename WORD_TYPE> struct priv_if { | |||||||
|     std::function<iss::status(unsigned, WORD_TYPE)> write_csr; |     std::function<iss::status(unsigned, WORD_TYPE)> write_csr; | ||||||
|     std::function<iss::status(uint8_t const*)> exec_htif; |     std::function<iss::status(uint8_t const*)> exec_htif; | ||||||
|     std::function<void(uint16_t, uint16_t, WORD_TYPE)> raise_trap; // trap_id, cause, fault_data |     std::function<void(uint16_t, uint16_t, WORD_TYPE)> raise_trap; // trap_id, cause, fault_data | ||||||
|     absl::flat_hash_map<unsigned, rd_csr_f>& csr_rd_cb; |     std::unordered_map<unsigned, rd_csr_f>& csr_rd_cb; | ||||||
|     absl::flat_hash_map<unsigned, wr_csr_f>& csr_wr_cb; |     std::unordered_map<unsigned, wr_csr_f>& csr_wr_cb; | ||||||
|     hart_state<WORD_TYPE>& state; |     hart_state<WORD_TYPE>& state; | ||||||
|     uint8_t& PRIV; |     uint8_t& PRIV; | ||||||
|     WORD_TYPE& PC; |     WORD_TYPE& PC; | ||||||
| @@ -524,10 +518,10 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co | |||||||
|             return iss::Err; |             return iss::Err; | ||||||
|         auto req_priv_lvl = (addr >> 8) & 0x3; |         auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|         if(this->reg.PRIV < req_priv_lvl) // not having required privileges |         if(this->reg.PRIV < req_priv_lvl) // not having required privileges | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         auto it = csr_rd_cb.find(addr); |         auto it = csr_rd_cb.find(addr); | ||||||
|         if(it == csr_rd_cb.end() || !it->second) // non existent register |         if(it == csr_rd_cb.end() || !it->second) // non existent register | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         return it->second(addr, val); |         return it->second(addr, val); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -536,12 +530,12 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co | |||||||
|             return iss::Err; |             return iss::Err; | ||||||
|         auto req_priv_lvl = (addr >> 8) & 0x3; |         auto req_priv_lvl = (addr >> 8) & 0x3; | ||||||
|         if(this->reg.PRIV < req_priv_lvl) // not having required privileges |         if(this->reg.PRIV < req_priv_lvl) // not having required privileges | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         if((addr & 0xc00) == 0xc00) // writing to read-only region |         if((addr & 0xc00) == 0xc00) // writing to read-only region | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         auto it = csr_wr_cb.find(addr); |         auto it = csr_wr_cb.find(addr); | ||||||
|         if(it == csr_wr_cb.end() || !it->second) // non existent register |         if(it == csr_wr_cb.end() || !it->second) // non existent register | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         return it->second(addr, val); |         return it->second(addr, val); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -638,7 +632,7 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co | |||||||
|  |  | ||||||
|     iss::status write_dcsr(unsigned addr, reg_t val) { |     iss::status write_dcsr(unsigned addr, reg_t val) { | ||||||
|         if(!debug_mode_active()) |         if(!debug_mode_active()) | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         //                  +-------------- ebreakm |         //                  +-------------- ebreakm | ||||||
|         //                  |   +---------- stepi |         //                  |   +---------- stepi | ||||||
|         //                  |   |  +++----- cause |         //                  |   |  +++----- cause | ||||||
| @@ -649,28 +643,28 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co | |||||||
|  |  | ||||||
|     iss::status read_debug(unsigned addr, reg_t& val) { |     iss::status read_debug(unsigned addr, reg_t& val) { | ||||||
|         if(!debug_mode_active()) |         if(!debug_mode_active()) | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         val = csr[addr]; |         val = csr[addr]; | ||||||
|         return iss::Ok; |         return iss::Ok; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     iss::status write_dscratch(unsigned addr, reg_t val) { |     iss::status write_dscratch(unsigned addr, reg_t val) { | ||||||
|         if(!debug_mode_active()) |         if(!debug_mode_active()) | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         csr[addr] = val; |         csr[addr] = val; | ||||||
|         return iss::Ok; |         return iss::Ok; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     iss::status read_dpc(unsigned addr, reg_t& val) { |     iss::status read_dpc(unsigned addr, reg_t& val) { | ||||||
|         if(!debug_mode_active()) |         if(!debug_mode_active()) | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         val = this->reg.DPC; |         val = this->reg.DPC; | ||||||
|         return iss::Ok; |         return iss::Ok; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     iss::status write_dpc(unsigned addr, reg_t val) { |     iss::status write_dpc(unsigned addr, reg_t val) { | ||||||
|         if(!debug_mode_active()) |         if(!debug_mode_active()) | ||||||
|             throw illegal_instruction_fault(this->fault_data); |             return iss::Err; | ||||||
|         this->reg.DPC = val; |         this->reg.DPC = val; | ||||||
|         return iss::Ok; |         return iss::Ok; | ||||||
|     } |     } | ||||||
| @@ -776,7 +770,7 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co | |||||||
|                                       this->fault_data = fault_data; |                                       this->fault_data = fault_data; | ||||||
|                                   }, |                                   }, | ||||||
|                               .csr_rd_cb{this->csr_rd_cb}, |                               .csr_rd_cb{this->csr_rd_cb}, | ||||||
|                               .csr_wr_cb{this->csr_wr_cb}, |                               .csr_wr_cb{csr_wr_cb}, | ||||||
|                               .state{this->state}, |                               .state{this->state}, | ||||||
|                               .PRIV{this->reg.PRIV}, |                               .PRIV{this->reg.PRIV}, | ||||||
|                               .PC{this->reg.PC}, |                               .PC{this->reg.PC}, | ||||||
| @@ -890,12 +884,11 @@ protected: | |||||||
|  |  | ||||||
|     instrumentation_if* get_instrumentation_if() override { return &instr_if; }; |     instrumentation_if* get_instrumentation_if() override { return &instr_if; }; | ||||||
|  |  | ||||||
|     using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>; |     using csr_type = std::array<typename traits<BASE>::reg_t, 1ULL << 12>; | ||||||
|     using csr_page_type = typename csr_type::page_type; |  | ||||||
|     csr_type csr; |     csr_type csr; | ||||||
|  |  | ||||||
|     absl::flat_hash_map<unsigned, rd_csr_f> csr_rd_cb; |     std::unordered_map<unsigned, rd_csr_f> csr_rd_cb; | ||||||
|     absl::flat_hash_map<unsigned, wr_csr_f> csr_wr_cb; |     std::unordered_map<unsigned, wr_csr_f> csr_wr_cb; | ||||||
|  |  | ||||||
|     reg_t mhartid_reg{0x0}; |     reg_t mhartid_reg{0x0}; | ||||||
|     uint64_t mcycle_csr{0}; |     uint64_t mcycle_csr{0}; | ||||||
|   | |||||||
| @@ -134,7 +134,7 @@ protected: | |||||||
|  |  | ||||||
|     hart_state<reg_t> state; |     hart_state<reg_t> state; | ||||||
|  |  | ||||||
|     absl::flat_hash_map<uint64_t, uint8_t> atomic_reservation; |     std::unordered_map<uint64_t, uint8_t> atomic_reservation; | ||||||
|  |  | ||||||
|     iss::status read_status(unsigned addr, reg_t& val); |     iss::status read_status(unsigned addr, reg_t& val); | ||||||
|     iss::status write_status(unsigned addr, reg_t val); |     iss::status write_status(unsigned addr, reg_t val); | ||||||
|   | |||||||
| @@ -48,9 +48,9 @@ | |||||||
| #ifndef FMT_HEADER_ONLY | #ifndef FMT_HEADER_ONLY | ||||||
| #define FMT_HEADER_ONLY | #define FMT_HEADER_ONLY | ||||||
| #endif | #endif | ||||||
| #include <fmt/format.h> |  | ||||||
| #include <iss/mem/memory_with_htif.h> | #include <iss/mem/memory_with_htif.h> | ||||||
| #include <iss/mem/mmu.h> | #include <iss/mem/mmu.h> | ||||||
|  | #include <fmt/format.h> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
|  |  | ||||||
| @@ -150,7 +150,7 @@ protected: | |||||||
|  |  | ||||||
|     hart_state<reg_t> state; |     hart_state<reg_t> state; | ||||||
|  |  | ||||||
|     absl::flat_hash_map<uint64_t, uint8_t> atomic_reservation; |     std::unordered_map<uint64_t, uint8_t> atomic_reservation; | ||||||
|  |  | ||||||
|     iss::status read_status(unsigned addr, reg_t& val); |     iss::status read_status(unsigned addr, reg_t& val); | ||||||
|     iss::status write_status(unsigned addr, reg_t val); |     iss::status write_status(unsigned addr, reg_t val); | ||||||
|   | |||||||
| @@ -160,7 +160,7 @@ protected: | |||||||
|  |  | ||||||
|     hart_state<reg_t> state; |     hart_state<reg_t> state; | ||||||
|  |  | ||||||
|     absl::flat_hash_map<uint64_t, uint8_t> atomic_reservation; |     std::unordered_map<uint64_t, uint8_t> atomic_reservation; | ||||||
|  |  | ||||||
|     iss::status read_status(unsigned addr, reg_t& val); |     iss::status read_status(unsigned addr, reg_t& val); | ||||||
|     iss::status write_status(unsigned addr, reg_t val); |     iss::status write_status(unsigned addr, reg_t val); | ||||||
|   | |||||||
| @@ -39,7 +39,6 @@ | |||||||
| #include <iss/iss.h> | #include <iss/iss.h> | ||||||
|  |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <memory> |  | ||||||
| #ifndef FMT_HEADER_ONLY | #ifndef FMT_HEADER_ONLY | ||||||
| #define FMT_HEADER_ONLY | #define FMT_HEADER_ONLY | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -32,9 +32,9 @@ | |||||||
|  *       eyck@minres.com - initial implementation |  *       eyck@minres.com - initial implementation | ||||||
|  ******************************************************************************/ |  ******************************************************************************/ | ||||||
|  |  | ||||||
|  | #include "memory_if.h" | ||||||
| #include "iss/arch/riscv_hart_common.h" | #include "iss/arch/riscv_hart_common.h" | ||||||
| #include "iss/vm_types.h" | #include "iss/vm_types.h" | ||||||
| #include "memory_if.h" |  | ||||||
| #include <util/logging.h> | #include <util/logging.h> | ||||||
|  |  | ||||||
| namespace iss { | namespace iss { | ||||||
| @@ -238,7 +238,7 @@ private: | |||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     reg_t satp; |     reg_t satp; | ||||||
|     absl::flat_hash_map<reg_t, uint64_t> ptw; |     std::unordered_map<reg_t, uint64_t> ptw; | ||||||
|     std::array<vm_info, 2> vmt; |     std::array<vm_info, 2> vmt; | ||||||
|     std::array<address_type, 4> addr_mode; |     std::array<address_type, 4> addr_mode; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -250,7 +250,7 @@ template <typename T> void semihosting_callback<T>::operator()(iss::arch_if* arc | |||||||
|         T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter); |         T cmd_addr = sh_read_field<T>(arch_if_ptr, *parameter); | ||||||
|         T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 1); |         T cmd_len = sh_read_field<T>(arch_if_ptr, (*parameter) + 1); | ||||||
|         std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len); |         std::string cmd = sh_read_string<T>(arch_if_ptr, cmd_addr, cmd_len); | ||||||
|         system(cmd.c_str()); |         auto val = system(cmd.c_str()); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case semihosting_syscalls::SYS_TICKFREQ: { |     case semihosting_syscalls::SYS_TICKFREQ: { | ||||||
|   | |||||||
| @@ -45,11 +45,10 @@ | |||||||
| #include <scc/report.h> | #include <scc/report.h> | ||||||
| #include <util/ities.h> | #include <util/ities.h> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <sstream> |  | ||||||
| #include <array> | #include <array> | ||||||
| #include <numeric> |  | ||||||
| #include <iss/plugin/cycle_estimate.h> | #include <iss/plugin/cycle_estimate.h> | ||||||
| #include <iss/plugin/instruction_count.h> | #include <iss/plugin/instruction_count.h> | ||||||
|  | #include <util/ities.h> | ||||||
|  |  | ||||||
| // clang-format on | // clang-format on | ||||||
|  |  | ||||||
| @@ -267,7 +266,10 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::before_end_of_elab | |||||||
|     cpu = new core_wrapper(this); |     cpu = new core_wrapper(this); | ||||||
|     cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid)); |     cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid)); | ||||||
|     sc_assert(cpu->vm != nullptr); |     sc_assert(cpu->vm != nullptr); | ||||||
|     cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr); |     auto disass = GET_PROP_VALUE(enable_disass); | ||||||
|  |     if(disass && trc->m_db) | ||||||
|  |         SCCINFO(SCMOD) << "Disasssembly will only be in transaction trace database!"; | ||||||
|  |     cpu->vm->setDisassEnabled(disass || trc->m_db != nullptr); | ||||||
|     if(GET_PROP_VALUE(plugins).length()) { |     if(GET_PROP_VALUE(plugins).length()) { | ||||||
|         auto p = util::split(GET_PROP_VALUE(plugins), ';'); |         auto p = util::split(GET_PROP_VALUE(plugins), ';'); | ||||||
|         for(std::string const& opt_val : p) { |         for(std::string const& opt_val : p) { | ||||||
| @@ -305,17 +307,20 @@ template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::before_end_of_elab | |||||||
| template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::start_of_simulation() { | template <unsigned int BUSWIDTH> void core_complex<BUSWIDTH>::start_of_simulation() { | ||||||
|     // quantum_keeper.reset(); |     // quantum_keeper.reset(); | ||||||
|     if(GET_PROP_VALUE(elf_file).size() > 0) { |     if(GET_PROP_VALUE(elf_file).size() > 0) { | ||||||
|         istringstream is(GET_PROP_VALUE(elf_file)); |         auto file_names = util::split(GET_PROP_VALUE(elf_file), ','); | ||||||
|         string s; |         for(auto& s : file_names) { | ||||||
|         while(getline(is, s, ',')) { |             std::pair<uint64_t, bool> load_result = cpu->load_file(s); | ||||||
|             std::pair<uint64_t, bool> start_addr = cpu->load_file(s); |             if(!std::get<1>(load_result)) { | ||||||
|  |                 SCCWARN(SCMOD) << "Could not load FW file " << s; | ||||||
|  |             } else { | ||||||
| #ifndef CWR_SYSTEMC | #ifndef CWR_SYSTEMC | ||||||
|             if(reset_address.is_default_value() && start_addr.second == true) |                 if(reset_address.is_default_value()) | ||||||
|                 reset_address.set_value(start_addr.first); |                     reset_address.set_value(load_result.first); | ||||||
| #else | #else | ||||||
|             if(start_addr.second == true) |                 if(start_addr.second == true) | ||||||
|                 reset_address = start_addr.first; |                     reset_address = start_addr.first; | ||||||
| #endif | #endif | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if(trc->m_db != nullptr && trc->stream_handle == nullptr) { |     if(trc->m_db != nullptr && trc->stream_handle == nullptr) { | ||||||
|   | |||||||
| @@ -38,17 +38,14 @@ | |||||||
| #include <iss/iss.h> | #include <iss/iss.h> | ||||||
| #include <iss/interp/vm_base.h> | #include <iss/interp/vm_base.h> | ||||||
|  |  | ||||||
| #include <stdexcept> |  | ||||||
| #include <unordered_map> |  | ||||||
| #include <util/logging.h> | #include <util/logging.h> | ||||||
| #include <boost/coroutine2/all.hpp> | #include <boost/coroutine2/all.hpp> | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <exception> | #include <exception> | ||||||
| #include <utility> |  | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <sstream> | #include <sstream> | ||||||
| #include <iss/instruction_decoder.h> | #include <iss/instruction_decoder.h> | ||||||
| #include <absl/container/flat_hash_map.h> |  | ||||||
|  |  | ||||||
| #ifndef FMT_HEADER_ONLY | #ifndef FMT_HEADER_ONLY | ||||||
| #define FMT_HEADER_ONLY | #define FMT_HEADER_ONLY | ||||||
| @@ -258,11 +255,6 @@ private: | |||||||
|             return iss::Err; |             return iss::Err; | ||||||
|         return iss::Ok; |         return iss::Ok; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     struct translation_buffer { |  | ||||||
|         std::vector<std::tuple<opcode_e, uint64_t, uint32_t>> entries; |  | ||||||
|     } tb; |  | ||||||
|     absl::flat_hash_map<uint64_t, translation_buffer> tb_lut; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
| @@ -320,8 +312,27 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|     auto& instr =  this->core.reg.instruction; |     auto& instr =  this->core.reg.instruction; | ||||||
|     // we fetch at max 4 byte, alignment is 2 |     // we fetch at max 4 byte, alignment is 2 | ||||||
|     auto *const data = reinterpret_cast<uint8_t*>(&instr); |     auto *const data = reinterpret_cast<uint8_t*>(&instr); | ||||||
|     auto exec = [this, PC, NEXT_PC](opcode_e inst_id, uint64_t pc, uint32_t instr) { |  | ||||||
|                 // pre execution stuff |     while(!this->core.should_stop() && | ||||||
|  |             !(is_icount_limit_enabled(cond) && icount >= count_limit) && | ||||||
|  |             !(is_fcount_limit_enabled(cond) && fetch_count >= count_limit)){ | ||||||
|  |         if(this->debugging_enabled()) | ||||||
|  |             this->tgt_adapter->check_continue(*PC); | ||||||
|  |         pc.val=*PC; | ||||||
|  |         if(fetch_ins(pc, data)!=iss::Ok){ | ||||||
|  |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max()); | ||||||
|  |             process_spawn_blocks(); | ||||||
|  |             if(this->sync_exec && POST_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max()); | ||||||
|  |             pc.val = super::core.enter_trap(arch::traits<ARCH>::RV_CAUSE_FETCH_ACCESS<<16, pc.val, 0); | ||||||
|  |         } else { | ||||||
|  |             if (is_jump_to_self_enabled(cond) && | ||||||
|  |                     (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' | ||||||
|  |             uint32_t inst_index = instr_decoder.decode_instr(instr); | ||||||
|  |             opcode_e inst_id = arch::traits<ARCH>::opcode_e::MAX_OPCODE;; | ||||||
|  |             if(inst_index <instr_descr.size()) | ||||||
|  |                 inst_id = instr_descr[inst_index].op; | ||||||
|  |  | ||||||
|  |             // pre execution stuff | ||||||
|             this->core.reg.last_branch = 0; |             this->core.reg.last_branch = 0; | ||||||
|             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); | ||||||
|             try{ |             try{ | ||||||
| @@ -334,7 +345,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), |                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "lui"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -361,7 +372,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), |                             "{mnemonic:10} {rd}, {imm:#08x}", fmt::arg("mnemonic", "auipc"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -388,7 +399,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), |                             "{mnemonic:10} {rd}, {imm:#0x}", fmt::arg("mnemonic", "jal"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -425,7 +436,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"), |                             "{mnemonic:10} {rd}, {rs1}, {imm:#0x}", fmt::arg("mnemonic", "jalr"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -463,7 +474,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "beq"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -499,7 +510,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bne"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -535,7 +546,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "blt"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -571,7 +582,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bge"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -607,7 +618,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bltu"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -643,7 +654,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), |                             "{mnemonic:10} {rs1}, {rs2}, {imm:#0x}", fmt::arg("mnemonic", "bgeu"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -679,7 +690,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), |                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lb"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -711,7 +722,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), |                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lh"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -743,7 +754,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), |                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lw"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -775,7 +786,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), |                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lbu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -807,7 +818,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), |                             "{mnemonic:10} {rd}, {imm}({rs1})", fmt::arg("mnemonic", "lhu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -839,7 +850,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), |                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sb"), | ||||||
|                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -867,7 +878,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), |                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sh"), | ||||||
|                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -895,7 +906,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), |                             "{mnemonic:10} {rs2}, {imm}({rs1})", fmt::arg("mnemonic", "sw"), | ||||||
|                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rs2", name(rs2)), fmt::arg("imm", imm), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -923,7 +934,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "addi"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "addi"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -951,7 +962,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "slti"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "slti"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -979,7 +990,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "sltiu"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "sltiu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1007,7 +1018,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "xori"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "xori"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1035,7 +1046,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "ori"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "ori"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1063,7 +1074,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "andi"), |                             "{mnemonic:10} {rd}, {rs1}, {imm}", fmt::arg("mnemonic", "andi"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1091,7 +1102,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), |                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "slli"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1119,7 +1130,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), |                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srli"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1147,7 +1158,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), |                             "{mnemonic:10} {rd}, {rs1}, {shamt}", fmt::arg("mnemonic", "srai"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("shamt", shamt)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1175,7 +1186,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "add"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1203,7 +1214,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sub"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1231,7 +1242,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sll"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1259,7 +1270,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "slt"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1287,7 +1298,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sltu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1315,7 +1326,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "xor"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1343,7 +1354,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "srl"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1371,7 +1382,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "sra"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1399,7 +1410,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "or"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1427,7 +1438,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "and"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1457,7 +1468,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {pred}, {succ} ({fm} , {rs1}, {rd})", fmt::arg("mnemonic", "fence"), |                             "{mnemonic:10} {pred}, {succ} ({fm} , {rs1}, {rd})", fmt::arg("mnemonic", "fence"), | ||||||
|                             fmt::arg("pred", pred), fmt::arg("succ", succ), fmt::arg("fm", fm), fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd))); |                             fmt::arg("pred", pred), fmt::arg("succ", succ), fmt::arg("fm", fm), fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1474,7 +1485,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "ecall"; |                         std::string mnemonic = "ecall"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1490,7 +1501,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "ebreak"; |                         std::string mnemonic = "ebreak"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1506,7 +1517,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "mret"; |                         std::string mnemonic = "mret"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1522,7 +1533,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "wfi"; |                         std::string mnemonic = "wfi"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1542,7 +1553,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), |                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrw"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1580,7 +1591,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), |                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrs"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1616,7 +1627,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), |                             "{mnemonic:10} {rd}, {csr}, {rs1}", fmt::arg("mnemonic", "csrrc"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1652,7 +1663,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), |                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrwi"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1685,7 +1696,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), |                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrsi"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1720,7 +1731,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), |                             "{mnemonic:10} {rd}, {csr}, {zimm:#0x}", fmt::arg("mnemonic", "csrrci"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); |                             fmt::arg("rd", name(rd)), fmt::arg("csr", csr), fmt::arg("zimm", zimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1755,7 +1766,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {rd}, {imm}", fmt::arg("mnemonic", "fence_i"), |                             "{mnemonic:10} {rs1}, {rd}, {imm}", fmt::arg("mnemonic", "fence_i"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -1776,7 +1787,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mul"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mul"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1805,7 +1816,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulh"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulh"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1834,7 +1845,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhsu"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhsu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1863,7 +1874,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhu"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "mulhu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1892,7 +1903,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "div"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "div"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1933,7 +1944,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "divu"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "divu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -1968,7 +1979,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "rem"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "rem"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2011,7 +2022,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "remu"), |                             "{mnemonic:10} {rd}, {rs1}, {rs2}", fmt::arg("mnemonic", "remu"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs1", name(rs1)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2045,7 +2056,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.addi4spn"), |                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.addi4spn"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(8+rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2071,7 +2082,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.lw"), |                             "{mnemonic:10} {rd}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.lw"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); |                             fmt::arg("rd", name(8+rd)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2095,7 +2106,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs2}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.sw"), |                             "{mnemonic:10} {rs2}, {uimm:#05x}({rs1})", fmt::arg("mnemonic", "c.sw"), | ||||||
|                             fmt::arg("rs2", name(8+rs2)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); |                             fmt::arg("rs2", name(8+rs2)), fmt::arg("uimm", uimm), fmt::arg("rs1", name(8+rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2117,7 +2128,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.addi"), |                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.addi"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2142,7 +2153,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "c.nop"; |                         std::string mnemonic = "c.nop"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2159,7 +2170,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.jal"), |                             "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.jal"), | ||||||
|                             fmt::arg("imm", imm)); |                             fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2181,7 +2192,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.li"), |                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.li"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2208,7 +2219,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.lui"), |                             "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "c.lui"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); |                             fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2232,7 +2243,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {nzimm:#05x}", fmt::arg("mnemonic", "c.addi16sp"), |                             "{mnemonic:10} {nzimm:#05x}", fmt::arg("mnemonic", "c.addi16sp"), | ||||||
|                             fmt::arg("nzimm", nzimm)); |                             fmt::arg("nzimm", nzimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2255,7 +2266,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = ".reserved_clui"; |                         std::string mnemonic = ".reserved_clui"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2274,7 +2285,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srli"), |                             "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srli"), | ||||||
|                             fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); |                             fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2294,7 +2305,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srai"), |                             "{mnemonic:10} {rs1}, {shamt}", fmt::arg("mnemonic", "c.srai"), | ||||||
|                             fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); |                             fmt::arg("rs1", name(8+rs1)), fmt::arg("shamt", shamt)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2321,7 +2332,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.andi"), |                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.andi"), | ||||||
|                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2341,7 +2352,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.sub"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.sub"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); |                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2361,7 +2372,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.xor"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.xor"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); |                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2381,7 +2392,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.or"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.or"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); |                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2401,7 +2412,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.and"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.and"), | ||||||
|                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); |                             fmt::arg("rd", name(8+rd)), fmt::arg("rs2", name(8+rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2420,7 +2431,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.j"), |                             "{mnemonic:10} {imm:#05x}", fmt::arg("mnemonic", "c.j"), | ||||||
|                             fmt::arg("imm", imm)); |                             fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2440,7 +2451,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.beqz"), |                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.beqz"), | ||||||
|                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2463,7 +2474,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.bnez"), |                             "{mnemonic:10} {rs1}, {imm:#05x}", fmt::arg("mnemonic", "c.bnez"), | ||||||
|                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); |                             fmt::arg("rs1", name(8+rs1)), fmt::arg("imm", imm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2486,7 +2497,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}, {nzuimm}", fmt::arg("mnemonic", "c.slli"), |                             "{mnemonic:10} {rs1}, {nzuimm}", fmt::arg("mnemonic", "c.slli"), | ||||||
|                             fmt::arg("rs1", name(rs1)), fmt::arg("nzuimm", nzuimm)); |                             fmt::arg("rs1", name(rs1)), fmt::arg("nzuimm", nzuimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2513,7 +2524,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, sp, {uimm:#05x}", fmt::arg("mnemonic", "c.lwsp"), |                             "{mnemonic:10} {rd}, sp, {uimm:#05x}", fmt::arg("mnemonic", "c.lwsp"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("uimm", uimm)); |                             fmt::arg("rd", name(rd)), fmt::arg("uimm", uimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2541,7 +2552,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.mv"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.mv"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2567,7 +2578,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jr"), |                             "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jr"), | ||||||
|                             fmt::arg("rs1", name(rs1))); |                             fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2591,7 +2602,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = ".reserved_cmv"; |                         std::string mnemonic = ".reserved_cmv"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2610,7 +2621,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.add"), |                             "{mnemonic:10} {rd}, {rs2}", fmt::arg("mnemonic", "c.add"), | ||||||
|                             fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); |                             fmt::arg("rd", name(rd)), fmt::arg("rs2", name(rs2))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2636,7 +2647,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jalr"), |                             "{mnemonic:10} {rs1}", fmt::arg("mnemonic", "c.jalr"), | ||||||
|                             fmt::arg("rs1", name(rs1))); |                             fmt::arg("rs1", name(rs1))); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2662,7 +2673,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "c.ebreak"; |                         std::string mnemonic = "c.ebreak"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2681,7 +2692,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         auto mnemonic = fmt::format( |                         auto mnemonic = fmt::format( | ||||||
|                             "{mnemonic:10} {rs2}, {uimm:#05x}(sp)", fmt::arg("mnemonic", "c.swsp"), |                             "{mnemonic:10} {rs2}, {uimm:#05x}(sp)", fmt::arg("mnemonic", "c.swsp"), | ||||||
|                             fmt::arg("rs2", name(rs2)), fmt::arg("uimm", uimm)); |                             fmt::arg("rs2", name(rs2)), fmt::arg("uimm", uimm)); | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); |                     auto* X = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::X0]); | ||||||
| @@ -2705,7 +2716,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|                         /* generate console output when executing the command */ |                         /* generate console output when executing the command */ | ||||||
|                         //No disass specified, using instruction name |                         //No disass specified, using instruction name | ||||||
|                         std::string mnemonic = "dii"; |                         std::string mnemonic = "dii"; | ||||||
|                         this->core.disass_output(pc, mnemonic); |                         this->core.disass_output(pc.val, mnemonic); | ||||||
|                     } |                     } | ||||||
|                     // used registers |                     // used registers | ||||||
|                     // calculate next pc value |                     // calculate next pc value | ||||||
| @@ -2728,54 +2739,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|             // if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt |             // if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt | ||||||
|             //    this->core.reg.trap_state =  this->core.reg.pending_trap; |             //    this->core.reg.trap_state =  this->core.reg.pending_trap; | ||||||
|             // trap check |             // trap check | ||||||
|             if(this->core.reg.trap_state!=0){ |             if(trap_state!=0){ | ||||||
|                 //In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval) |                 //In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval) | ||||||
|                 auto mcause = (this->core.reg.trap_state>>16) & 0xff;  |                 auto mcause = (trap_state>>16) & 0xff;  | ||||||
|                 super::core.enter_trap(this->core.reg.trap_state, pc, mcause ? instr:tval); |                 super::core.enter_trap(trap_state, pc.val, mcause ? instr:tval); | ||||||
|             } else { |             } else { | ||||||
|                 this->core.reg.icount++; |                 icount++; | ||||||
|                 this->core.reg.instret++; |                 instret++; | ||||||
|             } |             } | ||||||
|             *PC = *NEXT_PC; |             *PC = *NEXT_PC; | ||||||
|             this->core.reg.trap_state =  this->core.reg.pending_trap; |             this->core.reg.trap_state =  this->core.reg.pending_trap; | ||||||
|  |  | ||||||
|     }; |  | ||||||
|     while(!this->core.should_stop() && |  | ||||||
|             !(is_icount_limit_enabled(cond) && icount >= count_limit) && |  | ||||||
|             !(is_fcount_limit_enabled(cond) && fetch_count >= count_limit)){ |  | ||||||
|         if(this->debugging_enabled()) |  | ||||||
|             this->tgt_adapter->check_continue(*PC); |  | ||||||
|         pc.val=*PC; |  | ||||||
|         auto current_tb = tb_lut.find(pc.val); |  | ||||||
|         if(current_tb==tb_lut.end()) { |  | ||||||
|             auto res = tb_lut.insert(std::make_pair(pc.val,translation_buffer{})); |  | ||||||
|             if(!res.second) |  | ||||||
|                 throw std::runtime_error(""); |  | ||||||
|             current_tb=res.first; |  | ||||||
|             do { |  | ||||||
|                 if(fetch_ins(pc, data)!=iss::Ok){ |  | ||||||
|                     if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max()); |  | ||||||
|                     process_spawn_blocks(); |  | ||||||
|                     if(this->sync_exec && POST_SYNC) this->do_sync(PRE_SYNC, std::numeric_limits<unsigned>::max()); |  | ||||||
|                     pc.val = super::core.enter_trap(arch::traits<ARCH>::RV_CAUSE_FETCH_ACCESS<<16, pc.val, 0); |  | ||||||
|                     break; |  | ||||||
|                 } else { |  | ||||||
|                     if (is_jump_to_self_enabled(cond) && |  | ||||||
|                             (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' |  | ||||||
|                     uint32_t inst_index = instr_decoder.decode_instr(instr); |  | ||||||
|                     opcode_e inst_id = arch::traits<ARCH>::opcode_e::MAX_OPCODE;; |  | ||||||
|                     if(inst_index <instr_descr.size()) |  | ||||||
|                         inst_id = instr_descr[inst_index].op; |  | ||||||
|                     if(is_jump_to_self_enabled(cond) && |  | ||||||
|                         inst_id==arch::traits<ARCH>::opcode_e::JAL && !bit_sub<7, 25>(instr) || |  | ||||||
|                         inst_id == arch::traits<ARCH>::opcode_e::C__J && !bit_sub<2, 11>(instr)) |  | ||||||
|                         throw simulation_stopped(0); |  | ||||||
|                     exec(inst_id, pc.val, instr); |  | ||||||
|                 } |  | ||||||
|             } while(this->core.reg.last_branch==0); |  | ||||||
|         } else { |  | ||||||
|             for(auto& e:current_tb->second.entries) |  | ||||||
|                 exec(std::get<0>(e), std::get<1>(e), std::get<2>(e)); |  | ||||||
|         } |         } | ||||||
|         fetch_count++; |         fetch_count++; | ||||||
|         cycle++; |         cycle++; | ||||||
|   | |||||||
| @@ -34,6 +34,7 @@ | |||||||
|  |  | ||||||
| #include "vector_functions.h" | #include "vector_functions.h" | ||||||
| #include "iss/vm_types.h" | #include "iss/vm_types.h" | ||||||
|  | #include "vm/aes_sbox.h" | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| @@ -98,4 +99,309 @@ vmask_view read_vmask(uint8_t* V, uint16_t VLEN, uint16_t elem_count, uint8_t re | |||||||
|     assert(mask_start + elem_count / 8 <= V + VLEN * RFS / 8); |     assert(mask_start + elem_count / 8 <= V + VLEN * RFS / 8); | ||||||
|     return {mask_start, elem_count}; |     return {mask_start, elem_count}; | ||||||
| } | } | ||||||
|  | uint8_t xt2(uint8_t x) { return (x << 1) ^ (bit_sub<7, 1>(x) ? 27 : 0); } | ||||||
|  |  | ||||||
|  | uint8_t xt3(uint8_t x) { return x ^ xt2(x); } | ||||||
|  |  | ||||||
|  | uint8_t gfmul(uint8_t x, uint8_t y) { | ||||||
|  |     return (bit_sub<0, 1>(y) ? x : 0) ^ (bit_sub<1, 1>(y) ? xt2(x) : 0) ^ (bit_sub<2, 1>(y) ? xt2(xt2(x)) : 0) ^ | ||||||
|  |            (bit_sub<3, 1>(y) ? xt2(xt2(xt2(x))) : 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_mixcolumn_byte_fwd(uint8_t so) { | ||||||
|  |     return ((uint32_t)gfmul(so, 3) << 24) | ((uint32_t)so << 16) | ((uint32_t)so << 8) | gfmul(so, 2); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_mixcolumn_byte_inv(uint8_t so) { | ||||||
|  |     return ((uint32_t)gfmul(so, 11) << 24) | ((uint32_t)gfmul(so, 13) << 16) | ((uint32_t)gfmul(so, 9) << 8) | gfmul(so, 14); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_mixcolumn_fwd(uint32_t x) { | ||||||
|  |     uint8_t s0 = bit_sub<0, 7 - 0 + 1>(x); | ||||||
|  |     uint8_t s1 = bit_sub<8, 15 - 8 + 1>(x); | ||||||
|  |     uint8_t s2 = bit_sub<16, 23 - 16 + 1>(x); | ||||||
|  |     uint8_t s3 = bit_sub<24, 31 - 24 + 1>(x); | ||||||
|  |     uint8_t b0 = xt2(s0) ^ xt3(s1) ^ (s2) ^ (s3); | ||||||
|  |     uint8_t b1 = (s0) ^ xt2(s1) ^ xt3(s2) ^ (s3); | ||||||
|  |     uint8_t b2 = (s0) ^ (s1) ^ xt2(s2) ^ xt3(s3); | ||||||
|  |     uint8_t b3 = xt3(s0) ^ (s1) ^ (s2) ^ xt2(s3); | ||||||
|  |     return ((uint32_t)b3 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b1 << 8) | b0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_mixcolumn_inv(uint32_t x) { | ||||||
|  |     uint8_t s0 = bit_sub<0, 7 - 0 + 1>(x); | ||||||
|  |     uint8_t s1 = bit_sub<8, 15 - 8 + 1>(x); | ||||||
|  |     uint8_t s2 = bit_sub<16, 23 - 16 + 1>(x); | ||||||
|  |     uint8_t s3 = bit_sub<24, 31 - 24 + 1>(x); | ||||||
|  |     uint8_t b0 = gfmul(s0, 14) ^ gfmul(s1, 11) ^ gfmul(s2, 13) ^ gfmul(s3, 9); | ||||||
|  |     uint8_t b1 = gfmul(s0, 9) ^ gfmul(s1, 14) ^ gfmul(s2, 11) ^ gfmul(s3, 13); | ||||||
|  |     uint8_t b2 = gfmul(s0, 13) ^ gfmul(s1, 9) ^ gfmul(s2, 14) ^ gfmul(s3, 11); | ||||||
|  |     uint8_t b3 = gfmul(s0, 11) ^ gfmul(s1, 13) ^ gfmul(s2, 9) ^ gfmul(s3, 14); | ||||||
|  |     return ((uint32_t)b3 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b1 << 8) | b0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_decode_rcon(uint8_t r) { | ||||||
|  |     switch(r) { | ||||||
|  |     case 0: | ||||||
|  |         return 1; | ||||||
|  |     case 1: | ||||||
|  |         return 2; | ||||||
|  |     case 2: | ||||||
|  |         return 4; | ||||||
|  |     case 3: | ||||||
|  |         return 8; | ||||||
|  |     case 4: | ||||||
|  |         return 16; | ||||||
|  |     case 5: | ||||||
|  |         return 32; | ||||||
|  |     case 6: | ||||||
|  |         return 64; | ||||||
|  |     case 7: | ||||||
|  |         return 128; | ||||||
|  |     case 8: | ||||||
|  |         return 27; | ||||||
|  |     case 9: | ||||||
|  |         return 54; | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_subword_fwd(uint32_t x) { | ||||||
|  |     return ((uint32_t)aes_sbox_fwd(bit_sub<24, 31 - 24 + 1>(x)) << 24) | ((uint32_t)aes_sbox_fwd(bit_sub<16, 23 - 16 + 1>(x)) << 16) | | ||||||
|  |            ((uint32_t)aes_sbox_fwd(bit_sub<8, 15 - 8 + 1>(x)) << 8) | aes_sbox_fwd(bit_sub<0, 7 - 0 + 1>(x)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_subword_inv(uint32_t x) { | ||||||
|  |     return ((uint32_t)aes_sbox_inv(bit_sub<24, 31 - 24 + 1>(x)) << 24) | ((uint32_t)aes_sbox_inv(bit_sub<16, 23 - 16 + 1>(x)) << 16) | | ||||||
|  |            ((uint32_t)aes_sbox_inv(bit_sub<8, 15 - 8 + 1>(x)) << 8) | aes_sbox_inv(bit_sub<0, 7 - 0 + 1>(x)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_get_column(__uint128_t state, unsigned c) { | ||||||
|  |     assert(c < 4); | ||||||
|  |     return static_cast<uint32_t>(state >> (32 * c)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | uint64_t aes_apply_fwd_sbox_to_each_byte(uint64_t x) { | ||||||
|  |     return ((uint64_t)aes_sbox_fwd(bit_sub<56, 63 - 56 + 1>(x)) << 56) | ((uint64_t)aes_sbox_fwd(bit_sub<48, 55 - 48 + 1>(x)) << 48) | | ||||||
|  |            ((uint64_t)aes_sbox_fwd(bit_sub<40, 47 - 40 + 1>(x)) << 40) | ((uint64_t)aes_sbox_fwd(bit_sub<32, 39 - 32 + 1>(x)) << 32) | | ||||||
|  |            ((uint64_t)aes_sbox_fwd(bit_sub<24, 31 - 24 + 1>(x)) << 24) | ((uint64_t)aes_sbox_fwd(bit_sub<16, 23 - 16 + 1>(x)) << 16) | | ||||||
|  |            ((uint64_t)aes_sbox_fwd(bit_sub<8, 15 - 8 + 1>(x)) << 8) | aes_sbox_fwd(bit_sub<0, 7 - 0 + 1>(x)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint64_t aes_apply_inv_sbox_to_each_byte(uint64_t x) { | ||||||
|  |     return ((uint64_t)aes_sbox_inv(bit_sub<56, 63 - 56 + 1>(x)) << 56) | ((uint64_t)aes_sbox_inv(bit_sub<48, 55 - 48 + 1>(x)) << 48) | | ||||||
|  |            ((uint64_t)aes_sbox_inv(bit_sub<40, 47 - 40 + 1>(x)) << 40) | ((uint64_t)aes_sbox_inv(bit_sub<32, 39 - 32 + 1>(x)) << 32) | | ||||||
|  |            ((uint64_t)aes_sbox_inv(bit_sub<24, 31 - 24 + 1>(x)) << 24) | ((uint64_t)aes_sbox_inv(bit_sub<16, 23 - 16 + 1>(x)) << 16) | | ||||||
|  |            ((uint64_t)aes_sbox_inv(bit_sub<8, 15 - 8 + 1>(x)) << 8) | aes_sbox_inv(bit_sub<0, 7 - 0 + 1>(x)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint64_t aes_rv64_shiftrows_fwd(uint64_t rs2, uint64_t rs1) { | ||||||
|  |     return ((uint64_t)bit_sub<24, 31 - 24 + 1>(rs1) << 56) | ((uint64_t)bit_sub<48, 55 - 48 + 1>(rs2) << 48) | | ||||||
|  |            ((uint64_t)bit_sub<8, 15 - 8 + 1>(rs2) << 40) | ((uint64_t)bit_sub<32, 39 - 32 + 1>(rs1) << 32) | | ||||||
|  |            ((uint64_t)bit_sub<56, 63 - 56 + 1>(rs2) << 24) | ((uint64_t)bit_sub<16, 23 - 16 + 1>(rs2) << 16) | | ||||||
|  |            ((uint64_t)bit_sub<40, 47 - 40 + 1>(rs1) << 8) | bit_sub<0, 7 - 0 + 1>(rs1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint64_t aes_rv64_shiftrows_inv(uint64_t rs2, uint64_t rs1) { | ||||||
|  |     return ((uint64_t)bit_sub<24, 31 - 24 + 1>(rs2) << 56) | ((uint64_t)bit_sub<48, 55 - 48 + 1>(rs2) << 48) | | ||||||
|  |            ((uint64_t)bit_sub<8, 15 - 8 + 1>(rs1) << 40) | ((uint64_t)bit_sub<32, 39 - 32 + 1>(rs1) << 32) | | ||||||
|  |            ((uint64_t)bit_sub<56, 63 - 56 + 1>(rs1) << 24) | ((uint64_t)bit_sub<16, 23 - 16 + 1>(rs2) << 16) | | ||||||
|  |            ((uint64_t)bit_sub<40, 47 - 40 + 1>(rs2) << 8) | bit_sub<0, 7 - 0 + 1>(rs1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_shift_rows_fwd(uint128_t x) { | ||||||
|  |     uint32_t ic3 = aes_get_column(x, 3); | ||||||
|  |     uint32_t ic2 = aes_get_column(x, 2); | ||||||
|  |     uint32_t ic1 = aes_get_column(x, 1); | ||||||
|  |     uint32_t ic0 = aes_get_column(x, 0); | ||||||
|  |     uint32_t oc0 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic3) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic2) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic1) << 8) | bit_sub<0, 7 - 0 + 1>(ic0); | ||||||
|  |     uint32_t oc1 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic0) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic3) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic2) << 8) | bit_sub<0, 7 - 0 + 1>(ic1); | ||||||
|  |     uint32_t oc2 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic1) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic0) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic3) << 8) | bit_sub<0, 7 - 0 + 1>(ic2); | ||||||
|  |     uint32_t oc3 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic2) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic1) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic0) << 8) | bit_sub<0, 7 - 0 + 1>(ic3); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_shift_rows_inv(uint128_t x) { | ||||||
|  |     uint32_t ic3 = aes_get_column(x, 3); | ||||||
|  |     uint32_t ic2 = aes_get_column(x, 2); | ||||||
|  |     uint32_t ic1 = aes_get_column(x, 1); | ||||||
|  |     uint32_t ic0 = aes_get_column(x, 0); | ||||||
|  |     uint32_t oc0 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic1) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic2) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic3) << 8) | bit_sub<0, 7 - 0 + 1>(ic0); | ||||||
|  |     uint32_t oc1 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic2) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic3) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic0) << 8) | bit_sub<0, 7 - 0 + 1>(ic1); | ||||||
|  |     uint32_t oc2 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic3) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic0) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic1) << 8) | bit_sub<0, 7 - 0 + 1>(ic2); | ||||||
|  |     uint32_t oc3 = ((uint32_t)bit_sub<24, 31 - 24 + 1>(ic0) << 24) | ((uint32_t)bit_sub<16, 23 - 16 + 1>(ic1) << 16) | | ||||||
|  |                    ((uint32_t)bit_sub<8, 15 - 8 + 1>(ic2) << 8) | bit_sub<0, 7 - 0 + 1>(ic3); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_subbytes_fwd(uint128_t x) { | ||||||
|  |     uint32_t oc0 = aes_subword_fwd(aes_get_column(x, 0)); | ||||||
|  |     uint32_t oc1 = aes_subword_fwd(aes_get_column(x, 1)); | ||||||
|  |     uint32_t oc2 = aes_subword_fwd(aes_get_column(x, 2)); | ||||||
|  |     uint32_t oc3 = aes_subword_fwd(aes_get_column(x, 3)); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_subbytes_inv(uint128_t x) { | ||||||
|  |     uint32_t oc0 = aes_subword_inv(aes_get_column(x, 0)); | ||||||
|  |     uint32_t oc1 = aes_subword_inv(aes_get_column(x, 1)); | ||||||
|  |     uint32_t oc2 = aes_subword_inv(aes_get_column(x, 2)); | ||||||
|  |     uint32_t oc3 = aes_subword_inv(aes_get_column(x, 3)); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_mixcolumns_fwd(uint128_t x) { | ||||||
|  |     uint32_t oc0 = aes_mixcolumn_fwd(aes_get_column(x, 0)); | ||||||
|  |     uint32_t oc1 = aes_mixcolumn_fwd(aes_get_column(x, 1)); | ||||||
|  |     uint32_t oc2 = aes_mixcolumn_fwd(aes_get_column(x, 2)); | ||||||
|  |     uint32_t oc3 = aes_mixcolumn_fwd(aes_get_column(x, 3)); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint128_t aes_mixcolumns_inv(uint128_t x) { | ||||||
|  |     uint32_t oc0 = aes_mixcolumn_inv(aes_get_column(x, 0)); | ||||||
|  |     uint32_t oc1 = aes_mixcolumn_inv(aes_get_column(x, 1)); | ||||||
|  |     uint32_t oc2 = aes_mixcolumn_inv(aes_get_column(x, 2)); | ||||||
|  |     uint32_t oc3 = aes_mixcolumn_inv(aes_get_column(x, 3)); | ||||||
|  |     return ((uint128_t)oc3 << 96) | ((uint128_t)oc2 << 64) | ((uint128_t)oc1 << 32) | oc0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint32_t aes_rotword(uint32_t x) { | ||||||
|  |     uint8_t a0 = bit_sub<0, 7 - 0 + 1>(x); | ||||||
|  |     uint8_t a1 = bit_sub<8, 15 - 8 + 1>(x); | ||||||
|  |     uint8_t a2 = bit_sub<16, 23 - 16 + 1>(x); | ||||||
|  |     uint8_t a3 = bit_sub<24, 31 - 24 + 1>(x); | ||||||
|  |     return ((uint32_t)a0 << 24) | ((uint32_t)a3 << 16) | ((uint32_t)a2 << 8) | a1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::function<uint128_t(uint128_t, uint128_t, uint128_t)> get_crypto_funct(unsigned funct6, unsigned vs1) { | ||||||
|  |     switch(funct6) { | ||||||
|  |     case 0b101000: // VAES.VV | ||||||
|  |     case 0b101001: // VAES.VS | ||||||
|  |         switch(vs1) { | ||||||
|  |         case 0b00000: // VAESDM | ||||||
|  |             return [](uint128_t state, uint128_t rkey, uint128_t) { | ||||||
|  |                 uint128_t sr = aes_shift_rows_inv(state); | ||||||
|  |                 uint128_t sb = aes_subbytes_inv(sr); | ||||||
|  |                 uint128_t ark = sb ^ rkey; | ||||||
|  |                 uint128_t mix = aes_mixcolumns_inv(ark); | ||||||
|  |                 return mix; | ||||||
|  |             }; | ||||||
|  |         case 0b00001: // VAESDF | ||||||
|  |             return [](uint128_t state, uint128_t rkey, uint128_t) { | ||||||
|  |                 uint128_t sr = aes_shift_rows_inv(state); | ||||||
|  |                 uint128_t sb = aes_subbytes_inv(sr); | ||||||
|  |                 uint128_t ark = sb ^ rkey; | ||||||
|  |                 return ark; | ||||||
|  |             }; | ||||||
|  |         case 0b00010: // VAESEM | ||||||
|  |             return [](uint128_t state, uint128_t rkey, uint128_t) { | ||||||
|  |                 uint128_t sb = aes_subbytes_fwd(state); | ||||||
|  |                 uint128_t sr = aes_shift_rows_fwd(sb); | ||||||
|  |                 uint128_t mix = aes_mixcolumns_fwd(sr); | ||||||
|  |                 uint128_t ark = mix ^ rkey; | ||||||
|  |                 return ark; | ||||||
|  |             }; | ||||||
|  |         case 0b00011: // VAESEF | ||||||
|  |             return [](uint128_t state, uint128_t rkey, uint128_t) { | ||||||
|  |                 uint128_t sb = aes_subbytes_fwd(state); | ||||||
|  |                 uint128_t sr = aes_shift_rows_fwd(sb); | ||||||
|  |                 uint128_t ark = sr ^ rkey; | ||||||
|  |                 return ark; | ||||||
|  |             }; | ||||||
|  |         case 0b00111: // VAESZ | ||||||
|  |             return [](uint128_t state, uint128_t rkey, uint128_t) { | ||||||
|  |                 uint128_t ark = state ^ rkey; | ||||||
|  |                 return ark; | ||||||
|  |             }; | ||||||
|  |         case 0b10000: // VSM4R | ||||||
|  |             throw new std::runtime_error("Unsupported operation in get_crypto_funct"); | ||||||
|  |         case 0b10001: // VGMUL | ||||||
|  |             return [](uint128_t vd, uint128_t vs2, uint128_t) { | ||||||
|  |                 uint128_t Y = brev8<uint128_t>(vd); | ||||||
|  |                 uint128_t H = brev8<uint128_t>(vs2); | ||||||
|  |                 uint128_t Z = 0; | ||||||
|  |                 for(size_t bit = 0; bit < 128; bit++) { | ||||||
|  |                     if((Y >> bit) & 1) | ||||||
|  |                         Z ^= H; | ||||||
|  |                     bool reduce = (H >> 127) & 1; | ||||||
|  |                     H = H << 1; | ||||||
|  |                     if(reduce) | ||||||
|  |                         H ^= 0x87; | ||||||
|  |                 } | ||||||
|  |                 uint128_t result = brev8<uint128_t>(Z); | ||||||
|  |                 return result; | ||||||
|  |             }; | ||||||
|  |         default: | ||||||
|  |             throw new std::runtime_error("Unsupported operation in get_crypto_funct"); | ||||||
|  |         } | ||||||
|  |     case 0b100000: // VSM3ME | ||||||
|  |     case 0b100001: // VSM4K | ||||||
|  |         throw new std::runtime_error("Unsupported operation in get_crypto_funct"); | ||||||
|  |     case 0b100010: // VAESKF1 | ||||||
|  |         return [](uint128_t vd, uint128_t vs2, uint128_t r) { | ||||||
|  |             auto extract_word = [](const uint128_t& value, int index) -> uint32_t { | ||||||
|  |                 return static_cast<uint32_t>((value >> (32 * index)) & std::numeric_limits<uint32_t>::max()); | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             uint32_t k0 = (vs2 >> 32 * 0) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k1 = (vs2 >> 32 * 1) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k2 = (vs2 >> 32 * 2) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k3 = (vs2 >> 32 * 3) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t w0 = aes_subword_fwd(aes_rotword(k3)) ^ aes_decode_rcon(r) ^ k0; | ||||||
|  |             uint32_t w1 = w0 ^ k1; | ||||||
|  |             uint32_t w2 = w1 ^ k2; | ||||||
|  |             uint32_t w3 = w2 ^ k3; | ||||||
|  |             uint128_t result = (uint128_t(w3) << 96) | (uint128_t(w2) << 64) | (uint128_t(w1) << 32) | (uint128_t(w0)); | ||||||
|  |             return result; | ||||||
|  |         }; | ||||||
|  |     case 0b101010: // VAESKF2 | ||||||
|  |         return [](uint128_t vd, uint128_t vs2, uint128_t r) { | ||||||
|  |             uint32_t k0 = (vs2 >> 32 * 0) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k1 = (vs2 >> 32 * 1) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k2 = (vs2 >> 32 * 2) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t k3 = (vs2 >> 32 * 3) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t rkb0 = (vd >> 32 * 0) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t rkb1 = (vd >> 32 * 1) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t rkb2 = (vd >> 32 * 2) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t rkb3 = (vd >> 32 * 3) & std::numeric_limits<uint32_t>::max(); | ||||||
|  |             uint32_t w0 = r & 1 ? aes_subword_fwd(k3) ^ rkb0 : aes_subword_fwd(aes_rotword(k3)) ^ aes_decode_rcon((r >> 1) - 1) ^ rkb0; | ||||||
|  |             uint32_t w1 = w0 ^ rkb1; | ||||||
|  |             uint32_t w2 = w1 ^ rkb2; | ||||||
|  |             uint32_t w3 = w2 ^ rkb3; | ||||||
|  |             uint128_t result = (uint128_t(w3) << 96) | (uint128_t(w2) << 64) | (uint128_t(w1) << 32) | (uint128_t(w0)); | ||||||
|  |             return result; | ||||||
|  |         }; | ||||||
|  |     case 0b101011: // VSM3C | ||||||
|  |         throw new std::runtime_error("Unsupported operation in get_crypto_funct"); | ||||||
|  |     case 0b101100: // VGHSH | ||||||
|  |         return [](uint128_t Y, uint128_t vs2, uint128_t X) { | ||||||
|  |             auto H = brev8<uint128_t>(vs2); | ||||||
|  |             uint128_t Z = 0; | ||||||
|  |             uint128_t S = brev8<uint128_t>(Y ^ X); | ||||||
|  |             for(size_t bit = 0; bit < 128; bit++) { | ||||||
|  |                 if((S >> bit) & 1) | ||||||
|  |                     Z ^= H; | ||||||
|  |                 bool reduce = (H >> 127) & 1; | ||||||
|  |                 H = H << 1; | ||||||
|  |                 if(reduce) | ||||||
|  |                     H ^= 0x87; | ||||||
|  |             } | ||||||
|  |             uint128_t result = brev8<uint128_t>(Z); | ||||||
|  |             return result; | ||||||
|  |         }; | ||||||
|  |     case 0b101101: // VSHA2MS | ||||||
|  |     case 0b101110: // VSHA2CH | ||||||
|  |     case 0b101111: // VSHA2CL | ||||||
|  |     default: | ||||||
|  |         throw new std::runtime_error("Unknown funct6 in get_crypto_funct"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| } // namespace softvector | } // namespace softvector | ||||||
| @@ -41,6 +41,10 @@ | |||||||
| #include <functional> | #include <functional> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| namespace softvector { | namespace softvector { | ||||||
|  | #ifndef _MSC_VER | ||||||
|  | using int128_t = __int128; | ||||||
|  | using uint128_t = unsigned __int128; | ||||||
|  | #endif | ||||||
| const unsigned RFS = 32; | const unsigned RFS = 32; | ||||||
|  |  | ||||||
| struct vtype_t { | struct vtype_t { | ||||||
| @@ -70,9 +74,14 @@ struct vmask_view { | |||||||
| }; | }; | ||||||
| vmask_view read_vmask(uint8_t* V, uint16_t VLEN, uint16_t elem_count, uint8_t reg_idx = 0); | vmask_view read_vmask(uint8_t* V, uint16_t VLEN, uint16_t elem_count, uint8_t reg_idx = 0); | ||||||
| template <unsigned VLEN> vmask_view read_vmask(uint8_t* V, uint16_t elem_count, uint8_t reg_idx = 0); | template <unsigned VLEN> vmask_view read_vmask(uint8_t* V, uint16_t elem_count, uint8_t reg_idx = 0); | ||||||
|  | std::function<uint128_t(uint128_t, uint128_t, uint128_t)> get_crypto_funct(unsigned funct6, unsigned vs1); | ||||||
|  |  | ||||||
|  | template <typename dest_elem_t, typename src_elem_t = dest_elem_t> dest_elem_t brev(src_elem_t vs2); | ||||||
|  | template <typename dest_elem_t, typename src_elem_t = dest_elem_t> dest_elem_t brev8(src_elem_t vs2); | ||||||
|  |  | ||||||
| bool softvec_read(void* core, uint64_t addr, uint64_t length, uint8_t* data); | bool softvec_read(void* core, uint64_t addr, uint64_t length, uint8_t* data); | ||||||
| bool softvec_write(void* core, uint64_t addr, uint64_t length, uint8_t* data); | bool softvec_write(void* core, uint64_t addr, uint64_t length, uint8_t* data); | ||||||
|  |  | ||||||
| template <unsigned VLEN, typename eew_t> | template <unsigned VLEN, typename eew_t> | ||||||
| uint64_t vector_load_store(void* core, std::function<bool(void*, uint64_t, uint64_t, uint8_t*)> load_store_fn, uint8_t* V, uint64_t vl, | uint64_t vector_load_store(void* core, std::function<bool(void*, uint64_t, uint64_t, uint8_t*)> load_store_fn, uint8_t* V, uint64_t vl, | ||||||
|                            uint64_t vstart, vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1, uint8_t segment_size, int64_t stride = 0, |                            uint64_t vstart, vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1, uint8_t segment_size, int64_t stride = 0, | ||||||
| @@ -167,6 +176,17 @@ void mask_fp_vector_vector_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t | |||||||
| template <unsigned VLEN, typename elem_t> | template <unsigned VLEN, typename elem_t> | ||||||
| void mask_fp_vector_imm_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, | void mask_fp_vector_imm_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, | ||||||
|                            elem_t imm, uint8_t rm); |                            elem_t imm, uint8_t rm); | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_vector_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                           unsigned vs1); | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_scalar_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                           unsigned vs1); | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_imm_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                        uint8_t imm); | ||||||
|  | template <unsigned VLEN, unsigned EGS, typename elem_type_t> | ||||||
|  | void vector_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, unsigned vs1); | ||||||
| } // namespace softvector | } // namespace softvector | ||||||
| #include "vm/vector_functions.hpp" | #include "vm/vector_functions.hpp" | ||||||
| #endif /* _VM_VECTOR_FUNCTIONS_H_ */ | #endif /* _VM_VECTOR_FUNCTIONS_H_ */ | ||||||
|   | |||||||
| @@ -32,6 +32,7 @@ | |||||||
| //       alex@minres.com - initial API and implementation | //       alex@minres.com - initial API and implementation | ||||||
| //////////////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////////////// | ||||||
| #pragma once | #pragma once | ||||||
|  | #include "iss/interp/vm_base.h" | ||||||
| extern "C" { | extern "C" { | ||||||
| #include <softfloat.h> | #include <softfloat.h> | ||||||
| } | } | ||||||
| @@ -55,6 +56,14 @@ extern "C" { | |||||||
| #ifdef __SIZEOF_INT128__ | #ifdef __SIZEOF_INT128__ | ||||||
| template <> struct std::make_signed<__uint128_t> { using type = __int128_t; }; | template <> struct std::make_signed<__uint128_t> { using type = __int128_t; }; | ||||||
| template <> struct std::make_signed<__int128_t> { using type = __int128_t; }; | template <> struct std::make_signed<__int128_t> { using type = __int128_t; }; | ||||||
|  | // helper struct to make calling twice<T> on 128-bit datatypes legal at compile time | ||||||
|  | struct poison128_t { | ||||||
|  |     poison128_t() { throw std::runtime_error("Attempt to use twice<__uint128_t>::type at runtime"); } | ||||||
|  |     poison128_t(const poison128_t&) { throw std::runtime_error("Copy of poison128_t is not allowed"); } | ||||||
|  |     template <typename U> poison128_t(U) { throw std::runtime_error("Conversion to poison128_t is not allowed"); } | ||||||
|  |     operator __uint128_t() const { throw std::runtime_error("Use of poison128_t as __uint128_t is not allowed"); } | ||||||
|  | }; | ||||||
|  | template <> struct std::make_signed<poison128_t> { using type = poison128_t; }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| namespace softvector { | namespace softvector { | ||||||
| @@ -108,6 +117,10 @@ template <> struct twice<uint32_t> { using type = uint64_t; }; | |||||||
| #ifdef __SIZEOF_INT128__ | #ifdef __SIZEOF_INT128__ | ||||||
| template <> struct twice<int64_t> { using type = __int128_t; }; | template <> struct twice<int64_t> { using type = __int128_t; }; | ||||||
| template <> struct twice<uint64_t> { using type = __uint128_t; }; | template <> struct twice<uint64_t> { using type = __uint128_t; }; | ||||||
|  |  | ||||||
|  | template <> struct twice<__uint128_t> { using type = poison128_t; }; | ||||||
|  | template <> struct twice<__int128_t> { using type = poison128_t; }; | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| template <class T> using twice_t = typename twice<T>::type; // for convenience | template <class T> using twice_t = typename twice<T>::type; // for convenience | ||||||
| template <typename TO, typename FROM> constexpr TO sext(FROM val) { | template <typename TO, typename FROM> constexpr TO sext(FROM val) { | ||||||
| @@ -180,6 +193,8 @@ std::function<dest_elem_t(dest_elem_t, src2_elem_t, src1_elem_t)> get_funct(unsi | |||||||
|         switch(funct6) { |         switch(funct6) { | ||||||
|         case 0b000000: // VADD |         case 0b000000: // VADD | ||||||
|             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 + vs1; }; |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 + vs1; }; | ||||||
|  |         case 0b000001: // VANDN | ||||||
|  |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 & ~vs1; }; | ||||||
|         case 0b000010: // VSUB |         case 0b000010: // VSUB | ||||||
|             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 - vs1; }; |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 - vs1; }; | ||||||
|         case 0b000011: // VRSUB |         case 0b000011: // VRSUB | ||||||
| @@ -205,6 +220,22 @@ std::function<dest_elem_t(dest_elem_t, src2_elem_t, src1_elem_t)> get_funct(unsi | |||||||
|                 return static_cast<std::make_signed_t<dest_elem_t>>(static_cast<std::make_signed_t<src2_elem_t>>(vs2) - |                 return static_cast<std::make_signed_t<dest_elem_t>>(static_cast<std::make_signed_t<src2_elem_t>>(vs2) - | ||||||
|                                                                     static_cast<std::make_signed_t<src1_elem_t>>(vs1)); |                                                                     static_cast<std::make_signed_t<src1_elem_t>>(vs1)); | ||||||
|             }; |             }; | ||||||
|  |         case 0b010100: // VROR | ||||||
|  |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|  |                 constexpr dest_elem_t bits = sizeof(src2_elem_t) * 8; | ||||||
|  |                 auto shamt = vs1 & shift_mask<src1_elem_t>(); | ||||||
|  |                 return (vs2 >> shamt) | (vs2 << (bits - shamt)); | ||||||
|  |             }; | ||||||
|  |         case 0b010101: { // VROL | ||||||
|  |             if(funct3 == OPIVI) | ||||||
|  |                 return get_funct<dest_elem_t>(0b010100, funct3); | ||||||
|  |             else | ||||||
|  |                 return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|  |                     constexpr dest_elem_t bits = sizeof(src2_elem_t) * 8; | ||||||
|  |                     auto shamt = vs1 & shift_mask<src1_elem_t>(); | ||||||
|  |                     return (vs2 << shamt) | (vs2 >> (bits - shamt)); | ||||||
|  |                 }; | ||||||
|  |         } | ||||||
|         case 0b100101: // VSLL |         case 0b100101: // VSLL | ||||||
|             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 << (vs1 & shift_mask<src2_elem_t>()); }; |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return vs2 << (vs1 & shift_mask<src2_elem_t>()); }; | ||||||
|         case 0b101000: // VSRL |         case 0b101000: // VSRL | ||||||
| @@ -219,6 +250,10 @@ std::function<dest_elem_t(dest_elem_t, src2_elem_t, src1_elem_t)> get_funct(unsi | |||||||
|             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|                 return static_cast<std::make_signed_t<src2_elem_t>>(vs2) >> (vs1 & shift_mask<src2_elem_t>()); |                 return static_cast<std::make_signed_t<src2_elem_t>>(vs2) >> (vs1 & shift_mask<src2_elem_t>()); | ||||||
|             }; |             }; | ||||||
|  |         case 0b110101: // VWSLL | ||||||
|  |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|  |                 return static_cast<dest_elem_t>(vs2) << (vs1 & (shift_mask<dest_elem_t>())); | ||||||
|  |             }; | ||||||
|         default: |         default: | ||||||
|             throw new std::runtime_error("Unknown funct6 in get_funct"); |             throw new std::runtime_error("Unknown funct6 in get_funct"); | ||||||
|         } |         } | ||||||
| @@ -328,6 +363,24 @@ std::function<dest_elem_t(dest_elem_t, src2_elem_t, src1_elem_t)> get_funct(unsi | |||||||
|             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|                 return sext<dest_elem_t>(vs1) * static_cast<dest_elem_t>(vs2) + vd; |                 return sext<dest_elem_t>(vs1) * static_cast<dest_elem_t>(vs2) + vd; | ||||||
|             }; |             }; | ||||||
|  |         case 0b001100: // VCLMUL | ||||||
|  |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|  |                 dest_elem_t output = 0; | ||||||
|  |                 for(size_t i = 0; i <= sizeof(dest_elem_t) * 8 - 1; i++) { | ||||||
|  |                     if((vs2 >> i) & 1) | ||||||
|  |                         output = output ^ (vs1 << i); | ||||||
|  |                 } | ||||||
|  |                 return output; | ||||||
|  |             }; | ||||||
|  |         case 0b001101: // VCLMULH | ||||||
|  |             return [](dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { | ||||||
|  |                 dest_elem_t output = 0; | ||||||
|  |                 for(size_t i = 1; i < sizeof(dest_elem_t) * 8; i++) { | ||||||
|  |                     if((vs2 >> i) & 1) | ||||||
|  |                         output = output ^ (vs1 >> (sizeof(dest_elem_t) * 8 - i)); | ||||||
|  |                 } | ||||||
|  |                 return output; | ||||||
|  |             }; | ||||||
|         default: |         default: | ||||||
|             throw new std::runtime_error("Unknown funct6 in get_funct"); |             throw new std::runtime_error("Unknown funct6 in get_funct"); | ||||||
|         } |         } | ||||||
| @@ -364,11 +417,10 @@ void vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, ui | |||||||
|     auto fn = get_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); |     auto fn = get_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); | ||||||
|     for(size_t idx = vstart; idx < vl; idx++) { |     for(size_t idx = vstart; idx < vl; idx++) { | ||||||
|         bool mask_active = vm ? 1 : mask_reg[idx]; |         bool mask_active = vm ? 1 : mask_reg[idx]; | ||||||
|         if(mask_active) { |         if(mask_active) | ||||||
|             vd_view[idx] = fn(vd_view[idx], vs2_view[idx], imm); |             vd_view[idx] = fn(vd_view[idx], vs2_view[idx], imm); | ||||||
|         } else { |         else if(vtype.vma()) | ||||||
|             vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if(vtype.vta()) |     if(vtype.vta()) | ||||||
|         for(size_t idx = vl; idx < vlmax; idx++) |         for(size_t idx = vl; idx < vlmax; idx++) | ||||||
| @@ -535,6 +587,79 @@ std::function<dest_elem_t(src2_elem_t)> get_unary_fn(unsigned unary_op) { | |||||||
|     case 0b00100: // VZEXT.VF4 |     case 0b00100: // VZEXT.VF4 | ||||||
|     case 0b00010: // VZEXT.VF8 |     case 0b00010: // VZEXT.VF8 | ||||||
|         return [](src2_elem_t vs2) { return vs2; }; |         return [](src2_elem_t vs2) { return vs2; }; | ||||||
|  |     case 0b01000: // VBREV8 | ||||||
|  |         return [](src2_elem_t vs2) { return brev8<dest_elem_t>(vs2); }; | ||||||
|  |     case 0b01001: // VREV8 | ||||||
|  |         return [](src2_elem_t vs2) { | ||||||
|  |             constexpr unsigned byte_count = sizeof(src2_elem_t); | ||||||
|  |             dest_elem_t result = 0; | ||||||
|  |             for(size_t i = 0; i < byte_count; ++i) { | ||||||
|  |                 result <<= 8; | ||||||
|  |                 result |= (vs2 & 0xFF); | ||||||
|  |                 vs2 >>= 8; | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         }; | ||||||
|  |     case 0b01010: // VBREV | ||||||
|  |         return [](src2_elem_t vs2) { return brev<dest_elem_t>(vs2); }; | ||||||
|  |     case 0b01100: // VCLZ | ||||||
|  |         return [](src2_elem_t vs2) { | ||||||
|  |             if(std::is_same_v<src2_elem_t, unsigned int>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_clz(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_clzl(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_clzll(vs2)); | ||||||
|  |             else { | ||||||
|  |                 constexpr dest_elem_t bits = sizeof(src2_elem_t) * 8; | ||||||
|  |                 if(vs2 == 0) | ||||||
|  |                     return bits; | ||||||
|  |                 dest_elem_t count = 0; | ||||||
|  |                 for(size_t i = bits - 1; i >= 0; --i) { | ||||||
|  |                     if((vs2 >> i) & 1) | ||||||
|  |                         break; | ||||||
|  |                     ++count; | ||||||
|  |                 } | ||||||
|  |                 return count; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     case 0b01101: // VCTZ | ||||||
|  |         return [](src2_elem_t vs2) { | ||||||
|  |             if(std::is_same_v<src2_elem_t, unsigned int>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_ctz(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_ctzl(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_ctzll(vs2)); | ||||||
|  |             else { | ||||||
|  |                 constexpr dest_elem_t bits = sizeof(src2_elem_t) * 8; | ||||||
|  |                 if(vs2 == 0) | ||||||
|  |                     return bits; | ||||||
|  |                 dest_elem_t count = 0; | ||||||
|  |                 while((vs2 & 1) == 0) { | ||||||
|  |                     ++count; | ||||||
|  |                     vs2 >>= 1; | ||||||
|  |                 } | ||||||
|  |                 return count; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |     case 0b01110: // VCPOP | ||||||
|  |         return [](src2_elem_t vs2) { | ||||||
|  |             if(std::is_same_v<src2_elem_t, unsigned int>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_popcount(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_popcountl(vs2)); | ||||||
|  |             else if(std::is_same_v<src2_elem_t, unsigned long long>) | ||||||
|  |                 return static_cast<dest_elem_t>(__builtin_popcountll(vs2)); | ||||||
|  |             else { | ||||||
|  |                 dest_elem_t count = 0; | ||||||
|  |                 while(vs2) { | ||||||
|  |                     count += vs2 & 1; | ||||||
|  |                     vs2 >>= 1; | ||||||
|  |                 } | ||||||
|  |                 return count; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|     default: |     default: | ||||||
|         throw new std::runtime_error("Unknown funct in get_unary_fn"); |         throw new std::runtime_error("Unknown funct in get_unary_fn"); | ||||||
|     } |     } | ||||||
| @@ -550,8 +675,8 @@ void vector_unary_op(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart | |||||||
|         bool mask_active = vm ? 1 : mask_reg[idx]; |         bool mask_active = vm ? 1 : mask_reg[idx]; | ||||||
|         if(mask_active) |         if(mask_active) | ||||||
|             vd_view[idx] = fn(vs2_view[idx]); |             vd_view[idx] = fn(vs2_view[idx]); | ||||||
|         else |         else if(vtype.vma()) | ||||||
|             vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|     } |     } | ||||||
|     if(vtype.vta()) |     if(vtype.vta()) | ||||||
|         for(size_t idx = vl; idx < vlmax; idx++) |         for(size_t idx = vl; idx < vlmax; idx++) | ||||||
| @@ -774,11 +899,10 @@ bool sat_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t | |||||||
|     auto fn = get_sat_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); |     auto fn = get_sat_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); | ||||||
|     for(size_t idx = vstart; idx < vl; idx++) { |     for(size_t idx = vstart; idx < vl; idx++) { | ||||||
|         bool mask_active = vm ? 1 : mask_reg[idx]; |         bool mask_active = vm ? 1 : mask_reg[idx]; | ||||||
|         if(mask_active) { |         if(mask_active) | ||||||
|             saturated |= fn(vxrm, vtype, vd_view[idx], vs2_view[idx], vs1_view[idx]); |             saturated |= fn(vxrm, vtype, vd_view[idx], vs2_view[idx], vs1_view[idx]); | ||||||
|         } else { |         else if(vtype.vma()) | ||||||
|             vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if(vtype.vta()) |     if(vtype.vta()) | ||||||
|         for(size_t idx = vl; idx < vlmax; idx++) { |         for(size_t idx = vl; idx < vlmax; idx++) { | ||||||
| @@ -797,11 +921,10 @@ bool sat_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl | |||||||
|     auto fn = get_sat_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); |     auto fn = get_sat_funct<dest_elem_t, src2_elem_t, src1_elem_t>(funct6, funct3); | ||||||
|     for(size_t idx = vstart; idx < vl; idx++) { |     for(size_t idx = vstart; idx < vl; idx++) { | ||||||
|         bool mask_active = vm ? 1 : mask_reg[idx]; |         bool mask_active = vm ? 1 : mask_reg[idx]; | ||||||
|         if(mask_active) { |         if(mask_active) | ||||||
|             saturated |= fn(vxrm, vtype, vd_view[idx], vs2_view[idx], imm); |             saturated |= fn(vxrm, vtype, vd_view[idx], vs2_view[idx], imm); | ||||||
|         } else { |         else if(vtype.vma()) | ||||||
|             vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     if(vtype.vta()) |     if(vtype.vta()) | ||||||
|         for(size_t idx = vl; idx < vlmax; idx++) { |         for(size_t idx = vl; idx < vlmax; idx++) { | ||||||
| @@ -1939,4 +2062,221 @@ template <unsigned VLEN> void vector_whole_move(uint8_t* V, unsigned vd, unsigne | |||||||
|     memcpy(vd_view.start, vs2_view.start, VLEN / 8 * count); |     memcpy(vd_view.start, vs2_view.start, VLEN / 8 * count); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_vector_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                           unsigned vs1) { | ||||||
|  |     uint64_t vlmax = VLEN * vtype.lmul() / (vtype.sew() * EGS); | ||||||
|  |     auto vs1_view = get_vreg<VLEN, uint128_t>(V, vs1, vlmax); | ||||||
|  |     auto vs2_view = get_vreg<VLEN, uint128_t>(V, vs2, vlmax); | ||||||
|  |     auto vd_view = get_vreg<VLEN, uint128_t>(V, vd, vlmax); | ||||||
|  |     auto fn = get_crypto_funct(funct6, vs1); | ||||||
|  |     for(size_t idx = eg_start; idx < eg_len; idx++) { | ||||||
|  |         vd_view[idx] = fn(vd_view[idx], vs2_view[idx], vs1_view[idx]); | ||||||
|  |     } | ||||||
|  |     if(vtype.vta()) | ||||||
|  |         for(size_t idx = eg_len; idx < vlmax; idx++) | ||||||
|  |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|  | } | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_scalar_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                           unsigned vs1) { | ||||||
|  |     uint64_t vlmax = VLEN * vtype.lmul() / (vtype.sew() * EGS); | ||||||
|  |     auto vs2_val = get_vreg<VLEN, uint128_t>(V, vs2, vlmax)[0]; | ||||||
|  |     auto vd_view = get_vreg<VLEN, uint128_t>(V, vd, vlmax); | ||||||
|  |     auto fn = get_crypto_funct(funct6, vs1); | ||||||
|  |     for(size_t idx = eg_start; idx < eg_len; idx++) { | ||||||
|  |         vd_view[idx] = fn(vd_view[idx], vs2_val, -1); | ||||||
|  |     } | ||||||
|  |     if(vtype.vta()) | ||||||
|  |         for(size_t idx = eg_len; idx < vlmax; idx++) | ||||||
|  |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <unsigned VLEN, unsigned EGS> | ||||||
|  | void vector_imm_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                        uint8_t imm) { | ||||||
|  |     uint64_t vlmax = VLEN * vtype.lmul() / (vtype.sew() * EGS); | ||||||
|  |     auto vs2_view = get_vreg<VLEN, uint128_t>(V, vs2, vlmax); | ||||||
|  |     auto vd_view = get_vreg<VLEN, uint128_t>(V, vd, vlmax); | ||||||
|  |     auto fn = get_crypto_funct(funct6, -1); | ||||||
|  |     for(size_t idx = eg_start; idx < eg_len; idx++) { | ||||||
|  |         vd_view[idx] = fn(vd_view[idx], vs2_view[idx], imm); | ||||||
|  |     } | ||||||
|  |     if(vtype.vta()) | ||||||
|  |         for(size_t idx = eg_len; idx < vlmax; idx++) | ||||||
|  |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|  | } | ||||||
|  | template <typename T> T rotr(T x, unsigned n) { | ||||||
|  |     assert(n < sizeof(T) * 8); | ||||||
|  |     return (x >> n) | (x << (sizeof(T) * 8 - n)); | ||||||
|  | } | ||||||
|  | template <typename T> T shr(T x, unsigned n) { | ||||||
|  |     assert(n < sizeof(T) * 8); | ||||||
|  |     return (x >> n); | ||||||
|  | } | ||||||
|  | template <typename T> T sum0(T); | ||||||
|  | template <> inline uint32_t sum0(uint32_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); } | ||||||
|  | template <> inline uint64_t sum0(uint64_t x) { return rotr(x, 28) ^ rotr(x, 34) ^ rotr(x, 39); } | ||||||
|  | template <typename T> T sum1(T); | ||||||
|  | template <> inline uint32_t sum1(uint32_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); } | ||||||
|  | template <> inline uint64_t sum1(uint64_t x) { return rotr(x, 14) ^ rotr(x, 18) ^ rotr(x, 41); } | ||||||
|  | template <typename T> T ch(T x, T y, T z) { return ((x & y) ^ ((~x) & z)); } | ||||||
|  | template <typename T> T maj(T x, T y, T z) { return ((x & y) ^ (x & z) ^ (y & z)); } | ||||||
|  | template <typename T> T sig0(T); | ||||||
|  | template <> inline uint32_t sig0(uint32_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); } | ||||||
|  | template <> inline uint64_t sig0(uint64_t x) { return rotr(x, 1) ^ rotr(x, 8) ^ shr(x, 7); } | ||||||
|  | template <typename T> T sig1(T); | ||||||
|  | template <> inline uint32_t sig1(uint32_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); } | ||||||
|  | template <> inline uint64_t sig1(uint64_t x) { return rotr(x, 19) ^ rotr(x, 61) ^ shr(x, 6); } | ||||||
|  | template <typename T> std::function<void(vreg_view<T>&, vreg_view<T>&, vreg_view<T>&)> get_crypto_funct(unsigned int funct6) { | ||||||
|  |     switch(funct6) { | ||||||
|  |     case 0b101110: // VSHA2CH | ||||||
|  |         return [](vreg_view<T>& vd_view, vreg_view<T>& vs2_view, vreg_view<T>& vs1_view) { | ||||||
|  |             T a = vs2_view[3]; | ||||||
|  |             T b = vs2_view[2]; | ||||||
|  |             T c = vd_view[3]; | ||||||
|  |             T d = vd_view[2]; | ||||||
|  |             T e = vs2_view[1]; | ||||||
|  |             T f = vs2_view[0]; | ||||||
|  |             T g = vd_view[1]; | ||||||
|  |             T h = vd_view[0]; | ||||||
|  |             T W0 = vs1_view[2]; | ||||||
|  |             T W1 = vs1_view[3]; | ||||||
|  |             T T1 = h + sum1(e) + ch(e, f, g) + W0; | ||||||
|  |             T T2 = sum0(a) + maj(a, b, c); | ||||||
|  |             h = g; | ||||||
|  |             g = f; | ||||||
|  |             f = e; | ||||||
|  |             e = d + T1; | ||||||
|  |             d = c; | ||||||
|  |             c = b; | ||||||
|  |             b = a; | ||||||
|  |             a = T1 + T2; | ||||||
|  |             T1 = h + sum1(e) + ch(e, f, g) + W1; | ||||||
|  |             T2 = sum0(a) + maj(a, b, c); | ||||||
|  |             h = g; | ||||||
|  |             g = f; | ||||||
|  |             f = e; | ||||||
|  |             e = d + T1; | ||||||
|  |             d = c; | ||||||
|  |             c = b; | ||||||
|  |             b = a; | ||||||
|  |             a = T1 + T2; | ||||||
|  |             vd_view[0] = f; | ||||||
|  |             vd_view[1] = e; | ||||||
|  |             vd_view[2] = b; | ||||||
|  |             vd_view[3] = a; | ||||||
|  |         }; | ||||||
|  |     case 0b101111: // VSHA2CL | ||||||
|  |         return [](vreg_view<T>& vd_view, vreg_view<T>& vs2_view, vreg_view<T>& vs1_view) { | ||||||
|  |             T a = vs2_view[3]; | ||||||
|  |             T b = vs2_view[2]; | ||||||
|  |             T c = vd_view[3]; | ||||||
|  |             T d = vd_view[2]; | ||||||
|  |             T e = vs2_view[1]; | ||||||
|  |             T f = vs2_view[0]; | ||||||
|  |             T g = vd_view[1]; | ||||||
|  |             T h = vd_view[0]; | ||||||
|  |             T W0 = vs1_view[0]; | ||||||
|  |             T W1 = vs1_view[1]; | ||||||
|  |             T T1 = h + sum1(e) + ch(e, f, g) + W0; | ||||||
|  |             T T2 = sum0(a) + maj(a, b, c); | ||||||
|  |             h = g; | ||||||
|  |             g = f; | ||||||
|  |             f = e; | ||||||
|  |             e = d + T1; | ||||||
|  |             d = c; | ||||||
|  |             c = b; | ||||||
|  |             b = a; | ||||||
|  |             a = T1 + T2; | ||||||
|  |             T1 = h + sum1(e) + ch(e, f, g) + W1; | ||||||
|  |             T2 = sum0(a) + maj(a, b, c); | ||||||
|  |             h = g; | ||||||
|  |             g = f; | ||||||
|  |             f = e; | ||||||
|  |             e = d + T1; | ||||||
|  |             d = c; | ||||||
|  |             c = b; | ||||||
|  |             b = a; | ||||||
|  |             a = T1 + T2; | ||||||
|  |             vd_view[0] = f; | ||||||
|  |             vd_view[1] = e; | ||||||
|  |             vd_view[2] = b; | ||||||
|  |             vd_view[3] = a; | ||||||
|  |         }; | ||||||
|  |     case 0b101101: // VSHA2MS | ||||||
|  |         return [](vreg_view<T>& vd_view, vreg_view<T>& vs2_view, vreg_view<T>& vs1_view) { | ||||||
|  |             T W0 = vd_view[0]; | ||||||
|  |             T W1 = vd_view[1]; | ||||||
|  |             T W2 = vd_view[2]; | ||||||
|  |             T W3 = vd_view[3]; | ||||||
|  |  | ||||||
|  |             T W4 = vs2_view[0]; | ||||||
|  |             T W9 = vs2_view[1]; | ||||||
|  |             T W10 = vs2_view[2]; | ||||||
|  |             T W11 = vs2_view[3]; | ||||||
|  |  | ||||||
|  |             T W12 = vs1_view[0]; | ||||||
|  |             T W13 = vs1_view[1]; | ||||||
|  |             T W14 = vs1_view[2]; | ||||||
|  |             T W15 = vs1_view[3]; | ||||||
|  |  | ||||||
|  |             T W16 = sig1(W14) + W9 + sig0(W1) + W0; | ||||||
|  |             T W17 = sig1(W15) + W10 + sig0(W2) + W1; | ||||||
|  |             T W18 = sig1(W16) + W11 + sig0(W3) + W2; | ||||||
|  |             T W19 = sig1(W17) + W12 + sig0(W4) + W3; | ||||||
|  |  | ||||||
|  |             vd_view[0] = W16; | ||||||
|  |             vd_view[1] = W17; | ||||||
|  |             vd_view[2] = W18; | ||||||
|  |             vd_view[3] = W19; | ||||||
|  |         }; | ||||||
|  |     default: | ||||||
|  |         throw new std::runtime_error("Unsupported operation in get_crypto_funct"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | template <unsigned VLEN, unsigned EGS, typename elem_type_t> | ||||||
|  | void vector_crypto(uint8_t* V, unsigned funct6, uint64_t eg_len, uint64_t eg_start, vtype_t vtype, unsigned vd, unsigned vs2, | ||||||
|  |                    unsigned vs1) { | ||||||
|  |     auto fn = get_crypto_funct<elem_type_t>(funct6); | ||||||
|  |     auto vd_view = get_vreg<VLEN, elem_type_t>(V, vd, EGS); | ||||||
|  |     auto vs2_view = get_vreg<VLEN, elem_type_t>(V, vs2, EGS); | ||||||
|  |     auto vs1_view = get_vreg<VLEN, elem_type_t>(V, vs1, EGS); | ||||||
|  |     for(size_t idx = eg_start; idx < eg_len; idx++) { | ||||||
|  |         fn(vd_view, vs2_view, vs1_view); | ||||||
|  |         // We cannot use views in case EGW < VLEN, as views can only address the start of a register | ||||||
|  |         vd_view.start += EGS * sizeof(elem_type_t); | ||||||
|  |         vs2_view.start += EGS * sizeof(elem_type_t); | ||||||
|  |         vs1_view.start += EGS * sizeof(elem_type_t); | ||||||
|  |     } | ||||||
|  |     if(vtype.vta()) { | ||||||
|  |         uint64_t vlmax = VLEN * vtype.lmul() / (vtype.sew()); | ||||||
|  |         auto vd_view = get_vreg<VLEN, elem_type_t>(V, vd, vlmax); | ||||||
|  |         for(size_t idx = eg_len * EGS; idx < vlmax; idx++) | ||||||
|  |             vd_view[idx] = agnostic_behavior(vd_view[idx]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename dest_elem_t, typename src_elem_t> dest_elem_t brev(src_elem_t vs2) { | ||||||
|  |     constexpr dest_elem_t bits = sizeof(src_elem_t) * 8; | ||||||
|  |     dest_elem_t result = 0; | ||||||
|  |     for(size_t i = 0; i < bits; ++i) { | ||||||
|  |         result <<= 1; | ||||||
|  |         result |= (vs2 & 1); | ||||||
|  |         vs2 >>= 1; | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | }; | ||||||
|  | template <typename dest_elem_t, typename src_elem_t> dest_elem_t brev8(src_elem_t vs2) { | ||||||
|  |     constexpr unsigned byte_count = sizeof(src_elem_t); | ||||||
|  |     dest_elem_t result = 0; | ||||||
|  |     for(size_t i = 0; i < byte_count; ++i) { | ||||||
|  |         dest_elem_t byte = (vs2 >> (i * 8)) & 0xFF; | ||||||
|  |         byte = ((byte & 0xF0) >> 4) | ((byte & 0x0F) << 4); | ||||||
|  |         byte = ((byte & 0xCC) >> 2) | ((byte & 0x33) << 2); | ||||||
|  |         byte = ((byte & 0xAA) >> 1) | ((byte & 0x55) << 1); | ||||||
|  |         result |= byte << (i * 8); | ||||||
|  |     } | ||||||
|  |     return result; | ||||||
|  | }; | ||||||
| } // namespace softvector | } // namespace softvector | ||||||
		Reference in New Issue
	
	Block a user