aboutsummaryrefslogtreecommitdiff
path: root/riscv/insns/psshar_dws.h
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/insns/psshar_dws.h')
-rw-r--r--riscv/insns/psshar_dws.h64
1 files changed, 64 insertions, 0 deletions
diff --git a/riscv/insns/psshar_dws.h b/riscv/insns/psshar_dws.h
new file mode 100644
index 00000000..1f530b39
--- /dev/null
+++ b/riscv/insns/psshar_dws.h
@@ -0,0 +1,64 @@
+require_rv32;
+P_RD_RS1_DW_LOOP(32, 32, {
+ uint64_t bits_SMIN = (uint64_t{1} << (32 - 1));
+ uint64_t bits_SMAX = ((uint64_t{1} << (32 - 1)) - 1);
+ bool ov = false;
+ int8_t m = P_FIELD(RS2, 0, 8);
+ int8_t rev = static_cast<int8_t>(m);
+ rev = (m < 0) ? static_cast<uint8_t>(~m + 1u) : m;
+ uint64_t mask = ((uint64_t{1} << 32) - 1);
+ p_rs1 &= mask;
+ if(m < 0){
+ if ((rev & 0xFFu) == 0u)
+ p_rd = (uint32_t)p_rs1;
+ else{
+ int128_t v_sext;
+ bool neg = ((p_rs1 >> (32 - 1)) & 1u);
+ if(!neg) v_sext = static_cast<int128_t>(p_rs1);
+ else v_sext = static_cast<int128_t>((~static_cast<uint128_t>(0) << 32) | static_cast<uint128_t>(p_rs1));
+ int128_t v_cat0 = v_sext << 1;
+
+ unsigned sh = ((unsigned)(uint8_t)rev > 255u) ? 255u : (unsigned)(uint8_t)rev;
+
+ int128_t sra_val;
+ if(sh == 0)
+ sra_val = v_cat0;
+ else if(sh >=127)
+ sra_val = (v_cat0 < 0) ? static_cast<int128_t>(-1) : static_cast<int128_t>(0);
+ else{
+ int128_t ux = static_cast<uint128_t>(v_cat0);
+ int128_t shifted = ux >> sh;
+ if(v_cat0 < 0)
+ shifted |= (~static_cast<uint128_t>(0)) << (128 - sh);
+ sra_val = static_cast<int128_t>(shifted);
+ }
+
+ int128_t plus1 = sra_val + static_cast<int128_t>(1);
+ uint128_t ures = static_cast<uint128_t>(plus1);
+ p_rd = (uint32_t)(static_cast<uint64_t>((ures >> 1) & static_cast<uint128_t>(mask)));
+ }
+ }
+ else{
+ if(rev==0) p_rd = (uint32_t)p_rs1;
+ else if(rev >= 32){
+ if(p_rs1==0)
+ p_rd = 0;
+ else{
+ ov = true;
+ uint64_t sign = (p_rs1 >> (32 - 1)) & 1u;
+ p_rd = (uint32_t)(sign ? bits_SMIN : bits_SMAX);
+ }
+ }
+ else{
+ uint64_t sign = (p_rs1 >> (32 - 1)) & 1u;
+ uint64_t top = (p_rs1 >> (32 - rev));
+ uint64_t need = sign ? ((uint64_t{1} << rev) - 1) : 0u;
+ ov = (top != need);
+ if(ov)
+ p_rd = (uint32_t)(sign ? bits_SMIN : bits_SMAX);
+ else
+ p_rd = (uint32_t)((p_rs1 << rev) & mask);
+ }
+ }
+ if (ov) P.VU.vxsat->write(1);
+})