[AON timer] Initial rtl commit
This commit adds the basic timers, registers and CDC for the AON wakeup
and watchdog timers.
There is one functional change to the HJSON, which is to add a wakeup
cause register. This register is written to zero by software to clear
the wakeup request (similar to pinmux wakeup).
CDC logic for register writes is currently not very sensible (a four
entry async fifo for every register). There are TODOs covering this and
it will be improved in subsequent updates.
Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
diff --git a/hw/ip/aon_timer/aon_timer.core b/hw/ip/aon_timer/aon_timer.core
new file mode 100644
index 0000000..207b351
--- /dev/null
+++ b/hw/ip/aon_timer/aon_timer.core
@@ -0,0 +1,65 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:ip:aon_timer:0.1"
+description: "Always-On Timer"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:all
+ - lowrisc:prim:lc_sync
+ - lowrisc:ip:tlul
+ files:
+ - rtl/aon_timer_reg_pkg.sv
+ - rtl/aon_timer_reg_top.sv
+ - rtl/aon_timer_core.sv
+ - rtl/aon_timer.sv
+ file_type: systemVerilogSource
+
+ files_verilator_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+ - lowrisc:lint:comportable
+
+ files_ascentlint_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+ - lowrisc:lint:comportable
+
+ files_veriblelint_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+ - lowrisc:lint:comportable
+
+parameters:
+ SYNTHESIS:
+ datatype: bool
+ paramtype: vlogdefine
+
+targets:
+ default: &default_target
+ filesets:
+ - tool_verilator ? (files_verilator_waiver)
+ - tool_ascentlint ? (files_ascentlint_waiver)
+ - tool_veriblelint ? (files_veriblelint_waiver)
+ - files_rtl
+ toplevel: aon_timer
+
+ lint:
+ <<: *default_target
+ default_tool: verilator
+ parameters:
+ - SYNTHESIS=true
+ tools:
+ ascentlint:
+ ascentlint_options:
+ - "-wait_license"
+ - "-stop_on_error"
+ verilator:
+ mode: lint-only
+ verilator_options:
+ - "-Wall"
diff --git a/hw/ip/aon_timer/data/aon_timer.hjson b/hw/ip/aon_timer/data/aon_timer.hjson
index ec4a0d6..0dd65ff 100644
--- a/hw/ip/aon_timer/data/aon_timer.hjson
+++ b/hw/ip/aon_timer/data/aon_timer.hjson
@@ -5,9 +5,14 @@
{
name: "aon_timer",
clock_primary: "clk_i",
+ reset_primary: "rst_ni",
other_clock_list: [
"clk_aon_i"
],
+ other_reset_list:
+ [
+ "rst_aon_ni"
+ ],
bus_device: "tlul",
interrupt_list: [
{ name: "wkup_timer_expired",
@@ -18,17 +23,18 @@
},
],
wakeup_list: [
- { name: "aon_timer",
+ { name: "aon_timer_wkup_req",
desc: "Raised if the wakeup or watchdog timer has hit the specified threshold"
},
],
inter_signal_list: [
- { name: "counter_run",
- type: "uni",
- act: "rsp",
- package: "",
- struct: "logic",
- width: "1"
+ // Broadcast from LC
+ { struct: "lc_tx"
+ type: "uni"
+ name: "lc_escalate_en"
+ act: "rcv"
+ default: "lc_ctrl_pkg::Off"
+ package: "lc_ctrl_pkg"
},
{ name: "sleep_mode",
type: "uni",
@@ -44,7 +50,9 @@
{ name: "WKUP_CTRL",
desc: "Wakeup Timer Control register",
swaccess: "rw",
- hwaccess: "hro",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
fields: [
{ bits: "0",
name: "enable",
@@ -59,7 +67,9 @@
{ name: "WKUP_THOLD",
desc: "Wakeup Timer Threshold Register",
swaccess: "rw",
- hwaccess: "hro",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
fields: [
{ bits: "31:0",
name: "threshold",
@@ -71,6 +81,8 @@
desc: "Wakeup Timer Count Register",
swaccess: "rw",
hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
fields: [
{ bits: "31:0",
name: "count",
@@ -81,7 +93,7 @@
{ name: "WDOG_REGWEN",
desc: "Watchdog Timer Write Enable Register",
swaccess: "rw0c",
- hwaccess: "hro",
+ hwaccess: "none",
fields: [
{ bits: "0",
name: "regwen",
@@ -93,7 +105,9 @@
{ name: "WDOG_CTRL",
desc: "Watchdog Timer Control register",
swaccess: "rw",
- hwaccess: "hro",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
regwen: "WDOG_REGWEN",
fields: [
{ bits: "0",
@@ -109,7 +123,9 @@
{ name: "WDOG_BARK_THOLD",
desc: "Watchdog Timer Bark Threshold Register",
swaccess: "rw",
- hwaccess: "hro",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
regwen: "WDOG_REGWEN",
fields: [
{ bits: "31:0",
@@ -121,7 +137,9 @@
{ name: "WDOG_BITE_THOLD",
desc: "Watchdog Timer Bite Threshold Register",
swaccess: "rw",
- hwaccess: "hro",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
regwen: "WDOG_REGWEN",
fields: [
{ bits: "31:0",
@@ -134,6 +152,8 @@
desc: "Watchdog Timer Count Register",
swaccess: "rw",
hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
fields: [
{ bits: "31:0",
name: "count",
@@ -160,6 +180,8 @@
desc: "Interrupt Test Register",
swaccess: "wo",
hwaccess: "hro",
+ hwext: "true",
+ hwqe: "true",
fields: [
{ bits: "0",
name: "wkup_timer_expired",
@@ -171,6 +193,19 @@
}
]
},
+ { name: "WKUP_CAUSE",
+ desc: "Wakeup request status",
+ swaccess: "rw0c",
+ hwaccess: "hrw",
+ hwext: "true",
+ hwqe: "true",
+ fields: [
+ { bits: "0",
+ name: "cause",
+ desc: "AON timer requested wakeup, write 0 to clear",
+ }
+ ]
+ },
],
}
diff --git a/hw/ip/aon_timer/doc/_index.md b/hw/ip/aon_timer/doc/_index.md
index 50f5fc0..55d5ed4 100644
--- a/hw/ip/aon_timer/doc/_index.md
+++ b/hw/ip/aon_timer/doc/_index.md
@@ -21,7 +21,7 @@
The always-on wakeup timer operation is straightforward.
A count starts at 0 and slowly ticks upwards (one tick every N+1 clock cycles, where N is the pre-scaler value).
When it reaches / exceeds the wake count, a level wakeup signal is sent to the power manager and a level IRQ is sent to the processor.
-This wakeup signal stays high until it is explicitly acknowledged by software.
+This wakeup signal stays high until it is explicitly acknowledged by software (software must write zero to the wkup_cause register to clear it).
The wakeup timer can be used like a real-time clock for long periods in a low-power mode (though it does not give any guarantees of time-accuracy TODO: specify accuracy).
### AON Watchdog timer
@@ -79,6 +79,8 @@
For the wakeup timer, pre-scaler extends the maximum timeout to ~1000 days.
Since the timer core runs on a slow clock, register values are sampled into the main clock domain to ensure register read / writes do not incur large latencies.
+The synchronization between clocks means that there is a delay between a register write completing and the underlying hardware taking the new value.
+Software can read back register values to know if/when updates have taken effect.
# Programmers Guide
diff --git a/hw/ip/aon_timer/rtl/aon_timer.sv b/hw/ip/aon_timer/rtl/aon_timer.sv
new file mode 100644
index 0000000..75bc8a5
--- /dev/null
+++ b/hw/ip/aon_timer/rtl/aon_timer.sv
@@ -0,0 +1,398 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+
+`include "prim_assert.sv"
+
+module aon_timer (
+ input logic clk_i,
+ input logic clk_aon_i,
+ input logic rst_ni,
+ input logic rst_aon_ni,
+
+ // TLUL interface on clk_i domain
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+
+ // clk_i domain
+ input lc_ctrl_pkg::lc_tx_t lc_escalate_en_i,
+ output logic intr_wkup_timer_expired_o,
+ output logic intr_wdog_timer_bark_o,
+
+ // clk_aon_i domain
+ input logic sleep_mode_i, // TODO where will this come from?
+ output logic aon_timer_wkup_req_o,
+ output logic rst_req_aon_timer_o
+);
+
+ import aon_timer_reg_pkg::*;
+
+ localparam int AON_WKUP = 0;
+ localparam int AON_WDOG = 1;
+
+ // Register structs
+ aon_timer_reg2hw_t reg2hw;
+ aon_timer_hw2reg_t hw2reg, aon_hw2reg, hw2reg_sync;
+ logic [3:0] unused_intr_state_bits;
+ // Register read signals
+ logic wkup_enable;
+ logic [11:0] wkup_prescaler;
+ logic [31:0] wkup_thold;
+ logic [31:0] wkup_count;
+ logic wdog_enable;
+ logic wdog_pause;
+ logic [31:0] wdog_bark_thold;
+ logic [31:0] wdog_bite_thold;
+ logic [31:0] wdog_count;
+ // Register write signals
+ logic wkup_ctrl_reg_wr;
+ logic [12:0] wkup_ctrl_wr_data;
+ logic wkup_thold_reg_wr;
+ logic [31:0] wkup_thold_wr_data;
+ logic wkup_count_reg_wr;
+ logic [31:0] wkup_count_wr_data;
+ logic wdog_ctrl_reg_wr;
+ logic [1:0] wdog_ctrl_wr_data;
+ logic wdog_bark_thold_reg_wr;
+ logic [31:0] wdog_bark_thold_wr_data;
+ logic wdog_bite_thold_reg_wr;
+ logic [31:0] wdog_bite_thold_wr_data;
+ logic wdog_count_reg_wr;
+ logic [31:0] wdog_count_wr_data;
+ // Other sync signals
+ lc_ctrl_pkg::lc_tx_t [2:0] lc_escalate_en;
+ // Wakeup signals
+ logic aon_wkup_req_d, aon_wkup_req_q;
+ logic wkup_ack, aon_wkup_ack;
+ // Interrupt signals
+ logic aon_wkup_intr_set, wkup_intr_set;
+ logic aon_wdog_intr_set, wdog_intr_set;
+ logic [1:0] intr_aon_test_q;
+ logic intr_aon_test_qe;
+ logic [1:0] intr_aon_state_q;
+ logic intr_aon_state_de;
+ logic [1:0] intr_aon_state_d;
+ logic [1:0] intr_out;
+ // Reset signals
+ logic aon_rst_req_set;
+ logic aon_rst_req_d, aon_rst_req_q;
+
+ ////////////////////////////
+ // Register Read Sampling //
+ ////////////////////////////
+
+ assign aon_hw2reg.wkup_ctrl.enable.d = wkup_enable;
+ assign aon_hw2reg.wkup_ctrl.prescaler.d = wkup_prescaler;
+ assign aon_hw2reg.wkup_thold.d = wkup_thold;
+ assign aon_hw2reg.wkup_count.d = wkup_count;
+ assign aon_hw2reg.wdog_ctrl.enable.d = wdog_enable;
+ assign aon_hw2reg.wdog_ctrl.pause_in_sleep.d = wdog_pause;
+ assign aon_hw2reg.wdog_bark_thold.d = wdog_bark_thold;
+ assign aon_hw2reg.wdog_bite_thold.d = wdog_bite_thold;
+ assign aon_hw2reg.wdog_count.d = wdog_count;
+ assign aon_hw2reg.wkup_cause.d = aon_wkup_req_q;
+ assign aon_hw2reg.intr_state = '0; // Doesn't come from AON domain
+
+ // Register read values sampled into clk_i domain. These are sampled with a special slow to fast
+ // synchronizer which captures the value on the negative edge of the slow clock.
+ prim_sync_slow_fast #(.Width ($bits(aon_hw2reg))) wkup_ctrl_enable_rd_sync (
+ .clk_slow_i (clk_aon_i),
+ .clk_fast_i (clk_i),
+ .rst_fast_ni (rst_ni),
+ .wdata_i (aon_hw2reg),
+ .rdata_o (hw2reg_sync)
+ );
+
+ assign hw2reg.wkup_ctrl.enable.d = hw2reg_sync.wkup_ctrl.enable.d;
+ assign hw2reg.wkup_ctrl.prescaler.d = hw2reg_sync.wkup_ctrl.prescaler.d;
+ assign hw2reg.wkup_thold.d = hw2reg_sync.wkup_thold.d;
+ assign hw2reg.wkup_count.d = hw2reg_sync.wkup_count.d;
+ assign hw2reg.wdog_ctrl.enable.d = hw2reg_sync.wdog_ctrl.enable.d;
+ assign hw2reg.wdog_ctrl.pause_in_sleep.d = hw2reg_sync.wdog_ctrl.pause_in_sleep.d;
+ assign hw2reg.wdog_bark_thold.d = hw2reg_sync.wdog_bark_thold.d;
+ assign hw2reg.wdog_bite_thold.d = hw2reg_sync.wdog_bite_thold.d;
+ assign hw2reg.wdog_count.d = hw2reg_sync.wdog_count.d;
+ assign hw2reg.wkup_cause.d = hw2reg_sync.wkup_cause.d;
+ assign unused_intr_state_bits = hw2reg_sync.intr_state;
+
+ //////////////////////////////
+ // Register Write Interface //
+ //////////////////////////////
+
+ // Register write data needs to be synchronized to make sure we capture sensible values.
+ // TODO This would probaby make more sense as a single fifo for all registers, but can't really
+ // achieve that at the moment with current register tooling.
+ // TODO An alternative improvement would be to fix the async fifo to allow depth < 4
+ // Note: these are fast clock to slow clock transfers
+
+ // wkup_ctrl
+ prim_fifo_async #(.Width (13), .Depth (4)) wkup_ctrl_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wkup_ctrl.enable.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i ({reg2hw.wkup_ctrl.prescaler.q, reg2hw.wkup_ctrl.enable.q}),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wkup_ctrl_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wkup_ctrl_wr_data),
+ .rdepth_o ());
+
+ // wkup_thold
+ prim_fifo_async #(.Width (32), .Depth (4)) wkup_thold_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wkup_thold.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i (reg2hw.wkup_thold.q),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wkup_thold_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wkup_thold_wr_data),
+ .rdepth_o ());
+
+ // wkup_count
+ prim_fifo_async #(.Width (32), .Depth (4)) wkup_count_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wkup_count.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i (reg2hw.wkup_count.q),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wkup_count_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wkup_count_wr_data),
+ .rdepth_o ());
+
+ // wdog_ctrl
+ prim_fifo_async #(.Width (2), .Depth (4)) wdog_ctrl_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wdog_ctrl.enable.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i ({reg2hw.wdog_ctrl.pause_in_sleep.q, reg2hw.wdog_ctrl.enable.q}),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wdog_ctrl_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wdog_ctrl_wr_data),
+ .rdepth_o ());
+
+ // wdog_bark_thold
+ prim_fifo_async #(.Width (32), .Depth (4)) wdog_bark_thold_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wdog_bark_thold.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i (reg2hw.wdog_bark_thold.q),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wdog_bark_thold_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wdog_bark_thold_wr_data),
+ .rdepth_o ());
+
+ // wdog_bite_thold
+ prim_fifo_async #(.Width (32), .Depth (4)) wdog_bite_thold_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wdog_bite_thold.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i (reg2hw.wdog_bite_thold.q),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wdog_bite_thold_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wdog_bite_thold_wr_data),
+ .rdepth_o ());
+
+ // wdog_count
+ prim_fifo_async #(.Width (32), .Depth (4)) wdog_count_wr_data_sync (
+ .clk_wr_i (clk_i),
+ .rst_wr_ni (rst_ni),
+ .wvalid_i (reg2hw.wdog_count.qe),
+ .wready_o (), // TODO no way of feeding this back to TLUL currently
+ .wdata_i (reg2hw.wdog_count.q),
+ .wdepth_o (),
+ .clk_rd_i (clk_aon_i),
+ .rst_rd_ni (rst_aon_ni),
+ .rvalid_o (wdog_count_reg_wr),
+ .rready_i (1'b1),
+ .rdata_o (wdog_count_wr_data),
+ .rdepth_o ());
+
+ // registers instantiation
+ aon_timer_reg_top u_reg (
+ .clk_i,
+ .rst_ni,
+
+ .tl_i,
+ .tl_o,
+
+ .reg2hw,
+ .hw2reg,
+
+ .devmode_i (1'b1)
+ );
+
+ // Lifecycle sync
+ prim_lc_sync #(
+ .NumCopies(3)
+ ) u_lc_sync_escalate_en (
+ .clk_i (clk_aon_i),
+ .rst_ni (rst_aon_ni),
+ .lc_en_i (lc_escalate_en_i),
+ .lc_en_o (lc_escalate_en)
+ );
+
+ ////////////////
+ // Timer Core //
+ ////////////////
+
+ aon_timer_core u_core (
+ .clk_aon_i,
+ .rst_aon_ni,
+ .sleep_mode_i,
+ .lc_escalate_en_i (lc_escalate_en),
+ .wkup_enable_o (wkup_enable),
+ .wkup_prescaler_o (wkup_prescaler),
+ .wkup_thold_o (wkup_thold),
+ .wkup_count_o (wkup_count),
+ .wdog_enable_o (wdog_enable),
+ .wdog_pause_o (wdog_pause),
+ .wdog_bark_thold_o (wdog_bark_thold),
+ .wdog_bite_thold_o (wdog_bite_thold),
+ .wdog_count_o (wdog_count),
+ .wkup_ctrl_reg_wr_i (wkup_ctrl_reg_wr),
+ .wkup_ctrl_wr_data_i (wkup_ctrl_wr_data),
+ .wkup_thold_reg_wr_i (wkup_thold_reg_wr),
+ .wkup_thold_wr_data_i (wkup_thold_wr_data),
+ .wkup_count_reg_wr_i (wkup_count_reg_wr),
+ .wkup_count_wr_data_i (wkup_count_wr_data),
+ .wdog_ctrl_reg_wr_i (wdog_ctrl_reg_wr),
+ .wdog_ctrl_wr_data_i (wdog_ctrl_wr_data),
+ .wdog_bark_thold_reg_wr_i (wdog_bark_thold_reg_wr),
+ .wdog_bark_thold_wr_data_i (wdog_bark_thold_wr_data),
+ .wdog_bite_thold_reg_wr_i (wdog_bite_thold_reg_wr),
+ .wdog_bite_thold_wr_data_i (wdog_bite_thold_wr_data),
+ .wdog_count_reg_wr_i (wdog_count_reg_wr),
+ .wdog_count_wr_data_i (wdog_count_wr_data),
+ .wkup_intr_o (aon_wkup_intr_set),
+ .wdog_intr_o (aon_wdog_intr_set),
+ .wdog_reset_req_o (aon_rst_req_set)
+ );
+
+ ////////////////////
+ // Wakeup Signals //
+ ////////////////////
+
+ // Wakeup signal remains high until acked by software
+ assign aon_wkup_req_d = aon_wkup_intr_set | aon_wdog_intr_set | (aon_wkup_req_q & ~aon_wkup_ack);
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ aon_wkup_req_q <= 1'b0;
+ end else begin
+ aon_wkup_req_q <= aon_wkup_req_d;
+ end
+ end
+
+ // Wakeup request is cleared by SW writing zero
+ assign wkup_ack = reg2hw.wkup_cause.qe & ~reg2hw.wkup_cause.q;
+
+ prim_pulse_sync wkup_ack_sync (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .src_pulse_i (wkup_ack),
+ .clk_dst_i (clk_aon_i),
+ .rst_dst_ni (rst_aon_ni),
+ .dst_pulse_o (aon_wkup_ack)
+ );
+
+ assign aon_timer_wkup_req_o = aon_wkup_req_q;
+
+ ////////////////////////
+ // Interrupt Handling //
+ ////////////////////////
+
+ // Synchronize the interrupt pulses from the counters into the clk_i domain.
+ prim_pulse_sync wkup_intr_req_sync (
+ .clk_src_i (clk_aon_i),
+ .rst_src_ni (rst_aon_ni),
+ .src_pulse_i (aon_wkup_intr_set),
+ .clk_dst_i (clk_i),
+ .rst_dst_ni (rst_ni),
+ .dst_pulse_o (wkup_intr_set)
+ );
+
+ prim_pulse_sync wdog_intr_req_sync (
+ .clk_src_i (clk_aon_i),
+ .rst_src_ni (rst_aon_ni),
+ .src_pulse_i (aon_wdog_intr_set),
+ .clk_dst_i (clk_i),
+ .rst_dst_ni (rst_ni),
+ .dst_pulse_o (wdog_intr_set)
+ );
+
+ // Registers to interrupt
+ assign intr_aon_test_qe = reg2hw.intr_test.wkup_timer_expired.qe |
+ reg2hw.intr_test.wdog_timer_expired.qe;
+ assign intr_aon_test_q [AON_WKUP] = reg2hw.intr_test.wkup_timer_expired.q;
+ assign intr_aon_state_q[AON_WKUP] = reg2hw.intr_state.wkup_timer_expired.q;
+ assign intr_aon_test_q [AON_WDOG] = reg2hw.intr_test.wdog_timer_expired.q;
+ assign intr_aon_state_q[AON_WDOG] = reg2hw.intr_state.wdog_timer_expired.q;
+
+ // Interrupts to registers
+ assign hw2reg.intr_state.wkup_timer_expired.d = intr_aon_state_d[AON_WKUP];
+ assign hw2reg.intr_state.wkup_timer_expired.de = intr_aon_state_de;
+ assign hw2reg.intr_state.wdog_timer_expired.d = intr_aon_state_d[AON_WDOG];
+ assign hw2reg.intr_state.wdog_timer_expired.de = intr_aon_state_de;
+
+ prim_intr_hw #(
+ .Width (2)
+ ) u_intr_hw (
+ .clk_i,
+ .rst_ni,
+ .event_intr_i ({wdog_intr_set, wkup_intr_set}),
+
+ .reg2hw_intr_enable_q_i (2'b11),
+ .reg2hw_intr_test_q_i (intr_aon_test_q),
+ .reg2hw_intr_test_qe_i (intr_aon_test_qe),
+ .reg2hw_intr_state_q_i (intr_aon_state_q),
+ .hw2reg_intr_state_de_o (intr_aon_state_de),
+ .hw2reg_intr_state_d_o (intr_aon_state_d),
+
+ .intr_o (intr_out)
+ );
+
+ assign intr_wkup_timer_expired_o = intr_out[AON_WKUP];
+ assign intr_wdog_timer_bark_o = intr_out[AON_WDOG];
+
+ ///////////////////
+ // Reset Request //
+ ///////////////////
+
+ // Once set, the reset request remains asserted until the next aon reset
+ assign aon_rst_req_d = aon_rst_req_set | aon_rst_req_q;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ aon_rst_req_q <= 1'b0;
+ end else begin
+ aon_rst_req_q <= aon_rst_req_d;
+ end
+ end
+
+ assign rst_req_aon_timer_o = aon_rst_req_q;
+
+endmodule
diff --git a/hw/ip/aon_timer/rtl/aon_timer_core.sv b/hw/ip/aon_timer/rtl/aon_timer_core.sv
new file mode 100644
index 0000000..b152a01
--- /dev/null
+++ b/hw/ip/aon_timer/rtl/aon_timer_core.sv
@@ -0,0 +1,196 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+
+module aon_timer_core (
+ input logic clk_aon_i,
+ input logic rst_aon_ni,
+
+ input lc_ctrl_pkg::lc_tx_t [2:0] lc_escalate_en_i,
+ input logic sleep_mode_i,
+
+ // Register read outputs
+ output logic wkup_enable_o,
+ output logic [11:0] wkup_prescaler_o,
+ output logic [31:0] wkup_thold_o,
+ output logic [31:0] wkup_count_o,
+ output logic wdog_enable_o,
+ output logic wdog_pause_o,
+ output logic [31:0] wdog_bark_thold_o,
+ output logic [31:0] wdog_bite_thold_o,
+ output logic [31:0] wdog_count_o,
+
+ // Register write inputs
+ input logic wkup_ctrl_reg_wr_i,
+ input logic [12:0] wkup_ctrl_wr_data_i,
+ input logic wkup_thold_reg_wr_i,
+ input logic [31:0] wkup_thold_wr_data_i,
+ input logic wkup_count_reg_wr_i,
+ input logic [31:0] wkup_count_wr_data_i,
+ input logic wdog_ctrl_reg_wr_i,
+ input logic [1:0] wdog_ctrl_wr_data_i,
+ input logic wdog_bark_thold_reg_wr_i,
+ input logic [31:0] wdog_bark_thold_wr_data_i,
+ input logic wdog_bite_thold_reg_wr_i,
+ input logic [31:0] wdog_bite_thold_wr_data_i,
+ input logic wdog_count_reg_wr_i,
+ input logic [31:0] wdog_count_wr_data_i,
+
+ output logic wkup_intr_o,
+ output logic wdog_intr_o,
+ output logic wdog_reset_req_o
+);
+
+ // Wakeup signals
+ logic wkup_enable_d, wkup_enable_q;
+ logic [11:0] wkup_prescaler_d, wkup_prescaler_q;
+ logic [31:0] wkup_thold_d, wkup_thold_q;
+ logic [11:0] prescale_count_d, prescale_count_q;
+ logic prescale_en;
+ logic wkup_incr, wkup_count_en;
+ logic [31:0] wkup_count_d, wkup_count_q;
+ // Watchdog signals
+ logic wdog_enable_d, wdog_enable_q;
+ logic wdog_pause_d, wdog_pause_q;
+ logic [31:0] wdog_bark_thold_d, wdog_bark_thold_q;
+ logic [31:0] wdog_bite_thold_d, wdog_bite_thold_q;
+ logic wdog_incr, wdog_count_en;
+ logic [31:0] wdog_count_d, wdog_count_q;
+
+ //////////////////
+ // Wakeup Timer //
+ //////////////////
+
+ // Wakeup control register
+ assign wkup_prescaler_d = wkup_ctrl_wr_data_i[12:1];
+ assign wkup_enable_d = wkup_ctrl_wr_data_i[0];
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wkup_prescaler_q <= 12'h000;
+ wkup_enable_q <= 1'b0;
+ end else if (wkup_ctrl_reg_wr_i) begin
+ wkup_prescaler_q <= wkup_prescaler_d;
+ wkup_enable_q <= wkup_enable_d;
+ end
+ end
+
+ assign wkup_enable_o = wkup_enable_q;
+ assign wkup_prescaler_o = wkup_prescaler_q;
+
+ // Wakeup threshold register
+ assign wkup_thold_d = wkup_thold_wr_data_i;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wkup_thold_q <= 32'd0;
+ end else if (wkup_thold_reg_wr_i) begin
+ wkup_thold_q <= wkup_thold_d;
+ end
+ end
+
+ assign wkup_thold_o = wkup_thold_q;
+
+ // Prescaler counter
+ assign prescale_count_d = wkup_incr ? 12'h000 : (prescale_count_q + 12'h001);
+ assign prescale_en = lc_escalate_en_i[0] == lc_ctrl_pkg::Off;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ prescale_count_q <= 12'h000;
+ end else if (prescale_en) begin
+ prescale_count_q <= prescale_count_d;
+ end
+ end
+
+ // Wakeup timer count
+ assign wkup_incr = (lc_escalate_en_i[1] == lc_ctrl_pkg::Off) & wkup_enable_q &
+ (prescale_count_q == wkup_prescaler_q);
+ assign wkup_count_d = wkup_count_reg_wr_i ? wkup_count_wr_data_i :
+ (wkup_count_q + 32'd1);
+ assign wkup_count_en = wkup_incr | wkup_count_reg_wr_i;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wkup_count_q <= 32'd0;
+ end else if (wkup_count_en) begin
+ wkup_count_q <= wkup_count_d;
+ end
+ end
+
+ assign wkup_count_o = wkup_count_q;
+
+ // Timer interrupt
+ assign wkup_intr_o = wkup_incr & (wkup_count_q == wkup_thold_q);
+
+ ////////////////////
+ // Watchdog Timer //
+ ////////////////////
+
+ // Watchdog control register
+ assign wdog_pause_d = wdog_ctrl_wr_data_i[1];
+ assign wdog_enable_d = wdog_ctrl_wr_data_i[0];
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wdog_pause_q <= 1'b0;
+ wdog_enable_q <= 1'b0;
+ end else if (wdog_ctrl_reg_wr_i) begin
+ wdog_pause_q <= wdog_pause_d;
+ wdog_enable_q <= wdog_enable_d;
+ end
+ end
+
+ assign wdog_enable_o = wdog_enable_q;
+ assign wdog_pause_o = wdog_pause_q;
+
+ // Watchdog bark threshold register
+ assign wdog_bark_thold_d = wdog_bark_thold_wr_data_i;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wdog_bark_thold_q <= 32'd0;
+ end else if (wdog_bark_thold_reg_wr_i) begin
+ wdog_bark_thold_q <= wdog_bark_thold_d;
+ end
+ end
+
+ assign wdog_bark_thold_o = wdog_bark_thold_q;
+
+ // Watchdog bite threshold register
+ assign wdog_bite_thold_d = wdog_bite_thold_wr_data_i;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wdog_bite_thold_q <= 32'd0;
+ end else if (wdog_bite_thold_reg_wr_i) begin
+ wdog_bite_thold_q <= wdog_bite_thold_d;
+ end
+ end
+
+ assign wdog_bite_thold_o = wdog_bite_thold_q;
+
+ // Watchdog timer count
+ assign wdog_incr = wdog_enable_q & (lc_escalate_en_i[2] == lc_ctrl_pkg::Off) &
+ ~(sleep_mode_i & wdog_pause_q);
+ assign wdog_count_d = wdog_count_reg_wr_i ? wdog_count_wr_data_i :
+ (wdog_count_q + 32'd1);
+ assign wdog_count_en = wdog_incr | wdog_count_reg_wr_i;
+
+ always_ff @(posedge clk_aon_i or negedge rst_aon_ni) begin
+ if (!rst_aon_ni) begin
+ wdog_count_q <= 32'd0;
+ end else if (wdog_count_en) begin
+ wdog_count_q <= wdog_count_d;
+ end
+ end
+
+ assign wdog_count_o = wdog_count_q;
+
+ // Timer interrupt
+ assign wdog_intr_o = wdog_incr & (wdog_count_q == wdog_bark_thold_q);
+ // Timer reset
+ assign wdog_reset_req_o = wdog_incr & (wdog_count_q == wdog_bite_thold_q);
+
+endmodule
diff --git a/hw/ip/aon_timer/rtl/aon_timer_reg_pkg.sv b/hw/ip/aon_timer/rtl/aon_timer_reg_pkg.sv
new file mode 100644
index 0000000..8737982
--- /dev/null
+++ b/hw/ip/aon_timer/rtl/aon_timer_reg_pkg.sv
@@ -0,0 +1,217 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package aon_timer_reg_pkg;
+
+ // Address width within the block
+ parameter int BlockAw = 6;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } enable;
+ struct packed {
+ logic [11:0] q;
+ logic qe;
+ } prescaler;
+ } aon_timer_reg2hw_wkup_ctrl_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } aon_timer_reg2hw_wkup_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } aon_timer_reg2hw_wkup_count_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } enable;
+ struct packed {
+ logic q;
+ logic qe;
+ } pause_in_sleep;
+ } aon_timer_reg2hw_wdog_ctrl_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } aon_timer_reg2hw_wdog_bark_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } aon_timer_reg2hw_wdog_bite_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] q;
+ logic qe;
+ } aon_timer_reg2hw_wdog_count_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ } wkup_timer_expired;
+ struct packed {
+ logic q;
+ } wdog_timer_expired;
+ } aon_timer_reg2hw_intr_state_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } wkup_timer_expired;
+ struct packed {
+ logic q;
+ logic qe;
+ } wdog_timer_expired;
+ } aon_timer_reg2hw_intr_test_reg_t;
+
+ typedef struct packed {
+ logic q;
+ logic qe;
+ } aon_timer_reg2hw_wkup_cause_reg_t;
+
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } enable;
+ struct packed {
+ logic [11:0] d;
+ } prescaler;
+ } aon_timer_hw2reg_wkup_ctrl_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ } aon_timer_hw2reg_wkup_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ } aon_timer_hw2reg_wkup_count_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ } enable;
+ struct packed {
+ logic d;
+ } pause_in_sleep;
+ } aon_timer_hw2reg_wdog_ctrl_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ } aon_timer_hw2reg_wdog_bark_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ } aon_timer_hw2reg_wdog_bite_thold_reg_t;
+
+ typedef struct packed {
+ logic [31:0] d;
+ } aon_timer_hw2reg_wdog_count_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } wkup_timer_expired;
+ struct packed {
+ logic d;
+ logic de;
+ } wdog_timer_expired;
+ } aon_timer_hw2reg_intr_state_reg_t;
+
+ typedef struct packed {
+ logic d;
+ } aon_timer_hw2reg_wkup_cause_reg_t;
+
+
+ ///////////////////////////////////////
+ // Register to internal design logic //
+ ///////////////////////////////////////
+ typedef struct packed {
+ aon_timer_reg2hw_wkup_ctrl_reg_t wkup_ctrl; // [191:177]
+ aon_timer_reg2hw_wkup_thold_reg_t wkup_thold; // [176:144]
+ aon_timer_reg2hw_wkup_count_reg_t wkup_count; // [143:111]
+ aon_timer_reg2hw_wdog_ctrl_reg_t wdog_ctrl; // [110:107]
+ aon_timer_reg2hw_wdog_bark_thold_reg_t wdog_bark_thold; // [106:74]
+ aon_timer_reg2hw_wdog_bite_thold_reg_t wdog_bite_thold; // [73:41]
+ aon_timer_reg2hw_wdog_count_reg_t wdog_count; // [40:8]
+ aon_timer_reg2hw_intr_state_reg_t intr_state; // [7:6]
+ aon_timer_reg2hw_intr_test_reg_t intr_test; // [5:2]
+ aon_timer_reg2hw_wkup_cause_reg_t wkup_cause; // [1:0]
+ } aon_timer_reg2hw_t;
+
+ ///////////////////////////////////////
+ // Internal design logic to register //
+ ///////////////////////////////////////
+ typedef struct packed {
+ aon_timer_hw2reg_wkup_ctrl_reg_t wkup_ctrl; // [179:167]
+ aon_timer_hw2reg_wkup_thold_reg_t wkup_thold; // [166:135]
+ aon_timer_hw2reg_wkup_count_reg_t wkup_count; // [134:103]
+ aon_timer_hw2reg_wdog_ctrl_reg_t wdog_ctrl; // [102:101]
+ aon_timer_hw2reg_wdog_bark_thold_reg_t wdog_bark_thold; // [100:69]
+ aon_timer_hw2reg_wdog_bite_thold_reg_t wdog_bite_thold; // [68:37]
+ aon_timer_hw2reg_wdog_count_reg_t wdog_count; // [36:5]
+ aon_timer_hw2reg_intr_state_reg_t intr_state; // [4:1]
+ aon_timer_hw2reg_wkup_cause_reg_t wkup_cause; // [0:0]
+ } aon_timer_hw2reg_t;
+
+ // Register Address
+ parameter logic [BlockAw-1:0] AON_TIMER_WKUP_CTRL_OFFSET = 6'h 0;
+ parameter logic [BlockAw-1:0] AON_TIMER_WKUP_THOLD_OFFSET = 6'h 4;
+ parameter logic [BlockAw-1:0] AON_TIMER_WKUP_COUNT_OFFSET = 6'h 8;
+ parameter logic [BlockAw-1:0] AON_TIMER_WDOG_REGWEN_OFFSET = 6'h c;
+ parameter logic [BlockAw-1:0] AON_TIMER_WDOG_CTRL_OFFSET = 6'h 10;
+ parameter logic [BlockAw-1:0] AON_TIMER_WDOG_BARK_THOLD_OFFSET = 6'h 14;
+ parameter logic [BlockAw-1:0] AON_TIMER_WDOG_BITE_THOLD_OFFSET = 6'h 18;
+ parameter logic [BlockAw-1:0] AON_TIMER_WDOG_COUNT_OFFSET = 6'h 1c;
+ parameter logic [BlockAw-1:0] AON_TIMER_INTR_STATE_OFFSET = 6'h 20;
+ parameter logic [BlockAw-1:0] AON_TIMER_INTR_TEST_OFFSET = 6'h 24;
+ parameter logic [BlockAw-1:0] AON_TIMER_WKUP_CAUSE_OFFSET = 6'h 28;
+
+
+ // Register Index
+ typedef enum int {
+ AON_TIMER_WKUP_CTRL,
+ AON_TIMER_WKUP_THOLD,
+ AON_TIMER_WKUP_COUNT,
+ AON_TIMER_WDOG_REGWEN,
+ AON_TIMER_WDOG_CTRL,
+ AON_TIMER_WDOG_BARK_THOLD,
+ AON_TIMER_WDOG_BITE_THOLD,
+ AON_TIMER_WDOG_COUNT,
+ AON_TIMER_INTR_STATE,
+ AON_TIMER_INTR_TEST,
+ AON_TIMER_WKUP_CAUSE
+ } aon_timer_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] AON_TIMER_PERMIT [11] = '{
+ 4'b 0011, // index[ 0] AON_TIMER_WKUP_CTRL
+ 4'b 1111, // index[ 1] AON_TIMER_WKUP_THOLD
+ 4'b 1111, // index[ 2] AON_TIMER_WKUP_COUNT
+ 4'b 0001, // index[ 3] AON_TIMER_WDOG_REGWEN
+ 4'b 0001, // index[ 4] AON_TIMER_WDOG_CTRL
+ 4'b 1111, // index[ 5] AON_TIMER_WDOG_BARK_THOLD
+ 4'b 1111, // index[ 6] AON_TIMER_WDOG_BITE_THOLD
+ 4'b 1111, // index[ 7] AON_TIMER_WDOG_COUNT
+ 4'b 0001, // index[ 8] AON_TIMER_INTR_STATE
+ 4'b 0001, // index[ 9] AON_TIMER_INTR_TEST
+ 4'b 0001 // index[10] AON_TIMER_WKUP_CAUSE
+ };
+endpackage
+
diff --git a/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv b/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv
new file mode 100644
index 0000000..a7295d0
--- /dev/null
+++ b/hw/ip/aon_timer/rtl/aon_timer_reg_top.sv
@@ -0,0 +1,567 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Register Top module auto-generated by `reggen`
+
+`include "prim_assert.sv"
+
+module aon_timer_reg_top (
+ input clk_i,
+ input rst_ni,
+
+ // Below Regster interface can be changed
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+ // To HW
+ output aon_timer_reg_pkg::aon_timer_reg2hw_t reg2hw, // Write
+ input aon_timer_reg_pkg::aon_timer_hw2reg_t hw2reg, // Read
+
+ // Config
+ input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+ import aon_timer_reg_pkg::* ;
+
+ localparam int AW = 6;
+ localparam int DW = 32;
+ localparam int DBW = DW/8; // Byte Width
+
+ // register signals
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
+
+ logic addrmiss, wr_err;
+
+ logic [DW-1:0] reg_rdata_next;
+
+ tlul_pkg::tl_h2d_t tl_reg_h2d;
+ tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+ assign tl_reg_h2d = tl_i;
+ assign tl_o = tl_reg_d2h;
+
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
+
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
+
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = (devmode_i & addrmiss) | wr_err ;
+
+ // Define SW related signals
+ // Format: <reg>_<field>_{wd|we|qs}
+ // or <reg>_{wd|we|qs} if field == 1 or 0
+ logic wkup_ctrl_enable_qs;
+ logic wkup_ctrl_enable_wd;
+ logic wkup_ctrl_enable_we;
+ logic wkup_ctrl_enable_re;
+ logic [11:0] wkup_ctrl_prescaler_qs;
+ logic [11:0] wkup_ctrl_prescaler_wd;
+ logic wkup_ctrl_prescaler_we;
+ logic wkup_ctrl_prescaler_re;
+ logic [31:0] wkup_thold_qs;
+ logic [31:0] wkup_thold_wd;
+ logic wkup_thold_we;
+ logic wkup_thold_re;
+ logic [31:0] wkup_count_qs;
+ logic [31:0] wkup_count_wd;
+ logic wkup_count_we;
+ logic wkup_count_re;
+ logic wdog_regwen_qs;
+ logic wdog_regwen_wd;
+ logic wdog_regwen_we;
+ logic wdog_ctrl_enable_qs;
+ logic wdog_ctrl_enable_wd;
+ logic wdog_ctrl_enable_we;
+ logic wdog_ctrl_enable_re;
+ logic wdog_ctrl_pause_in_sleep_qs;
+ logic wdog_ctrl_pause_in_sleep_wd;
+ logic wdog_ctrl_pause_in_sleep_we;
+ logic wdog_ctrl_pause_in_sleep_re;
+ logic [31:0] wdog_bark_thold_qs;
+ logic [31:0] wdog_bark_thold_wd;
+ logic wdog_bark_thold_we;
+ logic wdog_bark_thold_re;
+ logic [31:0] wdog_bite_thold_qs;
+ logic [31:0] wdog_bite_thold_wd;
+ logic wdog_bite_thold_we;
+ logic wdog_bite_thold_re;
+ logic [31:0] wdog_count_qs;
+ logic [31:0] wdog_count_wd;
+ logic wdog_count_we;
+ logic wdog_count_re;
+ logic intr_state_wkup_timer_expired_qs;
+ logic intr_state_wkup_timer_expired_wd;
+ logic intr_state_wkup_timer_expired_we;
+ logic intr_state_wdog_timer_expired_qs;
+ logic intr_state_wdog_timer_expired_wd;
+ logic intr_state_wdog_timer_expired_we;
+ logic intr_test_wkup_timer_expired_wd;
+ logic intr_test_wkup_timer_expired_we;
+ logic intr_test_wdog_timer_expired_wd;
+ logic intr_test_wdog_timer_expired_we;
+ logic wkup_cause_qs;
+ logic wkup_cause_wd;
+ logic wkup_cause_we;
+ logic wkup_cause_re;
+
+ // Register instances
+ // R[wkup_ctrl]: V(True)
+
+ // F[enable]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_wkup_ctrl_enable (
+ .re (wkup_ctrl_enable_re),
+ .we (wkup_ctrl_enable_we),
+ .wd (wkup_ctrl_enable_wd),
+ .d (hw2reg.wkup_ctrl.enable.d),
+ .qre (),
+ .qe (reg2hw.wkup_ctrl.enable.qe),
+ .q (reg2hw.wkup_ctrl.enable.q ),
+ .qs (wkup_ctrl_enable_qs)
+ );
+
+
+ // F[prescaler]: 12:1
+ prim_subreg_ext #(
+ .DW (12)
+ ) u_wkup_ctrl_prescaler (
+ .re (wkup_ctrl_prescaler_re),
+ .we (wkup_ctrl_prescaler_we),
+ .wd (wkup_ctrl_prescaler_wd),
+ .d (hw2reg.wkup_ctrl.prescaler.d),
+ .qre (),
+ .qe (reg2hw.wkup_ctrl.prescaler.qe),
+ .q (reg2hw.wkup_ctrl.prescaler.q ),
+ .qs (wkup_ctrl_prescaler_qs)
+ );
+
+
+ // R[wkup_thold]: V(True)
+
+ prim_subreg_ext #(
+ .DW (32)
+ ) u_wkup_thold (
+ .re (wkup_thold_re),
+ .we (wkup_thold_we),
+ .wd (wkup_thold_wd),
+ .d (hw2reg.wkup_thold.d),
+ .qre (),
+ .qe (reg2hw.wkup_thold.qe),
+ .q (reg2hw.wkup_thold.q ),
+ .qs (wkup_thold_qs)
+ );
+
+
+ // R[wkup_count]: V(True)
+
+ prim_subreg_ext #(
+ .DW (32)
+ ) u_wkup_count (
+ .re (wkup_count_re),
+ .we (wkup_count_we),
+ .wd (wkup_count_wd),
+ .d (hw2reg.wkup_count.d),
+ .qre (),
+ .qe (reg2hw.wkup_count.qe),
+ .q (reg2hw.wkup_count.q ),
+ .qs (wkup_count_qs)
+ );
+
+
+ // R[wdog_regwen]: V(False)
+
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("W0C"),
+ .RESVAL (1'h1)
+ ) u_wdog_regwen (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (wdog_regwen_we),
+ .wd (wdog_regwen_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0 ),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+
+ // to register interface (read)
+ .qs (wdog_regwen_qs)
+ );
+
+
+ // R[wdog_ctrl]: V(True)
+
+ // F[enable]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_wdog_ctrl_enable (
+ .re (wdog_ctrl_enable_re),
+ // qualified with register enable
+ .we (wdog_ctrl_enable_we & wdog_regwen_qs),
+ .wd (wdog_ctrl_enable_wd),
+ .d (hw2reg.wdog_ctrl.enable.d),
+ .qre (),
+ .qe (reg2hw.wdog_ctrl.enable.qe),
+ .q (reg2hw.wdog_ctrl.enable.q ),
+ .qs (wdog_ctrl_enable_qs)
+ );
+
+
+ // F[pause_in_sleep]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_wdog_ctrl_pause_in_sleep (
+ .re (wdog_ctrl_pause_in_sleep_re),
+ // qualified with register enable
+ .we (wdog_ctrl_pause_in_sleep_we & wdog_regwen_qs),
+ .wd (wdog_ctrl_pause_in_sleep_wd),
+ .d (hw2reg.wdog_ctrl.pause_in_sleep.d),
+ .qre (),
+ .qe (reg2hw.wdog_ctrl.pause_in_sleep.qe),
+ .q (reg2hw.wdog_ctrl.pause_in_sleep.q ),
+ .qs (wdog_ctrl_pause_in_sleep_qs)
+ );
+
+
+ // R[wdog_bark_thold]: V(True)
+
+ prim_subreg_ext #(
+ .DW (32)
+ ) u_wdog_bark_thold (
+ .re (wdog_bark_thold_re),
+ // qualified with register enable
+ .we (wdog_bark_thold_we & wdog_regwen_qs),
+ .wd (wdog_bark_thold_wd),
+ .d (hw2reg.wdog_bark_thold.d),
+ .qre (),
+ .qe (reg2hw.wdog_bark_thold.qe),
+ .q (reg2hw.wdog_bark_thold.q ),
+ .qs (wdog_bark_thold_qs)
+ );
+
+
+ // R[wdog_bite_thold]: V(True)
+
+ prim_subreg_ext #(
+ .DW (32)
+ ) u_wdog_bite_thold (
+ .re (wdog_bite_thold_re),
+ // qualified with register enable
+ .we (wdog_bite_thold_we & wdog_regwen_qs),
+ .wd (wdog_bite_thold_wd),
+ .d (hw2reg.wdog_bite_thold.d),
+ .qre (),
+ .qe (reg2hw.wdog_bite_thold.qe),
+ .q (reg2hw.wdog_bite_thold.q ),
+ .qs (wdog_bite_thold_qs)
+ );
+
+
+ // R[wdog_count]: V(True)
+
+ prim_subreg_ext #(
+ .DW (32)
+ ) u_wdog_count (
+ .re (wdog_count_re),
+ .we (wdog_count_we),
+ .wd (wdog_count_wd),
+ .d (hw2reg.wdog_count.d),
+ .qre (),
+ .qe (reg2hw.wdog_count.qe),
+ .q (reg2hw.wdog_count.q ),
+ .qs (wdog_count_qs)
+ );
+
+
+ // R[intr_state]: V(False)
+
+ // F[wkup_timer_expired]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("W1C"),
+ .RESVAL (1'h0)
+ ) u_intr_state_wkup_timer_expired (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (intr_state_wkup_timer_expired_we),
+ .wd (intr_state_wkup_timer_expired_wd),
+
+ // from internal hardware
+ .de (hw2reg.intr_state.wkup_timer_expired.de),
+ .d (hw2reg.intr_state.wkup_timer_expired.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.intr_state.wkup_timer_expired.q ),
+
+ // to register interface (read)
+ .qs (intr_state_wkup_timer_expired_qs)
+ );
+
+
+ // F[wdog_timer_expired]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("W1C"),
+ .RESVAL (1'h0)
+ ) u_intr_state_wdog_timer_expired (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (intr_state_wdog_timer_expired_we),
+ .wd (intr_state_wdog_timer_expired_wd),
+
+ // from internal hardware
+ .de (hw2reg.intr_state.wdog_timer_expired.de),
+ .d (hw2reg.intr_state.wdog_timer_expired.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.intr_state.wdog_timer_expired.q ),
+
+ // to register interface (read)
+ .qs (intr_state_wdog_timer_expired_qs)
+ );
+
+
+ // R[intr_test]: V(True)
+
+ // F[wkup_timer_expired]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_intr_test_wkup_timer_expired (
+ .re (1'b0),
+ .we (intr_test_wkup_timer_expired_we),
+ .wd (intr_test_wkup_timer_expired_wd),
+ .d ('0),
+ .qre (),
+ .qe (reg2hw.intr_test.wkup_timer_expired.qe),
+ .q (reg2hw.intr_test.wkup_timer_expired.q ),
+ .qs ()
+ );
+
+
+ // F[wdog_timer_expired]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_intr_test_wdog_timer_expired (
+ .re (1'b0),
+ .we (intr_test_wdog_timer_expired_we),
+ .wd (intr_test_wdog_timer_expired_wd),
+ .d ('0),
+ .qre (),
+ .qe (reg2hw.intr_test.wdog_timer_expired.qe),
+ .q (reg2hw.intr_test.wdog_timer_expired.q ),
+ .qs ()
+ );
+
+
+ // R[wkup_cause]: V(True)
+
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_wkup_cause (
+ .re (wkup_cause_re),
+ .we (wkup_cause_we),
+ .wd (wkup_cause_wd),
+ .d (hw2reg.wkup_cause.d),
+ .qre (),
+ .qe (reg2hw.wkup_cause.qe),
+ .q (reg2hw.wkup_cause.q ),
+ .qs (wkup_cause_qs)
+ );
+
+
+
+
+ logic [10:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[ 0] = (reg_addr == AON_TIMER_WKUP_CTRL_OFFSET);
+ addr_hit[ 1] = (reg_addr == AON_TIMER_WKUP_THOLD_OFFSET);
+ addr_hit[ 2] = (reg_addr == AON_TIMER_WKUP_COUNT_OFFSET);
+ addr_hit[ 3] = (reg_addr == AON_TIMER_WDOG_REGWEN_OFFSET);
+ addr_hit[ 4] = (reg_addr == AON_TIMER_WDOG_CTRL_OFFSET);
+ addr_hit[ 5] = (reg_addr == AON_TIMER_WDOG_BARK_THOLD_OFFSET);
+ addr_hit[ 6] = (reg_addr == AON_TIMER_WDOG_BITE_THOLD_OFFSET);
+ addr_hit[ 7] = (reg_addr == AON_TIMER_WDOG_COUNT_OFFSET);
+ addr_hit[ 8] = (reg_addr == AON_TIMER_INTR_STATE_OFFSET);
+ addr_hit[ 9] = (reg_addr == AON_TIMER_INTR_TEST_OFFSET);
+ addr_hit[10] = (reg_addr == AON_TIMER_WKUP_CAUSE_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = 1'b0;
+ if (addr_hit[ 0] && reg_we && (AON_TIMER_PERMIT[ 0] != (AON_TIMER_PERMIT[ 0] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 1] && reg_we && (AON_TIMER_PERMIT[ 1] != (AON_TIMER_PERMIT[ 1] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 2] && reg_we && (AON_TIMER_PERMIT[ 2] != (AON_TIMER_PERMIT[ 2] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 3] && reg_we && (AON_TIMER_PERMIT[ 3] != (AON_TIMER_PERMIT[ 3] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 4] && reg_we && (AON_TIMER_PERMIT[ 4] != (AON_TIMER_PERMIT[ 4] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 5] && reg_we && (AON_TIMER_PERMIT[ 5] != (AON_TIMER_PERMIT[ 5] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 6] && reg_we && (AON_TIMER_PERMIT[ 6] != (AON_TIMER_PERMIT[ 6] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 7] && reg_we && (AON_TIMER_PERMIT[ 7] != (AON_TIMER_PERMIT[ 7] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 8] && reg_we && (AON_TIMER_PERMIT[ 8] != (AON_TIMER_PERMIT[ 8] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[ 9] && reg_we && (AON_TIMER_PERMIT[ 9] != (AON_TIMER_PERMIT[ 9] & reg_be))) wr_err = 1'b1 ;
+ if (addr_hit[10] && reg_we && (AON_TIMER_PERMIT[10] != (AON_TIMER_PERMIT[10] & reg_be))) wr_err = 1'b1 ;
+ end
+
+ assign wkup_ctrl_enable_we = addr_hit[0] & reg_we & ~wr_err;
+ assign wkup_ctrl_enable_wd = reg_wdata[0];
+ assign wkup_ctrl_enable_re = addr_hit[0] && reg_re;
+
+ assign wkup_ctrl_prescaler_we = addr_hit[0] & reg_we & ~wr_err;
+ assign wkup_ctrl_prescaler_wd = reg_wdata[12:1];
+ assign wkup_ctrl_prescaler_re = addr_hit[0] && reg_re;
+
+ assign wkup_thold_we = addr_hit[1] & reg_we & ~wr_err;
+ assign wkup_thold_wd = reg_wdata[31:0];
+ assign wkup_thold_re = addr_hit[1] && reg_re;
+
+ assign wkup_count_we = addr_hit[2] & reg_we & ~wr_err;
+ assign wkup_count_wd = reg_wdata[31:0];
+ assign wkup_count_re = addr_hit[2] && reg_re;
+
+ assign wdog_regwen_we = addr_hit[3] & reg_we & ~wr_err;
+ assign wdog_regwen_wd = reg_wdata[0];
+
+ assign wdog_ctrl_enable_we = addr_hit[4] & reg_we & ~wr_err;
+ assign wdog_ctrl_enable_wd = reg_wdata[0];
+ assign wdog_ctrl_enable_re = addr_hit[4] && reg_re;
+
+ assign wdog_ctrl_pause_in_sleep_we = addr_hit[4] & reg_we & ~wr_err;
+ assign wdog_ctrl_pause_in_sleep_wd = reg_wdata[1];
+ assign wdog_ctrl_pause_in_sleep_re = addr_hit[4] && reg_re;
+
+ assign wdog_bark_thold_we = addr_hit[5] & reg_we & ~wr_err;
+ assign wdog_bark_thold_wd = reg_wdata[31:0];
+ assign wdog_bark_thold_re = addr_hit[5] && reg_re;
+
+ assign wdog_bite_thold_we = addr_hit[6] & reg_we & ~wr_err;
+ assign wdog_bite_thold_wd = reg_wdata[31:0];
+ assign wdog_bite_thold_re = addr_hit[6] && reg_re;
+
+ assign wdog_count_we = addr_hit[7] & reg_we & ~wr_err;
+ assign wdog_count_wd = reg_wdata[31:0];
+ assign wdog_count_re = addr_hit[7] && reg_re;
+
+ assign intr_state_wkup_timer_expired_we = addr_hit[8] & reg_we & ~wr_err;
+ assign intr_state_wkup_timer_expired_wd = reg_wdata[0];
+
+ assign intr_state_wdog_timer_expired_we = addr_hit[8] & reg_we & ~wr_err;
+ assign intr_state_wdog_timer_expired_wd = reg_wdata[1];
+
+ assign intr_test_wkup_timer_expired_we = addr_hit[9] & reg_we & ~wr_err;
+ assign intr_test_wkup_timer_expired_wd = reg_wdata[0];
+
+ assign intr_test_wdog_timer_expired_we = addr_hit[9] & reg_we & ~wr_err;
+ assign intr_test_wdog_timer_expired_wd = reg_wdata[1];
+
+ assign wkup_cause_we = addr_hit[10] & reg_we & ~wr_err;
+ assign wkup_cause_wd = reg_wdata[0];
+ assign wkup_cause_re = addr_hit[10] && reg_re;
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = wkup_ctrl_enable_qs;
+ reg_rdata_next[12:1] = wkup_ctrl_prescaler_qs;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[31:0] = wkup_thold_qs;
+ end
+
+ addr_hit[2]: begin
+ reg_rdata_next[31:0] = wkup_count_qs;
+ end
+
+ addr_hit[3]: begin
+ reg_rdata_next[0] = wdog_regwen_qs;
+ end
+
+ addr_hit[4]: begin
+ reg_rdata_next[0] = wdog_ctrl_enable_qs;
+ reg_rdata_next[1] = wdog_ctrl_pause_in_sleep_qs;
+ end
+
+ addr_hit[5]: begin
+ reg_rdata_next[31:0] = wdog_bark_thold_qs;
+ end
+
+ addr_hit[6]: begin
+ reg_rdata_next[31:0] = wdog_bite_thold_qs;
+ end
+
+ addr_hit[7]: begin
+ reg_rdata_next[31:0] = wdog_count_qs;
+ end
+
+ addr_hit[8]: begin
+ reg_rdata_next[0] = intr_state_wkup_timer_expired_qs;
+ reg_rdata_next[1] = intr_state_wdog_timer_expired_qs;
+ end
+
+ addr_hit[9]: begin
+ reg_rdata_next[0] = '0;
+ reg_rdata_next[1] = '0;
+ end
+
+ addr_hit[10]: begin
+ reg_rdata_next[0] = wkup_cause_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // Assertions for Register Interface
+ `ASSERT_PULSE(wePulse, reg_we)
+ `ASSERT_PULSE(rePulse, reg_re)
+
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+ // this is formulated as an assumption such that the FPV testbenches do disprove this
+ // property by mistake
+ `ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.parity_en == 1'b0)
+
+endmodule