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: