72 Commits

Author SHA1 Message Date
8f5d666b7d corrects mistake from rebasing, adds newly generated templates 2025-03-31 12:50:05 +02:00
cc123939ce configures logger in main 2025-03-31 10:19:16 +02:00
a2e5405e25 small changes regarding vector template 2025-03-31 10:19:16 +02:00
cd3ec0b79d removes conversion functions in favor of more explicit conversions 2025-03-31 10:19:16 +02:00
0e35a2a8c9 adds complete Zfh support, small rework regarding floating point interface 2025-03-31 10:19:16 +02:00
8220c00a3d small correction for floating point h 2025-03-31 10:19:16 +02:00
ec5fb1e87e increases verbosity for file loading errors 2025-03-31 10:19:16 +02:00
453407568c removes carry_t, moves functionality to own functions 2025-03-31 10:19:16 +02:00
0fe9e6ebc8 corrects error for narrowing fp dispatch 2025-03-31 10:19:16 +02:00
484d9dbe08 removes rounding mode lookup as it is not needes 2025-03-31 10:19:15 +02:00
7a7035f267 adds support for half precision float 2025-03-31 10:19:15 +02:00
d9f1e5d31b small refactor 2025-03-31 10:19:15 +02:00
7b35f45a48 changes to make correct oversighst for XLEN=64 in Vector functions 2025-03-31 10:19:15 +02:00
ece6f7290f small bugfixes, adds some half point functionality 2025-03-31 10:19:15 +02:00
2166a6d81e makes widenning function types more explicit 2025-03-31 10:19:15 +02:00
fe9f2a5455 corrects vectorslide, changes all loop index type 2025-03-31 10:19:15 +02:00
42bf6ee380 corrects errors w.r.t. floating point dispatch 2025-03-31 10:19:15 +02:00
f0b582df6c corrects ambiguity in frsqrt 2025-03-31 10:19:15 +02:00
6fcb3dbb66 adds missing floating point instructions 2025-03-31 10:19:15 +02:00
c01eb39a76 reworks merge instrs, adds fp comparisons 2025-03-31 10:19:15 +02:00
08280a094f allows assigning to mask_view elements 2025-03-31 10:19:15 +02:00
ae90adc854 adds most fp functions 2025-03-31 10:19:15 +02:00
cd358198ad expands floating point functions 2025-03-31 10:19:14 +02:00
8746003d3e adds floating point reduction instrs, widening are untested 2025-03-31 10:19:14 +02:00
60d2b45a81 adds floating point Permutation Instructions 2025-03-31 10:19:14 +02:00
0264c5d66f small cleanup 2025-03-31 10:19:14 +02:00
528c2536af removes unused declarations 2025-03-31 10:19:14 +02:00
19e38ec898 corrects bug 2025-03-31 10:19:14 +02:00
fd11ce18c4 changes order of arguments to reflect assembly 2025-03-31 10:19:14 +02:00
9b7a9fa273 updates indexed load to use vreg_views 2025-03-31 10:19:14 +02:00
e24c1874c4 Changes load_store to use vreg_views aswell 2025-03-31 10:19:14 +02:00
221d2ee38c adds whole register moves 2025-03-31 10:19:14 +02:00
877cad27ba adds gather instructions 2025-03-31 10:19:14 +02:00
a26505cb5c adds more functions, up to slide 2025-03-31 10:19:13 +02:00
c1277b6528 adds mask_mask logical instructions 2025-03-31 10:19:13 +02:00
63889b02e7 adds widening reductions 2025-03-31 10:19:13 +02:00
f049d8cbb3 adds Integer Reduction Instructions 2025-03-31 10:19:13 +02:00
28ac169cfe adds narrowing fixed point instructions 2025-03-31 10:19:13 +02:00
a6f24db83a adds vssrl and vssra 2025-03-31 10:19:13 +02:00
e1911bc450 adds vsmul, widens functions parameters for sat_vector operations 2025-03-31 10:19:13 +02:00
75d96bf18d small cleanup, adds first fixed point instrs 2025-03-31 10:19:13 +02:00
e59458aa0e adds the missing vector csrs to the architectural state 2025-03-31 10:18:51 +02:00
77807fec01 adds merge and move instructions 2025-03-31 10:18:10 +02:00
6852d1d299 adds Vector Widening Integer Multiply-Add Instructions 2025-03-31 10:18:10 +02:00
ac1322d66b changes to ternary functions for Multiply-Add Instructions 2025-03-31 10:18:10 +02:00
9ba9d2432c adds Vector Widening Integer Multiply Instructions 2025-03-31 10:18:10 +02:00
c9b7962cd3 adds Vector Integer Divide Instructions 2025-03-31 10:18:10 +02:00
ab31fd27c9 adds single width integer instructins, also small cleanup 2025-03-31 10:18:10 +02:00
b3f189145f adds funct3 to vector functions 2025-03-31 10:18:10 +02:00
dd4416ab15 adds min/max instructions 2025-03-31 10:18:10 +02:00
0027946f90 renames mask operations to distinguish from vector integer compare instructions 2025-03-31 10:18:09 +02:00
feaff8c4a5 adds support for narrowing shifts 2025-03-31 10:18:09 +02:00
af3e76cc98 adds integer extension and add/substract with carry vector instructions 2025-03-31 10:18:09 +02:00
b1ceac2c2a small correction for vector_functions 2025-03-31 10:18:09 +02:00
b5862039e7 changes order of operands to more closely resemble assembly 2025-03-31 10:18:09 +02:00
51f3802394 adds vector_imm instructions to vector_functions, makes size of all involved registers a template parameter 2025-03-31 10:18:09 +02:00
6ce0d97e81 general improvements to vector_functions, adds functions to process arithmetic instructions (working add) 2025-03-31 10:18:09 +02:00
69c8fda5d2 corrects oversight in vector_functions 2025-03-31 10:18:09 +02:00
c1f9328528 corrects vector_functions 2025-03-31 10:18:09 +02:00
2b85748279 adds load_store_index to vector_functions 2025-03-31 10:18:09 +02:00
f7aa51b12e adds small optimization, clarifies variables in vector_functions 2025-03-31 10:18:09 +02:00
3428745a00 small corrections in vector functions 2025-03-31 10:18:09 +02:00
512b79a3e7 makes elem_count an explicit parameter for the softvector functions rather than calculating it from vtype 2025-03-31 10:18:08 +02:00
7a048f8b93 changes wording of returned index to better reflect what it means, cleans up a bit 2025-03-31 10:18:08 +02:00
6f4daf91ed adds explicit RFS to assertions 2025-03-31 10:18:08 +02:00
947d353bbf adds working vector (unit) stride (segmented) loads and stores 2025-03-31 10:18:08 +02:00
b95f518c91 updates templates for interp to make extension specific includes conditonal 2025-03-31 10:18:08 +02:00
4cef0f57c1 updates templates and adds newly generated files 2025-03-31 10:18:05 +02:00
28af695592 adds vector support to m and mu priv wrapper 2025-03-31 10:16:01 +02:00
f6cdd9d07c adds vector csr to riscv_common 2025-03-31 09:54:26 +02:00
9e390971d4 corrects include guard comment for fp_functions 2025-03-31 09:54:26 +02:00
2bb2e56310 adds dependencies for K ISA (Cryptography) 2025-03-31 09:54:26 +02:00
16 changed files with 4197 additions and 324 deletions

View File

@@ -21,6 +21,7 @@ set(LIB_SOURCES
src/iss/mem/memory_if.cpp
src/vm/interp/vm_tgc5c.cpp
src/vm/fp_functions.cpp
src/vm/vector_functions.cpp
src/iss/debugger/csr_names.cpp
src/iss/semihosting/semihosting.cpp
)

View File

@@ -20,7 +20,7 @@ RVI:
mask: 0b00000000000000000000000001111111
size: 32
branch: true
delay: 1
delay: [1,1]
JALR:
index: 3
encoding: 0b00000000000000000000000001100111

View File

