| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 |  | 
 | `include "prim_assert.sv" | 
 |  | 
 | /** | 
 |  * OTBN execute block for the base instruction subset | 
 |  * | 
 |  * This ALU supports the execution of all of OTBN's base instruction subset. | 
 |  */ | 
 | module otbn_alu_base | 
 |   import otbn_pkg::*; | 
 | ( | 
 |   // Block is combinatorial; clk/rst are for assertions only. | 
 |   input  logic                 clk_i, | 
 |   input  logic                 rst_ni, | 
 |  | 
 |   input  alu_base_operation_t  operation_i, | 
 |   input  alu_base_comparison_t comparison_i, | 
 |  | 
 |   output logic [31:0]          operation_result_o, | 
 |   output logic                 comparison_result_o | 
 | ); | 
 |  | 
 |   logic [32:0] adder_op_a, adder_op_b; | 
 |   logic        adder_op_b_negate; | 
 |   logic [33:0] adder_result; | 
 |  | 
 |   logic [31:0] and_result; | 
 |   logic [31:0] or_result; | 
 |   logic [31:0] xor_result; | 
 |   logic [31:0] not_result; | 
 |  | 
 |   logic  is_equal; | 
 |  | 
 |   /////////// | 
 |   // Adder // | 
 |   /////////// | 
 |  | 
 |   // Adder takes in 33-bit operands. The addition of the input operands occurs on bits [32:1], | 
 |   // setting addr_op_b_negate will cause a carry-in into bit 1. Combined with an inversion of | 
 |   // operation_i.operand_b this gives a two's-complement negation (~b + 1) | 
 |  | 
 |   assign adder_op_b_negate = operation_i.op == AluOpBaseSub; | 
 |  | 
 |   assign adder_op_a = {operation_i.operand_a, 1'b1}; | 
 |   assign adder_op_b = adder_op_b_negate ? {~operation_i.operand_b, 1'b1} : {operation_i.operand_b, 1'b0}; | 
 |  | 
 |   assign adder_result = adder_op_a + adder_op_b; | 
 |  | 
 |   ////////////////////////// | 
 |   // Bit-wise logical ops // | 
 |   ////////////////////////// | 
 |  | 
 |   assign and_result = operation_i.operand_a & operation_i.operand_b; | 
 |   assign or_result  = operation_i.operand_a | operation_i.operand_b; | 
 |   assign xor_result = operation_i.operand_a ^ operation_i.operand_b; | 
 |   assign not_result = ~operation_i.operand_a; | 
 |  | 
 |   ///////////// | 
 |   // Shifter // | 
 |   ///////////// | 
 |  | 
 |   logic [32:0] shift_in; | 
 |   logic [4:0]  shift_amt; | 
 |   logic [31:0] operand_a_reverse; | 
 |   logic [32:0] shift_out; | 
 |   logic [31:0] shift_out_reverse; | 
 |  | 
 |   for (genvar i = 0;i < 32; i++) begin : g_shifter_reverses | 
 |     assign operand_a_reverse[i] = operation_i.operand_a[31-i]; | 
 |     assign shift_out_reverse[i] = shift_out[31-i]; | 
 |   end | 
 |  | 
 |   assign shift_amt = operation_i.operand_b[4:0]; | 
 |   // Shifter performs right arithmetic 33-bit shifts. Force top bit to 0 to get logical shifting | 
 |   // otherwise replicate top bit of shift_in. Left shifts performed by reversing the input and | 
 |   // output. | 
 |   assign shift_in[31:0] = (operation_i.op == AluOpBaseSll) ? operand_a_reverse : operation_i.operand_a; | 
 |   assign shift_in[32] = (operation_i.op == AluOpBaseSra) ? operation_i.operand_a[31] : 1'b0; | 
 |  | 
 |   assign shift_out = signed'(shift_in) >>> shift_amt; | 
 |  | 
 |   //////////////// | 
 |   // Output Mux // | 
 |   //////////////// | 
 |  | 
 |   always_comb begin | 
 |     operation_result_o = adder_result[32:1]; | 
 |  | 
 |     unique case (operation_i.op) | 
 |       AluOpBaseAnd: operation_result_o = and_result; | 
 |       AluOpBaseOr:  operation_result_o = or_result; | 
 |       AluOpBaseXor: operation_result_o = xor_result; | 
 |       AluOpBaseNot: operation_result_o = not_result; | 
 |       AluOpBaseSra: operation_result_o = shift_out[31:0]; | 
 |       AluOpBaseSrl: operation_result_o = shift_out[31:0]; | 
 |       AluOpBaseSll: operation_result_o = shift_out_reverse; | 
 |       default: ; | 
 |     endcase | 
 |   end | 
 |  | 
 |   ///////////////// | 
 |   // Comparisons // | 
 |   ///////////////// | 
 |  | 
 |   // Dedicated comparator to deal with branches. As only Equal/Not-Equal is required no need to use | 
 |   // the adder (which frees it to compute the branch target in the same cycle). No point in using | 
 |   // existing XOR logic as area added from extra mux to choose xor operands negates area saving from | 
 |   // avoiding an dedicated comparator. | 
 |   assign is_equal = comparison_i.operand_a == comparison_i.operand_b; | 
 |  | 
 |   assign comparison_result_o = (comparison_i.op == ComparisonOpBaseEq) ? is_equal : ~is_equal; | 
 | endmodule |