blob: 23d2c39f5fbe512554784ed114fd0e0e0c3fd8ef [file] [log] [blame]
Greg Chadwickf7863442020-09-14 18:11:33 +01001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5`include "prim_assert.sv"
6
7/**
8 * OTBN alu block for the bignum instruction subset
9 *
10 * This ALU supports all of the 'plain' arithmetic and logic bignum instructions, BN.MULQACC is
Rupert Swarbrick70926b52021-05-27 09:44:03 +010011 * implemented in a separate block.
Greg Chadwickf7863442020-09-14 18:11:33 +010012 *
13 * One barrel shifter and two adders (X and Y) are implemented along with the logic operators
14 * (AND,OR,XOR,NOT).
15 *
16 * The adders have 256-bit operands with a carry_in and optional invert on the second operand. This
17 * can be used to implement subtraction (a - b == a + ~b + 1). BN.SUBB/BN.ADDC are implemented by
18 * feeding in the carry flag as carry in rather than a fixed 0 or 1.
19 *
20 * The shifter takes a 512-bit input (to implement BN.RSHI, concatenate and right shift) and shifts
21 * right by up to 256-bits. The lower (256-bit) half of the input and output can be reversed to
22 * allow left shift implementation. There is no concatenate and left shift instruction so reversing
23 * isn't required over the full width.
24 *
25 * The dataflow between the adders and shifter is in the diagram below. This arrangement allows the
26 * implementation of the pseudo-mod (BN.ADDM/BN.SUBM) instructions in a single cycle whilst
27 * minimising the critical path. The pseudo-mod instructions do not have a shifted input so X can
28 * compute the initial add/sub and Y computes the pseudo-mod result. For all other add/sub
29 * operations Y computes the operation with one of the inputs supplied by the shifter and the other
30 * from operand_a.
31 *
32 * Both adder X and the shifter get supplied with operand_a and operand_b from the operation_i
33 * input. In addition the shifter gets a shift amount (shift_amt) and can use 0 instead of
34 * operand_a. The shifter concatenates operand_a (or 0) and operand_b together before shifting with
35 * operand_a in the upper (256-bit) half {operand_a/0, operand_b}. This allows the shifter to pass
36 * through operand_b simply by not performing a shift.
37 *
38 * A 0
39 * | |
40 * \-----/
41 * \---/
42 * A B | B shift_amt
43 * | | | | |
44 * +-----------+ +-----------+
45 * | Adder X | | Shifter |
46 * +-----------+ +-----------+
47 * | |
48 * |----+ +----|
49 * | | | |
50 * X result | | Shifter result
51 * | |
52 * | | +-----------+
53 * A | | +---| MOD WSR |
54 * | | | | +-----------+
55 * \-----/ \-----/
56 * \---/ \---/
57 * | |
58 * | |
59 * +-----------+
60 * | Adder Y |
61 * +-----------+
62 * |
63 * Y result
64 */
65
66
67module otbn_alu_bignum
68 import otbn_pkg::*;
69(
70 input logic clk_i,
71 input logic rst_ni,
72
73 input alu_bignum_operation_t operation_i,
74 output logic [WLEN-1:0] operation_result_o,
Greg Chadwick009d9ee2021-04-26 16:25:51 +010075 output logic selection_flag_o,
Greg Chadwickf7863442020-09-14 18:11:33 +010076
77 input ispr_e ispr_addr_i,
78 input logic [31:0] ispr_base_wdata_i,
79 input logic [BaseWordsPerWLEN-1:0] ispr_base_wr_en_i,
80 input logic [WLEN-1:0] ispr_bignum_wdata_i,
81 input logic ispr_bignum_wr_en_i,
Greg Chadwickb5b86862021-04-09 15:49:43 +010082 input logic ispr_init_i,
Greg Chadwickf7863442020-09-14 18:11:33 +010083 output logic [WLEN-1:0] ispr_rdata_o,
84
Greg Chadwick94786452020-10-28 18:19:51 +000085 input logic [WLEN-1:0] ispr_acc_i,
86 output logic [WLEN-1:0] ispr_acc_wr_data_o,
87 output logic ispr_acc_wr_en_o,
88
Rupert Swarbrick8e016022020-11-19 16:59:02 +000089 input flags_t mac_operation_flags_i,
90 input flags_t mac_operation_flags_en_i,
91
Greg Chadwickb168ae92021-04-14 16:04:03 +010092 input logic [WLEN-1:0] rnd_data_i,
93 input logic [WLEN-1:0] urnd_data_i
Greg Chadwickf7863442020-09-14 18:11:33 +010094);
95 ///////////
96 // ISPRs //
97 ///////////
98
99 flags_t flags_q [NFlagGroups];
100 flags_t flags_d [NFlagGroups];
101 logic [NFlagGroups*FlagsWidth-1:0] flags_flattened;
102 logic [NFlagGroups-1:0] flags_en;
103 logic [NFlagGroups-1:0] is_operation_flag_group;
104 flags_t selected_flags;
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100105 flags_t adder_update_flags;
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000106 logic adder_update_flags_en, adder_update_flags_en_raw;
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100107 flags_t logic_update_flags;
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000108 logic logic_update_flags_en, logic_update_flags_en_raw;
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000109 flags_t mac_update_flags;
110 logic mac_update_flags_en;
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100111 logic ispr_update_flags_en;
112
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000113 assign adder_update_flags_en = operation_i.alu_flag_en & adder_update_flags_en_raw;
114 assign logic_update_flags_en = operation_i.alu_flag_en & logic_update_flags_en_raw;
115 assign mac_update_flags_en = operation_i.mac_flag_en;
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000116
Greg Chadwickb5b86862021-04-09 15:49:43 +0100117 assign ispr_update_flags_en = ispr_base_wr_en_i[0] & (ispr_addr_i == IsprFlags);
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000118
Greg Chadwick8a48d542020-11-12 12:19:52 +0000119 `ASSERT(UpdateFlagsOnehot,
Greg Chadwickb5b86862021-04-09 15:49:43 +0100120 $onehot0({ispr_init_i, adder_update_flags_en, logic_update_flags_en, mac_update_flags_en,
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000121 ispr_update_flags_en}))
122
123 assign selected_flags = flags_q[operation_i.flag_group];
124
125 assign mac_update_flags = (selected_flags & ~mac_operation_flags_en_i) |
126 (mac_operation_flags_i & mac_operation_flags_en_i);
Greg Chadwickf7863442020-09-14 18:11:33 +0100127
128 for (genvar i_fg = 0; i_fg < NFlagGroups; i_fg++) begin : g_flag_groups
129 always_ff @(posedge clk_i or negedge rst_ni) begin
130 if (!rst_ni) begin
Greg Chadwick6c632722020-10-08 17:59:18 +0100131 flags_q[i_fg] <= '{Z : 1'b0, L : 1'b0, M : 1'b0, C : 1'b0};
Greg Chadwickf7863442020-09-14 18:11:33 +0100132 end else if (flags_en[i_fg]) begin
133 flags_q[i_fg] <= flags_d[i_fg];
134 end
135 end
136
137 assign is_operation_flag_group[i_fg] = operation_i.flag_group == i_fg;
138
Greg Chadwickf7863442020-09-14 18:11:33 +0100139 assign flags_flattened[i_fg * FlagsWidth +: FlagsWidth] = flags_q[i_fg];
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100140
141 // Flag updates can come from the Y adder result, the logical operation result or from an ISPR
142 // write.
143 always_comb begin
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000144 flags_d[i_fg] = adder_update_flags;
145
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100146 unique case (1'b1)
Greg Chadwickb5b86862021-04-09 15:49:43 +0100147 ispr_init_i: flags_d[i_fg] = '0;
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100148 adder_update_flags_en: flags_d[i_fg] = adder_update_flags;
149 logic_update_flags_en: flags_d[i_fg] = logic_update_flags;
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000150 mac_update_flags_en: flags_d[i_fg] = mac_update_flags;
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000151 ispr_update_flags_en: flags_d[i_fg] = ispr_base_wdata_i[i_fg * FlagsWidth +: FlagsWidth];
152 default: ;
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100153 endcase
154 end
155
Greg Chadwickb5b86862021-04-09 15:49:43 +0100156 assign flags_en[i_fg] = ispr_init_i | ispr_update_flags_en |
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000157 (adder_update_flags_en & is_operation_flag_group[i_fg]) |
Rupert Swarbrick8e016022020-11-19 16:59:02 +0000158 (logic_update_flags_en & is_operation_flag_group[i_fg]) |
159 (mac_update_flags_en & is_operation_flag_group[i_fg]);
Greg Chadwickf7863442020-09-14 18:11:33 +0100160 end
161
Greg Chadwickf7863442020-09-14 18:11:33 +0100162
163 logic [WLEN-1:0] mod_q;
164 logic [WLEN-1:0] mod_d;
165 logic [BaseWordsPerWLEN-1:0] mod_wr_en;
166
167 for (genvar i_word = 0; i_word < BaseWordsPerWLEN; i_word++) begin : g_mod_words
168 always_ff @(posedge clk_i or negedge rst_ni) begin
169 if (!rst_ni) begin
170 mod_q[i_word*32+:32] <= '0;
171 end else if (mod_wr_en[i_word]) begin
172 mod_q[i_word*32+:32] <= mod_d[i_word*32+:32];
173 end
174 end
175
Greg Chadwickb5b86862021-04-09 15:49:43 +0100176 always_comb begin
177 mod_d[i_word*32+:32] = ispr_bignum_wdata_i[i_word*32+:32];
Greg Chadwickf7863442020-09-14 18:11:33 +0100178
Greg Chadwickb5b86862021-04-09 15:49:43 +0100179 unique case (1'b1)
180 ispr_init_i: mod_d[i_word*32+:32] = '0;
181 ispr_base_wr_en_i[i_word]: mod_d[i_word*32+:32] = ispr_base_wdata_i;
182 default: ;
183 endcase
184 end
185
186 `ASSERT(ModWrSelOneHot, $onehot0({ispr_init_i, ispr_base_wr_en_i[i_word]}))
187
188 assign mod_wr_en[i_word] = ispr_init_i |
189 ((ispr_addr_i == IsprMod) & (ispr_base_wr_en_i[i_word] | ispr_bignum_wr_en_i));
Greg Chadwickf7863442020-09-14 18:11:33 +0100190 end
191
Greg Chadwickb5b86862021-04-09 15:49:43 +0100192 assign ispr_acc_wr_en_o = ((ispr_addr_i == IsprAcc) & ispr_bignum_wr_en_i) | ispr_init_i;
193 assign ispr_acc_wr_data_o = ispr_init_i ? '0 : ispr_bignum_wdata_i;
Greg Chadwick94786452020-10-28 18:19:51 +0000194
Greg Chadwickf7863442020-09-14 18:11:33 +0100195 always_comb begin
196 ispr_rdata_o = mod_q;
197
198 unique case (ispr_addr_i)
199 IsprMod: ispr_rdata_o = mod_q;
Greg Chadwickb168ae92021-04-14 16:04:03 +0100200 IsprRnd: ispr_rdata_o = rnd_data_i;
201 IsprUrnd: ispr_rdata_o = urnd_data_i;
Greg Chadwick94786452020-10-28 18:19:51 +0000202 IsprAcc: ispr_rdata_o = ispr_acc_i;
Greg Chadwickf7863442020-09-14 18:11:33 +0100203 IsprFlags: ispr_rdata_o = {{(WLEN - (NFlagGroups * FlagsWidth)){1'b0}}, flags_flattened};
204 default: ;
205 endcase
206 end
207
208 /////////////
209 // Shifter //
210 /////////////
211
212 logic shift_right;
213 logic [WLEN-1:0] shifter_in_upper, shifter_in_lower, shifter_in_lower_reverse;
214 logic [WLEN*2-1:0] shifter_in;
215 logic [WLEN*2-1:0] shifter_out;
Philipp Wagner711d2262021-01-21 18:17:42 +0000216 logic [WLEN-1:0] shifter_out_lower_reverse, shifter_res, unused_shifter_out_upper;
Greg Chadwickf7863442020-09-14 18:11:33 +0100217
218 assign shifter_in_upper = operation_i.op == AluOpBignumRshi ? operation_i.operand_a : '0;
219 assign shifter_in_lower = operation_i.operand_b;
220
221 for (genvar i = 0; i < WLEN; i++) begin : g_shifter_in_lower_reverse
222 assign shifter_in_lower_reverse[i] = shifter_in_lower[WLEN - i - 1];
223 end
224
225 assign shifter_in = {shifter_in_upper, shift_right ? shifter_in_lower :
226 shifter_in_lower_reverse};
227
228 assign shifter_out = shifter_in >> operation_i.shift_amt;
229
230 for (genvar i = 0; i < WLEN; i++) begin : g_shifter_out_lower_reverse
231 assign shifter_out_lower_reverse[i] = shifter_out[WLEN - i - 1];
232 end
233
234 assign shifter_res = shift_right ? shifter_out[WLEN-1:0] : shifter_out_lower_reverse;
235
Philipp Wagner711d2262021-01-21 18:17:42 +0000236 // Only the lower WLEN bits of the shift result are returned.
237 assign unused_shifter_out_upper = shifter_out[WLEN*2-1:WLEN];
238
Greg Chadwickf7863442020-09-14 18:11:33 +0100239 //////////////////
240 // Adders X & Y //
241 //////////////////
242
243 logic [WLEN:0] adder_x_op_a, adder_x_op_b;
244 logic adder_x_carry_in;
245 logic adder_x_op_b_invert;
246 logic [WLEN+1:0] adder_x_res;
247
248 logic [WLEN:0] adder_y_op_a, adder_y_op_b;
249 logic adder_y_carry_in;
250 logic adder_y_op_b_invert;
251 logic [WLEN+1:0] adder_y_res;
252
253 logic shift_mod_sel;
254 logic [WLEN-1:0] shift_mod_mux_out;
255 logic x_res_operand_a_sel;
256 logic [WLEN-1:0] x_res_operand_a_mux_out;
257
258 assign adder_x_op_a = {operation_i.operand_a, 1'b1};
259 assign adder_x_op_b = {adder_x_op_b_invert ? ~operation_i.operand_b : operation_i.operand_b,
260 adder_x_carry_in};
261
262 assign adder_x_res = adder_x_op_a + adder_x_op_b;
263
Philipp Wagnerdc946522020-12-03 10:52:58 +0000264 assign x_res_operand_a_mux_out = x_res_operand_a_sel ? adder_x_res[WLEN:1] :
265 operation_i.operand_a;
Greg Chadwickf7863442020-09-14 18:11:33 +0100266 assign shift_mod_mux_out = shift_mod_sel ? shifter_res : mod_q;
267
268 assign adder_y_op_a = {x_res_operand_a_mux_out, 1'b1};
269 assign adder_y_op_b = {adder_y_op_b_invert ? ~shift_mod_mux_out : shift_mod_mux_out,
270 adder_y_carry_in};
271
272 assign adder_y_res = adder_y_op_a + adder_y_op_b;
273
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100274 assign adder_update_flags.C = (operation_i.op == AluOpBignumAdd ||
275 operation_i.op == AluOpBignumAddc) ? adder_y_res[WLEN+1] :
276 ~adder_y_res[WLEN+1];
277 assign adder_update_flags.M = adder_y_res[WLEN];
278 assign adder_update_flags.L = adder_y_res[1];
279 assign adder_update_flags.Z = ~|adder_y_res[WLEN:1];
Greg Chadwickf7863442020-09-14 18:11:33 +0100280
Philipp Wagner711d2262021-01-21 18:17:42 +0000281 // The LSb of the adder results are unused.
282 logic unused_adder_x_res_lsb, unused_adder_y_res_lsb;
283 assign unused_adder_x_res_lsb = adder_x_res[0];
284 assign unused_adder_y_res_lsb = adder_y_res[0];
285
Greg Chadwickf7863442020-09-14 18:11:33 +0100286 //////////////////////////////
287 // Shifter & Adders control //
288 //////////////////////////////
289
290 always_comb begin
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000291 shift_right = 1'b0;
292 adder_x_carry_in = 1'b0;
293 adder_x_op_b_invert = 1'b0;
294 x_res_operand_a_sel = 1'b0;
295 shift_mod_sel = 1'b0;
296 adder_y_carry_in = 1'b0;
297 adder_y_op_b_invert = 1'b0;
298 adder_update_flags_en_raw = 1'b0;
299 logic_update_flags_en_raw = 1'b0;
Greg Chadwickf7863442020-09-14 18:11:33 +0100300
301 unique case (operation_i.op)
302 AluOpBignumAdd: begin
303 // Shifter computes B [>>|<<] shift_amt
304 // Y computes A + shifter_res
305 // X ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000306 shift_right = operation_i.shift_right;
307 x_res_operand_a_sel = 1'b0;
308 shift_mod_sel = 1'b1;
309 adder_y_carry_in = 1'b0;
310 adder_y_op_b_invert = 1'b0;
311 adder_update_flags_en_raw = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100312 end
313 AluOpBignumAddc: begin
314 // Shifter computes B [>>|<<] shift_amt
315 // Y computes A + shifter_res + flags.C
316 // X ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000317 shift_right = operation_i.shift_right;
318 x_res_operand_a_sel = 1'b0;
319 shift_mod_sel = 1'b1;
320 adder_y_carry_in = selected_flags.C;
321 adder_y_op_b_invert = 1'b0;
322 adder_update_flags_en_raw = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100323 end
324 AluOpBignumAddm: begin
325 // X computes A + B
326 // Y computes adder_x_res - mod = adder_x_res + ~mod + 1
327 // Shifter ignored
328 // Output mux chooses result based on top bit of X result (whether mod subtraction in
329 // Y should be applied or not)
330 adder_x_carry_in = 1'b0;
331 adder_x_op_b_invert = 1'b0;
332 x_res_operand_a_sel = 1'b1;
333 shift_mod_sel = 1'b0;
334 adder_y_carry_in = 1'b1;
335 adder_y_op_b_invert = 1'b1;
336 end
337 AluOpBignumSub: begin
338 // Shifter computes B [>>|<<] shift_amt
339 // Y computes A - shifter_res = A + ~shifter_res + 1
340 // X ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000341 shift_right = operation_i.shift_right;
342 x_res_operand_a_sel = 1'b0;
343 shift_mod_sel = 1'b1;
344 adder_y_carry_in = 1'b1;
345 adder_y_op_b_invert = 1'b1;
346 adder_update_flags_en_raw = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100347 end
348 AluOpBignumSubb: begin
349 // Shifter computes B [>>|<<] shift_amt
350 // Y computes A - shifter_res + ~flags.C = A + ~shifter_res + flags.C
351 // X ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000352 shift_right = operation_i.shift_right;
353 x_res_operand_a_sel = 1'b0;
354 shift_mod_sel = 1'b1;
355 adder_y_carry_in = ~selected_flags.C;
356 adder_y_op_b_invert = 1'b1;
357 adder_update_flags_en_raw = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100358 end
359 AluOpBignumSubm: begin
360 // X computes A - B = A + ~B + 1
361 // Y computes adder_x_res + mod
362 // Shifter ignored
363 // Output mux chooses result based on top bit of X result (whether subtraction in Y should
364 // be applied or not)
365 adder_x_carry_in = 1'b1;
366 adder_x_op_b_invert = 1'b1;
367 x_res_operand_a_sel = 1'b1;
368 shift_mod_sel = 1'b0;
369 adder_y_carry_in = 1'b0;
370 adder_y_op_b_invert = 1'b0;
371 end
372 AluOpBignumRshi: begin
373 // Shifter computes {A, B} >> shift_amt
374 // X, Y ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000375 shift_right = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100376 end
377 AluOpBignumXor,
378 AluOpBignumOr,
379 AluOpBignumAnd,
380 AluOpBignumNot: begin
381 // Shift computes one operand for the logical operation
382 // X & Y ignored
Greg Chadwick73cd46c2020-11-12 11:55:56 +0000383 shift_right = operation_i.shift_right;
384 logic_update_flags_en_raw = 1'b1;
Greg Chadwickf7863442020-09-14 18:11:33 +0100385 end
386 default: ;
387 endcase
388 end
389
390 ////////////////////////
391 // Logical operations //
392 ////////////////////////
393
394 logic [WLEN-1:0] logical_res;
395
396 always_comb begin
397 logical_res = ~operation_i.operand_a;
398
399 unique case (operation_i.op)
400 AluOpBignumXor: logical_res = operation_i.operand_a ^ shifter_res;
401 AluOpBignumOr: logical_res = operation_i.operand_a | shifter_res;
402 AluOpBignumAnd: logical_res = operation_i.operand_a & shifter_res;
403 AluOpBignumNot: logical_res = ~shifter_res;
404 default:;
405 endcase
406 end
407
Greg Chadwick3dcf49e2020-10-07 12:57:51 +0100408 // Logical operations only update M, L and Z; C must remain at its old value.
409 assign logic_update_flags.C = selected_flags.C;
410 assign logic_update_flags.M = logical_res[WLEN-1];
411 assign logic_update_flags.L = logical_res[0];
412 assign logic_update_flags.Z = ~|logical_res;
413
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100414 /////////////////////////////////
415 // Conditional Select Flag Mux //
416 /////////////////////////////////
Greg Chadwick8e235012020-10-08 17:04:02 +0100417
418 always_comb begin
419 unique case (operation_i.sel_flag)
Greg Chadwick009d9ee2021-04-26 16:25:51 +0100420 FlagC: selection_flag_o = selected_flags.C;
421 FlagL: selection_flag_o = selected_flags.L;
422 FlagM: selection_flag_o = selected_flags.M;
423 FlagZ: selection_flag_o = selected_flags.Z;
424 default: selection_flag_o = selected_flags.C;
Greg Chadwick8e235012020-10-08 17:04:02 +0100425 endcase
426 end
427
Greg Chadwick8e235012020-10-08 17:04:02 +0100428 ////////////////////////
Greg Chadwickf7863442020-09-14 18:11:33 +0100429 // Output multiplexer //
430 ////////////////////////
431
432 always_comb begin
433 operation_result_o = adder_y_res[WLEN:1];
434
435 unique case(operation_i.op)
436 AluOpBignumAdd,
437 AluOpBignumAddc,
438 AluOpBignumSub,
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100439 AluOpBignumSubb: begin
440 operation_result_o = adder_y_res[WLEN:1];
441 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100442
443 // For pseudo-mod operations the result depends upon initial a + b / a - b result that is
444 // computed in X. Operation to add/subtract mod (X + mod / X - mod) is computed in Y.
445 // Subtraction is computed using in the X & Y adders as a - b == a + ~b + 1. Note that for
446 // a - b the top bit of the result will be set if a - b >= 0 and otherwise clear.
447
448 // BN.ADDM - X = a + b, Y = X - mod, subtract mod if a + b >= mod
449 // * If X generates carry a + b > mod (as mod is 256-bit) - Select Y result
Philipp Wagner711d2262021-01-21 18:17:42 +0000450 // * If Y generates carry X - mod == (a + b) - mod >= 0 hence a + b >= mod, note this is only
451 // valid if X does not generate carry - Select Y result
Greg Chadwickf7863442020-09-14 18:11:33 +0100452 // * If neither happen a + b < mod - Select X result
453 AluOpBignumAddm: begin
454 if (adder_x_res[WLEN+1] || adder_y_res[WLEN+1]) begin
455 operation_result_o = adder_y_res[WLEN:1];
456 end else begin
457 operation_result_o = adder_x_res[WLEN:1];
458 end
459 end
460
461 // BN.SUBM - X = a - b, Y = X + mod, add mod if a - b < 0
462 // * If X generates carry a - b >= 0 - Select X result
463 // * Otherwise select Y result
464 AluOpBignumSubm: begin
465 if (adder_x_res[WLEN+1]) begin
466 operation_result_o = adder_x_res[WLEN:1];
467 end else begin
468 operation_result_o = adder_y_res[WLEN:1];
469 end
470 end
471
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100472 AluOpBignumRshi: begin
473 operation_result_o = shifter_res[WLEN-1:0];
474 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100475
476 AluOpBignumXor,
477 AluOpBignumOr,
478 AluOpBignumAnd,
Greg Chadwick9e858fb2020-10-12 17:39:16 +0100479 AluOpBignumNot: begin
480 operation_result_o = logical_res;
481 end
Greg Chadwickf7863442020-09-14 18:11:33 +0100482 default: ;
483 endcase
484 end
485endmodule