blob: 21ff7e0f833ddcf870a4d1c71ff70bac32e64591 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// TODO: this is only a first cut data path (not functional yet).
module otp_ctrl_scrmbl import otp_ctrl_pkg::*; (
input clk_i,
input rst_ni,
// input data and command
input [PresentBlockSize-1:0] data_i,
input otp_scrmbl_cmd_e cmd_i,
input valid_i,
output logic ready_o,
// output data
output logic [PresentBlockSize-1:0] data_o,
output logic valid_o
);
//////////////
// Datapath //
//////////////
logic [PresentKeySize-1:0] key_state_d, key_state_q;
logic [PresentBlockSize-1:0] data_state_d, data_state_low_q, data_state_high_q;
logic [PresentBlockSize-1:0] digest_state_d, digest_state_q;
logic [PresentBlockSize-1:0] enc_data_out, dec_data_out;
logic [PresentKeySize-1:0] dec_key_out, enc_key_out;
typedef enum logic [2:0] {SelEncDataOut,
SelDecDataOut,
SelDigestState,
SelDigestIV,
SelDataInput64} data_state_sel_e;
typedef enum logic [2:0] {SelDecKeyOut,
SelEncKeyOut,
SelDecKeyInit,
SelEncKeyInit,
SelDigestConst,
SelDataInput128} key_state_sel_e;
data_state_sel_e data_state_sel;
key_state_sel_e key_state_sel;
logic data_state_low_en, data_state_high_en, digest_state_en, key_state_en;
assign data_state_d = (data_state_sel == SelEncDataOut) ? enc_data_out :
(data_state_sel == SelDecDataOut) ? dec_data_out :
(data_state_sel == SelDigestState) ? digest_state_q :
(data_state_sel == SelDigestIV) ? OtpDigestIV :
data_i;
assign key_state_d = (key_state_sel == SelDecKeyOut) ? dec_key_out :
(key_state_sel == SelEncKeyOut) ? enc_key_out :
(key_state_sel == SelDecKeyInit) ? OtpDecKey :
(key_state_sel == SelEncKeyInit) ? OtpEncKey :
(key_state_sel == SelDigestConst) ? OtpDigestConst :
{data_state_high_q, data_state_low_q};
// TODO: might want to mask this with 0 if unused
assign enc_data_in = data_state_low_q;
assign dec_data_in = data_state_low_q;
assign dec_key_in = key_state_q;
assign enc_key_in = key_state_q;
assign digest_state_d = enc_data_out;
/////////////
// Counter //
/////////////
localparam int CntWidth = $clog2(NumPresentRounds+1);
logic [CntWidth-1:0] cnt_d, cnt_q;
logic cnt_clr, cnt_en;
assign cnt_d = (cnt_clr) ? '0 :
(cnt_en) ? cnt_q + 1 :
cnt_q;
/////////
// FSM //
/////////
typedef enum logic [1:0] {Idle, DecPass, EncPass, Digest} state_e;
state_e state_d, state_q;
logic valid_d, valid_q;
assign valid_o = valid_q;
always_comb begin : p_fsm
state_d = state_q;
data_state_sel = SelDataInput64;
key_state_sel = SelDataInput128;
data_state_low_en = 1'b0;
data_state_high_en = 1'b0;
key_state_en = 1'b0;
digest_state_en = 1'b0;
cnt_en = 1'b0;
cnt_clr = 1'b0;
valid_d = 1'b0;
ready_o = 1'b0;
unique case (state_q)
// Idle State: decode command and
// load working regs accordingly
Idle: begin
cnt_clr = 1'b1;
ready_o = 1'b1;
if (cmd_i == Decrypt && valid_i) begin
state_d = DecPass;
key_state_sel = SelDecKeyInit;
data_state_low_en = 1'b1;
key_state_en = 1'b1;
end else if (cmd_i == Encrypt && valid_i) begin
state_d = EncPass;
key_state_sel = SelEncKeyInit;
data_state_low_en = 1'b1;
key_state_en = 1'b1;
end else if (cmd_i == LoadLow && valid_i) begin
data_state_low_en = 1'b1;
end else if (cmd_i == LoadHigh && valid_i) begin
data_state_high_en = 1'b1;
end else if (cmd_i == DigestFirst && valid_i) begin
state_d = Digest;
data_state_sel = SelDigestIV;
data_state_low_en = 1'b1;
key_state_en = 1'b1;
end else if (cmd_i == DigestUpdate && valid_i) begin
state_d = Digest;
data_state_sel = SelDigestState;
data_state_low_en = 1'b1;
key_state_en = 1'b1;
end else if (cmd_i == DigestFinalize && valid_i) begin
state_d = Digest;
data_state_sel = SelDigestState;
key_state_sel = SelDigestConst;
data_state_low_en = 1'b1;
key_state_en = 1'b1;
end
// missing modes:
// 1) digest, then decrypt
// 2) encrypt, then digest
end
// perform 31 decrypt rounds
DecPass: begin
data_state_sel = SelDecDataOut;
key_state_sel = SelDecKeyOut;
digest_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
if (cnt_q == NumPresentRounds-1) begin
state_d = Idle;
valid_d = 1'b1;
end
end
// perform 31 encrypt rounds
EncPass: begin
data_state_sel = SelEncDataOut;
key_state_sel = SelEncKeyOut;
digest_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
if (cnt_q == NumPresentRounds-1) begin
state_d = Idle;
valid_d = 1'b1;
end
end
// perform 4 hashing rounds
// this uses the encrypt path
Digest: begin
data_state_sel = SelEncDataOut;
key_state_sel = SelEncKeyOut;
digest_state_en = 1'b1;
key_state_en = 1'b1;
cnt_en = 1'b1;
if (cnt_q == NumDigestRounds-1) begin
state_d = Idle;
valid_d = 1'b1;
// backup state digest for further updates
digest_state_en = 1'b1;
end
end
default: ;
endcase // state_q
end
/////////////////////////////
// PRESENT DEC/ENC Modules //
/////////////////////////////
prim_present #(
.KeyWidth(128),
.NumRounds(1)
) i_prim_present_enc (
.data_i ( enc_data_in ),
.key_i ( enc_key_in ),
.data_o ( enc_data_out ),
.key_o ( enc_key_out )
);
prim_present #(
.KeyWidth(128),
.NumRounds(1),
.Decrypt(1)
) i_prim_present_dec (
.data_i ( dec_data_in ),
.key_i ( dec_key_in ),
.data_o ( dec_data_out ),
.key_o ( dec_key_out )
);
///////////////
// Registers //
///////////////
always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs
if (!rst_ni) begin
state_q <= Idle;
cnt_q <= '0;
key_state_q <= '0;
data_state_low_q <= '0;
data_state_high_q <= '0;
digest_state_q <= '0;
valid_q <= 1'b0;
end else begin
state_q <= state_d;
cnt_q <= cnt_d;
valid_q <= valid_d;
// enable regs
if (key_state_en) begin
key_state_q <= key_state_d;
end
if (data_state_low_en) begin
data_state_low_q <= data_state_d;
end
if (data_state_high_en) begin
data_state_high_q <= data_state_d;
end
if (digest_state_en) begin
digest_state_q <= digest_state_d;
end
end
end
endmodule : otp_ctrl_scrmbl