blob: 368b3be2be29008b6f23277b50b8c2e020029351 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// AES counter for CTR mode
//
// This module uses a 16-bit counter to iteratively increment the 128-bit counter value.
`include "prim_assert.sv"
module aes_ctr(
input logic clk_i,
input logic rst_ni,
input logic incr_i,
output logic ready_o,
input logic [7:0][15:0] ctr_i, // 8 times 2 bytes
output logic [7:0][15:0] ctr_o, // 8 times 2 bytes
output logic [7:0] ctr_we_o
);
// Reverse byte order
function automatic logic [15:0][7:0] aes_rev_order_byte(logic [15:0][7:0] in);
logic [15:0][7:0] out;
for (int i=0; i<16; i++) begin
out[i] = in[15-i];
end
return out;
endfunction
// Reverse bit order
function automatic logic [7:0] aes_rev_order_bit(logic [7:0] in);
logic [7:0] out;
for (int i=0; i<8; i++) begin
out[i] = in[7-i];
end
return out;
endfunction
// Types
typedef enum logic {
IDLE, INCR
} aes_ctr_e;
// Signals
aes_ctr_e aes_ctr_ns, aes_ctr_cs;
logic [2:0] ctr_slice_idx_d, ctr_slice_idx_q;
logic ctr_carry_d, ctr_carry_q;
logic [7:0][15:0] ctr_i_rev; // 8 times 2 bytes
logic [7:0][15:0] ctr_o_rev; // 8 times 2 bytes
logic [7:0] ctr_we_o_rev;
logic ctr_we;
logic [15:0] ctr_i_slice;
logic [15:0] ctr_o_slice;
logic [16:0] ctr_value;
////////////
// Inputs //
////////////
// Reverse byte order
assign ctr_i_rev = aes_rev_order_byte(ctr_i);
/////////////
// Counter //
/////////////
// We do 16 bits at a time.
assign ctr_i_slice = ctr_i_rev[ctr_slice_idx_q];
assign ctr_value = ctr_i_slice + {15'b0, ctr_carry_q};
assign ctr_o_slice = ctr_value[15:0];
/////////////
// Control //
/////////////
// FSM
always_comb begin : aes_ctr_fsm
// Outputs
ready_o = 1'b0;
ctr_we = 1'b0;
// FSM
aes_ctr_ns = aes_ctr_cs;
ctr_slice_idx_d = ctr_slice_idx_q;
ctr_carry_d = ctr_carry_q;
unique case (aes_ctr_cs)
IDLE: begin
ready_o = 1'b1;
if (incr_i) begin
// Initialize slice index and carry bit.
ctr_slice_idx_d = '0;
ctr_carry_d = 1'b1;
aes_ctr_ns = INCR;
end
end
INCR: begin
// Increment slice index.
ctr_slice_idx_d = ctr_slice_idx_q + 3'b1;
ctr_carry_d = ctr_value[16];
ctr_we = 1'b1;
if (ctr_slice_idx_q == 3'b111) begin
aes_ctr_ns = IDLE;
end
end
default: aes_ctr_ns = IDLE;
endcase
end
// Registers
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
aes_ctr_cs <= IDLE;
ctr_slice_idx_q <= '0;
ctr_carry_q <= '0;
end else begin
aes_ctr_cs <= aes_ctr_ns;
ctr_slice_idx_q <= ctr_slice_idx_d;
ctr_carry_q <= ctr_carry_d;
end
end
/////////////
// Outputs //
/////////////
// Combine input and counter output.
always_comb begin
ctr_o_rev = ctr_i_rev;
ctr_o_rev[ctr_slice_idx_q] = ctr_o_slice;
end
// Generate the sliced write enable.
always_comb begin
ctr_we_o_rev = '0;
ctr_we_o_rev[ctr_slice_idx_q] = ctr_we;
end
// Reverse byte and bit order.
assign ctr_o = aes_rev_order_byte(ctr_o_rev);
assign ctr_we_o = aes_rev_order_bit(ctr_we_o_rev);
////////////////
// Assertions //
////////////////
`ASSERT_KNOWN(AesCtrStateKnown, aes_ctr_cs)
endmodule