blob: 61d9f7075fd08c2c6f0bd9d377c86b693b3fa4b2 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* State machine to handle actions that occur around the start and stop of OTBN.
*
* This recieves the start signals from the top-level and passes them on to the
* controller to begin execution when pre-start actions have finished.
*
* pre-start actions:
* - Seed LFSR for URND
*
* post-stop actions:
* - Internal Secure Wipe
* -Delete WDRs
* -Delete Base registers
* -Delete Accumulator
* -Delete Modulus
* -Reset stack
*/
`include "prim_assert.sv"
module otbn_start_stop_control
import otbn_pkg::*;
#(
// Enable internal secure wipe
parameter bit SecWipeEn = 1'b0
)(
input logic clk_i,
input logic rst_ni,
input logic start_i,
output logic controller_start_o,
output logic urnd_reseed_req_o,
input logic urnd_reseed_busy_i,
output logic urnd_advance_o,
input logic start_secure_wipe_i,
output logic secure_wipe_running_o,
output logic done_o,
output logic sec_wipe_wdr_o,
output logic sec_wipe_wdr_urnd_o,
output logic sec_wipe_base_o,
output logic sec_wipe_base_urnd_o,
output logic [4:0] sec_wipe_addr_o,
output logic sec_wipe_acc_urnd_o,
output logic sec_wipe_mod_urnd_o,
output logic sec_wipe_zero_o,
output logic ispr_init_o,
output logic state_reset_o
);
otbn_start_stop_state_e state_q, state_d;
logic addr_cnt_inc;
logic [4:0] addr_cnt_q, addr_cnt_d;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
state_q <= OtbnStartStopStateHalt;
end else begin
state_q <= state_d;
end
end
always_comb begin
urnd_reseed_req_o = 1'b0;
urnd_advance_o = 1'b0;
state_d = state_q;
ispr_init_o = 1'b0;
state_reset_o = 1'b0;
sec_wipe_wdr_o = 1'b0;
sec_wipe_wdr_urnd_o = 1'b0;
sec_wipe_base_o = 1'b0;
sec_wipe_base_urnd_o = 1'b0;
sec_wipe_acc_urnd_o = 1'b0;
sec_wipe_mod_urnd_o = 1'b0;
sec_wipe_zero_o = 1'b0;
addr_cnt_inc = 1'b0;
secure_wipe_running_o = 1'b0;
unique case (state_q)
OtbnStartStopStateHalt: begin
if (start_i) begin
urnd_reseed_req_o = 1'b1;
ispr_init_o = 1'b1;
state_reset_o = 1'b1;
state_d = OtbnStartStopStateUrndRefresh;
end
end
OtbnStartStopStateUrndRefresh: begin
if (!urnd_reseed_busy_i) begin
state_d = OtbnStartStopStateRunning;
end
end
OtbnStartStopStateRunning: begin
urnd_advance_o = 1'b1;
if (start_secure_wipe_i) begin
if (SecWipeEn) begin
state_d = OtbnStartStopSecureWipeWdrUrnd;
end
else begin
state_d = OtbnStartStopSecureWipeComplete;
end
end
end
// Writing random numbers to the wide data registers.
OtbnStartStopSecureWipeWdrUrnd: begin
urnd_advance_o = 1'b1;
addr_cnt_inc = 1'b1;
sec_wipe_wdr_o = 1'b1;
sec_wipe_wdr_urnd_o = 1'b1;
secure_wipe_running_o = 1'b1;
if (addr_cnt_q == 5'b11111) begin
state_d = OtbnStartStopSecureWipeAccModBaseUrnd;
end
end
// Writing random numbers to the accumulator, modulus and the base registers.
// addr_cnt_q wraps around to 0 when first moving to this state, and we need to
// supress writes to the zero register and the call stack.
OtbnStartStopSecureWipeAccModBaseUrnd: begin
secure_wipe_running_o = 1'b1;
urnd_advance_o = 1'b1;
addr_cnt_inc = 1'b1;
// The first two clock cycles are used to write random data to accumulator and modulus.
sec_wipe_acc_urnd_o = (addr_cnt_q == 5'b00000);
sec_wipe_mod_urnd_o = (addr_cnt_q == 5'b00001);
// Supress writes to the zero register and the call stack.
sec_wipe_base_o = (addr_cnt_q > 5'b00001);
sec_wipe_base_urnd_o = (addr_cnt_q > 5'b00001);
if (addr_cnt_q == 5'b11111) begin
state_d = OtbnStartStopSecureWipeAllZero;
end
end
// Writing zeros to the accumulator, modulus and the registers.
// Resetting stack
OtbnStartStopSecureWipeAllZero: begin
secure_wipe_running_o = 1'b1;
sec_wipe_zero_o = (addr_cnt_q == 5'b00000);
sec_wipe_wdr_o = 1'b1;
sec_wipe_base_o = (addr_cnt_q > 5'b00001);
addr_cnt_inc = 1'b1;
if (addr_cnt_q == 5'b11111) begin
state_d = OtbnStartStopSecureWipeComplete;
end
end
OtbnStartStopSecureWipeComplete: begin
urnd_advance_o = 1'b1;
secure_wipe_running_o = 1'b1;
state_d = OtbnStartStopStateHalt;
end
default: ;
endcase
end
// Logic separate from main FSM code to avoid false combinational loop warning from verilator
assign controller_start_o = (state_q == OtbnStartStopStateUrndRefresh) & !urnd_reseed_busy_i;
if (SecWipeEn) begin: gen_sec_wipe
assign done_o = (state_q == OtbnStartStopSecureWipeComplete);
end
else begin: gen_bypass_sec_wipe
assign done_o = start_secure_wipe_i;
end
assign addr_cnt_d = addr_cnt_inc ? (addr_cnt_q + 5'd1) : 5'd0;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
addr_cnt_q <= 5'd0;
end else
addr_cnt_q <= addr_cnt_d;
end
assign sec_wipe_addr_o = addr_cnt_q;
`ASSERT(StartStopStateValid,
state_q inside {OtbnStartStopStateHalt,
OtbnStartStopStateUrndRefresh,
OtbnStartStopStateRunning,
OtbnStartStopSecureWipeWdrUrnd,
OtbnStartStopSecureWipeAccModBaseUrnd,
OtbnStartStopSecureWipeAllZero,
OtbnStartStopSecureWipeComplete})
endmodule