Skip to content

Commit

Permalink
[adc_ctrl] Remove filter_status register
Browse files Browse the repository at this point in the history
This removes the redundant filter_status register and relies on the
interrupt status register to generate the wakeup request instead.

Fixes #11354

Signed-off-by: Michael Schaffner <[email protected]>
  • Loading branch information
msfschaffner committed Mar 5, 2024
1 parent 15a729c commit b365614
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 260 deletions.
18 changes: 0 additions & 18 deletions hw/ip/adc_ctrl/data/adc_ctrl.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -312,24 +312,6 @@
]
}

{ name: "filter_status",
desc: '''
Adc filter match status

Indicates whether a particular filter has matched on all channels.
''',
swaccess: "rw1c",
hwaccess: "hrw",
async: "clk_aon_i",
resval: "0",
fields: [
{ bits: "7:0",
name: "COND",
desc: "0: filter condition is not met; 1: filter condition is met",
}
]
}

{ name: "adc_intr_ctl",
desc: '''
Interrupt enable controls.
Expand Down
32 changes: 6 additions & 26 deletions hw/ip/adc_ctrl/doc/registers.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@
| adc_ctrl.[`adc_chn_val_0`](#adc_chn_val) | 0x64 | 4 | ADC value sampled on channel |
| adc_ctrl.[`adc_chn_val_1`](#adc_chn_val) | 0x68 | 4 | ADC value sampled on channel |
| adc_ctrl.[`adc_wakeup_ctl`](#adc_wakeup_ctl) | 0x6c | 4 | Enable filter matches as wakeups |
| adc_ctrl.[`filter_status`](#filter_status) | 0x70 | 4 | Adc filter match status |
| adc_ctrl.[`adc_intr_ctl`](#adc_intr_ctl) | 0x74 | 4 | Interrupt enable controls. |
| adc_ctrl.[`adc_intr_status`](#adc_intr_status) | 0x78 | 4 | Debug cable internal status |
| adc_ctrl.[`adc_fsm_state`](#adc_fsm_state) | 0x7c | 4 | State of the internal state machine |
| adc_ctrl.[`adc_intr_ctl`](#adc_intr_ctl) | 0x70 | 4 | Interrupt enable controls. |
| adc_ctrl.[`adc_intr_status`](#adc_intr_status) | 0x74 | 4 | Debug cable internal status |
| adc_ctrl.[`adc_fsm_state`](#adc_fsm_state) | 0x78 | 4 | State of the internal state machine |

## INTR_STATE
Interrupt State Register
Expand Down Expand Up @@ -317,33 +316,14 @@ Enable filter matches as wakeups
| 31:8 | | | | Reserved |
| 7:0 | rw | 0x0 | EN | 0: filter match wil not generate wakeupe; 1: filter match will generate wakeup |

## filter_status
Adc filter match status

Indicates whether a particular filter has matched on all channels.
- Offset: `0x70`
- Reset default: `0x0`
- Reset mask: `0xff`

### Fields

```wavejson
{"reg": [{"name": "COND", "bits": 8, "attr": ["rw1c"], "rotate": 0}, {"bits": 24}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
```

| Bits | Type | Reset | Name | Description |
|:------:|:------:|:-------:|:-------|:-----------------------------------------------------------|
| 31:8 | | | | Reserved |
| 7:0 | rw1c | 0x0 | COND | 0: filter condition is not met; 1: filter condition is met |

## adc_intr_ctl
Interrupt enable controls.

adc_ctrl sends out only 1 interrupt, so this register controls
which internal sources are actually registered.

This register uses the same bit enumeration as [`ADC_INTR_STATUS`](#adc_intr_status)
- Offset: `0x74`
- Offset: `0x70`
- Reset default: `0x0`
- Reset mask: `0x1ff`

Expand All @@ -360,7 +340,7 @@ This register uses the same bit enumeration as [`ADC_INTR_STATUS`](#adc_intr_sta

## adc_intr_status
Debug cable internal status
- Offset: `0x78`
- Offset: `0x74`
- Reset default: `0x0`
- Reset mask: `0x1ff`

Expand All @@ -378,7 +358,7 @@ Debug cable internal status

## adc_fsm_state
State of the internal state machine
- Offset: `0x7c`
- Offset: `0x78`
- Reset default: `0x0`
- Reset mask: `0x1f`

Expand Down
13 changes: 3 additions & 10 deletions hw/ip/adc_ctrl/rtl/adc_ctrl_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,6 @@ module adc_ctrl_core import adc_ctrl_reg_pkg::* ; (
match[k] == (chn0_match[k] & chn1_match[k]), clk_aon_i, !rst_aon_ni)
end

// adc filter status
assign aon_filter_status_o.d = match_pulse | reg2hw_i.filter_status.q;
assign aon_filter_status_o.de = |match_pulse;

// generate wakeup to external power manager if filter status
// and wakeup enable are set.
assign wkup_req_o = |(reg2hw_i.filter_status.q &
reg2hw_i.adc_wakeup_ctl.q);

//instantiate the main state machine
adc_ctrl_fsm u_adc_ctrl_fsm (
.clk_aon_i,
Expand Down Expand Up @@ -188,14 +179,16 @@ module adc_ctrl_core import adc_ctrl_reg_pkg::* ; (
.clk_i,
.rst_ni,
.cfg_intr_en_i(reg2hw_i.adc_intr_ctl.q),
.cfg_wkup_en_i(reg2hw_i.adc_wakeup_ctl.q),
.cfg_oneshot_done_i(cfg_oneshot_done),
.intr_state_i(reg2hw_i.intr_state),
.intr_enable_i(reg2hw_i.intr_enable),
.intr_test_i(reg2hw_i.intr_test),
.intr_state_o,
.adc_intr_status_i(reg2hw_i.adc_intr_status),
.adc_intr_status_o,
.intr_o
.intr_o,
.wkup_req_o
);

// unused register inputs
Expand Down
78 changes: 61 additions & 17 deletions hw/ip/adc_ctrl/rtl/adc_ctrl_intr.sv
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (

input [NumAdcFilter-1:0] aon_filter_match_i,
input [8:0] cfg_intr_en_i,
input [7:0] cfg_wkup_en_i,
input cfg_oneshot_done_i,

input adc_ctrl_reg2hw_intr_state_reg_t intr_state_i,
Expand All @@ -22,7 +23,8 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
input adc_ctrl_reg2hw_adc_intr_status_reg_t adc_intr_status_i,
output adc_ctrl_hw2reg_adc_intr_status_reg_t adc_intr_status_o,

output intr_o
output intr_o,
output wkup_req_o
);


Expand All @@ -31,37 +33,46 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
// The request portion on the other hand does not change until
// a request/ack handshake cycle has completed.

logic [NumAdcFilter-1:0] staging_filter_match;
logic [NumAdcFilter-1:0] staging_filter_match_q;
logic aon_ld_req;

// staging portion takes on the value of the incoming event match
// and clears when it is snapshot into request hold.
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
if (!rst_aon_ni) begin
staging_filter_match <= '0;
staging_filter_match_q <= '0;
end else if (aon_ld_req && |aon_filter_match_i) begin
staging_filter_match <= aon_filter_match_i;
staging_filter_match_q <= aon_filter_match_i;
end else if (aon_ld_req) begin
staging_filter_match <= '0;
staging_filter_match_q <= '0;
end else if (|aon_filter_match_i) begin
staging_filter_match <= staging_filter_match | aon_filter_match_i;
staging_filter_match_q <= staging_filter_match_q | aon_filter_match_i;
end
end

logic [NumAdcFilter-1:0] aon_req_hold;
logic [NumAdcFilter-1:0] aon_req_hold_q, aon_req_hold_q1;
logic aon_ack;

// staging has pending requsts
assign aon_ld_req = (aon_req_hold == '0) & |staging_filter_match;
assign aon_ld_req = (aon_req_hold_q == '0) & |staging_filter_match_q;

// request hold self clears when the handshake cycle is complete
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
if (!rst_aon_ni) begin
aon_req_hold_q <= '0;
end else if (aon_ld_req) begin
aon_req_hold_q <= staging_filter_match_q;
end else if (aon_ack) begin
aon_req_hold_q <= '0;
end
end

// delay register to hold the wakeup request until the bus-side status has been re-synced.
always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
if (!rst_aon_ni) begin
aon_req_hold <= '0;
end else if (aon_ld_req) begin
aon_req_hold <= staging_filter_match;
end else if (aon_ack) begin
aon_req_hold <= '0;
aon_req_hold_q1 <= '0;
end else begin
aon_req_hold_q1 <= aon_req_hold_q;
end
end

Expand All @@ -72,7 +83,7 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
.clk_dst_i(clk_i),
.rst_dst_ni(rst_ni),
.req_chk_i(1'b1),
.src_req_i(|aon_req_hold),
.src_req_i(|aon_req_hold_q),
.src_ack_o(aon_ack),
.dst_req_o(filter_match_event),
.dst_ack_i(filter_match_event)
Expand All @@ -81,12 +92,12 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
//To write into interrupt status register
logic [1+NumAdcFilter-1:0] intr_events;

// Note that aon_req_hold is a value held in an async domain.
// aon_req_hold's value should not change until handshake is completed by `prim_sync_reqack`.
// Note that aon_req_hold_q is a value held in an async domain.
// aon_req_hold_q's value should not change until handshake is completed by `prim_sync_reqack`.
// There is no reason to use `prim_sync_reqack` in this case because that module passes
// through data only when the direction is src->dst.
assign intr_events = {cfg_oneshot_done_i,
{NumAdcFilter{filter_match_event}} & aon_req_hold} & cfg_intr_en_i;
{NumAdcFilter{filter_match_event}} & aon_req_hold_q} & cfg_intr_en_i;

assign adc_intr_status_o.filter_match.de = |intr_events[7:0];
assign adc_intr_status_o.oneshot.de = intr_events[8];
Expand All @@ -99,6 +110,18 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
assign unused_oneshot = adc_intr_status_i.oneshot.q;
assign adc_intr_status_o.oneshot.d = 1'b1;

// Re-synchronize the IRQ status from the bus side to the AON clock side so that we can
// hold the wkup request until the IRQ has been cleared.
logic [NumAdcFilter-1:0] aon_irq_status;
prim_flop_2sync #(
.Width(NumAdcFilter)
) u_prim_flop_2sync (
.clk_i(clk_aon_i),
.rst_ni(rst_aon_ni),
.d_i(adc_intr_status_i),
.q_o(aon_irq_status)
);

// instantiate interrupt hardware primitive
prim_intr_hw #(.Width(1)) i_adc_ctrl_intr_o (
.clk_i(clk_i),
Expand All @@ -113,4 +136,25 @@ module adc_ctrl_intr import adc_ctrl_reg_pkg::*; (
.intr_o
);

// We use the staging registers above to create a wakeup request as long as it has not been synced
// to the bus domain yet. Once synchronized, the wakeup request is held until the bus-side
// register has been cleared. aon_req_hold_q1 is used to bridge a potential gap between clearing
// aon_req_hold_q and the arrival of the synced bus side status aon_irq_status.
logic wkup_req_d, wkup_req_q;
assign wkup_req_d = cfg_wkup_en_i & (aon_filter_match_i |
staging_filter_match_q |
aon_req_hold_q |
aon_req_hold_q1 |
aon_irq_status);

always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin : p_wkup
if (!rst_aon_ni) begin
wkup_req_q <= 0;
end else begin
wkup_req_q <= wkup_req_d;
end
end

assign wkup_req_o = wkup_req_q;

endmodule
56 changes: 21 additions & 35 deletions hw/ip/adc_ctrl/rtl/adc_ctrl_reg_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,6 @@ package adc_ctrl_reg_pkg;
logic [7:0] q;
} adc_ctrl_reg2hw_adc_wakeup_ctl_reg_t;

typedef struct packed {
logic [7:0] q;
} adc_ctrl_reg2hw_filter_status_reg_t;

typedef struct packed {
logic [8:0] q;
} adc_ctrl_reg2hw_adc_intr_ctl_reg_t;
Expand Down Expand Up @@ -144,11 +140,6 @@ package adc_ctrl_reg_pkg;
} adc_chn_value_intr;
} adc_ctrl_hw2reg_adc_chn_val_mreg_t;

typedef struct packed {
logic [7:0] d;
logic de;
} adc_ctrl_hw2reg_filter_status_reg_t;

typedef struct packed {
struct packed {
logic [7:0] d;
Expand All @@ -166,28 +157,26 @@ package adc_ctrl_reg_pkg;

// Register -> HW type
typedef struct packed {
adc_ctrl_reg2hw_intr_state_reg_t intr_state; // [447:447]
adc_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [446:446]
adc_ctrl_reg2hw_intr_test_reg_t intr_test; // [445:444]
adc_ctrl_reg2hw_alert_test_reg_t alert_test; // [443:442]
adc_ctrl_reg2hw_adc_en_ctl_reg_t adc_en_ctl; // [441:440]
adc_ctrl_reg2hw_adc_pd_ctl_reg_t adc_pd_ctl; // [439:411]
adc_ctrl_reg2hw_adc_lp_sample_ctl_reg_t adc_lp_sample_ctl; // [410:403]
adc_ctrl_reg2hw_adc_sample_ctl_reg_t adc_sample_ctl; // [402:387]
adc_ctrl_reg2hw_adc_fsm_rst_reg_t adc_fsm_rst; // [386:386]
adc_ctrl_reg2hw_adc_chn0_filter_ctl_mreg_t [7:0] adc_chn0_filter_ctl; // [385:210]
adc_ctrl_reg2hw_adc_chn1_filter_ctl_mreg_t [7:0] adc_chn1_filter_ctl; // [209:34]
adc_ctrl_reg2hw_adc_wakeup_ctl_reg_t adc_wakeup_ctl; // [33:26]
adc_ctrl_reg2hw_filter_status_reg_t filter_status; // [25:18]
adc_ctrl_reg2hw_intr_state_reg_t intr_state; // [439:439]
adc_ctrl_reg2hw_intr_enable_reg_t intr_enable; // [438:438]
adc_ctrl_reg2hw_intr_test_reg_t intr_test; // [437:436]
adc_ctrl_reg2hw_alert_test_reg_t alert_test; // [435:434]
adc_ctrl_reg2hw_adc_en_ctl_reg_t adc_en_ctl; // [433:432]
adc_ctrl_reg2hw_adc_pd_ctl_reg_t adc_pd_ctl; // [431:403]
adc_ctrl_reg2hw_adc_lp_sample_ctl_reg_t adc_lp_sample_ctl; // [402:395]
adc_ctrl_reg2hw_adc_sample_ctl_reg_t adc_sample_ctl; // [394:379]
adc_ctrl_reg2hw_adc_fsm_rst_reg_t adc_fsm_rst; // [378:378]
adc_ctrl_reg2hw_adc_chn0_filter_ctl_mreg_t [7:0] adc_chn0_filter_ctl; // [377:202]
adc_ctrl_reg2hw_adc_chn1_filter_ctl_mreg_t [7:0] adc_chn1_filter_ctl; // [201:26]
adc_ctrl_reg2hw_adc_wakeup_ctl_reg_t adc_wakeup_ctl; // [25:18]
adc_ctrl_reg2hw_adc_intr_ctl_reg_t adc_intr_ctl; // [17:9]
adc_ctrl_reg2hw_adc_intr_status_reg_t adc_intr_status; // [8:0]
} adc_ctrl_reg2hw_t;

// HW -> register type
typedef struct packed {
adc_ctrl_hw2reg_intr_state_reg_t intr_state; // [82:81]
adc_ctrl_hw2reg_adc_chn_val_mreg_t [1:0] adc_chn_val; // [80:25]
adc_ctrl_hw2reg_filter_status_reg_t filter_status; // [24:16]
adc_ctrl_hw2reg_intr_state_reg_t intr_state; // [73:72]
adc_ctrl_hw2reg_adc_chn_val_mreg_t [1:0] adc_chn_val; // [71:16]
adc_ctrl_hw2reg_adc_intr_status_reg_t adc_intr_status; // [15:5]
adc_ctrl_hw2reg_adc_fsm_state_reg_t adc_fsm_state; // [4:0]
} adc_ctrl_hw2reg_t;
Expand Down Expand Up @@ -221,10 +210,9 @@ package adc_ctrl_reg_pkg;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_CHN_VAL_0_OFFSET = 7'h 64;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_CHN_VAL_1_OFFSET = 7'h 68;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_WAKEUP_CTL_OFFSET = 7'h 6c;
parameter logic [BlockAw-1:0] ADC_CTRL_FILTER_STATUS_OFFSET = 7'h 70;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_INTR_CTL_OFFSET = 7'h 74;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_INTR_STATUS_OFFSET = 7'h 78;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_FSM_STATE_OFFSET = 7'h 7c;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_INTR_CTL_OFFSET = 7'h 70;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_INTR_STATUS_OFFSET = 7'h 74;
parameter logic [BlockAw-1:0] ADC_CTRL_ADC_FSM_STATE_OFFSET = 7'h 78;

// Reset values for hwext registers and their fields
parameter logic [0:0] ADC_CTRL_INTR_TEST_RESVAL = 1'h 0;
Expand Down Expand Up @@ -264,14 +252,13 @@ package adc_ctrl_reg_pkg;
ADC_CTRL_ADC_CHN_VAL_0,
ADC_CTRL_ADC_CHN_VAL_1,
ADC_CTRL_ADC_WAKEUP_CTL,
ADC_CTRL_FILTER_STATUS,
ADC_CTRL_ADC_INTR_CTL,
ADC_CTRL_ADC_INTR_STATUS,
ADC_CTRL_ADC_FSM_STATE
} adc_ctrl_id_e;

// Register width information to check illegal writes
parameter logic [3:0] ADC_CTRL_PERMIT [32] = '{
parameter logic [3:0] ADC_CTRL_PERMIT [31] = '{
4'b 0001, // index[ 0] ADC_CTRL_INTR_STATE
4'b 0001, // index[ 1] ADC_CTRL_INTR_ENABLE
4'b 0001, // index[ 2] ADC_CTRL_INTR_TEST
Expand Down Expand Up @@ -300,10 +287,9 @@ package adc_ctrl_reg_pkg;
4'b 1111, // index[25] ADC_CTRL_ADC_CHN_VAL_0
4'b 1111, // index[26] ADC_CTRL_ADC_CHN_VAL_1
4'b 0001, // index[27] ADC_CTRL_ADC_WAKEUP_CTL
4'b 0001, // index[28] ADC_CTRL_FILTER_STATUS
4'b 0011, // index[29] ADC_CTRL_ADC_INTR_CTL
4'b 0011, // index[30] ADC_CTRL_ADC_INTR_STATUS
4'b 0001 // index[31] ADC_CTRL_ADC_FSM_STATE
4'b 0011, // index[28] ADC_CTRL_ADC_INTR_CTL
4'b 0011, // index[29] ADC_CTRL_ADC_INTR_STATUS
4'b 0001 // index[30] ADC_CTRL_ADC_FSM_STATE
};

endpackage
Loading

0 comments on commit b365614

Please sign in to comment.