hw/vendor/lowrisc_ibex/rtl/ibex_alu.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:  * Arithmetic logic unit
   8:  */
   9: module ibex_alu (
  10:     input  ibex_pkg::alu_op_e operator_i,
  11:     input  logic [31:0]       operand_a_i,
  12:     input  logic [31:0]       operand_b_i,
  13: 
  14:     input  logic [32:0]       multdiv_operand_a_i,
  15:     input  logic [32:0]       multdiv_operand_b_i,
  16: 
  17:     input  logic              multdiv_en_i,
  18: 
  19:     output logic [31:0]       adder_result_o,
  20:     output logic [33:0]       adder_result_ext_o,
  21: 
  22:     output logic [31:0]       result_o,
  23:     output logic              comparison_result_o,
  24:     output logic              is_equal_result_o
  25: );
  26:   import ibex_pkg::*;
  27: 
  28:   logic [31:0] operand_a_rev;
  29:   logic [32:0] operand_b_neg;
  30: 
  31:   // bit reverse operand_a for left shifts and bit counting
  32:   for (genvar k = 0; k < 32; k++) begin : gen_rev_operand_a
  33:     assign operand_a_rev[k] = operand_a_i[31-k];
  34:   end
  35: 
  36:   ///////////
  37:   // Adder //
  38:   ///////////
  39: 
  40:   logic        adder_op_b_negate;
  41:   logic [32:0] adder_in_a, adder_in_b;
  42:   logic [31:0] adder_result;
  43: 
  44:   always_comb begin
  45:     adder_op_b_negate = 1'b0;
  46: 
  47:     unique case (operator_i)
  48:       // Adder OPs
  49:       ALU_SUB,
  50: 
  51:       // Comparator OPs
  52:       ALU_EQ,   ALU_NE,
  53:       ALU_GE,   ALU_GEU,
  54:       ALU_LT,   ALU_LTU,
  55:       ALU_SLT,  ALU_SLTU: adder_op_b_negate = 1'b1;
  56: 
  57:       default:;
  58:     endcase
  59:   end
  60: 
  61:   // prepare operand a
  62:   assign adder_in_a    = multdiv_en_i ? multdiv_operand_a_i : {operand_a_i,1'b1};
  63: 
  64:   // prepare operand b
  65:   assign operand_b_neg = {operand_b_i,1'b0} ^ {33{adder_op_b_negate}};
  66:   assign adder_in_b    = multdiv_en_i ? multdiv_operand_b_i : operand_b_neg ;
  67: 
  68:   // actual adder
  69:   assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
  70: 
  71:   assign adder_result       = adder_result_ext_o[32:1];
  72: 
  73:   assign adder_result_o     = adder_result;
  74: 
  75:   ///////////
  76:   // Shift //
  77:   ///////////
  78: 
  79:   logic        shift_left;         // should we shift left
  80:   logic        shift_arithmetic;
  81: 
  82:   logic  [4:0] shift_amt;          // amount of shift, to the right
  83:   logic [31:0] shift_op_a;         // input of the shifter
  84:   logic [31:0] shift_result;
  85:   logic [31:0] shift_right_result;
  86:   logic [31:0] shift_left_result;
  87: 
  88:   assign shift_amt = operand_b_i[4:0];
  89: 
  90:   assign shift_left = (operator_i == ALU_SLL);
  91: 
  92:   assign shift_arithmetic = (operator_i == ALU_SRA);
  93: 
  94:   // choose the bit reversed or the normal input for shift operand a
  95:   assign shift_op_a    = shift_left ? operand_a_rev : operand_a_i;
  96: 
  97:   // right shifts, we let the synthesizer optimize this
  98:   logic [32:0] shift_op_a_32;
  99:   assign shift_op_a_32 = {shift_arithmetic & shift_op_a[31], shift_op_a};
 100: 
 101:   // The MSB of shift_right_result_ext can safely be ignored. We just extend the input to always
 102:   // do arithmetic shifts.
 103:   logic signed [32:0] shift_right_result_signed;
 104:   logic        [32:0] shift_right_result_ext;
 105:   assign shift_right_result_signed = $signed(shift_op_a_32) >>> shift_amt[4:0];
 106:   assign shift_right_result_ext    = $unsigned(shift_right_result_signed);
 107:   assign shift_right_result        = shift_right_result_ext[31:0];
 108: 
 109:   // bit reverse the shift_right_result for left shifts
 110:   for (genvar j = 0; j < 32; j++) begin : gen_rev_shift_right_result
 111:     assign shift_left_result[j] = shift_right_result[31-j];
 112:   end
 113: 
 114:   assign shift_result = shift_left ? shift_left_result : shift_right_result;
 115: 
 116:   ////////////////
 117:   // Comparison //
 118:   ////////////////
 119: 
 120:   logic is_equal;
 121:   logic is_greater_equal;  // handles both signed and unsigned forms
 122:   logic cmp_signed;
 123: 
 124:   always_comb begin
 125:     cmp_signed = 1'b0;
 126: 
 127:     unique case (operator_i)
 128:       ALU_GE,
 129:       ALU_LT,
 130:       ALU_SLT: begin
 131:         cmp_signed = 1'b1;
 132:       end
 133: 
 134:       default:;
 135:     endcase
 136:   end
 137: 
 138:   assign is_equal = (adder_result == 32'b0);
 139:   assign is_equal_result_o = is_equal;
 140: 
 141:   // Is greater equal
 142:   always_comb begin
 143:     if ((operand_a_i[31] ^ operand_b_i[31]) == 1'b0) begin
 144:       is_greater_equal = (adder_result[31] == 1'b0);
 145:     end else begin
 146:       is_greater_equal = operand_a_i[31] ^ (cmp_signed);
 147:     end
 148:   end
 149: 
 150:   // GTE unsigned:
 151:   // (a[31] == 1 && b[31] == 1) => adder_result[31] == 0
 152:   // (a[31] == 0 && b[31] == 0) => adder_result[31] == 0
 153:   // (a[31] == 1 && b[31] == 0) => 1
 154:   // (a[31] == 0 && b[31] == 1) => 0
 155: 
 156:   // GTE signed:
 157:   // (a[31] == 1 && b[31] == 1) => adder_result[31] == 0
 158:   // (a[31] == 0 && b[31] == 0) => adder_result[31] == 0
 159:   // (a[31] == 1 && b[31] == 0) => 0
 160:   // (a[31] == 0 && b[31] == 1) => 1
 161: 
 162:   // generate comparison result
 163:   logic cmp_result;
 164: 
 165:   always_comb begin
 166:     cmp_result = is_equal;
 167: 
 168:     unique case (operator_i)
 169:       ALU_EQ:            cmp_result =  is_equal;
 170:       ALU_NE:            cmp_result = ~is_equal;
 171:       ALU_GE,  ALU_GEU:  cmp_result = is_greater_equal;
 172:       ALU_LT,  ALU_LTU,
 173:       ALU_SLT, ALU_SLTU: cmp_result = ~is_greater_equal;
 174: 
 175:       default:;
 176:     endcase
 177:   end
 178: 
 179:   assign comparison_result_o = cmp_result;
 180: 
 181:   ////////////////
 182:   // Result mux //
 183:   ////////////////
 184: 
 185:   always_comb begin
 186:     result_o   = '0;
 187: 
 188:     unique case (operator_i)
 189:       // Standard Operations
 190:       ALU_AND:  result_o = operand_a_i & operand_b_i;
 191:       ALU_OR:   result_o = operand_a_i | operand_b_i;
 192:       ALU_XOR:  result_o = operand_a_i ^ operand_b_i;
 193: 
 194:       // Adder Operations
 195:       ALU_ADD, ALU_SUB: result_o = adder_result;
 196: 
 197:       // Shift Operations
 198:       ALU_SLL,
 199:       ALU_SRL, ALU_SRA: result_o = shift_result;
 200: 
 201:       // Comparison Operations
 202:       ALU_EQ,   ALU_NE,
 203:       ALU_GE,   ALU_GEU,
 204:       ALU_LT,   ALU_LTU,
 205:       ALU_SLT,  ALU_SLTU: result_o = {31'h0,cmp_result};
 206: 
 207:       default:;
 208:     endcase
 209:   end
 210: 
 211: endmodule
 212: