aboutsummaryrefslogtreecommitdiff
path: root/riscv
diff options
context:
space:
mode:
authorDave.Wen <dave.wen@sifive.com>2019-04-25 01:50:46 -0700
committerDave.Wen <dave.wen@sifive.com>2019-04-25 01:50:46 -0700
commitf6ecc5bb21a690ef3c3a5c3b95259307ff5da938 (patch)
tree930871fd50c26ffe9c144171bda2a4ef9a7077d6 /riscv
parent4265438d34183efeccb377cbe5a2a444c7507827 (diff)
downloadspike-f6ecc5bb21a690ef3c3a5c3b95259307ff5da938.zip
spike-f6ecc5bb21a690ef3c3a5c3b95259307ff5da938.tar.gz
spike-f6ecc5bb21a690ef3c3a5c3b95259307ff5da938.tar.bz2
rvv: fix vsmulv[vx]
Diffstat (limited to 'riscv')
-rw-r--r--riscv/decode.h14
-rw-r--r--riscv/insns/vsmul_vv.h60
-rw-r--r--riscv/insns/vsmul_vx.h59
-rw-r--r--riscv/processor.h4
4 files changed, 76 insertions, 61 deletions
diff --git a/riscv/decode.h b/riscv/decode.h
index 885fd09..2ccaf69 100644
--- a/riscv/decode.h
+++ b/riscv/decode.h
@@ -921,20 +921,22 @@ enum VMUNARY0{
#define INT_ROUNDING(result, xrm, sew) \
switch(xrm){\
case VRM::RNU:\
- result += (1 << (sew - 2));\
- break;\
+ result += ((uint64_t)1 << (sew - 1));\
+ break;\
case VRM::RNE:\
- assert(true);\
+ if ((result & ((uint64_t)1 << (sew + 1))) == 0){\
+ result += ((uint64_t)1 << (sew - 1));\
+ }\
break;\
case VRM::RDN:\
result = (result >> (sew - 1)) << (sew - 1);\
break;\
case VRM::ROD:\
- if ((result & (1 << ((sew -1) - 1 ))) > 0){\
- result = ((result >> (sew - 1)) + 1) << (sew - 1);\
+ if ((result & ((uint64_t)1 << (sew + 1))) == 1){\
+ result += ((uint64_t)1 << (sew - 1));\
}\
break;\
- case VRM::INVALID_RM:\
+ case VRM::INVALID_RM:\
assert(true);\
}
// Seems that 0x0 doesn't work.
diff --git a/riscv/insns/vsmul_vv.h b/riscv/insns/vsmul_vv.h
index ba5243d..395a1b3 100644
--- a/riscv/insns/vsmul_vv.h
+++ b/riscv/insns/vsmul_vv.h
@@ -1,31 +1,39 @@
// vsmul: Signed saturating and rounding fractional multiply
-int64_t round = 0;
-VRM vrm = STATE.VU.get_vround_mode();
+VRM xrm = STATE.VU.get_vround_mode();
+int64_t int_max = (1 << STATE.VU.vsew) - 1;
+int64_t int_min = - (1 << (STATE.VU.vsew - 1));
+int64_t val_mask = ((1 << (STATE.VU.vsew - 1)) - 1);
+int64_t sign_mask = ((1 << (STATE.VU.vsew - 1)));
+
VI_VV_LOOP
({
- int64_t result = vsext(vs1 * vs2, sew * 2);
- // rounding
- switch(vrm){
- case VRM::RNU:
- result += (1 << (sew - 1) );
- break;
- case VRM::RNE:
- assert(true);
- break;
- case VRM::RDN:
- result = (result >> (sew - 1)) << (sew - 1);
- break;
- case VRM::ROD:
- if ((result & (1 << ((sew -1) - 1 ))) > 0){
- result = ((result >> (sew - 1)) + 1) << (sew - 1);
- }
- break;
- case VRM::INVALID_RM:
- assert(true);
- };
-
+ int64_t vs1_sign;
+ int64_t vs2_sign;
+ int64_t result_sign;
+
+ vs1_sign = vs1 & sign_mask;
+ vs2_sign = vs2 & sign_mask;
+ vs1 = vs1 & val_mask;
+ vs2 = vs2 & val_mask;
+ uint64_t result = vzext((uint64_t)vs1 * (uint64_t)vs2, sew * 2);
+ result_sign = vs1_sign ^ vs2_sign;
+ // rounding
+ INT_ROUNDING(result, xrm, sew);
+ // checking the overflow
+ uint64_t overflow = result & ((uint64_t)-1 << ((sew - 1) * 2));
+ // unsigned shifting to rs1
+ result = result >> (sew - 1);
+ result &= val_mask;
+ result |= result_sign;
+
// saturation
- if (result >= (int64_t)(2^(sew - 1)))
- result = (2^(sew - 1)) - 1;
-
+ if (overflow){
+ if (result_sign == 0){ // positive
+ result = int_max;
+ }else{
+ result = int_min;
+ }
+ STATE.VU.vxsat = 1;
+ }
+ vd = result;
})
diff --git a/riscv/insns/vsmul_vx.h b/riscv/insns/vsmul_vx.h
index 5cebfa7..7998868 100644
--- a/riscv/insns/vsmul_vx.h
+++ b/riscv/insns/vsmul_vx.h
@@ -1,31 +1,38 @@
// vsmul
-int64_t round = 0;
-VRM vrm = STATE.VU.get_vround_mode();
+VRM xrm = STATE.VU.get_vround_mode();
+int64_t int_max = (1 << STATE.VU.vsew) - 1;
+int64_t int_min = - (1 << (STATE.VU.vsew - 1));
+int64_t val_mask = ((1 << (STATE.VU.vsew - 1)) - 1);
+int64_t sign_mask = ((1 << (STATE.VU.vsew - 1)));
+
VI_VX_LOOP
({
- int64_t result = vsext(rs1 * vs2, sew * 2);
- // rounding
- switch(vrm){
- case VRM::RNU:
- result += (1 << (sew - 1) );
- break;
- case VRM::RNE:
- assert(true);
- break;
- case VRM::RDN:
- result = (result >> (sew - 1)) << (sew - 1);
- break;
- case VRM::ROD:
- if ((result & (1 << ((sew -1) - 1 ))) > 0){
- result = ((result >> (sew - 1)) + 1) << (sew - 1);
- }
- break;
- case VRM::INVALID_RM:
- assert(true);
- };
-
+ int64_t rs1_sign;
+ int64_t vs2_sign;
+ int64_t result_sign;
+
+ rs1_sign = rs1 & sign_mask;
+ vs2_sign = vs2 & sign_mask;
+ rs1 = rs1 & val_mask;
+ vs2 = vs2 & val_mask;
+ uint64_t result = vzext((uint64_t)rs1 * (uint64_t)vs2, sew * 2);
+ result_sign = rs1_sign ^ vs2_sign;
+ // rounding
+ INT_ROUNDING(result, xrm, sew);
+ // checking the overflow
+ uint64_t overflow = result & ((uint64_t)-1 << ((sew - 1) * 2));
+ result = result >> (sew - 1);
+ result &= val_mask;
+ result |= result_sign;
+
// saturation
- if (result >= (int64_t)(2^(sew - 1)))
- result = (2^(sew - 1)) - 1;
-
+ if (overflow){
+ if (result_sign == 0){ // positive
+ result = int_max;
+ }else{
+ result = int_min;
+ }
+ STATE.VU.vxsat = 1;
+ }
+ vd = result;
})
diff --git a/riscv/processor.h b/riscv/processor.h
index eae4581..ae15cc7 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -200,9 +200,7 @@ struct vectorUnit_t {
reg_t get_slen() { return SLEN; }
VRM get_vround_mode() {
- uint32_t rm = BITS(vxrm, 0, 2);
- assert( rm < VRM::INVALID_RM );
- return (VRM)rm;
+ return (VRM)vxrm;
}
};