[dcd] Added design files
Signed-off-by: Eric Shiu <eshiu@google.com>
diff --git a/hw/ip/dcd/dcd.core b/hw/ip/dcd/dcd.core
index a8f5a08..e6a2a2b 100644
--- a/hw/ip/dcd/dcd.core
+++ b/hw/ip/dcd/dcd.core
@@ -52,7 +52,7 @@
parameters:
- SYNTHESIS=true
tools:
- vdcd.hjsonerilator:
+ verilator:
mode: lint-only
verilator_options:
- "-Wall"
diff --git a/hw/ip/dcd/rtl/dcd.sv b/hw/ip/dcd/rtl/dcd.sv
index 7e742a3..c2e905b 100644
--- a/hw/ip/dcd/rtl/dcd.sv
+++ b/hw/ip/dcd/rtl/dcd.sv
@@ -21,16 +21,21 @@
//Inter-module IO
//AST interface
- //input [9:0] adc_d,//ADC voltage level, each step is 2.148mV(2200mV/1024). It covers 0-2.2V
+ //input [9:0] adc_d,
+ //ADC voltage level, each step is 2.148mV(2200mV/1024). It covers 0-2.2V
//input adc_d_val,//Valid bit(pulse) for adc_d
//output logic adc_pd,//Power down ADC(used in deep sleep mode to save power)
- //output logic [1:0] adc_chnsel,//channel select for ADC; 2’b0 means stop, 2’b01 means first channel, 2’b10 means second channel, 2’b11 ilegal
+ //output logic [1:0] adc_chnsel,
+ //channel select for ADC;
+ //2’b0 means stop, 2’b01 means first channel, 2’b10 means second channel, 2’b11 ilegal
//interrupt interface
- output logic intr_debug_cable_o,// Debug cable is detected(attached or disconnected); raise the interrupt to CPU
+ output logic intr_debug_cable_o,
+ // Debug cable is detected(attached or disconnected); raise the interrupt to CPU
//pwrmgr interface
- output logic debug_cable_wakeup_o //Debug cable is detected; wake up the GSC(CPU) in normal sleep and deep sleep mode
+ output logic debug_cable_wakeup_o
+ //Debug cable is detected; wake up the GSC(CPU) in normal sleep and deep sleep mode
//input [2:0] pwr_sts,//3’b001: deep sleep, 3’b010: normal sleep, 3’b100: fully active
);
@@ -39,6 +44,8 @@
dcd_reg2hw_t reg2hw;
dcd_hw2reg_t hw2reg;
+ logic nc_intg_err_o;//FIXME
+
// Register module
dcd_reg_top i_reg_top (
.clk_i(clk_i),
@@ -47,6 +54,7 @@
.tl_o(tl_o),
.reg2hw(reg2hw),
.hw2reg(hw2reg),
+ .intg_err_o(nc_intg_err_o),
.devmode_i (1'b1)
);
@@ -56,10 +64,34 @@
.rst_slow_ni(rst_slow_ni),
.clk_i(clk_i),
.rst_ni(rst_ni),
- .debug_cable_wakeup(debug_cable_wakeup_o),
+ .adc_en_ctl_i(reg2hw.adc_en_ctl),
+ .adc_pd_ctl_i(reg2hw.adc_pd_ctl),
+ .adc_lp_sample_ctl_i(reg2hw.adc_lp_sample_ctl),
+ .adc_sample_ctl_i(reg2hw.adc_sample_ctl),
+ .adc_fsm_rst_i(reg2hw.adc_fsm_rst),
+ .adc_chn0_filter_ctl_i(reg2hw.adc_chn0_filter_ctl),
+ .adc_chn1_filter_ctl_i(reg2hw.adc_chn1_filter_ctl),
+ .adc_wakeup_ctl_i(reg2hw.adc_wakeup_ctl),
+ .adc_intr_ctl_i(reg2hw.adc_intr_ctl),
+ .adc_chn_val_o(hw2reg.adc_chn_val),
+ .intr_state_i(reg2hw.intr_state),
+ .intr_enable_i(reg2hw.intr_enable),
+ .intr_test_i(reg2hw.intr_test),
+ .intr_state_o(hw2reg.intr_state),
+ .adc_intr_status_o(hw2reg.adc_intr_status),
+ .adc_wakeup_status_o(hw2reg.adc_wakeup_status),
+ .debug_cable_wakeup_o(debug_cable_wakeup_o),
.intr_debug_cable_o(intr_debug_cable_o),
.adc_i(adc_i),
.adc_o(adc_o)
);
+ // All outputs should be known value after reset
+ `ASSERT_KNOWN(IntrDebugCableKnown, intr_debug_cable_o)
+ `ASSERT_KNOWN(WakeDebugCableKnown, debug_cable_wakeup_o)
+ `ASSERT_KNOWN(TlODValidKnown, tl_o.d_valid)
+ `ASSERT_KNOWN(TlOAReadyKnown, tl_o.a_ready)
+ `ASSERT_KNOWN(ADCPDKnown, adc_o.pd)
+ `ASSERT_KNOWN(ADCChnSelKnown, adc_o.channel_sel)
+
endmodule
diff --git a/hw/ip/dcd/rtl/dcd_core.sv b/hw/ip/dcd/rtl/dcd_core.sv
new file mode 100644
index 0000000..558943e
--- /dev/null
+++ b/hw/ip/dcd/rtl/dcd_core.sv
@@ -0,0 +1,693 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// DCD core module
+
+module dcd_core import dcd_reg_pkg::* ; (
+ input clk_aon_i,//Always-on 200KHz clock(logic)
+ input rst_slow_ni,//power-on reset for the 200KHz clock(logic)
+ input clk_i,//regular core clock for SW config interface
+ input rst_ni,//power-on hardware reset
+
+ input dcd_reg2hw_adc_en_ctl_reg_t adc_en_ctl_i,
+ input dcd_reg2hw_adc_pd_ctl_reg_t adc_pd_ctl_i,
+ input dcd_reg2hw_adc_lp_sample_ctl_reg_t adc_lp_sample_ctl_i,
+ input dcd_reg2hw_adc_sample_ctl_reg_t adc_sample_ctl_i,
+ input dcd_reg2hw_adc_fsm_rst_reg_t adc_fsm_rst_i,
+ input dcd_reg2hw_adc_chn0_filter_ctl_mreg_t [NumAdcFilter-1:0] adc_chn0_filter_ctl_i,
+ input dcd_reg2hw_adc_chn1_filter_ctl_mreg_t [NumAdcFilter-1:0] adc_chn1_filter_ctl_i,
+ input dcd_reg2hw_adc_wakeup_ctl_reg_t adc_wakeup_ctl_i,
+ input dcd_reg2hw_adc_intr_ctl_reg_t adc_intr_ctl_i,
+
+ output dcd_hw2reg_adc_chn_val_mreg_t [NumAdcChannel-1:0] adc_chn_val_o,
+
+ input dcd_reg2hw_intr_state_reg_t intr_state_i,
+ input dcd_reg2hw_intr_enable_reg_t intr_enable_i,
+ input dcd_reg2hw_intr_test_reg_t intr_test_i,
+
+ output dcd_hw2reg_intr_state_reg_t intr_state_o,
+ output dcd_hw2reg_adc_intr_status_reg_t adc_intr_status_o,
+ output dcd_hw2reg_adc_wakeup_status_reg_t adc_wakeup_status_o,
+
+ output debug_cable_wakeup_o,
+ output intr_debug_cable_o,
+
+ input ast_pkg::adc_ast_rsp_t adc_i,
+ output ast_pkg::adc_ast_req_t adc_o
+);
+
+ logic cfg_adc_enable;
+ logic cfg_oneshot_mode;
+ logic cfg_lp_mode;
+ logic load_pwrup_time, load_wakeup_time;
+ logic load_lp_sample_cnt, load_np_sample_cnt;
+ logic [3:0] cfg_pwrup_time, cfg_pwrup_time_d;
+ logic [23:0] cfg_wakeup_time, cfg_wakeup_time_d;
+ logic [7:0] cfg_lp_sample_cnt, cfg_lp_sample_cnt_d;
+ logic [15:0] cfg_np_sample_cnt, cfg_np_sample_cnt_d;
+ logic cfg_fsm_rst;
+
+ //There are eight filters
+ //Each filter can have different settings
+ logic [9:0] cfg_chn0_min_v [NumAdcFilter];
+ logic [9:0] cfg_chn0_max_v [NumAdcFilter];
+ logic [9:0] cfg_chn1_min_v [NumAdcFilter];
+ logic [9:0] cfg_chn1_max_v [NumAdcFilter];
+ logic [9:0] cfg_chn0_min_v_d [NumAdcFilter];
+ logic [9:0] cfg_chn0_max_v_d [NumAdcFilter];
+ logic [9:0] cfg_chn1_min_v_d [NumAdcFilter];
+ logic [9:0] cfg_chn1_max_v_d [NumAdcFilter];
+ logic [NumAdcFilter-1:0] cfg_chn0_cond;
+ logic [NumAdcFilter-1:0] cfg_chn1_cond;
+ logic [NumAdcFilter-1:0] load_chn0_min_v;
+ logic [NumAdcFilter-1:0] load_chn1_min_v;
+ logic [NumAdcFilter-1:0] load_chn0_max_v;
+ logic [NumAdcFilter-1:0] load_chn1_max_v;
+
+ //wakeup and interrupt control registers
+ logic [NumAdcFilter-1:0] cfg_wakeup_en;
+ //[0-7] for filters, [8] is for oneshot
+ logic [NumAdcFilter-1:0] cfg_intr_en;
+ logic cfg_oneshot_intr_en;
+
+ logic chn0_val_we, chn1_val_we;//write enable for the latest ADC sample
+ logic [9:0] chn0_val, chn1_val;
+ logic cfg_chn0_rvalid, cfg_chn1_rvalid;
+ logic [9:0] cfg_chn0_val, cfg_chn1_val;
+ logic cfg_chn0_rvalid_intr, cfg_chn1_rvalid_intr;
+ logic [9:0] cfg_chn0_val_intr, cfg_chn1_val_intr;
+
+ logic [NumAdcFilter-1:0] chn0_match, chn1_match, dcd_match;
+ logic [NumAdcFilter-1:0] dcd_match_pulse;
+ logic dcd_done, oneshot_done;//write enable for the ADC sample when the interrupt is triggered
+ logic cfg_dcd_done, cfg_oneshot_done;
+ //CFG clock domain synchronized write enable when interrupt is triggered
+ logic cfg_chn_val_intr_we;//Either oneshot_done or dcd_done
+
+ //synchronize between cfg(24MHz) and always-on(200KHz)
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_adc_enable (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_en_ctl_i.adc_enable.q),
+ .q_o(cfg_adc_enable)
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_oneshot_mode (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_en_ctl_i.oneshot_mode.q),
+ .q_o(cfg_oneshot_mode)
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_lp_mode (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_pd_ctl_i.lp_mode.q),
+ .q_o(cfg_lp_mode)
+ );
+ prim_fifo_async #(
+ .Width(4),
+ .Depth(2)
+ ) i_cfg_pwrup_time (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_pd_ctl_i.pwrup_time.qe),
+ .wready_o (),
+ .wdata_i (adc_pd_ctl_i.pwrup_time.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_pwrup_time),
+ .rready_i (1'b1),
+ .rdata_o (cfg_pwrup_time_d),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_pwrup_time_reg
+ if (!rst_slow_ni) begin
+ cfg_pwrup_time <= '0;
+ end else if (load_pwrup_time) begin
+ cfg_pwrup_time <= cfg_pwrup_time_d;
+ end
+ end
+
+ prim_fifo_async #(
+ .Width(24),
+ .Depth(2)
+ ) i_cfg_wakeup_time (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_pd_ctl_i.wakeup_time.qe),
+ .wready_o (),
+ .wdata_i (adc_pd_ctl_i.wakeup_time.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_wakeup_time),
+ .rready_i (1'b1),
+ .rdata_o (cfg_wakeup_time_d),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_wakeup_time_reg
+ if (!rst_slow_ni) begin
+ cfg_wakeup_time <= '0;
+ end else if (load_wakeup_time) begin
+ cfg_wakeup_time <= cfg_wakeup_time_d;
+ end
+ end
+
+ prim_fifo_async #(
+ .Width(8),
+ .Depth(2)
+ ) i_cfg_lp_sample_cnt (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_lp_sample_ctl_i.qe),
+ .wready_o (),
+ .wdata_i (adc_lp_sample_ctl_i.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_lp_sample_cnt),
+ .rready_i (1'b1),
+ .rdata_o (cfg_lp_sample_cnt_d),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_lp_sample_cnt_reg
+ if (!rst_slow_ni) begin
+ cfg_lp_sample_cnt <= '0;
+ end else if (load_lp_sample_cnt) begin
+ cfg_lp_sample_cnt <= cfg_lp_sample_cnt_d;
+ end
+ end
+
+ prim_fifo_async #(
+ .Width(16),
+ .Depth(2)
+ ) i_cfg_np_sample_cnt (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_sample_ctl_i.qe),
+ .wready_o (),
+ .wdata_i (adc_sample_ctl_i.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_np_sample_cnt),
+ .rready_i (1'b1),
+ .rdata_o (cfg_np_sample_cnt_d),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_np_sample_cnt_reg
+ if (!rst_slow_ni) begin
+ cfg_np_sample_cnt <= '0;
+ end else if (load_np_sample_cnt) begin
+ cfg_np_sample_cnt <= cfg_np_sample_cnt_d;
+ end
+ end
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_fsm_rst (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_fsm_rst_i.q),
+ .q_o(cfg_fsm_rst)
+ );
+
+ //synchronize between cfg(24MHz) and always-on(200KHz) for the filters
+ for (genvar k = 0 ; k < NumAdcFilter ; k++) begin : gen_filter_sync
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_chn0_cond (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_chn0_filter_ctl_i[k].cond.q),
+ .q_o(cfg_chn0_cond[k])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_chn1_cond (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_chn1_filter_ctl_i[k].cond.q),
+ .q_o(cfg_chn1_cond[k])
+ );
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn0_min_v (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_chn0_filter_ctl_i[k].min_v.qe),
+ .wready_o (),
+ .wdata_i (adc_chn0_filter_ctl_i[k].min_v.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_chn0_min_v[k]),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn0_min_v_d[k]),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_chn0_min_v_reg
+ if (!rst_slow_ni) begin
+ cfg_chn0_min_v[k] <= '0;
+ end else if (load_chn0_min_v[k]) begin
+ cfg_chn0_min_v[k] <= cfg_chn0_min_v_d[k];
+ end
+ end
+
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn1_min_v (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_chn1_filter_ctl_i[k].min_v.qe),
+ .wready_o (),
+ .wdata_i (adc_chn1_filter_ctl_i[k].min_v.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_chn1_min_v[k]),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn1_min_v_d[k]),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_chn1_min_v_reg
+ if (!rst_slow_ni) begin
+ cfg_chn1_min_v[k] <= '0;
+ end else if (load_chn1_min_v[k]) begin
+ cfg_chn1_min_v[k] <= cfg_chn1_min_v_d[k];
+ end
+ end
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn0_max_v (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_chn0_filter_ctl_i[k].max_v.qe),
+ .wready_o (),
+ .wdata_i (adc_chn0_filter_ctl_i[k].max_v.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_chn0_max_v[k]),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn0_max_v_d[k]),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_chn0_max_v_reg
+ if (!rst_slow_ni) begin
+ cfg_chn0_max_v[k] <= '0;
+ end else if (load_chn0_max_v[k]) begin
+ cfg_chn0_max_v[k] <= cfg_chn0_max_v_d[k];
+ end
+ end
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn1_max_v (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (adc_chn1_filter_ctl_i[k].max_v.qe),
+ .wready_o (),
+ .wdata_i (adc_chn1_filter_ctl_i[k].max_v.q),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_slow_ni),
+ .rvalid_o (load_chn1_max_v[k]),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn1_max_v_d[k]),
+ .rdepth_o ()
+ );
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_cfg_chn1_max_v_reg
+ if (!rst_slow_ni) begin
+ cfg_chn1_max_v[k] <= '0;
+ end else if (load_chn1_max_v[k]) begin
+ cfg_chn1_max_v[k] <= cfg_chn1_max_v_d[k];
+ end
+ end
+
+ end
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en0 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter0_en.q),
+ .q_o(cfg_wakeup_en[0])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en1 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter1_en.q),
+ .q_o(cfg_wakeup_en[1])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en2 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter2_en.q),
+ .q_o(cfg_wakeup_en[2])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en3 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter3_en.q),
+ .q_o(cfg_wakeup_en[3])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en4 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter4_en.q),
+ .q_o(cfg_wakeup_en[4])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en5 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter5_en.q),
+ .q_o(cfg_wakeup_en[5])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en6 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter6_en.q),
+ .q_o(cfg_wakeup_en[6])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_wakeup_en7 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_wakeup_ctl_i.chn0_1_filter7_en.q),
+ .q_o(cfg_wakeup_en[7])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en0 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter0_en.q),
+ .q_o(cfg_intr_en[0])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en1 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter1_en.q),
+ .q_o(cfg_intr_en[1])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en2 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter2_en.q),
+ .q_o(cfg_intr_en[2])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en3 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter3_en.q),
+ .q_o(cfg_intr_en[3])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en4 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter4_en.q),
+ .q_o(cfg_intr_en[4])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en5 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter5_en.q),
+ .q_o(cfg_intr_en[5])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en6 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter6_en.q),
+ .q_o(cfg_intr_en[6])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_intr_en7 (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.chn0_1_filter7_en.q),
+ .q_o(cfg_intr_en[7])
+ );
+
+ prim_flop_2sync # (
+ .Width(1)
+ ) i_cfg_oneshot_intr_en (
+ .clk_i(clk_aon_i),
+ .rst_ni(rst_slow_ni),
+ .d_i(adc_intr_ctl_i.oneshot_intr_en.q),
+ .q_o(cfg_oneshot_intr_en)
+ );
+
+ //Synchronize from 200KHz always-onclock to 24MHz cfg clock
+ prim_pulse_sync i_oneshot_done (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (oneshot_done),
+ .dst_pulse_o (cfg_oneshot_done)
+ );
+
+ prim_pulse_sync i_dcd_done (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_done),
+ .dst_pulse_o (cfg_dcd_done)
+ );
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn0_val (
+ .clk_wr_i (clk_aon_i),
+ .rst_wr_ni (rst_slow_ni),
+ .wvalid_i (chn0_val_we),
+ .wready_o (),
+ .wdata_i (chn0_val),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_i),
+ .rst_rd_ni (rst_ni),
+ .rvalid_o (cfg_chn0_rvalid),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn0_val),
+ .rdepth_o ()
+ );
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn1_val (
+ .clk_wr_i (clk_aon_i),
+ .rst_wr_ni (rst_slow_ni),
+ .wvalid_i (chn1_val_we),
+ .wready_o (),
+ .wdata_i (chn1_val),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_i),
+ .rst_rd_ni (rst_ni),
+ .rvalid_o (cfg_chn1_rvalid),
+ .rready_i (1'b1),
+ .rdata_o (cfg_chn1_val),
+ .rdepth_o ()
+ );
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn0_val_intr (
+ .clk_wr_i (clk_aon_i),
+ .rst_wr_ni (rst_slow_ni),
+ .wvalid_i (chn0_val_we),
+ .wready_o (),
+ .wdata_i (chn0_val),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_i),
+ .rst_rd_ni (rst_ni),
+ .rvalid_o (cfg_chn0_rvalid_intr),
+ .rready_i (cfg_chn_val_intr_we),
+ .rdata_o (cfg_chn0_val_intr),
+ .rdepth_o ()
+ );
+
+ prim_fifo_async #(
+ .Width(10),
+ .Depth(2)
+ ) i_cfg_chn1_val_intr (
+ .clk_wr_i (clk_aon_i),
+ .rst_wr_ni (rst_slow_ni),
+ .wvalid_i (chn1_val_we),
+ .wready_o (),
+ .wdata_i (chn1_val),
+ .wdepth_o (),
+
+ .clk_rd_i (clk_i),
+ .rst_rd_ni (rst_ni),
+ .rvalid_o (cfg_chn1_rvalid_intr),
+ .rready_i (cfg_chn_val_intr_we),
+ .rdata_o (cfg_chn1_val_intr),
+ .rdepth_o ()
+ );
+ //To write into adc_chn_val register
+ assign adc_chn_val_o[0].adc_chn_value.de = cfg_chn0_rvalid;
+ assign adc_chn_val_o[0].adc_chn_value.d = cfg_chn0_val;
+ assign adc_chn_val_o[1].adc_chn_value.de = cfg_chn1_rvalid;
+ assign adc_chn_val_o[1].adc_chn_value.d = cfg_chn1_val;
+
+ assign cfg_chn_val_intr_we = cfg_oneshot_done || cfg_dcd_done;
+
+ assign adc_chn_val_o[0].adc_chn_value_intr.de = cfg_chn0_rvalid_intr;
+ assign adc_chn_val_o[0].adc_chn_value_intr.d = cfg_chn0_val_intr;
+ assign adc_chn_val_o[1].adc_chn_value_intr.de = cfg_chn1_rvalid_intr;
+ assign adc_chn_val_o[1].adc_chn_value_intr.d = cfg_chn1_val_intr;
+
+ //Connect the ports for future extension
+ assign adc_chn_val_o[0].adc_chn_value_ext.de = 1'b0;
+ assign adc_chn_val_o[0].adc_chn_value_ext.d = 2'b0;
+ assign adc_chn_val_o[1].adc_chn_value_ext.de = 1'b0;
+ assign adc_chn_val_o[1].adc_chn_value_ext.d = 2'b0;
+
+ assign adc_chn_val_o[0].adc_chn_value_intr_ext.de = 1'b0;
+ assign adc_chn_val_o[0].adc_chn_value_intr_ext.d = 2'b0;
+ assign adc_chn_val_o[1].adc_chn_value_intr_ext.de = 1'b0;
+ assign adc_chn_val_o[1].adc_chn_value_intr_ext.d = 2'b0;
+
+ //Evaluate if there is a match from chn0 and chn1 samples
+ for (genvar k = 0 ; k < NumAdcFilter ; k++) begin : gen_filter_match
+ assign chn0_match[k] = (!cfg_chn0_cond[k]) ?
+ (cfg_chn0_min_v[k] <= chn0_val) && (chn0_val <= cfg_chn0_max_v[k]) :
+ (cfg_chn0_min_v[k] > chn0_val) || (chn0_val > cfg_chn0_max_v[k]);
+ assign chn1_match[k] = (!cfg_chn1_cond[k]) ?
+ (cfg_chn1_min_v[k] <= chn1_val) && (chn1_val <= cfg_chn1_max_v[k]) :
+ (cfg_chn1_min_v[k] > chn1_val) || (chn1_val > cfg_chn1_max_v[k]);
+ assign dcd_match[k] = chn0_match[k] && chn1_match[k];
+ assign dcd_match_pulse[k] = dcd_done && dcd_match[k];
+ end
+
+ //instantiate the main state machine
+ dcd_fsm i_dcd_fsm (
+ .clk_aon_i(clk_aon_i),
+ .rst_slow_ni(rst_slow_ni),
+ .cfg_fsm_rst(cfg_fsm_rst),
+ .cfg_adc_enable(cfg_adc_enable),
+ .cfg_oneshot_mode(cfg_oneshot_mode),
+ .cfg_lp_mode(cfg_lp_mode),
+ .cfg_pwrup_time(cfg_pwrup_time),
+ .cfg_wakeup_time(cfg_wakeup_time),
+ .cfg_lp_sample_cnt(cfg_lp_sample_cnt),
+ .cfg_np_sample_cnt(cfg_np_sample_cnt),
+ .dcd_match(dcd_match),
+ .adc_d(adc_i.data),
+ .adc_d_val(adc_i.data_valid),
+ .adc_pd(adc_o.pd),
+ .adc_chn_sel(adc_o.channel_sel),
+ .chn0_val_we(chn0_val_we),
+ .chn1_val_we(chn1_val_we),
+ .chn0_val(chn0_val),
+ .chn1_val(chn1_val),
+ .dcd_done(dcd_done),
+ .oneshot_done(oneshot_done)
+ );
+
+ //Instantiate the interrupt module
+ dcd_intr i_dcd_intr (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .clk_aon_i(clk_aon_i),
+ .rst_slow_ni(rst_slow_ni),
+ .cfg_wakeup_en(cfg_wakeup_en),
+ .cfg_intr_en(cfg_intr_en),
+ .cfg_oneshot_intr_en(cfg_oneshot_intr_en),
+ .dcd_match_pulse(dcd_match_pulse),
+ .cfg_oneshot_done(cfg_oneshot_done),
+ .intr_state_i(intr_state_i),
+ .intr_enable_i(intr_enable_i),
+ .intr_test_i(intr_test_i),
+ .intr_state_o(intr_state_o),
+ .adc_intr_status_o(adc_intr_status_o),
+ .adc_wakeup_status_o(adc_wakeup_status_o),
+ .debug_cable_wakeup_o(debug_cable_wakeup_o),
+ .intr_debug_cable_o(intr_debug_cable_o)
+ );
+
+
+endmodule
diff --git a/hw/ip/dcd/rtl/dcd_fsm.sv b/hw/ip/dcd/rtl/dcd_fsm.sv
new file mode 100644
index 0000000..8ee4ce0
--- /dev/null
+++ b/hw/ip/dcd/rtl/dcd_fsm.sv
@@ -0,0 +1,374 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description DCD detection FSM module
+
+module dcd_fsm
+ import dcd_reg_pkg::*;
+(
+ input clk_aon_i,
+ input rst_slow_ni,
+ input cfg_fsm_rst,
+ input cfg_adc_enable,
+ input cfg_oneshot_mode,
+ input cfg_lp_mode,
+ input [3:0] cfg_pwrup_time,
+ input [23:0] cfg_wakeup_time,
+ input [7:0] cfg_lp_sample_cnt,
+ input [15:0] cfg_np_sample_cnt,
+ input [NumAdcFilter-1:0] dcd_match,
+ input [9:0] adc_d,
+ input adc_d_val,//valid bit for ADC value
+ output logic adc_pd,
+ output logic[1:0] adc_chn_sel,
+ output logic chn0_val_we,
+ output logic chn1_val_we,
+ output logic [9:0] chn0_val,
+ output logic [9:0] chn1_val,
+ output logic dcd_done,
+ output logic oneshot_done
+);
+
+ logic trigger_q;
+ logic trigger_l2h, trigger_h2l;
+
+ logic [3:0] pwrup_timer_cnt_d, pwrup_timer_cnt_q;
+ logic pwrup_timer_cnt_clr, pwrup_timer_cnt_en;
+ logic [9:0] chn0_val_d, chn1_val_d;
+ logic fsm_chn0_sel, fsm_chn1_sel;
+ logic chn0_val_we_d, chn1_val_we_d;
+ logic [7:0] lp_sample_cnt_d, lp_sample_cnt_q;
+ logic lp_sample_cnt_clr, lp_sample_cnt_en;
+ logic [23:0] wakeup_timer_cnt_d, wakeup_timer_cnt_q;
+ logic wakeup_timer_cnt_clr, wakeup_timer_cnt_en;
+ logic [NumAdcFilter-1:0] dcd_match_q, fst_lp_match;
+ logic any_fst_lp_match, stay_match;
+ logic [15:0] np_sample_cnt_d, np_sample_cnt_q;
+ logic np_sample_cnt_clr, np_sample_cnt_en;
+
+ //FSM flow
+ //1. PWRDN->PWRUP->IDLE->ONEST_0->ONEST_021->ONEST_1->PWRDN
+ //2. PWRDN->PWRUP->IDLE->LP_0->LP_021->LP_1->LP_EVAL->LP_SLP->LP_PWRUP->LP0->
+ // LP_021->LP_1->LP_EVAL->NP_0->NP_021->NP_1->NP_EVAL->NP_0...repeat
+ //3. PWRDN->PWRUP->IDLE->NP_0->NP_021->NP_1->NP_EVAL->NP_0....repeat
+ typedef enum logic [3:0] {
+ PWRDN = 4'h0,// in the power down state
+ PWRUP = 4'h1,// being powered up
+ IDLE = 4'h2,// powered up after the pwrup_timer
+ ONEST_0 = 4'h3,// in oneshot mode; sample channel0 value
+ ONEST_021 = 4'h4,// in oneshot mode; transition from chn0 to chn1
+ ONEST_1 = 4'h5,// in oneshot mode; sample channel1 value
+ LP_0 = 4'h6,// in low-power mode, sample channel0 value
+ LP_021 = 4'h7,// in low-power mode, transition from chn0 to chn1
+ LP_1 = 4'h8,// in low-power mode, sample channel1 value
+ LP_EVAL = 4'h9,// in low-power mode, evaluate if there is a match
+ LP_SLP = 4'ha,// in low-power mode, go to sleep
+ LP_PWRUP = 4'hb,// in low-power mode, being powered up
+ NP_0 = 4'hc,// in normal-power mode, sample channel0 value
+ NP_021 = 4'hd,// in normal-power mode, transition from chn0 to chn1
+ NP_1 = 4'he,// in normal-power mode, sample channel1 value
+ NP_EVAL = 4'hf// in normal-power mode, detection is done
+ } fsm_state_e;
+
+ fsm_state_e fsm_state_q, fsm_state_d;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_trigger_reg
+ if (!rst_slow_ni) begin
+ trigger_q <= 1'b0;
+ end
+ else if (cfg_fsm_rst) begin
+ trigger_q <= 1'b0;
+ end else begin
+ trigger_q <= cfg_adc_enable;
+ end
+ end
+
+ assign trigger_l2h = (trigger_q == 1'b0) && (cfg_adc_enable == 1'b1);
+ assign trigger_h2l = (trigger_q == 1'b1) && (cfg_adc_enable == 1'b0);
+
+ assign pwrup_timer_cnt_d = (pwrup_timer_cnt_en) ? pwrup_timer_cnt_q + 1'b1 : pwrup_timer_cnt_q;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_pwrup_timer_cnt_reg
+ if (!rst_slow_ni) begin
+ pwrup_timer_cnt_q <= '0;
+ end
+ else if (pwrup_timer_cnt_clr || cfg_fsm_rst) begin
+ pwrup_timer_cnt_q <= '0;
+ end else begin
+ pwrup_timer_cnt_q <= pwrup_timer_cnt_d;
+ end
+ end
+
+ assign lp_sample_cnt_d = (lp_sample_cnt_en) ? lp_sample_cnt_q + 1'b1 : lp_sample_cnt_q;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_lp_sample_cnt_reg
+ if (!rst_slow_ni) begin
+ lp_sample_cnt_q <= '0;
+ end
+ else if (lp_sample_cnt_clr || cfg_fsm_rst) begin
+ lp_sample_cnt_q <= '0;
+ end else begin
+ lp_sample_cnt_q <= lp_sample_cnt_d;
+ end
+ end
+
+ assign np_sample_cnt_d = (np_sample_cnt_en) ? np_sample_cnt_q + 1'b1 : np_sample_cnt_q;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_np_sample_cnt_reg
+ if (!rst_slow_ni) begin
+ np_sample_cnt_q <= '0;
+ end
+ else if (np_sample_cnt_clr || cfg_fsm_rst) begin
+ np_sample_cnt_q <= '0;
+ end else begin
+ np_sample_cnt_q <= np_sample_cnt_d;
+ end
+ end
+
+ assign wakeup_timer_cnt_d = (wakeup_timer_cnt_en) ?
+ wakeup_timer_cnt_q + 1'b1 : wakeup_timer_cnt_q;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_wakeup_timer_cnt_reg
+ if (!rst_slow_ni) begin
+ wakeup_timer_cnt_q <= '0;
+ end
+ else if (wakeup_timer_cnt_clr || cfg_fsm_rst) begin
+ wakeup_timer_cnt_q <= '0;
+ end else begin
+ wakeup_timer_cnt_q <= wakeup_timer_cnt_d;
+ end
+ end
+
+ assign fsm_chn0_sel = (fsm_state_q == ONEST_0) || (fsm_state_q == LP_0) || (fsm_state_q == NP_0);
+ assign chn0_val_we_d = fsm_chn0_sel && adc_d_val;//adc_d_val is a valid pulse
+ assign chn0_val_d = (chn0_val_we_d) ? adc_d : chn0_val;
+
+ assign fsm_chn1_sel = (fsm_state_q == ONEST_1) || (fsm_state_q == LP_1) || (fsm_state_q == NP_1);
+ assign chn1_val_we_d = fsm_chn1_sel && adc_d_val;
+ assign chn1_val_d = (chn1_val_we_d) ? adc_d : chn1_val;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_chn01_val_we_reg
+ if (!rst_slow_ni) begin
+ chn0_val_we <= '0;
+ chn1_val_we <= '0;
+ chn0_val <= '0;
+ chn1_val <= '0;
+ end
+ else if (cfg_fsm_rst) begin
+ chn0_val_we <= '0;
+ chn1_val_we <= '0;
+ chn0_val <= '0;
+ chn1_val <= '0;
+ end else begin
+ chn0_val_we <= chn0_val_we_d;
+ chn1_val_we <= chn1_val_we_d;
+ chn0_val <= chn0_val_d;
+ chn1_val <= chn1_val_d;
+ end
+ end
+
+ for (genvar k = 0 ; k < NumAdcFilter ; k++) begin : gen_fst_lp_match
+ assign fst_lp_match[k] =
+ ((lp_sample_cnt_q == 8'd1) && (fsm_state_q == LP_EVAL)) ? dcd_match[k] : 1'b0;
+ end
+
+ assign any_fst_lp_match = |fst_lp_match;
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_dcd_match_reg
+ if (!rst_slow_ni) begin
+ dcd_match_q <= '0;
+ end
+ else if (cfg_fsm_rst) begin
+ dcd_match_q <= '0;
+ end
+ else if ((fsm_state_q == LP_EVAL) || (fsm_state_q == NP_EVAL)) begin
+ dcd_match_q <= dcd_match;
+ end
+ end
+
+ assign stay_match = any_fst_lp_match || (dcd_match == dcd_match_q);
+
+ always_ff @(posedge clk_aon_i or negedge rst_slow_ni) begin: i_fsm_state_reg
+ if (!rst_slow_ni) begin
+ fsm_state_q <= PWRDN;
+ end
+ else if (trigger_h2l || cfg_fsm_rst) begin
+ fsm_state_q <= PWRDN;
+ end else begin
+ fsm_state_q <= fsm_state_d;
+ end
+ end
+
+ always_comb begin: adc_fsm
+ fsm_state_d = fsm_state_q;
+ //outputs
+ adc_chn_sel = 2'b0;
+ adc_pd = 1'b1;//default value
+ pwrup_timer_cnt_clr = 1'b0;
+ pwrup_timer_cnt_en = 1'b0;
+ lp_sample_cnt_clr = 1'b0;
+ lp_sample_cnt_en = 1'b0;
+ wakeup_timer_cnt_clr = 1'b0;
+ wakeup_timer_cnt_en = 1'b0;
+ np_sample_cnt_clr = 1'b0;
+ np_sample_cnt_en = 1'b0;
+ dcd_done = 1'b0;
+ oneshot_done = 1'b0;
+
+ unique case (fsm_state_q)
+ PWRDN: begin
+ if (trigger_l2h) begin
+ fsm_state_d = PWRUP;
+ end
+ end
+
+ PWRUP: begin
+ adc_pd = 1'b0;
+ if (pwrup_timer_cnt_q != cfg_pwrup_time) begin
+ pwrup_timer_cnt_en = 1'b1;
+ end
+ else if (pwrup_timer_cnt_q == cfg_pwrup_time) begin
+ pwrup_timer_cnt_clr = 1'b1;
+ fsm_state_d = IDLE;
+ end
+ end
+
+ IDLE: begin
+ adc_pd = 1'b0;
+ if (cfg_oneshot_mode) begin
+ fsm_state_d = ONEST_0;
+ end
+ else if (cfg_lp_mode) begin
+ fsm_state_d = LP_0;
+ end
+ else if (!cfg_lp_mode) begin
+ fsm_state_d = NP_0;
+ end
+ end
+
+ ONEST_0: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b01;
+ if (adc_d_val) begin//sample chn0 value
+ fsm_state_d = ONEST_021;
+ end
+ end
+
+ ONEST_021: begin//transition betwenn chn0 and chn1; adc_chn_sel=2'b0
+ adc_pd = 1'b0;
+ fsm_state_d = ONEST_1;
+ end
+
+ ONEST_1: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b10;
+ if (adc_d_val) begin//sample chn1 value
+ oneshot_done = 1'b1;
+ fsm_state_d = PWRDN;
+ end
+ end
+
+ LP_0: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b01;
+ if (adc_d_val) begin//sample chn0 value
+ fsm_state_d = LP_021;
+ end
+ end
+
+ LP_021: begin//transition betwenn chn0 and chn1; adc_chn_sel=2'b0
+ adc_pd = 1'b0;
+ fsm_state_d = LP_1;
+ end
+
+ LP_1: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b10;
+ if (adc_d_val) begin//sample chn1 value
+ fsm_state_d = LP_EVAL;
+ lp_sample_cnt_en = 1'b1;
+ end
+ end
+
+ LP_EVAL: begin
+ adc_pd = 1'b0;
+ if ((lp_sample_cnt_q != cfg_lp_sample_cnt) && (stay_match == 1'b1)) begin
+ fsm_state_d = LP_SLP;
+ end
+ else if ((lp_sample_cnt_q != cfg_lp_sample_cnt) && (stay_match != 1'b1)) begin
+ fsm_state_d = LP_SLP;
+ lp_sample_cnt_clr = 1'b1;
+ end
+ else if ((lp_sample_cnt_q == cfg_lp_sample_cnt) && (stay_match == 1'b1)) begin
+ fsm_state_d = NP_0;
+ lp_sample_cnt_clr = 1'b1;
+ end
+ end
+
+ LP_SLP: begin
+ adc_pd = 1'b1;
+ if (wakeup_timer_cnt_q != cfg_wakeup_time) begin
+ wakeup_timer_cnt_en = 1'b1;
+ end
+ else if (wakeup_timer_cnt_q == cfg_wakeup_time) begin
+ fsm_state_d = LP_PWRUP;
+ wakeup_timer_cnt_clr = 1'b1;
+ end
+ end
+
+ LP_PWRUP: begin
+ adc_pd = 1'b0;
+ if (pwrup_timer_cnt_q != cfg_pwrup_time) begin
+ pwrup_timer_cnt_en = 1'b1;
+ end
+ else if (pwrup_timer_cnt_q == cfg_pwrup_time) begin
+ pwrup_timer_cnt_clr = 1'b1;
+ fsm_state_d = LP_0;
+ end
+ end
+
+ NP_0: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b01;
+ if (adc_d_val) begin//sample chn0 value
+ fsm_state_d = NP_021;
+ end
+ end
+
+ NP_021: begin//transition betwenn chn0 and chn1; adc_chn_sel=2'b0
+ adc_pd = 1'b0;
+ fsm_state_d = NP_1;
+ end
+
+ NP_1: begin
+ adc_pd = 1'b0;
+ adc_chn_sel = 2'b10;
+ if (adc_d_val) begin//sample chn1 value
+ fsm_state_d = NP_EVAL;
+ np_sample_cnt_en = 1'b1;
+ end
+ end
+
+ NP_EVAL: begin
+ adc_pd = 1'b0;
+ if ((np_sample_cnt_q != cfg_np_sample_cnt) && (stay_match == 1'b1)) begin
+ fsm_state_d = NP_0;
+ end
+ else if ((np_sample_cnt_q != cfg_np_sample_cnt) && (stay_match != 1'b1)) begin
+ fsm_state_d = NP_0;
+ np_sample_cnt_clr = 1'b1;
+ end
+ else if ((np_sample_cnt_q == cfg_np_sample_cnt) && (stay_match == 1'b1)) begin
+ fsm_state_d = NP_0;
+ np_sample_cnt_clr = 1'b1;
+ dcd_done = 1'b1;
+ end
+ end
+
+ default: fsm_state_d = PWRDN;
+ endcase
+ end
+
+
+endmodule
diff --git a/hw/ip/dcd/rtl/dcd_intr.sv b/hw/ip/dcd/rtl/dcd_intr.sv
new file mode 100644
index 0000000..2631a79
--- /dev/null
+++ b/hw/ip/dcd/rtl/dcd_intr.sv
@@ -0,0 +1,168 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: DCD interrupt Module
+//
+module dcd_intr import dcd_reg_pkg::*; (
+ input clk_i,
+ input rst_ni,
+ input clk_aon_i,
+ input rst_slow_ni,
+
+ input [NumAdcFilter-1:0] cfg_wakeup_en,
+ input [NumAdcFilter-1:0] cfg_intr_en,
+ input cfg_oneshot_intr_en,
+ input [NumAdcFilter-1:0] dcd_match_pulse,
+ input cfg_oneshot_done,
+
+ input dcd_reg2hw_intr_state_reg_t intr_state_i,
+ input dcd_reg2hw_intr_enable_reg_t intr_enable_i,
+ input dcd_reg2hw_intr_test_reg_t intr_test_i,
+
+ output dcd_hw2reg_intr_state_reg_t intr_state_o,
+ output dcd_hw2reg_adc_intr_status_reg_t adc_intr_status_o,
+ output dcd_hw2reg_adc_wakeup_status_reg_t adc_wakeup_status_o,
+
+ output debug_cable_wakeup_o,
+ output intr_debug_cable_o
+);
+
+ logic [NumAdcFilter-1:0] cfg_dcd_match_done;
+ logic dcd_event;
+
+ //Synchronize from 200KHz always-onclock to 24MHz cfg clock
+ prim_pulse_sync i_cc_sink_det (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[0]),
+ .dst_pulse_o (cfg_dcd_match_done[0])
+ );
+
+ prim_pulse_sync i_cc_1a5_sink_det (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[1]),
+ .dst_pulse_o (cfg_dcd_match_done[1])
+ );
+
+ prim_pulse_sync i_cc_3a0_sink_det (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[2]),
+ .dst_pulse_o (cfg_dcd_match_done[2])
+ );
+
+ prim_pulse_sync i_cc_src_det (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[3]),
+ .dst_pulse_o (cfg_dcd_match_done[3])
+ );
+
+ prim_pulse_sync i_cc_1a5_src_det (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[4]),
+ .dst_pulse_o (cfg_dcd_match_done[4])
+ );
+
+ prim_pulse_sync i_cc_src_det_flip (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[5]),
+ .dst_pulse_o (cfg_dcd_match_done[5])
+ );
+
+ prim_pulse_sync i_cc_1a5_src_det_flip (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[6]),
+ .dst_pulse_o (cfg_dcd_match_done[6])
+ );
+
+ prim_pulse_sync i_cc_discon (
+ .clk_src_i (clk_aon_i),
+ .clk_dst_i (clk_i),
+ .rst_src_ni (rst_slow_ni),
+ .rst_dst_ni (rst_ni),
+ .src_pulse_i (dcd_match_pulse[7]),
+ .dst_pulse_o (cfg_dcd_match_done[7])
+ );
+
+ //To write into interrupt status register
+ assign adc_intr_status_o.cc_sink_det.de = cfg_dcd_match_done[0];
+ assign adc_intr_status_o.cc_1a5_sink_det.de = cfg_dcd_match_done[1];
+ assign adc_intr_status_o.cc_3a0_sink_det.de = cfg_dcd_match_done[2];
+ assign adc_intr_status_o.cc_src_det.de = cfg_dcd_match_done[3];
+ assign adc_intr_status_o.cc_1a5_src_det.de = cfg_dcd_match_done[4];
+ assign adc_intr_status_o.cc_src_det_flip.de = cfg_dcd_match_done[5];
+ assign adc_intr_status_o.cc_1a5_src_det_flip.de = cfg_dcd_match_done[6];
+ assign adc_intr_status_o.cc_discon.de = cfg_dcd_match_done[7];
+ assign adc_intr_status_o.oneshot.de = cfg_oneshot_done;
+
+ assign adc_intr_status_o.cc_sink_det.d = 1'b1;
+ assign adc_intr_status_o.cc_1a5_sink_det.d = 1'b1;
+ assign adc_intr_status_o.cc_3a0_sink_det.d = 1'b1;
+ assign adc_intr_status_o.cc_src_det.d = 1'b1;
+ assign adc_intr_status_o.cc_1a5_src_det.d = 1'b1;
+ assign adc_intr_status_o.cc_src_det_flip.d = 1'b1;
+ assign adc_intr_status_o.cc_1a5_src_det_flip.d = 1'b1;
+ assign adc_intr_status_o.cc_discon.d = 1'b1;
+ assign adc_intr_status_o.oneshot.d = 1'b1;
+
+ //Qualify each bit with intr_en
+ assign dcd_event = (|(cfg_dcd_match_done & cfg_intr_en)) ||
+ (cfg_oneshot_done & cfg_oneshot_intr_en);
+
+ // instantiate interrupt hardware primitive
+ prim_intr_hw #(.Width(1)) i_dcd_intr_o (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .event_intr_i (dcd_event),
+ .reg2hw_intr_enable_q_i (intr_enable_i.q),
+ .reg2hw_intr_test_q_i (intr_test_i.q),
+ .reg2hw_intr_test_qe_i (intr_test_i.qe),
+ .reg2hw_intr_state_q_i (intr_state_i.q),
+ .hw2reg_intr_state_de_o (intr_state_o.de),
+ .hw2reg_intr_state_d_o (intr_state_o.d),
+ .intr_o (intr_debug_cable_o)
+ );
+
+ //To write into wakeup status register
+ assign adc_wakeup_status_o.cc_sink_det.de = cfg_dcd_match_done[0];
+ assign adc_wakeup_status_o.cc_1a5_sink_det.de = cfg_dcd_match_done[1];
+ assign adc_wakeup_status_o.cc_3a0_sink_det.de = cfg_dcd_match_done[2];
+ assign adc_wakeup_status_o.cc_src_det.de = cfg_dcd_match_done[3];
+ assign adc_wakeup_status_o.cc_1a5_src_det.de = cfg_dcd_match_done[4];
+ assign adc_wakeup_status_o.cc_src_det_flip.de = cfg_dcd_match_done[5];
+ assign adc_wakeup_status_o.cc_1a5_src_det_flip.de = cfg_dcd_match_done[6];
+ assign adc_wakeup_status_o.cc_discon.de = cfg_dcd_match_done[7];
+
+ assign adc_wakeup_status_o.cc_sink_det.d = 1'b1;
+ assign adc_wakeup_status_o.cc_1a5_sink_det.d = 1'b1;
+ assign adc_wakeup_status_o.cc_3a0_sink_det.d = 1'b1;
+ assign adc_wakeup_status_o.cc_src_det.d = 1'b1;
+ assign adc_wakeup_status_o.cc_1a5_src_det.d = 1'b1;
+ assign adc_wakeup_status_o.cc_src_det_flip.d = 1'b1;
+ assign adc_wakeup_status_o.cc_1a5_src_det_flip.d = 1'b1;
+ assign adc_wakeup_status_o.cc_discon.d = 1'b1;
+
+ //Qualify each bit with wakeup_en
+ assign debug_cable_wakeup_o = |(cfg_dcd_match_done & cfg_wakeup_en);
+
+endmodule
diff --git a/hw/ip/dcd/rtl/dcd_pkg.sv b/hw/ip/dcd/rtl/dcd_pkg.sv
new file mode 100644
index 0000000..e25850a
--- /dev/null
+++ b/hw/ip/dcd/rtl/dcd_pkg.sv
@@ -0,0 +1,21 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// DCD Module
+package dcd_pkg;
+
+typedef struct {
+ logic [1:0] chnsel;
+ logic powerdown;
+} adc_req_t;
+
+typedef struct {
+ logic [9:0] data;
+ logic valid;
+} adc_rsp_t;
+
+localparam adc_req_t ADC_REQ_DEFAULT = '{default:'0};
+localparam adc_rsp_t ADC_RSP_DEFAULT = '{default:'0};
+
+endpackage