[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