aboutsummaryrefslogtreecommitdiff
path: root/riscv/insns/pssha_dhs.h
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/insns/pssha_dhs.h')
-rw-r--r--riscv/insns/pssha_dhs.h45
1 files changed, 45 insertions, 0 deletions
diff --git a/riscv/insns/pssha_dhs.h b/riscv/insns/pssha_dhs.h
new file mode 100644
index 00000000..a85d2a5a
--- /dev/null
+++ b/riscv/insns/pssha_dhs.h
@@ -0,0 +1,45 @@
+require_rv32;
+P_RD_RS1_DW_LOOP(16, 16, {
+ uint64_t bits_SMIN = (uint64_t{1} << (16 - 1));
+ uint64_t bits_SMAX = ((uint64_t{1} << (16 - 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} << 16) - 1);
+ p_rs1 &= mask;
+ if(m < 0){
+ unsigned sh = ((unsigned)(uint8_t)rev > 255u) ? 255u : (unsigned)(uint8_t)rev;
+ uint64_t sign = (p_rs1 >> (16 - 1)) & 1u;
+
+ if(sh >= 16) p_rd = (uint16_t)(sign ? mask : 0u);
+ else{
+ uint64_t shifted = (p_rs1 >> sh);
+ uint64_t fill = (~uint64_t{0}) << (16 - sh);
+ shifted |= fill;
+ p_rd = (uint16_t)(shifted & mask);
+ }
+ }
+ else{
+ if(rev==0) p_rd = (uint16_t)p_rs1;
+ else if(rev >= 16){
+ if(p_rs1==0) p_rd = 0;
+ else{
+ ov = true;
+ uint64_t sign = (p_rs1 >> (16 - 1)) & 1u;
+ p_rd = (uint16_t)(sign ? bits_SMIN : bits_SMAX);
+ }
+ }
+ else{
+ uint64_t sign = (p_rs1 >> (16 - 1)) & 1u;
+ uint64_t top = (p_rs1 >> (16 - rev));
+ uint64_t need = sign ? ((uint64_t{1} << rev) - 1) : 0u;
+ ov = (top != need);
+ if(ov)
+ p_rd = (uint16_t)(sign ? bits_SMIN : bits_SMAX);
+ else
+ p_rd = (uint16_t)((p_rs1 << rev) & mask);
+ }
+ }
+ if (ov) P.VU.vxsat->write(1);
+}) \ No newline at end of file