Skip to content

Commit

Permalink
[soc_dbg_ctrl,rtl] Implement HALT feature via rom_ctrl
Browse files Browse the repository at this point in the history
An artifial halt feature is implemented by adding an artificial
rom_ctrl input to the pwrmgr. The soc_dbg_ctrl is setting this
when wanting to halt the Ibex on boot.

Signed-off-by: Robert Schilling <[email protected]>
  • Loading branch information
Razer6 committed Dec 6, 2024
1 parent 0d47575 commit 35a49fd
Show file tree
Hide file tree
Showing 21 changed files with 409 additions and 32 deletions.
39 changes: 39 additions & 0 deletions hw/ip/soc_dbg_ctrl/data/soc_dbg_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,31 @@
This signals enables TEST & RMA mode accesses.
'''
}
{ struct: "lc_tx"
type: "uni"
name: "lc_raw_test_rma"
act: "rcv"
default: "lc_ctrl_pkg::Off"
package: "lc_ctrl_pkg"
desc: '''
Test enable qualifier coming from life cycle controller.
This signals enables RAW, TEST and RMA mode accesses.
'''
}
{ struct: 'logic'
type: 'uni'
name: 'halt_cpu_boot'
act: 'rcv'
}
{ struct: 'pwrmgr_data'
type: 'uni'
name: 'continue_cpu_boot'
package: 'rom_ctrl_pkg'
act: 'req'
desc: '''
Artificial ROM control input to the pwrmgr to halt the boot process.
'''
}
]

regwidth: "32"
Expand Down Expand Up @@ -239,6 +264,20 @@
}
]
}
{ name: "JTAG_CONTROL"
desc: "JTAG control register to interact with the boot flow."
swaccess: "rw"
hwaccess: "hro"
fields: [
{ bits: "0"
resval: "0"
name: "boot_continue"
desc: '''
JTAG bit to stop or continue the boot flow if Ibex.
'''
}
]
}
]
}
}
18 changes: 18 additions & 0 deletions hw/ip/soc_dbg_ctrl/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Trace register to observe the valid or relocked state that is either determined
|:-------------------------------------------------------------------------------------------------|:---------|---------:|:---------------------------------------------------------------------------------------------------------|
| soc_dbg_ctrl.[`JTAG_TRACE_DEBUG_POLICY_CATEGORY`](#jtag_trace_debug_policy_category) | 0x0 | 4 | Trace register to observe the debug category that is either determined by hardware or software. |
| soc_dbg_ctrl.[`JTAG_TRACE_DEBUG_POLICY_VALID_RELOCKED`](#jtag_trace_debug_policy_valid_relocked) | 0x4 | 4 | Trace register to observe the valid or relocked state that is either determined by hardware or software. |
| soc_dbg_ctrl.[`JTAG_CONTROL`](#jtag_control) | 0x8 | 4 | JTAG control register to interact with the boot flow. |

## JTAG_TRACE_DEBUG_POLICY_CATEGORY
Trace register to observe the debug category that is either determined by hardware or software.
Expand Down Expand Up @@ -163,5 +164,22 @@ Trace register to observe the valid or relocked state that is either determined
| 7:4 | ro | 0x9 | relocked | The relocked state determined by hardware or software. |
| 3:0 | ro | 0x9 | valid | The valid state determined by hardware or software. |

## JTAG_CONTROL
JTAG control register to interact with the boot flow.
- Offset: `0x8`
- Reset default: `0x0`
- Reset mask: `0x1`

### Fields

```wavejson
{"reg": [{"name": "boot_continue", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 150}}
```

| Bits | Type | Reset | Name | Description |
|:------:|:------:|:-------:|:--------------|:----------------------------------------------------|
| 31:1 | | | | Reserved |
| 0 | rw | 0x0 | boot_continue | JTAG bit to stop or continue the boot flow if Ibex. |


<!-- END CMDGEN -->
94 changes: 91 additions & 3 deletions hw/ip/soc_dbg_ctrl/rtl/soc_dbg_ctrl.sv
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,24 @@ module soc_dbg_ctrl
input lc_ctrl_state_pkg::soc_dbg_state_t soc_dbg_state_i,
input lc_ctrl_pkg::lc_tx_t lc_dft_en_i,
input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
// Boot information from the pwrmgr
input lc_ctrl_pkg::lc_tx_t lc_raw_test_rma_i,
input pwrmgr_pkg::pwr_boot_status_t boot_status_i
// Boot information from the pwrmgr
// Halts CPU boot in early lifecycle stages after reset based on an external signal
// Halt functionality disappears in the production lifecycle
input logic halt_cpu_boot_i,
output rom_ctrl_pkg::pwrmgr_data_t continue_cpu_boot_o
);
socdbg_ctrl_core_reg2hw_t core_reg2hw;
socdbg_ctrl_core_hw2reg_t core_hw2reg;
socdbg_ctrl_jtag_reg2hw_t jtag_reg2hw;
socdbg_ctrl_jtag_hw2reg_t jtag_hw2reg;

//////////////////////////////////////////////////////////////////////////////////////////////////
// Alert Management
//////////////////////////////////////////////////////////////////////////////////////////////////

logic core_tl_intg_err, jtag_tl_intg_err;
logic core_tl_intg_err, jtag_tl_intg_err, halt_fsm_err;
logic shadowed_storage_err, shadowed_update_err;
logic policy_shadowed_storage_err, policy_shadowed_update_err;
logic [NumAlerts-1:0] alert_test, alert;
Expand All @@ -53,7 +59,7 @@ module soc_dbg_ctrl
core_reg2hw.alert_test.recov_ctrl_update_err.qe
};
assign alert[0] = core_tl_intg_err | jtag_tl_intg_err | shadowed_storage_err |
policy_shadowed_storage_err;
policy_shadowed_storage_err | halt_fsm_err;
assign alert[1] = shadowed_update_err | policy_shadowed_update_err;

localparam logic [NumAlerts-1:0] IsFatal = {1'b0, 1'b1};
Expand Down Expand Up @@ -97,6 +103,7 @@ module soc_dbg_ctrl
.rst_ni,
.tl_i (jtag_tl_i),
.tl_o (jtag_tl_o),
.reg2hw (jtag_reg2hw),
.hw2reg (jtag_hw2reg),
// SEC_CM: BUS.INTEGRITY
.intg_err_o (jtag_tl_intg_err)
Expand Down Expand Up @@ -232,6 +239,85 @@ module soc_dbg_ctrl
assign jtag_hw2reg.jtag_trace_debug_policy_valid_relocked.relocked.de = 1'b1;
assign jtag_hw2reg.jtag_trace_debug_policy_valid_relocked.relocked.d = soc_dbg_policy_q.relocked;

//////////////////////////////////////////////////////////////////////////////////////////////////
// Ibex Halt feature via the pwrmgr's ROM_CTRL input
//////////////////////////////////////////////////////////////////////////////////////////////////

// Synchronize the input pin to io_div4 clk --> same as the pwrmgr fsm clk
logic halt_cpu_boot_sync;
prim_flop_2sync #(
.Width(1)
) u_prim_flop_2sync (
.clk_i,
.rst_ni,
.d_i(halt_cpu_boot_i),
.q_o(halt_cpu_boot_sync)
);

halt_state_e halt_state_d, halt_state_q;

always_comb begin
// Default assignments
halt_state_d = halt_state_q;
alert_fsm_error = 0;
continue_cpu_boot_o.done = prim_mubi_pkg::mubi4_t'(MuBi4False);

unique case (halt_state_q)
Idle: begin
if (boot_status_i.lc_done) begin
halt_state_d = CheckLifecycleState;
end
end

CheckLifecycleState: begin
// If RAW state, wait for volatile unlock
if (lc_tx_test_true_strict(lc_raw_test_rma_i)) begin
halt_state_d = Wait4DftEn;
end else begin
halt_state_d = HaltDone;
end
end

Wait4DftEn: begin
// Wait in this state until Volatile Raw Unlock is performed
// If !SecVolatileRawUnlockEn this is a passthrough state as lc_dft_en
// should be asserted along with lc_raw_test_rma
if (lc_tx_test_true_strict(lc_dft_en_i)) begin
halt_state_d = CheckHaltPin;
end
end

CheckHaltPin: begin
// Go to halt state if required
if (halt_cpu_boot_sync) begin
halt_state_d = CheckJtagGo;
end else begin
halt_state_d = HaltDone;
end
end

CheckJtagGo: begin
// Stay in halt state until JTAG command
if (jtag_reg2hw.jtag_control.q) begin
halt_state_d = HaltDone;
end
end

HaltDone: begin
// Stay here until the next reset
continue_cpu_boot_o.done = prim_mubi_pkg::mubi4_t'(MuBi4True)
end

default: begin
// Should not enter this state
alert_fsm_error = 1'b1;
end
endcase
end

// SEC_CM: FSM.SPARSE
`PRIM_FLOP_SPARSE_FSM(u_state_regs, halt_state_d, halt_state_q, halt_state_e, Idle)

logic unused_signals;
assign unused_signals = ^{boot_status_i.clk_status,
boot_status_i.cpu_fetch_en,
Expand All @@ -251,4 +337,6 @@ module soc_dbg_ctrl
`ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, u_core_reg, alert_tx_o[0])
`ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(JtagRegWeOnehotCheck_A, u_jtag_reg, alert_tx_o[0])

// Alert assertion for sparse FSM.
`ASSERT_PRIM_FSM_ERROR_TRIGGER_ALERT(HaltStateFsmCheck_A, u_state_regs, alert_tx_o[0])
endmodule
52 changes: 47 additions & 5 deletions hw/ip/soc_dbg_ctrl/rtl/soc_dbg_ctrl_jtag_reg_top.sv
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module soc_dbg_ctrl_jtag_reg_top (
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o,
// To HW
output soc_dbg_ctrl_reg_pkg::soc_dbg_ctrl_jtag_reg2hw_t reg2hw, // Write
input soc_dbg_ctrl_reg_pkg::soc_dbg_ctrl_jtag_hw2reg_t hw2reg, // Read

// Integrity check errors
Expand All @@ -20,7 +21,7 @@ module soc_dbg_ctrl_jtag_reg_top (

import soc_dbg_ctrl_reg_pkg::* ;

localparam int AW = 3;
localparam int AW = 4;
localparam int DW = 32;
localparam int DBW = DW/8; // Byte Width

Expand Down Expand Up @@ -51,9 +52,9 @@ module soc_dbg_ctrl_jtag_reg_top (

// also check for spurious write enables
logic reg_we_err;
logic [1:0] reg_we_check;
logic [2:0] reg_we_check;
prim_reg_we_check #(
.OneHotWidth(2)
.OneHotWidth(3)
) u_prim_reg_we_check (
.clk_i(clk_i),
.rst_ni(rst_ni),
Expand Down Expand Up @@ -123,6 +124,9 @@ module soc_dbg_ctrl_jtag_reg_top (
logic [6:0] jtag_trace_debug_policy_category_qs;
logic [3:0] jtag_trace_debug_policy_valid_relocked_valid_qs;
logic [3:0] jtag_trace_debug_policy_valid_relocked_relocked_qs;
logic jtag_control_we;
logic jtag_control_qs;
logic jtag_control_wd;

// Register instances
// R[jtag_trace_debug_policy_category]: V(False)
Expand Down Expand Up @@ -209,12 +213,41 @@ module soc_dbg_ctrl_jtag_reg_top (
);


// R[jtag_control]: V(False)
prim_subreg #(
.DW (1),
.SwAccess(prim_subreg_pkg::SwAccessRW),
.RESVAL (1'h0),
.Mubi (1'b0)
) u_jtag_control (
.clk_i (clk_i),
.rst_ni (rst_ni),

// from register interface
.we (jtag_control_we),
.wd (jtag_control_wd),

// from internal hardware
.de (1'b0),
.d ('0),

// to internal hardware
.qe (),
.q (reg2hw.jtag_control.q),
.ds (),

// to register interface (read)
.qs (jtag_control_qs)
);

logic [1:0] addr_hit;


logic [2:0] addr_hit;
always_comb begin
addr_hit = '0;
addr_hit[0] = (reg_addr == SOC_DBG_CTRL_JTAG_TRACE_DEBUG_POLICY_CATEGORY_OFFSET);
addr_hit[1] = (reg_addr == SOC_DBG_CTRL_JTAG_TRACE_DEBUG_POLICY_VALID_RELOCKED_OFFSET);
addr_hit[2] = (reg_addr == SOC_DBG_CTRL_JTAG_CONTROL_OFFSET);
end

assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
Expand All @@ -223,16 +256,21 @@ module soc_dbg_ctrl_jtag_reg_top (
always_comb begin
wr_err = (reg_we &
((addr_hit[0] & (|(SOC_DBG_CTRL_JTAG_PERMIT[0] & ~reg_be))) |
(addr_hit[1] & (|(SOC_DBG_CTRL_JTAG_PERMIT[1] & ~reg_be)))));
(addr_hit[1] & (|(SOC_DBG_CTRL_JTAG_PERMIT[1] & ~reg_be))) |
(addr_hit[2] & (|(SOC_DBG_CTRL_JTAG_PERMIT[2] & ~reg_be)))));
end

// Generate write-enables
assign jtag_control_we = addr_hit[2] & reg_we & !reg_error;

assign jtag_control_wd = reg_wdata[0];

// Assign write-enables to checker logic vector.
always_comb begin
reg_we_check = '0;
reg_we_check[0] = 1'b0;
reg_we_check[1] = 1'b0;
reg_we_check[2] = jtag_control_we;
end

// Read data return
Expand All @@ -248,6 +286,10 @@ module soc_dbg_ctrl_jtag_reg_top (
reg_rdata_next[7:4] = jtag_trace_debug_policy_valid_relocked_relocked_qs;
end

addr_hit[2]: begin
reg_rdata_next[0] = jtag_control_qs;
end

default: begin
reg_rdata_next = '1;
end
Expand Down
29 changes: 29 additions & 0 deletions hw/ip/soc_dbg_ctrl/rtl/soc_dbg_ctrl_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,33 @@ package soc_dbg_ctrl_pkg;
prim_mubi_pkg::mubi4_t relocked;
} soc_dbg_policy_t;

// Encoding generated with:
// $ ./util/design/sparse-fsm-encode.py -d 3 -m 6 -n 6 \
// -s 1870242553 --language=sv
//
// Hamming distance histogram:
//
// 0: --
// 1: --
// 2: --
// 3: |||||||||||||||||||| (53.33%)
// 4: ||||||||||||||||| (46.67%)
// 5: --
// 6: --
//
// Minimum Hamming distance: 3
// Maximum Hamming distance: 4
// Minimum Hamming weight: 2
// Maximum Hamming weight: 5
//
localparam int StateWidth = 6;
typedef enum logic [StateWidth-1:0] {
Idle = 6'b101000,
CheckLifecycleState = 6'b011101,
Wait4DftEn = 6'b000110,
CheckHaltPin = 6'b110011,
CheckJtagGo = 6'b111110,
HaltDone = 6'b100101
} halt_state_e;

endpackage
Loading

0 comments on commit 35a49fd

Please sign in to comment.