@@ -30,11 +30,21 @@
*
*******************************************************************************/
<%
def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
def nativeSize(int size){
if(size<=8) return 8;
if(size<=16) return 16;
if(size<=32) return 32;
if(size<=64) return 64;
if(size<=128) return 128;
if(size<=256) return 256;
if(size<=512) return 512;
if(size<=1024) return 1024;
if(size<=2048) return 2048;
if(size<=4096) return 4096;
throw new IllegalArgumentException("Unsupported size in nativeSize in CORENAME.h.gtl");
}
def getRegisterSizes(){
def regs = registers.collect{nativeTypeSize(it.size)}
def regs = registers.collect{nativeSize(it.size)}
regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
return regs
}
@@ -47,13 +57,7 @@ def getRegisterOffsets(){
}
return offsets
}
def byteSize(int size){
if(size<=8) return 8;
if(size<=16) return 16;
if(size<=32) return 32;
if(size<=64) return 64;
return 128;
}
def getCString(def val){
return val.toString()+'ULL'
}
@@ -84,6 +88,8 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
constexpr static unsigned V_REGS_SIZE = ${constants.find {it.name=='VLEN'}?.value?:0};
enum reg_e {
${registers.collect{it.name}.join(', ')}, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
@@ -142,8 +148,10 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
#pragma pack(push, 1)
struct ${coreDef.name}_regs {<%
registers.each { reg -> if(reg.size>0) {%>
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
registers.each { reg -> if(reg.size>64) {%>
uint8_t ${reg.name}[${reg.size/8}] = {0};<%
}else if(reg.size>0) {%>
uint${nativeSize(reg.size)}_t ${reg.name} = 0;<%
}}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0; // counts number of instructions undisturbed
@@ -164,6 +172,31 @@ if(fcsr != null) {%>
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}
def vstart = registers.find {it.name=='vstart'}
def vl = registers.find {it.name=='vl'}
def vtype = registers.find {it.name=='vtype'}
def vxsat = registers.find {it.name=='vxsat'}
def vxrm = registers.find {it.name=='vxrm'}
if(vtype != null) {%>
uint${vstart.size}_t get_vstart(){return reg.vstart;}
void set_vstart(uint${vstart.size}_t val){reg.vstart = val;}
uint${vl.size}_t get_vl(){return reg.vl;}
uint${vtype.size}_t get_vtype(){return reg.vtype;}
uint${vxsat.size}_t get_vxsat(){return reg.vxsat;}
void set_vxsat(uint${vxsat.size}_t val){reg.vxsat = val;}
uint${vxrm.size}_t get_vxrm(){return reg.vxrm;}
void set_vxrm(uint${vxrm.size}_t val){reg.vxrm = val;}
<%} else { %>
uint32_t get_vstart(){return 0;}
void set_vstart(uint32_t val){}
uint32_t get_vl(){return 0;}
uint32_t get_vtype(){return 0;}
uint32_t get_vxsat(){return 0;}
void set_vxsat(uint32_t val){}
uint32_t get_vxrm(){return 0;}
void set_vxrm(uint32_t val){}
<%}%>
};

View File

@@ -30,6 +30,9 @@
*
*******************************************************************************/
<%
def floating_point = registers.find {it.name=='FCSR'}
def vector = registers.find {it.name=='vtype'}
def aes = functions.find { it.contains('aes') }
def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
}
@@ -41,7 +44,16 @@ def nativeTypeSize(int size){
#include <iss/debugger/server.h>
#include <iss/iss.h>
#include <iss/interp/vm_base.h>
<%
if(floating_point != null) {%>
#include <vm/fp_functions.h>
<%}
if(vector != null) {%>
#include <vm/vector_functions.h>
<%}
if(aes != null) {%>
#include <vm/aes_sbox.h>
<%}%>
#include <util/logging.h>
#include <boost/coroutine2/all.hpp>
#include <functional>
@@ -102,9 +114,47 @@ protected:
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
<%
def fcsr = registers.find {it.name=='FCSR'}
if(fcsr != null) {%>
if(floating_point != null) {%>
inline const char *fname(size_t index){return index < 32?name(index+traits::F0):"illegal";}
<%}
if(vector != null) {%>
inline const char* vname(size_t index) { return index < 32 ? name(index + traits::V0) : "illegal"; }
inline const char* sew_name(size_t bits) {
switch(bits) {
case 0b000:
return "e8";
case 0b001:
return "e16";
case 0b010:
return "e32";
case 0b011:
return "e64";
default:
return "illegal";
}
}
inline const char* lmul_name(size_t bits) {
switch(bits) {
case 0b101:
return "mf8";
case 0b110:
return "mf4";
case 0b111:
return "mf2";
case 0b000:
return "m1";
case 0b001:
return "m2";
case 0b010:
return "m4";
case 0b011:
return "m8";
default:
return "illegal";
}
}
inline const char* ma_name(bool ma) { return ma ? "ma" : "mu"; }
inline const char* ta_name(bool ta) { return ta ? "ta" : "tu"; }
<%}%>
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
@@ -127,7 +177,792 @@ if(fcsr != null) {%>
inline void set_tval(uint64_t new_tval){
tval = new_tval;
}
<%if(vector != null) {
def xlen = constants.find { it.name == 'XLEN' }?.value ?: 0
def vlen = constants.find { it.name == 'VLEN' }?.value ?: 0 %>
inline void lower(){
this->core.reg.trap_state = 0;
}
uint64_t vlseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1_val, uint8_t width_val, uint8_t segment_size){
switch(width_val){
case 0b000:
return softvector::vector_load_store<${vlen}, uint8_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b101:
return softvector::vector_load_store<${vlen}, uint16_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b110:
return softvector::vector_load_store<${vlen}, uint32_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b111:
return softvector::vector_load_store<${vlen}, uint64_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
default:
throw new std::runtime_error("Unsupported width bit value");
}
}
uint64_t vsseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1_val, uint8_t width_val, uint8_t segment_size){
switch(width_val){
case 0b000:
return softvector::vector_load_store<${vlen}, uint8_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b101:
return softvector::vector_load_store<${vlen}, uint16_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b110:
return softvector::vector_load_store<${vlen}, uint32_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
case 0b111:
return softvector::vector_load_store<${vlen}, uint64_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size);
default:
throw new std::runtime_error("Unsupported width bit value");
}
}
uint64_t vlsseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1_val, uint8_t width_val, uint8_t segment_size, int64_t stride){
switch(width_val){
case 0b000:
return softvector::vector_load_store<${vlen}, uint8_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b101:
return softvector::vector_load_store<${vlen}, uint16_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b110:
return softvector::vector_load_store<${vlen}, uint32_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b111:
return softvector::vector_load_store<${vlen}, uint64_t>(this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
default:
throw new std::runtime_error("Unsupported width bit value");
}
}
uint64_t vssseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1_val, uint8_t width_val, uint8_t segment_size, int64_t stride){
switch(width_val){
case 0b000:
return softvector::vector_load_store<${vlen}, uint8_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b101:
return softvector::vector_load_store<${vlen}, uint16_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b110:
return softvector::vector_load_store<${vlen}, uint32_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
case 0b111:
return softvector::vector_load_store<${vlen}, uint64_t>(this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vd, rs1_val, segment_size, stride, true);
default:
throw new std::runtime_error("Unsupported width bit value");
}
}
using indexed_load_store_t = std::function<uint64_t(void*, std::function<bool(void*, uint64_t, uint64_t, uint8_t*)>, uint8_t*, uint64_t, uint64_t, softvector::vtype_t, bool, uint8_t, uint64_t, uint8_t, uint8_t)>;
template <typename T1, typename T2> indexed_load_store_t getFunction() {
return [this](void* core, std::function<uint64_t(void*, uint64_t, uint64_t, uint8_t*)> load_store_fn, uint8_t* V, uint64_t vl,
uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1, uint8_t vs2, uint8_t segment_size) {
return softvector::vector_load_store_index<${xlen}, ${vlen}, T1, T2>(core, load_store_fn, V, vl, vstart, vtype, vm, vd, rs1, vs2, segment_size);
};
}
const std::array<std::array<indexed_load_store_t, 4>, 4> functionTable = {{
{getFunction<uint8_t, uint8_t>(), getFunction<uint8_t, uint16_t>(), getFunction<uint8_t, uint32_t>(), getFunction<uint8_t, uint64_t>()},
{getFunction<uint16_t, uint8_t>(), getFunction<uint16_t, uint16_t>(), getFunction<uint16_t, uint32_t>(), getFunction<uint16_t, uint64_t>()},
{getFunction<uint32_t, uint8_t>(), getFunction<uint32_t, uint16_t>(), getFunction<uint32_t, uint32_t>(), getFunction<uint32_t, uint64_t>()},
{getFunction<uint64_t, uint8_t>(), getFunction<uint64_t, uint16_t>(), getFunction<uint64_t, uint32_t>(), getFunction<uint64_t, uint64_t>()}
}};
const size_t map_index_size[9] = { 0, 0, 1, 0, 2, 0, 0, 0, 3 }; // translate number of bytes to index in functionTable
uint64_t vlxseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1_val, uint8_t vs2, uint8_t segment_size, uint8_t index_byte_size, uint8_t data_byte_size, bool ordered){
return functionTable[map_index_size[index_byte_size]][data_byte_size](this->get_arch(), softvector::softvec_read, V, vl, vstart, vtype, vm, vd, rs1_val, vs2, segment_size);
}
uint64_t vsxseg(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vs3, uint64_t rs1_val, uint8_t vs2, uint8_t segment_size, uint8_t index_byte_size, uint8_t data_byte_size, bool ordered){
return functionTable[map_index_size[index_byte_size]][data_byte_size](this->get_arch(), softvector::softvec_write, V, vl, vstart, vtype, vm, vs3, rs1_val, vs2, segment_size);
}
void vector_vector_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::vector_vector_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_imm_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_op<${vlen}, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_op<${vlen}, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_ww(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_op<${vlen}, uint16_t, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_ww(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_op<${vlen}, uint16_t, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_extend(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 target_sew_pow, uint8_t frac_pow){
switch(target_sew_pow){
case 4: // uint16_t target
if(frac_pow != 1) throw new std::runtime_error("Unsupported frac_pow");
return softvector::vector_unary_op<${vlen}, uint16_t, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
case 5: // uint32_t target
switch(frac_pow){
case 1:
return softvector::vector_unary_op<${vlen}, uint32_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
case 2:
return softvector::vector_unary_op<${vlen}, uint32_t, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
default:
throw new std::runtime_error("Unsupported frac_pow");
}
case 6: // uint64_t target
switch(frac_pow){
case 1:
return softvector::vector_unary_op<${vlen}, uint64_t, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
case 2:
return softvector::vector_unary_op<${vlen}, uint64_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
case 3:
return softvector::vector_unary_op<${vlen}, uint64_t, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2);
default:
throw new std::runtime_error("Unsupported frac_pow");
}
default:
throw new std::runtime_error("Unsupported target_sew_pow");
}
}
void vector_vector_carry(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val, int8_t carry){
switch(sew_val){
case 0b000:
return softvector::vector_vector_carry<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, vs1, carry);
case 0b001:
return softvector::vector_vector_carry<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, vs1, carry);
case 0b010:
return softvector::vector_vector_carry<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, vs1, carry);
case 0b011:
return softvector::vector_vector_carry<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, vs1, carry);
default:
throw new std::runtime_error("Unsupported sew bit value");
} }
void vector_imm_carry(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val, int8_t carry){
switch(sew_val){
case 0b000:
return softvector::vector_imm_carry<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, imm, carry);
case 0b001:
return softvector::vector_imm_carry<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, imm, carry);
case 0b010:
return softvector::vector_imm_carry<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, imm, carry);
case 0b011:
return softvector::vector_imm_carry<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vd, vs2, imm, carry);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void carry_vector_vector_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, unsigned vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::carry_vector_vector_op<${vlen}, uint8_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::carry_vector_vector_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::carry_vector_vector_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::carry_vector_vector_op<${vlen}, uint64_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void carry_vector_imm_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::carry_vector_imm_op<${vlen}, uint8_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::carry_vector_imm_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::carry_vector_imm_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::carry_vector_imm_op<${vlen}, uint64_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void mask_vector_vector_op(uint8_t* V, unsigned funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, unsigned vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::mask_vector_vector_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::mask_vector_vector_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::mask_vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::mask_vector_vector_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void mask_vector_imm_op(uint8_t* V, unsigned funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::mask_vector_imm_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::mask_vector_imm_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::mask_vector_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::mask_vector_imm_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_vw(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_op<${vlen}, uint8_t, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_op<${vlen}, uint16_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_op<${vlen}, uint32_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_vw(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_op<${vlen}, uint8_t, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_op<${vlen}, uint16_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_op<${vlen}, uint32_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_merge(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_merge<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_merge<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_merge<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::vector_vector_merge<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_merge(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_merge<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_merge<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_merge<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_imm_merge<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
bool sat_vector_vector_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint64_t vxrm, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::sat_vector_vector_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b001:
return softvector::sat_vector_vector_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b010:
return softvector::sat_vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b011:
return softvector::sat_vector_vector_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
bool sat_vector_imm_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint64_t vxrm, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::sat_vector_imm_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b001:
return softvector::sat_vector_imm_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b010:
return softvector::sat_vector_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b011:
return softvector::sat_vector_imm_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
bool sat_vector_vector_vw(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint64_t vxrm, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::sat_vector_vector_op<${vlen}, uint8_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b001:
return softvector::sat_vector_vector_op<${vlen}, uint16_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b010:
return softvector::sat_vector_vector_op<${vlen}, uint32_t, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, vs1);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
bool sat_vector_imm_vw(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint64_t vxrm, bool vm, uint8_t vd, uint8_t vs2, int64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::sat_vector_imm_op<${vlen}, uint8_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b001:
return softvector::sat_vector_imm_op<${vlen}, uint16_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b010:
return softvector::sat_vector_imm_op<${vlen}, uint32_t, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vxrm, vm, vd, vs2, imm);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_red_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_red_op<${vlen}, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_red_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_red_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::vector_red_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_red_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_red_op<${vlen}, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_red_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_red_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1){
return softvector::mask_mask_op<${vlen}>(V, funct6, funct3, vl, vstart, vd, vs2, vs1);
}
uint64_t vcpop(uint8_t* V, uint64_t vl, uint64_t vstart, bool vm, unsigned vs2){
return softvector::vcpop<${vlen}>(V, vl, vstart, vm, vs2);
}
int64_t vfirst(uint8_t* V, uint64_t vl, uint64_t vstart, bool vm, unsigned vs2){
return softvector::vfirst<${vlen}>(V, vl, vstart, vm, vs2);
}
void mask_set_op(uint8_t* V, unsigned enc, uint64_t vl, uint64_t vstart, bool vm, unsigned vd, unsigned vs2){
return softvector::mask_set_op<${vlen}>(V, enc, vl, vstart, vm, vd, vs2);
}
void viota(uint8_t* V, 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::viota<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2);
case 0b001:
return softvector::viota<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2);
case 0b010:
return softvector::viota<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2);
case 0b011:
return softvector::viota<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vid(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vid<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd);
case 0b001:
return softvector::vid<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd);
case 0b010:
return softvector::vid<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd);
case 0b011:
return softvector::vid<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void scalar_to_vector(uint8_t* V, softvector::vtype_t vtype, unsigned vd, uint64_t val, uint8_t sew_val){
switch(sew_val){
case 0b000:
softvector::scalar_move<${vlen}, uint8_t>(V, vtype, vd, val, true);
break;
case 0b001:
softvector::scalar_move<${vlen}, uint16_t>(V, vtype, vd, val, true);
break;
case 0b010:
softvector::scalar_move<${vlen}, uint32_t>(V, vtype, vd, val, true);
break;
case 0b011:
softvector::scalar_move<${vlen}, uint64_t>(V, vtype, vd, val, true);
break;
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
uint64_t scalar_from_vector(uint8_t* V, softvector::vtype_t vtype, unsigned vd, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::scalar_move<${vlen}, uint8_t>(V, vtype, vd, 0, false);
case 0b001:
return softvector::scalar_move<${vlen}, uint16_t>(V, vtype, vd, 0, false);
case 0b010:
return softvector::scalar_move<${vlen}, uint32_t>(V, vtype, vd, 0, false);
case 0b011:
return softvector::scalar_move<${vlen}, uint64_t>(V, vtype, vd, 0, false);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_slideup(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
switch(sew_val){
case 0b000:
return softvector::vector_slideup<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_slideup<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_slideup<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_slideup<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_slidedown(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
switch(sew_val){
case 0b000:
return softvector::vector_slidedown<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_slidedown<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_slidedown<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_slidedown<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_slide1up(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
switch(sew_val){
case 0b000:
return softvector::vector_slide1up<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_slide1up<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_slide1up<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_slide1up<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_slide1down(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
switch(sew_val){
case 0b000:
return softvector::vector_slide1down<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_slide1down<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_slide1down<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_slide1down<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_gather(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_gather<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_gather<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_gather<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::vector_vector_gather<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_vector_gatherei16(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_vector_gather<${vlen}, uint8_t, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b001:
return softvector::vector_vector_gather<${vlen}, uint16_t, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b010:
return softvector::vector_vector_gather<${vlen}, uint32_t, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
case 0b011:
return softvector::vector_vector_gather<${vlen}, uint64_t, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_imm_gather(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_imm_gather<${vlen}, uint8_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b001:
return softvector::vector_imm_gather<${vlen}, uint16_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b010:
return softvector::vector_imm_gather<${vlen}, uint32_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
case 0b011:
return softvector::vector_imm_gather<${vlen}, uint64_t>(V, vl, vstart, vtype, vm, vd, vs2, imm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_compress(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::vector_compress<${vlen}, uint8_t>(V, vl, vstart, vtype, vd, vs2, vs1);
case 0b001:
return softvector::vector_compress<${vlen}, uint16_t>(V, vl, vstart, vtype, vd, vs2, vs1);
case 0b010:
return softvector::vector_compress<${vlen}, uint32_t>(V, vl, vstart, vtype, vd, vs2, vs1);
case 0b011:
return softvector::vector_compress<${vlen}, uint64_t>(V, vl, vstart, vtype, vd, vs2, vs1);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void vector_whole_move(uint8_t* V, uint8_t vd, uint8_t vs2, uint8_t count){
return softvector::vector_whole_move<${vlen}>(V, vd, vs2, count);
}
uint64_t fp_scalar_from_vector(uint8_t* V, softvector::vtype_t vtype, unsigned vd, uint8_t sew_val){
return scalar_from_vector(V, vtype, vd, sew_val);
}
void fp_vector_slide1up(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
return vector_slide1up(V, vl, vstart, vtype, vm, vd, vs2, imm, sew_val);
}
void fp_vector_slide1down(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm, uint8_t sew_val) {
return vector_slide1down(V, vl, vstart, vtype, vm, vd, vs2, imm, sew_val);
}
void fp_vector_red_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_red_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_red_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
return softvector::fp_vector_red_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_red_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::fp_vector_red_op<${vlen}, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b001:
return softvector::fp_vector_red_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_red_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011: // would require 128 bits vs2 value
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_vector_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_vector_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
return softvector::fp_vector_vector_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_imm_op(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_imm_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011:
return softvector::fp_vector_imm_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_vector_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_vector_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_imm_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_imm_op<${vlen}, uint32_t, uint16_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint64_t, uint32_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_vector_ww(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_vector_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_imm_ww(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_imm_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_unary_op(uint8_t* V, uint8_t encoding_space, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::fp_vector_unary_op<${vlen}, uint16_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_op<${vlen}, uint32_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011:
return softvector::fp_vector_unary_op<${vlen}, uint64_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void mask_fp_vector_vector_op(uint8_t* V, uint8_t funct6, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::mask_fp_vector_vector_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::mask_fp_vector_vector_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
return softvector::mask_fp_vector_vector_op<${vlen}, uint64_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void mask_fp_vector_imm_op(uint8_t* V, uint8_t funct6, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
return softvector::mask_fp_vector_imm_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::mask_fp_vector_imm_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011:
return softvector::mask_fp_vector_imm_op<${vlen}, uint64_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm, rm);
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_imm_merge(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t sew_val){
vector_imm_merge(V, vl, vstart, vtype, vm, vd, vs2, imm, sew_val);
}
void fp_vector_unary_w(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 rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::fp_vector_unary_w<${vlen}, uint16_t, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b001:
return softvector::fp_vector_unary_w<${vlen}, uint32_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_w<${vlen}, uint64_t, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_unary_n(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 rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
return softvector::fp_vector_unary_n<${vlen}, uint8_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b001:
return softvector::fp_vector_unary_n<${vlen}, uint16_t, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_n<${vlen}, uint32_t, uint64_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011: // would require 128 bit value to narrow
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
<%}%>
uint64_t fetch_count{0};
uint64_t tval{0};
@@ -271,8 +1106,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// used registers<%instr.usedVariables.each{ k,v->
if(v.isArray) {%>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);<%}}%>
// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction<%instr.behavior.eachLine{%>
${it}<%}%>

View File

@@ -35,19 +35,18 @@
#ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON
#include <iss/arch/traits.h>
#include <iss/log_categories.h>
#include <iss/mem/memory_if.h>
#include <iss/vm_types.h>
#include "mstatus.h"
#include "util/delegate.h"
#include <array>
#include <cstdint>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/log_categories.h>
#include <iss/mem/memory_if.h>
#include <iss/semihosting/semihosting.h>
#include <iss/vm_types.h>
#include <limits>
#include <sstream>
#include <string>
@@ -195,7 +194,17 @@ enum riscv_csr {
dcsr = 0x7B0,
dpc = 0x7B1,
dscratch0 = 0x7B2,
dscratch1 = 0x7B3
dscratch1 = 0x7B3,
// vector CSR
// URW
vstart = 0x008,
vxsat = 0x009,
vxrm = 0x00A,
vcsr = 0x00F,
// URO
vl = 0xC20,
vtype = 0xC21,
vlenb = 0xC22,
};
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3, PRIV_D = 4 };
@@ -314,6 +323,19 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co
csr_rd_cb[frm] = MK_CSR_RD_CB(read_fcsr);
csr_wr_cb[frm] = MK_CSR_WR_CB(write_fcsr);
}
if(traits<BASE>::V_REGS_SIZE > 0) {
csr_rd_cb[vstart] = MK_CSR_RD_CB(read_vstart);
csr_wr_cb[vstart] = MK_CSR_WR_CB(write_vstart);
csr_rd_cb[vxsat] = MK_CSR_RD_CB(read_vxsat);
csr_wr_cb[vxsat] = MK_CSR_WR_CB(write_vxsat);
csr_rd_cb[vxrm] = MK_CSR_RD_CB(read_vxrm);
csr_wr_cb[vxrm] = MK_CSR_WR_CB(write_vxrm);
csr_rd_cb[vcsr] = MK_CSR_RD_CB(read_vcsr);
csr_wr_cb[vcsr] = MK_CSR_WR_CB(write_vcsr);
csr_rd_cb[vl] = MK_CSR_RD_CB(read_vl);
csr_rd_cb[vtype] = MK_CSR_RD_CB(read_vtype);
csr_rd_cb[vlenb] = MK_CSR_RD_CB(read_vlenb);
}
for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) {
csr_rd_cb[addr] = MK_CSR_RD_CB(read_null);
csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain);
@@ -390,8 +412,10 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co
// Load ELF data
if(reader.load(name)) {
// check elf properties
if(reader.get_class() != expected_elf_class)
if(reader.get_class() != expected_elf_class) {
CPPLOG(ERR) << "ISA missmatch, selected XLEN does not match supplied file ";
return false;
}
if(reader.get_type() != ELFIO::ET_EXEC)
return false;
if(reader.get_machine() != ELFIO::EM_RISCV)
@@ -684,6 +708,63 @@ template <typename BASE, typename LOGCAT = logging::disass> struct riscv_hart_co
return iss::Ok;
}
iss::status read_vstart(unsigned addr, reg_t& val) {
val = this->get_vstart();
return iss::Ok;
}
iss::status write_vstart(unsigned addr, reg_t val) {
this->set_vstart(val);
return iss::Ok;
}
iss::status read_vxsat(unsigned addr, reg_t& val) {
val = this->get_vxsat();
return iss::Ok;
}
iss::status write_vxsat(unsigned addr, reg_t val) {
this->set_vxsat(val & 1);
csr[vcsr] = (~1ULL & csr[vcsr]) | (val & 1);
return iss::Ok;
}
iss::status read_vxrm(unsigned addr, reg_t& val) {
val = this->get_vxrm();
return iss::Ok;
}
iss::status write_vxrm(unsigned addr, reg_t val) {
this->set_vxrm(val & 0b11);
csr[vcsr] = (~0b110ULL & csr[vcsr]) | ((val & 0b11) << 1);
return iss::Ok;
}
iss::status read_vcsr(unsigned addr, reg_t& val) {
val = csr[vcsr];
return iss::Ok;
}
iss::status write_vcsr(unsigned addr, reg_t val) {
csr[vcsr] = val;
return iss::Ok;
}
iss::status read_vl(unsigned addr, reg_t& val) {
val = this->get_vl();
return iss::Ok;
}
iss::status read_vtype(unsigned addr, reg_t& val) {
val = this->get_vtype();
return iss::Ok;
}
iss::status read_vlenb(unsigned addr, reg_t& val) {
val = csr[vlenb];
return iss::Ok;
}
priv_if<reg_t> get_priv_if() {
return priv_if<reg_t>{.read_csr = [this](unsigned addr, reg_t& val) -> iss::status { return read_csr(addr, val); },
.write_csr = [this](unsigned addr, reg_t val) -> iss::status { return write_csr(addr, val); },

View File

@@ -45,10 +45,10 @@
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <iss/mem/memory_with_htif.h>
#include <array>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iss/mem/memory_with_htif.h>
#include <unordered_map>
namespace iss {

View File

@@ -47,8 +47,8 @@
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
#endif
#include <iss/mem/memory_with_htif.h>
#include <fmt/format.h>
#include <iss/mem/memory_with_htif.h>
#include <unordered_map>
namespace iss {

File diff suppressed because one or more lines are too long

View File

@@ -40,6 +40,7 @@
#include <vector>
#include "iss/arch/tgc_mapper.h"
#include "util/logging.h"
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#ifdef WITH_LLVM
@@ -258,6 +259,7 @@ int main(int argc, char* argv[]) {
LOG(ERR) << "Error opening file " << filename << std::endl;
return 1;
}
LOGGER(DEFAULT)::reporting_level() = logging::ERR;
for(auto addr = start_addr; addr < end_addr; addr += data.size()) {
vm->get_arch()->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0 /*MEM*/, addr, data.size(),
data.data()); // FIXME: get space from iss::arch::traits<ARCH>::mem_type_e::MEM

69
src/vm/aes_sbox.h Normal file
View File

@@ -0,0 +1,69 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2025, MINRES Technologies GmbH
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Contributors:
// ales@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#ifndef _VM_AES_SBOX_H_
#define _VM_AES_SBOX_H_
#include <cstdint>
const uint8_t AES_ENC_SBOX[] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59,
0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1,
0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83,
0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C,
0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE,
0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6,
0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9,
0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1,
0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16};
uint8_t inline aes_sbox_fwd(uint8_t index) { return AES_ENC_SBOX[index]; }
const uint8_t AES_DEC_SBOX[] = {
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F,
0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B,
0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8,
0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3,
0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9,
0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07,
0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F,
0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B,
0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D};
uint8_t inline aes_sbox_inv(uint8_t index) { return AES_DEC_SBOX[index]; }
#endif /* _VM_AES_SBOX_H_ */

View File

@@ -33,7 +33,9 @@
////////////////////////////////////////////////////////////////////////////////
#include "fp_functions.h"
#include "softfloat_types.h"
#include <array>
#include <cstdint>
extern "C" {
#include "internals.h"
@@ -44,21 +46,375 @@ extern "C" {
#include <limits>
using this_t = uint8_t*;
// this does not inlcude any reserved rm or the DYN rm, as DYN rm should be taken care of in the vm_impl
const std::array<uint8_t, 5> rmm_map = {
softfloat_round_near_even /*RNE*/, softfloat_round_minMag /*RTZ*/, softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/,
softfloat_round_near_maxMag /*RMM*/
};
template <typename T> T constexpr defaultNaN();
template <> uint16_t constexpr defaultNaN<uint16_t>() { return defaultNaNF16UI; }
template <> uint32_t constexpr defaultNaN<uint32_t>() { return defaultNaNF32UI; }
template <> uint64_t constexpr defaultNaN<uint64_t>() { return defaultNaNF64UI; }
template <typename T> T constexpr posInf();
template <> uint16_t constexpr posInf<uint16_t>() { return 0x7C00; }
template <> uint32_t constexpr posInf<uint32_t>() { return 0x7F800000; }
template <> uint64_t constexpr posInf<uint64_t>() { return 0x7FF0000000000000; }
template <typename T> T constexpr negInf();
template <> uint16_t constexpr negInf<uint16_t>() { return 0xFC00; }
template <> uint32_t constexpr negInf<uint32_t>() { return 0xFF800000; }
template <> uint64_t constexpr negInf<uint64_t>() { return 0xFFF0000000000000; }
template <typename T> T constexpr negZero();
template <> uint16_t constexpr negZero<uint16_t>() { return 0x8000; }
template <> uint32_t constexpr negZero<uint32_t>() { return 0x80000000; }
template <> uint64_t constexpr negZero<uint64_t>() { return 0x8000000000000000; }
const uint32_t quiet_nan32 = 0x7fC00000;
template <typename T> bool rsqrt_check(T fclass_val, bool& subnormal, T& ret_val) {
softfloat_exceptionFlags = 0;
switch(fclass_val) {
case 0x0001: {
softfloat_exceptionFlags |= softfloat_flag_invalid;
ret_val = defaultNaN<T>();
return true;
}
case 0x0002: {
softfloat_exceptionFlags |= softfloat_flag_invalid;
ret_val = defaultNaN<T>();
return true;
}
case 0x0004: {
softfloat_exceptionFlags |= softfloat_flag_invalid;
ret_val = defaultNaN<T>();
return true;
}
case 0x0100: {
softfloat_exceptionFlags |= softfloat_flag_invalid;
ret_val = defaultNaN<T>();
return true;
}
case 0x0200: {
ret_val = defaultNaN<T>();
return true;
}
case 0x0008: {
softfloat_exceptionFlags |= softfloat_flag_infinite;
ret_val = negInf<T>();
return true;
}
case 0x0010: {
softfloat_exceptionFlags |= softfloat_flag_infinite;
ret_val = posInf<T>();
return true;
}
case 0x0080: {
ret_val = 0;
return true;
}
case 0x0020: {
subnormal = true;
}
default:
return false;
}
}
static constexpr std::array<std::array<uint64_t, 64>, 2> rsqrt_table{
{{
52, 51, 50, 48, 47, 46, 44, 43, 42, 41, 40, 39, 38, 36, 35, 34, 33, 32, 31, 30, 30, 29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20,
19, 19, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 10, 10, 9, 9, 8, 7, 7, 6, 6, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0,
},
{127, 125, 123, 121, 119, 118, 116, 114, 113, 111, 109, 108, 106, 105, 103, 102, 100, 99, 97, 96, 95, 93,
92, 91, 90, 88, 87, 86, 85, 84, 83, 82, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 70,
69, 68, 67, 66, 65, 64, 63, 63, 62, 61, 60, 59, 59, 58, 57, 56, 56, 55, 54, 53}}};
uint64_t constexpr frsqrt7_general(const unsigned s, const unsigned e, const uint64_t sign, const int64_t exp, const uint64_t sig,
const bool subnormal) {
int64_t normalized_exp = exp;
uint64_t normalized_sig = sig;
if(subnormal) {
signed nr_leadingzeros = __builtin_clzll(sig) - (64 - s);
normalized_exp = -nr_leadingzeros;
normalized_sig = (sig << (1 + nr_leadingzeros)) & ((1ULL << s) - 1);
}
unsigned exp_idx = normalized_exp & 1;
unsigned sig_idx = (normalized_sig >> (s - 6)) & 0x3f;
// The output of the table becomes the seven high bits of the result significand (after the leading one); the remainder of the
// result significand is zero.
uint64_t out_sig = rsqrt_table[exp_idx][sig_idx] << (s - 7);
// The output exponent equals floor((3*B - 1 - the normalized input exponent) / 2), where B is the exponent bias.
unsigned bias = (1UL << (e - 1)) - 1;
uint64_t out_exp = (3 * bias - 1 - normalized_exp) / 2;
// The output sign equals the input sign.
return (sign << (s + e)) | (out_exp << s) | out_sig;
}
template <typename T> bool recip_check(T fclass_val, bool& subnormal, uint64_t& ret_val) {
softfloat_exceptionFlags = 0;
switch(fclass_val) {
case 0x0001: {
ret_val = negZero<T>();
return true;
}
case 0x0080: {
ret_val = 0;
return true;
}
case 0x0008: {
softfloat_exceptionFlags |= softfloat_flag_infinite;
ret_val = negInf<T>();
return true;
}
case 0x0010: {
softfloat_exceptionFlags |= softfloat_flag_infinite;
ret_val = posInf<T>();
return true;
}
case 0x0100: {
softfloat_exceptionFlags |= softfloat_flag_invalid;
ret_val = defaultNaN<T>();
return true;
}
case 0x0200: {
ret_val = defaultNaN<T>();
return true;
}
case 0x0004: {
subnormal = true;
return false;
}
case 0x0020: {
subnormal = true;
return false;
}
default: {
subnormal = false;
return false;
}
}
}
static constexpr std::array<uint64_t, 128> rec_table{
{127, 125, 123, 121, 119, 117, 116, 114, 112, 110, 109, 107, 105, 104, 102, 100, 99, 97, 96, 94, 93, 91, 90, 88, 87, 85,
84, 83, 81, 80, 79, 77, 76, 75, 74, 72, 71, 70, 69, 68, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55,
54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 40, 39, 38, 37, 36, 35, 35, 34, 33, 32, 31,
31, 30, 29, 28, 28, 27, 26, 25, 25, 24, 23, 23, 22, 21, 21, 20, 19, 19, 18, 17, 17, 16, 15, 15, 14, 14,
13, 12, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0}};
bool frec_general(uint64_t& res, const unsigned s, const unsigned e, const uint64_t sign, const int64_t exp, const uint64_t sig,
const bool subnormal, uint8_t mode) {
int nr_leadingzeros = __builtin_clzll(sig) - (64 - s);
int64_t normalized_exp = subnormal ? -nr_leadingzeros : exp;
uint64_t normalized_sig = subnormal ? ((sig << (1 + nr_leadingzeros)) & ((1ULL << s) - 1)) : sig;
unsigned idx = (normalized_sig >> (s - 7)) & 0x7f;
unsigned bias = (1UL << (e - 1)) - 1;
uint64_t mid_exp = 2 * (bias)-1 - normalized_exp;
uint64_t mid_sig = rec_table[idx] << (s - 7);
uint64_t out_exp = mid_exp;
uint64_t out_sig = mid_sig;
if(mid_exp == 0) {
out_exp = mid_exp;
out_sig = (mid_sig >> 1) | (1ULL << (s - 1));
} else if(mid_exp == (1ULL << e) - 1) {
out_exp = 0;
out_sig = (mid_sig >> 2) | (1ULL << (s - 2));
}
if(subnormal && nr_leadingzeros > 1) {
if((mode == 0b001) || (mode == 0b010 && sign == 0b0) || (mode == 0b011 && sign == 0b1)) {
res = (sign << (s + e)) | ((1ULL << (e - 1)) - 1) << s | ((1ULL << s) - 1);
return true;
} else {
res = (sign << (s + e)) | ((1ULL << e) - 1) << s;
return true;
}
}
res = (sign << (s + e)) | (out_exp << s) | out_sig;
return false;
}
extern "C" {
uint32_t fget_flags() { return softfloat_exceptionFlags & 0x1f; }
uint16_t fadd_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t r = f16_add(v1f, v2f);
return r.v;
}
uint16_t fsub_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t r = f16_sub(v1f, v2f);
return r.v;
}
uint16_t fmul_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t r = f16_mul(v1f, v2f);
return r.v;
}
uint16_t fdiv_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t r = f16_div(v1f, v2f);
return r.v;
}
uint16_t fsqrt_h(uint16_t v1, uint8_t mode) {
float16_t v1f{v1};
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t r = f16_sqrt(v1f);
return r.v;
}
uint16_t fcmp_h(uint16_t v1, uint16_t v2, uint16_t op) {
float16_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = v1 == defaultNaNF16UI || v2 & defaultNaNF16UI;
bool snan = softfloat_isSigNaNF16UI(v1) || softfloat_isSigNaNF16UI(v2);
switch(op) {
case 0:
if(nan | snan) {
if(snan)
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_eq(v1f, v2f) ? 1 : 0;
case 1:
if(nan | snan) {
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_le(v1f, v2f) ? 1 : 0;
case 2:
if(nan | snan) {
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_lt(v1f, v2f) ? 1 : 0;
default:
break;
}
return -1;
}
uint16_t fmadd_h(uint16_t v1, uint16_t v2, uint16_t v3, uint16_t op, uint8_t mode) {
uint16_t F16_SIGN = 1UL << 15;
switch(op) {
case 0: // FMADD_S
break;
case 1: // FMSUB_S
v3 ^= F16_SIGN;
break;
case 2: // FNMADD_S
v1 ^= F16_SIGN;
v3 ^= F16_SIGN;
break;
case 3: // FNMSUB_S
v1 ^= F16_SIGN;
break;
}
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float16_t res = softfloat_mulAddF16(v1, v2, v3, 0);
return res.v;
}
uint16_t fsel_h(uint16_t v1, uint16_t v2, uint16_t op) {
softfloat_exceptionFlags = 0;
bool v1_nan = (v1 & defaultNaNF16UI) == defaultNaNF16UI;
bool v2_nan = (v2 & defaultNaNF16UI) == defaultNaNF16UI;
bool v1_snan = softfloat_isSigNaNF16UI(v1);
bool v2_snan = softfloat_isSigNaNF16UI(v2);
if(v1_snan || v2_snan)
softfloat_raiseFlags(softfloat_flag_invalid);
if(v1_nan || v1_snan)
return (v2_nan || v2_snan) ? defaultNaNF16UI : v2;
else if(v2_nan || v2_snan)
return v1;
else {
if((v1 & 0x7fff) == 0 && (v2 & 0x7fff) == 0) {
return op == 0 ? ((v1 & 0x8000) ? v1 : v2) : ((v1 & 0x8000) ? v2 : v1);
} else {
float16_t v1f{v1}, v2f{v2};
return op == 0 ? (f16_lt(v1f, v2f) ? v1 : v2) : (f16_lt(v1f, v2f) ? v2 : v1);
}
}
}
uint16_t fclass_h(uint16_t v1) {
float16_t a{v1};
union ui16_f16 uA;
uint_fast16_t uiA;
uA.f = a;
uiA = uA.ui;
bool infOrNaN = expF16UI(uiA) == 0x1F;
bool subnormalOrZero = expF16UI(uiA) == 0;
bool sign = signF16UI(uiA);
bool fracZero = fracF16UI(uiA) == 0;
bool isNaN = isNaNF16UI(uiA);
bool isSNaN = softfloat_isSigNaNF16UI(uiA);
return (sign && infOrNaN && fracZero) << 0 | (sign && !infOrNaN && !subnormalOrZero) << 1 |
(sign && subnormalOrZero && !fracZero) << 2 | (sign && subnormalOrZero && fracZero) << 3 | (!sign && infOrNaN && fracZero) << 7 |
(!sign && !infOrNaN && !subnormalOrZero) << 6 | (!sign && subnormalOrZero && !fracZero) << 5 |
(!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9;
}
uint16_t frsqrt7_h(uint16_t v) {
bool subnormal = false;
uint16_t ret_val = 0;
if(rsqrt_check(fclass_h(v), subnormal, ret_val)) {
return ret_val;
}
uint16_t sig = fracF64UI(v);
int16_t exp = expF64UI(v);
uint16_t sign = signF64UI(v);
unsigned constexpr e = 5;
unsigned constexpr s = 10;
return frsqrt7_general(s, e, sign, exp, sig, subnormal);
}
uint16_t frec7_h(uint16_t v, uint8_t mode) {
bool subnormal = false;
uint64_t ret_val = 0;
if(recip_check(fclass_h(v), subnormal, ret_val)) {
return ret_val;
}
uint16_t sig = fracF16UI(v);
int exp = expF16UI(v);
uint16_t sign = signF16UI(v);
unsigned constexpr e = 5;
unsigned constexpr s = 10;
if(frec_general(ret_val, s, e, sign, exp, sig, subnormal, mode))
softfloat_exceptionFlags |= (softfloat_flag_inexact | softfloat_flag_overflow);
return ret_val;
}
uint16_t unbox_h(uint8_t FLEN, uint64_t v) {
uint64_t mask = 0;
switch(FLEN) {
case 32: {
mask = std::numeric_limits<uint32_t>::max() & ~((uint64_t)std::numeric_limits<uint16_t>::max());
break;
}
case 64: {
mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint16_t>::max());
break;
}
default:
break;
}
if((v & mask) != mask)
return defaultNaNF16UI;
else
return v & std::numeric_limits<uint32_t>::max();
}
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t r = f32_add(v1f, v2f);
return r.v;
@@ -66,7 +422,7 @@ uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) {
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t r = f32_sub(v1f, v2f);
return r.v;
@@ -74,7 +430,7 @@ uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode) {
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t r = f32_mul(v1f, v2f);
return r.v;
@@ -82,7 +438,7 @@ uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode) {
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
float32_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t r = f32_div(v1f, v2f);
return r.v;
@@ -90,7 +446,7 @@ uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode) {
uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
float32_t v1f{v1};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t r = f32_sqrt(v1f);
return r.v;
@@ -99,7 +455,7 @@ uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) {
float32_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32 || (v2 & defaultNaNF32UI) == quiet_nan32;
bool nan = v1 == defaultNaNF32UI || v2 == defaultNaNF32UI;
bool snan = softfloat_isSigNaNF32UI(v1) || softfloat_isSigNaNF32UI(v2);
switch(op) {
case 0:
@@ -127,29 +483,6 @@ uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) {
return -1;
}
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode) {
float32_t v1f{v1};
softfloat_exceptionFlags = 0;
float32_t r;
switch(op) {
case 0: { // FCVT__W__S
uint_fast32_t res = f32_to_i32(v1f, rmm_map.at(mode), true);
return (uint32_t)res;
}
case 1: { // FCVT__WU__S
uint_fast32_t res = f32_to_ui32(v1f, rmm_map.at(mode), true);
return (uint32_t)res;
}
case 2: // FCVT__S__W
r = i32_to_f32((int32_t)v1);
return r.v;
case 3: // FCVT__S__WU
r = ui32_to_f32(v1);
return r.v;
}
return 0;
}
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode) {
uint32_t F32_SIGN = 1UL << 31;
switch(op) {
@@ -166,7 +499,7 @@ uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mod
v1 ^= F32_SIGN;
break;
}
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float32_t res = softfloat_mulAddF32(v1, v2, v3, 0);
return res.v;
@@ -216,37 +549,60 @@ uint32_t fclass_s(uint32_t v1) {
(!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9;
}
uint32_t fconv_d2f(uint64_t v1, uint8_t mode) {
bool isNan = isNaNF64UI(v1);
bool isSNaN = softfloat_isSigNaNF64UI(v1);
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
if(isNan) {
if(isSNaN)
softfloat_raiseFlags(softfloat_flag_invalid);
return defaultNaNF32UI;
} else {
float32_t res = f64_to_f32(float64_t{v1});
return res.v;
uint32_t frsqrt7_s(uint32_t v) {
bool subnormal = false;
uint32_t ret_val = 0;
if(rsqrt_check(fclass_s(v), subnormal, ret_val)) {
return ret_val;
}
uint32_t sig = fracF32UI(v);
int exp = expF32UI(v);
uint32_t sign = signF32UI(v);
unsigned constexpr e = 8;
unsigned constexpr s = 23;
return frsqrt7_general(s, e, sign, exp, sig, subnormal);
}
uint64_t fconv_f2d(uint32_t v1, uint8_t mode) {
bool infOrNaN = expF32UI(v1) == 0xFF;
bool subnormalOrZero = expF32UI(v1) == 0;
if(infOrNaN || subnormalOrZero) {
return defaultNaNF64UI;
} else {
float64_t res = f32_to_f64(float32_t{v1});
return res.v;
uint32_t frec7_s(uint32_t v, uint8_t mode) {
bool subnormal = false;
uint64_t ret_val = 0;
if(recip_check(fclass_s(v), subnormal, ret_val)) {
return ret_val;
}
uint32_t sig = fracF32UI(v);
int exp = expF32UI(v);
uint32_t sign = signF32UI(v);
unsigned constexpr e = 8;
unsigned constexpr s = 23;
if(frec_general(ret_val, s, e, sign, exp, sig, subnormal, mode))
softfloat_exceptionFlags |= (softfloat_flag_inexact | softfloat_flag_overflow);
return ret_val;
}
uint32_t unbox_s(uint8_t FLEN, uint64_t v) {
uint64_t mask = 0;
switch(FLEN) {
case 32: {
return v;
}
case 64: {
mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint32_t>::max());
break;
}
default:
break;
}
if((v & mask) != mask)
return defaultNaNF32UI;
else
return v & std::numeric_limits<uint32_t>::max();
}
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32;
bool nan = v1 == defaultNaNF32UI;
bool snan = softfloat_isSigNaNF32UI(v1);
float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t r = f64_add(v1f, v2f);
return r.v;
@@ -254,7 +610,7 @@ uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t r = f64_sub(v1f, v2f);
return r.v;
@@ -262,7 +618,7 @@ uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode) {
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t r = f64_mul(v1f, v2f);
return r.v;
@@ -270,7 +626,7 @@ uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode) {
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t r = f64_div(v1f, v2f);
return r.v;
@@ -278,7 +634,7 @@ uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode) {
uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
float64_t v1f{v1};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t r = f64_sqrt(v1f);
return r.v;
@@ -287,7 +643,7 @@ uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
float64_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = (v1 & defaultNaNF64UI) == quiet_nan32 || (v2 & defaultNaNF64UI) == quiet_nan32;
bool nan = v1 == defaultNaNF64UI || v2 == defaultNaNF64UI;
bool snan = softfloat_isSigNaNF64UI(v1) || softfloat_isSigNaNF64UI(v2);
switch(op) {
case 0:
@@ -315,30 +671,6 @@ uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
return -1;
}
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode) {
float64_t v1f{v1};
softfloat_exceptionFlags = 0;
float64_t r;
switch(op) {
case 0: { // l from d
int64_t res = f64_to_i64(v1f, rmm_map.at(mode), true);
return (uint64_t)res;
}
case 1: { // lu from d
uint64_t res = f64_to_ui64(v1f, rmm_map.at(mode), true);
return res;
}
case 2: // d from l
r = i64_to_f64(v1);
return r.v;
case 3: // d from lu
r = ui64_to_f64(v1);
return r.v;
}
return 0;
}
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode) {
uint64_t F64_SIGN = 1ULL << 63;
switch(op) {
@@ -355,7 +687,7 @@ uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mod
v1 ^= F64_SIGN;
break;
}
softfloat_roundingMode = rmm_map.at(mode);
softfloat_roundingMode = mode;
softfloat_exceptionFlags = 0;
float64_t res = softfloat_mulAddF64(v1, v2, v3, 0);
return res.v;
@@ -406,52 +738,211 @@ uint64_t fclass_d(uint64_t v1) {
(!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9;
}
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode) {
float32_t v1f{v1};
softfloat_exceptionFlags = 0;
float64_t r;
switch(op) {
case 0: // l->s, fp to int32
return f32_to_i64(v1f, rmm_map.at(mode), true);
case 1: // wu->s
return f32_to_ui64(v1f, rmm_map.at(mode), true);
case 2: // s->w
r = i32_to_f64(v1);
return r.v;
case 3: // s->wu
r = ui32_to_f64(v1);
return r.v;
uint64_t frsqrt7_d(uint64_t v) {
bool subnormal = false;
uint64_t ret_val = 0;
if(rsqrt_check(fclass_d(v), subnormal, ret_val)) {
return ret_val;
}
return 0;
uint64_t sig = fracF64UI(v);
int exp = expF64UI(v);
uint64_t sign = signF64UI(v);
unsigned constexpr e = 11;
unsigned constexpr s = 52;
return frsqrt7_general(s, e, sign, exp, sig, subnormal);
}
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode) {
softfloat_exceptionFlags = 0;
float32_t r;
switch(op) {
case 0: { // wu->s
int32_t r = f64_to_i32(float64_t{v1}, rmm_map.at(mode), true);
return r;
uint64_t frec7_d(uint64_t v, uint8_t mode) {
bool subnormal = false;
uint64_t ret_val = 0;
if(recip_check(fclass_d(v), subnormal, ret_val)) {
return ret_val;
}
case 1: { // wu->s
uint32_t r = f64_to_ui32(float64_t{v1}, rmm_map.at(mode), true);
return r;
}
case 2: // l->s, fp to int32
r = i64_to_f32(v1);
return r.v;
case 3: // wu->s
r = ui64_to_f32(v1);
return r.v;
}
return 0;
uint64_t sig = fracF64UI(v);
int exp = expF64UI(v);
uint64_t sign = signF64UI(v);
unsigned constexpr e = 11;
unsigned constexpr s = 52;
if(frec_general(ret_val, s, e, sign, exp, sig, subnormal, mode))
softfloat_exceptionFlags |= (softfloat_flag_inexact | softfloat_flag_overflow);
return ret_val;
}
uint32_t unbox_s(uint64_t v) {
constexpr uint64_t mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint32_t>::max());
uint64_t unbox_d(uint8_t FLEN, uint64_t v) {
uint64_t mask = 0;
switch(FLEN) {
case 64: {
return v;
break;
}
default:
break;
}
if((v & mask) != mask)
return 0x7fc00000;
return defaultNaNF64UI;
else
return v & std::numeric_limits<uint32_t>::max();
}
// conversion: float to float
uint32_t f16tof32(uint16_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_f32(float16_t{val}).v;
}
uint64_t f16tof64(uint16_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_f64(float16_t{val}).v;
}
uint16_t f32tof16(uint32_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_f16(float32_t{val}).v;
}
uint64_t f32tof64(uint32_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_f64(float32_t{val}).v;
}
uint16_t f64tof16(uint64_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_f16(float64_t{val}).v;
}
uint32_t f64tof32(uint64_t val, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_f32(float64_t{val}).v;
}
// conversions: float to unsigned
uint32_t f16toui32(uint16_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_ui32(float16_t{v}, rm, true);
}
uint64_t f16toui64(uint16_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_ui64(float16_t{v}, rm, true);
}
uint32_t f32toui32(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_ui32(float32_t{v}, rm, true);
}
uint64_t f32toui64(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_ui64(float32_t{v}, rm, true);
}
uint32_t f64toui32(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_ui32(float64_t{v}, rm, true);
}
uint64_t f64toui64(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_ui64(float64_t{v}, rm, true);
}
// conversions: float to signed
uint32_t f16toi32(uint16_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_i32(float16_t{v}, rm, true);
}
uint64_t f16toi64(uint16_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_i64(float16_t{v}, rm, true);
}
uint32_t f32toi32(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i32(float32_t{v}, rm, true);
}
uint64_t f32toi64(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i64(float32_t{v}, rm, true);
}
uint32_t f64toi32(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_i32(float64_t{v}, rm, true);
}
uint64_t f64toi64(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_i64(float64_t{v}, rm, true);
}
// conversions: unsigned to float
uint16_t ui32tof16(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f16(v).v;
}
uint16_t ui64tof16(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui64_to_f16(v).v;
}
uint32_t ui32tof32(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f32(v).v;
}
uint32_t ui64tof32(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui64_to_f32(v).v;
}
uint64_t ui32tof64(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f64(v).v;
}
uint64_t ui64tof64(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui64_to_f64(v).v;
}
// conversions: signed to float
uint16_t i32tof16(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f16(v).v;
}
uint16_t i64tof16(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i64_to_f16(v).v;
}
uint32_t i32tof32(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f32(v).v;
}
uint32_t i64tof32(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i64_to_f32(v).v;
}
uint64_t i32tof64(uint32_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f64(v).v;
}
uint64_t i64tof64(uint64_t v, uint8_t rm) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i64_to_f64(v).v;
}
}

View File

@@ -39,30 +39,88 @@
extern "C" {
uint32_t fget_flags();
// half precision
uint16_t fadd_h(uint16_t v1, uint16_t v2, uint8_t mode);
uint16_t fsub_h(uint16_t v1, uint16_t v2, uint8_t mode);
uint16_t fmul_h(uint16_t v1, uint16_t v2, uint8_t mode);
uint16_t fdiv_h(uint16_t v1, uint16_t v2, uint8_t mode);
uint16_t fsqrt_h(uint16_t v1, uint8_t mode);
uint16_t fcmp_h(uint16_t v1, uint16_t v2, uint16_t op);
uint16_t fmadd_h(uint16_t v1, uint16_t v2, uint16_t v3, uint16_t op, uint8_t mode);
uint16_t fsel_h(uint16_t v1, uint16_t v2, uint16_t op);
uint16_t fsqrt_h(uint16_t v1, uint8_t mode);
uint16_t fclass_h(uint16_t v1);
uint16_t frsqrt7_h(uint16_t v);
uint16_t frec7_h(uint16_t v, uint8_t mode);
uint16_t unbox_h(uint8_t FLEN, uint64_t v);
// single precision
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode);
uint32_t fsqrt_s(uint32_t v1, uint8_t mode);
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op);
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode);
uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op);
uint32_t fclass_s(uint32_t v1);
uint32_t fconv_d2f(uint64_t v1, uint8_t mode);
uint64_t fconv_f2d(uint32_t v1, uint8_t mode);
uint32_t frsqrt7_s(uint32_t v);
uint32_t frec7_s(uint32_t v, uint8_t mode);
uint32_t unbox_s(uint8_t FLEN, uint64_t v);
// double precision
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode);
uint64_t fsqrt_d(uint64_t v1, uint8_t mode);
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op);
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode);
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode);
uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op);
uint64_t fclass_d(uint64_t v1);
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode);
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode);
uint32_t unbox_s(uint64_t v);
uint64_t frsqrt7_d(uint64_t v);
uint64_t frec7_d(uint64_t v, uint8_t mode);
uint64_t unbox_d(uint8_t FLEN, uint64_t v);
// conversion: float to float
uint32_t f16tof32(uint16_t val, uint8_t rm);
uint64_t f16tof64(uint16_t val, uint8_t rm);
uint16_t f32tof16(uint32_t val, uint8_t rm);
uint64_t f32tof64(uint32_t val, uint8_t rm);
uint16_t f64tof16(uint64_t val, uint8_t rm);
uint32_t f64tof32(uint64_t val, uint8_t rm);
// conversions: float to unsigned
uint32_t f16toui32(uint16_t v, uint8_t rm);
uint64_t f16toui64(uint16_t v, uint8_t rm);
uint32_t f32toui32(uint32_t v, uint8_t rm);
uint64_t f32toui64(uint32_t v, uint8_t rm);
uint32_t f64toui32(uint64_t v, uint8_t rm);
uint64_t f64toui64(uint64_t v, uint8_t rm);
// conversions: float to signed
uint32_t f16toi32(uint16_t v, uint8_t rm);
uint64_t f16toi64(uint16_t v, uint8_t rm);
uint32_t f32toi32(uint32_t v, uint8_t rm);
uint64_t f32toi64(uint32_t v, uint8_t rm);
uint32_t f64toi32(uint64_t v, uint8_t rm);
uint64_t f64toi64(uint64_t v, uint8_t rm);
// conversions: unsigned to float
uint16_t ui32tof16(uint32_t v, uint8_t rm);
uint16_t ui64tof16(uint64_t v, uint8_t rm);
uint32_t ui32tof32(uint32_t v, uint8_t rm);
uint32_t ui64tof32(uint64_t v, uint8_t rm);
uint64_t ui32tof64(uint32_t v, uint8_t rm);
uint64_t ui64tof64(uint64_t v, uint8_t rm);
// conversions: signed to float
uint16_t i32tof16(uint32_t v, uint8_t rm);
uint16_t i64tof16(uint64_t v, uint8_t rm);
uint32_t i32tof32(uint32_t v, uint8_t rm);
uint32_t i64tof32(uint64_t v, uint8_t rm);
uint64_t i32tof64(uint32_t v, uint8_t rm);
uint64_t i64tof64(uint64_t v, uint8_t rm);
}
#endif /* RISCV_SRC_VM_FP_FUNCTIONS_H_ */
#endif /* _VM_FP_FUNCTIONS_H_ */

File diff suppressed because it is too large Load Diff

101
src/vm/vector_functions.cpp Normal file
View File

@@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2025, MINRES Technologies GmbH
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Contributors:
// alex@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#include "vector_functions.h"
#include "iss/vm_types.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <limits>
#include <math.h>
#include <stdexcept>
#include <vector>
namespace softvector {
bool softvec_read(void* core, uint64_t addr, uint64_t length, uint8_t* data) {
// Read length bytes from addr into *data
iss::status status = static_cast<iss::arch_if*>(core)->read(iss::address_type::PHYSICAL, iss::access_type::READ,
0 /*traits<ARCH>::MEM*/, addr, length, data);
return status == iss::Ok;
}
bool softvec_write(void* core, uint64_t addr, uint64_t length, uint8_t* data) {
// Write length bytes from addr into *data
iss::status status = static_cast<iss::arch_if*>(core)->write(iss::address_type::PHYSICAL, iss::access_type::READ,
0 /*traits<ARCH>::MEM*/, addr, length, data);
return status == iss::Ok;
}
vtype_t::vtype_t(uint32_t vtype_val) { underlying = (vtype_val & 0x8000) << 32 | (vtype_val & ~0x8000); }
vtype_t::vtype_t(uint64_t vtype_val) { underlying = vtype_val; }
bool vtype_t::vill() { return underlying >> 63; }
bool vtype_t::vma() { return (underlying >> 7) & 1; }
bool vtype_t::vta() { return (underlying >> 6) & 1; }
unsigned vtype_t::sew() {
uint8_t vsew = (underlying >> 3) & 0b111;
// pow(2, 3 + vsew);
return 1 << (3 + vsew);
}
double vtype_t::lmul() {
uint8_t vlmul = underlying & 0b111;
assert(vlmul != 0b100); // reserved encoding
int8_t signed_vlmul = (vlmul >> 2) ? 0b11111000 | vlmul : vlmul;
return pow(2, signed_vlmul);
}
mask_bit_reference& mask_bit_reference::operator=(const bool new_value) {
*start = *start & ~(1U << pos) | static_cast<unsigned>(new_value) << pos;
return *this;
}
mask_bit_reference::mask_bit_reference(uint8_t* start, uint8_t pos)
: start(start)
, pos(pos) {
assert(pos < 8 && "Bit reference can only be initialized for bytes");
};
mask_bit_reference::operator bool() const { return *(start) & (1U << (pos)); }
mask_bit_reference vmask_view::operator[](size_t idx) const {
assert(idx < elem_count);
return {start + idx / 8, static_cast<uint8_t>(idx % 8)};
}
vmask_view read_vmask(uint8_t* V, uint16_t VLEN, uint16_t elem_count, uint8_t reg_idx) {
uint8_t* mask_start = V + VLEN / 8 * reg_idx;
assert(mask_start + elem_count / 8 <= V + VLEN * RFS / 8);
return {mask_start, elem_count};
}
} // namespace softvector

172
src/vm/vector_functions.h Normal file
View File

@@ -0,0 +1,172 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2025, MINRES Technologies GmbH
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Contributors:
// alex@minres.com - initial API and implementation
////////////////////////////////////////////////////////////////////////////////
#ifndef _VM_VECTOR_FUNCTIONS_H_
#define _VM_VECTOR_FUNCTIONS_H_
#include "iss/arch_if.h"
#include "iss/vm_types.h"
#include <cstdint>
#include <functional>
#include <stdint.h>
namespace softvector {
const unsigned RFS = 32;
struct vtype_t {
uint64_t underlying;
vtype_t(uint32_t vtype_val);
vtype_t(uint64_t vtype_val);
unsigned sew();
double lmul();
bool vill();
bool vma();
bool vta();
};
class mask_bit_reference {
uint8_t* start;
uint8_t pos;
public:
mask_bit_reference& operator=(const bool new_value);
mask_bit_reference(uint8_t* start, uint8_t pos);
operator bool() const;
};
struct vmask_view {
uint8_t* start;
size_t elem_count;
mask_bit_reference operator[](size_t) const;
};
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);
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);
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 vstart, vtype_t vtype, bool vm, uint8_t vd, uint64_t rs1, uint8_t segment_size, int64_t stride = 0,
bool use_stride = false);
template <unsigned XLEN, unsigned VLEN, typename eew_t, typename sew_t>
uint64_t vector_load_store_index(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 vs2,
uint8_t segment_size);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = src2_elem_t>
void vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, unsigned vs1);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = src2_elem_t>
void vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, typename std::make_signed<src1_elem_t>::type imm);
template <unsigned VLEN, typename elem_t>
void vector_vector_carry(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, unsigned vd,
unsigned vs2, unsigned vs1, signed carry);
template <unsigned VLEN, typename elem_t>
void vector_imm_carry(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, unsigned vd, unsigned vs2,
typename std::make_signed<elem_t>::type imm, signed carry);
template <unsigned VLEN, typename scr_elem_t>
void vector_vector_merge(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, unsigned vs1);
template <unsigned VLEN, typename scr_elem_t>
void vector_imm_merge(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t>
void vector_unary_op(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2);
template <unsigned VLEN, typename elem_t>
void mask_vector_vector_op(uint8_t* V, unsigned funct, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, unsigned vs1);
template <unsigned VLEN, typename elem_t>
void mask_vector_imm_op(uint8_t* V, unsigned funct, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, typename std::make_signed<elem_t>::type imm);
void carry_vector_vector_op(uint8_t* V, unsigned funct, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
unsigned vs1);
template <unsigned VLEN, typename elem_t>
void carry_vector_imm_op(uint8_t* V, unsigned funct, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
typename std::make_signed<elem_t>::type imm);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = dest_elem_t>
bool sat_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, int64_t vxrm, bool vm,
unsigned vd, unsigned vs2, unsigned vs1);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = dest_elem_t>
bool sat_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, int64_t vxrm, bool vm,
unsigned vd, unsigned vs2, typename std::make_signed<src1_elem_t>::type imm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
void vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, unsigned vs1);
template <unsigned VLEN>
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1);
template <unsigned VLEN> uint64_t vcpop(uint8_t* V, uint64_t vl, uint64_t vstart, bool vm, unsigned vs2);
template <unsigned VLEN> uint64_t vfirst(uint8_t* V, uint64_t vl, uint64_t vstart, bool vm, unsigned vs2);
template <unsigned VLEN> void mask_set_op(uint8_t* V, unsigned enc, uint64_t vl, uint64_t vstart, bool vm, unsigned vd, unsigned vs2);
template <unsigned VLEN, typename src_elem_t>
void viota(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2);
template <unsigned VLEN, typename src_elem_t> void vid(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd);
template <unsigned VLEN, typename src_elem_t> uint64_t scalar_move(uint8_t* V, vtype_t vtype, unsigned vd, uint64_t val, bool to_vector);
template <unsigned VLEN, typename src_elem_t>
void vector_slideup(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename src_elem_t>
void vector_slidedown(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename src_elem_t>
void vector_slide1up(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename src_elem_t>
void vector_slide1down(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename dest_elem_t, typename scr_elem_t = dest_elem_t>
void vector_vector_gather(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, unsigned vs1);
template <unsigned VLEN, typename scr_elem_t>
void vector_imm_gather(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, uint64_t imm);
template <unsigned VLEN, typename scr_elem_t>
void vector_compress(uint8_t* V, uint64_t vl, uint64_t vstart, vtype_t vtype, unsigned vd, unsigned vs2, unsigned vs1);
template <unsigned VLEN> void vector_whole_move(uint8_t* V, unsigned vd, unsigned vs2, unsigned count);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
void fp_vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, unsigned vs1, uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = src2_elem_t>
void fp_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, unsigned vs1, uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = src2_elem_t>
void fp_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, src1_elem_t imm, uint8_t rm);
template <unsigned VLEN, typename elem_t>
void fp_vector_unary_op(uint8_t* V, unsigned encoding_space, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm,
unsigned vd, unsigned vs2, uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_w(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_n(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm);
template <unsigned VLEN, typename elem_t>
void mask_fp_vector_vector_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
unsigned vs1, uint8_t rm);
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,
elem_t imm, uint8_t rm);
} // namespace softvector
#include "vm/vector_functions.hpp"
#endif /* _VM_VECTOR_FUNCTIONS_H_ */

1942
src/vm/vector_functions.hpp Normal file

File diff suppressed because it is too large Load Diff