blob: 79a9a1d49f88f57b3dc517a00f09b0abe95372cf [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
/**
* Scramble control for OTBN
*
* This provides a key and nonce for scrambling the OTBN IMem and DMem. The OTP
* key interface is used to request a new key and nonce when they are requested.
*/
module otbn_scramble_ctrl
import otbn_pkg::*;
#(
// Default seed and nonce for scrambling
parameter otp_ctrl_pkg::otbn_key_t RndCnstOtbnKey = otbn_pkg::RndCnstOtbnKeyDefault,
parameter otp_ctrl_pkg::otbn_nonce_t RndCnstOtbnNonce = otbn_pkg::RndCnstOtbnNonceDefault
) (
// OTBN clock
input clk_i,
input rst_ni,
// OTP Clock (for key interface)
input clk_otp_i,
input rst_otp_ni,
// OTP key interface
output otp_ctrl_pkg::otbn_otp_key_req_t otbn_otp_key_o,
input otp_ctrl_pkg::otbn_otp_key_rsp_t otbn_otp_key_i,
output otp_ctrl_pkg::otbn_key_t otbn_dmem_scramble_key_o,
output otbn_dmem_nonce_t otbn_dmem_scramble_nonce_o,
output logic otbn_dmem_scramble_valid_o,
output logic otbn_dmem_scramble_key_seed_valid_o,
output otp_ctrl_pkg::otbn_key_t otbn_imem_scramble_key_o,
output otbn_imem_nonce_t otbn_imem_scramble_nonce_o,
output logic otbn_imem_scramble_valid_o,
output logic otbn_imem_scramble_key_seed_valid_o,
input logic otbn_dmem_scramble_new_req_i,
input logic otbn_imem_scramble_new_req_i
);
typedef enum logic [1:0] {
ScrambleCtrlIdle,
ScrambleCtrlDmemReq,
ScrambleCtrlImemReq
} scramble_ctrl_state_t;
scramble_ctrl_state_t state_q, state_d;
logic dmem_key_valid_q, dmem_key_valid_d;
logic imem_key_valid_q, imem_key_valid_d;
logic dmem_key_seed_valid_q, dmem_key_seed_valid_d;
logic imem_key_seed_valid_q, imem_key_seed_valid_d;
logic dmem_scramble_req_pending_q, dmem_scramble_req_pending_d;
logic imem_scramble_req_pending_q, imem_scramble_req_pending_d;
logic dmem_key_nonce_en;
logic imem_key_nonce_en;
otp_ctrl_pkg::otbn_key_t dmem_key_q;
otp_ctrl_pkg::otbn_key_t imem_key_q;
otbn_dmem_nonce_t dmem_nonce_q;
otbn_imem_nonce_t imem_nonce_q;
logic otp_key_req, otp_key_ack;
otp_ctrl_pkg::otbn_key_t otp_key;
otp_ctrl_pkg::otbn_nonce_t otp_nonce;
logic otp_key_seed_valid;
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
dmem_key_q <= RndCnstOtbnKey;
dmem_nonce_q <= RndCnstOtbnNonce;
end else if (dmem_key_nonce_en) begin
dmem_key_q <= otp_key;
dmem_nonce_q <= otp_nonce;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
imem_key_q <= RndCnstOtbnKey;
imem_nonce_q <= RndCnstOtbnNonce;
end else if (imem_key_nonce_en) begin
imem_key_q <= otp_key;
imem_nonce_q <= otp_nonce;
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
// Initial key and nonce are taken from defaults so on reset a valid key
// is available.
dmem_key_valid_q <= 1'b1;
imem_key_valid_q <= 1'b1;
dmem_key_seed_valid_q <= 1'b0;
imem_key_seed_valid_q <= 1'b0;
dmem_scramble_req_pending_q <= 1'b0;
imem_scramble_req_pending_q <= 1'b0;
state_q <= ScrambleCtrlIdle;
end else begin
dmem_key_valid_q <= dmem_key_valid_d;
imem_key_valid_q <= imem_key_valid_d;
dmem_key_seed_valid_q <= dmem_key_seed_valid_d;
imem_key_seed_valid_q <= imem_key_seed_valid_d;
dmem_scramble_req_pending_q <= dmem_scramble_req_pending_d;
imem_scramble_req_pending_q <= imem_scramble_req_pending_d;
state_q <= state_d;
end
end
always_comb begin
dmem_key_valid_d = dmem_key_valid_q;
imem_key_valid_d = imem_key_valid_q;
dmem_key_seed_valid_d = dmem_key_seed_valid_q;
imem_key_seed_valid_d = imem_key_seed_valid_q;
dmem_key_nonce_en = 1'b0;
imem_key_nonce_en = 1'b0;
dmem_scramble_req_pending_d = dmem_scramble_req_pending_q | otbn_dmem_scramble_new_req_i;
imem_scramble_req_pending_d = imem_scramble_req_pending_q | otbn_imem_scramble_new_req_i;
state_d = state_q;
otp_key_req = 1'b0;
unique case (state_q)
ScrambleCtrlIdle: begin
if (dmem_scramble_req_pending_q) begin
otp_key_req = 1'b1;
dmem_key_valid_d = 1'b0;
state_d = ScrambleCtrlDmemReq;
end else if (imem_scramble_req_pending_q) begin
otp_key_req = 1'b1;
imem_key_valid_d = 1'b0;
state_d = ScrambleCtrlImemReq;
end
end
ScrambleCtrlDmemReq: begin
if (otp_key_ack) begin
state_d = ScrambleCtrlIdle;
dmem_scramble_req_pending_d = 1'b0;
dmem_key_nonce_en = 1'b1;
dmem_key_valid_d = 1'b1;
dmem_key_seed_valid_d = otp_key_seed_valid;
end
end ScrambleCtrlImemReq: begin
if (otp_key_ack) begin
state_d = ScrambleCtrlIdle;
imem_scramble_req_pending_d = 1'b0;
imem_key_nonce_en = 1'b1;
imem_key_valid_d = 1'b1;
imem_key_seed_valid_d = otp_key_seed_valid;
end
end
default: ;
endcase
end
prim_sync_reqack_data #(
.Width($bits(otp_ctrl_pkg::otbn_otp_key_rsp_t)-1),
.DataSrc2Dst(1'b0)
) u_otp_key_req_sync (
.clk_src_i (clk_i),
.rst_src_ni(rst_ni),
.clk_dst_i (clk_otp_i),
.rst_dst_ni(rst_otp_ni),
.req_chk_i (1'b1),
.src_req_i (otp_key_req),
.src_ack_o (otp_key_ack),
.dst_req_o (otbn_otp_key_o.req),
.dst_ack_i (otbn_otp_key_i.ack),
.data_i ({otbn_otp_key_i.key,
otbn_otp_key_i.nonce,
otbn_otp_key_i.seed_valid}),
.data_o ({otp_key,
otp_nonce,
otp_key_seed_valid})
);
assign otbn_dmem_scramble_key_o = dmem_key_q;
assign otbn_dmem_scramble_nonce_o = dmem_nonce_q;
assign otbn_dmem_scramble_valid_o = dmem_key_valid_q;
assign otbn_dmem_scramble_key_seed_valid_o = dmem_key_seed_valid_q;
assign otbn_imem_scramble_key_o = imem_key_q;
assign otbn_imem_scramble_nonce_o = imem_nonce_q;
assign otbn_imem_scramble_valid_o = imem_key_valid_q;
assign otbn_imem_scramble_key_seed_valid_o = imem_key_seed_valid_q;
endmodule