../src/lowrisc_ibex_ibex_core_0.1/rtl/ibex_multdiv_slow.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
   3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   4: // SPDX-License-Identifier: Apache-2.0
   5: 
   6: /**
   7:  * Slow Multiplier and Division
   8:  *
   9:  * Baugh-Wooley multiplier and Long Division
  10:  */
  11: 
  12: `include "prim_assert.sv"
  13: 
  14: module ibex_multdiv_slow
  15: (
  16:     input  logic             clk_i,
  17:     input  logic             rst_ni,
  18:     input  logic             mult_en_i,  // dynamic enable signal, for FSM control
  19:     input  logic             div_en_i,   // dynamic enable signal, for FSM control
  20:     input  logic             mult_sel_i, // static decoder output, for data muxes
  21:     input  logic             div_sel_i,  // static decoder output, for data muxes
  22:     input  ibex_pkg::md_op_e operator_i,
  23:     input  logic  [1:0]      signed_mode_i,
  24:     input  logic [31:0]      op_a_i,
  25:     input  logic [31:0]      op_b_i,
  26:     input  logic [33:0]      alu_adder_ext_i,
  27:     input  logic [31:0]      alu_adder_i,
  28:     input  logic             equal_to_zero_i,
  29:     input  logic             data_ind_timing_i,
  30: 
  31:     output logic [32:0]      alu_operand_a_o,
  32:     output logic [32:0]      alu_operand_b_o,
  33: 
  34:     input  logic [33:0]      imd_val_q_i,
  35:     output logic [33:0]      imd_val_d_o,
  36:     output logic             imd_val_we_o,
  37: 
  38:     input  logic             multdiv_ready_id_i,
  39: 
  40:     output logic [31:0]      multdiv_result_o,
  41: 
  42:     output logic             valid_o
  43: );
  44: 
  45:   import ibex_pkg::*;
  46: 
  47:   typedef enum logic [2:0] {
  48:     MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
  49:   } md_fsm_e;
  50:   md_fsm_e md_state_q, md_state_d;
  51: 
  52:   logic [32:0] accum_window_q, accum_window_d;
  53:   logic        unused_imd_val;
  54: 
  55:   logic [32:0] res_adder_l;
  56:   logic [32:0] res_adder_h;
  57: 
  58:   logic [ 4:0] multdiv_count_q, multdiv_count_d;
  59:   logic [32:0] op_b_shift_q, op_b_shift_d;
  60:   logic [32:0] op_a_shift_q, op_a_shift_d;
  61:   logic [32:0] op_a_ext, op_b_ext;
  62:   logic [32:0] one_shift;
  63:   logic [32:0] op_a_bw_pp, op_a_bw_last_pp;
  64:   logic [31:0] b_0;
  65:   logic        sign_a, sign_b;
  66:   logic [32:0] next_quotient;
  67:   logic [31:0] next_remainder;
  68:   logic [31:0] op_numerator_q, op_numerator_d;
  69:   logic        is_greater_equal;
  70:   logic        div_change_sign, rem_change_sign;
  71:   logic        div_by_zero_d, div_by_zero_q;
  72:   logic        multdiv_hold;
  73:   logic        multdiv_en;
  74: 
  75:    // (accum_window_q + op_a_shift_q)
  76:   assign res_adder_l = alu_adder_ext_i[32:0];
  77:    // (accum_window_q + op_a_shift_q)>>1
  78:   assign res_adder_h = alu_adder_ext_i[33:1];
  79: 
  80:   /////////////////////
  81:   // ALU Operand MUX //
  82:   /////////////////////
  83: 
  84:   // Use shared intermediate value register in id_stage for accum_window
  85:   assign imd_val_d_o    = {1'b0,accum_window_d};
  86:   assign imd_val_we_o   = ~multdiv_hold;
  87:   assign accum_window_q = imd_val_q_i[32:0];
  88:   assign unused_imd_val = imd_val_q_i[33];
  89: 
  90:   always_comb begin
  91:     alu_operand_a_o = accum_window_q;
  92: 
  93:     unique case(operator_i)
  94: 
  95:       MD_OP_MULL: begin
  96:         alu_operand_b_o = op_a_bw_pp;
  97:       end
  98: 
  99:       MD_OP_MULH: begin
 100:         alu_operand_b_o = (md_state_q == MD_LAST) ? op_a_bw_last_pp : op_a_bw_pp;
 101:       end
 102: 
 103:       MD_OP_DIV,
 104:       MD_OP_REM: begin
 105:         unique case(md_state_q)
 106:           MD_IDLE: begin
 107:             // 0 - B = 0 iff B == 0
 108:             alu_operand_a_o = {32'h0  , 1'b1};
 109:             alu_operand_b_o = {~op_b_i, 1'b1};
 110:           end
 111:           MD_ABS_A: begin
 112:             // ABS(A) = 0 - A
 113:             alu_operand_a_o = {32'h0  , 1'b1};
 114:             alu_operand_b_o = {~op_a_i, 1'b1};
 115:           end
 116:           MD_ABS_B: begin
 117:             // ABS(B) = 0 - B
 118:             alu_operand_a_o = {32'h0  , 1'b1};
 119:             alu_operand_b_o = {~op_b_i, 1'b1};
 120:           end
 121:           MD_CHANGE_SIGN: begin
 122:             // ABS(Quotient) = 0 - Quotient (or Reminder)
 123:             alu_operand_a_o = {32'h0  , 1'b1};
 124:             alu_operand_b_o = {~accum_window_q[31:0], 1'b1};
 125:           end
 126:           default: begin
 127:             // Division
 128:             alu_operand_a_o = {accum_window_q[31:0], 1'b1}; // it contains the remainder
 129:             alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1};  // -denominator two's compliment
 130:           end
 131:         endcase
 132:       end
 133:       default: begin
 134:         alu_operand_a_o = accum_window_q;
 135:         alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1};
 136:       end
 137:     endcase
 138:   end
 139: 
 140:   // Multiplier partial product calculation
 141:   assign b_0             = {32{op_b_shift_q[0]}};
 142:   assign op_a_bw_pp      = { ~(op_a_shift_q[32] & op_b_shift_q[0]),  (op_a_shift_q[31:0] & b_0) };
 143:   assign op_a_bw_last_pp = {  (op_a_shift_q[32] & op_b_shift_q[0]), ~(op_a_shift_q[31:0] & b_0) };
 144: 
 145:   // Sign extend the input operands
 146:   assign sign_a   = op_a_i[31] & signed_mode_i[0];
 147:   assign sign_b   = op_b_i[31] & signed_mode_i[1];
 148: 
 149:   assign op_a_ext = {sign_a, op_a_i};
 150:   assign op_b_ext = {sign_b, op_b_i};
 151: 
 152:   // Divider calculations
 153: 
 154:   // The adder in the ALU computes Remainder - Divisor. If Remainder - Divisor >= 0,
 155:   // is_greater_equal is true, the next Remainder is the subtraction result and the Quotient
 156:   // multdiv_count_q-th bit is set to 1.
 157:   assign is_greater_equal = (accum_window_q[31] == op_b_shift_q[31]) ?
 158:       ~res_adder_h[31] : accum_window_q[31];
 159: 
 160:   assign one_shift      = {32'b0, 1'b1} << multdiv_count_q;
 161: 
 162:   assign next_remainder = is_greater_equal ? res_adder_h[31:0]        : accum_window_q[31:0];
 163:   assign next_quotient  = is_greater_equal ? op_a_shift_q | one_shift : op_a_shift_q;
 164: 
 165:   assign div_change_sign  = (sign_a ^ sign_b) & ~div_by_zero_q;
 166:   assign rem_change_sign  = sign_a;
 167: 
 168:   always_comb begin
 169:     multdiv_count_d  = multdiv_count_q;
 170:     accum_window_d   = accum_window_q;
 171:     op_b_shift_d     = op_b_shift_q;
 172:     op_a_shift_d     = op_a_shift_q;
 173:     op_numerator_d   = op_numerator_q;
 174:     md_state_d       = md_state_q;
 175:     multdiv_hold     = 1'b0;
 176:     div_by_zero_d    = div_by_zero_q;
 177:     if (mult_sel_i || div_sel_i) begin
 178:       unique case(md_state_q)
 179:         MD_IDLE: begin
 180:           unique case(operator_i)
 181:             MD_OP_MULL: begin
 182:               op_a_shift_d   = op_a_ext << 1;
 183:               accum_window_d = {       ~(op_a_ext[32]   &     op_b_i[0]),
 184:                                          op_a_ext[31:0] & {32{op_b_i[0]}}  };
 185:               op_b_shift_d   = op_b_ext >> 1;
 186:               // Proceed with multiplication by 0/1 in data-independent time mode
 187:               md_state_d     = (!data_ind_timing_i && ((op_b_ext >> 1) == 0)) ? MD_LAST : MD_COMP;
 188:             end
 189:             MD_OP_MULH: begin
 190:               op_a_shift_d   = op_a_ext;
 191:               accum_window_d = { 1'b1, ~(op_a_ext[32]   &     op_b_i[0]),
 192:                                          op_a_ext[31:1] & {31{op_b_i[0]}}  };
 193:               op_b_shift_d   = op_b_ext >> 1;
 194:               md_state_d     = MD_COMP;
 195:             end
 196:             MD_OP_DIV: begin
 197:               // Check if the denominator is 0
 198:               // quotient for division by 0 is specified to be -1
 199:               // Note with data-independent time option, the full divide operation will proceed as
 200:               // normal and will naturally return -1
 201:               accum_window_d = {33{1'b1}};
 202:               md_state_d     = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
 203:               // Record that this is a div by zero to stop the sign change at the end of the
 204:               // division (in data_ind_timing mode).
 205:               div_by_zero_d  = equal_to_zero_i;
 206:             end
 207:             MD_OP_REM: begin
 208:               // Check if the denominator is 0
 209:               // remainder for division by 0 is specified to be the numerator (operand a)
 210:               // Note with data-independent time option, the full divide operation will proceed as
 211:               // normal and will naturally return operand a
 212:               accum_window_d = op_a_ext;
 213:               md_state_d     = (!data_ind_timing_i && equal_to_zero_i) ? MD_FINISH : MD_ABS_A;
 214:             end
 215:             default:;
 216:           endcase
 217:           multdiv_count_d   = 5'd31;
 218:         end
 219: 
 220:         MD_ABS_A: begin
 221:           // quotient
 222:           op_a_shift_d   = '0;
 223:           // A abs value
 224:           op_numerator_d = sign_a ? alu_adder_i : op_a_i;
 225:           md_state_d     = MD_ABS_B;
 226:         end
 227: 
 228:         MD_ABS_B: begin
 229:           // remainder
 230:           accum_window_d = {32'h0,op_numerator_q[31]};
 231:           // B abs value
 232:           op_b_shift_d   = sign_b ? {1'b0,alu_adder_i} : {1'b0,op_b_i};
 233:           md_state_d     = MD_COMP;
 234:         end
 235: 
 236:         MD_COMP: begin
 237:           multdiv_count_d = multdiv_count_q - 5'h1;
 238:           unique case(operator_i)
 239:             MD_OP_MULL: begin
 240:               accum_window_d = res_adder_l;
 241:               op_a_shift_d   = op_a_shift_q << 1;
 242:               op_b_shift_d   = op_b_shift_q >> 1;
 243:               // Multiplication is complete once op_b is zero, unless in data_ind_timing mode where
 244:               // the maximum possible shift-add operations will be completed regardless of op_b
 245:               md_state_d     = ((!data_ind_timing_i && (op_b_shift_d == 0)) ||
 246:                                 (multdiv_count_q == 5'd1)) ? MD_LAST : MD_COMP;
 247:             end
 248:             MD_OP_MULH: begin
 249:               accum_window_d = res_adder_h;
 250:               op_a_shift_d   = op_a_shift_q;
 251:               op_b_shift_d   = op_b_shift_q >> 1;
 252:               md_state_d     = (multdiv_count_q == 5'd1) ? MD_LAST : MD_COMP;
 253:             end
 254:             MD_OP_DIV,
 255:             MD_OP_REM: begin
 256:               accum_window_d = {next_remainder[31:0], op_numerator_q[multdiv_count_d]};
 257:               op_a_shift_d   = next_quotient;
 258:               md_state_d     = (multdiv_count_q == 5'd1) ? MD_LAST : MD_COMP;
 259:             end
 260:             default: ;
 261:           endcase
 262:         end
 263: 
 264:         MD_LAST: begin
 265:           unique case(operator_i)
 266:             MD_OP_MULL: begin
 267:               accum_window_d = res_adder_l;
 268: 
 269:               // Note no state transition will occur if multdiv_hold is set
 270:               md_state_d   = MD_IDLE;
 271:               multdiv_hold = ~multdiv_ready_id_i;
 272:             end
 273:             MD_OP_MULH: begin
 274:               accum_window_d = res_adder_l;
 275:               md_state_d     = MD_IDLE;
 276: 
 277:               // Note no state transition will occur if multdiv_hold is set
 278:               md_state_d   = MD_IDLE;
 279:               multdiv_hold = ~multdiv_ready_id_i;
 280:             end
 281:             MD_OP_DIV: begin
 282:               // this time we save the quotient in accum_window_q since we do not need anymore the
 283:               // remainder
 284:               accum_window_d = next_quotient;
 285:               md_state_d     = MD_CHANGE_SIGN;
 286:             end
 287:             MD_OP_REM: begin
 288:               // this time we do not save the quotient anymore since we need only the remainder
 289:               accum_window_d = {1'b0, next_remainder[31:0]};
 290:               md_state_d     = MD_CHANGE_SIGN;
 291:             end
 292:             default: ;
 293:           endcase
 294:         end
 295: 
 296:         MD_CHANGE_SIGN: begin
 297:           md_state_d = MD_FINISH;
 298:           unique case(operator_i)
 299:             MD_OP_DIV:
 300:               accum_window_d = div_change_sign ? {1'b0,alu_adder_i} : accum_window_q;
 301:             MD_OP_REM:
 302:               accum_window_d = rem_change_sign ? {1'b0,alu_adder_i} : accum_window_q;
 303:             default: ;
 304:           endcase
 305:         end
 306: 
 307:         MD_FINISH: begin
 308:           // Note no state transition will occur if multdiv_hold is set
 309:           md_state_d   = MD_IDLE;
 310:           multdiv_hold = ~multdiv_ready_id_i;
 311:         end
 312: 
 313:         default: begin
 314:           md_state_d = MD_IDLE;
 315:         end
 316:       endcase // md_state_q
 317:     end // (mult_sel_i || div_sel_i)
 318:   end
 319: 
 320:   //////////////////////////////////////////
 321:   // Mutliplier / Divider state registers //
 322:   //////////////////////////////////////////
 323: 
 324:   assign multdiv_en = (mult_en_i | div_en_i) & ~multdiv_hold;
 325: 
 326:   always_ff @(posedge clk_i or negedge rst_ni) begin
 327:     if (!rst_ni) begin
 328:       multdiv_count_q  <= 5'h0;
 329:       op_b_shift_q     <= 33'h0;
 330:       op_a_shift_q     <= 33'h0;
 331:       op_numerator_q   <= 32'h0;
 332:       md_state_q       <= MD_IDLE;
 333:       div_by_zero_q    <= 1'b0;
 334:     end else if (multdiv_en) begin
 335:       multdiv_count_q  <= multdiv_count_d;
 336:       op_b_shift_q     <= op_b_shift_d;
 337:       op_a_shift_q     <= op_a_shift_d;
 338:       op_numerator_q   <= op_numerator_d;
 339:       md_state_q       <= md_state_d;
 340:       div_by_zero_q    <= div_by_zero_d;
 341:     end
 342:   end
 343: 
 344:   /////////////
 345:   // Outputs //
 346:   /////////////
 347: 
 348:   assign valid_o = (md_state_q == MD_FINISH) |
 349:                    (md_state_q == MD_LAST &
 350:                    (operator_i == MD_OP_MULL |
 351:                     operator_i == MD_OP_MULH));
 352: 
 353:   assign multdiv_result_o = div_en_i ? accum_window_q[31:0] : res_adder_l[31:0];
 354: 
 355:   ////////////////
 356:   // Assertions //
 357:   ////////////////
 358: 
 359:   // State must be valid.
 360:   `ASSERT(IbexMultDivStateValid, md_state_q inside {
 361:       MD_IDLE, MD_ABS_A, MD_ABS_B, MD_COMP, MD_LAST, MD_CHANGE_SIGN, MD_FINISH
 362:       }, clk_i, !rst_ni)
 363: 
 364: endmodule
 365: