[otbn] Added sparse FSM encoding
Signed-off-by: Vladimir Rozic <vrozic@lowrisc.org>
diff --git a/hw/ip/otbn/dv/verilator/otbn_top_sim.sv b/hw/ip/otbn/dv/verilator/otbn_top_sim.sv
index 2ba9f74..ec13a2f 100644
--- a/hw/ip/otbn/dv/verilator/otbn_top_sim.sv
+++ b/hw/ip/otbn/dv/verilator/otbn_top_sim.sv
@@ -110,6 +110,7 @@
.illegal_bus_access_i ( 1'b0 ),
.lifecycle_escalation_i ( 1'b0 ),
.software_errs_fatal_i ( 1'b0 ),
+ .otbn_scramble_state_error_i ( 1'b0 ),
.sideload_key_shares_i ( sideload_key_shares ),
.sideload_key_shares_valid_i ( 2'b11 )
diff --git a/hw/ip/otbn/otbn.core b/hw/ip/otbn/otbn.core
index 3e9be37..cb571d9 100644
--- a/hw/ip/otbn/otbn.core
+++ b/hw/ip/otbn/otbn.core
@@ -15,6 +15,7 @@
- lowrisc:prim:cipher_pkg
- lowrisc:prim:mubi
- lowrisc:prim:crc32
+ - lowrisc:prim:sparse_fsm
- lowrisc:ip:keymgr_pkg
- lowrisc:ip:edn_pkg
- lowrisc:ip:otbn_pkg
diff --git a/hw/ip/otbn/rtl/otbn.sv b/hw/ip/otbn/rtl/otbn.sv
index 90d63fb..bafe5df 100644
--- a/hw/ip/otbn/rtl/otbn.sv
+++ b/hw/ip/otbn/rtl/otbn.sv
@@ -224,6 +224,8 @@
logic otbn_dmem_scramble_valid;
logic unused_otbn_dmem_scramble_key_seed_valid;
+ logic otbn_scramble_state_error;
+
otbn_scramble_ctrl #(
.RndCnstOtbnKey (RndCnstOtbnKey),
.RndCnstOtbnNonce(RndCnstOtbnNonce)
@@ -248,7 +250,9 @@
.otbn_imem_scramble_key_seed_valid_o(unused_otbn_imem_scramble_key_seed_valid),
.otbn_dmem_scramble_new_req_i(1'b0),
- .otbn_imem_scramble_new_req_i(1'b0)
+ .otbn_imem_scramble_new_req_i(1'b0),
+
+ .state_error_o(otbn_scramble_state_error)
);
prim_ram_1p_scr #(
@@ -959,6 +963,8 @@
.software_errs_fatal_i (software_errs_fatal_q),
+ .otbn_scramble_state_error_i (otbn_scramble_state_error),
+
.sideload_key_shares_i (keymgr_key_i.key),
.sideload_key_shares_valid_i ({2{keymgr_key_i.valid}})
);
@@ -1015,6 +1021,8 @@
.software_errs_fatal_i (software_errs_fatal_q),
+ .otbn_scramble_state_error_i (otbn_scramble_state_error),
+
.sideload_key_shares_i (keymgr_key_i.key),
.sideload_key_shares_valid_i ({2{keymgr_key_i.valid}})
);
@@ -1051,4 +1059,12 @@
// Constraint from package, check here as we cannot have `ASSERT_INIT in package
`ASSERT_INIT(WsrESizeMatchesParameter_A, $bits(wsr_e) == WsrNumWidth)
+
+ `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(OtbnStartStopFsmCheck_A,
+ u_otbn_core.u_otbn_start_stop_control.u_state_regs, alert_tx_o[1])
+ `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(OtbnControllerFsmCheck_A,
+ u_otbn_core.u_otbn_controller.u_state_regs, alert_tx_o[1])
+ `ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(OtbnScrambleCtrlFsmCheck_A,
+ u_otbn_scramble_ctrl.u_state_regs, alert_tx_o[1])
+
endmodule
diff --git a/hw/ip/otbn/rtl/otbn_controller.sv b/hw/ip/otbn/rtl/otbn_controller.sv
index 5e2fd16..8eb1f41 100644
--- a/hw/ip/otbn/rtl/otbn_controller.sv
+++ b/hw/ip/otbn/rtl/otbn_controller.sv
@@ -138,6 +138,8 @@
input logic illegal_bus_access_i,
input logic lifecycle_escalation_i,
input logic software_errs_fatal_i,
+ input logic start_stop_state_error_i,
+ input logic otbn_scramble_state_error_i,
input logic [1:0] sideload_key_shares_valid_i,
@@ -157,6 +159,7 @@
logic recoverable_err;
logic done_complete;
logic executing;
+ logic state_error;
logic insn_fetch_req_valid_raw;
logic [ImemAddrWidth-1:0] insn_fetch_req_addr_last;
@@ -304,7 +307,8 @@
err_bits_en = 1'b0;
prefetch_en_o = 1'b0;
- // TODO: Harden state machine
+ state_error = 1'b0;
+
unique case (state_q)
OtbnStateHalt: begin
if (start_i) begin
@@ -370,7 +374,9 @@
insn_fetch_req_valid_raw = 1'b0;
state_d = OtbnStateLocked;
end
- default: ;
+ default: begin
+ state_error = 1'b1;
+ end
endcase
// On any error immediately halt, either going to OtbnStateLocked or OtbnStateHalt depending on
@@ -427,7 +433,8 @@
assign err_bits.fatal_software = software_err & software_errs_fatal_i;
assign err_bits.lifecycle_escalation = lifecycle_escalation_i;
assign err_bits.illegal_bus_access = illegal_bus_access_i;
- assign err_bits.bad_internal_state = 0;
+ assign err_bits.bad_internal_state = start_stop_state_error_i | state_error |
+ otbn_scramble_state_error_i;
assign err_bits.bus_intg_violation = bus_intg_violation_i;
assign err_bits.reg_intg_violation = rf_base_rd_data_err_i | rf_bignum_rd_data_err_i;
assign err_bits.dmem_intg_violation = lsu_rdata_err_i;
@@ -459,6 +466,7 @@
assign fatal_err = |{err_bits.fatal_software,
err_bits.lifecycle_escalation,
err_bits.illegal_bus_access,
+ err_bits.bad_internal_state ,
err_bits.bus_intg_violation,
err_bits.reg_intg_violation,
err_bits.dmem_intg_violation,
@@ -511,13 +519,20 @@
`ASSERT(NoStallOnBranch,
insn_valid_i & insn_dec_shared_i.branch_insn |-> state_q != OtbnStateStall)
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- state_q <= OtbnStateHalt;
- end else begin
- state_q <= state_d;
- end
- end
+ // This primitive is used to place a size-only constraint on the
+ // flops in order to prevent FSM state encoding optimizations.
+ logic [StateControllerWidth-1:0] state_raw_q;
+ assign state_q = otbn_state_e'(state_raw_q);
+ prim_sparse_fsm_flop #(
+ .StateEnumT(otbn_state_e),
+ .Width(StateControllerWidth),
+ .ResetValue(StateControllerWidth'(OtbnStateHalt))
+ ) u_state_regs (
+ .clk_i,
+ .rst_ni,
+ .state_i ( state_d ),
+ .state_o ( state_raw_q )
+ );
assign insn_cnt_clear = state_reset_i | (state_q == OtbnStateLocked) | insn_cnt_clear_i;
diff --git a/hw/ip/otbn/rtl/otbn_core.sv b/hw/ip/otbn/rtl/otbn_core.sv
index 0f72f08..e7ec7f1 100644
--- a/hw/ip/otbn/rtl/otbn_core.sv
+++ b/hw/ip/otbn/rtl/otbn_core.sv
@@ -84,6 +84,9 @@
// When set software errors become fatal errors.
input logic software_errs_fatal_i,
+ // Indicates an invalid state of the scramble controller. Results in a fatal error.
+ input logic otbn_scramble_state_error_i,
+
input logic [1:0] sideload_key_shares_valid_i,
input logic [1:0][SideloadKeyWidth-1:0] sideload_key_shares_i
);
@@ -214,6 +217,8 @@
logic [ImemAddrWidth:0] prefetch_loop_end_addr;
logic [ImemAddrWidth-1:0] prefetch_loop_jump_addr;
+ logic start_stop_state_error;
+
// Start stop control start OTBN execution when requested and deals with any pre start or post
// stop actions.
otbn_start_stop_control #(
@@ -245,7 +250,8 @@
.sec_wipe_zero_o (sec_wipe_zero),
.ispr_init_o (ispr_init),
- .state_reset_o(state_reset)
+ .state_reset_o(state_reset),
+ .state_error_o(start_stop_state_error)
);
// Depending on its usage, the instruction address (program counter) is qualified by two valid
@@ -423,6 +429,8 @@
.illegal_bus_access_i,
.lifecycle_escalation_i,
.software_errs_fatal_i,
+ .start_stop_state_error_i(start_stop_state_error),
+ .otbn_scramble_state_error_i,
.sideload_key_shares_valid_i,
diff --git a/hw/ip/otbn/rtl/otbn_pkg.sv b/hw/ip/otbn/rtl/otbn_pkg.sv
index f9708a0..63d92ec 100644
--- a/hw/ip/otbn/rtl/otbn_pkg.sv
+++ b/hw/ip/otbn/rtl/otbn_pkg.sv
@@ -385,24 +385,90 @@
} mac_bignum_operation_t;
// States for controller state machine
- typedef enum logic [2:0] {
- OtbnStateHalt,
- OtbnStateUrndRefresh,
- OtbnStateRun,
- OtbnStateStall,
- OtbnStateLocked
+ // Encoding generated with:
+ // $ ./util/design/sparse-fsm-encode.py -d 3 -m 5 -n 6 \
+ // -s 5799399942 --language=sv
+ //
+ // Hamming distance histogram:
+ //
+ // 0: --
+ // 1: --
+ // 2: --
+ // 3: |||||||||||||||||||| (50.00%)
+ // 4: |||||||||||||||| (40.00%)
+ // 5: |||| (10.00%)
+ // 6: --
+ //
+ // Minimum Hamming distance: 3
+ // Maximum Hamming distance: 5
+ // Minimum Hamming weight: 1
+ // Maximum Hamming weight: 4
+ //
+ localparam int StateControllerWidth = 6;
+ typedef enum logic [StateControllerWidth-1:0] {
+ OtbnStateHalt = 6'b001000,
+ OtbnStateUrndRefresh = 6'b010100,
+ OtbnStateRun = 6'b100101,
+ OtbnStateStall = 6'b110011,
+ OtbnStateLocked = 6'b001111
} otbn_state_e;
- typedef enum logic [2:0] {
- OtbnStartStopStateHalt,
- OtbnStartStopStateUrndRefresh,
- OtbnStartStopStateRunning,
- OtbnStartStopSecureWipeWdrUrnd,
- OtbnStartStopSecureWipeAccModBaseUrnd,
- OtbnStartStopSecureWipeAllZero,
- OtbnStartStopSecureWipeComplete
+ // States for start_stop_controller
+ // Encoding generated with:
+ // $ ./util/design/sparse-fsm-encode.py -d 3 -m 7 -n 6 \
+ // -s 5799399943 --language=sv
+ //
+ // Hamming distance histogram:
+ //
+ // 0: --
+ // 1: --
+ // 2: --
+ // 3: |||||||||||||||||||| (57.14%)
+ // 4: ||||||||||||||| (42.86%)
+ // 5: --
+ // 6: --
+ //
+ // Minimum Hamming distance: 3
+ // Maximum Hamming distance: 4
+ // Minimum Hamming weight: 1
+ // Maximum Hamming weight: 5
+ //
+ localparam int StateStartStopWidth = 6;
+ typedef enum logic [StateStartStopWidth-1:0] {
+ OtbnStartStopStateHalt = 6'b011100,
+ OtbnStartStopStateUrndRefresh = 6'b101111,
+ OtbnStartStopStateRunning = 6'b010111,
+ OtbnStartStopSecureWipeWdrUrnd = 6'b000010,
+ OtbnStartStopSecureWipeAccModBaseUrnd = 6'b110001,
+ OtbnStartStopSecureWipeAllZero = 6'b001001,
+ OtbnStartStopSecureWipeComplete = 6'b100100
} otbn_start_stop_state_e;
+// Encoding generated with:
+// $ ./util/design/sparse-fsm-encode.py -d 3 -m 3 -n 5 \
+// -s 5799399983 --language=sv
+//
+// Hamming distance histogram:
+//
+// 0: --
+// 1: --
+// 2: --
+// 3: |||||||||||||||||||| (66.67%)
+// 4: |||||||||| (33.33%)
+// 5: --
+//
+// Minimum Hamming distance: 3
+// Maximum Hamming distance: 4
+// Minimum Hamming weight: 1
+// Maximum Hamming weight: 3
+//
+localparam int StateScrambleCtrlWidth = 5;
+typedef enum logic [StateScrambleCtrlWidth-1:0] {
+ ScrambleCtrlIdle = 5'b01101,
+ ScrambleCtrlDmemReq = 5'b10000,
+ ScrambleCtrlImemReq = 5'b00110
+} scramble_ctrl_state_e;
+
// URNG PRNG default seed.
// These parameters have been generated with
// $ ./util/design/gen-lfsr-seed.py --width 256 --seed 2840984437 --prefix "Urnd"
diff --git a/hw/ip/otbn/rtl/otbn_scramble_ctrl.sv b/hw/ip/otbn/rtl/otbn_scramble_ctrl.sv
index 79a9a1d..7f71ed0 100644
--- a/hw/ip/otbn/rtl/otbn_scramble_ctrl.sv
+++ b/hw/ip/otbn/rtl/otbn_scramble_ctrl.sv
@@ -38,15 +38,12 @@
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;
+ input logic otbn_imem_scramble_new_req_i,
- scramble_ctrl_state_t state_q, state_d;
+ output logic state_error_o
+);
+
+ scramble_ctrl_state_e state_q, state_d;
logic dmem_key_valid_q, dmem_key_valid_d;
logic imem_key_valid_q, imem_key_valid_d;
@@ -101,7 +98,6 @@
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;
@@ -109,10 +105,24 @@
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
+ // This primitive is used to place a size-only constraint on the
+ // flops in order to prevent FSM state encoding optimizations.
+ logic [StateScrambleCtrlWidth-1:0] state_raw_q;
+ assign state_q = scramble_ctrl_state_e'(state_raw_q);
+ prim_sparse_fsm_flop #(
+ .StateEnumT(scramble_ctrl_state_e),
+ .Width(StateScrambleCtrlWidth),
+ .ResetValue(StateScrambleCtrlWidth'(ScrambleCtrlIdle))
+ ) u_state_regs (
+ .clk_i,
+ .rst_ni,
+ .state_i ( state_d ),
+ .state_o ( state_raw_q )
+ );
+
always_comb begin
dmem_key_valid_d = dmem_key_valid_q;
imem_key_valid_d = imem_key_valid_q;
@@ -124,6 +134,7 @@
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;
+ state_error_o = 1'b0;
unique case (state_q)
ScrambleCtrlIdle: begin
@@ -154,7 +165,9 @@
imem_key_seed_valid_d = otp_key_seed_valid;
end
end
- default: ;
+ default: begin
+ state_error_o = 1'b1;
+ end
endcase
end
diff --git a/hw/ip/otbn/rtl/otbn_start_stop_control.sv b/hw/ip/otbn/rtl/otbn_start_stop_control.sv
index 61d9f70..9ed4a75 100644
--- a/hw/ip/otbn/rtl/otbn_start_stop_control.sv
+++ b/hw/ip/otbn/rtl/otbn_start_stop_control.sv
@@ -54,20 +54,28 @@
output logic sec_wipe_zero_o,
output logic ispr_init_o,
- output logic state_reset_o
+ output logic state_reset_o,
+ output logic state_error_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
+ // This primitive is used to place a size-only constraint on the
+ // flops in order to prevent FSM state encoding optimizations.
+ logic [StateStartStopWidth-1:0] state_raw_q;
+ assign state_q = otbn_start_stop_state_e'(state_raw_q);
+ prim_sparse_fsm_flop #(
+ .StateEnumT(otbn_start_stop_state_e),
+ .Width(StateStartStopWidth),
+ .ResetValue(StateStartStopWidth'(OtbnStartStopStateHalt))
+ ) u_state_regs (
+ .clk_i,
+ .rst_ni,
+ .state_i ( state_d ),
+ .state_o ( state_raw_q )
+ );
always_comb begin
urnd_reseed_req_o = 1'b0;
@@ -84,6 +92,7 @@
sec_wipe_zero_o = 1'b0;
addr_cnt_inc = 1'b0;
secure_wipe_running_o = 1'b0;
+ state_error_o = 1'b0;
unique case (state_q)
OtbnStartStopStateHalt: begin
@@ -155,7 +164,9 @@
secure_wipe_running_o = 1'b1;
state_d = OtbnStartStopStateHalt;
end
- default: ;
+ default: begin
+ state_error_o = 1'b1;
+ end
endcase
end