| // 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 |