diff --git a/Changes b/Changes index 55dd8249e..bc936324d 100644 --- a/Changes +++ b/Changes @@ -5,6 +5,8 @@ The contributors that suggested a given feature are shown in []. Thanks! * Verilator 3.905 devel +*** Fix shifts by more than 32-bit numbers, bug1174. [Clifford Wolf] + * Verilator 3.904 2017-05-30 diff --git a/include/verilated.h b/include/verilated.h index 39946a04f..a77ddde69 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1585,6 +1585,22 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l } return(owp); } +static inline WDataOutP VL_SHIFTL_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + return VL_ZERO_RESET_W(obits, owp); + } + } + return VL_SHIFTL_WWI(obits,lbits,32,owp,lwp,rwp[0]); +} +static inline IData VL_SHIFTL_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + return 0; + } + } + return VL_CLEAN_II(obits,obits,lhs<>32 or more + return VL_ZERO_RESET_W(obits, owp); + } + } + return VL_SHIFTR_WWI(obits,lbits,32,owp,lwp,rwp[0]); +} +static inline IData VL_SHIFTR_IIW(int obits,int,int rbits,IData lhs, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + return 0; + } + } + return VL_CLEAN_II(obits,obits,lhs>>rwp[0]); +} // EMIT_RULE: VL_SHIFTRS: oclean=false; lclean=clean, rclean==clean; static inline IData VL_SHIFTRS_III(int obits, int lbits, int, IData lhs, IData rhs) { @@ -1665,6 +1697,44 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa } return(owp); } +static inline WDataOutP VL_SHIFTRS_WWW(int obits,int lbits,int rbits,WDataOutP owp,WDataInP lwp, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + int lmsw = VL_WORDS_I(obits)-1; + IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]); + for (int i=0; i <= lmsw; i++) owp[i] = sign; + owp[lmsw] &= VL_MASK_I(lbits); + return owp; + } + } + return VL_SHIFTRS_WWI(obits,lbits,32,owp,lwp,rwp[0]); +} +static inline IData VL_SHIFTRS_IIW(int obits,int lbits,int rbits,IData lhs, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + IData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative + return VL_CLEAN_II(obits,obits,sign); + } + } + return VL_SHIFTRS_III(obits,lbits,32,lhs,rwp[0]); +} +static inline QData VL_SHIFTRS_QQW(int obits,int lbits,int rbits,QData lhs, WDataInP rwp) { + for (int i=1; i < VL_WORDS_I(rbits); i++) { + if (VL_UNLIKELY(rwp[i])) { // Huge shift 1>>32 or more + QData sign = -(lhs >> (lbits-1)); // ffff_ffff if negative + return VL_CLEAN_QQ(obits,obits,sign); + } + } + return VL_SHIFTRS_QQI(obits,lbits,32,lhs,rwp[0]); +} +static inline IData VL_SHIFTRS_IIQ(int obits,int lbits,int rbits,IData lhs, QData rhs) { + WData rwp[2]; VL_SET_WQ(rwp,rhs); + return VL_SHIFTRS_IIW(obits,lbits,rbits,lhs,rwp); +} +static inline QData VL_SHIFTRS_QQQ(int obits,int lbits,int rbits,QData lhs, QData rhs) { + WData rwp[2]; VL_SET_WQ(rwp,rhs); + return VL_SHIFTRS_QQW(obits,lbits,rbits,lhs,rwp); +} //=================================================================== // Bit selection diff --git a/test_regress/t/t_math_shift.v b/test_regress/t/t_math_shift.v index a2ca18556..e6b935073 100644 --- a/test_regress/t/t_math_shift.v +++ b/test_regress/t/t_math_shift.v @@ -5,13 +5,15 @@ module t (/*AUTOARG*/ // Outputs - ign, + ign, ign2, ign3, // Inputs clk ); input clk; output [31:0] ign; + output [3:0] ign2; + output [11:0] ign3; parameter [95:0] P6 = 6; localparam P64 = (1 << P6); @@ -23,6 +25,14 @@ module t (/*AUTOARG*/ reg [31:0] amt; assign ign = {31'h0, clk} >>> 4'bx; // bug760 + assign ign2 = {amt[1:0] >> {22{amt[5:2]}}, amt[1:0] << (0 <<< amt[5:2])}; // bug1174 + assign ign3 = {amt[1:0] >> {22{amt[5:2]}}, + amt[1:0] >> {11{amt[5:2]}}, + $signed(amt[1:0]) >>> {22{amt[5:2]}}, + $signed(amt[1:0]) >>> {11{amt[5:2]}}, + amt[1:0] << {22{amt[5:2]}}, + amt[1:0] << {11{amt[5:2]}}}; + always @* begin right = 32'h819b018a >> amt;