blob: 8c22c8813e61c4fe0785b79cc37954281fcc3dc2 [file] [log] [blame]
// 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 [32: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;
logic signed [32:0] shift_in_signed;
assign shift_in_signed = signed'(shift_in);
assign shift_out = unsigned'(shift_in_signed >>> 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;
// The bottom bit of adder_result is discarded. It simply corresponds to the carry in used to
// produce twos complement subtraction from an addition.
logic unused_adder_result_bit;
// The top bit of shift_out is discarded. shift_in contains an extra bit to deal with sign
// extension which isn't needed in the shift_out result.
logic unused_shift_out_result_bit;
assign unused_shift_out_result_bit = shift_out[32];
assign unused_adder_result_bit = adder_result[0];
// clk_i, rst_ni are only used by assertions
logic unused_clk;
logic unused_rst_n;
assign unused_clk = clk_i;
assign unused_rst_n = rst_ni;
endmodule