diff --git a/hw/ip_templates/clkmgr/FUSESOC_IGNORE b/hw/ip_templates/clkmgr/FUSESOC_IGNORE
new file mode 100644
index 00000000000000..8b137891791fe9
--- /dev/null
+++ b/hw/ip_templates/clkmgr/FUSESOC_IGNORE
@@ -0,0 +1 @@
+
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/BUILD b/hw/top_earlgrey/ip_autogen/clkmgr/BUILD
new file mode 100644
index 00000000000000..1d0a656815a103
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/BUILD
@@ -0,0 +1,12 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "all_files",
+ srcs = glob(["**"]) + [
+ "//hw/ip/clkmgr/data:all_files",
+ ],
+)
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/FUSESOC_IGNORE b/hw/top_earlgrey/ip_autogen/clkmgr/FUSESOC_IGNORE
new file mode 100644
index 00000000000000..8b137891791fe9
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/FUSESOC_IGNORE
@@ -0,0 +1 @@
+
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/README.md b/hw/top_earlgrey/ip_autogen/clkmgr/README.md
new file mode 100644
index 00000000000000..5a5ca07d16d3aa
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/README.md
@@ -0,0 +1,18 @@
+# Clock Manager HWIP Technical Specification
+
+[`clkmgr`](https://reports.opentitan.org/hw/ip/clkmgr/dv/latest/report.html):
+![](https://dashboards.lowrisc.org/badges/dv/clkmgr/test.svg)
+![](https://dashboards.lowrisc.org/badges/dv/clkmgr/passing.svg)
+![](https://dashboards.lowrisc.org/badges/dv/clkmgr/functional.svg)
+![](https://dashboards.lowrisc.org/badges/dv/clkmgr/code.svg)
+
+# Overview
+
+This document specifies the functionality of the OpenTitan clock manager.
+
+## Features
+
+- Attribute based controls of OpenTitan clocks.
+- Minimal software clock controls to reduce risks in clock manipulation.
+- External clock switch support
+- Clock frequency /time-out measurement
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr.core b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr.core
new file mode 100644
index 00000000000000..643f1a29e7d1f7
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr.core
@@ -0,0 +1,75 @@
+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:opentitan:top_earlgrey_clkmgr:0.1
+description: "Top specific clock manager "
+virtual:
+ - lowrisc:ip_interfaces:clkmgr
+
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:ip:lc_ctrl_pkg
+ - lowrisc:ip_interfaces:pwrmgr_pkg
+ - lowrisc:ip:tlul
+ - lowrisc:prim:all
+ - lowrisc:prim:buf
+ - lowrisc:prim:clock_buf
+ - lowrisc:prim:clock_div
+ - lowrisc:prim:clock_gating
+ - lowrisc:prim:edge_detector
+ - lowrisc:prim:lc_sync
+ - lowrisc:prim:lc_sender
+ - lowrisc:prim:measure
+ - lowrisc:opentitan:top_earlgrey_clkmgr_pkg:0.1
+ - lowrisc:opentitan:top_earlgrey_clkmgr_reg:0.1
+ files:
+ - rtl/clkmgr.sv
+ - rtl/clkmgr_byp.sv
+ - rtl/clkmgr_clk_status.sv
+ - rtl/clkmgr_meas_chk.sv
+ - rtl/clkmgr_root_ctrl.sv
+ - rtl/clkmgr_trans.sv
+ file_type: systemVerilogSource
+
+ files_verilator_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+ - lowrisc:lint:comportable
+ files:
+ file_type: vlt
+
+ files_ascentlint_waiver:
+ depend:
+ # common waivers
+ - lowrisc:lint:common
+ - lowrisc:lint:comportable
+ files:
+ - lint/clkmgr.waiver
+ file_type: waiver
+
+parameters:
+ SYNTHESIS:
+ datatype: bool
+ paramtype: vlogdefine
+
+targets:
+ default: &default_target
+ filesets:
+ - tool_verilator ? (files_verilator_waiver)
+ - tool_ascentlint ? (files_ascentlint_waiver)
+ - files_rtl
+ toplevel: clkmgr
+
+ lint:
+ <<: *default_target
+ default_tool: verilator
+ parameters:
+ - SYNTHESIS=true
+ tools:
+ verilator:
+ mode: lint-only
+ verilator_options:
+ - "-Wall"
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_pkg.core b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_pkg.core
new file mode 100644
index 00000000000000..a445d0e59f0d31
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_pkg.core
@@ -0,0 +1,23 @@
+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:opentitan:top_earlgrey_clkmgr_pkg:0.1
+description: "Top specific clock manager package"
+virtual:
+ - lowrisc:ip_interfaces:clkmgr_pkg
+
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:constants:top_pkg
+ - lowrisc:ip_interfaces:pwrmgr_pkg
+ - lowrisc:prim:mubi
+ files:
+ - rtl/clkmgr_pkg.sv
+ file_type: systemVerilogSource
+
+targets:
+ default: &default_target
+ filesets:
+ - files_rtl
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_reg.core b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_reg.core
new file mode 100644
index 00000000000000..a6122f8454188a
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/clkmgr_reg.core
@@ -0,0 +1,22 @@
+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:opentitan:top_earlgrey_clkmgr_reg:0.1
+description: "Clock manager registers"
+virtual:
+ - lowrisc:ip_interfaces:clkmgr_reg
+
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:tlul:headers
+ files:
+ - rtl/clkmgr_reg_pkg.sv
+ - rtl/clkmgr_reg_top.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_rtl
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/data/BUILD b/hw/top_earlgrey/ip_autogen/clkmgr/data/BUILD
new file mode 100644
index 00000000000000..b98cf3975a1a35
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/data/BUILD
@@ -0,0 +1,19 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+load("//rules:autogen.bzl", "autogen_hjson_header")
+
+package(default_visibility = ["//visibility:public"])
+
+autogen_hjson_header(
+ name = "clkmgr_regs",
+ srcs = [
+ "clkmgr.hjson",
+ ],
+)
+
+filegroup(
+ name = "all_files",
+ srcs = glob(["**"]),
+)
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr.hjson b/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr.hjson
new file mode 100644
index 00000000000000..c952766ae53478
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr.hjson
@@ -0,0 +1,1020 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+# CLKMGR register template
+#
+{
+ name: "clkmgr",
+ human_name: "Clock Manager",
+ one_line_desc: "Derives and monitors on-chip clock signals, handles clock gating requests from power manager and software",
+ one_paragraph_desc: '''
+ Clock Manager derives on-chip clocks from root clock signals provided by Analog Sensor Top (AST).
+ Input and output clocks may be asynchronous to each other.
+ During clock derivation, Clock Manager can divide clocks to lower frequencies and gate clocks based on control signals from the power manager and to a limited extent from software.
+ For example, the idle status of relevant hardware blocks is tracked and clock gating requests from software are ignored as long as these blocks are active.
+ Further security features include switchable clock jitter, continuous monitoring of clock frequencies, and various countermeasures to deter fault injection (FI) attacks.
+ '''
+ // Unique comportable IP identifier defined under KNOWN_CIP_IDS in the regtool.
+ cip_id: "4",
+ design_spec: "../doc",
+ dv_doc: "../doc/dv",
+ hw_checklist: "../doc/checklist",
+ sw_checklist: "/sw/device/lib/dif/dif_clkmgr",
+ revisions: [
+ {
+ version: "1.0.0",
+ life_stage: "L1",
+ design_stage: "D2S",
+ verification_stage: "V2S",
+ dif_stage: "S2",
+ }
+ ]
+ scan: "true",
+ clocking: [
+ {clock: "clk_i", reset: "rst_ni", primary: true},
+ {reset: "rst_root_ni"},
+ {clock: "clk_main_i", reset: "rst_main_ni"},
+ {clock: "clk_io_i", reset: "rst_io_ni"},
+ {clock: "clk_usb_i", reset: "rst_usb_ni"},
+ {clock: "clk_aon_i", reset: "rst_aon_ni"},
+ {clock: "clk_io_div2_i", reset: "rst_io_div2_ni", internal: true},
+ {clock: "clk_io_div4_i", reset: "rst_io_div4_ni", internal: true},
+ {reset: "rst_root_main_ni"},
+ {reset: "rst_root_io_ni"},
+ {reset: "rst_root_io_div2_ni"},
+ {reset: "rst_root_io_div4_ni"},
+ {reset: "rst_root_usb_ni"},
+ ]
+ bus_interfaces: [
+ { protocol: "tlul", direction: "device" }
+ ],
+ alert_list: [
+ { name: "recov_fault",
+ desc: '''
+ This recoverable alert is triggered when there are measurement errors.
+ '''
+ }
+ { name: "fatal_fault",
+ desc: '''
+ This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected.
+ '''
+ }
+ ],
+ regwidth: "32",
+ param_list: [
+ { name: "NumGroups",
+ desc: "Number of clock groups",
+ type: "int",
+ default: "7",
+ local: "true"
+ },
+ { name: "NumSwGateableClocks",
+ desc: "Number of SW gateable clocks",
+ type: "int",
+ default: "4",
+ local: "true"
+ },
+ { name: "NumHintableClocks",
+ desc: "Number of hintable clocks",
+ type: "int",
+ default: "4",
+ local: "true"
+ },
+ ],
+
+ features: [
+ { name: "CLKMGR.ENABLE.IO_DIV4",
+ desc: "Gating of IO_DIV4 peripheral clock."
+ }
+ { name: "CLKMGR.ENABLE.IO_DIV2",
+ desc: "Gating of IO_DIV2 peripheral clock."
+ }
+ { name: "CLKMGR.ENABLE.IO",
+ desc: "Gating of IO peripheral clock."
+ }
+ { name: "CLKMGR.ENABLE.USB",
+ desc: "Gating of USB peripheral clock."
+ }
+ { name: "CLKMGR.HINT.AES",
+ desc: "Gating of AES transactional clock."
+ }
+ { name: "CLKMGR.HINT.HMAC",
+ desc: "Gating of HMAC transactional clock."
+ }
+ { name: "CLKMGR.HINT.KMAC",
+ desc: "Gating of KMAC transactional clock."
+ }
+ { name: "CLKMGR.HINT.OTBN",
+ desc: "Gating of OTBN transactional clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.REGWEN",
+ desc: '''Control modification of all clock frequency and timeout
+ measurements.
+ '''
+ }
+ { name: "CLKMGR.MEAS_CTRL.IO",
+ desc: "Frequency and timeout measurements of IO clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.IO_DIV2",
+ desc: "Frequency and timeout measurements of IO_DIV2 clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.IO_DIV4",
+ desc: "Frequency and timeout measurements of IO_DIV4 clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.MAIN",
+ desc: "Frequency and timeout measurements of MAIN clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.USB",
+ desc: "Frequency and timeout measurements of USB clock."
+ }
+ { name: "CLKMGR.MEAS_CTRL.RECOV_ERR",
+ desc: "Frequency and timeout measurements can flag recoverable errors."
+ }
+ { name: "CLKMGR.LC_EXTCLK.SPEED",
+ desc: "Speed of LC controlled modification of external clock."
+ }
+ { name: "CLKMGR.SW_EXTCLK.REGWEN",
+ desc: "Control software modification of external clock configuration."
+ }
+ { name: "CLKMGR.SW_EXTCLK.HIGH_SPEED",
+ desc: "Software configuration of external clock running at 96 MHz."
+ }
+ { name: "CLKMGR.SW_EXTCLK.LOW_SPEED",
+ desc: "Software configuration of external clock running at 48 MHz."
+ }
+ { name: "CLKMGR.JITTER.REGWEN",
+ desc: "Control modification of clock jitter enable."
+ }
+ { name: "CLKMGR.JITTER.ENABLE",
+ desc: "Enable clock jitter."
+ }
+ { name: "CLKMGR.ALERT_HANDLER.CLOCK_STATUS",
+ desc: "Inform alert handler about clock enable status for each clock."
+ }
+]
+
+ inter_signal_list: [
+ { struct: "clkmgr_out",
+ type: "uni",
+ name: "clocks",
+ act: "req",
+ package: "clkmgr_pkg",
+ },
+
+ { struct: "clkmgr_cg_en",
+ type: "uni",
+ name: "cg_en",
+ act: "req",
+ package: "clkmgr_pkg",
+ },
+
+ { struct: "lc_tx",
+ type: "uni",
+ name: "lc_hw_debug_en",
+ act: "rcv",
+ package: "lc_ctrl_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "io_clk_byp_req",
+ act: "req",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "io_clk_byp_ack",
+ act: "rcv",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "all_clk_byp_req",
+ act: "req",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "all_clk_byp_ack",
+ act: "rcv",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "hi_speed_sel",
+ act: "req",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "div_step_down_req",
+ act: "rcv",
+ package: "prim_mubi_pkg",
+ },
+
+ { struct: "lc_tx",
+ type: "uni",
+ name: "lc_clk_byp_req",
+ act: "rcv",
+ package: "lc_ctrl_pkg",
+ },
+
+ { struct: "lc_tx",
+ type: "uni",
+ name: "lc_clk_byp_ack",
+ act: "req",
+ package: "lc_ctrl_pkg",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "jitter_en",
+ act: "req",
+ package: "prim_mubi_pkg"
+ },
+
+ // Exported clocks
+
+ { struct: "pwr_clk",
+ type: "req_rsp",
+ name: "pwr",
+ act: "rsp",
+ },
+
+ { struct: "mubi4",
+ type: "uni",
+ name: "idle",
+ act: "rcv",
+ package: "prim_mubi_pkg",
+ width: "4"
+ },
+
+ { struct: "mubi4",
+ desc: "Indicates clocks are calibrated and frequencies accurate",
+ type: "uni",
+ name: "calib_rdy",
+ act: "rcv",
+ package: "prim_mubi_pkg",
+ default: "prim_mubi_pkg::MuBi4True"
+ },
+ ],
+
+ countermeasures: [
+ { name: "BUS.INTEGRITY",
+ desc: "End-to-end bus integrity scheme."
+ },
+ { name: "TIMEOUT.CLK.BKGN_CHK",
+ desc: "Background check for clock timeout."
+ },
+ { name: "MEAS.CLK.BKGN_CHK",
+ desc: "Background check for clock frequency."
+ },
+ { name: "MEAS.CONFIG.SHADOW",
+ desc: "Measurement configurations are shadowed."
+ }
+ { name: "IDLE.INTERSIG.MUBI",
+ desc: "Idle inputs are multibit encoded."
+ }
+ { name: "LC_CTRL.INTERSIG.MUBI",
+ desc: "The life cycle control signals are multibit encoded."
+ }
+ { name: "LC_CTRL_CLK_HANDSHAKE.INTERSIG.MUBI",
+ desc: "The life cycle clock req/ack signals are multibit encoded."
+ }
+ { name: "CLK_HANDSHAKE.INTERSIG.MUBI",
+ desc: "The external clock req/ack signals are multibit encoded."
+ }
+ { name: "DIV.INTERSIG.MUBI",
+ desc: "Divider step down request is multibit encoded."
+ }
+ { name: "JITTER.CONFIG.MUBI",
+ desc: "The jitter enable configuration is multibit encoded."
+ }
+ { name: "IDLE.CTR.REDUN",
+ desc: "Idle counter is duplicated."
+ }
+ { name: "MEAS.CONFIG.REGWEN",
+ desc: "The measurement controls protected with regwen."
+ }
+ { name: "CLK_CTRL.CONFIG.REGWEN",
+ desc: "Software controlled clock requests are proteced with regwen."
+ }
+
+ ]
+
+ registers: [
+ { name: "EXTCLK_CTRL_REGWEN",
+ desc: "External clock control write enable",
+ swaccess: "rw0c",
+ hwaccess: "none",
+ fields: [
+ { bits: "0",
+ name: "EN",
+ resval: "1"
+ desc: '''
+ When 1, the value of !!EXTCLK_CTRL can be set. When 0, writes to !!EXTCLK_CTRL have no
+ effect.
+ '''
+ },
+ ]
+ },
+
+ { name: "EXTCLK_CTRL",
+ desc: '''
+ Select external clock
+ ''',
+ regwen: "EXTCLK_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ fields: [
+ {
+ bits: "3:0",
+ name: "SEL",
+ mubi: true,
+ desc: '''
+ When the current value is not kMultiBitBool4True, writing a value of kMultiBitBool4True
+ selects external clock as clock for the system. Writing any other value has
+ no impact.
+
+ When the current value is kMultiBitBool4True, writing a value of kMultiBitBool4False
+ selects internal clock as clock for the system. Writing any other value during this stage
+ has no impact.
+
+ While this register can always be programmed, it only takes effect when debug functions are enabled
+ in life cycle TEST, DEV or RMA states.
+ '''
+ resval: "false"
+ },
+ {
+ bits: "7:4",
+ name: "HI_SPEED_SEL",
+ mubi: true,
+ desc: '''
+ A value of kMultiBitBool4True selects nominal speed external clock.
+ All other values selects low speed clocks.
+
+ Note this field only has an effect when the !!EXTCLK_CTRL.SEL field is set to
+ kMultiBitBool4True.
+
+ Nominal speed means the external clock is approximately the same frequency as
+ the internal oscillator source. When this option is used, all clocks operate
+ at roughly the nominal frequency.
+
+ Low speed means the external clock is approximately half the frequency of the
+ internal oscillator source. When this option is used, the internal dividers are
+ stepped down. As a result, previously undivided clocks now run at half frequency,
+ while previously divided clocks run at roughly the nominal frequency.
+
+ See external clock switch support in documentation for more details.
+ '''
+ resval: false
+ }
+ ]
+ // avoid writing random values to this register as it could trigger transient checks
+ // in mubi sync
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "EXTCLK_STATUS",
+ desc: '''
+ Status of requested external clock switch
+ ''',
+ swaccess: "ro",
+ hwaccess: "hwo",
+ hwext: "true",
+ fields: [
+ {
+ bits: "3:0",
+ name: "ACK",
+ mubi: true,
+ desc: '''
+ When !!EXTCLK_CTRL.SEL is set to kMultiBitBool4True, this field reflects
+ whether the clock has been switched the external source.
+
+ kMultiBitBool4True indicates the switch is complete.
+ kMultiBitBool4False indicates the switch is either not possible or still ongoing.
+ '''
+ resval: "false"
+ },
+ ]
+ },
+
+ { name: "JITTER_REGWEN",
+ desc: "Jitter write enable",
+ swaccess: "rw0c",
+ hwaccess: "none",
+ fields: [
+ { bits: "0",
+ name: "EN",
+ resval: "1"
+ desc: '''
+ When 1, the value of !!JITTER_ENABLE can be changed. When 0, writes have no
+ effect.
+ '''
+ },
+ ]
+ },
+
+ { name: "JITTER_ENABLE",
+ desc: '''
+ Enable jittery clock
+ ''',
+ swaccess: "rw",
+ hwaccess: "hro",
+ fields: [
+ {
+ mubi: true,
+ bits: "3:0",
+ name: "VAL",
+ desc: '''
+ Enable jittery clock.
+ A value of kMultiBitBool4False disables the jittery clock,
+ while all other values enable jittery clock.
+ ''',
+ resval: false
+ // avoid writing random values to this register as it could trigger transient checks
+ // in mubi sync
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ }
+ ]
+ },
+
+ { name: "CLK_ENABLES",
+ desc: '''
+ Clock enable for software gateable clocks.
+ These clocks are directly controlled by software.
+ ''',
+ swaccess: "rw",
+ hwaccess: "hro",
+ fields: [
+ {
+ bits: "0",
+ name: "CLK_IO_DIV4_PERI_EN",
+ resval: 1,
+ desc: '''
+ 0 CLK_IO_DIV4_PERI is disabled.
+ 1 CLK_IO_DIV4_PERI is enabled.
+ '''
+ }
+ {
+ bits: "1",
+ name: "CLK_IO_DIV2_PERI_EN",
+ resval: 1,
+ desc: '''
+ 0 CLK_IO_DIV2_PERI is disabled.
+ 1 CLK_IO_DIV2_PERI is enabled.
+ '''
+ }
+ {
+ bits: "2",
+ name: "CLK_IO_PERI_EN",
+ resval: 1,
+ desc: '''
+ 0 CLK_IO_PERI is disabled.
+ 1 CLK_IO_PERI is enabled.
+ '''
+ }
+ {
+ bits: "3",
+ name: "CLK_USB_PERI_EN",
+ resval: 1,
+ desc: '''
+ 0 CLK_USB_PERI is disabled.
+ 1 CLK_USB_PERI is enabled.
+ '''
+ }
+ ]
+ // the CLK_ENABLE register cannot be written.
+ // During top level randomized tests, it is possible to disable the clocks and then access
+ // a register in the disabled block. This would lead to a top level hang.
+ tags: ["excl:CsrAllTests:CsrExclAll"]
+ },
+
+ { name: "CLK_HINTS",
+ desc: '''
+ Clock hint for software gateable transactional clocks during active mode.
+ During low power mode, all clocks are gated off regardless of the software hint.
+
+ Transactional clocks are not fully controlled by software. Instead software provides only a disable hint.
+
+ When software provides a disable hint, the clock manager checks to see if the associated hardware block is idle.
+ If the hardware block is idle, then the clock is disabled.
+ If the hardware block is not idle, the clock is kept on.
+
+ For the enable case, the software hint is immediately honored and the clock turned on. Hardware does not provide any
+ feedback in this case.
+ ''',
+ swaccess: "rw",
+ hwaccess: "hro",
+ fields: [
+ {
+ bits: "0",
+ name: "CLK_MAIN_AES_HINT",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_AES can be disabled.
+ 1 CLK_MAIN_AES is enabled.
+ '''
+ }
+ {
+ bits: "1",
+ name: "CLK_MAIN_HMAC_HINT",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_HMAC can be disabled.
+ 1 CLK_MAIN_HMAC is enabled.
+ '''
+ }
+ {
+ bits: "2",
+ name: "CLK_MAIN_KMAC_HINT",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_KMAC can be disabled.
+ 1 CLK_MAIN_KMAC is enabled.
+ '''
+ }
+ {
+ bits: "3",
+ name: "CLK_MAIN_OTBN_HINT",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_OTBN can be disabled.
+ 1 CLK_MAIN_OTBN is enabled.
+ '''
+ }
+ ]
+ // the CLK_HINT register cannot be written.
+ // During top level randomized tests, it is possible to disable the clocks to transactional blocks
+ // and then access a register in the disabled block. This would lead to a top level hang.
+ tags: ["excl:CsrAllTests:CsrExclAll"]
+ },
+
+ { name: "CLK_HINTS_STATUS",
+ desc: '''
+ Since the final state of !!CLK_HINTS is not always determined by software,
+ this register provides read feedback for the current clock state.
+
+ ''',
+ swaccess: "ro",
+ hwaccess: "hwo",
+ fields: [
+ {
+ bits: "0",
+ name: "CLK_MAIN_AES_VAL",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_AES is disabled.
+ 1 CLK_MAIN_AES is enabled.
+ '''
+ }
+ {
+ bits: "1",
+ name: "CLK_MAIN_HMAC_VAL",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_HMAC is disabled.
+ 1 CLK_MAIN_HMAC is enabled.
+ '''
+ }
+ {
+ bits: "2",
+ name: "CLK_MAIN_KMAC_VAL",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_KMAC is disabled.
+ 1 CLK_MAIN_KMAC is enabled.
+ '''
+ }
+ {
+ bits: "3",
+ name: "CLK_MAIN_OTBN_VAL",
+ resval: 1,
+ desc: '''
+ 0 CLK_MAIN_OTBN is disabled.
+ 1 CLK_MAIN_OTBN is enabled.
+ '''
+ }
+ ]
+ // the CLK_HINT_STATUS register is read-only and cannot be checked.
+ // This register's value depends on the IDLE inputs, so cannot be predicted.
+ tags: ["excl:CsrNonInitTests:CsrExclCheck:CsrExclCheck"]
+ },
+
+ { name: "MEASURE_CTRL_REGWEN",
+ desc: "Measurement control write enable",
+ swaccess: "rw0c",
+ hwaccess: "hrw",
+ fields: [
+ { bits: "0",
+ name: "EN",
+ resval: "1"
+ desc: '''
+ When 1, the value of the measurement control can be set. When 0, writes have no
+ effect.
+ '''
+ },
+ ]
+ },
+ { name: "IO_MEAS_CTRL_EN",
+ desc: '''
+ Enable for measurement control
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ async: "clk_io_i",
+ fields: [
+ {
+ bits: "3:0",
+ name: "EN",
+ desc: "Enable measurement for io",
+ mubi: true,
+ resval: false,
+ },
+ ]
+ // Measurements can cause recoverable errors depending on the
+ // thresholds which randomized CSR tests will not predict correctly.
+ // To provide better CSR coverage we allow writing the threshold
+ // fields, but not enabling the counters.
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "IO_MEAS_CTRL_SHADOWED",
+ desc: '''
+ Configuration controls for io measurement.
+
+ The threshold fields are made wider than required (by 1 bit) to ensure
+ there is room to adjust for measurement inaccuracies.
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ async: "clk_io_i",
+ shadowed: "true",
+ update_err_alert: "recov_fault",
+ storage_err_alert: "fatal_fault",
+ fields: [
+ {
+ bits: "9:0",
+ name: "HI",
+ desc: "Max threshold for io measurement",
+ resval: "490"
+ },
+
+ {
+ bits: "19:10",
+ name: "LO",
+ desc: "Min threshold for io measurement",
+ resval: "470"
+ },
+ ]
+ },
+ { name: "IO_DIV2_MEAS_CTRL_EN",
+ desc: '''
+ Enable for measurement control
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ async: "clk_io_div2_i",
+ fields: [
+ {
+ bits: "3:0",
+ name: "EN",
+ desc: "Enable measurement for io_div2",
+ mubi: true,
+ resval: false,
+ },
+ ]
+ // Measurements can cause recoverable errors depending on the
+ // thresholds which randomized CSR tests will not predict correctly.
+ // To provide better CSR coverage we allow writing the threshold
+ // fields, but not enabling the counters.
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "IO_DIV2_MEAS_CTRL_SHADOWED",
+ desc: '''
+ Configuration controls for io_div2 measurement.
+
+ The threshold fields are made wider than required (by 1 bit) to ensure
+ there is room to adjust for measurement inaccuracies.
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ async: "clk_io_div2_i",
+ shadowed: "true",
+ update_err_alert: "recov_fault",
+ storage_err_alert: "fatal_fault",
+ fields: [
+ {
+ bits: "8:0",
+ name: "HI",
+ desc: "Max threshold for io_div2 measurement",
+ resval: "250"
+ },
+
+ {
+ bits: "17:9",
+ name: "LO",
+ desc: "Min threshold for io_div2 measurement",
+ resval: "230"
+ },
+ ]
+ },
+ { name: "IO_DIV4_MEAS_CTRL_EN",
+ desc: '''
+ Enable for measurement control
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ async: "clk_io_div4_i",
+ fields: [
+ {
+ bits: "3:0",
+ name: "EN",
+ desc: "Enable measurement for io_div4",
+ mubi: true,
+ resval: false,
+ },
+ ]
+ // Measurements can cause recoverable errors depending on the
+ // thresholds which randomized CSR tests will not predict correctly.
+ // To provide better CSR coverage we allow writing the threshold
+ // fields, but not enabling the counters.
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "IO_DIV4_MEAS_CTRL_SHADOWED",
+ desc: '''
+ Configuration controls for io_div4 measurement.
+
+ The threshold fields are made wider than required (by 1 bit) to ensure
+ there is room to adjust for measurement inaccuracies.
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ async: "clk_io_div4_i",
+ shadowed: "true",
+ update_err_alert: "recov_fault",
+ storage_err_alert: "fatal_fault",
+ fields: [
+ {
+ bits: "7:0",
+ name: "HI",
+ desc: "Max threshold for io_div4 measurement",
+ resval: "130"
+ },
+
+ {
+ bits: "15:8",
+ name: "LO",
+ desc: "Min threshold for io_div4 measurement",
+ resval: "110"
+ },
+ ]
+ },
+ { name: "MAIN_MEAS_CTRL_EN",
+ desc: '''
+ Enable for measurement control
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ async: "clk_main_i",
+ fields: [
+ {
+ bits: "3:0",
+ name: "EN",
+ desc: "Enable measurement for main",
+ mubi: true,
+ resval: false,
+ },
+ ]
+ // Measurements can cause recoverable errors depending on the
+ // thresholds which randomized CSR tests will not predict correctly.
+ // To provide better CSR coverage we allow writing the threshold
+ // fields, but not enabling the counters.
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "MAIN_MEAS_CTRL_SHADOWED",
+ desc: '''
+ Configuration controls for main measurement.
+
+ The threshold fields are made wider than required (by 1 bit) to ensure
+ there is room to adjust for measurement inaccuracies.
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ async: "clk_main_i",
+ shadowed: "true",
+ update_err_alert: "recov_fault",
+ storage_err_alert: "fatal_fault",
+ fields: [
+ {
+ bits: "9:0",
+ name: "HI",
+ desc: "Max threshold for main measurement",
+ resval: "510"
+ },
+
+ {
+ bits: "19:10",
+ name: "LO",
+ desc: "Min threshold for main measurement",
+ resval: "490"
+ },
+ ]
+ },
+ { name: "USB_MEAS_CTRL_EN",
+ desc: '''
+ Enable for measurement control
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hrw",
+ async: "clk_usb_i",
+ fields: [
+ {
+ bits: "3:0",
+ name: "EN",
+ desc: "Enable measurement for usb",
+ mubi: true,
+ resval: false,
+ },
+ ]
+ // Measurements can cause recoverable errors depending on the
+ // thresholds which randomized CSR tests will not predict correctly.
+ // To provide better CSR coverage we allow writing the threshold
+ // fields, but not enabling the counters.
+ tags: ["excl:CsrAllTests:CsrExclWrite"]
+ },
+
+ { name: "USB_MEAS_CTRL_SHADOWED",
+ desc: '''
+ Configuration controls for usb measurement.
+
+ The threshold fields are made wider than required (by 1 bit) to ensure
+ there is room to adjust for measurement inaccuracies.
+ ''',
+ regwen: "MEASURE_CTRL_REGWEN",
+ swaccess: "rw",
+ hwaccess: "hro",
+ async: "clk_usb_i",
+ shadowed: "true",
+ update_err_alert: "recov_fault",
+ storage_err_alert: "fatal_fault",
+ fields: [
+ {
+ bits: "8:0",
+ name: "HI",
+ desc: "Max threshold for usb measurement",
+ resval: "250"
+ },
+
+ {
+ bits: "17:9",
+ name: "LO",
+ desc: "Min threshold for usb measurement",
+ resval: "230"
+ },
+ ]
+ },
+
+ { name: "RECOV_ERR_CODE",
+ desc: "Recoverable Error code",
+ swaccess: "rw1c",
+ hwaccess: "hwo",
+ fields: [
+ { bits: "0",
+ name: "SHADOW_UPDATE_ERR",
+ resval: 0
+ desc: '''
+ One of the shadow registers encountered an update error.
+ '''
+ },
+ {
+ bits: "1",
+ name: "IO_MEASURE_ERR",
+ resval: 0,
+ desc: '''
+ io has encountered a measurement error.
+ '''
+ },
+ {
+ bits: "2",
+ name: "IO_DIV2_MEASURE_ERR",
+ resval: 0,
+ desc: '''
+ io_div2 has encountered a measurement error.
+ '''
+ },
+ {
+ bits: "3",
+ name: "IO_DIV4_MEASURE_ERR",
+ resval: 0,
+ desc: '''
+ io_div4 has encountered a measurement error.
+ '''
+ },
+ {
+ bits: "4",
+ name: "MAIN_MEASURE_ERR",
+ resval: 0,
+ desc: '''
+ main has encountered a measurement error.
+ '''
+ },
+ {
+ bits: "5",
+ name: "USB_MEASURE_ERR",
+ resval: 0,
+ desc: '''
+ usb has encountered a measurement error.
+ '''
+ },
+ {
+ bits: "6",
+ name: "IO_TIMEOUT_ERR",
+ resval: 0,
+ desc: '''
+ io has timed out.
+ '''
+ }
+ {
+ bits: "7",
+ name: "IO_DIV2_TIMEOUT_ERR",
+ resval: 0,
+ desc: '''
+ io_div2 has timed out.
+ '''
+ }
+ {
+ bits: "8",
+ name: "IO_DIV4_TIMEOUT_ERR",
+ resval: 0,
+ desc: '''
+ io_div4 has timed out.
+ '''
+ }
+ {
+ bits: "9",
+ name: "MAIN_TIMEOUT_ERR",
+ resval: 0,
+ desc: '''
+ main has timed out.
+ '''
+ }
+ {
+ bits: "10",
+ name: "USB_TIMEOUT_ERR",
+ resval: 0,
+ desc: '''
+ usb has timed out.
+ '''
+ }
+ ]
+ },
+
+ { name: "FATAL_ERR_CODE",
+ desc: "Error code",
+ swaccess: "ro",
+ hwaccess: "hrw",
+ fields: [
+ { bits: "0",
+ name: "REG_INTG",
+ resval: 0
+ desc: '''
+ Register file has experienced a fatal integrity error.
+ '''
+ },
+ { bits: "1",
+ name: "IDLE_CNT",
+ resval: 0
+ desc: '''
+ One of the idle counts encountered a duplicate error.
+ '''
+ },
+ { bits: "2",
+ name: "SHADOW_STORAGE_ERR",
+ resval: 0
+ desc: '''
+ One of the shadow registers encountered a storage error.
+ '''
+ },
+ ]
+ },
+ ]
+}
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr_testplan.hjson b/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr_testplan.hjson
new file mode 100644
index 00000000000000..1f693046e735aa
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/data/clkmgr_testplan.hjson
@@ -0,0 +1,334 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ name: "clkmgr"
+ import_testplans: ["hw/dv/tools/dvsim/testplans/csr_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/intr_test_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/alert_test_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/tl_device_access_types_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/stress_all_with_reset_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson",
+ "clkmgr_sec_cm_testplan.hjson",
+ "hw/dv/tools/dvsim/testplans/sec_cm_count_testplan.hjson"]
+ testpoints: [
+ {
+ name: smoke
+ desc: '''
+ Smoke test disabling peripheral and transactional clocks.
+
+ - Disables all peripheral clocks from their enabled reset state.
+ - Transactional clocks gating depends on whether they are idle.
+ - Initializes all units as busy (not idle).
+ - Clears each unit's `clk_hints` bit, which has no effect until
+ the unit becomes idle.
+ - Sets the unit's `idle_i` bit, which should disable the clock.
+ - Writes both values of the `jitter_enable` CSR.
+
+ **Stimulus**:
+ - CSR writes to `clk_enables` and `clk_hints`.
+ - Setting `idle_i` clkmgr input.
+
+ **Checks**:
+ - SVA assertions for peripheral clocks enable and disable
+ properties.
+ - Transactional clocks check SVA properties as follows:
+ - If the hint enables it, the clock becomes active.
+ - If the hint disables it but the unit is busy, the clock remains
+ active.
+ - If the hint disables it and the unit is idle, the clock stops.
+ - For transactional units the CSR `clk_hints_status` is checked
+ to correspond to `clk_hints` once the units are idle.
+ - Check in scoreboard the `jitter_en_o` output tracks updates of the
+ `jitter_enable` CSR.
+ '''
+ stage: V1
+ tests: ["clkmgr_smoke"]
+ }
+ {
+ name: peri_enables
+ desc: '''
+ Peripheral clocks are disabled if its `clk_enables` bit is off,
+ or the corresponding `pwr_i.*_ip_clk_en` is off, and `scanmode_i`
+ is not `lc_ctrl_pkg::On`.
+
+ This test runs multiple rounds which do the following:
+ - Randomize `pwr_i.usb_ip_clk_en` and `scanmode_i`, and the initial
+ setting of `clk_enables`.
+ - Send a CSR write to `clk_enables` with its initial value.
+ - Send a CSR write to `clk_enables` that flips all bits.
+
+ It makes no sense to have `pwr_i.io_ip_clk_en` set to zero since
+ that would prevent the CPU from running and sending CSR updates.
+
+ **Checks**:
+ - SVA assertions for peripheral clocks enable and disable
+ properties.
+ '''
+ stage: V2
+ tests: ["clkmgr_peri"]
+ }
+ {
+ name: trans_enables
+ desc: '''
+ Transactional unit clocks are disabled if they are idle and
+ their CSR `clk_hints` bit is off, or `pwr_i.main_ip_clk_en` is off,
+ and `scanmode_i` is not `lc_ctrl_pkg::On`.
+ This test randomizes the initial setting of `idle_i` and the
+ desired value of `clk_hints`. Each round performs this sequence:
+ - Writes the desired value to CSR `clk_hints` and checks that the
+ CSR `clk_hints_status` reflects CSR `clk_hints` except for the
+ units not-idle.
+ - Marks all units as idle, and checks that `csr_hints_status`
+ matches `clk_hints`.
+ - Writes `clk_hints` to all ones and checks that `csr_hints_status`
+ is all ones.
+ - Writes `clk_hints` with its reset value.
+
+ **Checks**:
+ - SVA assertions for transactional unit clocks described in
+ clkmgr_smoke.
+ '''
+ stage: V2
+ tests: ["clkmgr_trans"]
+ }
+ {
+ name: extclk
+ desc: '''
+ Tests the functionality of enabling external clocks.
+
+ - External clock is enabled if the `lc_clk_byp_req_i` input from
+ `lc_ctrl` is `lc_ctrl_pkg::On`.
+ - External clock is also be enabled when CSR `extclk_ctrl.sel` is
+ set to
+ `lc_ctrl_pkg::On` and the `lc_dtl_en_i` input from `lc_ctrl` is
+ `lc_ctrl_pkg::On`.
+ - Notice writes to the `extclk_ctrl.sel` register are ignored unless
+ the CSR `extclk_ctrl_regwen` is 1.
+ - A successful switch to external clocks due to `lc_clk_byl_req_i`
+ will cause the clkmgr to undo a divide by 2 for io_div4 and
+ io_div2 clocks except when `(scanmode_i == prim_mubi_pkg::MuBi4True)`.
+ - A software triggered switch to external clock will undo divides
+ by 2 if `extclk_ctrl.hi_speed_sel` is set to `prim_mubi_pkg::MuBi4True`.
+
+ **Stimulus**:
+ - CSR writes to `extclk_ctrl` and `extclk_ctrl_regwen`.
+ - Setting `lc_hw_debug_en_i`, `lc_clk_byp_req_i`, and the handshake to
+ ast via `ast_clk_byp_req_o` and `ast_clk_byp_ack_i`.
+ - Setting `scanmode_i`.
+
+ **Checks**:
+ Clock divider checks are done with SVA assertions.
+ - When the external clock is selected (and not defeated by
+ `scanmode_i` for scoreboard checks):
+ - The `clk_io_div2_powerup` output matches the `clk_io_powerup`
+ output.
+ - The `clk_io_div4_powerup` output matches the `clk_io_powerup`
+ output at half its frequency.
+ - When the external clock is not selected or division is defeated:
+ - The `clk_io_div2_powerup` output matches the `clk_io_powerup`
+ output at half its frequency.
+ - The `clk_io_div4_powerup` output matches the `clk_io_powerup`
+ output at a quarter of its frequency.
+ LC / AST handshake:
+ - When the external clock functionality is triggered the
+ `ast_clk_byp_req_o` output pin is set to `lc_ctrl_pkg::On`.
+ - When `ast_clk_byp_ack_i` is set to `lc_ctrl_pkg::On` in response
+ to a corresponding request:
+ - The clock dividers are stepped down, unless defeated by
+ `scanmode_i` being `lc_ctrl_pkg::On`.
+ - If the initial request was due to the assertion of the
+ `lc_clk_byp_req_i`, the `lc_clk_byp_ack_o` output is set to
+ `lc_ctrl_pkg::On`.
+ '''
+ stage: V2
+ tests: ["clkmgr_extclk"]
+ }
+ {
+ name: clk_status
+ desc: '''
+ This tests the three `pwr_o.*_status` output ports, for the
+ `io`, `main`, and `usb` clocks.
+
+ The `pwr_o.*_status` output must track the correspponding
+ `pwr_i.*_ip_clk_en` input.
+
+ **Stimulus**:
+ - Randomize the `pwr_i.*_ip_clk_en` setting for each clock.
+
+ **Check**:
+ - The checks are done in SVA at `clkmgr_pwrmgr_sva_if.sv`.
+ '''
+ stage: V2
+ tests: ["clkmgr_clk_status"]
+ }
+ {
+ name: jitter
+ desc: '''
+ This tests the jitter functionality.
+
+ The jitter functionality is implemented by the AST block, but
+ controlled by the `jitter_enable` CSR in this block. This CSR
+ directly drives the `jitter_en_o` output pin.
+
+ **Stimulus**:
+ - CSR write to `jitter_enable`.
+
+ **Check**:
+ - The `jitter_en_o` output pin reflects the `jitter_enable` CSR.
+ Test is implemented in the scoreboard, and is always running.
+ '''
+ stage: V2
+ tests: ["clkmgr_smoke"]
+ }
+ {
+ name: frequency
+ desc: '''This tests the frequency counters measured count functionality.
+
+ These counters compute the number of cycles of each clock relative
+ to the aon timer, and compares it to the corresponding
+ thresholds written into the `*_meas_ctrl_shadowed` CSR. Measurements
+ beyond these thresholds trigger a recoverable alert and set a bit
+ in the `recov_err_code` CSR. Also, if the counters reach their
+ maximum value they don't wrap around.
+
+ If clock calibration is lost, indicated by the `calib_rdy_i` input
+ being `prim_mubi_pkg::MuBi4False`, the measurements stop, no
+ error is triggered, and `measure_ctrl_regwen` is set to 1.
+
+ **Stimulus**:
+ - Randomly set slow, correct, and fast interval for each counter
+ and test.
+ - Randomly set the `calib_rdy_i` input.
+ - Randomly trigger a clock saturation by forcing its cycle count
+ to be near its maximum value while counting.
+
+ **Check**:
+ - Slow and fast intervals should cause a recoverable alert.
+ - Coverage collected per clock.
+ '''
+ stage: V2
+ tests: ["clkmgr_frequency"]
+ }
+ {
+ name: frequency_timeout
+ desc: '''This tests the frequency counters timeout functionality.
+
+ These counters compute the number of cycles of some clock relative
+ to the aon timer. It should trigger a recoverable alert when there
+ is no valid measurement when enabled, leading to a timeout. This is
+ separate from the `frequenty` testpoint to simplify the test checks.
+
+ **Stimulus**:
+ - Randomly stop measured clocks to trigger a timeout.
+
+ **Check**:
+ - Timeout should cause a recoverable alert.
+ - Coverage collected per clock.
+ '''
+ stage: V2
+ tests: ["clkmgr_frequency_timeout"]
+ }
+ {
+ name: frequency_overflow
+ desc: '''This tests the overflow feature in prim_clock_meas.
+
+ This needs to modify the state of the counter to trigger the
+ feature.
+
+ **Stimulus**:
+ - Program the counter. Whenever it hits the value of 1, set it to
+ the range - 2.
+
+ **Check**:
+ - The internal cnt_ovfl flop is set.
+ - The fast_o output should be set.
+ '''
+ stage: V2
+ tests: ["clkmgr_frequency"]
+ }
+ {
+ name: regwen
+ desc: '''This tests the behavior of the regwen CSRs.
+
+ When a regwen is clear, any write to CSRs it locks are ignored.
+ Once a regwen is cleared, it will only be set again after a full
+ reset.
+
+ **Stimulus**:
+ - Clear each regwen.
+ - Write to the corresponding locked CSRs.
+
+ **Check**:
+ - The locked CSR value is not updated.
+ '''
+ stage: V3
+ tests: ["clkmgr_regwen"]
+ }
+ {
+ name: stress_all
+ desc: '''This runs random sequences in succession.
+
+ Randomly chooses from the following sequences:
+ - clkmgr_extclk_vseq,
+ - clkmgr_frequency_timeout_vseq,
+ - clkmgr_frequency_vseq,
+ - clkmgr_peri_vseq,
+ - clkmgr_smoke_vseq,
+ - clkmgr_trans_vseq
+ '''
+ stage: V2
+ tests: ["clkmgr_stress_all"]
+ }
+ ]
+
+ covergroups: [
+ {
+ name: peri_cg
+ desc: '''
+ Collects coverage for each peripheral clock.
+
+ The peripheral clocks depend on a bit in the clk_enables CSR,
+ the ip_clk_en input from pwrmgr, and the scanmode input.
+ This collects the cross of them for each peripheral.
+
+ FIXME This is collected in an array, one instance for each clock,
+ but the dvsim coverage flow doesn't yet support arrays.
+ '''
+ }
+ {
+ name: trans_cg
+ desc: '''
+ Collects coverage for each transactional unit clock.
+
+ The transactional unit clocks depend on a bit in the clk_hints CSR,
+ the ip_clk_en input from pwrmgr, the respective idle input bit from
+ the unit, and the scanmode input.
+ This collects the cross of them for each transactional unit.
+
+ FIXME This is collected in an array, one instance for each clock,
+ but the dvsim coverage flow doesn't yet support arrays.
+ '''
+ }
+ {
+ name: extclk_cg
+ desc: '''
+ Collects coverage for the external clock selection.
+
+ The external clock selection depends on the `extclk_ctrl` CSR
+ fields `sel` and `hi_speed_sel`, and the `lc_hw_debug_en_i`,
+ `lc_clk_byp_req_i`, and `scanmode_i` input pins. This covergroup
+ collects their cross.
+ '''
+ }
+ {
+ name: freq_measure_cg
+ desc: '''
+ Collects coverage for the frequency measurement counters.
+
+ The relevant information is whether it got an okay, slow, or
+ fast measurement, or a timeout.
+ '''
+ }
+ ]
+}
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/data/top_earlgrey_clkmgr.ipconfig.hjson b/hw/top_earlgrey/ip_autogen/clkmgr/data/top_earlgrey_clkmgr.ipconfig.hjson
new file mode 100644
index 00000000000000..e0eef4e11ddc29
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/data/top_earlgrey_clkmgr.ipconfig.hjson
@@ -0,0 +1,263 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ instance_name: top_earlgrey_clkmgr
+ param_values:
+ {
+ src_clks:
+ {
+ main:
+ {
+ name: main
+ aon: false
+ freq: 100000000
+ ref: false
+ }
+ io:
+ {
+ name: io
+ aon: false
+ freq: 96000000
+ ref: false
+ }
+ usb:
+ {
+ name: usb
+ aon: false
+ freq: 48000000
+ ref: false
+ }
+ aon:
+ {
+ name: aon
+ aon: true
+ freq: 200000
+ ref: true
+ }
+ }
+ derived_clks:
+ {
+ io_div2:
+ {
+ name: io_div2
+ aon: false
+ freq: 48000000
+ ref: false
+ div: 2
+ src:
+ {
+ name: io
+ aon: no
+ freq: "96000000"
+ ref: false
+ }
+ }
+ io_div4:
+ {
+ name: io_div4
+ aon: false
+ freq: 24000000
+ ref: false
+ div: 4
+ src:
+ {
+ name: io
+ aon: no
+ freq: "96000000"
+ ref: false
+ }
+ }
+ }
+ typed_clocks:
+ {
+ ast_clks:
+ {
+ clk_main_i:
+ {
+ src_name: main
+ endpoint_ip: clkmgr_aon
+ }
+ clk_io_i:
+ {
+ src_name: io
+ endpoint_ip: clkmgr_aon
+ }
+ clk_usb_i:
+ {
+ src_name: usb
+ endpoint_ip: clkmgr_aon
+ }
+ clk_aon_i:
+ {
+ src_name: aon
+ endpoint_ip: clkmgr_aon
+ }
+ }
+ ft_clks:
+ {
+ clk_io_div4_powerup:
+ {
+ src_name: io_div4
+ endpoint_ip: pwrmgr_aon
+ }
+ clk_aon_powerup:
+ {
+ src_name: aon
+ endpoint_ip: pwrmgr_aon
+ }
+ clk_main_powerup:
+ {
+ src_name: main
+ endpoint_ip: rstmgr_aon
+ }
+ clk_io_powerup:
+ {
+ src_name: io
+ endpoint_ip: rstmgr_aon
+ }
+ clk_usb_powerup:
+ {
+ src_name: usb
+ endpoint_ip: rstmgr_aon
+ }
+ clk_io_div2_powerup:
+ {
+ src_name: io_div2
+ endpoint_ip: rstmgr_aon
+ }
+ clk_aon_secure:
+ {
+ src_name: aon
+ endpoint_ip: sysrst_ctrl_aon
+ }
+ clk_aon_peri:
+ {
+ src_name: aon
+ endpoint_ip: usbdev
+ }
+ clk_aon_timers:
+ {
+ src_name: aon
+ endpoint_ip: aon_timer_aon
+ }
+ }
+ rg_clks:
+ {
+ clk_io_div4_infra:
+ {
+ src_name: io_div4
+ endpoint_ip: ast
+ }
+ clk_main_infra:
+ {
+ src_name: main
+ endpoint_ip: flash_ctrl
+ }
+ clk_usb_infra:
+ {
+ src_name: usb
+ endpoint_ip: main
+ }
+ clk_io_infra:
+ {
+ src_name: io
+ endpoint_ip: main
+ }
+ clk_io_div2_infra:
+ {
+ src_name: io_div2
+ endpoint_ip: main
+ }
+ clk_io_div4_secure:
+ {
+ src_name: io_div4
+ endpoint_ip: otp_ctrl
+ }
+ clk_main_secure:
+ {
+ src_name: main
+ endpoint_ip: otp_ctrl
+ }
+ clk_io_div4_timers:
+ {
+ src_name: io_div4
+ endpoint_ip: rv_timer
+ }
+ }
+ sw_clks:
+ {
+ clk_io_div4_peri:
+ {
+ src_name: io_div4
+ endpoint_ip: uart0
+ }
+ clk_io_div2_peri:
+ {
+ src_name: io_div2
+ endpoint_ip: spi_device
+ }
+ clk_io_peri:
+ {
+ src_name: io
+ endpoint_ip: spi_host0
+ }
+ clk_usb_peri:
+ {
+ src_name: usb
+ endpoint_ip: usbdev
+ }
+ }
+ hint_clks:
+ {
+ clk_main_aes:
+ {
+ src_name: main
+ endpoint_ip: aes
+ }
+ clk_main_hmac:
+ {
+ src_name: main
+ endpoint_ip: hmac
+ }
+ clk_main_kmac:
+ {
+ src_name: main
+ endpoint_ip: kmac
+ }
+ clk_main_otbn:
+ {
+ src_name: main
+ endpoint_ip: otbn
+ }
+ }
+ }
+ hint_names:
+ {
+ clk_main_aes: HintMainAes
+ clk_main_hmac: HintMainHmac
+ clk_main_kmac: HintMainKmac
+ clk_main_otbn: HintMainOtbn
+ }
+ parent_child_clks:
+ {
+ main:
+ [
+ main
+ ]
+ io:
+ [
+ io
+ io_div2
+ io_div4
+ ]
+ usb:
+ [
+ usb
+ ]
+ }
+ exported_clks: {}
+ number_of_clock_groups: 7
+ topname: earlgrey
+ }
+}
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/checklist.md b/hw/top_earlgrey/ip_autogen/clkmgr/doc/checklist.md
new file mode 100644
index 00000000000000..f685650e418e1f
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/checklist.md
@@ -0,0 +1,271 @@
+# CLKMGR Checklist
+
+
+This checklist is for [Hardware Stage](../../../../../doc/project_governance/development_stages.md) transitions for the [CLKMGR peripheral.](../README.md)
+All checklist items refer to the content in the [Checklist.](../../../../../doc/project_governance/checklist/README.md)
+
+## Design Checklist
+
+### D1
+
+Type | Item | Resolution | Note/Collaterals
+--------------|--------------------------------|-------------|------------------
+Documentation | [SPEC_COMPLETE][] | Done | [CLKMGR Design Spec](../README.md)
+Documentation | [CSR_DEFINED][] | Done |
+RTL | [CLKRST_CONNECTED][] | Done |
+RTL | [IP_TOP][] | Done |
+RTL | [IP_INSTANTIABLE][] | Done |
+RTL | [PHYSICAL_MACROS_DEFINED_80][] | NA |
+RTL | [FUNC_IMPLEMENTED][] | Done |
+RTL | [ASSERT_KNOWN_ADDED][] | Done |
+Code Quality | [LINT_SETUP][] | Done |
+
+[SPEC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#spec_complete
+[CSR_DEFINED]: ../../../../../doc/project_governance/checklist/README.md#csr_defined
+[CLKRST_CONNECTED]: ../../../../../doc/project_governance/checklist/README.md#clkrst_connected
+[IP_TOP]: ../../../../../doc/project_governance/checklist/README.md#ip_top
+[IP_INSTANTIABLE]: ../../../../../doc/project_governance/checklist/README.md#ip_instantiable
+[PHYSICAL_MACROS_DEFINED_80]: ../../../../../doc/project_governance/checklist/README.md#physical_macros_defined_80
+[FUNC_IMPLEMENTED]: ../../../../../doc/project_governance/checklist/README.md#func_implemented
+[ASSERT_KNOWN_ADDED]: ../../../../../doc/project_governance/checklist/README.md#assert_known_added
+[LINT_SETUP]: ../../../../../doc/project_governance/checklist/README.md#lint_setup
+
+### D2
+
+Type | Item | Resolution | Note/Collaterals
+--------------|---------------------------|-------------|------------------
+Documentation | [NEW_FEATURES][] | Done |
+Documentation | [BLOCK_DIAGRAM][] | Done |
+Documentation | [DOC_INTERFACE][] | Done |
+Documentation | [DOC_INTEGRATION_GUIDE][] | Waived | This checklist item has been added retrospectively.
+Documentation | [MISSING_FUNC][] | Done |
+Documentation | [FEATURE_FROZEN][] | Done |
+RTL | [FEATURE_COMPLETE][] | Done |
+RTL | [PORT_FROZEN][] | Done |
+RTL | [ARCHITECTURE_FROZEN][] | Done |
+RTL | [REVIEW_TODO][] | Done |
+RTL | [STYLE_X][] | Done |
+RTL | [CDC_SYNCMACRO][] | Done |
+Code Quality | [LINT_PASS][] | Done |
+Code Quality | [CDC_SETUP][] | Waived | No block-level flow available - waived to top-level signoff.
+Code Quality | [RDC_SETUP][] | Waived | No block-level flow available - waived to top-level signoff.
+Code Quality | [AREA_CHECK][] | Done |
+Code Quality | [TIMING_CHECK][] | Done |
+Security | [SEC_CM_DOCUMENTED][] | Done |
+
+[NEW_FEATURES]: ../../../../../doc/project_governance/checklist/README.md#new_features
+[BLOCK_DIAGRAM]: ../../../../../doc/project_governance/checklist/README.md#block_diagram
+[DOC_INTERFACE]: ../../../../../doc/project_governance/checklist/README.md#doc_interface
+[DOC_INTEGRATION_GUIDE]: ../../../../../doc/project_governance/checklist/README.md#doc_integration_guide
+[MISSING_FUNC]: ../../../../../doc/project_governance/checklist/README.md#missing_func
+[FEATURE_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#feature_frozen
+[FEATURE_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#feature_complete
+[PORT_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#port_frozen
+[ARCHITECTURE_FROZEN]: ../../../../../doc/project_governance/checklist/README.md#architecture_frozen
+[REVIEW_TODO]: ../../../../../doc/project_governance/checklist/README.md#review_todo
+[STYLE_X]: ../../../../../doc/project_governance/checklist/README.md#style_x
+[CDC_SYNCMACRO]: ../../../../../doc/project_governance/checklist/README.md#cdc_syncmacro
+[LINT_PASS]: ../../../../../doc/project_governance/checklist/README.md#lint_pass
+[CDC_SETUP]: ../../../../../doc/project_governance/checklist/README.md#cdc_setup
+[RDC_SETUP]: ../../../../../doc/project_governance/checklist/README.md#rdc_setup
+[AREA_CHECK]: ../../../../../doc/project_governance/checklist/README.md#area_check
+[TIMING_CHECK]: ../../../../../doc/project_governance/checklist/README.md#timing_check
+[SEC_CM_DOCUMENTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_documented
+
+### D2S
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|------------------------------|-------------|------------------
+Security | [SEC_CM_ASSETS_LISTED][] | Done |
+Security | [SEC_CM_IMPLEMENTED][] | Done |
+Security | [SEC_CM_RND_CNST][] | N/A |
+Security | [SEC_CM_NON_RESET_FLOPS][] | Done |
+Security | [SEC_CM_SHADOW_REGS][] | Done |
+Security | [SEC_CM_RTL_REVIEWED][] | Done |
+Security | [SEC_CM_COUNCIL_REVIEWED][] | Done |
+
+[SEC_CM_ASSETS_LISTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_assets_listed
+[SEC_CM_IMPLEMENTED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_implemented
+[SEC_CM_RND_CNST]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_rnd_cnst
+[SEC_CM_NON_RESET_FLOPS]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_non_reset_flops
+[SEC_CM_SHADOW_REGS]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_shadow_regs
+[SEC_CM_RTL_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_rtl_reviewed
+[SEC_CM_COUNCIL_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_council_reviewed
+
+### D3
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|-------------------------|-------------|------------------
+Documentation | [NEW_FEATURES_D3][] | Not Started |
+RTL | [TODO_COMPLETE][] | Not Started |
+Code Quality | [LINT_COMPLETE][] | Not Started |
+Code Quality | [CDC_COMPLETE][] | Not Started |
+Code Quality | [RDC_COMPLETE][] | Not Started |
+Review | [REVIEW_RTL][] | Not Started |
+Review | [REVIEW_DELETED_FF][] | Not Started |
+Review | [REVIEW_SW_CHANGE][] | Not Started |
+Review | [REVIEW_SW_ERRATA][] | Not Started |
+Review | Reviewer(s) | Not Started |
+Review | Signoff date | Not Started |
+
+[NEW_FEATURES_D3]: ../../../../../doc/project_governance/checklist/README.md#new_features_d3
+[TODO_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#todo_complete
+[LINT_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#lint_complete
+[CDC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#cdc_complete
+[RDC_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#rdc_complete
+[REVIEW_RTL]: ../../../../../doc/project_governance/checklist/README.md#review_rtl
+[REVIEW_DELETED_FF]: ../../../../../doc/project_governance/checklist/README.md#review_deleted_ff
+[REVIEW_SW_CHANGE]: ../../../../../doc/project_governance/checklist/README.md#review_sw_change
+[REVIEW_SW_ERRATA]: ../../../../../doc/project_governance/checklist/README.md#review_sw_errata
+
+## Verification Checklist
+
+### V1
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|---------------------------------------|-------------|------------------
+Documentation | [DV_DOC_DRAFT_COMPLETED][] | Done | [CLKMGR DV document](../dv/README.md)
+Documentation | [TESTPLAN_COMPLETED][] | Done | [CLKMGR Testplan](../dv/README.md#testplan)
+Testbench | [TB_TOP_CREATED][] | Done |
+Testbench | [PRELIMINARY_ASSERTION_CHECKS_ADDED][]| Done |
+Testbench | [SIM_TB_ENV_CREATED][] | Done |
+Testbench | [SIM_RAL_MODEL_GEN_AUTOMATED][] | Done |
+Testbench | [CSR_CHECK_GEN_AUTOMATED][] | Done |
+Testbench | [TB_GEN_AUTOMATED][] | Done |
+Tests | [SIM_SMOKE_TEST_PASSING][] | Done |
+Tests | [SIM_CSR_MEM_TEST_SUITE_PASSING][] | NA |
+Tests | [FPV_MAIN_ASSERTIONS_PROVEN][] | NA |
+Tool Setup | [SIM_ALT_TOOL_SETUP][] | Done | xcelium
+Regression | [SIM_SMOKE_REGRESSION_SETUP][] | Done |
+Regression | [SIM_NIGHTLY_REGRESSION_SETUP][] | Done |
+Regression | [FPV_REGRESSION_SETUP][] | NA |
+Coverage | [SIM_COVERAGE_MODEL_ADDED][] | Done |
+Code Quality | [TB_LINT_SETUP][] | Done |
+Integration | [PRE_VERIFIED_SUB_MODULES_V1][] | NA |
+Review | [DESIGN_SPEC_REVIEWED][] | Done |
+Review | [TESTPLAN_REVIEWED][] | Done |
+Review | [STD_TEST_CATEGORIES_PLANNED][] | Done |
+Review | [V2_CHECKLIST_SCOPED][] | Done |
+
+[DV_DOC_DRAFT_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#dv_doc_draft_completed
+[TESTPLAN_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#testplan_completed
+[TB_TOP_CREATED]: ../../../../../doc/project_governance/checklist/README.md#tb_top_created
+[PRELIMINARY_ASSERTION_CHECKS_ADDED]: ../../../../../doc/project_governance/checklist/README.md#preliminary_assertion_checks_added
+[SIM_TB_ENV_CREATED]: ../../../../../doc/project_governance/checklist/README.md#sim_tb_env_created
+[SIM_RAL_MODEL_GEN_AUTOMATED]: ../../../../../doc/project_governance/checklist/README.md#sim_ral_model_gen_automated
+[CSR_CHECK_GEN_AUTOMATED]: ../../../../../doc/project_governance/checklist/README.md#csr_check_gen_automated
+[TB_GEN_AUTOMATED]: ../../../../../doc/project_governance/checklist/README.md#tb_gen_automated
+[SIM_SMOKE_TEST_PASSING]: ../../../../../doc/project_governance/checklist/README.md#sim_smoke_test_passing
+[SIM_CSR_MEM_TEST_SUITE_PASSING]: ../../../../../doc/project_governance/checklist/README.md#sim_csr_mem_test_suite_passing
+[FPV_MAIN_ASSERTIONS_PROVEN]: ../../../../../doc/project_governance/checklist/README.md#fpv_main_assertions_proven
+[SIM_ALT_TOOL_SETUP]: ../../../../../doc/project_governance/checklist/README.md#sim_alt_tool_setup
+[SIM_SMOKE_REGRESSION_SETUP]: ../../../../../doc/project_governance/checklist/README.md#sim_smoke_regression_setup
+[SIM_NIGHTLY_REGRESSION_SETUP]: ../../../../../doc/project_governance/checklist/README.md#sim_nightly_regression_setup
+[FPV_REGRESSION_SETUP]: ../../../../../doc/project_governance/checklist/README.md#fpv_regression_setup
+[SIM_COVERAGE_MODEL_ADDED]: ../../../../../doc/project_governance/checklist/README.md#sim_coverage_model_added
+[TB_LINT_SETUP]: ../../../../../doc/project_governance/checklist/README.md#tb_lint_setup
+[PRE_VERIFIED_SUB_MODULES_V1]: ../../../../../doc/project_governance/checklist/README.md#pre_verified_sub_modules_v1
+[DESIGN_SPEC_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#design_spec_reviewed
+[TESTPLAN_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#testplan_reviewed
+[STD_TEST_CATEGORIES_PLANNED]: ../../../../../doc/project_governance/checklist/README.md#std_test_categories_planned
+[V2_CHECKLIST_SCOPED]: ../../../../../doc/project_governance/checklist/README.md#v2_checklist_scoped
+
+### V2
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|-----------------------------------------|-------------|------------------
+Documentation | [DESIGN_DELTAS_CAPTURED_V2][] | Done |
+Documentation | [DV_DOC_COMPLETED][] | Done |
+Testbench | [FUNCTIONAL_COVERAGE_IMPLEMENTED][] | Done |
+Testbench | [ALL_INTERFACES_EXERCISED][] | Done |
+Testbench | [ALL_ASSERTION_CHECKS_ADDED][] | Done |
+Testbench | [SIM_TB_ENV_COMPLETED][] | Done |
+Tests | [SIM_ALL_TESTS_PASSING][] | Done |
+Tests | [FPV_ALL_ASSERTIONS_WRITTEN][] | NA |
+Tests | [FPV_ALL_ASSUMPTIONS_REVIEWED][] | NA |
+Tests | [SIM_FW_SIMULATED][] | Done |
+Regression | [SIM_NIGHTLY_REGRESSION_V2][] | Done |
+Coverage | [SIM_CODE_COVERAGE_V2][] | Done |
+Coverage | [SIM_FUNCTIONAL_COVERAGE_V2][] | Done |
+Coverage | [FPV_CODE_COVERAGE_V2][] | NA |
+Coverage | [FPV_COI_COVERAGE_V2][] | NA |
+Integration | [PRE_VERIFIED_SUB_MODULES_V2][] | NA |
+Issues | [NO_HIGH_PRIORITY_ISSUES_PENDING][] | Done |
+Issues | [ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED][] | Done |
+Review | [DV_DOC_TESTPLAN_REVIEWED][] | Done |
+Review | [V3_CHECKLIST_SCOPED][] | Done |
+
+[DESIGN_DELTAS_CAPTURED_V2]: ../../../../../doc/project_governance/checklist/README.md#design_deltas_captured_v2
+[DV_DOC_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#dv_doc_completed
+[FUNCTIONAL_COVERAGE_IMPLEMENTED]: ../../../../../doc/project_governance/checklist/README.md#functional_coverage_implemented
+[ALL_INTERFACES_EXERCISED]: ../../../../../doc/project_governance/checklist/README.md#all_interfaces_exercised
+[ALL_ASSERTION_CHECKS_ADDED]: ../../../../../doc/project_governance/checklist/README.md#all_assertion_checks_added
+[SIM_TB_ENV_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#sim_tb_env_completed
+[SIM_ALL_TESTS_PASSING]: ../../../../../doc/project_governance/checklist/README.md#sim_all_tests_passing
+[FPV_ALL_ASSERTIONS_WRITTEN]: ../../../../../doc/project_governance/checklist/README.md#fpv_all_assertions_written
+[FPV_ALL_ASSUMPTIONS_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#fpv_all_assumptions_reviewed
+[SIM_FW_SIMULATED]: ../../../../../doc/project_governance/checklist/README.md#sim_fw_simulated
+[SIM_NIGHTLY_REGRESSION_V2]: ../../../../../doc/project_governance/checklist/README.md#sim_nightly_regression_v2
+[SIM_CODE_COVERAGE_V2]: ../../../../../doc/project_governance/checklist/README.md#sim_code_coverage_v2
+[SIM_FUNCTIONAL_COVERAGE_V2]: ../../../../../doc/project_governance/checklist/README.md#sim_functional_coverage_v2
+[FPV_CODE_COVERAGE_V2]: ../../../../../doc/project_governance/checklist/README.md#fpv_code_coverage_v2
+[FPV_COI_COVERAGE_V2]: ../../../../../doc/project_governance/checklist/README.md#fpv_coi_coverage_v2
+[PRE_VERIFIED_SUB_MODULES_V2]: ../../../../../doc/project_governance/checklist/README.md#pre_verified_sub_modules_v2
+[NO_HIGH_PRIORITY_ISSUES_PENDING]: ../../../../../doc/project_governance/checklist/README.md#no_high_priority_issues_pending
+[ALL_LOW_PRIORITY_ISSUES_ROOT_CAUSED]:../../../../../doc/project_governance/checklist/README.md#all_low_priority_issues_root_caused
+[DV_DOC_TESTPLAN_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#dv_doc_testplan_reviewed
+[V3_CHECKLIST_SCOPED]: ../../../../../doc/project_governance/checklist/README.md#v3_checklist_scoped
+
+### V2S
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|-----------------------------------------|-------------|------------------
+Documentation | [SEC_CM_TESTPLAN_COMPLETED][] | Done |
+Tests | [FPV_SEC_CM_VERIFIED][] | Done |
+Tests | [SIM_SEC_CM_VERIFIED][] | Done |
+Coverage | [SIM_COVERAGE_REVIEWED][] | Done |
+Review | [SEC_CM_DV_REVIEWED][] | Done |
+
+[SEC_CM_TESTPLAN_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_testplan_completed
+[FPV_SEC_CM_VERIFIED]: ../../../../../doc/project_governance/checklist/README.md#fpv_sec_cm_verified
+[SIM_SEC_CM_VERIFIED]: ../../../../../doc/project_governance/checklist/README.md#sim_sec_cm_verified
+[SIM_COVERAGE_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sim_coverage_reviewed
+[SEC_CM_DV_REVIEWED]: ../../../../../doc/project_governance/checklist/README.md#sec_cm_dv_reviewed
+
+### V3
+
+ Type | Item | Resolution | Note/Collaterals
+--------------|-----------------------------------|-------------|------------------
+Documentation | [DESIGN_DELTAS_CAPTURED_V3][] | Not Started |
+Tests | [X_PROP_ANALYSIS_COMPLETED][] | Not Started |
+Tests | [FPV_ASSERTIONS_PROVEN_AT_V3][] | Not Started |
+Regression | [SIM_NIGHTLY_REGRESSION_AT_V3][] | Not Started |
+Coverage | [SIM_CODE_COVERAGE_AT_100][] | Not Started |
+Coverage | [SIM_FUNCTIONAL_COVERAGE_AT_100][]| Not Started |
+Coverage | [FPV_CODE_COVERAGE_AT_100][] | Not Started |
+Coverage | [FPV_COI_COVERAGE_AT_100][] | Not Started |
+Code Quality | [ALL_TODOS_RESOLVED][] | Not Started |
+Code Quality | [NO_TOOL_WARNINGS_THROWN][] | Not Started |
+Code Quality | [TB_LINT_COMPLETE][] | Not Started |
+Integration | [PRE_VERIFIED_SUB_MODULES_V3][] | Not Started |
+Issues | [NO_ISSUES_PENDING][] | Not Started |
+Review | Reviewer(s) | Not Started |
+Review | Signoff date | Not Started |
+
+[DESIGN_DELTAS_CAPTURED_V3]: ../../../../../doc/project_governance/checklist/README.md#design_deltas_captured_v3
+[X_PROP_ANALYSIS_COMPLETED]: ../../../../../doc/project_governance/checklist/README.md#x_prop_analysis_completed
+[FPV_ASSERTIONS_PROVEN_AT_V3]: ../../../../../doc/project_governance/checklist/README.md#fpv_assertions_proven_at_v3
+[SIM_NIGHTLY_REGRESSION_AT_V3]: ../../../../../doc/project_governance/checklist/README.md#sim_nightly_regression_at_v3
+[SIM_CODE_COVERAGE_AT_100]: ../../../../../doc/project_governance/checklist/README.md#sim_code_coverage_at_100
+[SIM_FUNCTIONAL_COVERAGE_AT_100]:../../../../../doc/project_governance/checklist/README.md#sim_functional_coverage_at_100
+[FPV_CODE_COVERAGE_AT_100]: ../../../../../doc/project_governance/checklist/README.md#fpv_code_coverage_at_100
+[FPV_COI_COVERAGE_AT_100]: ../../../../../doc/project_governance/checklist/README.md#fpv_coi_coverage_at_100
+[ALL_TODOS_RESOLVED]: ../../../../../doc/project_governance/checklist/README.md#all_todos_resolved
+[NO_TOOL_WARNINGS_THROWN]: ../../../../../doc/project_governance/checklist/README.md#no_tool_warnings_thrown
+[TB_LINT_COMPLETE]: ../../../../../doc/project_governance/checklist/README.md#tb_lint_complete
+[PRE_VERIFIED_SUB_MODULES_V3]: ../../../../../doc/project_governance/checklist/README.md#pre_verified_sub_modules_v3
+[NO_ISSUES_PENDING]: ../../../../../doc/project_governance/checklist/README.md#no_issues_pending
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_block_diagram.svg b/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_block_diagram.svg
new file mode 100644
index 00000000000000..b3977b5124caec
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_block_diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_rst_domain.svg b/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_rst_domain.svg
new file mode 100644
index 00000000000000..2e5276cc7c2189
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/clkmgr_rst_domain.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/example_chip_partition.svg b/hw/top_earlgrey/ip_autogen/clkmgr/doc/example_chip_partition.svg
new file mode 100644
index 00000000000000..2c8bc65081b17e
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/example_chip_partition.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/interfaces.md b/hw/top_earlgrey/ip_autogen/clkmgr/doc/interfaces.md
new file mode 100644
index 00000000000000..625a4ecebe3777
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/interfaces.md
@@ -0,0 +1,59 @@
+# Hardware Interfaces
+
+
+Referring to the [Comportable guideline for peripheral device functionality](https://opentitan.org/book/doc/contributing/hw/comportability), the module **`clkmgr`** has the following hardware interfaces defined
+- Primary Clock: **`clk_i`**
+- Other Clocks: **`clk_main_i`**, **`clk_io_i`**, **`clk_usb_i`**, **`clk_aon_i`**, **`clk_io_div2_i`**, **`clk_io_div4_i`**
+- Bus Device Interfaces (TL-UL): **`tl`**
+- Bus Host Interfaces (TL-UL): *none*
+- Peripheral Pins for Chip IO: *none*
+- Interrupts: *none*
+
+## [Inter-Module Signals](https://opentitan.org/book/doc/contributing/hw/comportability/index.html#inter-signal-handling)
+
+| Port Name | Package::Struct | Type | Act | Width | Description |
+|:------------------|:-------------------------|:--------|:------|--------:|:---------------------------------------------------------|
+| clocks | clkmgr_pkg::clkmgr_out | uni | req | 1 | |
+| cg_en | clkmgr_pkg::clkmgr_cg_en | uni | req | 1 | |
+| lc_hw_debug_en | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
+| io_clk_byp_req | prim_mubi_pkg::mubi4 | uni | req | 1 | |
+| io_clk_byp_ack | prim_mubi_pkg::mubi4 | uni | rcv | 1 | |
+| all_clk_byp_req | prim_mubi_pkg::mubi4 | uni | req | 1 | |
+| all_clk_byp_ack | prim_mubi_pkg::mubi4 | uni | rcv | 1 | |
+| hi_speed_sel | prim_mubi_pkg::mubi4 | uni | req | 1 | |
+| div_step_down_req | prim_mubi_pkg::mubi4 | uni | rcv | 1 | |
+| lc_clk_byp_req | lc_ctrl_pkg::lc_tx | uni | rcv | 1 | |
+| lc_clk_byp_ack | lc_ctrl_pkg::lc_tx | uni | req | 1 | |
+| jitter_en | prim_mubi_pkg::mubi4 | uni | req | 1 | |
+| pwr | pwr_clk | req_rsp | rsp | 1 | |
+| idle | prim_mubi_pkg::mubi4 | uni | rcv | 4 | |
+| calib_rdy | prim_mubi_pkg::mubi4 | uni | rcv | 1 | Indicates clocks are calibrated and frequencies accurate |
+| tl | tlul_pkg::tl | req_rsp | rsp | 1 | |
+
+## Security Alerts
+
+| Alert Name | Description |
+|:-------------|:----------------------------------------------------------------------------------|
+| recov_fault | This recoverable alert is triggered when there are measurement errors. |
+| fatal_fault | This fatal alert is triggered when a fatal TL-UL bus integrity fault is detected. |
+
+## Security Countermeasures
+
+| Countermeasure ID | Description |
+|:-------------------------------------------|:-------------------------------------------------------------|
+| CLKMGR.BUS.INTEGRITY | End-to-end bus integrity scheme. |
+| CLKMGR.TIMEOUT.CLK.BKGN_CHK | Background check for clock timeout. |
+| CLKMGR.MEAS.CLK.BKGN_CHK | Background check for clock frequency. |
+| CLKMGR.MEAS.CONFIG.SHADOW | Measurement configurations are shadowed. |
+| CLKMGR.IDLE.INTERSIG.MUBI | Idle inputs are multibit encoded. |
+| CLKMGR.LC_CTRL.INTERSIG.MUBI | The life cycle control signals are multibit encoded. |
+| CLKMGR.LC_CTRL_CLK_HANDSHAKE.INTERSIG.MUBI | The life cycle clock req/ack signals are multibit encoded. |
+| CLKMGR.CLK_HANDSHAKE.INTERSIG.MUBI | The external clock req/ack signals are multibit encoded. |
+| CLKMGR.DIV.INTERSIG.MUBI | Divider step down request is multibit encoded. |
+| CLKMGR.JITTER.CONFIG.MUBI | The jitter enable configuration is multibit encoded. |
+| CLKMGR.IDLE.CTR.REDUN | Idle counter is duplicated. |
+| CLKMGR.MEAS.CONFIG.REGWEN | The measurement controls protected with regwen. |
+| CLKMGR.CLK_CTRL.CONFIG.REGWEN | Software controlled clock requests are proteced with regwen. |
+
+
+
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/programmers_guide.md b/hw/top_earlgrey/ip_autogen/clkmgr/doc/programmers_guide.md
new file mode 100644
index 00000000000000..eea3386a2e234d
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/programmers_guide.md
@@ -0,0 +1,17 @@
+# Programmer's Guide
+
+There are in general only two software controllable functions in the clock manager.
+
+
+## Transactional Clock Hints
+
+To enable a transactional clock, set the corresponding hint in [`CLK_HINTS`](registers.md#clk_hints) to `1`.
+To disable a transactional clock, set the corresponding hint in [`CLK_HINTS`](registers.md#clk_hints) to `0`.
+Note, a `0` does not indicate clock is actually disabled, software can thus check [`CLK_HINTS_STATUS`](registers.md#clk_hints_status) for the actual state of the clock.
+
+## Peripheral Clock Controls
+To control peripheral clocks, directly change the bits in [`CLK_ENABLES`](registers.md#clk_enables).
+
+## Device Interface Functions (DIFs)
+
+- [Device Interface Functions](../../../../../sw/device/lib/dif/dif_clkmgr.h)
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/registers.md b/hw/top_earlgrey/ip_autogen/clkmgr/doc/registers.md
new file mode 100644
index 00000000000000..a3ea64371ffe5a
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/registers.md
@@ -0,0 +1,510 @@
+# Registers
+
+
+## Summary
+
+| Name | Offset | Length | Description |
+|:-------------------------------------------------------------------|:---------|---------:|:---------------------------------------------------------------------------|
+| clkmgr.[`ALERT_TEST`](#alert_test) | 0x0 | 4 | Alert Test Register |
+| clkmgr.[`EXTCLK_CTRL_REGWEN`](#extclk_ctrl_regwen) | 0x4 | 4 | External clock control write enable |
+| clkmgr.[`EXTCLK_CTRL`](#extclk_ctrl) | 0x8 | 4 | Select external clock |
+| clkmgr.[`EXTCLK_STATUS`](#extclk_status) | 0xc | 4 | Status of requested external clock switch |
+| clkmgr.[`JITTER_REGWEN`](#jitter_regwen) | 0x10 | 4 | Jitter write enable |
+| clkmgr.[`JITTER_ENABLE`](#jitter_enable) | 0x14 | 4 | Enable jittery clock |
+| clkmgr.[`CLK_ENABLES`](#clk_enables) | 0x18 | 4 | Clock enable for software gateable clocks. |
+| clkmgr.[`CLK_HINTS`](#clk_hints) | 0x1c | 4 | Clock hint for software gateable transactional clocks during active mode. |
+| clkmgr.[`CLK_HINTS_STATUS`](#clk_hints_status) | 0x20 | 4 | Since the final state of !!CLK_HINTS is not always determined by software, |
+| clkmgr.[`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen) | 0x24 | 4 | Measurement control write enable |
+| clkmgr.[`IO_MEAS_CTRL_EN`](#io_meas_ctrl_en) | 0x28 | 4 | Enable for measurement control |
+| clkmgr.[`IO_MEAS_CTRL_SHADOWED`](#io_meas_ctrl_shadowed) | 0x2c | 4 | Configuration controls for io measurement. |
+| clkmgr.[`IO_DIV2_MEAS_CTRL_EN`](#io_div2_meas_ctrl_en) | 0x30 | 4 | Enable for measurement control |
+| clkmgr.[`IO_DIV2_MEAS_CTRL_SHADOWED`](#io_div2_meas_ctrl_shadowed) | 0x34 | 4 | Configuration controls for io_div2 measurement. |
+| clkmgr.[`IO_DIV4_MEAS_CTRL_EN`](#io_div4_meas_ctrl_en) | 0x38 | 4 | Enable for measurement control |
+| clkmgr.[`IO_DIV4_MEAS_CTRL_SHADOWED`](#io_div4_meas_ctrl_shadowed) | 0x3c | 4 | Configuration controls for io_div4 measurement. |
+| clkmgr.[`MAIN_MEAS_CTRL_EN`](#main_meas_ctrl_en) | 0x40 | 4 | Enable for measurement control |
+| clkmgr.[`MAIN_MEAS_CTRL_SHADOWED`](#main_meas_ctrl_shadowed) | 0x44 | 4 | Configuration controls for main measurement. |
+| clkmgr.[`USB_MEAS_CTRL_EN`](#usb_meas_ctrl_en) | 0x48 | 4 | Enable for measurement control |
+| clkmgr.[`USB_MEAS_CTRL_SHADOWED`](#usb_meas_ctrl_shadowed) | 0x4c | 4 | Configuration controls for usb measurement. |
+| clkmgr.[`RECOV_ERR_CODE`](#recov_err_code) | 0x50 | 4 | Recoverable Error code |
+| clkmgr.[`FATAL_ERR_CODE`](#fatal_err_code) | 0x54 | 4 | Error code |
+
+## ALERT_TEST
+Alert Test Register
+- Offset: `0x0`
+- Reset default: `0x0`
+- Reset mask: `0x3`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "recov_fault", "bits": 1, "attr": ["wo"], "rotate": -90}, {"name": "fatal_fault", "bits": 1, "attr": ["wo"], "rotate": -90}, {"bits": 30}], "config": {"lanes": 1, "fontsize": 10, "vspace": 130}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:------------|:-------------------------------------------------|
+| 31:2 | | | | Reserved |
+| 1 | wo | 0x0 | fatal_fault | Write 1 to trigger one alert event of this kind. |
+| 0 | wo | 0x0 | recov_fault | Write 1 to trigger one alert event of this kind. |
+
+## EXTCLK_CTRL_REGWEN
+External clock control write enable
+- Offset: `0x4`
+- Reset default: `0x1`
+- Reset mask: `0x1`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:--------------------------------------------------------------------------------------------------------------------------------|
+| 31:1 | | | | Reserved |
+| 0 | rw0c | 0x1 | EN | When 1, the value of [`EXTCLK_CTRL`](#extclk_ctrl) can be set. When 0, writes to [`EXTCLK_CTRL`](#extclk_ctrl) have no effect. |
+
+## EXTCLK_CTRL
+Select external clock
+- Offset: `0x8`
+- Reset default: `0x99`
+- Reset mask: `0xff`
+- Register enable: [`EXTCLK_CTRL_REGWEN`](#extclk_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "SEL", "bits": 4, "attr": ["rw"], "rotate": 0}, {"name": "HI_SPEED_SEL", "bits": 4, "attr": ["rw"], "rotate": -90}, {"bits": 24}], "config": {"lanes": 1, "fontsize": 10, "vspace": 140}}
+```
+
+| Bits | Type | Reset | Name |
+|:------:|:------:|:-------:|:-------------------------------------------|
+| 31:8 | | | Reserved |
+| 7:4 | rw | 0x9 | [HI_SPEED_SEL](#extclk_ctrl--hi_speed_sel) |
+| 3:0 | rw | 0x9 | [SEL](#extclk_ctrl--sel) |
+
+### EXTCLK_CTRL . HI_SPEED_SEL
+A value of kMultiBitBool4True selects nominal speed external clock.
+All other values selects low speed clocks.
+
+Note this field only has an effect when the [`EXTCLK_CTRL.SEL`](#extclk_ctrl) field is set to
+kMultiBitBool4True.
+
+Nominal speed means the external clock is approximately the same frequency as
+the internal oscillator source. When this option is used, all clocks operate
+at roughly the nominal frequency.
+
+Low speed means the external clock is approximately half the frequency of the
+internal oscillator source. When this option is used, the internal dividers are
+stepped down. As a result, previously undivided clocks now run at half frequency,
+while previously divided clocks run at roughly the nominal frequency.
+
+See external clock switch support in documentation for more details.
+
+### EXTCLK_CTRL . SEL
+When the current value is not kMultiBitBool4True, writing a value of kMultiBitBool4True
+selects external clock as clock for the system. Writing any other value has
+no impact.
+
+When the current value is kMultiBitBool4True, writing a value of kMultiBitBool4False
+selects internal clock as clock for the system. Writing any other value during this stage
+has no impact.
+
+While this register can always be programmed, it only takes effect when debug functions are enabled
+in life cycle TEST, DEV or RMA states.
+
+## EXTCLK_STATUS
+Status of requested external clock switch
+- Offset: `0xc`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "ACK", "bits": 4, "attr": ["ro"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name |
+|:------:|:------:|:-------:|:---------------------------|
+| 31:4 | | | Reserved |
+| 3:0 | ro | 0x9 | [ACK](#extclk_status--ack) |
+
+### EXTCLK_STATUS . ACK
+When [`EXTCLK_CTRL.SEL`](#extclk_ctrl) is set to kMultiBitBool4True, this field reflects
+whether the clock has been switched the external source.
+
+kMultiBitBool4True indicates the switch is complete.
+kMultiBitBool4False indicates the switch is either not possible or still ongoing.
+
+## JITTER_REGWEN
+Jitter write enable
+- Offset: `0x10`
+- Reset default: `0x1`
+- Reset mask: `0x1`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:-------------------------------------------------------------------------------------------------------|
+| 31:1 | | | | Reserved |
+| 0 | rw0c | 0x1 | EN | When 1, the value of [`JITTER_ENABLE`](#jitter_enable) can be changed. When 0, writes have no effect. |
+
+## JITTER_ENABLE
+Enable jittery clock
+- Offset: `0x14`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "VAL", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:------------------------------------------------------------------------------------------------------------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | VAL | Enable jittery clock. A value of kMultiBitBool4False disables the jittery clock, while all other values enable jittery clock. |
+
+## CLK_ENABLES
+Clock enable for software gateable clocks.
+These clocks are directly controlled by software.
+- Offset: `0x18`
+- Reset default: `0xf`
+- Reset mask: `0xf`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "CLK_IO_DIV4_PERI_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_IO_DIV2_PERI_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_IO_PERI_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_USB_PERI_EN", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 210}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:--------------------|:---------------------------------------------------------------|
+| 31:4 | | | | Reserved |
+| 3 | rw | 0x1 | CLK_USB_PERI_EN | 0 CLK_USB_PERI is disabled. 1 CLK_USB_PERI is enabled. |
+| 2 | rw | 0x1 | CLK_IO_PERI_EN | 0 CLK_IO_PERI is disabled. 1 CLK_IO_PERI is enabled. |
+| 1 | rw | 0x1 | CLK_IO_DIV2_PERI_EN | 0 CLK_IO_DIV2_PERI is disabled. 1 CLK_IO_DIV2_PERI is enabled. |
+| 0 | rw | 0x1 | CLK_IO_DIV4_PERI_EN | 0 CLK_IO_DIV4_PERI is disabled. 1 CLK_IO_DIV4_PERI is enabled. |
+
+## CLK_HINTS
+Clock hint for software gateable transactional clocks during active mode.
+During low power mode, all clocks are gated off regardless of the software hint.
+
+Transactional clocks are not fully controlled by software. Instead software provides only a disable hint.
+
+When software provides a disable hint, the clock manager checks to see if the associated hardware block is idle.
+If the hardware block is idle, then the clock is disabled.
+If the hardware block is not idle, the clock is kept on.
+
+For the enable case, the software hint is immediately honored and the clock turned on. Hardware does not provide any
+feedback in this case.
+- Offset: `0x1c`
+- Reset default: `0xf`
+- Reset mask: `0xf`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "CLK_MAIN_AES_HINT", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_MAIN_HMAC_HINT", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_MAIN_KMAC_HINT", "bits": 1, "attr": ["rw"], "rotate": -90}, {"name": "CLK_MAIN_OTBN_HINT", "bits": 1, "attr": ["rw"], "rotate": -90}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------------------|:-------------------------------------------------------------|
+| 31:4 | | | | Reserved |
+| 3 | rw | 0x1 | CLK_MAIN_OTBN_HINT | 0 CLK_MAIN_OTBN can be disabled. 1 CLK_MAIN_OTBN is enabled. |
+| 2 | rw | 0x1 | CLK_MAIN_KMAC_HINT | 0 CLK_MAIN_KMAC can be disabled. 1 CLK_MAIN_KMAC is enabled. |
+| 1 | rw | 0x1 | CLK_MAIN_HMAC_HINT | 0 CLK_MAIN_HMAC can be disabled. 1 CLK_MAIN_HMAC is enabled. |
+| 0 | rw | 0x1 | CLK_MAIN_AES_HINT | 0 CLK_MAIN_AES can be disabled. 1 CLK_MAIN_AES is enabled. |
+
+## CLK_HINTS_STATUS
+Since the final state of [`CLK_HINTS`](#clk_hints) is not always determined by software,
+this register provides read feedback for the current clock state.
+
+- Offset: `0x20`
+- Reset default: `0xf`
+- Reset mask: `0xf`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "CLK_MAIN_AES_VAL", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "CLK_MAIN_HMAC_VAL", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "CLK_MAIN_KMAC_VAL", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "CLK_MAIN_OTBN_VAL", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 190}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:------------------|:---------------------------------------------------------|
+| 31:4 | | | | Reserved |
+| 3 | ro | 0x1 | CLK_MAIN_OTBN_VAL | 0 CLK_MAIN_OTBN is disabled. 1 CLK_MAIN_OTBN is enabled. |
+| 2 | ro | 0x1 | CLK_MAIN_KMAC_VAL | 0 CLK_MAIN_KMAC is disabled. 1 CLK_MAIN_KMAC is enabled. |
+| 1 | ro | 0x1 | CLK_MAIN_HMAC_VAL | 0 CLK_MAIN_HMAC is disabled. 1 CLK_MAIN_HMAC is enabled. |
+| 0 | ro | 0x1 | CLK_MAIN_AES_VAL | 0 CLK_MAIN_AES is disabled. 1 CLK_MAIN_AES is enabled. |
+
+## MEASURE_CTRL_REGWEN
+Measurement control write enable
+- Offset: `0x24`
+- Reset default: `0x1`
+- Reset mask: `0x1`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 1, "attr": ["rw0c"], "rotate": -90}, {"bits": 31}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:-----------------------------------------------------------------------------------------|
+| 31:1 | | | | Reserved |
+| 0 | rw0c | 0x1 | EN | When 1, the value of the measurement control can be set. When 0, writes have no effect. |
+
+## IO_MEAS_CTRL_EN
+Enable for measurement control
+- Offset: `0x28`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:--------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | EN | Enable measurement for io |
+
+## IO_MEAS_CTRL_SHADOWED
+Configuration controls for io measurement.
+
+The threshold fields are made wider than required (by 1 bit) to ensure
+there is room to adjust for measurement inaccuracies.
+- Offset: `0x2c`
+- Reset default: `0x759ea`
+- Reset mask: `0xfffff`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "HI", "bits": 10, "attr": ["rw"], "rotate": 0}, {"name": "LO", "bits": 10, "attr": ["rw"], "rotate": 0}, {"bits": 12}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:---------------------------------|
+| 31:20 | | | | Reserved |
+| 19:10 | rw | 0x1d6 | LO | Min threshold for io measurement |
+| 9:0 | rw | 0x1ea | HI | Max threshold for io measurement |
+
+## IO_DIV2_MEAS_CTRL_EN
+Enable for measurement control
+- Offset: `0x30`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:-------------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | EN | Enable measurement for io_div2 |
+
+## IO_DIV2_MEAS_CTRL_SHADOWED
+Configuration controls for io_div2 measurement.
+
+The threshold fields are made wider than required (by 1 bit) to ensure
+there is room to adjust for measurement inaccuracies.
+- Offset: `0x34`
+- Reset default: `0x1ccfa`
+- Reset mask: `0x3ffff`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "HI", "bits": 9, "attr": ["rw"], "rotate": 0}, {"name": "LO", "bits": 9, "attr": ["rw"], "rotate": 0}, {"bits": 14}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:--------------------------------------|
+| 31:18 | | | | Reserved |
+| 17:9 | rw | 0xe6 | LO | Min threshold for io_div2 measurement |
+| 8:0 | rw | 0xfa | HI | Max threshold for io_div2 measurement |
+
+## IO_DIV4_MEAS_CTRL_EN
+Enable for measurement control
+- Offset: `0x38`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:-------------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | EN | Enable measurement for io_div4 |
+
+## IO_DIV4_MEAS_CTRL_SHADOWED
+Configuration controls for io_div4 measurement.
+
+The threshold fields are made wider than required (by 1 bit) to ensure
+there is room to adjust for measurement inaccuracies.
+- Offset: `0x3c`
+- Reset default: `0x6e82`
+- Reset mask: `0xffff`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "HI", "bits": 8, "attr": ["rw"], "rotate": 0}, {"name": "LO", "bits": 8, "attr": ["rw"], "rotate": 0}, {"bits": 16}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:--------------------------------------|
+| 31:16 | | | | Reserved |
+| 15:8 | rw | 0x6e | LO | Min threshold for io_div4 measurement |
+| 7:0 | rw | 0x82 | HI | Max threshold for io_div4 measurement |
+
+## MAIN_MEAS_CTRL_EN
+Enable for measurement control
+- Offset: `0x40`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:----------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | EN | Enable measurement for main |
+
+## MAIN_MEAS_CTRL_SHADOWED
+Configuration controls for main measurement.
+
+The threshold fields are made wider than required (by 1 bit) to ensure
+there is room to adjust for measurement inaccuracies.
+- Offset: `0x44`
+- Reset default: `0x7a9fe`
+- Reset mask: `0xfffff`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "HI", "bits": 10, "attr": ["rw"], "rotate": 0}, {"name": "LO", "bits": 10, "attr": ["rw"], "rotate": 0}, {"bits": 12}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:-----------------------------------|
+| 31:20 | | | | Reserved |
+| 19:10 | rw | 0x1ea | LO | Min threshold for main measurement |
+| 9:0 | rw | 0x1fe | HI | Max threshold for main measurement |
+
+## USB_MEAS_CTRL_EN
+Enable for measurement control
+- Offset: `0x48`
+- Reset default: `0x9`
+- Reset mask: `0xf`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "EN", "bits": 4, "attr": ["rw"], "rotate": 0}, {"bits": 28}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:---------------------------|
+| 31:4 | | | | Reserved |
+| 3:0 | rw | 0x9 | EN | Enable measurement for usb |
+
+## USB_MEAS_CTRL_SHADOWED
+Configuration controls for usb measurement.
+
+The threshold fields are made wider than required (by 1 bit) to ensure
+there is room to adjust for measurement inaccuracies.
+- Offset: `0x4c`
+- Reset default: `0x1ccfa`
+- Reset mask: `0x3ffff`
+- Register enable: [`MEASURE_CTRL_REGWEN`](#measure_ctrl_regwen)
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "HI", "bits": 9, "attr": ["rw"], "rotate": 0}, {"name": "LO", "bits": 9, "attr": ["rw"], "rotate": 0}, {"bits": 14}], "config": {"lanes": 1, "fontsize": 10, "vspace": 80}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------|:----------------------------------|
+| 31:18 | | | | Reserved |
+| 17:9 | rw | 0xe6 | LO | Min threshold for usb measurement |
+| 8:0 | rw | 0xfa | HI | Max threshold for usb measurement |
+
+## RECOV_ERR_CODE
+Recoverable Error code
+- Offset: `0x50`
+- Reset default: `0x0`
+- Reset mask: `0x7ff`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "SHADOW_UPDATE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_MEASURE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_DIV2_MEASURE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_DIV4_MEASURE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "MAIN_MEASURE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "USB_MEASURE_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_TIMEOUT_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_DIV2_TIMEOUT_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "IO_DIV4_TIMEOUT_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "MAIN_TIMEOUT_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"name": "USB_TIMEOUT_ERR", "bits": 1, "attr": ["rw1c"], "rotate": -90}, {"bits": 21}], "config": {"lanes": 1, "fontsize": 10, "vspace": 210}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:--------------------|:---------------------------------------------------------|
+| 31:11 | | | | Reserved |
+| 10 | rw1c | 0x0 | USB_TIMEOUT_ERR | usb has timed out. |
+| 9 | rw1c | 0x0 | MAIN_TIMEOUT_ERR | main has timed out. |
+| 8 | rw1c | 0x0 | IO_DIV4_TIMEOUT_ERR | io_div4 has timed out. |
+| 7 | rw1c | 0x0 | IO_DIV2_TIMEOUT_ERR | io_div2 has timed out. |
+| 6 | rw1c | 0x0 | IO_TIMEOUT_ERR | io has timed out. |
+| 5 | rw1c | 0x0 | USB_MEASURE_ERR | usb has encountered a measurement error. |
+| 4 | rw1c | 0x0 | MAIN_MEASURE_ERR | main has encountered a measurement error. |
+| 3 | rw1c | 0x0 | IO_DIV4_MEASURE_ERR | io_div4 has encountered a measurement error. |
+| 2 | rw1c | 0x0 | IO_DIV2_MEASURE_ERR | io_div2 has encountered a measurement error. |
+| 1 | rw1c | 0x0 | IO_MEASURE_ERR | io has encountered a measurement error. |
+| 0 | rw1c | 0x0 | SHADOW_UPDATE_ERR | One of the shadow registers encountered an update error. |
+
+## FATAL_ERR_CODE
+Error code
+- Offset: `0x54`
+- Reset default: `0x0`
+- Reset mask: `0x7`
+
+### Fields
+
+```wavejson
+{"reg": [{"name": "REG_INTG", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "IDLE_CNT", "bits": 1, "attr": ["ro"], "rotate": -90}, {"name": "SHADOW_STORAGE_ERR", "bits": 1, "attr": ["ro"], "rotate": -90}, {"bits": 29}], "config": {"lanes": 1, "fontsize": 10, "vspace": 200}}
+```
+
+| Bits | Type | Reset | Name | Description |
+|:------:|:------:|:-------:|:-------------------|:---------------------------------------------------------|
+| 31:3 | | | | Reserved |
+| 2 | ro | 0x0 | SHADOW_STORAGE_ERR | One of the shadow registers encountered a storage error. |
+| 1 | ro | 0x0 | IDLE_CNT | One of the idle counts encountered a duplicate error. |
+| 0 | ro | 0x0 | REG_INTG | Register file has experienced a fatal integrity error. |
+
+
+
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/doc/theory_of_operation.md b/hw/top_earlgrey/ip_autogen/clkmgr/doc/theory_of_operation.md
new file mode 100644
index 00000000000000..5d81a4805fda5e
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/doc/theory_of_operation.md
@@ -0,0 +1,298 @@
+# Theory of Operation
+
+Clock management in OpenTitan is divided into groups.
+Each group has specific attributes and controls whether software is allowed to influence individual clocks during the active power state.
+For low power states, please see [power manager](../../pwrmgr/README.md).
+
+The grouping is derived from the chip partition and related security properties.
+For illustrative purposes, this document uses the following assumed chip partition
+
+![Example chip partition](example_chip_partition.svg)
+
+The actual partition may differ per design, however the general principles are assumed to be the same.
+Each group can be made up of more than 1 source clock.
+The clocks themselves may be asynchronous - the grouping is thus a logical grouping instead of a physical one.
+
+The grouping is summarized in the table below and described in more detail afterwards.
+The table shows the group name, the modules that belong to each group, and whether SW can directly (via register control) or indirectly (via wait-for-interrupt) influence the state of the clock in the form of clock gating.
+
+| Group | Frequencies | Modules | Software | Wait for Interrupt |
+| ------------- | ------------------------------ | -------------------------------------------------------------- | -------------- | ------------------ |
+| Power-up | 100~200KHz, 24MHz | Clock Manager, Power Manager, Reset Manager, Pinmux | No | No |
+| Transactional | ~100MHz | Aes, Kmac, Hmac, Key Manager, Otbn | Yes (1) | Yes (2) |
+| Infrastructural | 24MHz, ~100MHz | Fabric, Fabric gaskets (iopmp), Memories | No | Yes (3) |
+| Security | 24MHz, ~100MHz | Alert handler, Entropy, Life cycle, Plic, Sensors | No | No |
+| Peripheral | 24MHz, 48MHz, 96MHz | I2c, Spi, Uart, Usb, others | Yes | Yes |
+| Timers | 100-200KHz, 24MHz | AON timers, Timers, Watchdog | No | No |
+
+* 1 - Transactional clock group's software control is only a software hint.
+* 2 - Transactional clock group's wait-for-interrupt control is only a hint.
+* 3 - May require additional complexity to handle multi-host (non-wait-for-interrupt) scenarios
+
+## Power-up Clock Group
+
+The group refers to modules responsible for power up, such as power, reset and clock managers.
+Large portions of these modules operate to release clocks and resets for the rest of the design, thus cannot operate on gated versions of the clocks themselves.
+They are the only group running clocks directly from the source.
+All follow groups are derived after root clock gating.
+See [block diagram](#block-diagram) for more details.
+
+## Transactional Clock Group
+
+This group refers to the collection of modules that are transactional by nature (example: `Hmac` / `Aes` / `Kmac`).
+This means these modules perform specific tasks (for example encrypt, decrypt or hashing).
+While performing these tasks, it is unsafe to manipulate or change the clocks.
+Once these tasks are complete, the clocks can be safely shut-off.
+
+To ensure such behavior on the clocks, The final clock enable is qualified with an `Idle` indication to signify that a transaction is ongoing and manipulation of the clock is not permitted.
+The `Idle` signal must be sourced from the transactional modules and sent to the clock manager.
+
+For this group software can only express its intent to shut-off, and does not have full control over the final state.
+This intent is indicated with a register in the clock manager register file, see [`CLK_HINTS`](registers.md#clk_hints).
+
+Even when the hint is set, the `Idle` does not directly manipulate the clock.
+When an idle indication is received, the `clkmgr` counts for a period of 10 local clocks to ensure the idle was not a glitch.
+
+Wait-for-interrupt based control is already a software hint, it can thus be applied to this group with the same `Idle` requirement.
+
+For modules in this group, each module can be individually influenced, and thus each has its own dedicated clock gating logic.
+The added benefit of allowing software control in this group is to save power, as some transactional modules can be both power and area hungry.
+
+## Infrastructure Clock Group
+
+This group refers to the collection of modules that support infrastructure functions.
+
+If the clocks to these modules are turned off, there may not be a way to turn them back on and could thus result in system deadlock.
+This includes but is not limited to:
+* Turning off fabric / gasket clocks, and thus having no way to access the fabric and resume the clock.
+* Turning off memory clocks such that there is no way to execute code that would resume the clocks.
+
+For this group, there is no reason to allow software control over the clocks, as it could be used to create a system deadlock where after disabling infrastructure clocks there is no way to turn them back on.
+Wait-for-interrupt controls however can be used, as long as there is a way to break the processor out of wait-for-interrupt and handle other bus hosts, while also separating the functional portions from bus access.
+See Wait-for-interrupt clock gating for more details.
+
+## Security Clock Group
+
+The security clock group is made up of security modules that either have background functions (entropy, alert manager, sensors) or perform critical security functions where disabling clocks could have unexpected side effects (life cycle, otp, pinmux, plic).
+
+For this group, no software influence over the clock state is allowed during the active state.
+The clocks are always running as long as the source is on.
+
+This group is not functionally identical to the power-up group.
+The power-up group is run on clocks directly from the clock source, while the security group is derived after root clock gating.
+
+## Timer Clock Group
+
+The timer clock group is composed of modules that track time for various purposes.
+As influencing time can change the perspective of software and potentially reveal security vulnerabilities, the clock state for these modules cannot be directly or indirectly influenced by software.
+
+Functionally, this group is identical to the security group.
+
+## Peripheral Clock Group
+
+The peripheral clock group is composed of I/O peripherals modules.
+By their nature, I/O peripherals are both transactional and most of the time not security critical - so long as proper care is taken to sandbox peripherals from the system.
+
+These modules can be both directly and indirectly controlled by software.
+The controls can also be individual to each peripheral.
+
+## Wait-for-Interrupt (wfi) Gating
+
+Wait-for-interrupt clock gating refers to the mechanism of using a processor’s sleep indication to actively gate off module clocks.
+Of the groups enumerated, only transactional, infrastructural and peripheral groups can be influenced by `wfi`.
+
+As `wfi` is effectively a processor clock request, there are subtleties related to its use.
+The interaction with each clock group is briefly described below.
+
+### Transactional Clock Group
+
+While `wfi` gating can be applied to this group, the modules in this category are already expected to be turned off and on by software depending on usage.
+Specifically, these modules are already completely managed by software when not in use, thus may not see significant benefit from `wfi` gating.
+
+### Peripheral Clock Group
+
+Since peripherals, especially those in device mode, are often operated in an interrupt driven way, the peripheral's core operating clock frequently must stay alive even if the processor is asleep.
+This implies that in order for peripherals to completely support `wfi` clock gating, they must be split between functional clocks and bus clocks.
+
+The bus clocks represent the software interface and can be turned off based on `wfi gating`, while the functional clocks should be kept running to ensure outside activity can be captured and interrupts created.
+In this scenario, it is important to ensure the functional clocks are responsible for creating interrupts and not the bus clocks, as the latter may not be available during `wfi`.
+
+This division may only be beneficial for peripherals where register and local fabric size is large relative to the functional component.
+
+### Infrastructural Clock Group
+
+This clock group matches `wfi` functionality well.
+Most infrastructural components such as fabric, gaskets and memories, have no need to be clocked when the processor is idle.
+Some components such as flash controller however would also need to be split into bus and functional halves to support long, background activities while the processor is idle.
+
+However, there are additional complications.
+In systems where the processor is not the only bus host, `wfi` can only be used as the software request and not final clock state decision.
+Hardware driven requests, such as those coming from a `dma` or any peripheral driven bus host, would also need to be included as part of the equation.
+Further, since it is possible hardware may issue requests at the boundary of a clock state changes, additional fabric gaskets would be required to protect hosts when destinations are temporarily clocked off.
+The bus requests themselves thus become dynamic clock request signals to help enable components in its path.
+
+There is thus a moderate design and high verification cost to supporting `wfi` gating for the infrastructural group.
+
+## Block Diagram
+
+The following is a high level block diagram of the clock manager.
+
+![Clock Manager Block Diagram](clkmgr_block_diagram.svg)
+
+### Reset Domains
+
+Since the function of the clock manager is tied closely into the power-up behavior of the device, the reset domain selection must also be purposefully done.
+To ensure that default clocks are available for the [power manager to release resets and initialize memories](../../pwrmgr/README.md#fast-clock-domain-fsm), the clock dividers inside the clock manager directly use `por` (power-on-reset) derived resets.
+This ensures that the root clocks are freely running after power-up and its status can be communicated to the `pwrmgr` regardless of any other activity in the device.
+
+The other functions inside the clock manager operate on the `life cycle reset` domain.
+This ensures that other clock manager functions still release early relative to most functions in the system, and that a user or escalation initiated reset still restores the clock manager to a default clean slate.
+
+The escalation reset restoration is especially important as the clock manager can generate fatal faults that lead to escalation.
+If there were not a mechanism that allows escalation to clear the original fault, the system would simply remain in a faulted state until a user initiated a `por` event.
+
+For a detailed breakdown between `por` and `life cycle` resets, please see the [reset manager](../../rstmgr/README.md).
+
+The following diagram enhances the block diagram to illustrate the overall reset domains of the clock manager.
+![Clock Manager Block Diagram](clkmgr_rst_domain.svg)
+
+### Clock Gated Indications for Alert Handler
+
+The alert handler needs to know the status of the various clock domains in the system to avoid false alert indications due to the ping mechanism.
+To that end, the clock manager outputs a 4bit MuBi signal for each clock domain that indicates whether its clock is active.
+For more information on this mechanism, see [alert handler documentation](../../alert_handler/doc/theory_of_operation.md#low-power-management-of-alert-channels).
+
+## Design Details
+
+### Root Clock Gating and Interface with Power Manager
+
+All clock groups except the power-up group run from gated source clocks.
+The source clocks are gated off during low power states as controlled by the power manager.
+When the power manager makes a clock enable request, the clock manager ensures all root clock gates are enabled before acknowledging.
+Likewise, when the power manager makes a clock disable request, the clock manager ensures all root clock gates off disabled before acknowledging.
+
+Note, the power manager's request to turn off clocks supersedes all other local controls in the clock manager.
+This means even if a particular clock is turned on by the clock manager (for example a transactional unit that is ongoing or a peripheral that is enabled), the power manager requests will still turn clocks on / off at the root.
+
+This makes it software's responsibility to ensure low power entry requests (which can only be initiated by software) do not conflict with any ongoing activities controlled by software.
+For example, software should ensure that Aes / Otbn activities have completed before initializing a low power entry process.
+
+### Clock Division
+
+Not all peripherals run at the full IO clock speed, hence the IO clock is divided down by 2x and 4x in normal operation.
+This division ratio can be modified to 1x and 2x when switching to an external clock, since the external clock may be slower than the internal clock source.
+See also [external clock switch support](#external-clock-switch-support).
+
+The divided clock is not assumed to be synchronous with its source and is thus treated like another asynchronous branch.
+Further, the clock dividers are hardwired and have no software control, this is to further ensure there are no simple paths for faulty or malicious software to tamper.
+
+Note that for debug purposes, `ast` can also request a change in the clock division ratio via a dedicated hardware interface (`div_step_down_req_i`).
+
+### Wait-for-Interrupt Support
+
+Given the marginal benefits and the increased complexity of `wfi` support, the first version of this design does not support `wfi` gating.
+All `wfi CG` modules in the block diagram are thus drawn with dashed lines to indicate it can be theoretically supported but currently not implemented.
+
+It may be added for future more complex systems where there is a need to tightly control infrastructural power consumption as a result from clocks.
+
+### External Clock Switch Support
+
+Clock manager supports the ability to request root clocks switch to an external clock.
+There are two occasions where this is required:
+- Life cycle transition from `RAW` / `TEST_LOCKED*` to `TEST_UNLOCKED*` [states](../../../../ip/lc_ctrl/README.md#clk_byp_req).
+- Software request for external clocks during normal functional mode.
+
+
+#### Life Cycle Requested External Clock
+
+The life cycle controller only requests the io clock input to be switched.
+When the life cycle controller requests external clock, a request signal `lc_clk_byp_req_i` is sent from `lc_ctrl` to `clkmgr`.
+`clkmgr` then forwards the request to `ast` through `io_clk_byp_req_o`, which performs the actual clock switch and is acknowledged through `io_clk_byp_ack_i`.
+When the clock switch is complete, the clock dividers are stepped down by a factor of 2 and the life cycle controller is acknowledged through `lc_clk_byp_ack_o`.
+
+Note that this division factor change is done since the external clock is expected to be 48MHz while the nominal frequency of the internal clock is 96MHz.
+I.e. this division factor change keeps the nominal frequencies of the div_2 and div_4 clocks stable at 48Mhz and 24MHz, respectively.
+See [Clock Frequency Summary](#clock-frequency-summary) for more details.
+
+#### Software Requested External Clocks
+
+Unlike the life cycle controller, a software request for external clocks switches all clock sources to an external source.
+Software request for external clocks is not always valid.
+Software is only able to request for external clocks when hardware debug functions are [allowed](../../../../ip/lc_ctrl/README.md#hw_debug_en).
+
+When software requests the external clock switch, it also provides an indication how fast the external clock is through [`EXTCLK_CTRL.HI_SPEED_SEL`](registers.md#extclk_ctrl).
+There are two supported clock speeds:
+* High speed - external clock is close to nominal speeds (e.g. external clock is 96MHz and nominal frequency is 96MHz-100MHz)
+* Low speed - external clock is half of nominal speeds (e.g. external clock is 48MHz and nominal frequency is 96MHz-100MHz)
+
+When software requests external clock, the register bit [`EXTCLK_CTRL.SEL`](registers.md#extclk_ctrl) is written.
+If hardware debug functions are allowed, the `clkmgr` sends a request signal `all_clk_byp_req_o` to `ast` and is acknowledged through `all_clk_byp_ack_i`.
+
+If software requests a low speed external clock, at the completion of the switch, internal dividers are also stepped down.
+When the divider is stepped down, a divide-by-4 clock becomes divide-by-2 clock , and a divide-by-2 becomes a divide-by-1 clock.
+
+If software requests a high speed external clock, the dividers are kept as is.
+
+
+Note, software external clock switch support is meant to be a debug / evaluation feature, and should not be used in conjunction with the clock frequency and timeout measurement features.
+This is because if the clock frequency suddenly changes, the thresholds used for timeout / measurement checks will no longer apply.
+There is currently no support in hardware to dynamically synchronize a threshold change to the expected frequency.
+
+#### Clock Frequency Summary
+
+The table below summarises the valid modes and the settings required.
+
+| Mode | `lc_clk_byp_req_i` | `extclk_ctrl.sel` | `extclk_ctrl.hi_speed_sel` | life cycle state |
+| ------------- | --------------------- | ----------------- | ----------------------------| -------------------------------|
+| Life cycle in `RAW`, `TEST*` and `RMA` states | `lc_ctrl_pkg::On` | `kMultiBit4False` | Don't care | Controlled by `lc_ctrl` |
+| Internal Clocks | `lc_ctrl_pkg::Off` | `kMultiBit4False` | Don't care | All |
+| Software external high speed | `lc_ctrl_pkg::Off` | `kMultiBit4True` | `kMultiBit4True` | `TEST_UNLOCKED*`, `DEV`, `RMA` |
+| Software external low speed | `lc_ctrl_pkg::Off` | `kMultiBit4True` | `kMultiBit4False` | `TEST_UNLOCKED*`, `DEV`, `RMA` |
+
+The table below summarizes the frequencies in each mode.
+This table assumes that the internal clock source is 96MHz.
+This table also assumes that high speed external clock is 96MHz, while low speed external clock is 48MHz.
+
+| Mode | External Clock Frequency | div_1_clock | div_2_clock | div_4_clock |
+| ------------- | ------------------------ | ------------- | --------------- | -------------|
+| Internal Clocks | Not applicable | 96MHz | 48MHz | 24MHz |
+| Life cycle transition | 48MHz | 48MHz | 48MHz | 24MHz |
+| Software external high speed | 96MHz | 96MHz | 48MHz | 24MHz |
+| Software external low speed | 48MHz | 48MHz | 48MHz | 24MHz |
+
+As can be seen from the table, the external clock switch scheme prioritizes the stability of the divided clocks, while allowing the undivided clocks to slow down.
+
+
+### Clock Frequency / Time-out Measurements
+
+Clock manager can continuously measure root clock frequencies to see if any of the root clocks have deviated from the expected frequency.
+This feature can be enabled through the various measurement control registers such as [`IO_MEASURE_CTRL`](registers.md#io_measure_ctrl).
+
+The root clocks, specifically the clocks supplied from `ast` and their divided variants, are constantly measured against the `always on clock` when this feature is enabled.
+Software sets both an expected maximum and minimum for each measured clock.
+
+Clock manager then counts the number of relevant root clock cycles in each always-on clock period.
+If the resulting count differs from the programmed thresholds, a recoverable error is registered.
+
+Since the counts are measured against a single cycle of always on clock, the minimal error that can be detected is dependent on the clock ratio between the measured clock and 1 cycle of the always on clock.
+Assume a 24MHz clock and an always-on clock of 200KHz.
+The minimal error detection is then 200KHz / 24MHz, or approximately 0.83%.
+
+This means if the clock's actual value is between 23.8MHz and 24.2MHz, this deviation will not be detected.
+Conversely, if the clock's natural operation has an error range wider than this resolution, the min / max counts must be adjusted to account for this error.
+
+Additionally, clock manager uses a similar time-out mechanism to see if any of the root clocks have stopped toggling for an extended period of time.
+This is done by creating an artificial handshake between the root clock domain and the always on clock domain that must complete within a certain amount of time based on known clock ratios.
+Based on the nature of the handshake and the margin window, the minimal timeout detection window is approximately 2-4 always on clock cycles.
+If the root clock domain stops and resumes in significantly less time than this window, the time-out may not be detected.
+
+There are three types of errors:
+* Clock too fast error
+* Clock too slow error
+* Clock time-out error
+
+Clock too fast is registered when the clock cycle count is greater than the software programmed max threshold.
+Clock too slow is registered when the clock cycle count is less than the software programmed min threshold.
+Clock time-out is registered when the clock stops toggling and the timeout threshold is reached.
+
+As these are all software supplied values, the entire measurement control can be locked from further programming through [`MEASURE_CTRL_REGWEN`](registers.md#measure_ctrl_regwen).
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/README.md b/hw/top_earlgrey/ip_autogen/clkmgr/dv/README.md
new file mode 100644
index 00000000000000..74e2a4a6ddfa33
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/README.md
@@ -0,0 +1,187 @@
+# CLKMGR DV document
+
+## Goals
+* **DV**
+ * Verify all CLKMGR IP features by running dynamic simulations with a SV/UVM based testbench.
+ * Develop and run all tests based on the [testplan](#testplan) below towards closing code and functional coverage on the IP and all of its sub-modules.
+* **FPV**
+ * Verify TileLink device protocol compliance with an SVA based testbench.
+ * Verify clock gating assertions.
+
+## Current status
+* [Design & verification stage](../../../../README.md)
+ * [HW development stages](../../../../../doc/project_governance/development_stages.md)
+* [Simulation results](https://reports.opentitan.org/hw/ip/clkmgr/dv/latest/report.html)
+
+## Design features
+The detailed information on CLKMGR design features is at [CLKMGR HWIP technical specification](../README.md).
+
+## Testbench architecture
+CLKMGR testbench has been constructed based on the [CIP testbench architecture](../../../../dv/sv/cip_lib/README.md).
+
+### Block diagram
+![Block diagram](./doc/tb.svg)
+
+### Top level testbench
+Top level testbench is located at `hw/top_earlgrey/ip_autogen/clkmgr/dv/tb.sv`.
+It instantiates the CLKMGR DUT module `hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr.sv`.
+In addition, it instantiates the following interfaces, connects them to the DUT and sets their handle into `uvm_config_db`:
+
+* [Clock and reset interface](../../../../dv/sv/common_ifs/README.md)
+* [TileLink host interface](../../../../dv/sv/tl_agent/README.md)
+* CLKMGR IOs: `hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_if.sv`
+
+### Common DV utility components
+The following utilities provide generic helper tasks and functions to perform activities that are common across the project:
+
+* [dv_utils_pkg](../../../../dv/sv/dv_utils/README.md)
+* [csr_utils_pkg](../../../../dv/sv/csr_utils/README.md)
+
+### Global types & methods
+All common types and methods defined at the package level can be found in
+`clkmgr_env_pkg`. Some of them in use are:
+
+```systemverilog
+ localparam int NUM_PERI = 4;
+ localparam int NUM_TRANS = 5;
+ localparam int NUM_ALERTS = 2;
+
+ typedef logic [NUM_PERI-1:0] peri_enables_t;
+ typedef logic [NUM_TRANS-1:0] hintables_t;
+
+ typedef virtual clkmgr_if clkmgr_vif;
+ typedef virtual clk_rst_if clk_rst_vif;
+ typedef enum int {PeriDiv4, PeriDiv2, PeriIo, PeriUsb} peri_e;
+ typedef enum int {TransAes, TransHmac, TransKmac, TransOtbnIoDiv4, TransOtbnMain} trans_e;
+```
+
+### TL_agent
+CLKMGR testbench instantiates (already handled in CIP base env) [tl_agent](../../../../dv/sv/tl_agent/README.md) which provides the ability to drive and independently monitor random traffic via TL host interface into CLKMGR device.
+
+### UVM RAL Model
+The CLKMGR RAL model is created with the [`ralgen`](../../../../dv/tools/ralgen/README.md) FuseSoC generator script automatically when the simulation is at the build stage.
+
+It can be created manually by invoking [`regtool`](../../../../../util/reggen/doc/setup_and_use.md):
+
+## Stimulus strategy
+This module is rather simple: the stimulus is just the external pins and the CSR updates.
+There are a couple stages for synchronization of the CSR updates for clock gating controls, but scanmode is used asynchronously.
+These go to the clock gating latches.
+The external pins controlling the external clock selection need no synchronization.
+The tests randomize the inputs and issue CSR updates affecting the specific functions being tested.
+
+### Test sequences
+All test sequences reside in `hw/ip/clkmgr/dv/env/seq_lib`.
+The `clkmgr_base_vseq` virtual sequence is extended from `cip_base_vseq` and serves as a starting point.
+It provides commonly used handles, variables, functions and tasks that the test sequences can use or call.
+Some of the most commonly used tasks / functions are as follows:
+* `clkmgr_init`: Sets the frequencies of the various clocks.
+* `control_ip_clocks`: Turns on or off the input clocks based on the various clock enable and status ports to and from the `pwrmgr` IP.
+
+All test sequences are extended from `clkmgr_base_vseq`, and are described below.
+
+#### clkmgr_peri_vseq
+
+The sequence `clkmgr_peri_vseq` randomizes the stimuli that drive the four peripheral clocks.
+These clocks are mutually independent so they are tested in parallel.
+They depend on
+* The `clk_enables` CSR, which has a dedicated enable for each peripheral clock
+* The pwrmgr's `_ip_clk_en` which has a dedicated bit controlling `io`, `main`, and `usb` clocks
+* The `scanmode_i` input, which is used asynchronously and also controls all.
+
+The sequence runs a number of iterations, each randomizing the above except for `io_ip_clk_en` since that would imply the processor is disabled.
+
+#### clkmgr_trans_vseq
+
+The sequence `clkmgr_trans_vseq` randomizes the stimuli that drive the five transactional unit clocks.
+These are also mutually independent so they are tested in parallel.
+They depend on the `clk_hints` CSR, which has a separate bit for each, `main_ip_clk_en` and `scanmode_i`, similar to the peripheral clocks.
+They also depend on the `idle_i` input, which also has a separate multi-bit value for each unit.
+Units are considered busy when their corresponding `idle_i` value is not `mubi_pkg::MuBi4True`, and this prevents its clock turning off until it becomes idle.
+
+#### clkmgr_extclk_vseq
+
+The sequence `clkmgr_extclk_vseq` randomizes the stimuli that drive the external clock selection.
+The selection is controlled by software if the `extclk_ctrl.sel` CSR is `prim_mubi_pkg::MuBi4True`, provided the `lc_hw_debug_en_i` input is also set to `lc_ctrl_pkg::On`.
+Alternatively, the external clock is selected by the life cycle controller if the `lc_ctrl_byp_req_i` input is `lc_ctrl_pkg::On`.
+When the external clock is selected and `scanmode_i` is not set to `prim_mubi_pkg::MuBi4True`, the clock dividers for the clk_io_div2 and clk_io_div4 output clocks are stepped down:
+* If `lc_ctrl_byp_req_i` is on, or
+* If `extclk_ctrl.hi_speed_sel` CSR is `prim_mubi_pkg::MuBi4True`, when the selection is enabled by software.
+
+#### clkmgr_frequency_vseq
+
+The sequence `clkmgr_frequency_vseq` randomly programs the frequency measurement for each clock so its measurement is either okay, slow, or fast.
+It checks the recoverable alerts trigger as expected when a measurement is not okay.
+It also checks the `recov_err_code` CSR sets bits for clocks whose measurement is out of bounds.
+It also checks that loss of calibration stops clock measurements and doesn't trigger errors.
+
+#### clkmgr_frequency_timeout_vseq
+
+The sequence `clkmgr_frequency_timeout_vseq` programs the frequency measurement for each clock so its measurement is okay.
+It randomly stops one of the clocks, and checks the corresponding bit in the `recov_err_code` show a timeout.
+It also checks the recoverable alerts trigger as expected for a timeout.
+
+#### clkmgr_clk_status_vseq
+
+This checks that the `pwr_o.*_status` outputs track the `pwr_i.*_ip_clk_en` inputs.
+The inputs are set at random and the outputs are checked via SVA.
+
+### Functional coverage
+To ensure high quality constrained random stimulus, it is necessary to develop a functional coverage model.
+The following covergroups have been developed to prove that the test intent has been adequately met:
+
+* Covergroups for inputs to each software gated peripheral clock.
+ These are wrapped in class `clkmgr_peri_cg_wrap` and instantiated in `clkmgr_env_cov`.
+* Covergroups for inputs to each transactional gated unit clock.
+ These are wrapped in class `clkmgr_trans_cg_wrap` and instantiated in `clkmgr_env_cov`.
+* Covergroups for the outcome of each clock measurement.
+ These are wrapped in class `freq_measure_cg_wrap` and instantiated in `clkmgr_env_cov`.
+* Covergroup for the external clock selection logic: `extclk_cg` in `clkmgr_env_cov`.
+
+See more detailed description at `hw/ip/clkmgr/data/clkmgr_testplan.hjson`.
+
+## Self-checking strategy
+
+Most of the checking is done using SVA for input to output, or CSR update to output behavior.
+Some of the CLKMGR outputs are gated clocks, which are controlled by both synchronous logic and asynchronous enables.
+These asynchronous enables become synchronous because of the SVA semantics.
+This is fine since the assertions allow some cycles for the expected behavior to occur.
+
+### Scoreboard
+The `clkmgr_scoreboard` combines CSR updates and signals from the clkmgr vif to instrument some checks and coverage collection.
+The CSR updates are determined using the TLUL analysis port.
+
+The CSR controlled output clocks can be separated into two groups: peripheral ip clocks and transactional unit clocks.
+Please refer to the [Test sequences section](#test-sequences) above.
+The clock gating logic is pretty similar across units in each group.
+For each peripheral and transactional clock the scoreboard samples their coverage based on clocking blocks instantiated in `clkmgr_if`.
+Most other other functional coverage groups are also sampled in the scoreboard.
+
+The `jitter_en_o` output is checked to match the `jitter_enable` CSR.
+
+### Assertions
+* Pwrmgr enable-status assertions: Interface `clkmgr_pwrmgr_sva_if` contains concurrent SVA that checks that edges of the various ip_clk_en are followed by corresponding edges of their clk_status.
+ The clocks checked are `main`, `io`, and `usb`.
+* Gated clock assertions: Interface `clkmgr_gated_clock_sva_if` contains concurrent SVA that checks each gated clock is either running or stopped based on their control logic.
+ There is one assertion for each of the four peripheral clock and four hintable clocks.
+* Transactional clock assertions: Interface `clkmgr_trans_sva_if` contains concurrent SVA that checks each transactional clock is either running or stopped based on their control logic.
+ There is one assertion for each of the four hintable clocks.
+* Clock divider assertions: Interface `clkmgr_div_sva_if` contains concurrent SVA that checks the `io_div2` and `io_div4` clocks are running at nominal frequency, or are divided by two each in response to the `extclk` logic.
+* External clock assertions: Interface `clkmgr_extclk_sva_if` contains concurrent SVA that checks the external control outputs respond correctly to the various CSR or inputs that control them.
+* Clock gating assertions: Interface `clkmgr_cg_en_sva_if` contains concurrent assertions that check a clock's cg_en output is active when the clock is disabled, and viceversa.
+ As a special case, interface `clkmgr_aon_cg_en_sva_if` checks cg_en is never active for an aon clock.
+* Lost calibration assertions: Interfaces `clkmgr_lost_calib_ctrl_en_sva_if` and `clkmgr_lost_calib_regwen_sva_if` check that losing calibration turns off clock measurements and re-enables measure control writes.
+* TLUL assertions: `clkmgr_bind.sv` binds the `tlul_assert` [assertions](../../../../ip/tlul/doc/TlulProtocolChecker.md) to the IP to ensure TileLink interface protocol compliance.
+* Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset.
+
+## Building and running tests
+We are using our in-house developed [regression tool](../../../../../util/dvsim/README.md) for building and running our tests and regressions.
+Please take a look at the link for detailed information on the usage, capabilities, features and known issues.
+Here's how to run a smoke test:
+
+```console
+$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke
+```
+
+## Testplan
+[Testplan](../data/clkmgr_testplan.hjson)
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim.core
new file mode 100644
index 00000000000000..9a6434e9065cb1
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim.core
@@ -0,0 +1,30 @@
+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:dv:clkmgr_sim:0.1"
+description: "CLKMGR DV sim target"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:ip_interfaces:clkmgr
+
+ files_dv:
+ depend:
+ - lowrisc:dv:clkmgr_test
+ - lowrisc:dv:clkmgr_sva
+ files:
+ - tb.sv
+ - cov/clkmgr_cov_bind.sv
+ file_type: systemVerilogSource
+
+targets:
+ sim: &sim_target
+ toplevel: tb
+ filesets:
+ - files_rtl
+ - files_dv
+ default_tool: vcs
+
+ lint:
+ <<: *sim_target
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson b/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson
new file mode 100644
index 00000000000000..580ffae9ac1c3b
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/clkmgr_sim_cfg.hjson
@@ -0,0 +1,129 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+{
+ // Name of the sim cfg - typically same as the name of the DUT.
+ name: clkmgr
+
+ // Top level dut name (sv module).
+ dut: clkmgr
+
+ // Top level testbench name (sv module).
+ tb: tb
+
+ // Simulator used to sign off this block
+ tool: vcs
+
+ // Fusesoc core file used for building the file list.
+ fusesoc_core: lowrisc:dv:clkmgr_sim:0.1
+
+ // Testplan hjson file.
+ testplan: "{self_dir}/../data/clkmgr_testplan.hjson"
+
+ // RAL spec - used to generate the RAL model.
+ ral_spec: "{self_dir}/../data/clkmgr.hjson"
+
+ // Import additional common sim cfg files.
+ import_cfgs: [// Project wide common sim cfg file
+ "{proj_root}/hw/dv/tools/dvsim/common_sim_cfg.hjson",
+ // Common CIP test lists
+ "{proj_root}/hw/dv/tools/dvsim/tests/csr_tests.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/intr_test.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/alert_test.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/tl_access_tests.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/stress_tests.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/sec_cm_tests.hjson",
+ "{proj_root}/hw/dv/tools/dvsim/tests/shadow_reg_errors_tests.hjson"
+ ]
+
+ // Add additional tops for simulation.
+ sim_tops: ["clkmgr_bind",
+ "clkmgr_cov_bind",
+ "sec_cm_prim_count_bind",
+ "sec_cm_prim_onehot_check_bind"]
+
+ // Default iterations for all tests - each test entry can override this.
+ reseed: 50
+
+ // CLKMGR exclusion files.
+ vcs_cov_excl_files: ["{self_dir}/cov/clkmgr_cov_manual_excl.el",
+ "{self_dir}/cov/clkmgr_cov_unr_excl.el"]
+
+ // Default UVM test and seq class name.
+ uvm_test: clkmgr_base_test
+ uvm_test_seq: clkmgr_base_vseq
+
+ // Disable clearing interrupts since clkmgr doesn't have any.
+ run_opts: ["+do_clear_all_interrupts=0",
+ // Enable cdc instrumentation.
+ "+cdc_instrumentation_enabled=1"]
+
+ // List of test specifications.
+ tests: [
+ {
+ name: clkmgr_smoke
+ uvm_test_seq: clkmgr_smoke_vseq
+ }
+ {
+ name: clkmgr_extclk
+ uvm_test_seq: clkmgr_extclk_vseq
+ }
+ {
+ name: clkmgr_frequency
+ uvm_test_seq: clkmgr_frequency_vseq
+ }
+ {
+ name: clkmgr_frequency_timeout
+ uvm_test_seq: clkmgr_frequency_timeout_vseq
+ }
+ {
+ name: clkmgr_peri
+ uvm_test_seq: clkmgr_peri_vseq
+ }
+ {
+ name: clkmgr_trans
+ uvm_test_seq: clkmgr_trans_vseq
+ }
+ {
+ name: clkmgr_clk_status
+ uvm_test_seq: clkmgr_clk_status_vseq
+ }
+ {
+ name: clkmgr_idle_intersig_mubi
+ uvm_test_seq: clkmgr_trans_vseq
+ run_opts: ["+clkmgr_mubi_mode=ClkmgrMubiIdle"]
+ }
+ {
+ name: clkmgr_lc_ctrl_intersig_mubi
+ uvm_test_seq: clkmgr_extclk_vseq
+ run_opts: ["+clkmgr_mubi_mode=ClkmgrMubiLcCtrl"]
+ }
+ {
+ name: clkmgr_lc_clk_byp_req_intersig_mubi
+ uvm_test_seq: clkmgr_extclk_vseq
+ run_opts: ["+clkmgr_mubi_mode=ClkmgrMubiLcHand"]
+ }
+ {
+ name: clkmgr_clk_handshake_intersig_mubi
+ uvm_test_seq: clkmgr_extclk_vseq
+ run_opts: ["+clkmgr_mubi_mode=ClkmgrMubiHand"]
+ }
+ {
+ name: clkmgr_div_intersig_mubi
+ uvm_test_seq: clkmgr_extclk_vseq
+ run_opts: ["+clkmgr_mubi_mode=ClkmgrMubiDiv"]
+ }
+ {
+ name: clkmgr_regwen
+ uvm_test_seq: clkmgr_regwen_vseq
+ }
+ ]
+
+ // List of regressions.
+ regressions: [
+ {
+ name: smoke
+ tests: ["clkmgr_smoke"]
+ }
+ ]
+}
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_bind.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_bind.sv
new file mode 100644
index 00000000000000..2797ab88145881
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_bind.sv
@@ -0,0 +1,50 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description:
+// Clock manager coverage bindings for multi bus input
+module clkmgr_cov_bind;
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_idle_0_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (idle_i[0])
+ );
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_idle_1_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (idle_i[1])
+ );
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_idle_2_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (idle_i[2])
+ );
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_idle_3_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (idle_i[3])
+ );
+
+ bind clkmgr cip_lc_tx_cov_if u_lc_hw_debug_en_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .val (lc_hw_debug_en_i)
+ );
+
+ bind clkmgr cip_lc_tx_cov_if u_lc_clk_byp_req_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .val (lc_clk_byp_req_i)
+ );
+
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_io_clk_byp_ack_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (io_clk_byp_ack_i)
+ );
+
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_all_clk_byp_ack_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (all_clk_byp_ack_i)
+ );
+
+ bind clkmgr cip_mubi_cov_if #(.Width(prim_mubi_pkg::MuBi4Width)) u_div_step_down_req_mubi_cov_if (
+ .rst_ni (rst_ni),
+ .mubi (div_step_down_req_i)
+ );
+
+endmodule // clkmgr_cov_bind
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_manual_excl.el b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_manual_excl.el
new file mode 100644
index 00000000000000..4228c8c539e81a
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_manual_excl.el
@@ -0,0 +1,49 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// This contains some obvious exclusions the UNR tool didn't flag.
+
+//==================================================
+// This file contains the Excluded objects
+// Generated By User: maturana
+// Format Version: 2
+// Date: Thu Sep 29 13:57:41 2022
+// ExclMode: default
+//==================================================
+CHECKSUM: "2301929872 1660332954"
+INSTANCE: tb.dut.u_clk_main_aes_trans.u_idle_cnt
+ANNOTATION: "[UNR] Input tied to a constant, and unr doesn't detect it."
+Toggle step_i "net step_i[3:0]"
+CHECKSUM: "2301929872 1660332954"
+INSTANCE: tb.dut.u_clk_main_hmac_trans.u_idle_cnt
+ANNOTATION: "[UNR] Input tied to a constant, and unr doesn't detect it."
+Toggle step_i "net step_i[3:0]"
+CHECKSUM: "2301929872 1660332954"
+INSTANCE: tb.dut.u_clk_main_kmac_trans.u_idle_cnt
+ANNOTATION: "[UNR] Input tied to a constant, and unr doesn't detect it."
+Toggle step_i "net step_i[3:0]"
+CHECKSUM: "2301929872 1660332954"
+INSTANCE: tb.dut.u_clk_main_otbn_trans.u_idle_cnt
+ANNOTATION: "[UNR] Input tied to a constant, and unr doesn't detect it."
+Toggle step_i "net step_i[3:0]"
+CHECKSUM: "953655365 3155586170"
+INSTANCE: tb.dut
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.aon_powerup "logic cg_en_o.aon_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.usb_powerup "logic cg_en_o.usb_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.main_powerup "logic cg_en_o.main_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.io_powerup "logic cg_en_o.io_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.io_div2_powerup "logic cg_en_o.io_div2_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.io_div4_powerup "logic cg_en_o.io_div4_powerup[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.aon_peri "logic cg_en_o.aon_peri[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.aon_timers "logic cg_en_o.aon_timers[3:0]"
+ANNOTATION: "[UNR] This is driven by a constant, and unr doesn't detect it."
+Toggle cg_en_o.aon_secure "logic cg_en_o.aon_secure[3:0]"
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_unr_excl.el b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_unr_excl.el
new file mode 100644
index 00000000000000..184b9d8a3c05f9
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/cov/clkmgr_cov_unr_excl.el
@@ -0,0 +1,200 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Generated UNR file from Synopsys UNR tool with security modules being
+// black-boxed.
+
+//==================================================
+// This file contains the Excluded objects
+// Generated By User: maturana
+// Format Version: 2
+// Date: Wed Jan 18 15:59:24 2023
+// ExclMode: default
+//==================================================
+CHECKSUM: "2972535896 3274445021"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_aes_val
+ANNOTATION: "VC_COV_UNR"
+Condition 1 "2397158838" "(wr_en ? wr_data : qs) 1 -1" (1 "0")
+CHECKSUM: "2972535896 3274445021"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_hmac_val
+ANNOTATION: "VC_COV_UNR"
+Condition 1 "2397158838" "(wr_en ? wr_data : qs) 1 -1" (1 "0")
+CHECKSUM: "2972535896 3274445021"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_kmac_val
+ANNOTATION: "VC_COV_UNR"
+Condition 1 "2397158838" "(wr_en ? wr_data : qs) 1 -1" (1 "0")
+CHECKSUM: "2972535896 3274445021"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_otbn_val
+ANNOTATION: "VC_COV_UNR"
+Condition 1 "2397158838" "(wr_en ? wr_data : qs) 1 -1" (1 "0")
+CHECKSUM: "2972535896 3554514034"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_aes_val
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3759852512" "wr_en" (1) "wr_en 0"
+ANNOTATION: "VC_COV_UNR"
+Branch 1 "1017474648" "(!rst_ni)" (2) "(!rst_ni) 0,0"
+CHECKSUM: "2972535896 3554514034"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_hmac_val
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3759852512" "wr_en" (1) "wr_en 0"
+ANNOTATION: "VC_COV_UNR"
+Branch 1 "1017474648" "(!rst_ni)" (2) "(!rst_ni) 0,0"
+CHECKSUM: "2972535896 3554514034"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_kmac_val
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3759852512" "wr_en" (1) "wr_en 0"
+ANNOTATION: "VC_COV_UNR"
+Branch 1 "1017474648" "(!rst_ni)" (2) "(!rst_ni) 0,0"
+CHECKSUM: "2972535896 3554514034"
+INSTANCE: tb.dut.u_reg.u_clk_hints_status_clk_main_otbn_val
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3759852512" "wr_en" (1) "wr_en 0"
+ANNOTATION: "VC_COV_UNR"
+Branch 1 "1017474648" "(!rst_ni)" (2) "(!rst_ni) 0,0"
+CHECKSUM: "215202837 3193272610"
+INSTANCE: tb.dut.u_io_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3003057152" "(!rst_ni)" (4) "(!rst_ni) 0,0,0,0"
+CHECKSUM: "215202837 3193272610"
+INSTANCE: tb.dut.u_io_div2_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3003057152" "(!rst_ni)" (4) "(!rst_ni) 0,0,0,0"
+CHECKSUM: "215202837 3193272610"
+INSTANCE: tb.dut.u_io_div4_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3003057152" "(!rst_ni)" (4) "(!rst_ni) 0,0,0,0"
+CHECKSUM: "215202837 3193272610"
+INSTANCE: tb.dut.u_main_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3003057152" "(!rst_ni)" (4) "(!rst_ni) 0,0,0,0"
+CHECKSUM: "215202837 3193272610"
+INSTANCE: tb.dut.u_usb_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk
+ANNOTATION: "VC_COV_UNR"
+Branch 0 "3003057152" "(!rst_ni)" (4) "(!rst_ni) 0,0,0,0"
+CHECKSUM: "2970503351 1213720317"
+INSTANCE: tb.dut.u_reg
+ANNOTATION: "VC_COV_UNR"
+Condition 53 "2949805610" "(io_io_meas_ctrl_en_we & io_io_meas_ctrl_en_regwen) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 55 "3453311186" "(io_div2_io_div2_meas_ctrl_en_we & io_div2_io_div2_meas_ctrl_en_regwen) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 57 "3988383834" "(io_div4_io_div4_meas_ctrl_en_we & io_div4_io_div4_meas_ctrl_en_regwen) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 59 "1995093715" "(main_main_meas_ctrl_en_we & main_main_meas_ctrl_en_regwen) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 61 "2462107587" "(usb_usb_meas_ctrl_en_we & usb_usb_meas_ctrl_en_regwen) 1 -1" (1 "01")
+CHECKSUM: "74367784 3785313510"
+INSTANCE: tb.dut.u_reg.u_reg_if
+ANNOTATION: "VC_COV_UNR"
+Condition 18 "3340270436" "(addr_align_err | malformed_meta_err | tl_err | instr_error | intg_error) 1 -1" (5 "01000")
+CHECKSUM: "2928260248 4109606122"
+INSTANCE: tb.dut.u_reg.u_io_meas_ctrl_en_cdc.u_arb
+ANNOTATION: "VC_COV_UNR"
+Condition 5 "593451913" "(((!gen_wr_req.dst_req)) && gen_wr_req.dst_lat_d) 1 -1" (1 "01")
+CHECKSUM: "2928260248 4109606122"
+INSTANCE: tb.dut.u_reg.u_io_div2_meas_ctrl_en_cdc.u_arb
+ANNOTATION: "VC_COV_UNR"
+Condition 5 "593451913" "(((!gen_wr_req.dst_req)) && gen_wr_req.dst_lat_d) 1 -1" (1 "01")
+CHECKSUM: "2928260248 4109606122"
+INSTANCE: tb.dut.u_reg.u_io_div4_meas_ctrl_en_cdc.u_arb
+ANNOTATION: "VC_COV_UNR"
+Condition 5 "593451913" "(((!gen_wr_req.dst_req)) && gen_wr_req.dst_lat_d) 1 -1" (1 "01")
+CHECKSUM: "2928260248 4109606122"
+INSTANCE: tb.dut.u_reg.u_main_meas_ctrl_en_cdc.u_arb
+ANNOTATION: "VC_COV_UNR"
+Condition 5 "593451913" "(((!gen_wr_req.dst_req)) && gen_wr_req.dst_lat_d) 1 -1" (1 "01")
+CHECKSUM: "2928260248 4109606122"
+INSTANCE: tb.dut.u_reg.u_usb_meas_ctrl_en_cdc.u_arb
+ANNOTATION: "VC_COV_UNR"
+Condition 5 "593451913" "(((!gen_wr_req.dst_req)) && gen_wr_req.dst_lat_d) 1 -1" (1 "01")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_reg.u_io_meas_ctrl_en_cdc.u_arb.gen_wr_req.u_dst_update_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_reg.u_io_div2_meas_ctrl_en_cdc.u_arb.gen_wr_req.u_dst_update_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_reg.u_io_div4_meas_ctrl_en_cdc.u_arb.gen_wr_req.u_dst_update_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_reg.u_main_meas_ctrl_en_cdc.u_arb.gen_wr_req.u_dst_update_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_reg.u_usb_meas_ctrl_en_cdc.u_arb.gen_wr_req.u_dst_update_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk.u_ref_timeout
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_meas.u_err_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_div2_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk.u_ref_timeout
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_div2_meas.u_err_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_div4_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk.u_ref_timeout
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_io_div4_meas.u_err_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_main_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk.u_ref_timeout
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_main_meas.u_err_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_usb_meas.u_meas.gen_clk_timeout_chk.u_timeout_ref_to_clk.u_ref_timeout
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
+CHECKSUM: "704952876 1147758610"
+INSTANCE: tb.dut.u_usb_meas.u_err_sync
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (1 "01")
+ANNOTATION: "VC_COV_UNR"
+Condition 2 "700807773" "(dst_req_o & dst_ack_i) 1 -1" (2 "10")
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/doc/tb.svg b/hw/top_earlgrey/ip_autogen/clkmgr/dv/doc/tb.svg
new file mode 100644
index 00000000000000..3f48ecc3accf26
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/doc/tb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_csrs_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_csrs_if.sv
new file mode 100644
index 00000000000000..f82c7e8e824924
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_csrs_if.sv
@@ -0,0 +1,23 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// This interface is used to sample some csr values directly from the rtl
+// to avoid any confusion.
+
+interface clkmgr_csrs_if (
+ input logic clk,
+ input logic [10:0] recov_err_csr,
+ input logic [2:0] fatal_err_csr,
+ input logic [3:0] clk_enables,
+ input logic [3:0] clk_hints
+);
+
+clocking csrs_cb @(posedge clk);
+ input recov_err_csr;
+ input fatal_err_csr;
+ input clk_enables;
+ input clk_hints;
+endclocking
+
+endinterface : clkmgr_csrs_if
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.core
new file mode 100644
index 00000000000000..a53818180557ab
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.core
@@ -0,0 +1,49 @@
+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:dv:clkmgr_env:0.1"
+description: "CLKMGR DV UVM environment"
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:ralgen
+ - lowrisc:dv:cip_lib
+ - lowrisc:ip_interfaces:pwrmgr_pkg
+ - lowrisc:ip_interfaces:clkmgr_pkg
+ files:
+ - clkmgr_csrs_if.sv
+ - clkmgr_env_pkg.sv
+ - clkmgr_env_cfg.sv: {is_include_file: true}
+ - clkmgr_env_cov.sv: {is_include_file: true}
+ - clkmgr_virtual_sequencer.sv: {is_include_file: true}
+ - clkmgr_scoreboard.sv: {is_include_file: true}
+ - clkmgr_env.sv: {is_include_file: true}
+ - seq_lib/clkmgr_vseq_list.sv: {is_include_file: true}
+ - seq_lib/clkmgr_base_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_clk_status_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_common_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_extclk_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_frequency_timeout_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_frequency_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_peri_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_regwen_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_smoke_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_stress_all_vseq.sv: {is_include_file: true}
+ - seq_lib/clkmgr_trans_vseq.sv: {is_include_file: true}
+ - clkmgr_if.sv
+ file_type: systemVerilogSource
+
+generate:
+ ral:
+ generator: ralgen
+ parameters:
+ name: clkmgr
+ ip_hjson: ../../data/clkmgr.hjson
+
+targets:
+ default:
+ filesets:
+ - files_dv
+ generate:
+ - ral
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.sv
new file mode 100644
index 00000000000000..55f805dabff897
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env.sv
@@ -0,0 +1,67 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_env extends cip_base_env #(
+ .CFG_T (clkmgr_env_cfg),
+ .COV_T (clkmgr_env_cov),
+ .VIRTUAL_SEQUENCER_T(clkmgr_virtual_sequencer),
+ .SCOREBOARD_T (clkmgr_scoreboard)
+);
+ `uvm_component_utils(clkmgr_env)
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "main_clk_rst_vif", cfg.main_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get main_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "io_clk_rst_vif", cfg.io_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get io_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "usb_clk_rst_vif", cfg.usb_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get usb_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "aon_clk_rst_vif", cfg.aon_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get aon_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "root_io_clk_rst_vif", cfg.root_io_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get root_io_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "root_main_clk_rst_vif", cfg.root_main_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get root_main_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clk_rst_if)::get(
+ this, "", "root_usb_clk_rst_vif", cfg.root_usb_clk_rst_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get root_usb_clk_rst_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clkmgr_if)::get(this, "", "clkmgr_vif", cfg.clkmgr_vif)) begin
+ `uvm_fatal(`gfn, "failed to get clkmgr_vif from uvm_config_db")
+ end
+ if (!uvm_config_db#(virtual clkmgr_csrs_if)::get(
+ this, "", "clkmgr_csrs_vif", cfg.clkmgr_csrs_vif
+ )) begin
+ `uvm_fatal(`gfn, "failed to get clkmgr_csrs_vif from uvm_config_db")
+ end
+ endfunction
+
+ function void connect_phase(uvm_phase phase);
+ super.connect_phase(phase);
+ endfunction
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv
new file mode 100644
index 00000000000000..ed288757287f15
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cfg.sv
@@ -0,0 +1,45 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_env_cfg extends cip_base_env_cfg #(
+ .RAL_T(clkmgr_reg_block)
+);
+
+ // This scoreboard handle is used to flag expected errors.
+ clkmgr_scoreboard scoreboard;
+
+ // ext component cfgs
+
+ // ext interfaces
+ virtual clkmgr_if clkmgr_vif;
+ virtual clkmgr_csrs_if clkmgr_csrs_vif;
+ virtual clk_rst_if main_clk_rst_vif;
+ virtual clk_rst_if io_clk_rst_vif;
+ virtual clk_rst_if usb_clk_rst_vif;
+ virtual clk_rst_if aon_clk_rst_vif;
+
+ virtual clk_rst_if root_io_clk_rst_vif;
+ virtual clk_rst_if root_main_clk_rst_vif;
+ virtual clk_rst_if root_usb_clk_rst_vif;
+
+ `uvm_object_utils_begin(clkmgr_env_cfg)
+ `uvm_object_utils_end
+
+ `uvm_object_new
+
+ virtual function void initialize(bit [31:0] csr_base_addr = '1);
+ list_of_alerts = clkmgr_env_pkg::LIST_OF_ALERTS;
+ super.initialize(csr_base_addr);
+
+ // This is for the integrity error test.
+ tl_intg_alert_name = "fatal_fault";
+ tl_intg_alert_fields[ral.fatal_err_code.reg_intg] = 1;
+ m_tl_agent_cfg.max_outstanding_req = 1;
+
+ // shadow registers
+ shadow_update_err_status_fields[ral.recov_err_code.shadow_update_err] = 1;
+ shadow_storage_err_status_fields[ral.fatal_err_code.shadow_storage_err] = 1;
+ endfunction
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cov.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cov.sv
new file mode 100644
index 00000000000000..1742c6ceb61f09
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_cov.sv
@@ -0,0 +1,190 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Covergoups that are dependent on run-time parameters that may be available
+ * only in build_phase can be defined here
+ * Covergroups may also be wrapped inside helper classes if needed.
+ */
+
+// Wrapper class for peripheral clock covergroup.
+class clkmgr_peri_cg_wrap;
+ // This covergroup collects signals affecting peripheral clock.
+ covergroup peri_cg(string name) with function sample (bit enable, bit ip_clk_en, bit scanmode);
+ option.name = name;
+ option.per_instance = 1;
+
+ csr_enable_cp: coverpoint enable;
+ ip_clk_en_cp: coverpoint ip_clk_en;
+ scanmode_cp: coverpoint scanmode;
+
+ peri_cross: cross csr_enable_cp, ip_clk_en_cp, scanmode_cp{
+ // The enable CSRs cannot be manipulated in low power mode.
+ ignore_bins ignore_enable_off = peri_cross with (csr_enable_cp == 1 && ip_clk_en_cp == 0);
+ }
+ endgroup
+
+ function new(string name);
+ peri_cg = new(name);
+ endfunction
+
+ function void sample (bit enable, bit ip_clk_en, bit scanmode);
+ peri_cg.sample(enable, ip_clk_en, scanmode);
+ endfunction
+endclass
+
+// Wrapper class for transactional unit clock covergroup.
+class clkmgr_trans_cg_wrap;
+ // This covergroup collects signals affecting transactional clock.
+ covergroup trans_cg(
+ string name
+ ) with function sample (
+ bit hint, bit ip_clk_en, bit scanmode, bit idle
+ );
+ option.name = name;
+ option.per_instance = 1;
+
+ csr_hint_cp: coverpoint hint;
+ ip_clk_en_cp: coverpoint ip_clk_en;
+ scanmode_cp: coverpoint scanmode;
+ idle_cp: coverpoint idle;
+
+ trans_cross: cross csr_hint_cp, ip_clk_en_cp, scanmode_cp, idle_cp{
+ // If the clock is disabled the unit must be idle.
+ ignore_bins ignore_idle_off = trans_cross with (idle_cp == 0 && ip_clk_en_cp == 0);
+ // The hint CSRs cannot be manipulated in low power mode.
+ ignore_bins ignore_enable_off = trans_cross with (csr_hint_cp == 1 && ip_clk_en_cp == 0);
+ }
+ endgroup
+
+ function new(string name);
+ trans_cg = new(name);
+ endfunction
+
+ function void sample (bit hint, bit ip_clk_en, bit scanmode, bit idle);
+ trans_cg.sample(hint, ip_clk_en, scanmode, idle);
+ endfunction
+endclass
+
+// Wrapper class for frequency measurement covergroup.
+class freq_measure_cg_wrap;
+ // This covergroup collects outcomes of clock frequency measurements.
+ covergroup freq_measure_cg(
+ string name
+ ) with function sample (
+ bit okay, bit slow, bit fast, bit timeout
+ );
+ option.name = name;
+ option.per_instance = 1;
+
+ okay_cp: coverpoint okay;
+ slow_cp: coverpoint slow;
+ fast_cp: coverpoint fast;
+ timeout_cp: coverpoint timeout;
+ endgroup
+
+ function new(string name);
+ freq_measure_cg = new(name);
+ endfunction
+
+ function void sample (bit okay, bit slow, bit fast, bit timeout);
+ freq_measure_cg.sample(okay, slow, fast, timeout);
+ endfunction
+endclass
+
+class clkmgr_env_cov extends cip_base_env_cov #(
+ .CFG_T(clkmgr_env_cfg)
+);
+ `uvm_component_utils(clkmgr_env_cov)
+
+ // the base class provides the following handles for use:
+ // clkmgr_env_cfg: cfg
+
+ // These covergroups collect signals affecting peripheral clocks.
+ clkmgr_peri_cg_wrap peri_cg_wrap[NUM_PERI];
+
+ // These covergroups collect signals affecting transactional clocks.
+ clkmgr_trans_cg_wrap trans_cg_wrap[NUM_TRANS];
+
+ // These covergroups collect outcomes of clock frequency measurements.
+ freq_measure_cg_wrap freq_measure_cg_wrap[5];
+
+ // This embeded covergroup collects coverage for the external clock functionality.
+ covergroup extclk_cg with function sample (
+ bit csr_sel, bit csr_low_speed, bit hw_debug_en, bit byp_req, bit scanmode
+ );
+ csr_sel_cp: coverpoint csr_sel;
+ csr_low_speed_cp: coverpoint csr_low_speed;
+ hw_debug_en_cp: coverpoint hw_debug_en;
+ byp_req_cp: coverpoint byp_req;
+ scanmode_cp: coverpoint scanmode;
+
+ extclk_cross: cross csr_sel_cp, csr_low_speed_cp, hw_debug_en_cp, byp_req_cp, scanmode_cp;
+ endgroup
+
+ // This collects coverage for recoverable errors.
+ covergroup recov_err_cg with function sample (
+ bit usb_timeout,
+ bit main_timeout,
+ bit io_div4_timeout,
+ bit io_div2_timeout,
+ bit io_timeout,
+ bit usb_measure,
+ bit main_measure,
+ bit io_div4_measure,
+ bit io_div2_measure,
+ bit io_measure,
+ bit shadow_update
+ );
+ shadow_update_cp: coverpoint shadow_update;
+ io_measure_cp: coverpoint io_measure;
+ io_div2_measure_cp: coverpoint io_div2_measure;
+ io_div4_measure_cp: coverpoint io_div4_measure;
+ main_measure_cp: coverpoint main_measure;
+ usb_measure_cp: coverpoint usb_measure;
+ io_timeout_cp: coverpoint io_timeout;
+ io_div2_timeout_cp: coverpoint io_div2_timeout;
+ io_div4_timeout_cp: coverpoint io_div4_timeout;
+ main_timeout_cp: coverpoint main_timeout;
+ usb_timeout_cp: coverpoint usb_timeout;
+ endgroup
+
+ // This collects coverage for fatal errors.
+ covergroup fatal_err_cg with function sample (
+ bit shadow_storage, bit idle_cnt, bit reg_integ
+ );
+ reg_integ_cp: coverpoint reg_integ;
+ idle_cnt_cp: coverpoint idle_cnt;
+ shadow_storage_cp: coverpoint shadow_storage;
+ endgroup
+
+ function new(string name, uvm_component parent);
+ super.new(name, parent);
+ // The peripheral covergoups.
+ foreach (peri_cg_wrap[i]) begin
+ clkmgr_env_pkg::peri_e peri = clkmgr_env_pkg::peri_e'(i);
+ peri_cg_wrap[i] = new(peri.name);
+ end
+ // The transactional covergroups.
+ foreach (trans_cg_wrap[i]) begin
+ clkmgr_env_pkg::trans_e trans = clkmgr_env_pkg::trans_e'(i);
+ trans_cg_wrap[i] = new(trans.name);
+ end
+ foreach (ExpectedCounts[i]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(i);
+ freq_measure_cg_wrap[i] = new(clk_mesr.name);
+ end
+ extclk_cg = new();
+ recov_err_cg = new();
+ fatal_err_cg = new();
+ endfunction : new
+
+ virtual function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+ // [or instantiate covergroups here]
+ // Please instantiate sticky_intr_cov array of objects for all interrupts that are sticky
+ // See cip_base_env_cov for details
+ endfunction
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_pkg.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_pkg.sv
new file mode 100644
index 00000000000000..c926017150b7ec
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_env_pkg.sv
@@ -0,0 +1,151 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package clkmgr_env_pkg;
+ // dep packages
+ import uvm_pkg::*;
+ import sec_cm_pkg::*;
+ import top_pkg::*;
+ import dv_utils_pkg::*;
+ import dv_lib_pkg::*;
+ import tl_agent_pkg::*;
+ import cip_base_pkg::*;
+ import dv_base_reg_pkg::*;
+ import csr_utils_pkg::*;
+ import clkmgr_ral_pkg::*;
+ import prim_mubi_pkg::mubi4_t;
+ import prim_mubi_pkg::MuBi4False;
+ import prim_mubi_pkg::MuBi4True;
+
+ import lc_ctrl_pkg::lc_tx_t;
+ import lc_ctrl_pkg::On;
+ import lc_ctrl_pkg::Off;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ typedef virtual clkmgr_if clkmgr_vif;
+ typedef virtual clk_rst_if clk_rst_vif;
+
+ // parameters
+ parameter int NUM_PERI = 4;
+ parameter int NUM_TRANS = 4;
+
+ typedef logic [NUM_PERI-1:0] peri_enables_t;
+ typedef logic [NUM_TRANS-1:0] hintables_t;
+ typedef mubi4_t [NUM_TRANS-1:0] mubi_hintables_t;
+ parameter mubi_hintables_t IdleAllBusy = {NUM_TRANS{prim_mubi_pkg::MuBi4False}};
+
+ parameter int MainClkHz = 100_000_000;
+ parameter int IoClkHz = 96_000_000;
+ parameter int UsbClkHz = 48_000_000;
+ parameter int AonClkHz = 200_000;
+ parameter int FakeAonClkHz = 7_000_000;
+
+ // alerts
+ parameter uint NUM_ALERTS = 2;
+ parameter string LIST_OF_ALERTS[] = {"recov_fault", "fatal_fault"};
+
+ // types
+
+ // Forward class decl to enable cfg to hold a scoreboard handle.
+ typedef class clkmgr_scoreboard;
+
+ // The enum values for these match the bit order in the CSRs.
+ typedef enum int {
+ PeriDiv4,
+ PeriDiv2,
+ PeriUsb,
+ PeriIo
+ } peri_e;
+ typedef struct packed {
+ logic usb_peri_en;
+ logic io_peri_en;
+ logic io_div2_peri_en;
+ logic io_div4_peri_en;
+ } clk_enables_t;
+
+ typedef enum int {
+ TransAes,
+ TransHmac,
+ TransKmac,
+ TransOtbn
+ } trans_e;
+ typedef struct packed {
+ logic otbn_main;
+ logic kmac;
+ logic hmac;
+ logic aes;
+ } clk_hints_t;
+
+ typedef struct {
+ logic valid;
+ logic slow;
+ logic fast;
+ } freq_measurement_t;
+
+ // These are ordered per the bits in the recov_err_code register.
+ typedef enum int {
+ ClkMesrIo,
+ ClkMesrIoDiv2,
+ ClkMesrIoDiv4,
+ ClkMesrMain,
+ ClkMesrUsb
+ } clk_mesr_e;
+
+ // Mubi test mode
+ typedef enum int {
+ ClkmgrMubiNone = 0,
+ ClkmgrMubiIdle = 1,
+ ClkmgrMubiLcCtrl = 2,
+ ClkmgrMubiLcHand = 3,
+ ClkmgrMubiHand = 4,
+ ClkmgrMubiDiv = 5
+ } clkmgr_mubi_e;
+
+ // This is to examine separately the measurement and timeout recoverable error bits.
+ typedef logic [ClkMesrUsb:0] recov_bits_t;
+
+ typedef struct packed {
+ recov_bits_t timeouts;
+ recov_bits_t measures;
+ logic shadow_update;
+ } clkmgr_recov_err_t;
+
+ // These must be after the declaration of clk_mesr_e for sizing.
+ parameter int ClkInHz[ClkMesrUsb+1] = {IoClkHz, IoClkHz / 2, IoClkHz / 4, MainClkHz, UsbClkHz};
+
+ parameter int ExpectedCounts[ClkMesrUsb+1] = {
+ ClkInHz[ClkMesrIo] / AonClkHz - 1,
+ ClkInHz[ClkMesrIoDiv2] / AonClkHz - 1,
+ ClkInHz[ClkMesrIoDiv4] / AonClkHz - 1,
+ ClkInHz[ClkMesrMain] / AonClkHz - 1,
+ ClkInHz[ClkMesrUsb] / AonClkHz - 1
+ };
+
+ // functions
+ function automatic void print_hintable(hintables_t tbl);
+ foreach (tbl[i]) begin
+ `uvm_info("HINTBL", $sformatf("entry%0d : %b", i, tbl[i]), UVM_LOW)
+ end
+ endfunction : print_hintable
+
+ function automatic void print_mubi_hintable(mubi_hintables_t tbl);
+ string val = "INVALID";
+ foreach (tbl[i]) begin
+ if (tbl[i].name != "") val = tbl[i].name;
+ `uvm_info("MUBIHINTBL", $sformatf("entry%0d : %s", i, val), UVM_LOW)
+ end
+ endfunction : print_mubi_hintable
+
+ // package sources
+ `include "clkmgr_env_cfg.sv"
+ `include "clkmgr_env_cov.sv"
+ `include "clkmgr_virtual_sequencer.sv"
+ `include "clkmgr_scoreboard.sv"
+ `include "clkmgr_env.sv"
+ `include "clkmgr_vseq_list.sv"
+
+endpackage
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_if.sv
new file mode 100644
index 00000000000000..6fb76023480ec9
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_if.sv
@@ -0,0 +1,362 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// clkmgr interface.
+
+interface clkmgr_if (
+ input logic clk,
+ input logic rst_n,
+ input logic clk_main,
+ input logic rst_io_n,
+ input logic rst_main_n,
+ input logic rst_usb_n
+);
+ import uvm_pkg::*;
+ import clkmgr_env_pkg::*;
+
+ // The ports to the dut side.
+
+ localparam int LcTxTWidth = $bits(lc_ctrl_pkg::lc_tx_t);
+
+ // Encodes the transactional units that are idle.
+ mubi_hintables_t idle_i;
+
+ // pwrmgr req contains ip_clk_en, set to enable the gated clocks.
+ pwrmgr_pkg::pwr_clk_req_t pwr_i;
+
+ // outputs clk_status: transitions to 1 if all clocks are enabled, and
+ // to 0 when all are disabled.
+ pwrmgr_pkg::pwr_clk_rsp_t pwr_o;
+
+ // scanmode_i == MuBi4True defeats all clock gating.
+ prim_mubi_pkg::mubi4_t scanmode_i;
+
+ // Life cycle enables clock bypass functionality.
+ lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i;
+
+ // Life cycle clock bypass request and clkmgr ack.
+ lc_ctrl_pkg::lc_tx_t lc_clk_byp_req;
+ lc_ctrl_pkg::lc_tx_t lc_clk_byp_ack;
+ // clkmgr clock bypass request for io clocks and ast ack: triggered by lc_clk_byp_req.
+ prim_mubi_pkg::mubi4_t io_clk_byp_req;
+ prim_mubi_pkg::mubi4_t io_clk_byp_ack;
+ // clkmgr clock bypass request for all clocks and ast ack: triggered by software.
+ prim_mubi_pkg::mubi4_t all_clk_byp_req;
+ prim_mubi_pkg::mubi4_t all_clk_byp_ack;
+
+ prim_mubi_pkg::mubi4_t div_step_down_req;
+
+ prim_mubi_pkg::mubi4_t jitter_en_o;
+ clkmgr_pkg::clkmgr_out_t clocks_o;
+
+ prim_mubi_pkg::mubi4_t calib_rdy;
+ prim_mubi_pkg::mubi4_t hi_speed_sel;
+
+ // Internal DUT signals.
+ // ICEBOX(lowrisc/opentitan#18379): This is a core env component (i.e. reusable entity) that
+ // makes hierarchical references into the DUT. A better strategy would be to bind this interface
+ // to the DUT in tb.sv and use relative paths instead.
+`ifndef CLKMGR_HIER
+ `define CLKMGR_HIER tb.dut
+`endif
+
+ // The CSR values from the testbench side.
+ clk_enables_t clk_enables_csr;
+ always_comb
+ clk_enables_csr = '{
+ usb_peri_en: `CLKMGR_HIER.reg2hw.clk_enables.clk_usb_peri_en.q,
+ io_peri_en: `CLKMGR_HIER.reg2hw.clk_enables.clk_io_peri_en.q,
+ io_div2_peri_en: `CLKMGR_HIER.reg2hw.clk_enables.clk_io_div2_peri_en.q,
+ io_div4_peri_en: `CLKMGR_HIER.reg2hw.clk_enables.clk_io_div4_peri_en.q
+ };
+
+ clk_hints_t clk_hints_csr;
+ always_comb
+ clk_hints_csr = '{
+ otbn_main: `CLKMGR_HIER.reg2hw.clk_hints.clk_main_otbn_hint.q,
+ kmac: `CLKMGR_HIER.reg2hw.clk_hints.clk_main_kmac_hint.q,
+ hmac: `CLKMGR_HIER.reg2hw.clk_hints.clk_main_hmac_hint.q,
+ aes: `CLKMGR_HIER.reg2hw.clk_hints.clk_main_aes_hint.q
+ };
+
+ clk_hints_t clk_hints_status_csr;
+ always_comb
+ clk_hints_status_csr = '{
+ otbn_main: `CLKMGR_HIER.u_reg.clk_hints_status_clk_main_otbn_val_qs,
+ kmac: `CLKMGR_HIER.u_reg.clk_hints_status_clk_main_kmac_val_qs,
+ hmac: `CLKMGR_HIER.u_reg.clk_hints_status_clk_main_hmac_val_qs,
+ aes: `CLKMGR_HIER.u_reg.clk_hints_status_clk_main_aes_val_qs
+ };
+
+ prim_mubi_pkg::mubi4_t extclk_ctrl_csr_sel;
+ always_comb begin
+ extclk_ctrl_csr_sel = prim_mubi_pkg::mubi4_t'(`CLKMGR_HIER.reg2hw.extclk_ctrl.sel.q);
+ end
+
+ prim_mubi_pkg::mubi4_t extclk_ctrl_csr_step_down;
+ always_comb begin
+ extclk_ctrl_csr_step_down = prim_mubi_pkg::mubi4_t'(
+ `CLKMGR_HIER.reg2hw.extclk_ctrl.hi_speed_sel.q);
+ end
+
+ prim_mubi_pkg::mubi4_t jitter_enable_csr;
+ always_comb begin
+ jitter_enable_csr = prim_mubi_pkg::mubi4_t'(`CLKMGR_HIER.reg2hw.jitter_enable.q);
+ end
+
+ freq_measurement_t io_freq_measurement;
+ logic io_timeout_err;
+ always @(posedge `CLKMGR_HIER.u_io_meas.u_meas.clk_i) begin
+ if (`CLKMGR_HIER.u_io_meas.u_meas.valid_o) begin
+ io_freq_measurement = '{valid: `CLKMGR_HIER.u_io_meas.u_meas.valid_o,
+ slow: `CLKMGR_HIER.u_io_meas.u_meas.slow_o,
+ fast: `CLKMGR_HIER.u_io_meas.u_meas.fast_o};
+ `uvm_info("clkmgr_if", $sformatf("Sampled coverage for ClkMesrIo as %p", io_freq_measurement),
+ UVM_HIGH)
+ end
+ end
+ always_comb io_timeout_err = `CLKMGR_HIER.u_io_meas.timeout_err_o;
+
+ freq_measurement_t io_div2_freq_measurement;
+ logic io_div2_timeout_err;
+ always @(posedge `CLKMGR_HIER.u_io_div2_meas.u_meas.clk_i) begin
+ if (`CLKMGR_HIER.u_io_div2_meas.u_meas.valid_o) begin
+ io_div2_freq_measurement = '{valid: `CLKMGR_HIER.u_io_div2_meas.u_meas.valid_o,
+ slow: `CLKMGR_HIER.u_io_div2_meas.u_meas.slow_o,
+ fast: `CLKMGR_HIER.u_io_div2_meas.u_meas.fast_o};
+ `uvm_info("clkmgr_if", $sformatf(
+ "Sampled coverage for ClkMesrIoDiv2 as %p", io_div2_freq_measurement), UVM_HIGH)
+ end
+ end
+ always_comb io_div2_timeout_err = `CLKMGR_HIER.u_io_div2_meas.timeout_err_o;
+
+ freq_measurement_t io_div4_freq_measurement;
+ logic io_div4_timeout_err;
+ always @(posedge `CLKMGR_HIER.u_io_div4_meas.u_meas.clk_i) begin
+ if (`CLKMGR_HIER.u_io_div4_meas.u_meas.valid_o) begin
+ io_div4_freq_measurement = '{valid: `CLKMGR_HIER.u_io_div4_meas.u_meas.valid_o,
+ slow: `CLKMGR_HIER.u_io_div4_meas.u_meas.slow_o,
+ fast: `CLKMGR_HIER.u_io_div4_meas.u_meas.fast_o};
+ `uvm_info("clkmgr_if", $sformatf(
+ "Sampled coverage for ClkMesrIoDiv4 as %p", io_div4_freq_measurement), UVM_HIGH)
+ end
+ end
+ always_comb io_div4_timeout_err = `CLKMGR_HIER.u_io_div4_meas.timeout_err_o;
+
+ freq_measurement_t main_freq_measurement;
+ logic main_timeout_err;
+ always @(posedge `CLKMGR_HIER.u_main_meas.u_meas.clk_i) begin
+ if (`CLKMGR_HIER.u_main_meas.u_meas.valid_o) begin
+ main_freq_measurement = '{valid: `CLKMGR_HIER.u_main_meas.u_meas.valid_o,
+ slow: `CLKMGR_HIER.u_main_meas.u_meas.slow_o,
+ fast: `CLKMGR_HIER.u_main_meas.u_meas.fast_o};
+ `uvm_info("clkmgr_if", $sformatf(
+ "Sampled coverage for ClkMesrMain as %p", main_freq_measurement), UVM_HIGH)
+ end
+ end
+ always_comb main_timeout_err = `CLKMGR_HIER.u_main_meas.timeout_err_o;
+
+ freq_measurement_t usb_freq_measurement;
+ logic usb_timeout_err;
+ always @(posedge `CLKMGR_HIER.u_usb_meas.u_meas.clk_i) begin
+ if (`CLKMGR_HIER.u_usb_meas.u_meas.valid_o) begin
+ usb_freq_measurement = '{valid: `CLKMGR_HIER.u_usb_meas.u_meas.valid_o,
+ slow: `CLKMGR_HIER.u_usb_meas.u_meas.slow_o,
+ fast: `CLKMGR_HIER.u_usb_meas.u_meas.fast_o};
+ `uvm_info("clkmgr_if", $sformatf("Sampled coverage for ClkMesrUsb as %p", usb_freq_measurement
+ ), UVM_HIGH)
+ end
+ end
+ always_comb usb_timeout_err = `CLKMGR_HIER.u_usb_meas.timeout_err_o;
+
+ function automatic void update_calib_rdy(prim_mubi_pkg::mubi4_t value);
+ calib_rdy = value;
+ endfunction
+
+ function automatic void update_idle(mubi_hintables_t value);
+ idle_i = value;
+ endfunction
+
+ function automatic void update_io_ip_clk_en(bit value);
+ pwr_i.io_ip_clk_en = value;
+ endfunction
+
+ function automatic void update_main_ip_clk_en(bit value);
+ pwr_i.main_ip_clk_en = value;
+ endfunction
+
+ function automatic void update_usb_ip_clk_en(bit value);
+ pwr_i.usb_ip_clk_en = value;
+ endfunction
+
+ function automatic void update_scanmode(prim_mubi_pkg::mubi4_t value);
+ scanmode_i = value;
+ endfunction
+
+ function automatic void update_lc_debug_en(lc_ctrl_pkg::lc_tx_t value);
+ lc_hw_debug_en_i = value;
+ endfunction
+
+ function automatic void update_lc_clk_byp_req(lc_ctrl_pkg::lc_tx_t value);
+ lc_clk_byp_req = value;
+ endfunction
+
+ function automatic void update_all_clk_byp_ack(prim_mubi_pkg::mubi4_t value);
+ `uvm_info("clkmgr_if", $sformatf("In clkmgr_if update_all_clk_byp_ack with %b", value),
+ UVM_MEDIUM)
+ all_clk_byp_ack = value;
+ endfunction
+
+ function automatic void update_div_step_down_req(prim_mubi_pkg::mubi4_t value);
+ `uvm_info("clkmgr_if", $sformatf("In clkmgr_if update_div_step_down_req with %b", value),
+ UVM_MEDIUM)
+ div_step_down_req = value;
+ endfunction
+
+ function automatic void update_io_clk_byp_ack(prim_mubi_pkg::mubi4_t value);
+ io_clk_byp_ack = value;
+ endfunction
+
+ function automatic void force_high_starting_count(clk_mesr_e clk);
+ `uvm_info("clkmgr_if", $sformatf("Forcing count of %0s to all 1.", clk.name()), UVM_MEDIUM)
+ case (clk)
+ ClkMesrIo: `CLKMGR_HIER.u_io_meas.u_meas.cnt = '1;
+ ClkMesrIoDiv2: `CLKMGR_HIER.u_io_div2_meas.u_meas.cnt = '1;
+ ClkMesrIoDiv4: `CLKMGR_HIER.u_io_div4_meas.u_meas.cnt = '1;
+ ClkMesrMain: `CLKMGR_HIER.u_main_meas.u_meas.cnt = '1;
+ ClkMesrUsb: `CLKMGR_HIER.u_usb_meas.u_meas.cnt = '1;
+ default: ;
+ endcase
+ endfunction
+
+ task automatic init(mubi_hintables_t idle, prim_mubi_pkg::mubi4_t scanmode,
+ lc_ctrl_pkg::lc_tx_t lc_debug_en = lc_ctrl_pkg::Off,
+ lc_ctrl_pkg::lc_tx_t lc_clk_byp_req = lc_ctrl_pkg::Off,
+ prim_mubi_pkg::mubi4_t calib_rdy = prim_mubi_pkg::MuBi4True);
+ `uvm_info("clkmgr_if", "In clkmgr_if init", UVM_MEDIUM)
+ update_calib_rdy(calib_rdy);
+ update_idle(idle);
+ update_lc_clk_byp_req(lc_clk_byp_req);
+ update_lc_debug_en(lc_debug_en);
+ update_scanmode(scanmode);
+ endtask
+
+ // Pipeline signals that go through synchronizers with the target clock domain's clock.
+ // thus the PIPELINE_DEPTH is 2.
+
+ // Use clocking blocks clocked by the target clock domain's clock to transfer relevant
+ // control signals back to the scoreboard.
+ localparam int PIPELINE_DEPTH = 2;
+
+ // Pipelines and clocking blocks for peripheral clocks.
+
+ logic [PIPELINE_DEPTH-1:0] clk_enable_div4_ffs;
+ logic [PIPELINE_DEPTH-1:0] ip_clk_en_div4_ffs;
+ always @(posedge clocks_o.clk_io_div4_powerup or negedge rst_io_n) begin
+ if (rst_io_n) begin
+ clk_enable_div4_ffs <= {
+ clk_enable_div4_ffs[PIPELINE_DEPTH-2:0], clk_enables_csr.io_div4_peri_en
+ };
+ ip_clk_en_div4_ffs <= {ip_clk_en_div4_ffs[PIPELINE_DEPTH-2:0], pwr_i.io_ip_clk_en};
+ end else begin
+ clk_enable_div4_ffs <= '0;
+ ip_clk_en_div4_ffs <= '0;
+ end
+ end
+ clocking peri_div4_cb @(posedge clocks_o.clk_io_div4_powerup or negedge rst_io_n);
+ input ip_clk_en = ip_clk_en_div4_ffs[PIPELINE_DEPTH-1];
+ input clk_enable = clk_enable_div4_ffs[PIPELINE_DEPTH-1];
+ endclocking
+
+ logic [PIPELINE_DEPTH-1:0] clk_enable_div2_ffs;
+ logic [PIPELINE_DEPTH-1:0] ip_clk_en_div2_ffs;
+ always @(posedge clocks_o.clk_io_div2_powerup or negedge rst_io_n) begin
+ if (rst_io_n) begin
+ clk_enable_div2_ffs <= {
+ clk_enable_div2_ffs[PIPELINE_DEPTH-2:0], clk_enables_csr.io_div2_peri_en
+ };
+ ip_clk_en_div2_ffs <= {ip_clk_en_div2_ffs[PIPELINE_DEPTH-2:0], pwr_i.io_ip_clk_en};
+ end else begin
+ clk_enable_div2_ffs <= '0;
+ ip_clk_en_div2_ffs <= '0;
+ end
+ end
+ clocking peri_div2_cb @(posedge clocks_o.clk_io_div2_powerup or negedge rst_io_n);
+ input ip_clk_en = ip_clk_en_div2_ffs[PIPELINE_DEPTH-1];
+ input clk_enable = clk_enable_div2_ffs[PIPELINE_DEPTH-1];
+ endclocking
+
+ logic [PIPELINE_DEPTH-1:0] clk_enable_io_ffs;
+ logic [PIPELINE_DEPTH-1:0] ip_clk_en_io_ffs;
+ always @(posedge clocks_o.clk_io_powerup or negedge rst_io_n) begin
+ if (rst_io_n) begin
+ clk_enable_io_ffs <= {clk_enable_io_ffs[PIPELINE_DEPTH-2:0], clk_enables_csr.io_peri_en};
+ ip_clk_en_io_ffs <= {ip_clk_en_io_ffs[PIPELINE_DEPTH-2:0], pwr_i.io_ip_clk_en};
+ end else begin
+ clk_enable_io_ffs <= '0;
+ ip_clk_en_io_ffs <= '0;
+ end
+ end
+ clocking peri_io_cb @(posedge clocks_o.clk_io_powerup or negedge rst_io_n);
+ input ip_clk_en = ip_clk_en_io_ffs[PIPELINE_DEPTH-1];
+ input clk_enable = clk_enable_io_ffs[PIPELINE_DEPTH-1];
+ endclocking
+
+ logic [PIPELINE_DEPTH-1:0] clk_enable_usb_ffs;
+ logic [PIPELINE_DEPTH-1:0] ip_clk_en_usb_ffs;
+ always @(posedge clocks_o.clk_usb_powerup or negedge rst_usb_n) begin
+ if (rst_usb_n) begin
+ clk_enable_usb_ffs <= {clk_enable_usb_ffs[PIPELINE_DEPTH-2:0], clk_enables_csr.usb_peri_en};
+ ip_clk_en_usb_ffs <= {ip_clk_en_usb_ffs[PIPELINE_DEPTH-2:0], pwr_i.usb_ip_clk_en};
+ end else begin
+ clk_enable_usb_ffs <= '0;
+ ip_clk_en_usb_ffs <= '0;
+ end
+ end
+ clocking peri_usb_cb @(posedge clocks_o.clk_usb_powerup or negedge rst_usb_n);
+ input ip_clk_en = ip_clk_en_usb_ffs[PIPELINE_DEPTH-1];
+ input clk_enable = clk_enable_usb_ffs[PIPELINE_DEPTH-1];
+ endclocking
+
+ // Pipelining and clocking block for transactional unit clocks.
+ logic [PIPELINE_DEPTH-1:0][NUM_TRANS-1:0] clk_hints_ffs;
+ logic [PIPELINE_DEPTH-1:0] trans_clk_en_ffs;
+ always @(posedge clocks_o.clk_main_powerup or negedge rst_main_n) begin
+ if (rst_main_n) begin
+ clk_hints_ffs <= {clk_hints_ffs[PIPELINE_DEPTH-2:0], clk_hints_csr};
+ trans_clk_en_ffs <= {trans_clk_en_ffs[PIPELINE_DEPTH-2:0], pwr_i.main_ip_clk_en};
+ end else begin
+ clk_hints_ffs <= '0;
+ trans_clk_en_ffs <= '0;
+ end
+ end
+ clocking trans_cb @(posedge clocks_o.clk_main_powerup or negedge rst_main_n);
+ input ip_clk_en = trans_clk_en_ffs[PIPELINE_DEPTH-1];
+ input clk_hints = clk_hints_ffs[PIPELINE_DEPTH-1];
+ input idle_i;
+ endclocking
+
+ // Pipelining and clocking block for external clock bypass. The divisor control is
+ // triggered by an ast ack, which goes through synchronizers.
+ logic step_down_ff;
+ always @(posedge clk) begin
+ if (rst_n) begin
+ step_down_ff <= io_clk_byp_ack == prim_mubi_pkg::MuBi4True;
+ end else begin
+ step_down_ff <= 1'b0;
+ end
+ end
+
+ clocking clk_cb @(posedge clk);
+ input calib_rdy;
+ input extclk_ctrl_csr_sel;
+ input extclk_ctrl_csr_step_down;
+ input lc_hw_debug_en_i;
+ input io_clk_byp_req;
+ input lc_clk_byp_req;
+ input step_down = step_down_ff;
+ input jitter_enable_csr;
+ endclocking
+
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_scoreboard.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_scoreboard.sv
new file mode 100644
index 00000000000000..6bfdab3f41d632
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_scoreboard.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
+
+// The scoreboard checks the jitter_an_o output, and processes CSR checks.
+// It also samples most functional coverage groups.
+class clkmgr_scoreboard extends cip_base_scoreboard #(
+ .CFG_T(clkmgr_env_cfg),
+ .RAL_T(clkmgr_reg_block),
+ .COV_T(clkmgr_env_cov)
+);
+ `uvm_component_utils(clkmgr_scoreboard)
+
+ // local variables
+ logic extclk_ctrl_regwen;
+ logic measure_ctrl_regwen;
+
+ // TLM agent fifos
+
+ // local queues to hold incoming packets pending comparison
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+ endfunction
+
+ function void connect_phase(uvm_phase phase);
+ super.connect_phase(phase);
+ cfg.scoreboard = this;
+ endfunction
+
+ task run_phase(uvm_phase phase);
+ super.run_phase(phase);
+ fork
+ monitor_all_clk_byp();
+ monitor_io_clk_byp();
+ monitor_jitter_en();
+ sample_peri_covs();
+ sample_trans_covs();
+ sample_freq_measurement_covs();
+ sample_fatal_err_cov();
+ sample_recov_err_cov();
+ join_none
+ endtask
+
+ task monitor_all_clk_byp();
+ mubi4_t prev_all_clk_byp_req = MuBi4False;
+ forever
+ @cfg.clkmgr_vif.clk_cb begin
+ if (cfg.clkmgr_vif.all_clk_byp_req != prev_all_clk_byp_req) begin
+ `uvm_info(`gfn, $sformatf(
+ "Got all_clk_byp_req %s",
+ cfg.clkmgr_vif.all_clk_byp_req == MuBi4True ? "True" : "False"
+ ), UVM_MEDIUM)
+ prev_all_clk_byp_req = cfg.clkmgr_vif.all_clk_byp_req;
+ end
+ if (cfg.clk_rst_vif.rst_n) begin
+ if (cfg.en_cov) begin
+ cov.extclk_cg.sample(cfg.clkmgr_vif.clk_cb.extclk_ctrl_csr_sel == MuBi4True,
+ cfg.clkmgr_vif.clk_cb.extclk_ctrl_csr_step_down == MuBi4True,
+ cfg.clkmgr_vif.clk_cb.lc_hw_debug_en_i == On,
+ cfg.clkmgr_vif.clk_cb.lc_clk_byp_req == On,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ end
+ endtask
+
+ task monitor_io_clk_byp();
+ lc_tx_t prev_lc_clk_byp_req = Off;
+ forever
+ @cfg.clkmgr_vif.clk_cb begin
+ if (cfg.clkmgr_vif.lc_clk_byp_req != prev_lc_clk_byp_req) begin
+ `uvm_info(`gfn, $sformatf(
+ "Got lc_clk_byp_req %s", cfg.clkmgr_vif.lc_clk_byp_req == On ? "On" : "Off"),
+ UVM_MEDIUM)
+ prev_lc_clk_byp_req = cfg.clkmgr_vif.lc_clk_byp_req;
+ end
+ if (cfg.clk_rst_vif.rst_n) begin
+ if (cfg.en_cov) begin
+ cov.extclk_cg.sample(cfg.clkmgr_vif.clk_cb.extclk_ctrl_csr_sel == MuBi4True,
+ cfg.clkmgr_vif.clk_cb.extclk_ctrl_csr_step_down == MuBi4True,
+ cfg.clkmgr_vif.clk_cb.lc_hw_debug_en_i == On,
+ cfg.clkmgr_vif.clk_cb.lc_clk_byp_req == On,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ end
+ endtask
+
+ task monitor_jitter_en();
+ fork
+ forever
+ @cfg.clkmgr_vif.clk_cb begin
+ if (cfg.clk_rst_vif.rst_n) begin
+ @cfg.clkmgr_vif.jitter_enable_csr begin
+ cfg.clk_rst_vif.wait_clks(2);
+ `DV_CHECK_EQ(cfg.clkmgr_vif.jitter_en_o, cfg.clkmgr_vif.jitter_enable_csr,
+ "Mismatching jitter enable output")
+ end
+ end
+ end
+ forever
+ @cfg.clkmgr_vif.clk_cb begin
+ if (cfg.clk_rst_vif.rst_n) begin
+ @cfg.clkmgr_vif.jitter_en_o begin
+ cfg.clk_rst_vif.wait_clks(2);
+ `DV_CHECK_EQ(cfg.clkmgr_vif.jitter_en_o, cfg.clkmgr_vif.jitter_enable_csr,
+ "Mismatching jitter enable output")
+ end
+ end
+ end
+ join
+ endtask
+
+ task sample_peri_covs();
+ fork
+ forever
+ @cfg.clkmgr_vif.peri_io_cb begin
+ if (cfg.io_clk_rst_vif.rst_n && cfg.en_cov) begin
+ cov.peri_cg_wrap[PeriIo].sample(cfg.clkmgr_vif.peri_io_cb.clk_enable,
+ cfg.clkmgr_vif.peri_io_cb.ip_clk_en,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ forever
+ @cfg.clkmgr_vif.peri_div2_cb begin
+ if (cfg.io_clk_rst_vif.rst_n && cfg.en_cov) begin
+ cov.peri_cg_wrap[PeriDiv2].sample(cfg.clkmgr_vif.peri_div2_cb.clk_enable,
+ cfg.clkmgr_vif.peri_div2_cb.ip_clk_en,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ forever
+ @cfg.clkmgr_vif.peri_div4_cb begin
+ if (cfg.io_clk_rst_vif.rst_n && cfg.en_cov) begin
+ cov.peri_cg_wrap[PeriDiv4].sample(cfg.clkmgr_vif.peri_div4_cb.clk_enable,
+ cfg.clkmgr_vif.peri_div4_cb.ip_clk_en,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ forever
+ @cfg.clkmgr_vif.peri_usb_cb begin
+ if (cfg.io_clk_rst_vif.rst_n && cfg.en_cov) begin
+ cov.peri_cg_wrap[PeriUsb].sample(cfg.clkmgr_vif.peri_usb_cb.clk_enable,
+ cfg.clkmgr_vif.peri_usb_cb.ip_clk_en,
+ cfg.clkmgr_vif.scanmode_i == MuBi4True);
+ end
+ end
+ join
+ endtask
+
+ task sample_trans_cov(int trans_index);
+ logic hint, clk_en, idle, src_rst_en;
+ trans_e trans = trans_e'(trans_index);
+ forever begin
+ @cfg.clkmgr_vif.trans_cb;
+ hint = cfg.clkmgr_vif.trans_cb.clk_hints[trans_index];
+ idle = cfg.clkmgr_vif.trans_cb.idle_i[trans_index];
+ clk_en = cfg.clkmgr_vif.trans_cb.ip_clk_en;
+ src_rst_en = cfg.main_clk_rst_vif.rst_n;
+ if (src_rst_en && cfg.en_cov) begin
+ logic scan_en = cfg.clkmgr_vif.scanmode_i == prim_mubi_pkg::MuBi4True;
+ cov.trans_cg_wrap[trans].sample(hint, clk_en, scan_en, idle);
+ end
+ end
+ endtask
+
+ task sample_trans_covs();
+ for (int i = 0; i < $bits(hintables_t); ++i) begin
+ fork
+ automatic int trans_index = i;
+ sample_trans_cov(trans_index);
+ join_none
+ end
+ endtask
+
+ local task sample_freq_measurement_cov(clk_mesr_e clk, ref freq_measurement_t measurement,
+ logic timeout);
+ if (cfg.en_cov) begin
+ cov.freq_measure_cg_wrap[clk].sample(!measurement.slow && !measurement.fast, measurement.slow,
+ measurement.fast, timeout);
+ `uvm_info(`gfn, $sformatf(
+ "Cov for %0s: %0s",
+ clk.name(),
+ measurement.slow ? "slow" : measurement.fast ? "fast" : "okay"
+ ), UVM_MEDIUM)
+ measurement = '{default: 0};
+ end
+ endtask
+
+ task sample_freq_measurement_covs();
+ fork
+ forever
+ @(posedge cfg.clkmgr_vif.io_freq_measurement.valid or
+ posedge cfg.clkmgr_vif.io_timeout_err) begin
+ sample_freq_measurement_cov(ClkMesrIo, cfg.clkmgr_vif.io_freq_measurement,
+ cfg.clkmgr_vif.io_timeout_err);
+ end
+
+ forever
+ @(posedge cfg.clkmgr_vif.io_div2_freq_measurement.valid or
+ posedge cfg.clkmgr_vif.io_div2_timeout_err) begin
+ sample_freq_measurement_cov(ClkMesrIoDiv2, cfg.clkmgr_vif.io_div2_freq_measurement,
+ cfg.clkmgr_vif.io_div2_timeout_err);
+
+ end
+ forever
+ @(posedge cfg.clkmgr_vif.io_div4_freq_measurement.valid or
+ posedge cfg.clkmgr_vif.io_div4_timeout_err) begin
+ sample_freq_measurement_cov(ClkMesrIoDiv4, cfg.clkmgr_vif.io_div4_freq_measurement,
+ cfg.clkmgr_vif.io_div4_timeout_err);
+ end
+ forever
+ @(posedge cfg.clkmgr_vif.main_freq_measurement.valid or
+ posedge cfg.clkmgr_vif.main_timeout_err) begin
+ sample_freq_measurement_cov(ClkMesrMain, cfg.clkmgr_vif.main_freq_measurement,
+ cfg.clkmgr_vif.main_timeout_err);
+ end
+ forever
+ @(posedge cfg.clkmgr_vif.usb_freq_measurement.valid or
+ posedge cfg.clkmgr_vif.usb_timeout_err) begin
+ sample_freq_measurement_cov(ClkMesrUsb, cfg.clkmgr_vif.usb_freq_measurement,
+ cfg.clkmgr_vif.usb_timeout_err);
+ end
+ join_none
+ endtask
+
+ task sample_recov_err_cov();
+ fork
+ forever
+ @cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr if (cfg.en_cov) begin
+ cov.recov_err_cg.sample(
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[10],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[9],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[8],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[7],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[6],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[5],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[4],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[3],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[2],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[1],
+ cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr[0]);
+ `uvm_info(`gfn, $sformatf(
+ "Recoverable errors sampled: 0x%x", cfg.clkmgr_csrs_vif.csrs_cb.recov_err_csr),
+ UVM_MEDIUM)
+ end
+ join_none
+ endtask
+
+ task sample_fatal_err_cov();
+ fork
+ forever
+ @cfg.clkmgr_csrs_vif.csrs_cb.fatal_err_csr if (cfg.en_cov) begin
+ cov.fatal_err_cg.sample(
+ cfg.clkmgr_csrs_vif.csrs_cb.fatal_err_csr[2],
+ cfg.clkmgr_csrs_vif.csrs_cb.fatal_err_csr[1],
+ cfg.clkmgr_csrs_vif.csrs_cb.fatal_err_csr[0]);
+ `uvm_info(`gfn, $sformatf(
+ "Fatal errors sampled: 0x%x", cfg.clkmgr_csrs_vif.csrs_cb.fatal_err_csr),
+ UVM_MEDIUM)
+ end
+ join_none
+ endtask
+
+ virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
+ uvm_reg csr;
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+ uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr);
+
+ bit addr_phase_read = (!write && channel == AddrChannel);
+ bit addr_phase_write = (write && channel == AddrChannel);
+ bit data_phase_read = (!write && channel == DataChannel);
+ bit data_phase_write = (write && channel == DataChannel);
+
+ string access_str = write ? "write" : "read";
+ string channel_str = channel == AddrChannel ? "address" : "data";
+
+ // if access was to a valid csr, get the csr handle
+ if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin
+ csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr);
+ `DV_CHECK_NE_FATAL(csr, null)
+ end else begin
+ `uvm_fatal(`gfn, $sformatf("Access unexpected addr 0x%0h", csr_addr))
+ end
+
+ // If incoming access is a write to a valid csr, update prediction right away.
+ if (addr_phase_write) begin
+ `uvm_info(`gfn, $sformatf("Writing 0x%0x to %s", item.a_data, csr.get_name()), UVM_MEDIUM)
+ void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
+ end
+
+ // Process the csr req:
+ // - For write, update local variable and fifo at address phase.
+ // - For read, update predication at address phase and compare at data phase.
+ case (csr.get_name())
+ // add individual case item for each csr
+ "alert_test": begin
+ // FIXME
+ end
+ "extclk_ctrl_regwen": begin
+ if (addr_phase_write) extclk_ctrl_regwen = item.a_data;
+ end
+ "extclk_ctrl": begin
+ typedef logic [2*$bits(prim_mubi_pkg::mubi4_t) - 1:0] extclk_ctrl_t;
+ if (addr_phase_write && extclk_ctrl_regwen) begin
+ `DV_CHECK_EQ(extclk_ctrl_t'(item.a_data), {
+ cfg.clkmgr_vif.extclk_ctrl_csr_step_down, cfg.clkmgr_vif.extclk_ctrl_csr_sel
+ })
+ end
+ end
+ "extclk_status": begin
+ do_read_check = 1'b0;
+ end
+ "jitter_regwen": begin
+ end
+ "jitter_enable": begin
+ if (addr_phase_write && `gmv(ral.jitter_regwen)) begin
+ `DV_CHECK_EQ(prim_mubi_pkg::mubi4_t'(item.a_data), cfg.clkmgr_vif.jitter_enable_csr)
+ end
+ end
+ "clk_enables": begin
+ if (addr_phase_write) begin
+ `DV_CHECK_EQ(clk_enables_t'(item.a_data), cfg.clkmgr_vif.clk_enables_csr)
+ end
+ end
+ "clk_hints": begin
+ // Clearing a hint sets an expectation for the status to transition to zero.
+ if (addr_phase_write) begin
+ `DV_CHECK_EQ(clk_hints_t'(item.a_data), cfg.clkmgr_vif.clk_hints_csr)
+ end
+ end
+ "clk_hints_status": begin
+ // The status will respond to the hint once the target unit is idle. We check it in
+ // the sequence.
+ do_read_check = 1'b0;
+ end
+ "measure_ctrl_regwen": begin
+ if (addr_phase_write) measure_ctrl_regwen = item.a_data;
+ end
+ "io_meas_ctrl_en": begin
+ end
+ "io_div2_meas_ctrl_en": begin
+ end
+ "io_div4_meas_ctrl_en": begin
+ end
+ "main_meas_ctrl_en": begin
+ end
+ "usb_meas_ctrl_en": begin
+ end
+ "io_meas_ctrl_shadowed": begin
+ end
+ "io_div2_meas_ctrl_shadowed": begin
+ end
+ "io_div4_meas_ctrl_shadowed": begin
+ end
+ "main_meas_ctrl_shadowed": begin
+ end
+ "usb_meas_ctrl_shadowed": begin
+ end
+ "recov_err_code": begin
+ do_read_check = 1'b0;
+ end
+ "fatal_err_code": begin
+ do_read_check = 1'b0;
+ end
+ default: begin
+ `uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
+ end
+ endcase
+
+ // On reads, if do_read_check, is set, then check mirrored_value against item.d_data
+ if (data_phase_read) begin
+ `uvm_info(`gfn, $sformatf("Reading 0x%0x from %s", item.d_data, csr.get_name()), UVM_MEDIUM)
+ if (do_read_check) begin
+ `DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data, $sformatf(
+ "reg name: %0s", csr.get_full_name()))
+ end
+ void'(csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ)));
+ end
+ endtask
+
+ virtual function void reset(string kind = "HARD");
+ super.reset(kind);
+ // reset local fifos queues and variables
+ extclk_ctrl_regwen = ral.extclk_ctrl_regwen.get_reset();
+ measure_ctrl_regwen = ral.measure_ctrl_regwen.get_reset();
+ endfunction
+
+ function void check_phase(uvm_phase phase);
+ super.check_phase(phase);
+ // post test checks - ensure that all local fifos and queues are empty
+ endfunction
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_virtual_sequencer.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_virtual_sequencer.sv
new file mode 100644
index 00000000000000..c631a82b1c7632
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/clkmgr_virtual_sequencer.sv
@@ -0,0 +1,14 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_virtual_sequencer extends cip_base_virtual_sequencer #(
+ .CFG_T(clkmgr_env_cfg),
+ .COV_T(clkmgr_env_cov)
+);
+ `uvm_component_utils(clkmgr_virtual_sequencer)
+
+
+ `uvm_component_new
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv
new file mode 100644
index 00000000000000..504663518652a0
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_base_vseq.sv
@@ -0,0 +1,456 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_base_vseq extends cip_base_vseq #(
+ .RAL_T (clkmgr_reg_block),
+ .CFG_T (clkmgr_env_cfg),
+ .COV_T (clkmgr_env_cov),
+ .VIRTUAL_SEQUENCER_T(clkmgr_virtual_sequencer)
+);
+
+ `uvm_object_utils(clkmgr_base_vseq)
+ `uvm_object_new
+
+ // The extra cycles to wait after reset before starting any test, required so some CSRs (notably
+ // hints_status) are properly set when inputs go through synchronizers.
+ localparam int POST_APPLY_RESET_CYCLES = 10;
+
+ // This delay is needed to allow updates to the idle inputs to go through synchronizers and
+ // counters.
+ localparam int IDLE_SYNC_CYCLES = 20;
+
+ // This is the timeout for the various clk status outputs to react to their inputs.
+ localparam int CLK_STATUS_TIMEOUT_NS = 100_000;
+
+ rand bit io_ip_clk_en;
+ rand bit main_ip_clk_en;
+ rand bit usb_ip_clk_en;
+
+ rand mubi_hintables_t idle;
+
+ // Override this from cip_base_vseq, since clkmgr tests are relatively short.
+ constraint rand_reset_delay_c {
+ rand_reset_delay dist {
+ [1 : 1000] :/ 1,
+ [1001 : 100_000] :/ 2,
+ [100_001 : 1_000_000] :/ 6
+ };
+ }
+
+ mubi4_t scanmode;
+ int scanmode_on_weight = 8;
+
+ mubi4_t extclk_ctrl_high_speed_sel;
+ mubi4_t extclk_ctrl_sel;
+ clkmgr_mubi_e mubi_mode;
+
+ // This holds the necessary per measure control CSR info.
+ typedef struct {
+ string name;
+ dv_base_reg en;
+ dv_base_reg_field ctrl_hi;
+ dv_base_reg_field ctrl_lo;
+ } meas_ctrl_regs_t;
+ meas_ctrl_regs_t meas_ctrl_regs[clk_mesr_e];
+
+ virtual function void set_scanmode_on_low_weight();
+ scanmode_on_weight = 2;
+ endfunction
+
+ function void post_randomize();
+ extclk_ctrl_high_speed_sel = get_rand_mubi4_val(6, 2, 2);
+ extclk_ctrl_sel = get_rand_mubi4_val(4, 2, 2);
+ scanmode = get_rand_mubi4_val(scanmode_on_weight, 4, 4);
+ `uvm_info(`gfn, $sformatf(
+ "randomize: extclk_ctrl_sel=0x%x, extclk_ctrl_high_speed_sel=0x%x, scanmode=0x%x",
+ extclk_ctrl_sel,
+ extclk_ctrl_high_speed_sel,
+ scanmode
+ ), UVM_MEDIUM)
+ super.post_randomize();
+ endfunction
+
+ virtual task initialize_on_start();
+ `uvm_info(`gfn, "In clkmgr_if initialize_on_start", UVM_MEDIUM)
+ idle = {NUM_TRANS{MuBi4True}};
+ scanmode = MuBi4False;
+ cfg.clkmgr_vif.init(.idle(idle), .scanmode(scanmode), .lc_debug_en(Off));
+ io_ip_clk_en = 1'b1;
+ main_ip_clk_en = 1'b1;
+ usb_ip_clk_en = 1'b1;
+ start_ip_clocks();
+ endtask
+
+ // Converts to bool with strict true.
+ protected function hintables_t mubi_hintables_to_hintables(mubi_hintables_t mubi_hints);
+ hintables_t ret;
+ foreach (mubi_hints[i]) ret[i] = prim_mubi_pkg::mubi4_test_true_strict(mubi_hints[i]);
+ return ret;
+ endfunction
+
+ local function void disable_unnecessary_exclusions();
+ ral.get_excl_item().enable_excl("clkmgr_reg_block.clk_enables", 0);
+ ral.get_excl_item().enable_excl("clkmgr_reg_block.clk_hints", 0);
+ `uvm_info(`gfn, "Adjusted exclusions", UVM_MEDIUM)
+ ral.get_excl_item().print_exclusions(UVM_MEDIUM);
+ endfunction
+
+ task pre_start();
+ meas_ctrl_regs[ClkMesrIo] = '{"io", ral.io_meas_ctrl_en, ral.io_meas_ctrl_shadowed.hi,
+ ral.io_meas_ctrl_shadowed.lo};
+ meas_ctrl_regs[ClkMesrIoDiv2] = '{"io div2", ral.io_div2_meas_ctrl_en,
+ ral.io_div2_meas_ctrl_shadowed.hi,
+ ral.io_div2_meas_ctrl_shadowed.lo};
+ meas_ctrl_regs[ClkMesrIoDiv4] = '{"io div4", ral.io_div4_meas_ctrl_en,
+ ral.io_div4_meas_ctrl_shadowed.hi,
+ ral.io_div4_meas_ctrl_shadowed.lo};
+ meas_ctrl_regs[ClkMesrMain] = '{"main", ral.main_meas_ctrl_en, ral.main_meas_ctrl_shadowed.hi,
+ ral.main_meas_ctrl_shadowed.lo};
+ meas_ctrl_regs[ClkMesrUsb] = '{"usb", ral.usb_meas_ctrl_en, ral.usb_meas_ctrl_shadowed.hi,
+ ral.usb_meas_ctrl_shadowed.lo};
+
+ mubi_mode = ClkmgrMubiNone;
+ `DV_GET_ENUM_PLUSARG(clkmgr_mubi_e, mubi_mode, clkmgr_mubi_mode)
+ `uvm_info(`gfn, $sformatf("mubi_mode = %s", mubi_mode.name), UVM_MEDIUM)
+ cfg.clkmgr_vif.init(.idle({NUM_TRANS{MuBi4True}}), .scanmode(scanmode), .lc_debug_en(Off));
+ cfg.clkmgr_vif.update_io_ip_clk_en(1'b1);
+ cfg.clkmgr_vif.update_main_ip_clk_en(1'b1);
+ cfg.clkmgr_vif.update_usb_ip_clk_en(1'b1);
+ cfg.clkmgr_vif.update_all_clk_byp_ack(MuBi4False);
+ cfg.clkmgr_vif.update_div_step_down_req(MuBi4False);
+ cfg.clkmgr_vif.update_io_clk_byp_ack(MuBi4False);
+
+ disable_unnecessary_exclusions();
+ clkmgr_init();
+ super.pre_start();
+ if (common_seq_type inside {"shadow_reg_errors", "shadow_reg_errors_with_csr_rw"}) begin
+ expect_fatal_alerts = 1;
+ end
+ endtask
+
+ virtual task dut_init(string reset_kind = "HARD");
+ super.dut_init(reset_kind);
+ endtask
+
+ virtual task dut_shutdown();
+ // check for pending clkmgr operations and wait for them to complete
+ endtask
+
+ // This turns on the actual input clocks, as the pwrmgr would.
+ task start_ip_clocks();
+ fork
+ start_io_ip_clock();
+ start_main_ip_clock();
+ start_usb_ip_clock();
+ join
+ endtask
+
+ task start_io_ip_clock();
+ `uvm_info(`gfn, $sformatf(
+ "starting io clk_en with current status %b", cfg.clkmgr_vif.pwr_o.io_status),
+ UVM_MEDIUM)
+ cfg.io_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.io_ip_clk_en = io_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.io_status == 1'b1);,
+ "timeout waiting for io_status to raise", CLK_STATUS_TIMEOUT_NS)
+ `uvm_info(`gfn, "starting io clock done", UVM_MEDIUM)
+ endtask
+
+ task start_main_ip_clock();
+ `uvm_info(`gfn, $sformatf(
+ "starting main clk_en with current status %b", cfg.clkmgr_vif.pwr_o.main_status),
+ UVM_MEDIUM)
+ cfg.main_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.main_ip_clk_en = main_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.main_status == 1'b1);,
+ "timeout waiting for main_status to raise", CLK_STATUS_TIMEOUT_NS)
+ `uvm_info(`gfn, "starting main clock done", UVM_MEDIUM)
+ endtask
+
+ task start_usb_ip_clock();
+ `uvm_info(`gfn, $sformatf(
+ "starting usb clk_en with current status %b", cfg.clkmgr_vif.pwr_o.usb_status),
+ UVM_MEDIUM)
+ cfg.usb_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.usb_ip_clk_en = usb_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.usb_status == 1'b1);,
+ "timeout waiting for usb_status to raise", CLK_STATUS_TIMEOUT_NS)
+ `uvm_info(`gfn, "starting usb clock done", UVM_MEDIUM)
+ endtask
+
+ // This turns on or off the actual input clocks, as the pwrmgr would.
+ task control_ip_clocks();
+ fork
+ control_io_ip_clock();
+ control_main_ip_clock();
+ control_usb_ip_clock();
+ join
+ endtask
+
+ task control_io_ip_clock();
+ // Do nothing if nothing interesting changed.
+ if (cfg.clkmgr_vif.pwr_i.io_ip_clk_en == io_ip_clk_en) return;
+ `uvm_info(`gfn, $sformatf(
+ "controlling io clk_en from %b to %b with current status %b",
+ cfg.clkmgr_vif.pwr_i.io_ip_clk_en,
+ io_ip_clk_en,
+ cfg.clkmgr_vif.pwr_o.io_status
+ ), UVM_MEDIUM)
+ if (!io_ip_clk_en) begin
+ cfg.clkmgr_vif.pwr_i.io_ip_clk_en = io_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.io_status == 1'b0);,
+ "timeout waiting for io_status to fall", CLK_STATUS_TIMEOUT_NS)
+ cfg.io_clk_rst_vif.stop_clk();
+ end else begin
+ cfg.io_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.io_ip_clk_en = io_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.io_status == 1'b1);,
+ "timeout waiting for io_status to raise", CLK_STATUS_TIMEOUT_NS)
+ end
+ `uvm_info(`gfn, "controlling io clock done", UVM_MEDIUM)
+ endtask
+
+ task control_main_ip_clock();
+ // Do nothing if nothing interesting changed.
+ if (cfg.clkmgr_vif.pwr_i.main_ip_clk_en == main_ip_clk_en) return;
+ `uvm_info(`gfn, $sformatf(
+ "controlling main clk_en from %b to %b with current status %b",
+ cfg.clkmgr_vif.pwr_i.main_ip_clk_en,
+ main_ip_clk_en,
+ cfg.clkmgr_vif.pwr_o.main_status
+ ), UVM_MEDIUM)
+ if (!main_ip_clk_en) begin
+ cfg.clkmgr_vif.pwr_i.main_ip_clk_en = main_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.main_status == 1'b0);,
+ "timeout waiting for main_status to fall", CLK_STATUS_TIMEOUT_NS)
+ cfg.main_clk_rst_vif.stop_clk();
+ end else begin
+ cfg.main_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.main_ip_clk_en = main_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.main_status == 1'b1);,
+ "timeout waiting for main_status to raise", CLK_STATUS_TIMEOUT_NS)
+ end
+ `uvm_info(`gfn, "controlling main clock done", UVM_MEDIUM)
+ endtask
+
+ task control_usb_ip_clock();
+ // Do nothing if nothing interesting changed.
+ if (cfg.clkmgr_vif.pwr_i.usb_ip_clk_en == usb_ip_clk_en) return;
+ `uvm_info(`gfn, $sformatf(
+ "controlling usb clk_en from %b to %b with current status %b",
+ cfg.clkmgr_vif.pwr_i.usb_ip_clk_en,
+ usb_ip_clk_en,
+ cfg.clkmgr_vif.pwr_o.usb_status
+ ), UVM_MEDIUM)
+ if (!usb_ip_clk_en) begin
+ cfg.clkmgr_vif.pwr_i.usb_ip_clk_en = usb_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.usb_status == 1'b0);,
+ "timeout waiting for usb_status to fall", CLK_STATUS_TIMEOUT_NS)
+ cfg.usb_clk_rst_vif.stop_clk();
+ end else begin
+ cfg.usb_clk_rst_vif.start_clk();
+ cfg.clkmgr_vif.pwr_i.usb_ip_clk_en = usb_ip_clk_en;
+ `DV_SPINWAIT(wait(cfg.clkmgr_vif.pwr_o.usb_status == 1'b1);,
+ "timeout waiting for usb_status to raise", CLK_STATUS_TIMEOUT_NS)
+ end
+ `uvm_info(`gfn, "controlling usb clock done", UVM_MEDIUM)
+ endtask
+
+ task disable_frequency_measurement(clk_mesr_e which);
+ `uvm_info(`gfn, $sformatf("Disabling frequency measurement for %0s", which.name), UVM_MEDIUM)
+ csr_wr(.ptr(meas_ctrl_regs[which].en), .value(MuBi4False));
+ endtask
+
+ local function int get_meas_ctrl_value(int min_threshold, int max_threshold, uvm_reg_field lo,
+ uvm_reg_field hi);
+ int lo_mask = (1 << lo.get_n_bits()) - 1;
+ int hi_mask = (1 << hi.get_n_bits()) - 1;
+
+ int value = (((min_threshold & lo_mask) << lo.get_lsb_pos()) |
+ ((max_threshold & hi_mask) << hi.get_lsb_pos()));
+ return value;
+ endfunction
+
+ // Any non-false mubi value in the enable CSR turns measurements on.
+ task enable_frequency_measurement(clk_mesr_e which, int min_threshold, int max_threshold);
+ int value = get_meas_ctrl_value(min_threshold, max_threshold, meas_ctrl_regs[which].ctrl_lo,
+ meas_ctrl_regs[which].ctrl_hi);
+ mubi4_t en_value = get_rand_mubi4_val(1, 0, 3);
+ `uvm_info(`gfn, $sformatf(
+ "Enabling frequency measurement for %0s, min=0x%x, max=0x%x, expected=0x%x",
+ which.name,
+ min_threshold,
+ max_threshold,
+ ExpectedCounts[which]
+ ), UVM_MEDIUM)
+ csr_wr(.ptr(meas_ctrl_regs[which].ctrl_lo.get_dv_base_reg_parent()), .value(value));
+ csr_wr(.ptr(meas_ctrl_regs[which].en), .value(en_value));
+ endtask
+
+ // This checks that when calibration is lost regwen should be re-enabled and measurements
+ // disabled.
+ task calibration_lost_checks();
+ void'(ral.measure_ctrl_regwen.predict(1));
+ csr_rd_check(.ptr(ral.measure_ctrl_regwen), .compare_value(1));
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ csr_rd_check(.ptr(meas_ctrl_regs[clk_mesr].en), .compare_value(MuBi4False));
+ end
+ endtask
+
+ local function void control_sync_pulse_assert(clk_mesr_e clk, bit enable);
+ case (clk)
+ ClkMesrIo: begin
+ if (enable) $asserton(0, "tb.dut.u_io_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ else $assertoff(0, "tb.dut.u_io_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ end
+ ClkMesrIoDiv2: begin
+ if (enable) $asserton(0, "tb.dut.u_io_div2_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ else $assertoff(0, "tb.dut.u_io_div2_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ end
+ ClkMesrIoDiv4: begin
+ if (enable) $asserton(0, "tb.dut.u_io_div4_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ else $assertoff(0, "tb.dut.u_io_div4_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ end
+ ClkMesrMain: begin
+ if (enable) $asserton(0, "tb.dut.u_main_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ else $assertoff(0, "tb.dut.u_main_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ end
+ ClkMesrUsb: begin
+ if (enable) $asserton(0, "tb.dut.u_usb_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ else $assertoff(0, "tb.dut.u_usb_meas.u_meas.u_sync_ref.SrcPulseCheck_M");
+ end
+ default: `uvm_error(`gfn, $sformatf("unexpected clock index '%0d'", clk))
+ endcase
+ endfunction
+
+ // This turns off/on some clocks being measured to trigger a measurement timeout.
+ // A side-effect is that some RTL assertions will fire, so they are corresponsdingly controlled.
+ task disturb_measured_clock(clk_mesr_e clk, bit enable);
+ case (clk)
+ ClkMesrIo, ClkMesrIoDiv2, ClkMesrIoDiv4: begin
+ if (enable) cfg.io_clk_rst_vif.start_clk();
+ else cfg.io_clk_rst_vif.stop_clk();
+ control_sync_pulse_assert(.clk(ClkMesrIo), .enable(enable));
+ control_sync_pulse_assert(.clk(ClkMesrIoDiv2), .enable(enable));
+ control_sync_pulse_assert(.clk(ClkMesrIoDiv4), .enable(enable));
+ end
+ ClkMesrMain: begin
+ if (enable) cfg.main_clk_rst_vif.start_clk();
+ else cfg.main_clk_rst_vif.stop_clk();
+ control_sync_pulse_assert(.clk(clk), .enable(enable));
+ end
+ ClkMesrUsb: begin
+ if (enable) cfg.usb_clk_rst_vif.start_clk();
+ else cfg.usb_clk_rst_vif.stop_clk();
+ control_sync_pulse_assert(.clk(clk), .enable(enable));
+ end
+ default: `uvm_fatal(`gfn, $sformatf("Unexpected clk '%0d'", clk))
+ endcase
+ endtask
+
+ function void report_recov_error_mismatch(string error_type, recov_bits_t expected,
+ recov_bits_t actual);
+ recov_bits_t mismatch = actual ^ expected;
+ foreach (mismatch[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ if (mismatch[clk]) begin
+ `uvm_info(`gfn, $sformatf(
+ "Mismatch %0s for %0s, expected %b, actual %b",
+ error_type,
+ clk_mesr.name,
+ expected[clk],
+ actual[clk]
+ ), UVM_LOW)
+ end
+ end
+ `uvm_error(`gfn, $sformatf(
+ "Mismatch for %0s recoverable error, expected 0b%b, got 0b%b",
+ error_type,
+ expected,
+ actual
+ ))
+ endfunction
+
+ // Returns the maximum clock period across non-aon clocks.
+ local function int maximum_clock_period();
+ int clk_periods_q[$] = {
+ cfg.aon_clk_rst_vif.clk_period_ps,
+ cfg.io_clk_rst_vif.clk_period_ps * 4,
+ cfg.main_clk_rst_vif.clk_period_ps,
+ cfg.usb_clk_rst_vif.clk_period_ps
+ };
+ return max(clk_periods_q);
+ endfunction
+
+ // This is tricky, and we choose to handle it all here, not in "super":
+ // - there are no multiple clk_rst_vifs,
+ // - it would be too complicated to coordinate reset durations with super.
+ // For hard resets we also reset the cfg.root*_clk_rst_vif, and its reset is shorter than
+ // that of all others.
+ virtual task apply_resets_concurrently(int reset_duration_ps = 0);
+ int clk_periods_q[$] = {
+ reset_duration_ps,
+ cfg.aon_clk_rst_vif.clk_period_ps,
+ cfg.io_clk_rst_vif.clk_period_ps * 4,
+ cfg.main_clk_rst_vif.clk_period_ps,
+ cfg.usb_clk_rst_vif.clk_period_ps
+ };
+ reset_duration_ps = max(clk_periods_q);
+
+ `uvm_info(`gfn, "In apply_resets_concurrently", UVM_MEDIUM)
+ cfg.root_io_clk_rst_vif.drive_rst_pin(0);
+ cfg.root_main_clk_rst_vif.drive_rst_pin(0);
+ cfg.root_usb_clk_rst_vif.drive_rst_pin(0);
+ cfg.aon_clk_rst_vif.drive_rst_pin(0);
+ cfg.clk_rst_vif.drive_rst_pin(0);
+ cfg.io_clk_rst_vif.drive_rst_pin(0);
+ cfg.main_clk_rst_vif.drive_rst_pin(0);
+ cfg.usb_clk_rst_vif.drive_rst_pin(0);
+
+ #(reset_duration_ps * $urandom_range(2, 10) * 1ps);
+ cfg.root_io_clk_rst_vif.drive_rst_pin(1);
+ cfg.root_main_clk_rst_vif.drive_rst_pin(1);
+ cfg.root_usb_clk_rst_vif.drive_rst_pin(1);
+ `uvm_info(`gfn, "apply_resets_concurrently releases POR", UVM_MEDIUM)
+
+ #(reset_duration_ps * $urandom_range(2, 10) * 1ps);
+ cfg.aon_clk_rst_vif.drive_rst_pin(1);
+ cfg.clk_rst_vif.drive_rst_pin(1);
+ cfg.io_clk_rst_vif.drive_rst_pin(1);
+ cfg.main_clk_rst_vif.drive_rst_pin(1);
+ cfg.usb_clk_rst_vif.drive_rst_pin(1);
+ `uvm_info(`gfn, "apply_resets_concurrently releases other resets", UVM_MEDIUM)
+ endtask
+
+ virtual task apply_reset(string kind = "HARD");
+ if (kind == "HARD") apply_resets_concurrently();
+ else begin
+ fork
+ cfg.clk_rst_vif.apply_reset();
+ cfg.aon_clk_rst_vif.apply_reset();
+ cfg.main_clk_rst_vif.apply_reset();
+ cfg.io_clk_rst_vif.apply_reset();
+ cfg.usb_clk_rst_vif.apply_reset();
+ join
+ end
+ endtask
+
+ task post_apply_reset(string reset_kind = "HARD");
+ super.post_apply_reset(reset_kind);
+ initialize_on_start();
+ cfg.io_clk_rst_vif.wait_clks(POST_APPLY_RESET_CYCLES);
+ endtask
+
+ // setup basic clkmgr features
+ virtual task clkmgr_init();
+ // Initialize input clock frequencies.
+ cfg.main_clk_rst_vif.set_freq_mhz((1.0 * MainClkHz) / 1_000_000);
+ cfg.io_clk_rst_vif.set_freq_mhz((1.0 * IoClkHz) / 1_000_000);
+ cfg.usb_clk_rst_vif.set_freq_mhz((1.0 * UsbClkHz) / 1_000_000);
+ // The real clock rate for aon is 200kHz, but that can slow testing down.
+ // Increasing its frequency improves DV efficiency without compromising quality.
+ cfg.aon_clk_rst_vif.set_freq_mhz((1.0 * FakeAonClkHz) / 1_000_000);
+ endtask
+endclass : clkmgr_base_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_clk_status_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_clk_status_vseq.sv
new file mode 100644
index 00000000000000..1bd2d7bc1f1e44
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_clk_status_vseq.sv
@@ -0,0 +1,35 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This tests the transitions of the various clock status outputs for random settings of the
+// various ip_clk_en inputs.
+//
+// The checks are done via SVA in clkmgr_pwrmgr_sva_if.
+class clkmgr_clk_status_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_clk_status_vseq)
+
+ `uvm_object_new
+
+ function void post_randomize();
+ super.post_randomize();
+ // Disable scanmode since it is not interesting.
+ scanmode = prim_mubi_pkg::MuBi4False;
+ endfunction
+
+ task body();
+ for (int i = 0; i < num_trans; ++i) begin
+ cfg.clk_rst_vif.wait_clks(4);
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ cfg.clkmgr_vif.init(.idle(idle), .scanmode(scanmode));
+ control_ip_clocks();
+
+ // If some units were not idle, make them so.
+ idle = '1;
+ // Wait for idle to percolate.
+ cfg.clk_rst_vif.wait_clks(10);
+ end
+ // And set it back to more common values for stress tests.
+ initialize_on_start();
+ endtask : body
+endclass : clkmgr_clk_status_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_common_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_common_vseq.sv
new file mode 100644
index 00000000000000..3753d80678b168
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_common_vseq.sv
@@ -0,0 +1,70 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_common_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_common_vseq)
+
+ constraint num_trans_c {num_trans inside {[1 : 2]};}
+ `uvm_object_new
+
+ virtual task pre_start();
+ csr_excl_item csr_excl = ral.get_excl_item();
+ super.pre_start();
+
+ // Remove rw1c type from same_csr_outstanding
+ if (common_seq_type == "same_csr_outstanding") begin
+ csr_excl.add_excl("clkmgr_reg_block.recov_err_code", CsrExclWrite);
+ end
+ endtask
+
+ virtual task body();
+ run_common_vseq_wrapper(num_trans);
+ endtask : body
+
+ virtual task check_sec_cm_fi_resp(sec_cm_base_if_proxy if_proxy);
+ super.check_sec_cm_fi_resp(if_proxy);
+
+ case (if_proxy.sec_cm_type)
+ SecCmPrimCount: begin
+ csr_rd_check(.ptr(ral.fatal_err_code.idle_cnt), .compare_value(1));
+ end
+ default: begin
+ `uvm_error(`gfn, $sformatf("Unexpected sec_cm_type %0s", if_proxy.sec_cm_type.name))
+ end
+ endcase
+ endtask
+
+ task initialize_on_start();
+ super.initialize_on_start();
+ // update default idle to false for
+ // csr test.
+ cfg.clkmgr_vif.idle_i = {NUM_TRANS{MuBi4False}};
+ endtask : initialize_on_start
+
+ // This task is used for non-main clock registers.
+ // to compensate clock difference, wait longer until
+ // see get_alert()
+ task skid_check_fatal_alert_nonblocking(string alert_name);
+ fork
+ `DV_SPINWAIT_EXIT(
+ forever begin
+ // 1 extra cycle to make sure no race condition
+ repeat (alert_esc_agent_pkg::ALERT_B2B_DELAY + 20) begin
+ cfg.clk_rst_vif.wait_n_clks(1);
+ if (cfg.m_alert_agent_cfgs[alert_name].vif.get_alert() == 1) break;
+ end
+ `DV_CHECK_EQ(cfg.m_alert_agent_cfgs[alert_name].vif.get_alert(), 1,
+ $sformatf("fatal error %0s does not trigger!", alert_name))
+ cfg.m_alert_agent_cfgs[alert_name].vif.wait_ack_complete();
+ end,
+ wait(cfg.under_reset);)
+ join_none
+ endtask
+
+ // Override shadow_reg_errors task
+ // to cover shadow regs under clock div2, div4
+ task shadow_reg_errors_check_fatal_alert_nonblocking(dv_base_reg shadowed_csr, string alert_name);
+ skid_check_fatal_alert_nonblocking(alert_name);
+ endtask
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv
new file mode 100644
index 00000000000000..5051fb9553c1a6
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_extclk_vseq.sv
@@ -0,0 +1,241 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// The extclk vseq causes the external clock selection to be triggered. More details
+// in the clkmgr_testplan.hjson file.
+class clkmgr_extclk_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_extclk_vseq)
+
+ `uvm_object_new
+
+ // When extclk_ctrl_regwen is clear it is not possible to select external clocks.
+ // This is tested in regular csr_rw, so here this register is simply set to 1.
+
+ // The extclk cannot be manipulated in low power mode.
+ constraint io_ip_clk_en_on_c {io_ip_clk_en == 1'b1;}
+ constraint main_ip_clk_en_on_c {main_ip_clk_en == 1'b1;}
+ constraint usb_ip_clk_en_on_c {usb_ip_clk_en == 1'b1;}
+
+ // This randomizes the time when the extclk_ctrl CSR write and the lc_clk_byp_req
+ // input is asserted for good measure. Of course, there is a good chance only a single
+ // one of these trigger a request, so they are also independently tested.
+ rand int cycles_before_extclk_ctrl_sel;
+ rand int cycles_before_lc_clk_byp_req;
+ rand int cycles_before_lc_clk_byp_ack;
+ rand int cycles_before_all_clk_byp_ack;
+ rand int cycles_before_div_step_down_req;
+ rand int cycles_before_io_clk_byp_ack;
+ rand int cycles_before_next_trans;
+
+ rand int flips_before_io_clk_byp_ack;
+ rand int flips_before_div_step_down_req;
+ rand int flips_before_all_clk_byp_ack;
+ rand int cycles_between_flips;
+
+ constraint cycles_to_stim_c {
+ cycles_before_extclk_ctrl_sel inside {[4 : 20]};
+ cycles_before_lc_clk_byp_req inside {[4 : 20]};
+ cycles_before_lc_clk_byp_ack inside {[16 : 30]};
+ cycles_before_all_clk_byp_ack inside {[3 : 11]};
+ cycles_before_div_step_down_req inside {[3 : 11]};
+ cycles_before_io_clk_byp_ack inside {[3 : 11]};
+ cycles_before_next_trans inside {[15 : 35]};
+ flips_before_io_clk_byp_ack inside {[0 : 3]};
+ flips_before_div_step_down_req inside {[0 : 3]};
+ flips_before_all_clk_byp_ack inside {[0 : 3]};
+ cycles_between_flips inside {[3 : 5]};
+ }
+
+ lc_tx_t lc_clk_byp_req;
+ lc_tx_t lc_debug_en;
+ mubi4_t io_clk_byp_ack_non_true;
+ mubi4_t all_clk_byp_ack_non_true;
+ mubi4_t div_step_down_req_non_true;
+
+ mubi4_t exp_all_clk_byp_ack;
+
+ function void post_randomize();
+ if (mubi_mode == ClkmgrMubiLcHand) begin
+ // increase weight of illegal value only in ClkmgrMubiLcHand
+ lc_clk_byp_req = get_rand_lc_tx_val(.t_weight(1), .f_weight(1), .other_weight(14));
+ end else begin
+ lc_clk_byp_req = get_rand_lc_tx_val(.t_weight(8), .f_weight(2), .other_weight(2));
+ end
+ if (mubi_mode == ClkmgrMubiLcCtrl) begin
+ // increase weight of illgal value only in ClkmgrMubiLcHand
+ lc_debug_en = get_rand_lc_tx_val(.t_weight(1), .f_weight(1), .other_weight(14));
+ end else begin
+ lc_debug_en = get_rand_lc_tx_val(.t_weight(8), .f_weight(2), .other_weight(2));
+ end
+
+ io_clk_byp_ack_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
+ all_clk_byp_ack_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
+ div_step_down_req_non_true = get_rand_mubi4_val(.t_weight(0), .f_weight(2), .other_weight(8));
+
+ `uvm_info(`gfn, $sformatf(
+ "randomize gives lc_clk_byp_req=0x%x, lc_debug_en=0x%x", lc_clk_byp_req, lc_debug_en),
+ UVM_MEDIUM)
+ super.post_randomize();
+
+ extclk_ctrl_sel = get_rand_mubi4_val(.t_weight(8), .f_weight(1), .other_weight(1));
+ `uvm_info(`gfn, $sformatf("overwrite extclk_ctrl_sel=0x%x", extclk_ctrl_sel), UVM_MEDIUM)
+
+ endfunction
+
+ // Notice only all_clk_byp_req and io_clk_byp_req Mubi4True and Mubi4False cause transitions.
+ local task delayed_update_all_clk_byp_ack(mubi4_t value, int cycles);
+ uvm_reg_data_t rd_data;
+
+ if (mubi_mode == ClkmgrMubiHand && value == MuBi4True) begin
+ repeat (flips_before_all_clk_byp_ack) begin
+ exp_all_clk_byp_ack = get_rand_mubi4_val(.t_weight(0), .f_weight(1), .other_weight(1));
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ cfg.clkmgr_vif.update_all_clk_byp_ack(exp_all_clk_byp_ack);
+ cfg.clk_rst_vif.wait_clks(4);
+ csr_rd(.ptr(ral.extclk_status), .value(rd_data));
+ // csr_rd_check didn't work well for status register read check
+ `DV_CHECK_EQ(exp_all_clk_byp_ack, rd_data, "extclk_status mismatch")
+ end
+ end
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ cfg.clkmgr_vif.update_all_clk_byp_ack(value);
+ endtask
+
+ local task delayed_update_div_step_down_req(mubi4_t value, int cycles);
+ if (mubi_mode == ClkmgrMubiDiv && value == MuBi4True) begin
+ repeat (flips_before_div_step_down_req) begin
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ cfg.clkmgr_vif.update_div_step_down_req(get_rand_mubi4_val(
+ .t_weight(0), .f_weight(1), .other_weight(1)));
+ end
+ end
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ `uvm_info(`gfn, $sformatf("Settling div_step_down_req to 0x%x", value), UVM_MEDIUM)
+ cfg.clkmgr_vif.update_div_step_down_req(value);
+ endtask
+
+ local task delayed_update_io_clk_byp_ack(mubi4_t value, int cycles);
+ if (mubi_mode == ClkmgrMubiHand && value == MuBi4True) begin
+ repeat (flips_before_io_clk_byp_ack) begin
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ cfg.clkmgr_vif.update_io_clk_byp_ack(get_rand_mubi4_val(
+ .t_weight(0), .f_weight(1), .other_weight(1)));
+ end
+ end
+ cfg.clk_rst_vif.wait_clks(cycles_between_flips);
+ `uvm_info(`gfn, $sformatf("Settling io_clk_byp_ack to 0x%x", value), UVM_MEDIUM)
+ cfg.clkmgr_vif.update_io_clk_byp_ack(value);
+ endtask
+
+ local task all_clk_byp_handshake();
+ forever
+ @cfg.clkmgr_vif.all_clk_byp_req begin : all_clk_byp_ack
+ if (cfg.clkmgr_vif.all_clk_byp_req == prim_mubi_pkg::MuBi4True) begin
+ `uvm_info(`gfn, "Got all_clk_byp_req on", UVM_MEDIUM)
+ fork
+ delayed_update_all_clk_byp_ack(MuBi4True, cycles_before_all_clk_byp_ack);
+ delayed_update_div_step_down_req(MuBi4True, cycles_before_div_step_down_req);
+ join
+ end else begin
+ `uvm_info(`gfn, "Got all_clk_byp_req off", UVM_MEDIUM)
+ // Set inputs to mubi4 non-True.
+ fork
+ delayed_update_all_clk_byp_ack(all_clk_byp_ack_non_true, cycles_before_all_clk_byp_ack);
+ delayed_update_div_step_down_req(div_step_down_req_non_true,
+ cycles_before_div_step_down_req);
+ join
+ end
+ end
+ endtask
+
+ local task io_clk_byp_handshake();
+ forever
+ @cfg.clkmgr_vif.io_clk_byp_req begin : io_clk_byp_ack
+ if (cfg.clkmgr_vif.io_clk_byp_req == MuBi4True) begin
+ `uvm_info(`gfn, "Got io_clk_byp_req True", UVM_MEDIUM)
+ fork
+ delayed_update_io_clk_byp_ack(MuBi4True, cycles_before_io_clk_byp_ack);
+ delayed_update_div_step_down_req(MuBi4True, cycles_before_div_step_down_req);
+ join
+ end else begin
+ `uvm_info(`gfn, "Got io_clk_byp_req non True", UVM_MEDIUM)
+ // Set inputs to mubi4 non-True.
+ fork
+ delayed_update_io_clk_byp_ack(io_clk_byp_ack_non_true, cycles_before_io_clk_byp_ack);
+ delayed_update_div_step_down_req(div_step_down_req_non_true,
+ cycles_before_div_step_down_req);
+ join
+ end
+ end
+ endtask
+
+ local task lc_clk_byp_handshake();
+ forever
+ @cfg.clkmgr_vif.lc_clk_byp_ack begin : lc_clk_byp_ack
+ if (cfg.clkmgr_vif.lc_clk_byp_ack == lc_ctrl_pkg::On) begin
+ `uvm_info(`gfn, "Got lc_clk_byp_ack on", UVM_MEDIUM)
+ end
+ end
+ endtask
+
+ local task run_test();
+ for (int i = 0; i < num_trans; ++i) begin
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ // Init needs to be synchronous.
+ @cfg.clk_rst_vif.cb begin
+ cfg.clkmgr_vif.init(.idle(idle), .scanmode(scanmode), .lc_debug_en(lc_debug_en));
+ control_ip_clocks();
+ end
+ fork
+ begin
+ cfg.clk_rst_vif.wait_clks(cycles_before_extclk_ctrl_sel);
+ csr_wr(.ptr(ral.extclk_ctrl), .value({extclk_ctrl_high_speed_sel, extclk_ctrl_sel}));
+ end
+ begin
+ cfg.clk_rst_vif.wait_clks(cycles_before_lc_clk_byp_req);
+ cfg.clkmgr_vif.update_lc_clk_byp_req(lc_clk_byp_req);
+ end
+ join
+ `uvm_info(`gfn, $sformatf(
+ {
+ "extclk_ctrl_sel=0x%0x, extclk_ctrl_high_speed_sel=0x%0x, lc_clk_byp_req=0x%0x, ",
+ "lc_debug_en=0x%0x, scanmode=0x%0x"
+ },
+ extclk_ctrl_sel,
+ extclk_ctrl_high_speed_sel,
+ lc_clk_byp_req,
+ lc_debug_en,
+ scanmode
+ ), UVM_MEDIUM)
+ csr_rd_check(.ptr(ral.extclk_ctrl),
+ .compare_value({extclk_ctrl_high_speed_sel, extclk_ctrl_sel}));
+ if (lc_clk_byp_req == lc_ctrl_pkg::On) begin
+ wait(cfg.clkmgr_vif.lc_clk_byp_req == lc_ctrl_pkg::On);
+ cfg.clk_rst_vif.wait_clks(cycles_before_lc_clk_byp_ack);
+ cfg.clkmgr_vif.update_lc_clk_byp_req(lc_ctrl_pkg::Off);
+ end
+ // Disable extclk software control.
+ csr_wr(.ptr(ral.extclk_ctrl), .value({Off, Off}));
+ cfg.clk_rst_vif.wait_clks(cycles_before_next_trans);
+ end
+ endtask
+
+ task body();
+ set_scanmode_on_low_weight();
+ csr_wr(.ptr(ral.extclk_ctrl_regwen), .value(1));
+
+ fork
+ begin : isolation_fork
+ fork
+ all_clk_byp_handshake();
+ io_clk_byp_handshake();
+ lc_clk_byp_handshake();
+ run_test();
+ join_any
+ disable fork;
+ end
+ join
+ endtask
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_timeout_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_timeout_vseq.sv
new file mode 100644
index 00000000000000..350073bdb9d962
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_timeout_vseq.sv
@@ -0,0 +1,142 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// The frequency timeout vseq exercises the frequency measurement counters. More details
+// in the clkmgr_testplan.hjson file.
+class clkmgr_frequency_timeout_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_frequency_timeout_vseq)
+
+ `uvm_object_new
+
+ // This is measured in aon clocks. We need to have a few rounds of measurement for timeouts to
+ // trigger, since they synchronize to the aon clock, and they wait for a few number of AON
+ // cycles before declaring a timeout.
+ localparam int CyclesToGetOneMeasurement = 12;
+
+ // If cause_timeout is set, turn off clk_timeout so it gets a timeout.
+ rand bit cause_timeout;
+ constraint cause_timeout_c {
+ cause_timeout dist {
+ 1 := 4,
+ 0 := 1
+ };
+ }
+ rand int clk_timeout;
+ constraint clk_timeout_c {clk_timeout inside {[ClkMesrIo : ClkMesrUsb]};}
+
+ constraint all_clk_en_c {
+ io_ip_clk_en == 1;
+ main_ip_clk_en == 1;
+ usb_ip_clk_en == 1;
+ }
+
+ // The clock that will be disabled.
+ clk_mesr_e clk_mesr_timeout;
+
+ // This waits a number of AON cycles so that the timeout can get detected.
+ task wait_before_read_recov_err_code();
+ cfg.aon_clk_rst_vif.wait_clks(CyclesToGetOneMeasurement);
+ endtask
+
+ // Get things back in normal order.
+ virtual task apply_resets_concurrently(int reset_duration_ps = 0);
+ super.apply_resets_concurrently(reset_duration_ps);
+ if (cause_timeout) disturb_measured_clock(.clk(clk_mesr_timeout), .enable(1'b1));
+ endtask
+
+ task body();
+ logic [TL_DW-1:0] value;
+ int prior_alert_count;
+ int current_alert_count;
+ csr_wr(.ptr(ral.measure_ctrl_regwen), .value(1));
+
+ // Make sure the aon clock is running as slow as it is meant to.
+ cfg.aon_clk_rst_vif.set_freq_khz(AonClkHz / 1_000);
+ control_ip_clocks();
+ // Wait so the frequency change takes effect.
+ cfg.aon_clk_rst_vif.wait_clks(2);
+
+ // Disable cip scoreboard exp_alert checks since they need very fine control, making checks
+ // really cumbersome. Instead we rely on the alert count to detect if alert were triggered.
+ cfg.scoreboard.do_alert_check = 0;
+
+ `uvm_info(`gfn, $sformatf("Will run %0d rounds", num_trans), UVM_MEDIUM)
+ for (int i = 0; i < num_trans; ++i) begin
+ clkmgr_recov_err_t actual_recov_err = '{default: '0};
+ logic [ClkMesrUsb:0] expected_recov_timeout_err = '0;
+ bit expect_alert = 0;
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ `uvm_info(`gfn, "New round", UVM_MEDIUM)
+
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ int min_threshold;
+ int max_threshold;
+ int expected = ExpectedCounts[clk];
+ min_threshold = expected - 2;
+ max_threshold = expected + 2;
+ enable_frequency_measurement(clk_mesr, min_threshold, max_threshold);
+ end
+
+ prior_alert_count = cfg.scoreboard.get_alert_count("recov_fault");
+ // Allow some cycles for measurements to start before turning off the clocks, since the
+ // measurement control CSRs are controlled by the clocks we intend to stop.
+ cfg.aon_clk_rst_vif.wait_clks(4);
+ clk_mesr_timeout = clk_mesr_e'(clk_timeout);
+
+ if (cause_timeout) begin
+ `uvm_info(`gfn, $sformatf("Will cause a timeout for clk %0s", clk_mesr_timeout.name()),
+ UVM_MEDIUM)
+ if (clk_mesr_timeout inside {ClkMesrIo, ClkMesrIoDiv2, ClkMesrIoDiv4}) begin
+ // All these clocks are derived from io so that gets disabled, and all derived
+ // clocks will get a timeout.
+ expected_recov_timeout_err[ClkMesrIo] = 1;
+ expected_recov_timeout_err[ClkMesrIoDiv2] = 1;
+ expected_recov_timeout_err[ClkMesrIoDiv4] = 1;
+ end else begin
+ expected_recov_timeout_err[clk_mesr_timeout] = 1;
+ end
+ disturb_measured_clock(.clk(clk_mesr_timeout), .enable(1'b0));
+ end
+ wait_before_read_recov_err_code();
+ if (cause_timeout) begin
+ disturb_measured_clock(.clk(clk_mesr_e'(clk_timeout)), .enable(1'b1));
+ end
+ csr_rd(.ptr(ral.recov_err_code), .value(actual_recov_err));
+ `uvm_info(`gfn, $sformatf("Got recov err register=0x%x", actual_recov_err), UVM_MEDIUM)
+ if (actual_recov_err.measures) begin
+ report_recov_error_mismatch("measurement", recov_bits_t'(0), actual_recov_err.measures);
+ end
+ if (!cfg.under_reset && actual_recov_err.timeouts != expected_recov_timeout_err) begin
+ report_recov_error_mismatch("timeout", expected_recov_timeout_err,
+ actual_recov_err.timeouts);
+ end
+ if (actual_recov_err.shadow_update != 0) begin
+ `uvm_error(`gfn, "Unexpected recoverable shadow update error")
+ end
+ // And check that the alert count increased if there was a timeout.
+ current_alert_count = cfg.scoreboard.get_alert_count("recov_fault");
+ if (cause_timeout) begin
+ if (!cfg.under_reset) begin
+ `DV_CHECK_NE(current_alert_count, prior_alert_count, "expected some alerts to fire")
+ end
+ end else begin
+ `DV_CHECK_EQ(current_alert_count, prior_alert_count, "expected no alerts to fire")
+ end
+
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ disable_frequency_measurement(clk_mesr);
+ end
+
+ // Wait enough time for measurements to complete, and for alerts to get processed
+ // by the alert agents so expected alerts are properly wound down.
+ cfg.aon_clk_rst_vif.wait_clks(6);
+ // And clear errors.
+ csr_wr(.ptr(ral.recov_err_code), .value('1));
+ cfg.aon_clk_rst_vif.wait_clks(2);
+ end
+ endtask : body
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_vseq.sv
new file mode 100644
index 00000000000000..9c7772c07cf1ab
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_frequency_vseq.sv
@@ -0,0 +1,236 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// The frequency vseq exercises the frequency measurement counters. More details
+// in the clkmgr_testplan.hjson file.
+class clkmgr_frequency_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_frequency_vseq)
+
+ `uvm_object_new
+
+ // This is measured in aon clocks. This is cannot be too precise because of a synchronizer.
+ localparam int CyclesToGetMeasurements = 6;
+
+ // The aon cycles between measurements, to make sure the previous measurement settles.
+ localparam int CyclesBetweenMeasurements = 6;
+
+ // This is measured in clkmgr clk_i clocks. It is set to cover worst case delays.
+ // The clk_i frequency is randomized for IPs, but the clkmgr is hooked to io_div4, which would
+ // allow a tighter number of cycles. Leaving the clk_i random probably provides more cases,
+ // so leaving it as is.
+ localparam int CyclesForErrUpdate = 16;
+
+ // The min ands max offsets from the expected counts. Notice the count occasionally matches
+ // expected_counts +- 2 because of CDC synchronizers, so the offsets are set carefully to
+ // avoid spurious results.
+ //
+ // The exp_alert cip feature requires a single alert at a time, so we set at most one of the
+ // clocks to fail measurement.
+ rand int clk_tested;
+ constraint clk_tested_c {clk_tested inside {[ClkMesrIo : ClkMesrUsb]};}
+
+ // If cause_saturation is active, force the initial measurement count of clk_tested to a high
+ // value so the counter will saturate.
+ rand bit cause_saturation;
+
+ typedef enum int {
+ MesrLow,
+ MesrRight,
+ MesrHigh
+ } mesr_e;
+ rand mesr_e mesr;
+ rand int min_offset;
+ rand int max_offset;
+
+ mubi4_t calib_rdy;
+
+ constraint thresholds_c {
+ solve clk_tested before mesr;
+ solve mesr before min_offset, max_offset;
+ if (mesr == MesrLow) {
+ min_offset inside {[-5 : -3]};
+ max_offset inside {[-5 : -3]};
+ min_offset <= max_offset;
+ } else
+ if (mesr == MesrRight) {
+ min_offset == -2;
+ max_offset == 2;
+ } else
+ if (mesr == MesrHigh) {
+ min_offset inside {[3 : 5]};
+ max_offset inside {[3 : 5]};
+ min_offset <= max_offset;
+ }
+ }
+
+ constraint all_clk_en_c {
+ io_ip_clk_en == 1;
+ main_ip_clk_en == 1;
+ usb_ip_clk_en == 1;
+ }
+
+ function void post_randomize();
+ calib_rdy = get_rand_mubi4_val(6, 2, 2);
+ `uvm_info(`gfn, $sformatf("randomize: calib_rdy=0x%x", calib_rdy), UVM_MEDIUM)
+ super.post_randomize();
+ endfunction
+
+ // Keep saturating the count on aon negedges if needed.
+ local task maybe_saturate_count(bit saturate, clk_mesr_e clk_tested);
+ forever begin
+ @cfg.aon_clk_rst_vif.cbn;
+ if (saturate) cfg.clkmgr_vif.force_high_starting_count(clk_mesr_e'(clk_tested));
+ end
+ endtask
+
+ // This waits a number of cycles so that:
+ // - at least one measurement completes, and,
+ // - the measurement has had time to update the recov_err_code CSR.
+ task wait_before_read_recov_err_code(bit expect_alert);
+ // Wait for one measurement (takes an extra cycle to really start).
+ cfg.aon_clk_rst_vif.wait_clks(CyclesToGetMeasurements);
+ // Wait for the result to propagate to the recov_err_code CSR.
+ cfg.clk_rst_vif.wait_clks(CyclesForErrUpdate);
+ endtask
+
+ // If clocks become uncalibrated measure_ctrl_regwen is re-enabled.
+ task check_measure_ctrl_regwen_for_calib_rdy();
+ logic value;
+ csr_wr(.ptr(ral.measure_ctrl_regwen), .value(0));
+ cfg.clkmgr_vif.update_calib_rdy(MuBi4False);
+ cfg.clk_rst_vif.wait_clks(20);
+ calibration_lost_checks();
+ endtask
+
+ task body();
+ logic [TL_DW-1:0] value;
+ int prior_alert_count;
+ int current_alert_count;
+
+ csr_wr(.ptr(ral.measure_ctrl_regwen), .value(1));
+
+ // Disable alert checks since we cannot make sure a single alert will fire: there is too
+ // much uncertainty on the cycles for one measurement to complete due to synchronizers.
+ // This test will instead check whether alerts fire using the alert count.
+ cfg.scoreboard.do_alert_check = 0;
+
+ // Make sure the aon clock is running as slow as it is meant to.
+ cfg.aon_clk_rst_vif.set_freq_khz(AonClkHz / 1_000);
+ control_ip_clocks();
+ // Wait so the frequency change takes effect.
+ cfg.aon_clk_rst_vif.wait_clks(2);
+
+ // Set the thresholds to get no error.
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ enable_frequency_measurement(clk_mesr, ExpectedCounts[clk] - 2, ExpectedCounts[clk] + 2);
+ end
+ wait_before_read_recov_err_code('0);
+ csr_rd_check(.ptr(ral.recov_err_code), .compare_value('0),
+ .err_msg("Expected no measurement errors"));
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ disable_frequency_measurement(clk_mesr);
+ end
+ cfg.aon_clk_rst_vif.wait_clks(CyclesBetweenMeasurements);
+ // And clear errors.
+ csr_wr(.ptr(ral.recov_err_code), .value('1));
+
+ `uvm_info(`gfn, $sformatf("Will run %0d rounds", num_trans), UVM_MEDIUM)
+ for (int i = 0; i < num_trans; ++i) begin
+ clkmgr_recov_err_t actual_recov_err = '{default: '0};
+ logic [ClkMesrUsb:0] expected_recov_meas_err = '0;
+ bit expect_alert = 0;
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ // Update calib_rdy input: if calibration is not ready the measurements
+ // don't happen, so we should not get faults.
+ cfg.clkmgr_vif.update_calib_rdy(calib_rdy);
+ `uvm_info(`gfn, $sformatf(
+ "Updating calib_rdy to 0x%x, predicted regwen 0x%x",
+ calib_rdy,
+ ral.measure_ctrl_regwen.get()
+ ), UVM_MEDIUM)
+ `uvm_info(`gfn, "New round", UVM_MEDIUM)
+ // Allow calib_rdy to generate side-effects.
+ cfg.clk_rst_vif.wait_clks(3);
+ if (calib_rdy == MuBi4False) calibration_lost_checks();
+ prior_alert_count = cfg.scoreboard.get_alert_count("recov_fault");
+ if (cause_saturation) `uvm_info(`gfn, "Will cause saturation", UVM_MEDIUM)
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ int min_threshold;
+ int max_threshold;
+ int expected = ExpectedCounts[clk];
+ if (clk == clk_tested) begin
+ min_threshold = expected + min_offset;
+ max_threshold = expected + max_offset;
+ if (calib_rdy != MuBi4False &&
+ (min_threshold > expected || max_threshold < expected - 1 || cause_saturation)) begin
+ `uvm_info(`gfn, $sformatf(
+ "Expect %0s to get a %0s error%0s",
+ clk_mesr.name,
+ (cause_saturation ? "fast" : (min_threshold > expected ? "slow" : "fast")),
+ (cause_saturation ? " due to saturation" : "")
+ ), UVM_MEDIUM)
+ expect_alert = 1;
+ expected_recov_meas_err[clk] = 1;
+ end
+ end else begin
+ min_threshold = expected - 2;
+ max_threshold = expected + 2;
+ end
+ enable_frequency_measurement(clk_mesr, min_threshold, max_threshold);
+ end
+
+ fork
+ begin : wait_for_measurements
+ fork
+ maybe_saturate_count(cause_saturation, clk_mesr_e'(clk_tested));
+ wait_before_read_recov_err_code(expect_alert);
+ join_any
+ disable fork;
+ end
+ join
+
+ csr_rd(.ptr(ral.recov_err_code), .value(actual_recov_err));
+ `uvm_info(`gfn, $sformatf("Expected recov err register=0x%x", expected_recov_meas_err),
+ UVM_MEDIUM)
+ if (!cfg.under_reset && actual_recov_err.measures != expected_recov_meas_err) begin
+ report_recov_error_mismatch("measurement", expected_recov_meas_err,
+ actual_recov_err.measures);
+ end
+ if (actual_recov_err.timeouts != '0) begin
+ `uvm_error(`gfn, $sformatf(
+ "Unexpected recoverable timeout error 0b%b", actual_recov_err.timeouts))
+ end
+ if (actual_recov_err.shadow_update != 0) begin
+ `uvm_error(`gfn, "Unexpected recoverable shadow update error")
+ end
+ // Check alerts.
+ current_alert_count = cfg.scoreboard.get_alert_count("recov_fault");
+ if (expect_alert) begin
+ if (!cfg.under_reset) begin
+ `DV_CHECK_NE(current_alert_count, prior_alert_count, "expected some alerts to fire")
+ end
+ end else begin
+ `DV_CHECK_EQ(current_alert_count, prior_alert_count, "expected no alerts to fire")
+ end
+
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ disable_frequency_measurement(clk_mesr);
+ end
+
+ // Wait enough time for measurements to complete, and for alerts to get processed
+ // by the alert agents so expected alerts are properly wound down.
+ cfg.aon_clk_rst_vif.wait_clks(CyclesBetweenMeasurements);
+ // And clear errors.
+ csr_wr(.ptr(ral.recov_err_code), .value('1));
+ cfg.aon_clk_rst_vif.wait_clks(12);
+ end
+ // And finally, check that unsetting calib_rdy causes meaesure_ctrl_regwen to be set to 1.
+ check_measure_ctrl_regwen_for_calib_rdy();
+ endtask
+
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv
new file mode 100644
index 00000000000000..8be1c46440eefb
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_peri_vseq.sv
@@ -0,0 +1,42 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Tests the control of the peripheral clocks using clk_enables CSR.
+//
+// This is more general than the corresponding smoke test since it randomizes the initial
+// value of clk_enables CSR and the ip_clk_en input.
+class clkmgr_peri_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_peri_vseq)
+
+ `uvm_object_new
+
+ rand peri_enables_t initial_enables;
+
+ // The clk_enables CSR cannot be manipulated in low power mode.
+ constraint io_ip_clk_en_on_c {io_ip_clk_en == 1'b1;}
+ constraint main_ip_clk_en_on_c {main_ip_clk_en == 1'b1;}
+ // ICEBOX(#17963) randomize the usb clk enable.
+ constraint usb_ip_clk_en_on_c {usb_ip_clk_en == 1'b1;}
+
+ task body();
+ for (int i = 0; i < num_trans; ++i) begin
+ peri_enables_t flipped_enables;
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+ cfg.clkmgr_vif.init(.idle(idle), .scanmode(scanmode));
+ control_ip_clocks();
+ csr_wr(.ptr(ral.clk_enables), .value(initial_enables));
+
+ // Flip all bits of clk_enables.
+ flipped_enables = initial_enables ^ ((1 << ral.clk_enables.get_n_bits()) - 1);
+ csr_wr(.ptr(ral.clk_enables), .value(flipped_enables));
+ // Allow some time for the side-effects to be observed: the dv environment sets the CSRs
+ // clock frequency randomly, so it may run too fast and the the updates may become a glitch
+ // that ends up not sampled in the SVAs.
+ cfg.clk_rst_vif.wait_clks(4);
+ end
+ // And set it back to the reset value for stress tests.
+ cfg.clk_rst_vif.wait_clks(1);
+ csr_wr(.ptr(ral.clk_enables), .value(ral.clk_enables.get_reset()));
+ endtask : body
+endclass : clkmgr_peri_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv
new file mode 100644
index 00000000000000..d81c12ed568557
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_regwen_vseq.sv
@@ -0,0 +1,82 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// The regwen vseq attempts to write to registers whose regwen is randomly on or off to check
+// the register contents is not updated when off. More details in the clkmgr_testplan.hjson file.
+class clkmgr_regwen_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_regwen_vseq)
+
+ `uvm_object_new
+
+ task check_extclk_regwen();
+ bit enable;
+ int prev_value;
+ int new_value = {extclk_ctrl_high_speed_sel, extclk_ctrl_sel};
+ `DV_CHECK_STD_RANDOMIZE_FATAL(enable)
+ `uvm_info(`gfn, $sformatf("Check extclk_ctrl regwen set to %b begin", enable), UVM_MEDIUM)
+ csr_wr(.ptr(ral.extclk_ctrl_regwen), .value(enable));
+ csr_rd(.ptr(ral.extclk_ctrl), .value(prev_value));
+ csr_wr(.ptr(ral.extclk_ctrl), .value(new_value));
+ csr_rd_check(.ptr(ral.extclk_ctrl), .compare_value(enable ? new_value : prev_value));
+ `uvm_info(`gfn, "Check extclk_ctrl regwen end", UVM_MEDIUM)
+ endtask : check_extclk_regwen
+
+ // This must be careful to turn measurements off right after checking the updates
+ // to avoid measurement errors. We could set the thresholds correctly, but we
+ // might as well set them randomly for good measure. Carefully masks only the
+ // real bits for the comparison.
+ task check_meas_ctrl_regwen();
+ bit regwen_enable;
+ `DV_CHECK_STD_RANDOMIZE_FATAL(regwen_enable)
+ csr_wr(.ptr(ral.measure_ctrl_regwen), .value(regwen_enable));
+ foreach (ExpectedCounts[clk]) begin
+ clk_mesr_e clk_mesr = clk_mesr_e'(clk);
+ uvm_reg ctrl_shadowed = meas_ctrl_regs[clk_mesr].ctrl_lo.get_dv_base_reg_parent();
+ uvm_reg_data_t prev_en;
+ mubi4_t new_en = get_rand_mubi4_val(1, 1, 2);
+ int prev_ctrl;
+ int new_ctrl = $urandom();
+ int actual_ctrl;
+ int lo_mask = ((1 << meas_ctrl_regs[clk_mesr].ctrl_lo.get_n_bits()) - 1) <<
+ meas_ctrl_regs[clk_mesr].ctrl_lo.get_lsb_pos();
+ int hi_mask = ((1 << meas_ctrl_regs[clk_mesr].ctrl_hi.get_n_bits()) - 1) <<
+ meas_ctrl_regs[clk_mesr].ctrl_hi.get_lsb_pos();
+ `uvm_info(`gfn, $sformatf(
+ "Check %0s regwen set to %b begin", meas_ctrl_regs[clk_mesr].name, regwen_enable),
+ UVM_MEDIUM)
+ csr_rd(.ptr(meas_ctrl_regs[clk_mesr].en), .value(prev_en));
+ csr_rd(.ptr(ctrl_shadowed), .value(prev_ctrl));
+ csr_wr(.ptr(ctrl_shadowed), .value(new_ctrl));
+ csr_wr(.ptr(meas_ctrl_regs[clk_mesr].en), .value(new_en));
+ csr_rd_check(.ptr(meas_ctrl_regs[clk_mesr].en),
+ .compare_value(mubi4_t'(regwen_enable ? new_en : prev_en)));
+ csr_rd_check(.ptr(ctrl_shadowed), .compare_value(regwen_enable ? new_ctrl : prev_ctrl),
+ .compare_mask(lo_mask | hi_mask));
+ `uvm_info(`gfn, $sformatf("Check %0s regwen end", meas_ctrl_regs[clk_mesr].name),
+ UVM_MEDIUM)
+ csr_wr(.ptr(meas_ctrl_regs[clk_mesr].en), .value(MuBi4False));
+ end
+ endtask : check_meas_ctrl_regwen
+
+ task body();
+ // Make sure the aon clock is running as slow as it is meant to, otherwise the aon clock
+ // runs fast enough that we could end up triggering faults due to the random settings for
+ // the thresholds.
+ cfg.aon_clk_rst_vif.set_freq_khz(AonClkHz / 1_000);
+
+ `uvm_info(`gfn, $sformatf("Will run %0d rounds", num_trans), UVM_MEDIUM)
+ for (int i = 0; i < num_trans; ++i) begin
+ check_extclk_regwen();
+ check_meas_ctrl_regwen();
+ apply_reset("HARD");
+ // This is to make sure we don't start writes immediately after reset,
+ // otherwise the tl_agent could mistakenly consider the following read
+ // happens during reset.
+ cfg.clk_rst_vif.wait_clks(4);
+ csr_rd_check(.ptr(ral.extclk_ctrl_regwen), .compare_value(1));
+ csr_rd_check(.ptr(ral.measure_ctrl_regwen), .compare_value(1));
+ end
+ endtask : body
+
+endclass : clkmgr_regwen_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv
new file mode 100644
index 00000000000000..a3f1b6f6575dd2
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_smoke_vseq.sv
@@ -0,0 +1,108 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// smoke test vseq
+class clkmgr_smoke_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_smoke_vseq)
+
+ `uvm_object_new
+
+ constraint io_ip_clk_en_on_c {io_ip_clk_en == 1'b1;}
+ constraint main_ip_clk_en_on_c {main_ip_clk_en == 1'b1;}
+ constraint usb_ip_clk_en_on_c {usb_ip_clk_en == 1'b1;}
+ constraint all_busy_c {idle == IdleAllBusy;}
+
+ task body();
+ cfg.clk_rst_vif.wait_clks(10);
+ test_jitter();
+ test_peri_clocks();
+ test_trans_clocks();
+ endtask : body
+
+ // Simply flip the jitter enable CSR. The side-effects are checked in the scoreboard.
+ // This needs to be done outside the various CSR tests, since they update the jitter_enable
+ // CSR, but the scoreboard is disabled for those tests.
+ task test_jitter();
+ prim_mubi_pkg::mubi4_t jitter_value;
+ for (int i = 0; i < (1 << $bits(prim_mubi_pkg::mubi4_t)); ++i) begin
+ jitter_value = prim_mubi_pkg::mubi4_t'(i);
+ csr_wr(.ptr(ral.jitter_enable), .value(jitter_value));
+ csr_rd_check(.ptr(ral.jitter_enable), .compare_value(jitter_value));
+ // And set it back.
+ cfg.clk_rst_vif.wait_clks(6);
+ csr_wr(.ptr(ral.jitter_enable), .value('0));
+ csr_rd_check(.ptr(ral.jitter_enable), .compare_value('0));
+ end
+ endtask
+
+ // Flips all clk_enables bits from the reset value with all enabled. All is checked
+ // via assertions in clkmgr_if.sv and behavioral code in the scoreboard.
+ task test_peri_clocks();
+ // Flip all bits of clk_enables.
+ peri_enables_t value = ral.clk_enables.get();
+ peri_enables_t flipped_value;
+ csr_rd(.ptr(ral.clk_enables), .value(value));
+ flipped_value = value ^ ((1 << ral.clk_enables.get_n_bits()) - 1);
+ csr_wr(.ptr(ral.clk_enables), .value(flipped_value));
+
+ // And set it back to the reset value for stress tests.
+ cfg.clk_rst_vif.wait_clks(1);
+ csr_wr(.ptr(ral.clk_enables), .value(ral.clk_enables.get_reset()));
+ endtask : test_peri_clocks
+
+ // Starts with all units busy, and for each one this clears the hint and reads the hint status,
+ // expecting it to remain at 1 since the unit is busy; then it sets the corresponding idle bit
+ // and reads status again, expecting it to be low.
+ //
+ // We disable the value checks when reset is active since the reads return unpredictable data.
+ task test_trans_clocks();
+ trans_e trans;
+ logic bit_value;
+ logic [TL_DW-1:0] value;
+ mubi_hintables_t idle;
+ hintables_t bool_idle;
+ typedef struct {
+ trans_e unit;
+ uvm_reg_field hint_bit;
+ uvm_reg_field value_bit;
+ } trans_descriptor_t;
+ trans_descriptor_t trans_descriptors[NUM_TRANS] = '{
+ '{TransAes, ral.clk_hints.clk_main_aes_hint, ral.clk_hints_status.clk_main_aes_val},
+ '{TransHmac, ral.clk_hints.clk_main_hmac_hint, ral.clk_hints_status.clk_main_hmac_val},
+ '{TransKmac, ral.clk_hints.clk_main_kmac_hint, ral.clk_hints_status.clk_main_kmac_val},
+ '{TransOtbn, ral.clk_hints.clk_main_otbn_hint, ral.clk_hints_status.clk_main_otbn_val}
+ };
+ idle = 0;
+ // Changes in idle take at least 10 cycles to stick.
+ cfg.clkmgr_vif.update_idle(idle);
+ cfg.clk_rst_vif.wait_clks(IDLE_SYNC_CYCLES);
+
+ trans = trans.first;
+ csr_rd(.ptr(ral.clk_hints), .value(value));
+ `uvm_info(`gfn, $sformatf("Starting hints at 0x%0x, idle at 0x%x", value, idle), UVM_MEDIUM)
+ do begin
+ trans_descriptor_t descriptor = trans_descriptors[int'(trans)];
+ `uvm_info(`gfn, $sformatf("Clearing %s hint bit", descriptor.unit.name), UVM_MEDIUM)
+ csr_wr(.ptr(descriptor.hint_bit), .value(1'b0));
+ csr_rd(.ptr(descriptor.value_bit), .value(bit_value));
+ if (!cfg.under_reset) begin
+ `DV_CHECK_EQ(bit_value, 1'b1, $sformatf(
+ "%s hint value cannot drop while busy", descriptor.unit.name()))
+ end
+ `uvm_info(`gfn, $sformatf("Setting %s idle bit", descriptor.unit.name), UVM_MEDIUM)
+ cfg.clk_rst_vif.wait_clks(1);
+ idle[trans] = prim_mubi_pkg::MuBi4True;
+ cfg.clkmgr_vif.update_idle(idle);
+ // Some cycles for the logic to settle.
+ cfg.clk_rst_vif.wait_clks(IDLE_SYNC_CYCLES);
+ csr_rd(.ptr(descriptor.value_bit), .value(bit_value));
+ if (!cfg.under_reset) begin
+ `DV_CHECK_EQ(bit_value, 1'b0, $sformatf(
+ "%s hint value should drop when idle", descriptor.unit.name()))
+ end
+ trans = trans.next();
+ end while (trans != trans.first);
+ csr_wr(.ptr(ral.clk_hints), .value(ral.clk_hints.get_reset()));
+ endtask : test_trans_clocks
+endclass : clkmgr_smoke_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_stress_all_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_stress_all_vseq.sv
new file mode 100644
index 00000000000000..c2b2e5ea32028e
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_stress_all_vseq.sv
@@ -0,0 +1,44 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// combine all clkmgr seqs (except below seqs) in one seq to run sequentially
+// 1. csr seq, which requires scb to be disabled
+class clkmgr_stress_all_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_stress_all_vseq)
+
+ `uvm_object_new
+
+ task body();
+ string seq_names[] = {
+ "clkmgr_extclk_vseq",
+ "clkmgr_frequency_timeout_vseq",
+ "clkmgr_frequency_vseq",
+ "clkmgr_peri_vseq",
+ "clkmgr_smoke_vseq",
+ "clkmgr_trans_vseq"
+ };
+ for (int i = 1; i <= num_trans; i++) begin
+ uvm_sequence seq;
+ clkmgr_base_vseq clkmgr_vseq;
+ uint seq_idx = $urandom_range(0, seq_names.size - 1);
+
+ seq = create_seq_by_name(seq_names[seq_idx]);
+ `downcast(clkmgr_vseq, seq)
+
+ // if upper seq disables do_apply_reset for this seq, then can't issue reset
+ // as upper seq may drive reset
+ if (do_apply_reset) clkmgr_vseq.do_apply_reset = $urandom_range(0, 1);
+ else clkmgr_vseq.do_apply_reset = 0;
+ clkmgr_vseq.set_sequencer(p_sequencer);
+ `DV_CHECK_RANDOMIZE_FATAL(clkmgr_vseq)
+ `uvm_info(`gfn, $sformatf("seq_idx = %0d, sequence is %0s", seq_idx, clkmgr_vseq.get_name()),
+ UVM_MEDIUM)
+
+ clkmgr_vseq.start(p_sequencer);
+ `uvm_info(`gfn, $sformatf(
+ "End of sequence %0s with seq_idx = %0d", clkmgr_vseq.get_name(), seq_idx),
+ UVM_MEDIUM)
+ end
+ endtask : body
+endclass
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv
new file mode 100644
index 00000000000000..7df237b9c3e8c4
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_trans_vseq.sv
@@ -0,0 +1,96 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// trans test vseq
+// This is a more randomized version of the corresponding test in the smoke sequence.
+// Starts with random units busy, set the hints at random. The idle units whose hint bit is off
+// will be disabled, but the others will remain enabled. Then all units are made idle to check
+// that status matches hints. Prior to the next round this raises all hints so all unit clocks are
+// running.
+//
+// Transitions to turn off the clock only go through if idle is asserted for at least 10 main
+// cycles, and there is additional synchronizer overhead.
+//
+// The checks for whether each unit's clock are running are done in SVA. This sequence only
+// explicitly checks hints_status.
+
+class clkmgr_trans_vseq extends clkmgr_base_vseq;
+ `uvm_object_utils(clkmgr_trans_vseq)
+
+ `uvm_object_new
+
+ rand hintables_t initial_hints;
+
+ // The clk_hints CSR cannot be manipulated in low power mode.
+ constraint io_ip_clk_en_on_c {io_ip_clk_en == 1'b1;}
+ constraint main_ip_clk_en_on_c {main_ip_clk_en == 1'b1;}
+ constraint usb_ip_clk_en_on_c {usb_ip_clk_en == 1'b1;}
+
+ task body();
+ for (int i = 0; i < num_trans; ++i) begin
+ logic bit_value;
+ hintables_t value;
+ hintables_t bool_idle;
+
+ `DV_CHECK_RANDOMIZE_FATAL(this)
+
+ csr_rd(.ptr(ral.clk_hints_status), .value(value));
+
+ `uvm_info(`gfn, $sformatf("Initial clk_hints_status: %b", value), UVM_MEDIUM)
+ cfg.clkmgr_vif.init(.idle(idle), .scanmode(scanmode));
+
+ // add random value if mubi idle test
+ if (mubi_mode == ClkmgrMubiIdle) drive_idle(idle);
+ print_mubi_hintable(idle);
+ control_ip_clocks();
+ `uvm_info(`gfn, $sformatf("Idle = 0x%x", cfg.clkmgr_vif.idle_i), UVM_MEDIUM)
+ cfg.clk_rst_vif.wait_clks(10);
+ `uvm_info(`gfn, $sformatf("Updating hints to 0x%0x", initial_hints), UVM_MEDIUM)
+ csr_wr(.ptr(ral.clk_hints), .value(initial_hints));
+
+ // Extra wait because of synchronizers plus counters.
+ cfg.clk_rst_vif.wait_clks(IDLE_SYNC_CYCLES);
+ // We expect the status to be determined by hints and idle, ignoring scanmode.
+ bool_idle = mubi_hintables_to_hintables(idle);
+ value = initial_hints | ~bool_idle;
+ csr_rd_check(.ptr(ral.clk_hints_status), .compare_value(value),
+ .err_msg($sformatf(
+ "Busy units have status high: hints=0x%x, idle=0x%x",
+ initial_hints,
+ bool_idle
+ )));
+
+ // Setting all idle should make hint_status match hints.
+ `uvm_info(`gfn, "Setting all units idle", UVM_MEDIUM)
+ cfg.clkmgr_vif.update_idle({NUM_TRANS{MuBi4True}});
+ cfg.clk_rst_vif.wait_clks(IDLE_SYNC_CYCLES);
+
+ csr_rd_check(.ptr(ral.clk_hints_status), .compare_value(initial_hints),
+ .err_msg("All idle: expect status matches hints"));
+
+ // Now set all hints, and the status should also be all ones.
+ value = '1;
+ csr_wr(.ptr(ral.clk_hints), .value(value));
+ cfg.clk_rst_vif.wait_clks(IDLE_SYNC_CYCLES);
+ // We expect all units to be on.
+ csr_rd_check(.ptr(ral.clk_hints_status), .compare_value(value),
+ .err_msg("All idle and all hints high: units status should be high"));
+
+ // Set hints to the reset value for stress tests.
+ csr_wr(.ptr(ral.clk_hints), .value(ral.clk_hints.get_reset()));
+ end
+ endtask : body
+
+ task drive_idle(ref mubi_hintables_t tbl);
+ int period;
+ mubi_hintables_t rand_idle;
+ foreach (rand_idle[i])
+ rand_idle[i] = get_rand_mubi4_val(.t_weight(0), .f_weight(0), .other_weight(1));
+
+ @cfg.clkmgr_vif.trans_cb;
+ cfg.clkmgr_vif.idle_i = rand_idle;
+
+ tbl = rand_idle;
+ endtask : drive_idle
+endclass : clkmgr_trans_vseq
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_vseq_list.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_vseq_list.sv
new file mode 100644
index 00000000000000..d95307f983c52e
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/env/seq_lib/clkmgr_vseq_list.sv
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "clkmgr_base_vseq.sv"
+`include "clkmgr_clk_status_vseq.sv"
+`include "clkmgr_common_vseq.sv"
+`include "clkmgr_frequency_timeout_vseq.sv"
+`include "clkmgr_frequency_vseq.sv"
+`include "clkmgr_extclk_vseq.sv"
+`include "clkmgr_peri_vseq.sv"
+`include "clkmgr_regwen_vseq.sv"
+`include "clkmgr_smoke_vseq.sv"
+`include "clkmgr_stress_all_vseq.sv"
+`include "clkmgr_trans_vseq.sv"
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_aon_cg_en_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_aon_cg_en_sva_if.sv
new file mode 100644
index 00000000000000..1b05e078e91e62
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_aon_cg_en_sva_if.sv
@@ -0,0 +1,16 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions for clock gating output to alert_handler for
+// AON clocks: they are never gated off.
+interface clkmgr_aon_cg_en_sva_if (
+ input logic clk,
+ input logic rst_n,
+ input logic cg_en
+);
+
+ bit disable_sva;
+
+ `ASSERT_INIT_NET(CgEn_A, !cg_en)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_bind.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_bind.sv
new file mode 100644
index 00000000000000..ad85e08cede1c1
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_bind.sv
@@ -0,0 +1,373 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module clkmgr_bind;
+`ifndef GATE_LEVEL
+ bind clkmgr tlul_assert #(
+ .EndpointType("Device")
+ ) tlul_assert_device (.clk_i, .rst_ni, .h2d(tl_i), .d2h(tl_o));
+
+
+ // In top-level testbench, do not bind the csr_assert_fpv to reduce simulation time.
+`ifndef TOP_LEVEL_DV
+ bind clkmgr clkmgr_csr_assert_fpv clkmgr_csr_assert (.clk_i, .rst_ni, .h2d(tl_i), .d2h(tl_o));
+`endif
+
+ bind clkmgr clkmgr_pwrmgr_sva_if clkmgr_pwrmgr_sva_if (
+ .clk_i,
+ .rst_ni,
+ .io_clk_en(pwr_i.io_ip_clk_en),
+ .io_status(pwr_o.io_status),
+ .main_clk_en(pwr_i.main_ip_clk_en),
+ .main_status(pwr_o.main_status),
+ .usb_clk_en(pwr_i.usb_ip_clk_en),
+ .usb_status(pwr_o.usb_status)
+ );
+
+ bind clkmgr clkmgr_gated_clock_sva_if clkmgr_io_div4_peri_sva_if (
+ .clk(clocks_o.clk_io_div4_powerup),
+ .rst_n(rst_io_div4_ni),
+ .ip_clk_en(pwr_i.io_ip_clk_en),
+ .sw_clk_en(reg2hw.clk_enables.clk_io_div4_peri_en.q),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .gated_clk(clocks_o.clk_io_div4_peri)
+ );
+
+ bind clkmgr clkmgr_gated_clock_sva_if clkmgr_io_div2_peri_sva_if (
+ .clk(clocks_o.clk_io_div2_powerup),
+ .rst_n(rst_io_div2_ni),
+ .ip_clk_en(pwr_i.io_ip_clk_en),
+ .sw_clk_en(reg2hw.clk_enables.clk_io_div2_peri_en.q),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .gated_clk(clocks_o.clk_io_div2_peri)
+ );
+
+ bind clkmgr clkmgr_gated_clock_sva_if clkmgr_io_peri_sva_if (
+ .clk(clocks_o.clk_io_powerup),
+ .rst_n(rst_io_ni),
+ .ip_clk_en(pwr_i.io_ip_clk_en),
+ .sw_clk_en(reg2hw.clk_enables.clk_io_peri_en.q),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .gated_clk(clocks_o.clk_io_peri)
+ );
+
+ bind clkmgr clkmgr_gated_clock_sva_if clkmgr_usb_peri_sva_if (
+ .clk(clocks_o.clk_usb_powerup),
+ .rst_n(rst_usb_ni),
+ .ip_clk_en(pwr_i.usb_ip_clk_en),
+ .sw_clk_en(reg2hw.clk_enables.clk_usb_peri_en.q),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .gated_clk(clocks_o.clk_usb_peri)
+ );
+
+ // Assertions for transactional clocks.
+ bind clkmgr clkmgr_trans_sva_if clkmgr_aes_trans_sva_if (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .hint(reg2hw.clk_hints.clk_main_aes_hint.q),
+ .idle(idle_i[0] == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .status(hw2reg.clk_hints_status.clk_main_aes_val.d),
+ .trans_clk(clocks_o.clk_main_aes)
+ );
+
+ bind clkmgr clkmgr_trans_sva_if clkmgr_hmac_trans_sva_if (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .hint(reg2hw.clk_hints.clk_main_hmac_hint.q),
+ .idle(idle_i[1] == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .status(hw2reg.clk_hints_status.clk_main_hmac_val.d),
+ .trans_clk(clocks_o.clk_main_hmac)
+ );
+
+ bind clkmgr clkmgr_trans_sva_if clkmgr_kmac_trans_sva_if (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .hint(reg2hw.clk_hints.clk_main_kmac_hint.q),
+ .idle(idle_i[2] == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .status(hw2reg.clk_hints_status.clk_main_kmac_val.d),
+ .trans_clk(clocks_o.clk_main_kmac)
+ );
+
+ bind clkmgr clkmgr_trans_sva_if clkmgr_otbn_trans_sva_if (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .hint(reg2hw.clk_hints.clk_main_otbn_hint.q),
+ .idle(idle_i[3] == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True),
+ .status(hw2reg.clk_hints_status.clk_main_otbn_val.d),
+ .trans_clk(clocks_o.clk_main_otbn)
+ );
+
+ bind clkmgr clkmgr_extclk_sva_if clkmgr_extclk_sva_if (
+ .clk_i,
+ .rst_ni,
+ .extclk_ctrl_sel,
+ .extclk_ctrl_hi_speed_sel,
+ .lc_hw_debug_en_i,
+ .lc_clk_byp_req_i,
+ .io_clk_byp_req_o,
+ .all_clk_byp_req_o,
+ .hi_speed_sel_o
+ );
+
+ bind clkmgr clkmgr_div_sva_if #(
+ .DIV(2)
+ ) clkmgr_div2_sva_if (
+ .clk(clocks_o.clk_io_powerup),
+ .rst_n(rst_ni),
+ .maybe_divided_clk(clocks_o.clk_io_div2_powerup),
+ .div_step_down_req_i(div_step_down_req_i == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True)
+ );
+
+ // The div2 clk also steps, so not a good reference. Instead, check it always tracks io_div2.
+ bind clkmgr clkmgr_div_sva_if #(
+ .DIV(4)
+ ) clkmgr_div4_sva_if (
+ .clk(clocks_o.clk_io_div2_powerup),
+ .rst_n(rst_ni),
+ .maybe_divided_clk(clocks_o.clk_io_div4_powerup),
+ .div_step_down_req_i(div_step_down_req_i == prim_mubi_pkg::MuBi4True),
+ .scanmode(scanmode_i == prim_mubi_pkg::MuBi4True)
+ );
+
+ // AON clock gating enables.
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_aon_peri (
+ .clk(clk_aon_i), .rst_n(rst_aon_ni), .cg_en(cg_en_o.aon_peri == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_aon_powerup (
+ .clk(clk_aon_i), .rst_n(rst_aon_ni), .cg_en(cg_en_o.aon_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_aon_secure (
+ .clk(clk_aon_i), .rst_n(rst_aon_ni), .cg_en(cg_en_o.aon_secure == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_aon_timers (
+ .clk(clk_aon_i), .rst_n(rst_aon_ni), .cg_en(cg_en_o.aon_timers == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_io_powerup (
+ .clk(clk_io_i), .rst_n(rst_io_ni), .cg_en(cg_en_o.io_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_io_div2_powerup (
+ .clk(clk_io_div2),
+ .rst_n(rst_io_div2_ni),
+ .cg_en(cg_en_o.io_div2_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_io_div4_powerup (
+ .clk(clk_io_div4),
+ .rst_n(rst_io_div4_ni),
+ .cg_en(cg_en_o.io_div4_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_main_powerup (
+ .clk(clk_main_i), .rst_n(rst_main_ni), .cg_en(cg_en_o.main_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_aon_cg_en_sva_if clkmgr_aon_cg_usb_powerup (
+ .clk(clk_usb_i), .rst_n(rst_usb_ni), .cg_en(cg_en_o.usb_powerup == prim_mubi_pkg::MuBi4True)
+ );
+
+ // Non-AON clock gating enables.
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div2_infra (
+ .clk(clk_io_div2),
+ .rst_n(rst_io_div2_ni),
+ .ip_clk_en(clk_io_div2_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div2_infra == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div4_infra (
+ .clk(clk_io_div4),
+ .rst_n(rst_io_div4_ni),
+ .ip_clk_en(clk_io_div4_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div4_infra == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_infra (
+ .clk(clk_io_i),
+ .rst_n(rst_io_ni),
+ .ip_clk_en(clk_io_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_infra == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_infra (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_infra == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div4_secure (
+ .clk(clk_io_div4),
+ .rst_n(rst_io_div4_ni),
+ .ip_clk_en(clk_io_div4_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div4_secure == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_secure (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_secure == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div4_timers (
+ .clk(clk_io_div4),
+ .rst_n(rst_io_div4_ni),
+ .ip_clk_en(clk_io_div4_en),
+ .sw_clk_en(1'b1),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div4_timers == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div2_peri (
+ .clk(clk_io_div2),
+ .rst_n(rst_io_div2_ni),
+ .ip_clk_en(clk_io_div2_en),
+ .sw_clk_en(clk_io_div2_peri_sw_en),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div2_peri == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_div4_peri (
+ .clk(clk_io_div4),
+ .rst_n(rst_io_div4_ni),
+ .ip_clk_en(clk_io_div4_en),
+ .sw_clk_en(clk_io_div4_peri_sw_en),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_div4_peri == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_io_peri (
+ .clk(clk_io_i),
+ .rst_n(rst_io_ni),
+ .ip_clk_en(clk_io_en),
+ .sw_clk_en(clk_io_peri_sw_en),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.io_peri == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_usb_peri (
+ .clk(clk_usb_i),
+ .rst_n(rst_usb_ni),
+ .ip_clk_en(clk_usb_en),
+ .sw_clk_en(clk_usb_peri_sw_en),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.usb_peri == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_aes (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(u_clk_main_aes_trans.sw_hint_synced || !u_clk_main_aes_trans.idle_valid),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_aes == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_hmac (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(u_clk_main_hmac_trans.sw_hint_synced || !u_clk_main_hmac_trans.idle_valid),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_hmac == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_kmac (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(u_clk_main_kmac_trans.sw_hint_synced || !u_clk_main_kmac_trans.idle_valid),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_kmac == prim_mubi_pkg::MuBi4True)
+ );
+
+ bind clkmgr clkmgr_cg_en_sva_if clkmgr_cg_main_otbn (
+ .clk(clk_main_i),
+ .rst_n(rst_main_ni),
+ .ip_clk_en(clk_main_en),
+ .sw_clk_en(u_clk_main_otbn_trans.sw_hint_synced || !u_clk_main_otbn_trans.idle_valid),
+ .scanmode(prim_mubi_pkg::MuBi4False),
+ .cg_en(cg_en_o.main_otbn == prim_mubi_pkg::MuBi4True)
+ );
+
+ // Calibration assertions.
+ bind clkmgr clkmgr_lost_calib_regwen_sva_if clkmgr_lost_calib_regwen_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_regwen(u_reg.measure_ctrl_regwen_qs)
+ );
+
+ bind clkmgr clkmgr_lost_calib_ctrl_en_sva_if clkmgr_lost_calib_io_ctrl_en_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_en(u_reg.io_meas_ctrl_en_qs)
+ );
+
+ bind clkmgr clkmgr_lost_calib_ctrl_en_sva_if clkmgr_lost_calib_io_div2_ctrl_en_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_en(u_reg.io_div2_meas_ctrl_en_qs)
+ );
+
+ bind clkmgr clkmgr_lost_calib_ctrl_en_sva_if clkmgr_lost_calib_io_div4_ctrl_en_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_en(u_reg.io_div4_meas_ctrl_en_qs)
+ );
+
+ bind clkmgr clkmgr_lost_calib_ctrl_en_sva_if clkmgr_lost_calib_main_ctrl_en_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_en(u_reg.main_meas_ctrl_en_qs)
+ );
+
+ bind clkmgr clkmgr_lost_calib_ctrl_en_sva_if clkmgr_lost_calib_usb_ctrl_en_sva_if (
+ .clk(clk_i),
+ .rst_n(rst_ni),
+ .calib_rdy(calib_rdy_i),
+ .meas_ctrl_en(u_reg.usb_meas_ctrl_en_qs)
+ );
+
+ bind clkmgr clkmgr_sec_cm_checker_assert clkmgr_sec_cm_checker_assert (
+ .clk_i,
+ .rst_ni,
+ .all_clk_byp_req_o,
+ .lc_hw_debug_en_i,
+ .lc_clk_byp_req_i,
+ .lc_clk_byp_ack_o,
+ .io_clk_byp_req_o,
+ // internal signal is picked due to inconsistent t->f, f->t delay
+ .io_clk_byp_ack(u_clkmgr_byp.io_clk_byp_ack),
+ // internal signal is picked due to inconsistent input to signal delay
+ .step_down_acks_sync(u_clkmgr_byp.step_down_acks_sync),
+ .extclk_ctrl_sel
+ );
+`endif
+endmodule : clkmgr_bind
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_cg_en_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_cg_en_sva_if.sv
new file mode 100644
index 00000000000000..6c9a99c8c2275a
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_cg_en_sva_if.sv
@@ -0,0 +1,30 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions for clock gating output to alert_handler.
+// - cg_en corresponds to clock gating enabled, which means the clock is gated,
+// thus inactive.
+// - ip_clk_en and sw_clk_en have the opposite polarity: when they are active
+// the clock is enabled.
+interface clkmgr_cg_en_sva_if
+ import prim_mubi_pkg::*;
+(
+ input logic clk,
+ input logic rst_n,
+ input logic ip_clk_en,
+ input logic sw_clk_en,
+ input prim_mubi_pkg::mubi4_t scanmode,
+ input logic cg_en
+);
+
+ bit disable_sva;
+
+ logic clk_enable;
+ always_comb clk_enable = ip_clk_en && sw_clk_en;
+
+ `ASSERT(CgEnOn_A, $fell(clk_enable) |=> ##[0:2] clk_enable || cg_en, clk,
+ !rst_n || scanmode == prim_mubi_pkg::MuBi4True || disable_sva)
+ `ASSERT(CgEnOff_A, $rose(clk_enable) |=> ##[0:2] !clk_enable || !cg_en, clk,
+ !rst_n || scanmode == prim_mubi_pkg::MuBi4True || disable_sva)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_div_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_div_sva_if.sv
new file mode 100644
index 00000000000000..1940a9176599c9
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_div_sva_if.sv
@@ -0,0 +1,68 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions for clock dividers.
+// - For div2 (DIV == 2) the reference clk is io clock, which is never stepped.
+// So when step_down check that the divided clock tracks the reference. This
+// means we check at negedge, or we would see nothing interesting.
+// - For div4 (DIV == 4) the reference clk is io_div2 clock, which is also stepped.
+// So check it is always twice as slow, except during transitions.
+//
+// All checks at negedges for simplicity.
+interface clkmgr_div_sva_if #(
+ parameter int DIV = 2
+) (
+ input logic clk,
+ input logic rst_n,
+ input logic maybe_divided_clk,
+ input logic div_step_down_req_i,
+ input logic scanmode
+);
+
+ localparam int WAIT_CYCLES = 20;
+ logic step_down;
+ always_comb step_down = div_step_down_req_i && !scanmode;
+
+ logic step_up;
+ always_comb step_up = !step_down;
+
+ sequence WholeLeadHigh_S;
+ step_down || maybe_divided_clk ##1 step_down || !maybe_divided_clk;
+ endsequence
+
+ sequence WholeLeadLow_S;
+ step_down || !maybe_divided_clk ##1 step_down || maybe_divided_clk;
+ endsequence
+
+ if (DIV == 2) begin : g_div2
+
+ sequence TracksClk_S; step_up || maybe_divided_clk ##1 step_up || maybe_divided_clk; endsequence
+
+ // Notice this fires at negedges, since maybe_divided_clk's value will be on when
+ // tracking.
+ `ASSERT(Div2Stepped_A, $rose(step_down) ##1 step_down [* WAIT_CYCLES] |-> TracksClk_S, !clk,
+ !rst_n)
+ `ASSERT(Div2Whole_A,
+ $fell(step_down) ##1 !step_down [* WAIT_CYCLES] |-> WholeLeadLow_S or WholeLeadHigh_S,
+ !clk, !rst_n)
+
+ end else begin : g_div4
+
+ sequence StepLeadHigh_S;
+ step_up || maybe_divided_clk ##1 step_up || !maybe_divided_clk;
+ endsequence
+
+ sequence StepLeadLow_S;
+ step_up || !maybe_divided_clk ##1 step_up || maybe_divided_clk;
+ endsequence
+
+ `ASSERT(Div4Stepped_A,
+ $rose(step_down) ##1 step_down [* WAIT_CYCLES] |-> StepLeadLow_S or StepLeadHigh_S,
+ !clk, !rst_n)
+ `ASSERT(Div4Whole_A,
+ $fell(step_down) ##1 !step_down [* WAIT_CYCLES] |-> WholeLeadLow_S or WholeLeadHigh_S,
+ !clk, !rst_n)
+
+ end
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_extclk_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_extclk_sva_if.sv
new file mode 100644
index 00000000000000..dcd1d2dc440f0d
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_extclk_sva_if.sv
@@ -0,0 +1,81 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions to check the external clock bypass control outputs.
+//
+// Notice when a condition fails we allow the logic to generate non strict mubi values. Ideally it
+// would generate mubi False: see https://github.com/lowRISC/opentitan/issues/11400.
+interface clkmgr_extclk_sva_if
+ import prim_mubi_pkg::*, lc_ctrl_pkg::*;
+(
+ input logic clk_i,
+ input logic rst_ni,
+ input mubi4_t extclk_ctrl_sel,
+ input mubi4_t extclk_ctrl_hi_speed_sel,
+ input lc_tx_t lc_hw_debug_en_i,
+ input lc_tx_t lc_clk_byp_req_i,
+ input mubi4_t io_clk_byp_req_o,
+ input mubi4_t all_clk_byp_req_o,
+ input mubi4_t hi_speed_sel_o
+);
+
+ // The times are to cover the clock domain synchronizers.
+ localparam int FallCyclesMin = 1;
+ localparam int FallCyclesMax = 3;
+
+ localparam int RiseCyclesMin = 1;
+ localparam int RiseCyclesMax = 3;
+
+ bit disable_sva;
+
+ // Check lc_clk_byp_req_i triggers io_clk_byp_req_o.
+ logic lc_clk_byp_req;
+ always_comb lc_clk_byp_req = lc_clk_byp_req_i == On;
+
+ `ASSERT(IoClkBypReqRise_A,
+ $rose(
+ lc_clk_byp_req
+ ) |=> ##[RiseCyclesMin:RiseCyclesMax] !lc_clk_byp_req || (io_clk_byp_req_o == MuBi4True),
+ clk_i, !rst_ni || disable_sva)
+ `ASSERT(IoClkBypReqFall_A,
+ $fell(
+ lc_clk_byp_req
+ ) |=> ##[FallCyclesMin:FallCyclesMax] lc_clk_byp_req || (io_clk_byp_req_o != MuBi4False),
+ clk_i, !rst_ni || disable_sva)
+
+ // Check extclk_ctrl triggers all_clk_byp_req_o and hi_speed_sel_o.
+ logic extclk_sel_enabled;
+ always_comb extclk_sel_enabled = extclk_ctrl_sel == MuBi4True && lc_hw_debug_en_i == On;
+
+ `ASSERT(AllClkBypReqRise_A,
+ $rose(
+ extclk_sel_enabled
+ ) |=> ##[RiseCyclesMin:RiseCyclesMax]
+ !extclk_sel_enabled || (all_clk_byp_req_o == MuBi4True),
+ clk_i, !rst_ni || disable_sva)
+ `ASSERT(AllClkBypReqFall_A,
+ $fell(
+ extclk_sel_enabled
+ ) |=> ##[FallCyclesMin:FallCyclesMax]
+ extclk_sel_enabled || (all_clk_byp_req_o != MuBi4True),
+ clk_i, !rst_ni || disable_sva)
+
+ logic hi_speed_enabled;
+ always_comb begin
+ hi_speed_enabled = extclk_ctrl_sel == MuBi4True && extclk_ctrl_hi_speed_sel == MuBi4True &&
+ lc_hw_debug_en_i == On;
+ end
+
+ `ASSERT(HiSpeedSelRise_A,
+ $rose(
+ hi_speed_enabled
+ ) |=> ##[RiseCyclesMin:RiseCyclesMax] !hi_speed_enabled || (hi_speed_sel_o == MuBi4True),
+ clk_i, !rst_ni || disable_sva)
+ `ASSERT(HiSpeedSelFall_A,
+ $fell(
+ hi_speed_enabled
+ ) |=> ##[FallCyclesMin:FallCyclesMax] hi_speed_enabled || (hi_speed_sel_o != MuBi4True),
+ clk_i, !rst_ni || disable_sva)
+
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_gated_clock_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_gated_clock_sva_if.sv
new file mode 100644
index 00000000000000..98677ff94afe69
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_gated_clock_sva_if.sv
@@ -0,0 +1,26 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions for gated clocks.
+interface clkmgr_gated_clock_sva_if (
+ input logic clk,
+ input logic rst_n,
+ input logic ip_clk_en,
+ input logic sw_clk_en,
+ input logic scanmode,
+ input logic gated_clk
+);
+ // This fires at negedges: if the gated clock is inactive its value is expected to be low,
+ // and viceversa. The assertions pass if clk_enabled is not stable to avoid cycle accuracy, and
+ // these gated clocks are expected to be changed infrequently.
+ logic clk_enabled;
+ always_comb clk_enabled = sw_clk_en && ip_clk_en || scanmode;
+
+ `ASSERT(GateOpen_A,
+ $rose(clk_enabled) |=> ##[0:3] !clk_enabled || $changed(clk_enabled) || gated_clk, !clk,
+ !rst_n)
+ `ASSERT(GateClose_A,
+ $fell(clk_enabled) |=> ##[0:3] clk_enabled || $changed(clk_enabled) || !gated_clk, !clk,
+ !rst_n)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_ctrl_en_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_ctrl_en_sva_if.sv
new file mode 100644
index 00000000000000..d9fa0d528271ea
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_ctrl_en_sva_if.sv
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions to check losing calibration turns off clock measurements.
+
+interface clkmgr_lost_calib_ctrl_en_sva_if (
+ input logic clk,
+ input logic rst_n,
+ input logic [$bits(prim_mubi_pkg::mubi4_t)-1:0] calib_rdy,
+ input logic [$bits(prim_mubi_pkg::mubi4_t)-1:0] meas_ctrl_en
+);
+ // There are two clocks involved, the clock measured and the clkmgr clk_i.
+ // The latter is io_div4 so it is pretty slow compared to all others. There
+ // are a number of clock domain crossings, so this needs a large number of
+ // wait cycles to account for the worst case.
+ localparam int MAX_CYCLES = 45;
+ `ASSERT(CtrlEnOn_A,
+ (calib_rdy == prim_mubi_pkg::MuBi4False && meas_ctrl_en != prim_mubi_pkg::MuBi4False) |=>
+ ##[0:MAX_CYCLES] (meas_ctrl_en == prim_mubi_pkg::MuBi4False),
+ clk, !rst_n)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_regwen_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_regwen_sva_if.sv
new file mode 100644
index 00000000000000..e8b12a0b687223
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_lost_calib_regwen_sva_if.sv
@@ -0,0 +1,17 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions to check losing calibration enables crtl regwen.
+
+interface clkmgr_lost_calib_regwen_sva_if (
+ input logic clk,
+ input logic rst_n,
+ input prim_mubi_pkg::mubi4_t calib_rdy,
+ input logic meas_ctrl_regwen
+);
+ localparam int MAX_CYCLES = 6;
+ `ASSERT(RegwenOff_A,
+ (calib_rdy == prim_mubi_pkg::MuBi4False) |=> ##[0:MAX_CYCLES] meas_ctrl_regwen, clk,
+ !rst_n)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.core
new file mode 100644
index 00000000000000..a99dc606934199
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.core
@@ -0,0 +1,19 @@
+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:dv:clkmgr_pwrmgr_sva_if:0.1"
+description: "CLKMGR to PWRMGR assertion interface."
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:mubi
+ files:
+ - clkmgr_pwrmgr_sva_if.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.sv
new file mode 100644
index 00000000000000..6d02f318dcab0e
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_pwrmgr_sva_if.sv
@@ -0,0 +1,56 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions to check that rising or falling edges of the various ip_clk_en
+// are followed by corresponding edges of their clk_status.
+interface clkmgr_pwrmgr_sva_if (
+ input logic clk_i,
+ input logic rst_ni,
+ input logic io_clk_en,
+ input logic io_status,
+ input logic main_clk_en,
+ input logic main_status,
+ input logic usb_clk_en,
+ input logic usb_status
+);
+
+ // The max times are longer to cover the different clock domain synchronizers.
+ // Ideally they would use the io_div4 clock, but it gets turned off when io_ip_clk_en
+ // goes inactive.
+ localparam int FallCyclesMin = 0;
+ localparam int FallCyclesMax = 20;
+
+ localparam int RiseCyclesMin = 0;
+ localparam int RiseCyclesMax = 20;
+
+ // Assuming io_div4 : 24MHz, AON : 200KHz
+ localparam int AonCycleInClki = 120;
+
+ // Since io_div4 and Aon is not aligned, max cycle delay
+ // can be 2 + 1 cycles fo AON clk.
+ localparam int UsbRiseCyclesMax = 3 * AonCycleInClki;
+
+ bit disable_sva;
+
+ `ASSERT(IoStatusFall_A,
+ $fell(io_clk_en) |-> ##[FallCyclesMin:FallCyclesMax] io_clk_en || !io_status, clk_i,
+ !rst_ni || disable_sva)
+ `ASSERT(IoStatusRise_A,
+ $rose(io_clk_en) |-> ##[RiseCyclesMin:RiseCyclesMax] !io_clk_en || io_status, clk_i,
+ !rst_ni || disable_sva)
+
+ `ASSERT(MainStatusFall_A,
+ $fell(main_clk_en) |-> ##[FallCyclesMin:FallCyclesMax] main_clk_en || !main_status, clk_i,
+ !rst_ni || disable_sva)
+ `ASSERT(MainStatusRise_A,
+ $rose(main_clk_en) |-> ##[RiseCyclesMin:RiseCyclesMax] !main_clk_en || main_status, clk_i,
+ !rst_ni || disable_sva)
+
+ `ASSERT(UsbStatusFall_A,
+ $fell(usb_clk_en) |-> ##[FallCyclesMin:FallCyclesMax] usb_clk_en || !usb_status, clk_i,
+ !rst_ni || disable_sva)
+ `ASSERT(UsbStatusRise_A,
+ $rose(usb_clk_en) |-> ##[RiseCyclesMin:UsbRiseCyclesMax] !usb_clk_en || usb_status, clk_i,
+ !rst_ni || disable_sva)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sec_cm_checker_assert.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sec_cm_checker_assert.sv
new file mode 100644
index 00000000000000..13cdf1d074cefa
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sec_cm_checker_assert.sv
@@ -0,0 +1,59 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// Assertion checker for external clock bypass
+// sec cm test
+module clkmgr_sec_cm_checker_assert (
+ input clk_i,
+ input rst_ni,
+ input prim_mubi_pkg::mubi4_t all_clk_byp_req_o,
+ input lc_ctrl_pkg::lc_tx_t lc_hw_debug_en_i,
+ input lc_ctrl_pkg::lc_tx_t lc_clk_byp_req_i,
+ input lc_ctrl_pkg::lc_tx_t lc_clk_byp_ack_o,
+ input prim_mubi_pkg::mubi4_t io_clk_byp_req_o,
+ input prim_mubi_pkg::mubi4_t io_clk_byp_ack,
+ input logic [1:0] step_down_acks_sync,
+ input prim_mubi_pkg::mubi4_t extclk_ctrl_sel
+);
+
+ bit disable_sva;
+ bit reset_or_disable;
+
+ always_comb reset_or_disable = !rst_ni || disable_sva;
+
+ // sec_cm_lc_ctrl_intersig_mubi
+ `ASSERT(AllClkBypReqTrue_A,
+ lc_hw_debug_en_i == lc_ctrl_pkg::On && extclk_ctrl_sel == prim_mubi_pkg::MuBi4True |=>
+ all_clk_byp_req_o == prim_mubi_pkg::MuBi4True,
+ clk_i, reset_or_disable)
+ `ASSERT(AllClkBypReqFalse_A,
+ lc_hw_debug_en_i != lc_ctrl_pkg::On || extclk_ctrl_sel != prim_mubi_pkg::MuBi4True |=>
+ all_clk_byp_req_o != prim_mubi_pkg::MuBi4True,
+ clk_i, reset_or_disable)
+
+ // sec_cm_lc_ctrl_clk_handshake_intersig_mubi
+ `ASSERT(IoClkBypReqTrue_A,
+ lc_clk_byp_req_i == lc_ctrl_pkg::On |=> ##[2:3]
+ io_clk_byp_req_o == prim_mubi_pkg::MuBi4True, clk_i, reset_or_disable)
+ `ASSERT(IoClkBypReqFalse_A,
+ lc_clk_byp_req_i != lc_ctrl_pkg::On |=> ##[2:3]
+ io_clk_byp_req_o == prim_mubi_pkg::MuBi4False, clk_i, reset_or_disable)
+
+ // sec_cm_clk_handshake_intersig_mubi, sec_cm_div_intersig_mubi
+ `ASSERT(LcClkBypAckTrue_A,
+ step_down_acks_sync == 2'b11 && io_clk_byp_ack == prim_mubi_pkg::MuBi4True |=> ($past(
+ lc_clk_byp_req_i, 3
+ ) == lc_clk_byp_ack_o) || ($past(
+ lc_clk_byp_req_i, 4
+ ) != $past(
+ lc_clk_byp_req_i, 3
+ )),
+ clk_i, reset_or_disable)
+ `ASSERT(LcClkBypAckFalse_A,
+ step_down_acks_sync != 2'b11 ||
+ io_clk_byp_ack != prim_mubi_pkg::MuBi4True |=>
+ lc_clk_byp_ack_o == lc_ctrl_pkg::Off,
+ clk_i, reset_or_disable)
+
+endmodule : clkmgr_sec_cm_checker_assert
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva.core
new file mode 100644
index 00000000000000..074efeefe9a2e0
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva.core
@@ -0,0 +1,40 @@
+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:dv:clkmgr_sva:0.1"
+description: "CLKMGR assertion modules and bind file."
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:tlul:headers
+ - lowrisc:fpv:csr_assert_gen
+ - lowrisc:dv:clkmgr_sva_ifs
+ files:
+ - clkmgr_bind.sv
+ - clkmgr_sec_cm_checker_assert.sv
+ file_type: systemVerilogSource
+
+ files_formal:
+ depend:
+ - lowrisc:ip_interfaces:clkmgr
+
+generate:
+ csr_assert_gen:
+ generator: csr_assert_gen
+ parameters:
+ spec: ../../data/clkmgr.hjson
+
+targets:
+ default: &default_target
+ filesets:
+ - files_dv
+ generate:
+ - csr_assert_gen
+
+ formal:
+ <<: *default_target
+ filesets:
+ - files_formal
+ - files_dv
+ toplevel: clkmgr
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva_ifs.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva_ifs.core
new file mode 100644
index 00000000000000..9f8fec693b3c79
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_sva_ifs.core
@@ -0,0 +1,28 @@
+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:dv:clkmgr_sva_ifs:0.1"
+description: "CLKMGR SVA interfaces."
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:prim:assert
+ - lowrisc:prim:mubi
+ - lowrisc:ip:lc_ctrl_pkg
+ - lowrisc:dv:clkmgr_pwrmgr_sva_if
+ files:
+ - clkmgr_aon_cg_en_sva_if.sv
+ - clkmgr_cg_en_sva_if.sv
+ - clkmgr_div_sva_if.sv
+ - clkmgr_extclk_sva_if.sv
+ - clkmgr_gated_clock_sva_if.sv
+ - clkmgr_lost_calib_ctrl_en_sva_if.sv
+ - clkmgr_lost_calib_regwen_sva_if.sv
+ - clkmgr_trans_sva_if.sv
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_trans_sva_if.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_trans_sva_if.sv
new file mode 100644
index 00000000000000..e1d8bac2bdd0b1
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/sva/clkmgr_trans_sva_if.sv
@@ -0,0 +1,35 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// This contains SVA assertions for trans clocks.
+interface clkmgr_trans_sva_if (
+ input logic clk,
+ input logic rst_n,
+ input logic hint,
+ input logic idle,
+ input logic scanmode,
+ input logic status,
+ input logic trans_clk
+);
+ // This fires at negedges: if the trans clock is inactive its value is expected to be low, and
+ // viceversa. The clock takes some cycles to react to idle and hint.
+ localparam int MIN_START_CYCLES = 0;
+ localparam int MAX_START_CYCLES = 3;
+
+ localparam int MIN_STOP_CYCLES = 2;
+ localparam int MAX_STOP_CYCLES = 15;
+
+ `ASSERT(TransStart_A,
+ $rose(
+ hint
+ ) ##1 hint [* MIN_START_CYCLES] |=>
+ ##[0:MAX_START_CYCLES-MIN_START_CYCLES] !hint || trans_clk,
+ !clk, !rst_n)
+ `ASSERT(TransStop_A,
+ $fell(
+ hint || !idle || scanmode
+ ) ##1 !hint && !scanmode [* MIN_STOP_CYCLES] |=>
+ ##[0:MAX_STOP_CYCLES-MIN_STOP_CYCLES] hint || scanmode || !trans_clk,
+ !clk, !rst_n)
+endinterface
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/tb.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tb.sv
new file mode 100644
index 00000000000000..36c4381ee0148b
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tb.sv
@@ -0,0 +1,211 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+module tb;
+ // dep packages
+ import uvm_pkg::*;
+ import dv_utils_pkg::*;
+ import clkmgr_env_pkg::*;
+ import clkmgr_test_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ wire clk, rst_n, rst_shadowed_n;
+ wire clk_main, rst_main_n;
+ wire clk_io, rst_io_n;
+ wire clk_usb, rst_usb_n;
+ wire clk_aon, rst_aon_n;
+
+ // clock interfaces
+ clk_rst_if clk_rst_if (
+ .clk (clk),
+ .rst_n(rst_n)
+ );
+ clk_rst_if main_clk_rst_if (
+ .clk (clk_main),
+ .rst_n(rst_main_n)
+ );
+ clk_rst_if io_clk_rst_if (
+ .clk (clk_io),
+ .rst_n(rst_io_n)
+ );
+ clk_rst_if usb_clk_rst_if (
+ .clk (clk_usb),
+ .rst_n(rst_usb_n)
+ );
+ clk_rst_if aon_clk_rst_if (
+ .clk (clk_aon),
+ .rst_n(rst_aon_n)
+ );
+ clk_rst_if root_io_clk_rst_if (
+ .clk (),
+ .rst_n(rst_root_io_n)
+ );
+ clk_rst_if root_main_clk_rst_if (
+ .clk (),
+ .rst_n(rst_root_main_n)
+ );
+ clk_rst_if root_usb_clk_rst_if (
+ .clk (),
+ .rst_n(rst_root_usb_n)
+ );
+
+ tl_if tl_if (
+ .clk (clk),
+ .rst_n(rst_n)
+ );
+
+ // The clkmgr interface.
+ clkmgr_if clkmgr_if (
+ .clk(clk),
+ .rst_n(rst_n),
+ .clk_main(clk_main),
+ .rst_io_n(rst_io_n),
+ .rst_main_n(rst_main_n),
+ .rst_usb_n(rst_usb_n)
+ );
+
+ bind clkmgr clkmgr_csrs_if clkmgr_csrs_if (
+ .clk(clk_i),
+ .recov_err_csr({
+ u_reg.u_recov_err_code_usb_timeout_err.qs,
+ u_reg.u_recov_err_code_main_timeout_err.qs,
+ u_reg.u_recov_err_code_io_div4_timeout_err.qs,
+ u_reg.u_recov_err_code_io_div2_timeout_err.qs,
+ u_reg.u_recov_err_code_io_timeout_err.qs,
+ u_reg.u_recov_err_code_usb_measure_err.qs,
+ u_reg.u_recov_err_code_main_measure_err.qs,
+ u_reg.u_recov_err_code_io_div4_measure_err.qs,
+ u_reg.u_recov_err_code_io_div2_measure_err.qs,
+ u_reg.u_recov_err_code_io_measure_err.qs,
+ u_reg.u_recov_err_code_shadow_update_err.qs
+ }),
+ .fatal_err_csr({
+ u_reg.u_fatal_err_code_shadow_storage_err.qs,
+ u_reg.u_fatal_err_code_idle_cnt.qs,
+ u_reg.u_fatal_err_code_reg_intg.qs
+ }),
+ .clk_enables({
+ reg2hw.clk_enables.clk_usb_peri_en.q,
+ reg2hw.clk_enables.clk_io_peri_en.q,
+ reg2hw.clk_enables.clk_io_div2_peri_en.q,
+ reg2hw.clk_enables.clk_io_div4_peri_en.q}),
+ .clk_hints({
+ reg2hw.clk_hints.clk_main_otbn_hint.q,
+ reg2hw.clk_hints.clk_main_kmac_hint.q,
+ reg2hw.clk_hints.clk_main_hmac_hint.q,
+ reg2hw.clk_hints.clk_main_aes_hint.q})
+ );
+
+ rst_shadowed_if rst_shadowed_if (
+ .rst_n(rst_n),
+ .rst_shadowed_n(rst_shadowed_n)
+ );
+
+ initial begin
+ // Clocks must be set to active at time 0. The rest of the clock configuration happens
+ // in clkmgr_base_vseq.sv.
+ clk_rst_if.set_active();
+ main_clk_rst_if.set_active();
+ io_clk_rst_if.set_active();
+ usb_clk_rst_if.set_active();
+ aon_clk_rst_if.set_active();
+
+ root_io_clk_rst_if.set_active();
+ root_main_clk_rst_if.set_active();
+ root_usb_clk_rst_if.set_active();
+ end
+
+ `DV_ALERT_IF_CONNECT()
+
+ // dut
+ clkmgr dut (
+ .clk_i(clk),
+ .rst_ni(rst_n),
+ .rst_shadowed_ni(rst_shadowed_n),
+
+ .clk_main_i (clk_main),
+ .rst_main_ni(rst_main_n),
+ .clk_io_i (clk_io),
+ // ICEBOX(#17934): differentiate the io resets to check they generate the
+ // expected side-effects. Probably doable with a very simple test.
+ .rst_io_ni (rst_io_n),
+ .rst_io_div2_ni(rst_io_n),
+ .rst_io_div4_ni(rst_io_n),
+ .clk_usb_i (clk_usb),
+ .rst_usb_ni (rst_usb_n),
+ .clk_aon_i (clk_aon),
+ .rst_aon_ni (rst_aon_n),
+
+ // ICEBOX(#17934): differentiate the root resets as mentioned for rst_io_ni above.
+ .rst_root_ni(rst_root_io_n),
+ .rst_root_io_ni(rst_root_io_n),
+ .rst_root_io_div2_ni(rst_root_io_n),
+ .rst_root_io_div4_ni(rst_root_io_n),
+ .rst_root_main_ni(rst_root_main_n),
+ .rst_root_usb_ni(rst_root_usb_n),
+
+ .tl_i(tl_if.h2d),
+ .tl_o(tl_if.d2h),
+
+ .alert_rx_i(alert_rx),
+ .alert_tx_o(alert_tx),
+
+ .pwr_i(clkmgr_if.pwr_i),
+ .pwr_o(clkmgr_if.pwr_o),
+
+ .scanmode_i(clkmgr_if.scanmode_i),
+ .idle_i (clkmgr_if.idle_i),
+
+ .lc_hw_debug_en_i(clkmgr_if.lc_hw_debug_en_i),
+ .all_clk_byp_req_o(clkmgr_if.all_clk_byp_req),
+ .all_clk_byp_ack_i(clkmgr_if.all_clk_byp_ack),
+ .io_clk_byp_req_o(clkmgr_if.io_clk_byp_req),
+ .io_clk_byp_ack_i(clkmgr_if.io_clk_byp_ack),
+ .lc_clk_byp_req_i(clkmgr_if.lc_clk_byp_req),
+ .lc_clk_byp_ack_o(clkmgr_if.lc_clk_byp_ack),
+ .div_step_down_req_i(clkmgr_if.div_step_down_req),
+
+ .cg_en_o(),
+
+ .jitter_en_o(clkmgr_if.jitter_en_o),
+ .clocks_o (clkmgr_if.clocks_o),
+
+ .calib_rdy_i(clkmgr_if.calib_rdy),
+ .hi_speed_sel_o(clkmgr_if.hi_speed_sel)
+ );
+
+ initial begin
+ // Register interfaces with uvm.
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "main_clk_rst_vif", main_clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "io_clk_rst_vif", io_clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "usb_clk_rst_vif", usb_clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "aon_clk_rst_vif", aon_clk_rst_if);
+
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "root_io_clk_rst_vif",
+ root_io_clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "root_main_clk_rst_vif",
+ root_main_clk_rst_if);
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "root_usb_clk_rst_vif",
+ root_usb_clk_rst_if);
+
+ uvm_config_db#(virtual clkmgr_if)::set(null, "*.env", "clkmgr_vif", clkmgr_if);
+
+ uvm_config_db#(virtual clkmgr_csrs_if)::set(null, "*.env", "clkmgr_csrs_vif",
+ dut.clkmgr_csrs_if);
+
+ // FIXME Un-comment this once interrupts are created for this ip.
+ // uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if);
+
+ uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
+ uvm_config_db#(virtual rst_shadowed_if)::set(null, "*.env", "rst_shadowed_vif",
+ rst_shadowed_if);
+ $timeformat(-12, 0, " ps", 12);
+ run_test();
+ end
+
+endmodule
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_base_test.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_base_test.sv
new file mode 100644
index 00000000000000..fda2cb69f672e0
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_base_test.sv
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class clkmgr_base_test extends cip_base_test #(
+ .CFG_T(clkmgr_env_cfg),
+ .ENV_T(clkmgr_env)
+);
+
+ `uvm_component_utils(clkmgr_base_test)
+ `uvm_component_new
+
+ // the base class dv_base_test creates the following instances:
+ // clkmgr_env_cfg: cfg
+ // clkmgr_env: env
+
+ // the base class also looks up UVM_TEST_SEQ plusarg to create and run that seq in
+ // the run_phase; as such, nothing more needs to be done
+
+endclass : clkmgr_base_test
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test.core b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test.core
new file mode 100644
index 00000000000000..2174e34c1ea6a8
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test.core
@@ -0,0 +1,19 @@
+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:dv:clkmgr_test:0.1"
+description: "CLKMGR DV UVM test"
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:clkmgr_env
+ files:
+ - clkmgr_test_pkg.sv
+ - clkmgr_base_test.sv: {is_include_file: true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test_pkg.sv b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test_pkg.sv
new file mode 100644
index 00000000000000..3411b2e197f141
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/dv/tests/clkmgr_test_pkg.sv
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package clkmgr_test_pkg;
+ // dep packages
+ import uvm_pkg::*;
+ import cip_base_pkg::*;
+ import clkmgr_env_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ // local types
+
+ // functions
+
+ // package sources
+ `include "clkmgr_base_test.sv"
+
+endpackage
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.vlt b/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.vlt
new file mode 100644
index 00000000000000..a3aadb827143ff
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.vlt
@@ -0,0 +1,5 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// waiver file for rstmgr
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.waiver b/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.waiver
new file mode 100644
index 00000000000000..2c3203bf791214
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/lint/clkmgr.waiver
@@ -0,0 +1,17 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# waiver file for clkmgr
+
+#
+# fake errors
+
+waive -rules INPUT_NOT_READ -location {prim_clock_gating.sv} -regexp {.*} \
+ -comment "Generated abstraction files use .*'s which create fake errors"
+
+waive -rules EMPTY_PARAM_LIST -location {prim_clock_gating.sv} -regexp {.*} \
+ -comment "Generated abstraction files may have empty params"
+
+waive -rules OUTPUT_NOT_DRIVEN -location {prim_clock_gating.sv} -regexp {.*} \
+ -comment "Generated abstraction files do not detect drivers"
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr.sv
new file mode 100644
index 00000000000000..c82336f5864e02
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr.sv
@@ -0,0 +1,1095 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// The overall clock manager
+
+
+`include "prim_assert.sv"
+
+ module clkmgr
+ import clkmgr_pkg::*;
+ import clkmgr_reg_pkg::*;
+ import lc_ctrl_pkg::lc_tx_t;
+ import prim_mubi_pkg::mubi4_t;
+#(
+ parameter logic [NumAlerts-1:0] AlertAsyncOn = {NumAlerts{1'b1}}
+) (
+ // Primary module control clocks and resets
+ // This drives the register interface
+ input clk_i,
+ input rst_ni,
+ input rst_shadowed_ni,
+
+ // System clocks and resets
+ // These are the source clocks for the system
+ input clk_main_i,
+ input rst_main_ni,
+ input clk_io_i,
+ input rst_io_ni,
+ input clk_usb_i,
+ input rst_usb_ni,
+ input clk_aon_i,
+ input rst_aon_ni,
+
+ // Resets for derived clocks
+ // clocks are derived locally
+ input rst_io_div2_ni,
+ input rst_io_div4_ni,
+
+ // Resets for derived clock generation, root clock gating and related status
+ input rst_root_ni,
+ input rst_root_main_ni,
+ input rst_root_io_ni,
+ input rst_root_io_div2_ni,
+ input rst_root_io_div4_ni,
+ input rst_root_usb_ni,
+
+ // Bus Interface
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+
+ // Alerts
+ input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i,
+ output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o,
+
+ // pwrmgr interface
+ input pwrmgr_pkg::pwr_clk_req_t pwr_i,
+ output pwrmgr_pkg::pwr_clk_rsp_t pwr_o,
+
+ // dft interface
+ input prim_mubi_pkg::mubi4_t scanmode_i,
+
+ // idle hints
+ // SEC_CM: IDLE.INTERSIG.MUBI
+ input prim_mubi_pkg::mubi4_t [3:0] idle_i,
+
+ // life cycle state output
+ // SEC_CM: LC_CTRL.INTERSIG.MUBI
+ input lc_tx_t lc_hw_debug_en_i,
+
+ // clock bypass control with lc_ctrl
+ // SEC_CM: LC_CTRL_CLK_HANDSHAKE.INTERSIG.MUBI
+ input lc_tx_t lc_clk_byp_req_i,
+ output lc_tx_t lc_clk_byp_ack_o,
+
+ // clock bypass control with ast
+ // SEC_CM: CLK_HANDSHAKE.INTERSIG.MUBI
+ output mubi4_t io_clk_byp_req_o,
+ input mubi4_t io_clk_byp_ack_i,
+ output mubi4_t all_clk_byp_req_o,
+ input mubi4_t all_clk_byp_ack_i,
+ output mubi4_t hi_speed_sel_o,
+
+ // clock calibration has been done.
+ // If this is signal is 0, assume clock frequencies to be
+ // uncalibrated.
+ input prim_mubi_pkg::mubi4_t calib_rdy_i,
+
+ // jittery enable to ast
+ output mubi4_t jitter_en_o,
+
+ // external indication for whether dividers should be stepped down
+ // SEC_CM: DIV.INTERSIG.MUBI
+ input mubi4_t div_step_down_req_i,
+
+ // clock gated indications going to alert handlers
+ output clkmgr_cg_en_t cg_en_o,
+
+ // clock output interface
+ output clkmgr_out_t clocks_o
+
+);
+
+ import prim_mubi_pkg::MuBi4False;
+ import prim_mubi_pkg::MuBi4True;
+ import prim_mubi_pkg::mubi4_test_true_strict;
+ import prim_mubi_pkg::mubi4_test_true_loose;
+ import prim_mubi_pkg::mubi4_test_false_strict;
+
+ // Hookup point for OCC's on root clocks.
+ logic clk_main;
+ prim_clock_buf #(
+ .NoFpgaBuf(1'b1)
+ ) u_clk_main_buf (
+ .clk_i(clk_main_i),
+ .clk_o(clk_main)
+ );
+ logic clk_io;
+ prim_clock_buf #(
+ .NoFpgaBuf(1'b1)
+ ) u_clk_io_buf (
+ .clk_i(clk_io_i),
+ .clk_o(clk_io)
+ );
+ logic clk_usb;
+ prim_clock_buf #(
+ .NoFpgaBuf(1'b1)
+ ) u_clk_usb_buf (
+ .clk_i(clk_usb_i),
+ .clk_o(clk_usb)
+ );
+ logic clk_aon;
+ prim_clock_buf #(
+ .NoFpgaBuf(1'b1)
+ ) u_clk_aon_buf (
+ .clk_i(clk_aon_i),
+ .clk_o(clk_aon)
+ );
+
+ ////////////////////////////////////////////////////
+ // External step down request
+ ////////////////////////////////////////////////////
+ mubi4_t io_step_down_req;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(1),
+ .StabilityCheck(1),
+ .ResetValue(MuBi4False)
+ ) u_io_step_down_req_sync (
+ .clk_i(clk_io),
+ .rst_ni(rst_io_ni),
+ .mubi_i(div_step_down_req_i),
+ .mubi_o({io_step_down_req})
+ );
+
+
+ ////////////////////////////////////////////////////
+ // Divided clocks
+ // Note divided clocks must use the por version of
+ // its related reset to ensure clock division
+ // can happen without any dependency
+ ////////////////////////////////////////////////////
+
+ logic [1:0] step_down_acks;
+
+ logic clk_io_div2;
+ logic clk_io_div4;
+
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] io_div2_div_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_io_div2_div_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o({io_div2_div_scanmode})
+ );
+
+ prim_clock_div #(
+ .Divisor(2)
+ ) u_no_scan_io_div2_div (
+ // We're using the pre-occ hookup (*_i) version for clock derivation.
+ .clk_i(clk_io_i),
+ .rst_ni(rst_root_io_ni),
+ .step_down_req_i(mubi4_test_true_strict(io_step_down_req)),
+ .step_down_ack_o(step_down_acks[0]),
+ .test_en_i(mubi4_test_true_strict(io_div2_div_scanmode[0])),
+ .clk_o(clk_io_div2)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] io_div4_div_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_io_div4_div_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o({io_div4_div_scanmode})
+ );
+
+ prim_clock_div #(
+ .Divisor(4)
+ ) u_no_scan_io_div4_div (
+ // We're using the pre-occ hookup (*_i) version for clock derivation.
+ .clk_i(clk_io_i),
+ .rst_ni(rst_root_io_ni),
+ .step_down_req_i(mubi4_test_true_strict(io_step_down_req)),
+ .step_down_ack_o(step_down_acks[1]),
+ .test_en_i(mubi4_test_true_strict(io_div4_div_scanmode[0])),
+ .clk_o(clk_io_div4)
+ );
+
+ ////////////////////////////////////////////////////
+ // Register Interface
+ ////////////////////////////////////////////////////
+
+ logic [NumAlerts-1:0] alert_test, alerts;
+ clkmgr_reg_pkg::clkmgr_reg2hw_t reg2hw;
+ clkmgr_reg_pkg::clkmgr_hw2reg_t hw2reg;
+
+ // SEC_CM: MEAS.CONFIG.REGWEN
+ // SEC_CM: MEAS.CONFIG.SHADOW
+ // SEC_CM: CLK_CTRL.CONFIG.REGWEN
+ clkmgr_reg_top u_reg (
+ .clk_i,
+ .rst_ni,
+ .rst_shadowed_ni,
+ .clk_io_i(clk_io),
+ .rst_io_ni,
+ .clk_io_div2_i(clk_io_div2),
+ .rst_io_div2_ni,
+ .clk_io_div4_i(clk_io_div4),
+ .rst_io_div4_ni,
+ .clk_main_i(clk_main),
+ .rst_main_ni,
+ .clk_usb_i(clk_usb),
+ .rst_usb_ni,
+ .tl_i,
+ .tl_o,
+ .reg2hw,
+ .hw2reg,
+ .shadowed_storage_err_o(hw2reg.fatal_err_code.shadow_storage_err.de),
+ .shadowed_update_err_o(hw2reg.recov_err_code.shadow_update_err.de),
+ // SEC_CM: BUS.INTEGRITY
+ .intg_err_o(hw2reg.fatal_err_code.reg_intg.de)
+ );
+ assign hw2reg.fatal_err_code.reg_intg.d = 1'b1;
+ assign hw2reg.recov_err_code.shadow_update_err.d = 1'b1;
+ assign hw2reg.fatal_err_code.shadow_storage_err.d = 1'b1;
+
+ ////////////////////////////////////////////////////
+ // Alerts
+ ////////////////////////////////////////////////////
+
+ assign alert_test = {
+ reg2hw.alert_test.fatal_fault.q & reg2hw.alert_test.fatal_fault.qe,
+ reg2hw.alert_test.recov_fault.q & reg2hw.alert_test.recov_fault.qe
+ };
+
+ logic recov_alert;
+ assign recov_alert =
+ hw2reg.recov_err_code.io_measure_err.de |
+ hw2reg.recov_err_code.io_timeout_err.de |
+ hw2reg.recov_err_code.io_div2_measure_err.de |
+ hw2reg.recov_err_code.io_div2_timeout_err.de |
+ hw2reg.recov_err_code.io_div4_measure_err.de |
+ hw2reg.recov_err_code.io_div4_timeout_err.de |
+ hw2reg.recov_err_code.main_measure_err.de |
+ hw2reg.recov_err_code.main_timeout_err.de |
+ hw2reg.recov_err_code.usb_measure_err.de |
+ hw2reg.recov_err_code.usb_timeout_err.de |
+ hw2reg.recov_err_code.shadow_update_err.de;
+
+ assign alerts = {
+ |reg2hw.fatal_err_code,
+ recov_alert
+ };
+
+ localparam logic [NumAlerts-1:0] AlertFatal = {1'b1, 1'b0};
+
+ for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_tx
+ prim_alert_sender #(
+ .AsyncOn(AlertAsyncOn[i]),
+ .IsFatal(AlertFatal[i])
+ ) u_prim_alert_sender (
+ .clk_i,
+ .rst_ni,
+ .alert_test_i ( alert_test[i] ),
+ .alert_req_i ( alerts[i] ),
+ .alert_ack_o ( ),
+ .alert_state_o ( ),
+ .alert_rx_i ( alert_rx_i[i] ),
+ .alert_tx_o ( alert_tx_o[i] )
+ );
+ end
+
+ ////////////////////////////////////////////////////
+ // Clock bypass request
+ ////////////////////////////////////////////////////
+
+ mubi4_t extclk_ctrl_sel;
+ mubi4_t extclk_ctrl_hi_speed_sel;
+
+ assign extclk_ctrl_sel = mubi4_t'(reg2hw.extclk_ctrl.sel.q);
+ assign extclk_ctrl_hi_speed_sel = mubi4_t'(reg2hw.extclk_ctrl.hi_speed_sel.q);
+
+ clkmgr_byp #(
+ .NumDivClks(2)
+ ) u_clkmgr_byp (
+ .clk_i,
+ .rst_ni,
+ .en_i(lc_hw_debug_en_i),
+ .lc_clk_byp_req_i,
+ .lc_clk_byp_ack_o,
+ .byp_req_i(extclk_ctrl_sel),
+ .byp_ack_o(hw2reg.extclk_status.d),
+ .hi_speed_sel_i(extclk_ctrl_hi_speed_sel),
+ .all_clk_byp_req_o,
+ .all_clk_byp_ack_i,
+ .io_clk_byp_req_o,
+ .io_clk_byp_ack_i,
+ .hi_speed_sel_o,
+
+ // divider step down controls
+ .step_down_acks_i(step_down_acks)
+ );
+
+ ////////////////////////////////////////////////////
+ // Feed through clocks
+ // Feed through clocks do not actually need to be in clkmgr, as they are
+ // completely untouched. The only reason they are here is for easier
+ // bundling management purposes through clocks_o
+ ////////////////////////////////////////////////////
+ prim_clock_buf u_clk_io_div4_powerup_buf (
+ .clk_i(clk_io_div4),
+ .clk_o(clocks_o.clk_io_div4_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.io_div4_powerup = MuBi4False;
+ prim_clock_buf u_clk_aon_powerup_buf (
+ .clk_i(clk_aon),
+ .clk_o(clocks_o.clk_aon_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.aon_powerup = MuBi4False;
+ prim_clock_buf u_clk_main_powerup_buf (
+ .clk_i(clk_main),
+ .clk_o(clocks_o.clk_main_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.main_powerup = MuBi4False;
+ prim_clock_buf u_clk_io_powerup_buf (
+ .clk_i(clk_io),
+ .clk_o(clocks_o.clk_io_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.io_powerup = MuBi4False;
+ prim_clock_buf u_clk_usb_powerup_buf (
+ .clk_i(clk_usb),
+ .clk_o(clocks_o.clk_usb_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.usb_powerup = MuBi4False;
+ prim_clock_buf u_clk_io_div2_powerup_buf (
+ .clk_i(clk_io_div2),
+ .clk_o(clocks_o.clk_io_div2_powerup)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.io_div2_powerup = MuBi4False;
+ prim_clock_buf u_clk_aon_secure_buf (
+ .clk_i(clk_aon),
+ .clk_o(clocks_o.clk_aon_secure)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.aon_secure = MuBi4False;
+ prim_clock_buf u_clk_aon_peri_buf (
+ .clk_i(clk_aon),
+ .clk_o(clocks_o.clk_aon_peri)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.aon_peri = MuBi4False;
+ prim_clock_buf u_clk_aon_timers_buf (
+ .clk_i(clk_aon),
+ .clk_o(clocks_o.clk_aon_timers)
+ );
+
+ // clock gated indication for alert handler: these clocks are never gated.
+ assign cg_en_o.aon_timers = MuBi4False;
+
+ ////////////////////////////////////////////////////
+ // Distribute pwrmgr ip_clk_en requests to each family
+ ////////////////////////////////////////////////////
+ // clk_main family
+ logic pwrmgr_main_en;
+ assign pwrmgr_main_en = pwr_i.main_ip_clk_en;
+ // clk_io family
+ logic pwrmgr_io_en;
+ logic pwrmgr_io_div2_en;
+ logic pwrmgr_io_div4_en;
+ assign pwrmgr_io_en = pwr_i.io_ip_clk_en;
+ assign pwrmgr_io_div2_en = pwr_i.io_ip_clk_en;
+ assign pwrmgr_io_div4_en = pwr_i.io_ip_clk_en;
+ // clk_usb family
+ logic pwrmgr_usb_en;
+ assign pwrmgr_usb_en = pwr_i.usb_ip_clk_en;
+
+ ////////////////////////////////////////////////////
+ // Root gating
+ ////////////////////////////////////////////////////
+
+ // clk_main family
+ logic [0:0] main_ens;
+
+ logic clk_main_en;
+ logic clk_main_root;
+ clkmgr_root_ctrl u_main_root_ctrl (
+ .clk_i(clk_main),
+ .rst_ni(rst_root_main_ni),
+ .scanmode_i,
+ .async_en_i(pwrmgr_main_en),
+ .en_o(clk_main_en),
+ .clk_o(clk_main_root)
+ );
+ assign main_ens[0] = clk_main_en;
+
+ // create synchronized status
+ clkmgr_clk_status #(
+ .NumClocks(1)
+ ) u_main_status (
+ .clk_i,
+ .rst_ni(rst_root_ni),
+ .ens_i(main_ens),
+ .status_o(pwr_o.main_status)
+ );
+
+ // clk_io family
+ logic [2:0] io_ens;
+
+ logic clk_io_en;
+ logic clk_io_root;
+ clkmgr_root_ctrl u_io_root_ctrl (
+ .clk_i(clk_io),
+ .rst_ni(rst_root_io_ni),
+ .scanmode_i,
+ .async_en_i(pwrmgr_io_en),
+ .en_o(clk_io_en),
+ .clk_o(clk_io_root)
+ );
+ assign io_ens[0] = clk_io_en;
+
+ logic clk_io_div2_en;
+ logic clk_io_div2_root;
+ clkmgr_root_ctrl u_io_div2_root_ctrl (
+ .clk_i(clk_io_div2),
+ .rst_ni(rst_root_io_div2_ni),
+ .scanmode_i,
+ .async_en_i(pwrmgr_io_div2_en),
+ .en_o(clk_io_div2_en),
+ .clk_o(clk_io_div2_root)
+ );
+ assign io_ens[1] = clk_io_div2_en;
+
+ logic clk_io_div4_en;
+ logic clk_io_div4_root;
+ clkmgr_root_ctrl u_io_div4_root_ctrl (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_root_io_div4_ni),
+ .scanmode_i,
+ .async_en_i(pwrmgr_io_div4_en),
+ .en_o(clk_io_div4_en),
+ .clk_o(clk_io_div4_root)
+ );
+ assign io_ens[2] = clk_io_div4_en;
+
+ // create synchronized status
+ clkmgr_clk_status #(
+ .NumClocks(3)
+ ) u_io_status (
+ .clk_i,
+ .rst_ni(rst_root_ni),
+ .ens_i(io_ens),
+ .status_o(pwr_o.io_status)
+ );
+
+ // clk_usb family
+ logic [0:0] usb_ens;
+
+ logic clk_usb_en;
+ logic clk_usb_root;
+ clkmgr_root_ctrl u_usb_root_ctrl (
+ .clk_i(clk_usb),
+ .rst_ni(rst_root_usb_ni),
+ .scanmode_i,
+ .async_en_i(pwrmgr_usb_en),
+ .en_o(clk_usb_en),
+ .clk_o(clk_usb_root)
+ );
+ assign usb_ens[0] = clk_usb_en;
+
+ // create synchronized status
+ clkmgr_clk_status #(
+ .NumClocks(1)
+ ) u_usb_status (
+ .clk_i,
+ .rst_ni(rst_root_ni),
+ .ens_i(usb_ens),
+ .status_o(pwr_o.usb_status)
+ );
+
+ ////////////////////////////////////////////////////
+ // Clock Measurement for the roots
+ // SEC_CM: TIMEOUT.CLK.BKGN_CHK, MEAS.CLK.BKGN_CHK
+ ////////////////////////////////////////////////////
+
+ typedef enum logic [2:0] {
+ BaseIdx,
+ ClkIoIdx,
+ ClkIoDiv2Idx,
+ ClkIoDiv4Idx,
+ ClkMainIdx,
+ ClkUsbIdx,
+ CalibRdyLastIdx
+ } clkmgr_calib_idx_e;
+
+ // if clocks become uncalibrated, allow the measurement control configurations to change
+ mubi4_t [CalibRdyLastIdx-1:0] calib_rdy;
+ prim_mubi4_sync #(
+ .AsyncOn(1),
+ .NumCopies(int'(CalibRdyLastIdx)),
+ .ResetValue(MuBi4False)
+ ) u_calib_rdy_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(calib_rdy_i),
+ .mubi_o({calib_rdy})
+ );
+
+ always_comb begin
+ hw2reg.measure_ctrl_regwen.de = '0;
+ hw2reg.measure_ctrl_regwen.d = reg2hw.measure_ctrl_regwen;
+
+ if (mubi4_test_false_strict(calib_rdy[BaseIdx])) begin
+ hw2reg.measure_ctrl_regwen.de = 1'b1;
+ hw2reg.measure_ctrl_regwen.d = 1'b1;
+ end
+ end
+
+ clkmgr_meas_chk #(
+ .Cnt(960),
+ .RefCnt(1)
+ ) u_io_meas (
+ .clk_i,
+ .rst_ni,
+ .clk_src_i(clk_io),
+ .rst_src_ni(rst_io_ni),
+ .clk_ref_i(clk_aon),
+ .rst_ref_ni(rst_aon_ni),
+ // signals on source domain
+ .src_en_i(clk_io_en & mubi4_test_true_loose(mubi4_t'(reg2hw.io_meas_ctrl_en))),
+ .src_max_cnt_i(reg2hw.io_meas_ctrl_shadowed.hi.q),
+ .src_min_cnt_i(reg2hw.io_meas_ctrl_shadowed.lo.q),
+ .src_cfg_meas_en_i(mubi4_t'(reg2hw.io_meas_ctrl_en.q)),
+ .src_cfg_meas_en_valid_o(hw2reg.io_meas_ctrl_en.de),
+ .src_cfg_meas_en_o(hw2reg.io_meas_ctrl_en.d),
+ // signals on local clock domain
+ .calib_rdy_i(calib_rdy[ClkIoIdx]),
+ .meas_err_o(hw2reg.recov_err_code.io_measure_err.de),
+ .timeout_err_o(hw2reg.recov_err_code.io_timeout_err.de)
+ );
+
+ assign hw2reg.recov_err_code.io_measure_err.d = 1'b1;
+ assign hw2reg.recov_err_code.io_timeout_err.d = 1'b1;
+
+
+ clkmgr_meas_chk #(
+ .Cnt(480),
+ .RefCnt(1)
+ ) u_io_div2_meas (
+ .clk_i,
+ .rst_ni,
+ .clk_src_i(clk_io_div2),
+ .rst_src_ni(rst_io_div2_ni),
+ .clk_ref_i(clk_aon),
+ .rst_ref_ni(rst_aon_ni),
+ // signals on source domain
+ .src_en_i(clk_io_div2_en & mubi4_test_true_loose(mubi4_t'(reg2hw.io_div2_meas_ctrl_en))),
+ .src_max_cnt_i(reg2hw.io_div2_meas_ctrl_shadowed.hi.q),
+ .src_min_cnt_i(reg2hw.io_div2_meas_ctrl_shadowed.lo.q),
+ .src_cfg_meas_en_i(mubi4_t'(reg2hw.io_div2_meas_ctrl_en.q)),
+ .src_cfg_meas_en_valid_o(hw2reg.io_div2_meas_ctrl_en.de),
+ .src_cfg_meas_en_o(hw2reg.io_div2_meas_ctrl_en.d),
+ // signals on local clock domain
+ .calib_rdy_i(calib_rdy[ClkIoDiv2Idx]),
+ .meas_err_o(hw2reg.recov_err_code.io_div2_measure_err.de),
+ .timeout_err_o(hw2reg.recov_err_code.io_div2_timeout_err.de)
+ );
+
+ assign hw2reg.recov_err_code.io_div2_measure_err.d = 1'b1;
+ assign hw2reg.recov_err_code.io_div2_timeout_err.d = 1'b1;
+
+
+ clkmgr_meas_chk #(
+ .Cnt(240),
+ .RefCnt(1)
+ ) u_io_div4_meas (
+ .clk_i,
+ .rst_ni,
+ .clk_src_i(clk_io_div4),
+ .rst_src_ni(rst_io_div4_ni),
+ .clk_ref_i(clk_aon),
+ .rst_ref_ni(rst_aon_ni),
+ // signals on source domain
+ .src_en_i(clk_io_div4_en & mubi4_test_true_loose(mubi4_t'(reg2hw.io_div4_meas_ctrl_en))),
+ .src_max_cnt_i(reg2hw.io_div4_meas_ctrl_shadowed.hi.q),
+ .src_min_cnt_i(reg2hw.io_div4_meas_ctrl_shadowed.lo.q),
+ .src_cfg_meas_en_i(mubi4_t'(reg2hw.io_div4_meas_ctrl_en.q)),
+ .src_cfg_meas_en_valid_o(hw2reg.io_div4_meas_ctrl_en.de),
+ .src_cfg_meas_en_o(hw2reg.io_div4_meas_ctrl_en.d),
+ // signals on local clock domain
+ .calib_rdy_i(calib_rdy[ClkIoDiv4Idx]),
+ .meas_err_o(hw2reg.recov_err_code.io_div4_measure_err.de),
+ .timeout_err_o(hw2reg.recov_err_code.io_div4_timeout_err.de)
+ );
+
+ assign hw2reg.recov_err_code.io_div4_measure_err.d = 1'b1;
+ assign hw2reg.recov_err_code.io_div4_timeout_err.d = 1'b1;
+
+
+ clkmgr_meas_chk #(
+ .Cnt(1000),
+ .RefCnt(1)
+ ) u_main_meas (
+ .clk_i,
+ .rst_ni,
+ .clk_src_i(clk_main),
+ .rst_src_ni(rst_main_ni),
+ .clk_ref_i(clk_aon),
+ .rst_ref_ni(rst_aon_ni),
+ // signals on source domain
+ .src_en_i(clk_main_en & mubi4_test_true_loose(mubi4_t'(reg2hw.main_meas_ctrl_en))),
+ .src_max_cnt_i(reg2hw.main_meas_ctrl_shadowed.hi.q),
+ .src_min_cnt_i(reg2hw.main_meas_ctrl_shadowed.lo.q),
+ .src_cfg_meas_en_i(mubi4_t'(reg2hw.main_meas_ctrl_en.q)),
+ .src_cfg_meas_en_valid_o(hw2reg.main_meas_ctrl_en.de),
+ .src_cfg_meas_en_o(hw2reg.main_meas_ctrl_en.d),
+ // signals on local clock domain
+ .calib_rdy_i(calib_rdy[ClkMainIdx]),
+ .meas_err_o(hw2reg.recov_err_code.main_measure_err.de),
+ .timeout_err_o(hw2reg.recov_err_code.main_timeout_err.de)
+ );
+
+ assign hw2reg.recov_err_code.main_measure_err.d = 1'b1;
+ assign hw2reg.recov_err_code.main_timeout_err.d = 1'b1;
+
+
+ clkmgr_meas_chk #(
+ .Cnt(480),
+ .RefCnt(1)
+ ) u_usb_meas (
+ .clk_i,
+ .rst_ni,
+ .clk_src_i(clk_usb),
+ .rst_src_ni(rst_usb_ni),
+ .clk_ref_i(clk_aon),
+ .rst_ref_ni(rst_aon_ni),
+ // signals on source domain
+ .src_en_i(clk_usb_en & mubi4_test_true_loose(mubi4_t'(reg2hw.usb_meas_ctrl_en))),
+ .src_max_cnt_i(reg2hw.usb_meas_ctrl_shadowed.hi.q),
+ .src_min_cnt_i(reg2hw.usb_meas_ctrl_shadowed.lo.q),
+ .src_cfg_meas_en_i(mubi4_t'(reg2hw.usb_meas_ctrl_en.q)),
+ .src_cfg_meas_en_valid_o(hw2reg.usb_meas_ctrl_en.de),
+ .src_cfg_meas_en_o(hw2reg.usb_meas_ctrl_en.d),
+ // signals on local clock domain
+ .calib_rdy_i(calib_rdy[ClkUsbIdx]),
+ .meas_err_o(hw2reg.recov_err_code.usb_measure_err.de),
+ .timeout_err_o(hw2reg.recov_err_code.usb_timeout_err.de)
+ );
+
+ assign hw2reg.recov_err_code.usb_measure_err.d = 1'b1;
+ assign hw2reg.recov_err_code.usb_timeout_err.d = 1'b1;
+
+
+ ////////////////////////////////////////////////////
+ // Clocks with only root gate
+ ////////////////////////////////////////////////////
+ assign clocks_o.clk_io_div4_infra = clk_io_div4_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div4_infra (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_io_div4_ni),
+ .mubi_i(((clk_io_div4_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div4_infra)
+ );
+ assign clocks_o.clk_main_infra = clk_main_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_main_infra (
+ .clk_i(clk_main),
+ .rst_ni(rst_main_ni),
+ .mubi_i(((clk_main_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.main_infra)
+ );
+ assign clocks_o.clk_usb_infra = clk_usb_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_usb_infra (
+ .clk_i(clk_usb),
+ .rst_ni(rst_usb_ni),
+ .mubi_i(((clk_usb_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.usb_infra)
+ );
+ assign clocks_o.clk_io_infra = clk_io_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_infra (
+ .clk_i(clk_io),
+ .rst_ni(rst_io_ni),
+ .mubi_i(((clk_io_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_infra)
+ );
+ assign clocks_o.clk_io_div2_infra = clk_io_div2_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div2_infra (
+ .clk_i(clk_io_div2),
+ .rst_ni(rst_io_div2_ni),
+ .mubi_i(((clk_io_div2_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div2_infra)
+ );
+ assign clocks_o.clk_io_div4_secure = clk_io_div4_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div4_secure (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_io_div4_ni),
+ .mubi_i(((clk_io_div4_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div4_secure)
+ );
+ assign clocks_o.clk_main_secure = clk_main_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_main_secure (
+ .clk_i(clk_main),
+ .rst_ni(rst_main_ni),
+ .mubi_i(((clk_main_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.main_secure)
+ );
+ assign clocks_o.clk_io_div4_timers = clk_io_div4_root;
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div4_timers (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_io_div4_ni),
+ .mubi_i(((clk_io_div4_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div4_timers)
+ );
+
+ ////////////////////////////////////////////////////
+ // Software direct control group
+ ////////////////////////////////////////////////////
+
+ logic clk_io_div4_peri_sw_en;
+ logic clk_io_div2_peri_sw_en;
+ logic clk_io_peri_sw_en;
+ logic clk_usb_peri_sw_en;
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_clk_io_div4_peri_sw_en_sync (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_io_div4_ni),
+ .d_i(reg2hw.clk_enables.clk_io_div4_peri_en.q),
+ .q_o(clk_io_div4_peri_sw_en)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] clk_io_div4_peri_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_clk_io_div4_peri_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o(clk_io_div4_peri_scanmode)
+ );
+
+ logic clk_io_div4_peri_combined_en;
+ assign clk_io_div4_peri_combined_en = clk_io_div4_peri_sw_en & clk_io_div4_en;
+ prim_clock_gating #(
+ .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions.
+ ) u_clk_io_div4_peri_cg (
+ .clk_i(clk_io_div4),
+ .en_i(clk_io_div4_peri_combined_en),
+ .test_en_i(mubi4_test_true_strict(clk_io_div4_peri_scanmode[0])),
+ .clk_o(clocks_o.clk_io_div4_peri)
+ );
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div4_peri (
+ .clk_i(clk_io_div4),
+ .rst_ni(rst_io_div4_ni),
+ .mubi_i(((clk_io_div4_peri_combined_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div4_peri)
+ );
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_clk_io_div2_peri_sw_en_sync (
+ .clk_i(clk_io_div2),
+ .rst_ni(rst_io_div2_ni),
+ .d_i(reg2hw.clk_enables.clk_io_div2_peri_en.q),
+ .q_o(clk_io_div2_peri_sw_en)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] clk_io_div2_peri_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_clk_io_div2_peri_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o(clk_io_div2_peri_scanmode)
+ );
+
+ logic clk_io_div2_peri_combined_en;
+ assign clk_io_div2_peri_combined_en = clk_io_div2_peri_sw_en & clk_io_div2_en;
+ prim_clock_gating #(
+ .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions.
+ ) u_clk_io_div2_peri_cg (
+ .clk_i(clk_io_div2),
+ .en_i(clk_io_div2_peri_combined_en),
+ .test_en_i(mubi4_test_true_strict(clk_io_div2_peri_scanmode[0])),
+ .clk_o(clocks_o.clk_io_div2_peri)
+ );
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_div2_peri (
+ .clk_i(clk_io_div2),
+ .rst_ni(rst_io_div2_ni),
+ .mubi_i(((clk_io_div2_peri_combined_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_div2_peri)
+ );
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_clk_io_peri_sw_en_sync (
+ .clk_i(clk_io),
+ .rst_ni(rst_io_ni),
+ .d_i(reg2hw.clk_enables.clk_io_peri_en.q),
+ .q_o(clk_io_peri_sw_en)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] clk_io_peri_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_clk_io_peri_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o(clk_io_peri_scanmode)
+ );
+
+ logic clk_io_peri_combined_en;
+ assign clk_io_peri_combined_en = clk_io_peri_sw_en & clk_io_en;
+ prim_clock_gating #(
+ .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions.
+ ) u_clk_io_peri_cg (
+ .clk_i(clk_io),
+ .en_i(clk_io_peri_combined_en),
+ .test_en_i(mubi4_test_true_strict(clk_io_peri_scanmode[0])),
+ .clk_o(clocks_o.clk_io_peri)
+ );
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_io_peri (
+ .clk_i(clk_io),
+ .rst_ni(rst_io_ni),
+ .mubi_i(((clk_io_peri_combined_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.io_peri)
+ );
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_clk_usb_peri_sw_en_sync (
+ .clk_i(clk_usb),
+ .rst_ni(rst_usb_ni),
+ .d_i(reg2hw.clk_enables.clk_usb_peri_en.q),
+ .q_o(clk_usb_peri_sw_en)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] clk_usb_peri_scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_clk_usb_peri_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o(clk_usb_peri_scanmode)
+ );
+
+ logic clk_usb_peri_combined_en;
+ assign clk_usb_peri_combined_en = clk_usb_peri_sw_en & clk_usb_en;
+ prim_clock_gating #(
+ .FpgaBufGlobal(1'b1) // This clock spans across multiple clock regions.
+ ) u_clk_usb_peri_cg (
+ .clk_i(clk_usb),
+ .en_i(clk_usb_peri_combined_en),
+ .test_en_i(mubi4_test_true_strict(clk_usb_peri_scanmode[0])),
+ .clk_o(clocks_o.clk_usb_peri)
+ );
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender_clk_usb_peri (
+ .clk_i(clk_usb),
+ .rst_ni(rst_usb_ni),
+ .mubi_i(((clk_usb_peri_combined_en) ? MuBi4False : MuBi4True)),
+ .mubi_o(cg_en_o.usb_peri)
+ );
+
+
+ ////////////////////////////////////////////////////
+ // Software hint group
+ // The idle hint feedback is assumed to be synchronous to the
+ // clock target
+ ////////////////////////////////////////////////////
+
+ logic [3:0] idle_cnt_err;
+
+ clkmgr_trans #(
+ .FpgaBufGlobal(1'b0) // This clock is used primarily locally.
+ ) u_clk_main_aes_trans (
+ .clk_i(clk_main),
+ .clk_gated_i(clk_main_root),
+ .rst_ni(rst_main_ni),
+ .en_i(clk_main_en),
+ .idle_i(idle_i[HintMainAes]),
+ .sw_hint_i(reg2hw.clk_hints.clk_main_aes_hint.q),
+ .scanmode_i,
+ .alert_cg_en_o(cg_en_o.main_aes),
+ .clk_o(clocks_o.clk_main_aes),
+ .clk_reg_i(clk_i),
+ .rst_reg_ni(rst_ni),
+ .reg_en_o(hw2reg.clk_hints_status.clk_main_aes_val.d),
+ .reg_cnt_err_o(idle_cnt_err[HintMainAes])
+ );
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(
+ ClkMainAesCountCheck_A,
+ u_clk_main_aes_trans.u_idle_cnt,
+ alert_tx_o[1])
+
+ clkmgr_trans #(
+ .FpgaBufGlobal(1'b0) // This clock is used primarily locally.
+ ) u_clk_main_hmac_trans (
+ .clk_i(clk_main),
+ .clk_gated_i(clk_main_root),
+ .rst_ni(rst_main_ni),
+ .en_i(clk_main_en),
+ .idle_i(idle_i[HintMainHmac]),
+ .sw_hint_i(reg2hw.clk_hints.clk_main_hmac_hint.q),
+ .scanmode_i,
+ .alert_cg_en_o(cg_en_o.main_hmac),
+ .clk_o(clocks_o.clk_main_hmac),
+ .clk_reg_i(clk_i),
+ .rst_reg_ni(rst_ni),
+ .reg_en_o(hw2reg.clk_hints_status.clk_main_hmac_val.d),
+ .reg_cnt_err_o(idle_cnt_err[HintMainHmac])
+ );
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(
+ ClkMainHmacCountCheck_A,
+ u_clk_main_hmac_trans.u_idle_cnt,
+ alert_tx_o[1])
+
+ clkmgr_trans #(
+ .FpgaBufGlobal(1'b1) // KMAC is getting too big for a single clock region.
+ ) u_clk_main_kmac_trans (
+ .clk_i(clk_main),
+ .clk_gated_i(clk_main_root),
+ .rst_ni(rst_main_ni),
+ .en_i(clk_main_en),
+ .idle_i(idle_i[HintMainKmac]),
+ .sw_hint_i(reg2hw.clk_hints.clk_main_kmac_hint.q),
+ .scanmode_i,
+ .alert_cg_en_o(cg_en_o.main_kmac),
+ .clk_o(clocks_o.clk_main_kmac),
+ .clk_reg_i(clk_i),
+ .rst_reg_ni(rst_ni),
+ .reg_en_o(hw2reg.clk_hints_status.clk_main_kmac_val.d),
+ .reg_cnt_err_o(idle_cnt_err[HintMainKmac])
+ );
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(
+ ClkMainKmacCountCheck_A,
+ u_clk_main_kmac_trans.u_idle_cnt,
+ alert_tx_o[1])
+
+ clkmgr_trans #(
+ .FpgaBufGlobal(1'b0) // This clock is used primarily locally.
+ ) u_clk_main_otbn_trans (
+ .clk_i(clk_main),
+ .clk_gated_i(clk_main_root),
+ .rst_ni(rst_main_ni),
+ .en_i(clk_main_en),
+ .idle_i(idle_i[HintMainOtbn]),
+ .sw_hint_i(reg2hw.clk_hints.clk_main_otbn_hint.q),
+ .scanmode_i,
+ .alert_cg_en_o(cg_en_o.main_otbn),
+ .clk_o(clocks_o.clk_main_otbn),
+ .clk_reg_i(clk_i),
+ .rst_reg_ni(rst_ni),
+ .reg_en_o(hw2reg.clk_hints_status.clk_main_otbn_val.d),
+ .reg_cnt_err_o(idle_cnt_err[HintMainOtbn])
+ );
+ `ASSERT_PRIM_COUNT_ERROR_TRIGGER_ALERT(
+ ClkMainOtbnCountCheck_A,
+ u_clk_main_otbn_trans.u_idle_cnt,
+ alert_tx_o[1])
+ assign hw2reg.fatal_err_code.idle_cnt.d = 1'b1;
+ assign hw2reg.fatal_err_code.idle_cnt.de = |idle_cnt_err;
+
+ // state readback
+ assign hw2reg.clk_hints_status.clk_main_aes_val.de = 1'b1;
+ assign hw2reg.clk_hints_status.clk_main_hmac_val.de = 1'b1;
+ assign hw2reg.clk_hints_status.clk_main_kmac_val.de = 1'b1;
+ assign hw2reg.clk_hints_status.clk_main_otbn_val.de = 1'b1;
+
+ // SEC_CM: JITTER.CONFIG.MUBI
+ assign jitter_en_o = mubi4_t'(reg2hw.jitter_enable.q);
+
+ ////////////////////////////////////////////////////
+ // Exported clocks
+ ////////////////////////////////////////////////////
+
+
+ ////////////////////////////////////////////////////
+ // Assertions
+ ////////////////////////////////////////////////////
+
+ `ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid)
+ `ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready)
+ `ASSERT_KNOWN(AlertsKnownO_A, alert_tx_o)
+ `ASSERT_KNOWN(PwrMgrKnownO_A, pwr_o)
+ `ASSERT_KNOWN(AllClkBypReqKnownO_A, all_clk_byp_req_o)
+ `ASSERT_KNOWN(IoClkBypReqKnownO_A, io_clk_byp_req_o)
+ `ASSERT_KNOWN(LcCtrlClkBypAckKnownO_A, lc_clk_byp_ack_o)
+ `ASSERT_KNOWN(JitterEnableKnownO_A, jitter_en_o)
+ `ASSERT_KNOWN(ClocksKownO_A, clocks_o)
+ `ASSERT_KNOWN(CgEnKnownO_A, cg_en_o)
+
+ // Alert assertions for reg_we onehot check
+ `ASSERT_PRIM_REG_WE_ONEHOT_ERROR_TRIGGER_ALERT(RegWeOnehotCheck_A, u_reg, alert_tx_o[1])
+endmodule // clkmgr
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_byp.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_byp.sv
new file mode 100644
index 00000000000000..cbe4026eed8cef
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_byp.sv
@@ -0,0 +1,163 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Handle clock manager bypass requests
+
+module clkmgr_byp
+ import clkmgr_pkg::*;
+ import lc_ctrl_pkg::lc_tx_t;
+ import prim_mubi_pkg::mubi4_t;
+# (
+ parameter int NumDivClks = 1
+) (
+ input clk_i,
+ input rst_ni,
+ // interaction with lc_ctrl
+ input lc_tx_t en_i,
+ input lc_tx_t lc_clk_byp_req_i,
+ output lc_tx_t lc_clk_byp_ack_o,
+ // interaction with software
+ input mubi4_t byp_req_i,
+ output mubi4_t byp_ack_o,
+ input mubi4_t hi_speed_sel_i,
+ // interaction with ast
+ output mubi4_t all_clk_byp_req_o,
+ input mubi4_t all_clk_byp_ack_i,
+ output mubi4_t io_clk_byp_req_o,
+ input mubi4_t io_clk_byp_ack_i,
+ output mubi4_t hi_speed_sel_o,
+ // interaction with dividers
+ input [NumDivClks-1:0] step_down_acks_i
+);
+
+ import prim_mubi_pkg::MuBi4Width;
+ import prim_mubi_pkg::MuBi4True;
+ import prim_mubi_pkg::MuBi4False;
+ import prim_mubi_pkg::mubi4_and_hi;
+ import prim_mubi_pkg::mubi4_test_true_strict;
+
+ // synchornize incoming lc signals
+ lc_tx_t en;
+ prim_lc_sync #(
+ .NumCopies(1),
+ .AsyncOn(1),
+ .ResetValueIsOn(0)
+ ) u_en_sync (
+ .clk_i,
+ .rst_ni,
+ .lc_en_i(en_i),
+ .lc_en_o({en})
+ );
+
+ typedef enum logic [1:0] {
+ LcClkBypReqIoReq,
+ LcClkBypReqLcAck,
+ LcClkBypReqLast
+ } lc_clk_byp_req_e;
+
+ lc_tx_t [LcClkBypReqLast-1:0] lc_clk_byp_req;
+ prim_lc_sync #(
+ .NumCopies(int'(LcClkBypReqLast)),
+ .AsyncOn(1),
+ .ResetValueIsOn(0)
+ ) u_lc_byp_req (
+ .clk_i,
+ .rst_ni,
+ .lc_en_i(lc_clk_byp_req_i),
+ .lc_en_o(lc_clk_byp_req)
+ );
+
+ // synchronize step down acks
+ logic [NumDivClks-1:0] step_down_acks_sync;
+ prim_flop #(
+ .Width(NumDivClks),
+ .ResetValue(0)
+ ) u_step_down_acks_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(step_down_acks_i),
+ .q_o(step_down_acks_sync)
+ );
+
+ // life cycle handling
+ mubi4_t io_clk_byp_req_d;
+ assign io_clk_byp_req_d = lc_ctrl_pkg::lc_tx_test_true_strict(lc_clk_byp_req[LcClkBypReqIoReq]) ?
+ MuBi4True :
+ MuBi4False;
+
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4False),
+ .EnSecBuf(1)
+ ) u_io_byp_req (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(io_clk_byp_req_d),
+ .mubi_o(io_clk_byp_req_o)
+ );
+
+ // only ack the lc_ctrl if it made a request.
+ mubi4_t io_clk_byp_ack;
+ prim_lc_sender u_send (
+ .clk_i,
+ .rst_ni,
+ .lc_en_i(&step_down_acks_sync & mubi4_test_true_strict(io_clk_byp_ack) ?
+ lc_clk_byp_req[LcClkBypReqLcAck] : lc_ctrl_pkg::Off),
+ .lc_en_o(lc_clk_byp_ack_o)
+ );
+
+ // software switch request handling
+ mubi4_t debug_en;
+ assign debug_en = lc_ctrl_pkg::lc_to_mubi4(en);
+
+ mubi4_t all_clk_byp_req_d;
+ assign all_clk_byp_req_d = mubi4_and_hi(byp_req_i, debug_en);
+
+ prim_mubi4_sender #(
+ .AsyncOn(1),
+ .ResetValue(MuBi4False),
+ .EnSecBuf(1)
+ ) u_all_byp_req (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(all_clk_byp_req_d),
+ .mubi_o(all_clk_byp_req_o)
+ );
+
+ prim_mubi4_sync #(
+ .AsyncOn(1),
+ .StabilityCheck(1),
+ .ResetValue(MuBi4False)
+ ) u_io_ack_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(io_clk_byp_ack_i),
+ .mubi_o({io_clk_byp_ack})
+ );
+
+ // since div_step_down_req is now directly fed externally, there is no longer
+ // a use for the related 'ack' signals
+ prim_mubi4_sync #(
+ .AsyncOn(1),
+ .StabilityCheck(1),
+ .ResetValue(MuBi4False)
+ ) u_all_ack_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(all_clk_byp_ack_i),
+ .mubi_o({byp_ack_o})
+ );
+
+ // the software high speed select is valid only when software requests clock
+ // bypass
+ prim_mubi4_sender #(
+ .AsyncOn(1),
+ .ResetValue(MuBi4True)
+ ) u_hi_speed_sel (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(mubi4_and_hi(all_clk_byp_req_d, hi_speed_sel_i)),
+ .mubi_o(hi_speed_sel_o)
+ );
+
+endmodule // clkmgr_byp
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_clk_status.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_clk_status.sv
new file mode 100644
index 00000000000000..3e9527e50e0f03
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_clk_status.sv
@@ -0,0 +1,58 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Wrapper module for computing enable / disable status on family of clocks
+
+module clkmgr_clk_status #(
+ parameter int NumClocks = 1,
+ parameter int FilterStages = 2
+) (
+ input clk_i,
+ input rst_ni,
+ input [NumClocks-1:0] ens_i,
+ output logic status_o
+);
+
+ // The enables are coming from different clock domains,
+ // therefore after synchronization we must de-bounce the
+ // signal to ensure it is stable
+ logic [NumClocks-1:0] ens_sync;
+ prim_flop_2sync #(
+ .Width(NumClocks)
+ ) u_en_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(ens_i),
+ .q_o(ens_sync)
+ );
+
+ logic [FilterStages-1:0] en_q, dis_q, en_d, dis_d;
+
+ // enable is true when all inputs are 1
+ assign en_d = {en_q[FilterStages-2:0], &ens_sync};
+
+ // disable is true all all inputs are 0
+ assign dis_d = {dis_q[FilterStages-2:0], ~|ens_sync};
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ en_q <= '0;
+ dis_q <= '0;
+ end else begin
+ en_q <= en_d;
+ dis_q <= dis_d;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ status_o <= '0;
+ end else if (&en_q) begin
+ status_o <= 1'b1;
+ end else if (&dis_q) begin
+ status_o <= 1'b0;
+ end
+ end
+
+endmodule // clkmgr_clk_status
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_meas_chk.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_meas_chk.sv
new file mode 100644
index 00000000000000..64f74df1f7a013
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_meas_chk.sv
@@ -0,0 +1,127 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Clock manager measurement and timeout checks
+
+module clkmgr_meas_chk
+ import prim_mubi_pkg::mubi4_t;
+#(
+ // Maximum value of input clock counts over measurement period
+ parameter int Cnt = 16,
+ // Maximum value of reference clock counts over measurement period
+ parameter int RefCnt = 1,
+ localparam int CntWidth = prim_util_pkg::vbits(Cnt)
+) (
+ // the local operating clock
+ input clk_i,
+ input rst_ni,
+ // the clock we are measuring
+ input clk_src_i,
+ input rst_src_ni,
+ // the reference clock we are measuring against
+ input clk_ref_i,
+ input rst_ref_ni,
+ // controls all provided on src clock
+ input src_en_i,
+ input [CntWidth-1:0] src_max_cnt_i,
+ input [CntWidth-1:0] src_min_cnt_i,
+ input mubi4_t src_cfg_meas_en_i,
+ output logic src_cfg_meas_en_valid_o,
+ output mubi4_t src_cfg_meas_en_o,
+ // calibration ready input provided on local operating clock
+ input mubi4_t calib_rdy_i,
+ // error output are provided on local operating clock
+ output logic meas_err_o,
+ output logic timeout_err_o
+);
+
+ logic src_fast_err;
+ logic src_slow_err;
+ logic ref_timeout_err;
+
+ prim_clock_meas #(
+ .Cnt(Cnt),
+ .RefCnt(RefCnt),
+ .ClkTimeOutChkEn(1'b1),
+ .RefTimeOutChkEn(1'b0)
+ ) u_meas (
+ .clk_i(clk_src_i),
+ .rst_ni(rst_src_ni),
+ .clk_ref_i,
+ .rst_ref_ni,
+ .en_i(src_en_i),
+ .max_cnt(src_max_cnt_i),
+ .min_cnt(src_min_cnt_i),
+ .valid_o(),
+ .fast_o(src_fast_err),
+ .slow_o(src_slow_err),
+ .timeout_clk_ref_o(),
+ .ref_timeout_clk_o(ref_timeout_err)
+ );
+
+ mubi4_t src_calib_rdy;
+ prim_mubi4_sync #(
+ .AsyncOn(1),
+ .ResetValue(prim_mubi_pkg::MuBi4False)
+ ) u_calib_rdy_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(calib_rdy_i),
+ .mubi_o({src_calib_rdy})
+ );
+
+ // if clocks become uncalibrated, switch off measurement controls
+ always_comb begin
+ src_cfg_meas_en_valid_o = '0;
+ src_cfg_meas_en_o = src_cfg_meas_en_i;
+
+ // if calibration is lost when measurement is currently enabled,
+ // disable measurement enable.
+ if (prim_mubi_pkg::mubi4_test_false_strict(src_calib_rdy) &&
+ prim_mubi_pkg::mubi4_test_true_loose(src_cfg_meas_en_o)) begin
+ src_cfg_meas_en_valid_o = 1'b1;
+ src_cfg_meas_en_o = prim_mubi_pkg::MuBi4False;
+ end
+ end
+
+ // A reqack module is used here instead of a pulse_saync
+ // because the source pulses may toggle too fast for the
+ // the destination to receive.
+ logic src_err_req, src_err_ack;
+ always_ff @(posedge clk_src_i or negedge rst_src_ni) begin
+ if (!rst_src_ni) begin
+ src_err_req <= '0;
+ end else if (src_fast_err || src_slow_err) begin
+ src_err_req <= 1'b1;
+ end else if (src_err_req && src_err_ack) begin
+ src_err_req <= '0;
+ end
+ end
+
+ prim_sync_reqack u_err_sync (
+ .clk_src_i,
+ .rst_src_ni,
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .req_chk_i(1'b1),
+ .src_req_i(src_err_req),
+ .src_ack_o(src_err_ack),
+ .dst_req_o(meas_err_o),
+ .dst_ack_i(meas_err_o)
+ );
+
+ prim_edge_detector #(
+ .Width(1),
+ .ResetValue('0),
+ .EnSync(1'b1)
+ ) u_timeout_err_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(ref_timeout_err),
+ .q_sync_o(),
+ .q_posedge_pulse_o(timeout_err_o),
+ .q_negedge_pulse_o()
+ );
+
+endmodule // clkmgr_meas_chk
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_pkg.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_pkg.sv
new file mode 100644
index 00000000000000..635613d2023a8a
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_pkg.sv
@@ -0,0 +1,85 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+
+
+package clkmgr_pkg;
+
+ typedef enum int {
+ HintMainAes = 0,
+ HintMainHmac = 1,
+ HintMainKmac = 2,
+ HintMainOtbn = 3
+ } hint_names_e;
+
+ // clocks generated and broadcast
+ typedef struct packed {
+ logic clk_io_div4_powerup;
+ logic clk_aon_powerup;
+ logic clk_main_powerup;
+ logic clk_io_powerup;
+ logic clk_usb_powerup;
+ logic clk_io_div2_powerup;
+ logic clk_aon_secure;
+ logic clk_aon_peri;
+ logic clk_aon_timers;
+ logic clk_main_aes;
+ logic clk_main_hmac;
+ logic clk_main_kmac;
+ logic clk_main_otbn;
+ logic clk_io_div4_infra;
+ logic clk_main_infra;
+ logic clk_usb_infra;
+ logic clk_io_infra;
+ logic clk_io_div2_infra;
+ logic clk_io_div4_secure;
+ logic clk_main_secure;
+ logic clk_io_div4_timers;
+ logic clk_io_div4_peri;
+ logic clk_io_div2_peri;
+ logic clk_io_peri;
+ logic clk_usb_peri;
+ } clkmgr_out_t;
+
+ // clock gating indication for alert handler
+ typedef struct packed {
+ prim_mubi_pkg::mubi4_t io_div4_powerup;
+ prim_mubi_pkg::mubi4_t aon_powerup;
+ prim_mubi_pkg::mubi4_t main_powerup;
+ prim_mubi_pkg::mubi4_t io_powerup;
+ prim_mubi_pkg::mubi4_t usb_powerup;
+ prim_mubi_pkg::mubi4_t io_div2_powerup;
+ prim_mubi_pkg::mubi4_t aon_secure;
+ prim_mubi_pkg::mubi4_t aon_peri;
+ prim_mubi_pkg::mubi4_t aon_timers;
+ prim_mubi_pkg::mubi4_t main_aes;
+ prim_mubi_pkg::mubi4_t main_hmac;
+ prim_mubi_pkg::mubi4_t main_kmac;
+ prim_mubi_pkg::mubi4_t main_otbn;
+ prim_mubi_pkg::mubi4_t io_div4_infra;
+ prim_mubi_pkg::mubi4_t main_infra;
+ prim_mubi_pkg::mubi4_t usb_infra;
+ prim_mubi_pkg::mubi4_t io_infra;
+ prim_mubi_pkg::mubi4_t io_div2_infra;
+ prim_mubi_pkg::mubi4_t io_div4_secure;
+ prim_mubi_pkg::mubi4_t main_secure;
+ prim_mubi_pkg::mubi4_t io_div4_timers;
+ prim_mubi_pkg::mubi4_t io_div4_peri;
+ prim_mubi_pkg::mubi4_t io_div2_peri;
+ prim_mubi_pkg::mubi4_t io_peri;
+ prim_mubi_pkg::mubi4_t usb_peri;
+ } clkmgr_cg_en_t;
+
+ parameter int NumOutputClk = 25;
+
+
+ typedef struct packed {
+ logic [4-1:0] idle;
+ } clk_hint_status_t;
+
+ parameter clk_hint_status_t CLK_HINT_STATUS_DEFAULT = '{
+ idle: {4{1'b1}}
+ };
+
+endpackage // clkmgr_pkg
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_pkg.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_pkg.sv
new file mode 100644
index 00000000000000..b21e731892a625
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_pkg.sv
@@ -0,0 +1,390 @@
+// 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 clkmgr_reg_pkg;
+
+ // Param list
+ parameter int NumGroups = 7;
+ parameter int NumSwGateableClocks = 4;
+ parameter int NumHintableClocks = 4;
+ parameter int NumAlerts = 2;
+
+ // Address widths within the block
+ parameter int BlockAw = 7;
+
+ ////////////////////////////
+ // Typedefs for registers //
+ ////////////////////////////
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ logic qe;
+ } fatal_fault;
+ struct packed {
+ logic q;
+ logic qe;
+ } recov_fault;
+ } clkmgr_reg2hw_alert_test_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [3:0] q;
+ } hi_speed_sel;
+ struct packed {
+ logic [3:0] q;
+ } sel;
+ } clkmgr_reg2hw_extclk_ctrl_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_jitter_enable_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ } clk_usb_peri_en;
+ struct packed {
+ logic q;
+ } clk_io_peri_en;
+ struct packed {
+ logic q;
+ } clk_io_div2_peri_en;
+ struct packed {
+ logic q;
+ } clk_io_div4_peri_en;
+ } clkmgr_reg2hw_clk_enables_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ } clk_main_otbn_hint;
+ struct packed {
+ logic q;
+ } clk_main_kmac_hint;
+ struct packed {
+ logic q;
+ } clk_main_hmac_hint;
+ struct packed {
+ logic q;
+ } clk_main_aes_hint;
+ } clkmgr_reg2hw_clk_hints_reg_t;
+
+ typedef struct packed {
+ logic q;
+ } clkmgr_reg2hw_measure_ctrl_regwen_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_io_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [9:0] q;
+ } lo;
+ struct packed {
+ logic [9:0] q;
+ } hi;
+ } clkmgr_reg2hw_io_meas_ctrl_shadowed_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_io_div2_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [8:0] q;
+ } lo;
+ struct packed {
+ logic [8:0] q;
+ } hi;
+ } clkmgr_reg2hw_io_div2_meas_ctrl_shadowed_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_io_div4_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [7:0] q;
+ } lo;
+ struct packed {
+ logic [7:0] q;
+ } hi;
+ } clkmgr_reg2hw_io_div4_meas_ctrl_shadowed_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_main_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [9:0] q;
+ } lo;
+ struct packed {
+ logic [9:0] q;
+ } hi;
+ } clkmgr_reg2hw_main_meas_ctrl_shadowed_reg_t;
+
+ typedef struct packed {
+ logic [3:0] q;
+ } clkmgr_reg2hw_usb_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic [8:0] q;
+ } lo;
+ struct packed {
+ logic [8:0] q;
+ } hi;
+ } clkmgr_reg2hw_usb_meas_ctrl_shadowed_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic q;
+ } shadow_storage_err;
+ struct packed {
+ logic q;
+ } idle_cnt;
+ struct packed {
+ logic q;
+ } reg_intg;
+ } clkmgr_reg2hw_fatal_err_code_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ } clkmgr_hw2reg_extclk_status_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } clk_main_aes_val;
+ struct packed {
+ logic d;
+ logic de;
+ } clk_main_hmac_val;
+ struct packed {
+ logic d;
+ logic de;
+ } clk_main_kmac_val;
+ struct packed {
+ logic d;
+ logic de;
+ } clk_main_otbn_val;
+ } clkmgr_hw2reg_clk_hints_status_reg_t;
+
+ typedef struct packed {
+ logic d;
+ logic de;
+ } clkmgr_hw2reg_measure_ctrl_regwen_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ logic de;
+ } clkmgr_hw2reg_io_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ logic de;
+ } clkmgr_hw2reg_io_div2_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ logic de;
+ } clkmgr_hw2reg_io_div4_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ logic de;
+ } clkmgr_hw2reg_main_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ logic [3:0] d;
+ logic de;
+ } clkmgr_hw2reg_usb_meas_ctrl_en_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } shadow_update_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_measure_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_div2_measure_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_div4_measure_err;
+ struct packed {
+ logic d;
+ logic de;
+ } main_measure_err;
+ struct packed {
+ logic d;
+ logic de;
+ } usb_measure_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_timeout_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_div2_timeout_err;
+ struct packed {
+ logic d;
+ logic de;
+ } io_div4_timeout_err;
+ struct packed {
+ logic d;
+ logic de;
+ } main_timeout_err;
+ struct packed {
+ logic d;
+ logic de;
+ } usb_timeout_err;
+ } clkmgr_hw2reg_recov_err_code_reg_t;
+
+ typedef struct packed {
+ struct packed {
+ logic d;
+ logic de;
+ } reg_intg;
+ struct packed {
+ logic d;
+ logic de;
+ } idle_cnt;
+ struct packed {
+ logic d;
+ logic de;
+ } shadow_storage_err;
+ } clkmgr_hw2reg_fatal_err_code_reg_t;
+
+ // Register -> HW type
+ typedef struct packed {
+ clkmgr_reg2hw_alert_test_reg_t alert_test; // [139:136]
+ clkmgr_reg2hw_extclk_ctrl_reg_t extclk_ctrl; // [135:128]
+ clkmgr_reg2hw_jitter_enable_reg_t jitter_enable; // [127:124]
+ clkmgr_reg2hw_clk_enables_reg_t clk_enables; // [123:120]
+ clkmgr_reg2hw_clk_hints_reg_t clk_hints; // [119:116]
+ clkmgr_reg2hw_measure_ctrl_regwen_reg_t measure_ctrl_regwen; // [115:115]
+ clkmgr_reg2hw_io_meas_ctrl_en_reg_t io_meas_ctrl_en; // [114:111]
+ clkmgr_reg2hw_io_meas_ctrl_shadowed_reg_t io_meas_ctrl_shadowed; // [110:91]
+ clkmgr_reg2hw_io_div2_meas_ctrl_en_reg_t io_div2_meas_ctrl_en; // [90:87]
+ clkmgr_reg2hw_io_div2_meas_ctrl_shadowed_reg_t io_div2_meas_ctrl_shadowed; // [86:69]
+ clkmgr_reg2hw_io_div4_meas_ctrl_en_reg_t io_div4_meas_ctrl_en; // [68:65]
+ clkmgr_reg2hw_io_div4_meas_ctrl_shadowed_reg_t io_div4_meas_ctrl_shadowed; // [64:49]
+ clkmgr_reg2hw_main_meas_ctrl_en_reg_t main_meas_ctrl_en; // [48:45]
+ clkmgr_reg2hw_main_meas_ctrl_shadowed_reg_t main_meas_ctrl_shadowed; // [44:25]
+ clkmgr_reg2hw_usb_meas_ctrl_en_reg_t usb_meas_ctrl_en; // [24:21]
+ clkmgr_reg2hw_usb_meas_ctrl_shadowed_reg_t usb_meas_ctrl_shadowed; // [20:3]
+ clkmgr_reg2hw_fatal_err_code_reg_t fatal_err_code; // [2:0]
+ } clkmgr_reg2hw_t;
+
+ // HW -> register type
+ typedef struct packed {
+ clkmgr_hw2reg_extclk_status_reg_t extclk_status; // [66:63]
+ clkmgr_hw2reg_clk_hints_status_reg_t clk_hints_status; // [62:55]
+ clkmgr_hw2reg_measure_ctrl_regwen_reg_t measure_ctrl_regwen; // [54:53]
+ clkmgr_hw2reg_io_meas_ctrl_en_reg_t io_meas_ctrl_en; // [52:48]
+ clkmgr_hw2reg_io_div2_meas_ctrl_en_reg_t io_div2_meas_ctrl_en; // [47:43]
+ clkmgr_hw2reg_io_div4_meas_ctrl_en_reg_t io_div4_meas_ctrl_en; // [42:38]
+ clkmgr_hw2reg_main_meas_ctrl_en_reg_t main_meas_ctrl_en; // [37:33]
+ clkmgr_hw2reg_usb_meas_ctrl_en_reg_t usb_meas_ctrl_en; // [32:28]
+ clkmgr_hw2reg_recov_err_code_reg_t recov_err_code; // [27:6]
+ clkmgr_hw2reg_fatal_err_code_reg_t fatal_err_code; // [5:0]
+ } clkmgr_hw2reg_t;
+
+ // Register offsets
+ parameter logic [BlockAw-1:0] CLKMGR_ALERT_TEST_OFFSET = 7'h 0;
+ parameter logic [BlockAw-1:0] CLKMGR_EXTCLK_CTRL_REGWEN_OFFSET = 7'h 4;
+ parameter logic [BlockAw-1:0] CLKMGR_EXTCLK_CTRL_OFFSET = 7'h 8;
+ parameter logic [BlockAw-1:0] CLKMGR_EXTCLK_STATUS_OFFSET = 7'h c;
+ parameter logic [BlockAw-1:0] CLKMGR_JITTER_REGWEN_OFFSET = 7'h 10;
+ parameter logic [BlockAw-1:0] CLKMGR_JITTER_ENABLE_OFFSET = 7'h 14;
+ parameter logic [BlockAw-1:0] CLKMGR_CLK_ENABLES_OFFSET = 7'h 18;
+ parameter logic [BlockAw-1:0] CLKMGR_CLK_HINTS_OFFSET = 7'h 1c;
+ parameter logic [BlockAw-1:0] CLKMGR_CLK_HINTS_STATUS_OFFSET = 7'h 20;
+ parameter logic [BlockAw-1:0] CLKMGR_MEASURE_CTRL_REGWEN_OFFSET = 7'h 24;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_MEAS_CTRL_EN_OFFSET = 7'h 28;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_MEAS_CTRL_SHADOWED_OFFSET = 7'h 2c;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_DIV2_MEAS_CTRL_EN_OFFSET = 7'h 30;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_DIV2_MEAS_CTRL_SHADOWED_OFFSET = 7'h 34;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_DIV4_MEAS_CTRL_EN_OFFSET = 7'h 38;
+ parameter logic [BlockAw-1:0] CLKMGR_IO_DIV4_MEAS_CTRL_SHADOWED_OFFSET = 7'h 3c;
+ parameter logic [BlockAw-1:0] CLKMGR_MAIN_MEAS_CTRL_EN_OFFSET = 7'h 40;
+ parameter logic [BlockAw-1:0] CLKMGR_MAIN_MEAS_CTRL_SHADOWED_OFFSET = 7'h 44;
+ parameter logic [BlockAw-1:0] CLKMGR_USB_MEAS_CTRL_EN_OFFSET = 7'h 48;
+ parameter logic [BlockAw-1:0] CLKMGR_USB_MEAS_CTRL_SHADOWED_OFFSET = 7'h 4c;
+ parameter logic [BlockAw-1:0] CLKMGR_RECOV_ERR_CODE_OFFSET = 7'h 50;
+ parameter logic [BlockAw-1:0] CLKMGR_FATAL_ERR_CODE_OFFSET = 7'h 54;
+
+ // Reset values for hwext registers and their fields
+ parameter logic [1:0] CLKMGR_ALERT_TEST_RESVAL = 2'h 0;
+ parameter logic [0:0] CLKMGR_ALERT_TEST_RECOV_FAULT_RESVAL = 1'h 0;
+ parameter logic [0:0] CLKMGR_ALERT_TEST_FATAL_FAULT_RESVAL = 1'h 0;
+ parameter logic [3:0] CLKMGR_EXTCLK_STATUS_RESVAL = 4'h 9;
+ parameter logic [3:0] CLKMGR_EXTCLK_STATUS_ACK_RESVAL = 4'h 9;
+
+ // Register index
+ typedef enum int {
+ CLKMGR_ALERT_TEST,
+ CLKMGR_EXTCLK_CTRL_REGWEN,
+ CLKMGR_EXTCLK_CTRL,
+ CLKMGR_EXTCLK_STATUS,
+ CLKMGR_JITTER_REGWEN,
+ CLKMGR_JITTER_ENABLE,
+ CLKMGR_CLK_ENABLES,
+ CLKMGR_CLK_HINTS,
+ CLKMGR_CLK_HINTS_STATUS,
+ CLKMGR_MEASURE_CTRL_REGWEN,
+ CLKMGR_IO_MEAS_CTRL_EN,
+ CLKMGR_IO_MEAS_CTRL_SHADOWED,
+ CLKMGR_IO_DIV2_MEAS_CTRL_EN,
+ CLKMGR_IO_DIV2_MEAS_CTRL_SHADOWED,
+ CLKMGR_IO_DIV4_MEAS_CTRL_EN,
+ CLKMGR_IO_DIV4_MEAS_CTRL_SHADOWED,
+ CLKMGR_MAIN_MEAS_CTRL_EN,
+ CLKMGR_MAIN_MEAS_CTRL_SHADOWED,
+ CLKMGR_USB_MEAS_CTRL_EN,
+ CLKMGR_USB_MEAS_CTRL_SHADOWED,
+ CLKMGR_RECOV_ERR_CODE,
+ CLKMGR_FATAL_ERR_CODE
+ } clkmgr_id_e;
+
+ // Register width information to check illegal writes
+ parameter logic [3:0] CLKMGR_PERMIT [22] = '{
+ 4'b 0001, // index[ 0] CLKMGR_ALERT_TEST
+ 4'b 0001, // index[ 1] CLKMGR_EXTCLK_CTRL_REGWEN
+ 4'b 0001, // index[ 2] CLKMGR_EXTCLK_CTRL
+ 4'b 0001, // index[ 3] CLKMGR_EXTCLK_STATUS
+ 4'b 0001, // index[ 4] CLKMGR_JITTER_REGWEN
+ 4'b 0001, // index[ 5] CLKMGR_JITTER_ENABLE
+ 4'b 0001, // index[ 6] CLKMGR_CLK_ENABLES
+ 4'b 0001, // index[ 7] CLKMGR_CLK_HINTS
+ 4'b 0001, // index[ 8] CLKMGR_CLK_HINTS_STATUS
+ 4'b 0001, // index[ 9] CLKMGR_MEASURE_CTRL_REGWEN
+ 4'b 0001, // index[10] CLKMGR_IO_MEAS_CTRL_EN
+ 4'b 0111, // index[11] CLKMGR_IO_MEAS_CTRL_SHADOWED
+ 4'b 0001, // index[12] CLKMGR_IO_DIV2_MEAS_CTRL_EN
+ 4'b 0111, // index[13] CLKMGR_IO_DIV2_MEAS_CTRL_SHADOWED
+ 4'b 0001, // index[14] CLKMGR_IO_DIV4_MEAS_CTRL_EN
+ 4'b 0011, // index[15] CLKMGR_IO_DIV4_MEAS_CTRL_SHADOWED
+ 4'b 0001, // index[16] CLKMGR_MAIN_MEAS_CTRL_EN
+ 4'b 0111, // index[17] CLKMGR_MAIN_MEAS_CTRL_SHADOWED
+ 4'b 0001, // index[18] CLKMGR_USB_MEAS_CTRL_EN
+ 4'b 0111, // index[19] CLKMGR_USB_MEAS_CTRL_SHADOWED
+ 4'b 0011, // index[20] CLKMGR_RECOV_ERR_CODE
+ 4'b 0001 // index[21] CLKMGR_FATAL_ERR_CODE
+ };
+
+endpackage
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv
new file mode 100644
index 00000000000000..c1461a04552f72
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_reg_top.sv
@@ -0,0 +1,2825 @@
+// 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 clkmgr_reg_top (
+ input clk_i,
+ input rst_ni,
+ input rst_shadowed_ni,
+ input clk_io_i,
+ input rst_io_ni,
+ input clk_io_div2_i,
+ input rst_io_div2_ni,
+ input clk_io_div4_i,
+ input rst_io_div4_ni,
+ input clk_main_i,
+ input rst_main_ni,
+ input clk_usb_i,
+ input rst_usb_ni,
+ input tlul_pkg::tl_h2d_t tl_i,
+ output tlul_pkg::tl_d2h_t tl_o,
+ // To HW
+ output clkmgr_reg_pkg::clkmgr_reg2hw_t reg2hw, // Write
+ input clkmgr_reg_pkg::clkmgr_hw2reg_t hw2reg, // Read
+
+ output logic shadowed_storage_err_o,
+ output logic shadowed_update_err_o,
+
+ // Integrity check errors
+ output logic intg_err_o
+);
+
+ import clkmgr_reg_pkg::* ;
+
+ localparam int AW = 7;
+ 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;
+ logic reg_busy;
+
+ tlul_pkg::tl_h2d_t tl_reg_h2d;
+ tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+
+ // incoming payload check
+ logic intg_err;
+ tlul_cmd_intg_chk u_chk (
+ .tl_i(tl_i),
+ .err_o(intg_err)
+ );
+
+ // also check for spurious write enables
+ logic reg_we_err;
+ logic [21:0] reg_we_check;
+ prim_reg_we_check #(
+ .OneHotWidth(22)
+ ) u_prim_reg_we_check (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .oh_i (reg_we_check),
+ .en_i (reg_we && !addrmiss),
+ .err_o (reg_we_err)
+ );
+
+ logic err_q;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ err_q <= '0;
+ end else if (intg_err || reg_we_err) begin
+ err_q <= 1'b1;
+ end
+ end
+
+ // integrity error output is permanent and should be used for alert generation
+ // register errors are transactional
+ assign intg_err_o = err_q | intg_err | reg_we_err;
+
+ // outgoing integrity generation
+ tlul_pkg::tl_d2h_t tl_o_pre;
+ tlul_rsp_intg_gen #(
+ .EnableRspIntgGen(1),
+ .EnableDataIntgGen(1)
+ ) u_rsp_intg_gen (
+ .tl_i(tl_o_pre),
+ .tl_o(tl_o)
+ );
+
+ assign tl_reg_h2d = tl_i;
+ assign tl_o_pre = tl_reg_d2h;
+
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW),
+ .EnableDataIntgGen(0)
+ ) u_reg_if (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
+
+ .en_ifetch_i(prim_mubi_pkg::MuBi4False),
+ .intg_error_o(),
+
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .busy_i (reg_busy),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
+
+ // cdc oversampling signals
+
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = addrmiss | wr_err | intg_err;
+
+ // Define SW related signals
+ // Format: __{wd|we|qs}
+ // or _{wd|we|qs} if field == 1 or 0
+ logic alert_test_we;
+ logic alert_test_recov_fault_wd;
+ logic alert_test_fatal_fault_wd;
+ logic extclk_ctrl_regwen_we;
+ logic extclk_ctrl_regwen_qs;
+ logic extclk_ctrl_regwen_wd;
+ logic extclk_ctrl_we;
+ logic [3:0] extclk_ctrl_sel_qs;
+ logic [3:0] extclk_ctrl_sel_wd;
+ logic [3:0] extclk_ctrl_hi_speed_sel_qs;
+ logic [3:0] extclk_ctrl_hi_speed_sel_wd;
+ logic extclk_status_re;
+ logic [3:0] extclk_status_qs;
+ logic jitter_regwen_we;
+ logic jitter_regwen_qs;
+ logic jitter_regwen_wd;
+ logic jitter_enable_we;
+ logic [3:0] jitter_enable_qs;
+ logic [3:0] jitter_enable_wd;
+ logic clk_enables_we;
+ logic clk_enables_clk_io_div4_peri_en_qs;
+ logic clk_enables_clk_io_div4_peri_en_wd;
+ logic clk_enables_clk_io_div2_peri_en_qs;
+ logic clk_enables_clk_io_div2_peri_en_wd;
+ logic clk_enables_clk_io_peri_en_qs;
+ logic clk_enables_clk_io_peri_en_wd;
+ logic clk_enables_clk_usb_peri_en_qs;
+ logic clk_enables_clk_usb_peri_en_wd;
+ logic clk_hints_we;
+ logic clk_hints_clk_main_aes_hint_qs;
+ logic clk_hints_clk_main_aes_hint_wd;
+ logic clk_hints_clk_main_hmac_hint_qs;
+ logic clk_hints_clk_main_hmac_hint_wd;
+ logic clk_hints_clk_main_kmac_hint_qs;
+ logic clk_hints_clk_main_kmac_hint_wd;
+ logic clk_hints_clk_main_otbn_hint_qs;
+ logic clk_hints_clk_main_otbn_hint_wd;
+ logic clk_hints_status_clk_main_aes_val_qs;
+ logic clk_hints_status_clk_main_hmac_val_qs;
+ logic clk_hints_status_clk_main_kmac_val_qs;
+ logic clk_hints_status_clk_main_otbn_val_qs;
+ logic measure_ctrl_regwen_we;
+ logic measure_ctrl_regwen_qs;
+ logic measure_ctrl_regwen_wd;
+ logic io_meas_ctrl_en_we;
+ logic [3:0] io_meas_ctrl_en_qs;
+ logic io_meas_ctrl_en_busy;
+ logic io_meas_ctrl_shadowed_re;
+ logic io_meas_ctrl_shadowed_we;
+ logic [19:0] io_meas_ctrl_shadowed_qs;
+ logic io_meas_ctrl_shadowed_busy;
+ logic io_meas_ctrl_shadowed_hi_storage_err;
+ logic io_meas_ctrl_shadowed_hi_update_err;
+ logic io_meas_ctrl_shadowed_lo_storage_err;
+ logic io_meas_ctrl_shadowed_lo_update_err;
+ logic io_div2_meas_ctrl_en_we;
+ logic [3:0] io_div2_meas_ctrl_en_qs;
+ logic io_div2_meas_ctrl_en_busy;
+ logic io_div2_meas_ctrl_shadowed_re;
+ logic io_div2_meas_ctrl_shadowed_we;
+ logic [17:0] io_div2_meas_ctrl_shadowed_qs;
+ logic io_div2_meas_ctrl_shadowed_busy;
+ logic io_div2_meas_ctrl_shadowed_hi_storage_err;
+ logic io_div2_meas_ctrl_shadowed_hi_update_err;
+ logic io_div2_meas_ctrl_shadowed_lo_storage_err;
+ logic io_div2_meas_ctrl_shadowed_lo_update_err;
+ logic io_div4_meas_ctrl_en_we;
+ logic [3:0] io_div4_meas_ctrl_en_qs;
+ logic io_div4_meas_ctrl_en_busy;
+ logic io_div4_meas_ctrl_shadowed_re;
+ logic io_div4_meas_ctrl_shadowed_we;
+ logic [15:0] io_div4_meas_ctrl_shadowed_qs;
+ logic io_div4_meas_ctrl_shadowed_busy;
+ logic io_div4_meas_ctrl_shadowed_hi_storage_err;
+ logic io_div4_meas_ctrl_shadowed_hi_update_err;
+ logic io_div4_meas_ctrl_shadowed_lo_storage_err;
+ logic io_div4_meas_ctrl_shadowed_lo_update_err;
+ logic main_meas_ctrl_en_we;
+ logic [3:0] main_meas_ctrl_en_qs;
+ logic main_meas_ctrl_en_busy;
+ logic main_meas_ctrl_shadowed_re;
+ logic main_meas_ctrl_shadowed_we;
+ logic [19:0] main_meas_ctrl_shadowed_qs;
+ logic main_meas_ctrl_shadowed_busy;
+ logic main_meas_ctrl_shadowed_hi_storage_err;
+ logic main_meas_ctrl_shadowed_hi_update_err;
+ logic main_meas_ctrl_shadowed_lo_storage_err;
+ logic main_meas_ctrl_shadowed_lo_update_err;
+ logic usb_meas_ctrl_en_we;
+ logic [3:0] usb_meas_ctrl_en_qs;
+ logic usb_meas_ctrl_en_busy;
+ logic usb_meas_ctrl_shadowed_re;
+ logic usb_meas_ctrl_shadowed_we;
+ logic [17:0] usb_meas_ctrl_shadowed_qs;
+ logic usb_meas_ctrl_shadowed_busy;
+ logic usb_meas_ctrl_shadowed_hi_storage_err;
+ logic usb_meas_ctrl_shadowed_hi_update_err;
+ logic usb_meas_ctrl_shadowed_lo_storage_err;
+ logic usb_meas_ctrl_shadowed_lo_update_err;
+ logic recov_err_code_we;
+ logic recov_err_code_shadow_update_err_qs;
+ logic recov_err_code_shadow_update_err_wd;
+ logic recov_err_code_io_measure_err_qs;
+ logic recov_err_code_io_measure_err_wd;
+ logic recov_err_code_io_div2_measure_err_qs;
+ logic recov_err_code_io_div2_measure_err_wd;
+ logic recov_err_code_io_div4_measure_err_qs;
+ logic recov_err_code_io_div4_measure_err_wd;
+ logic recov_err_code_main_measure_err_qs;
+ logic recov_err_code_main_measure_err_wd;
+ logic recov_err_code_usb_measure_err_qs;
+ logic recov_err_code_usb_measure_err_wd;
+ logic recov_err_code_io_timeout_err_qs;
+ logic recov_err_code_io_timeout_err_wd;
+ logic recov_err_code_io_div2_timeout_err_qs;
+ logic recov_err_code_io_div2_timeout_err_wd;
+ logic recov_err_code_io_div4_timeout_err_qs;
+ logic recov_err_code_io_div4_timeout_err_wd;
+ logic recov_err_code_main_timeout_err_qs;
+ logic recov_err_code_main_timeout_err_wd;
+ logic recov_err_code_usb_timeout_err_qs;
+ logic recov_err_code_usb_timeout_err_wd;
+ logic fatal_err_code_reg_intg_qs;
+ logic fatal_err_code_idle_cnt_qs;
+ logic fatal_err_code_shadow_storage_err_qs;
+ // Define register CDC handling.
+ // CDC handling is done on a per-reg instead of per-field boundary.
+
+ logic [3:0] io_io_meas_ctrl_en_ds_int;
+ logic [3:0] io_io_meas_ctrl_en_qs_int;
+ logic [3:0] io_io_meas_ctrl_en_ds;
+ logic io_io_meas_ctrl_en_qe;
+ logic [3:0] io_io_meas_ctrl_en_qs;
+ logic [3:0] io_io_meas_ctrl_en_wdata;
+ logic io_io_meas_ctrl_en_we;
+ logic unused_io_io_meas_ctrl_en_wdata;
+ logic io_io_meas_ctrl_en_regwen;
+
+ always_comb begin
+ io_io_meas_ctrl_en_qs = 4'h9;
+ io_io_meas_ctrl_en_ds = 4'h9;
+ io_io_meas_ctrl_en_ds = io_io_meas_ctrl_en_ds_int;
+ io_io_meas_ctrl_en_qs = io_io_meas_ctrl_en_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(4),
+ .ResetVal(4'h9),
+ .BitMask(4'hf),
+ .DstWrReq(1)
+ ) u_io_meas_ctrl_en_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_i),
+ .rst_dst_ni (rst_io_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_meas_ctrl_en_we),
+ .src_re_i ('0),
+ .src_wd_i (reg_wdata[3:0]),
+ .src_busy_o (io_meas_ctrl_en_busy),
+ .src_qs_o (io_meas_ctrl_en_qs), // for software read back
+ .dst_update_i (io_io_meas_ctrl_en_qe),
+ .dst_ds_i (io_io_meas_ctrl_en_ds),
+ .dst_qs_i (io_io_meas_ctrl_en_qs),
+ .dst_we_o (io_io_meas_ctrl_en_we),
+ .dst_re_o (),
+ .dst_regwen_o (io_io_meas_ctrl_en_regwen),
+ .dst_wd_o (io_io_meas_ctrl_en_wdata)
+ );
+ assign unused_io_io_meas_ctrl_en_wdata =
+ ^io_io_meas_ctrl_en_wdata;
+
+ logic [9:0] io_io_meas_ctrl_shadowed_hi_qs_int;
+ logic [9:0] io_io_meas_ctrl_shadowed_lo_qs_int;
+ logic [19:0] io_io_meas_ctrl_shadowed_qs;
+ logic [19:0] io_io_meas_ctrl_shadowed_wdata;
+ logic io_io_meas_ctrl_shadowed_we;
+ logic unused_io_io_meas_ctrl_shadowed_wdata;
+ logic io_io_meas_ctrl_shadowed_re;
+ logic io_io_meas_ctrl_shadowed_regwen;
+
+ always_comb begin
+ io_io_meas_ctrl_shadowed_qs = 20'h759ea;
+ io_io_meas_ctrl_shadowed_qs[9:0] = io_io_meas_ctrl_shadowed_hi_qs_int;
+ io_io_meas_ctrl_shadowed_qs[19:10] = io_io_meas_ctrl_shadowed_lo_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(20),
+ .ResetVal(20'h759ea),
+ .BitMask(20'hfffff),
+ .DstWrReq(0)
+ ) u_io_meas_ctrl_shadowed_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_i),
+ .rst_dst_ni (rst_io_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_meas_ctrl_shadowed_we),
+ .src_re_i (io_meas_ctrl_shadowed_re),
+ .src_wd_i (reg_wdata[19:0]),
+ .src_busy_o (io_meas_ctrl_shadowed_busy),
+ .src_qs_o (io_meas_ctrl_shadowed_qs), // for software read back
+ .dst_update_i ('0),
+ .dst_ds_i ('0),
+ .dst_qs_i (io_io_meas_ctrl_shadowed_qs),
+ .dst_we_o (io_io_meas_ctrl_shadowed_we),
+ .dst_re_o (io_io_meas_ctrl_shadowed_re),
+ .dst_regwen_o (io_io_meas_ctrl_shadowed_regwen),
+ .dst_wd_o (io_io_meas_ctrl_shadowed_wdata)
+ );
+ assign unused_io_io_meas_ctrl_shadowed_wdata =
+ ^io_io_meas_ctrl_shadowed_wdata;
+
+ logic [3:0] io_div2_io_div2_meas_ctrl_en_ds_int;
+ logic [3:0] io_div2_io_div2_meas_ctrl_en_qs_int;
+ logic [3:0] io_div2_io_div2_meas_ctrl_en_ds;
+ logic io_div2_io_div2_meas_ctrl_en_qe;
+ logic [3:0] io_div2_io_div2_meas_ctrl_en_qs;
+ logic [3:0] io_div2_io_div2_meas_ctrl_en_wdata;
+ logic io_div2_io_div2_meas_ctrl_en_we;
+ logic unused_io_div2_io_div2_meas_ctrl_en_wdata;
+ logic io_div2_io_div2_meas_ctrl_en_regwen;
+
+ always_comb begin
+ io_div2_io_div2_meas_ctrl_en_qs = 4'h9;
+ io_div2_io_div2_meas_ctrl_en_ds = 4'h9;
+ io_div2_io_div2_meas_ctrl_en_ds = io_div2_io_div2_meas_ctrl_en_ds_int;
+ io_div2_io_div2_meas_ctrl_en_qs = io_div2_io_div2_meas_ctrl_en_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(4),
+ .ResetVal(4'h9),
+ .BitMask(4'hf),
+ .DstWrReq(1)
+ ) u_io_div2_meas_ctrl_en_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_div2_i),
+ .rst_dst_ni (rst_io_div2_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_div2_meas_ctrl_en_we),
+ .src_re_i ('0),
+ .src_wd_i (reg_wdata[3:0]),
+ .src_busy_o (io_div2_meas_ctrl_en_busy),
+ .src_qs_o (io_div2_meas_ctrl_en_qs), // for software read back
+ .dst_update_i (io_div2_io_div2_meas_ctrl_en_qe),
+ .dst_ds_i (io_div2_io_div2_meas_ctrl_en_ds),
+ .dst_qs_i (io_div2_io_div2_meas_ctrl_en_qs),
+ .dst_we_o (io_div2_io_div2_meas_ctrl_en_we),
+ .dst_re_o (),
+ .dst_regwen_o (io_div2_io_div2_meas_ctrl_en_regwen),
+ .dst_wd_o (io_div2_io_div2_meas_ctrl_en_wdata)
+ );
+ assign unused_io_div2_io_div2_meas_ctrl_en_wdata =
+ ^io_div2_io_div2_meas_ctrl_en_wdata;
+
+ logic [8:0] io_div2_io_div2_meas_ctrl_shadowed_hi_qs_int;
+ logic [8:0] io_div2_io_div2_meas_ctrl_shadowed_lo_qs_int;
+ logic [17:0] io_div2_io_div2_meas_ctrl_shadowed_qs;
+ logic [17:0] io_div2_io_div2_meas_ctrl_shadowed_wdata;
+ logic io_div2_io_div2_meas_ctrl_shadowed_we;
+ logic unused_io_div2_io_div2_meas_ctrl_shadowed_wdata;
+ logic io_div2_io_div2_meas_ctrl_shadowed_re;
+ logic io_div2_io_div2_meas_ctrl_shadowed_regwen;
+
+ always_comb begin
+ io_div2_io_div2_meas_ctrl_shadowed_qs = 18'h1ccfa;
+ io_div2_io_div2_meas_ctrl_shadowed_qs[8:0] = io_div2_io_div2_meas_ctrl_shadowed_hi_qs_int;
+ io_div2_io_div2_meas_ctrl_shadowed_qs[17:9] = io_div2_io_div2_meas_ctrl_shadowed_lo_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(18),
+ .ResetVal(18'h1ccfa),
+ .BitMask(18'h3ffff),
+ .DstWrReq(0)
+ ) u_io_div2_meas_ctrl_shadowed_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_div2_i),
+ .rst_dst_ni (rst_io_div2_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_div2_meas_ctrl_shadowed_we),
+ .src_re_i (io_div2_meas_ctrl_shadowed_re),
+ .src_wd_i (reg_wdata[17:0]),
+ .src_busy_o (io_div2_meas_ctrl_shadowed_busy),
+ .src_qs_o (io_div2_meas_ctrl_shadowed_qs), // for software read back
+ .dst_update_i ('0),
+ .dst_ds_i ('0),
+ .dst_qs_i (io_div2_io_div2_meas_ctrl_shadowed_qs),
+ .dst_we_o (io_div2_io_div2_meas_ctrl_shadowed_we),
+ .dst_re_o (io_div2_io_div2_meas_ctrl_shadowed_re),
+ .dst_regwen_o (io_div2_io_div2_meas_ctrl_shadowed_regwen),
+ .dst_wd_o (io_div2_io_div2_meas_ctrl_shadowed_wdata)
+ );
+ assign unused_io_div2_io_div2_meas_ctrl_shadowed_wdata =
+ ^io_div2_io_div2_meas_ctrl_shadowed_wdata;
+
+ logic [3:0] io_div4_io_div4_meas_ctrl_en_ds_int;
+ logic [3:0] io_div4_io_div4_meas_ctrl_en_qs_int;
+ logic [3:0] io_div4_io_div4_meas_ctrl_en_ds;
+ logic io_div4_io_div4_meas_ctrl_en_qe;
+ logic [3:0] io_div4_io_div4_meas_ctrl_en_qs;
+ logic [3:0] io_div4_io_div4_meas_ctrl_en_wdata;
+ logic io_div4_io_div4_meas_ctrl_en_we;
+ logic unused_io_div4_io_div4_meas_ctrl_en_wdata;
+ logic io_div4_io_div4_meas_ctrl_en_regwen;
+
+ always_comb begin
+ io_div4_io_div4_meas_ctrl_en_qs = 4'h9;
+ io_div4_io_div4_meas_ctrl_en_ds = 4'h9;
+ io_div4_io_div4_meas_ctrl_en_ds = io_div4_io_div4_meas_ctrl_en_ds_int;
+ io_div4_io_div4_meas_ctrl_en_qs = io_div4_io_div4_meas_ctrl_en_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(4),
+ .ResetVal(4'h9),
+ .BitMask(4'hf),
+ .DstWrReq(1)
+ ) u_io_div4_meas_ctrl_en_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_div4_i),
+ .rst_dst_ni (rst_io_div4_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_div4_meas_ctrl_en_we),
+ .src_re_i ('0),
+ .src_wd_i (reg_wdata[3:0]),
+ .src_busy_o (io_div4_meas_ctrl_en_busy),
+ .src_qs_o (io_div4_meas_ctrl_en_qs), // for software read back
+ .dst_update_i (io_div4_io_div4_meas_ctrl_en_qe),
+ .dst_ds_i (io_div4_io_div4_meas_ctrl_en_ds),
+ .dst_qs_i (io_div4_io_div4_meas_ctrl_en_qs),
+ .dst_we_o (io_div4_io_div4_meas_ctrl_en_we),
+ .dst_re_o (),
+ .dst_regwen_o (io_div4_io_div4_meas_ctrl_en_regwen),
+ .dst_wd_o (io_div4_io_div4_meas_ctrl_en_wdata)
+ );
+ assign unused_io_div4_io_div4_meas_ctrl_en_wdata =
+ ^io_div4_io_div4_meas_ctrl_en_wdata;
+
+ logic [7:0] io_div4_io_div4_meas_ctrl_shadowed_hi_qs_int;
+ logic [7:0] io_div4_io_div4_meas_ctrl_shadowed_lo_qs_int;
+ logic [15:0] io_div4_io_div4_meas_ctrl_shadowed_qs;
+ logic [15:0] io_div4_io_div4_meas_ctrl_shadowed_wdata;
+ logic io_div4_io_div4_meas_ctrl_shadowed_we;
+ logic unused_io_div4_io_div4_meas_ctrl_shadowed_wdata;
+ logic io_div4_io_div4_meas_ctrl_shadowed_re;
+ logic io_div4_io_div4_meas_ctrl_shadowed_regwen;
+
+ always_comb begin
+ io_div4_io_div4_meas_ctrl_shadowed_qs = 16'h6e82;
+ io_div4_io_div4_meas_ctrl_shadowed_qs[7:0] = io_div4_io_div4_meas_ctrl_shadowed_hi_qs_int;
+ io_div4_io_div4_meas_ctrl_shadowed_qs[15:8] = io_div4_io_div4_meas_ctrl_shadowed_lo_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(16),
+ .ResetVal(16'h6e82),
+ .BitMask(16'hffff),
+ .DstWrReq(0)
+ ) u_io_div4_meas_ctrl_shadowed_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_io_div4_i),
+ .rst_dst_ni (rst_io_div4_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (io_div4_meas_ctrl_shadowed_we),
+ .src_re_i (io_div4_meas_ctrl_shadowed_re),
+ .src_wd_i (reg_wdata[15:0]),
+ .src_busy_o (io_div4_meas_ctrl_shadowed_busy),
+ .src_qs_o (io_div4_meas_ctrl_shadowed_qs), // for software read back
+ .dst_update_i ('0),
+ .dst_ds_i ('0),
+ .dst_qs_i (io_div4_io_div4_meas_ctrl_shadowed_qs),
+ .dst_we_o (io_div4_io_div4_meas_ctrl_shadowed_we),
+ .dst_re_o (io_div4_io_div4_meas_ctrl_shadowed_re),
+ .dst_regwen_o (io_div4_io_div4_meas_ctrl_shadowed_regwen),
+ .dst_wd_o (io_div4_io_div4_meas_ctrl_shadowed_wdata)
+ );
+ assign unused_io_div4_io_div4_meas_ctrl_shadowed_wdata =
+ ^io_div4_io_div4_meas_ctrl_shadowed_wdata;
+
+ logic [3:0] main_main_meas_ctrl_en_ds_int;
+ logic [3:0] main_main_meas_ctrl_en_qs_int;
+ logic [3:0] main_main_meas_ctrl_en_ds;
+ logic main_main_meas_ctrl_en_qe;
+ logic [3:0] main_main_meas_ctrl_en_qs;
+ logic [3:0] main_main_meas_ctrl_en_wdata;
+ logic main_main_meas_ctrl_en_we;
+ logic unused_main_main_meas_ctrl_en_wdata;
+ logic main_main_meas_ctrl_en_regwen;
+
+ always_comb begin
+ main_main_meas_ctrl_en_qs = 4'h9;
+ main_main_meas_ctrl_en_ds = 4'h9;
+ main_main_meas_ctrl_en_ds = main_main_meas_ctrl_en_ds_int;
+ main_main_meas_ctrl_en_qs = main_main_meas_ctrl_en_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(4),
+ .ResetVal(4'h9),
+ .BitMask(4'hf),
+ .DstWrReq(1)
+ ) u_main_meas_ctrl_en_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_main_i),
+ .rst_dst_ni (rst_main_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (main_meas_ctrl_en_we),
+ .src_re_i ('0),
+ .src_wd_i (reg_wdata[3:0]),
+ .src_busy_o (main_meas_ctrl_en_busy),
+ .src_qs_o (main_meas_ctrl_en_qs), // for software read back
+ .dst_update_i (main_main_meas_ctrl_en_qe),
+ .dst_ds_i (main_main_meas_ctrl_en_ds),
+ .dst_qs_i (main_main_meas_ctrl_en_qs),
+ .dst_we_o (main_main_meas_ctrl_en_we),
+ .dst_re_o (),
+ .dst_regwen_o (main_main_meas_ctrl_en_regwen),
+ .dst_wd_o (main_main_meas_ctrl_en_wdata)
+ );
+ assign unused_main_main_meas_ctrl_en_wdata =
+ ^main_main_meas_ctrl_en_wdata;
+
+ logic [9:0] main_main_meas_ctrl_shadowed_hi_qs_int;
+ logic [9:0] main_main_meas_ctrl_shadowed_lo_qs_int;
+ logic [19:0] main_main_meas_ctrl_shadowed_qs;
+ logic [19:0] main_main_meas_ctrl_shadowed_wdata;
+ logic main_main_meas_ctrl_shadowed_we;
+ logic unused_main_main_meas_ctrl_shadowed_wdata;
+ logic main_main_meas_ctrl_shadowed_re;
+ logic main_main_meas_ctrl_shadowed_regwen;
+
+ always_comb begin
+ main_main_meas_ctrl_shadowed_qs = 20'h7a9fe;
+ main_main_meas_ctrl_shadowed_qs[9:0] = main_main_meas_ctrl_shadowed_hi_qs_int;
+ main_main_meas_ctrl_shadowed_qs[19:10] = main_main_meas_ctrl_shadowed_lo_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(20),
+ .ResetVal(20'h7a9fe),
+ .BitMask(20'hfffff),
+ .DstWrReq(0)
+ ) u_main_meas_ctrl_shadowed_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_main_i),
+ .rst_dst_ni (rst_main_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (main_meas_ctrl_shadowed_we),
+ .src_re_i (main_meas_ctrl_shadowed_re),
+ .src_wd_i (reg_wdata[19:0]),
+ .src_busy_o (main_meas_ctrl_shadowed_busy),
+ .src_qs_o (main_meas_ctrl_shadowed_qs), // for software read back
+ .dst_update_i ('0),
+ .dst_ds_i ('0),
+ .dst_qs_i (main_main_meas_ctrl_shadowed_qs),
+ .dst_we_o (main_main_meas_ctrl_shadowed_we),
+ .dst_re_o (main_main_meas_ctrl_shadowed_re),
+ .dst_regwen_o (main_main_meas_ctrl_shadowed_regwen),
+ .dst_wd_o (main_main_meas_ctrl_shadowed_wdata)
+ );
+ assign unused_main_main_meas_ctrl_shadowed_wdata =
+ ^main_main_meas_ctrl_shadowed_wdata;
+
+ logic [3:0] usb_usb_meas_ctrl_en_ds_int;
+ logic [3:0] usb_usb_meas_ctrl_en_qs_int;
+ logic [3:0] usb_usb_meas_ctrl_en_ds;
+ logic usb_usb_meas_ctrl_en_qe;
+ logic [3:0] usb_usb_meas_ctrl_en_qs;
+ logic [3:0] usb_usb_meas_ctrl_en_wdata;
+ logic usb_usb_meas_ctrl_en_we;
+ logic unused_usb_usb_meas_ctrl_en_wdata;
+ logic usb_usb_meas_ctrl_en_regwen;
+
+ always_comb begin
+ usb_usb_meas_ctrl_en_qs = 4'h9;
+ usb_usb_meas_ctrl_en_ds = 4'h9;
+ usb_usb_meas_ctrl_en_ds = usb_usb_meas_ctrl_en_ds_int;
+ usb_usb_meas_ctrl_en_qs = usb_usb_meas_ctrl_en_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(4),
+ .ResetVal(4'h9),
+ .BitMask(4'hf),
+ .DstWrReq(1)
+ ) u_usb_meas_ctrl_en_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_usb_i),
+ .rst_dst_ni (rst_usb_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (usb_meas_ctrl_en_we),
+ .src_re_i ('0),
+ .src_wd_i (reg_wdata[3:0]),
+ .src_busy_o (usb_meas_ctrl_en_busy),
+ .src_qs_o (usb_meas_ctrl_en_qs), // for software read back
+ .dst_update_i (usb_usb_meas_ctrl_en_qe),
+ .dst_ds_i (usb_usb_meas_ctrl_en_ds),
+ .dst_qs_i (usb_usb_meas_ctrl_en_qs),
+ .dst_we_o (usb_usb_meas_ctrl_en_we),
+ .dst_re_o (),
+ .dst_regwen_o (usb_usb_meas_ctrl_en_regwen),
+ .dst_wd_o (usb_usb_meas_ctrl_en_wdata)
+ );
+ assign unused_usb_usb_meas_ctrl_en_wdata =
+ ^usb_usb_meas_ctrl_en_wdata;
+
+ logic [8:0] usb_usb_meas_ctrl_shadowed_hi_qs_int;
+ logic [8:0] usb_usb_meas_ctrl_shadowed_lo_qs_int;
+ logic [17:0] usb_usb_meas_ctrl_shadowed_qs;
+ logic [17:0] usb_usb_meas_ctrl_shadowed_wdata;
+ logic usb_usb_meas_ctrl_shadowed_we;
+ logic unused_usb_usb_meas_ctrl_shadowed_wdata;
+ logic usb_usb_meas_ctrl_shadowed_re;
+ logic usb_usb_meas_ctrl_shadowed_regwen;
+
+ always_comb begin
+ usb_usb_meas_ctrl_shadowed_qs = 18'h1ccfa;
+ usb_usb_meas_ctrl_shadowed_qs[8:0] = usb_usb_meas_ctrl_shadowed_hi_qs_int;
+ usb_usb_meas_ctrl_shadowed_qs[17:9] = usb_usb_meas_ctrl_shadowed_lo_qs_int;
+ end
+
+ prim_reg_cdc #(
+ .DataWidth(18),
+ .ResetVal(18'h1ccfa),
+ .BitMask(18'h3ffff),
+ .DstWrReq(0)
+ ) u_usb_meas_ctrl_shadowed_cdc (
+ .clk_src_i (clk_i),
+ .rst_src_ni (rst_ni),
+ .clk_dst_i (clk_usb_i),
+ .rst_dst_ni (rst_usb_ni),
+ .src_regwen_i (measure_ctrl_regwen_qs),
+ .src_we_i (usb_meas_ctrl_shadowed_we),
+ .src_re_i (usb_meas_ctrl_shadowed_re),
+ .src_wd_i (reg_wdata[17:0]),
+ .src_busy_o (usb_meas_ctrl_shadowed_busy),
+ .src_qs_o (usb_meas_ctrl_shadowed_qs), // for software read back
+ .dst_update_i ('0),
+ .dst_ds_i ('0),
+ .dst_qs_i (usb_usb_meas_ctrl_shadowed_qs),
+ .dst_we_o (usb_usb_meas_ctrl_shadowed_we),
+ .dst_re_o (usb_usb_meas_ctrl_shadowed_re),
+ .dst_regwen_o (usb_usb_meas_ctrl_shadowed_regwen),
+ .dst_wd_o (usb_usb_meas_ctrl_shadowed_wdata)
+ );
+ assign unused_usb_usb_meas_ctrl_shadowed_wdata =
+ ^usb_usb_meas_ctrl_shadowed_wdata;
+
+ // Register instances
+ // R[alert_test]: V(True)
+ logic alert_test_qe;
+ logic [1:0] alert_test_flds_we;
+ assign alert_test_qe = &alert_test_flds_we;
+ // F[recov_fault]: 0:0
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_alert_test_recov_fault (
+ .re (1'b0),
+ .we (alert_test_we),
+ .wd (alert_test_recov_fault_wd),
+ .d ('0),
+ .qre (),
+ .qe (alert_test_flds_we[0]),
+ .q (reg2hw.alert_test.recov_fault.q),
+ .ds (),
+ .qs ()
+ );
+ assign reg2hw.alert_test.recov_fault.qe = alert_test_qe;
+
+ // F[fatal_fault]: 1:1
+ prim_subreg_ext #(
+ .DW (1)
+ ) u_alert_test_fatal_fault (
+ .re (1'b0),
+ .we (alert_test_we),
+ .wd (alert_test_fatal_fault_wd),
+ .d ('0),
+ .qre (),
+ .qe (alert_test_flds_we[1]),
+ .q (reg2hw.alert_test.fatal_fault.q),
+ .ds (),
+ .qs ()
+ );
+ assign reg2hw.alert_test.fatal_fault.qe = alert_test_qe;
+
+
+ // R[extclk_ctrl_regwen]: V(False)
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW0C),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_extclk_ctrl_regwen (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (extclk_ctrl_regwen_we),
+ .wd (extclk_ctrl_regwen_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (extclk_ctrl_regwen_qs)
+ );
+
+
+ // R[extclk_ctrl]: V(False)
+ // Create REGWEN-gated WE signal
+ logic extclk_ctrl_gated_we;
+ assign extclk_ctrl_gated_we = extclk_ctrl_we & extclk_ctrl_regwen_qs;
+ // F[sel]: 3:0
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_extclk_ctrl_sel (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (extclk_ctrl_gated_we),
+ .wd (extclk_ctrl_sel_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.extclk_ctrl.sel.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (extclk_ctrl_sel_qs)
+ );
+
+ // F[hi_speed_sel]: 7:4
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_extclk_ctrl_hi_speed_sel (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (extclk_ctrl_gated_we),
+ .wd (extclk_ctrl_hi_speed_sel_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.extclk_ctrl.hi_speed_sel.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (extclk_ctrl_hi_speed_sel_qs)
+ );
+
+
+ // R[extclk_status]: V(True)
+ prim_subreg_ext #(
+ .DW (4)
+ ) u_extclk_status (
+ .re (extclk_status_re),
+ .we (1'b0),
+ .wd ('0),
+ .d (hw2reg.extclk_status.d),
+ .qre (),
+ .qe (),
+ .q (),
+ .ds (),
+ .qs (extclk_status_qs)
+ );
+
+
+ // R[jitter_regwen]: V(False)
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW0C),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_jitter_regwen (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (jitter_regwen_we),
+ .wd (jitter_regwen_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (jitter_regwen_qs)
+ );
+
+
+ // R[jitter_enable]: V(False)
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_jitter_enable (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (jitter_enable_we),
+ .wd (jitter_enable_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.jitter_enable.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (jitter_enable_qs)
+ );
+
+
+ // R[clk_enables]: V(False)
+ // F[clk_io_div4_peri_en]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_enables_clk_io_div4_peri_en (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_enables_we),
+ .wd (clk_enables_clk_io_div4_peri_en_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_enables.clk_io_div4_peri_en.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_enables_clk_io_div4_peri_en_qs)
+ );
+
+ // F[clk_io_div2_peri_en]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_enables_clk_io_div2_peri_en (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_enables_we),
+ .wd (clk_enables_clk_io_div2_peri_en_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_enables.clk_io_div2_peri_en.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_enables_clk_io_div2_peri_en_qs)
+ );
+
+ // F[clk_io_peri_en]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_enables_clk_io_peri_en (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_enables_we),
+ .wd (clk_enables_clk_io_peri_en_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_enables.clk_io_peri_en.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_enables_clk_io_peri_en_qs)
+ );
+
+ // F[clk_usb_peri_en]: 3:3
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_enables_clk_usb_peri_en (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_enables_we),
+ .wd (clk_enables_clk_usb_peri_en_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_enables.clk_usb_peri_en.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_enables_clk_usb_peri_en_qs)
+ );
+
+
+ // R[clk_hints]: V(False)
+ // F[clk_main_aes_hint]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_clk_main_aes_hint (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_hints_we),
+ .wd (clk_hints_clk_main_aes_hint_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_hints.clk_main_aes_hint.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_clk_main_aes_hint_qs)
+ );
+
+ // F[clk_main_hmac_hint]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_clk_main_hmac_hint (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_hints_we),
+ .wd (clk_hints_clk_main_hmac_hint_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_hints.clk_main_hmac_hint.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_clk_main_hmac_hint_qs)
+ );
+
+ // F[clk_main_kmac_hint]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_clk_main_kmac_hint (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_hints_we),
+ .wd (clk_hints_clk_main_kmac_hint_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_hints.clk_main_kmac_hint.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_clk_main_kmac_hint_qs)
+ );
+
+ // F[clk_main_otbn_hint]: 3:3
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_clk_main_otbn_hint (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (clk_hints_we),
+ .wd (clk_hints_clk_main_otbn_hint_wd),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.clk_hints.clk_main_otbn_hint.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_clk_main_otbn_hint_qs)
+ );
+
+
+ // R[clk_hints_status]: V(False)
+ // F[clk_main_aes_val]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_status_clk_main_aes_val (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.clk_hints_status.clk_main_aes_val.de),
+ .d (hw2reg.clk_hints_status.clk_main_aes_val.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_status_clk_main_aes_val_qs)
+ );
+
+ // F[clk_main_hmac_val]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_status_clk_main_hmac_val (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.clk_hints_status.clk_main_hmac_val.de),
+ .d (hw2reg.clk_hints_status.clk_main_hmac_val.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_status_clk_main_hmac_val_qs)
+ );
+
+ // F[clk_main_kmac_val]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_status_clk_main_kmac_val (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.clk_hints_status.clk_main_kmac_val.de),
+ .d (hw2reg.clk_hints_status.clk_main_kmac_val.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_status_clk_main_kmac_val_qs)
+ );
+
+ // F[clk_main_otbn_val]: 3:3
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_clk_hints_status_clk_main_otbn_val (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.clk_hints_status.clk_main_otbn_val.de),
+ .d (hw2reg.clk_hints_status.clk_main_otbn_val.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (clk_hints_status_clk_main_otbn_val_qs)
+ );
+
+
+ // R[measure_ctrl_regwen]: V(False)
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW0C),
+ .RESVAL (1'h1),
+ .Mubi (1'b0)
+ ) u_measure_ctrl_regwen (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (measure_ctrl_regwen_we),
+ .wd (measure_ctrl_regwen_wd),
+
+ // from internal hardware
+ .de (hw2reg.measure_ctrl_regwen.de),
+ .d (hw2reg.measure_ctrl_regwen.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.measure_ctrl_regwen.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (measure_ctrl_regwen_qs)
+ );
+
+
+ // R[io_meas_ctrl_en]: V(False)
+ logic [0:0] io_meas_ctrl_en_flds_we;
+ assign io_io_meas_ctrl_en_qe = |io_meas_ctrl_en_flds_we;
+ // Create REGWEN-gated WE signal
+ logic io_io_meas_ctrl_en_gated_we;
+ assign io_io_meas_ctrl_en_gated_we = io_io_meas_ctrl_en_we & io_io_meas_ctrl_en_regwen;
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_io_meas_ctrl_en (
+ .clk_i (clk_io_i),
+ .rst_ni (rst_io_ni),
+
+ // from register interface
+ .we (io_io_meas_ctrl_en_gated_we),
+ .wd (io_io_meas_ctrl_en_wdata[3:0]),
+
+ // from internal hardware
+ .de (hw2reg.io_meas_ctrl_en.de),
+ .d (hw2reg.io_meas_ctrl_en.d),
+
+ // to internal hardware
+ .qe (io_meas_ctrl_en_flds_we[0]),
+ .q (reg2hw.io_meas_ctrl_en.q),
+ .ds (io_io_meas_ctrl_en_ds_int),
+
+ // to register interface (read)
+ .qs (io_io_meas_ctrl_en_qs_int)
+ );
+
+
+ // R[io_meas_ctrl_shadowed]: V(False)
+ // Create REGWEN-gated WE signal
+ logic io_io_meas_ctrl_shadowed_gated_we;
+ assign io_io_meas_ctrl_shadowed_gated_we =
+ io_io_meas_ctrl_shadowed_we & io_io_meas_ctrl_shadowed_regwen;
+ // F[hi]: 9:0
+ logic async_io_meas_ctrl_shadowed_hi_err_update;
+ logic async_io_meas_ctrl_shadowed_hi_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_meas_ctrl_shadowed_hi_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_meas_ctrl_shadowed_hi_err_storage),
+ .q_o(io_meas_ctrl_shadowed_hi_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_meas_ctrl_shadowed_hi_err_update_sync (
+ .clk_src_i(clk_io_i),
+ .rst_src_ni(rst_io_ni),
+ .src_pulse_i(async_io_meas_ctrl_shadowed_hi_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_meas_ctrl_shadowed_hi_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (10),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (10'h1ea),
+ .Mubi (1'b0)
+ ) u_io_meas_ctrl_shadowed_hi (
+ .clk_i (clk_io_i),
+ .rst_ni (rst_io_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_io_meas_ctrl_shadowed_re),
+ .we (io_io_meas_ctrl_shadowed_gated_we),
+ .wd (io_io_meas_ctrl_shadowed_wdata[9:0]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_meas_ctrl_shadowed.hi.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_io_meas_ctrl_shadowed_hi_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_meas_ctrl_shadowed_hi_err_update),
+ .err_storage (async_io_meas_ctrl_shadowed_hi_err_storage)
+ );
+
+ // F[lo]: 19:10
+ logic async_io_meas_ctrl_shadowed_lo_err_update;
+ logic async_io_meas_ctrl_shadowed_lo_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_meas_ctrl_shadowed_lo_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_meas_ctrl_shadowed_lo_err_storage),
+ .q_o(io_meas_ctrl_shadowed_lo_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_meas_ctrl_shadowed_lo_err_update_sync (
+ .clk_src_i(clk_io_i),
+ .rst_src_ni(rst_io_ni),
+ .src_pulse_i(async_io_meas_ctrl_shadowed_lo_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_meas_ctrl_shadowed_lo_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (10),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (10'h1d6),
+ .Mubi (1'b0)
+ ) u_io_meas_ctrl_shadowed_lo (
+ .clk_i (clk_io_i),
+ .rst_ni (rst_io_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_io_meas_ctrl_shadowed_re),
+ .we (io_io_meas_ctrl_shadowed_gated_we),
+ .wd (io_io_meas_ctrl_shadowed_wdata[19:10]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_meas_ctrl_shadowed.lo.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_io_meas_ctrl_shadowed_lo_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_meas_ctrl_shadowed_lo_err_update),
+ .err_storage (async_io_meas_ctrl_shadowed_lo_err_storage)
+ );
+
+
+ // R[io_div2_meas_ctrl_en]: V(False)
+ logic [0:0] io_div2_meas_ctrl_en_flds_we;
+ assign io_div2_io_div2_meas_ctrl_en_qe = |io_div2_meas_ctrl_en_flds_we;
+ // Create REGWEN-gated WE signal
+ logic io_div2_io_div2_meas_ctrl_en_gated_we;
+ assign io_div2_io_div2_meas_ctrl_en_gated_we =
+ io_div2_io_div2_meas_ctrl_en_we & io_div2_io_div2_meas_ctrl_en_regwen;
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_io_div2_meas_ctrl_en (
+ .clk_i (clk_io_div2_i),
+ .rst_ni (rst_io_div2_ni),
+
+ // from register interface
+ .we (io_div2_io_div2_meas_ctrl_en_gated_we),
+ .wd (io_div2_io_div2_meas_ctrl_en_wdata[3:0]),
+
+ // from internal hardware
+ .de (hw2reg.io_div2_meas_ctrl_en.de),
+ .d (hw2reg.io_div2_meas_ctrl_en.d),
+
+ // to internal hardware
+ .qe (io_div2_meas_ctrl_en_flds_we[0]),
+ .q (reg2hw.io_div2_meas_ctrl_en.q),
+ .ds (io_div2_io_div2_meas_ctrl_en_ds_int),
+
+ // to register interface (read)
+ .qs (io_div2_io_div2_meas_ctrl_en_qs_int)
+ );
+
+
+ // R[io_div2_meas_ctrl_shadowed]: V(False)
+ // Create REGWEN-gated WE signal
+ logic io_div2_io_div2_meas_ctrl_shadowed_gated_we;
+ assign io_div2_io_div2_meas_ctrl_shadowed_gated_we =
+ io_div2_io_div2_meas_ctrl_shadowed_we & io_div2_io_div2_meas_ctrl_shadowed_regwen;
+ // F[hi]: 8:0
+ logic async_io_div2_meas_ctrl_shadowed_hi_err_update;
+ logic async_io_div2_meas_ctrl_shadowed_hi_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_div2_meas_ctrl_shadowed_hi_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_div2_meas_ctrl_shadowed_hi_err_storage),
+ .q_o(io_div2_meas_ctrl_shadowed_hi_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_div2_meas_ctrl_shadowed_hi_err_update_sync (
+ .clk_src_i(clk_io_div2_i),
+ .rst_src_ni(rst_io_div2_ni),
+ .src_pulse_i(async_io_div2_meas_ctrl_shadowed_hi_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_div2_meas_ctrl_shadowed_hi_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (9),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (9'hfa),
+ .Mubi (1'b0)
+ ) u_io_div2_meas_ctrl_shadowed_hi (
+ .clk_i (clk_io_div2_i),
+ .rst_ni (rst_io_div2_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_div2_io_div2_meas_ctrl_shadowed_re),
+ .we (io_div2_io_div2_meas_ctrl_shadowed_gated_we),
+ .wd (io_div2_io_div2_meas_ctrl_shadowed_wdata[8:0]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_div2_meas_ctrl_shadowed.hi.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_div2_io_div2_meas_ctrl_shadowed_hi_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_div2_meas_ctrl_shadowed_hi_err_update),
+ .err_storage (async_io_div2_meas_ctrl_shadowed_hi_err_storage)
+ );
+
+ // F[lo]: 17:9
+ logic async_io_div2_meas_ctrl_shadowed_lo_err_update;
+ logic async_io_div2_meas_ctrl_shadowed_lo_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_div2_meas_ctrl_shadowed_lo_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_div2_meas_ctrl_shadowed_lo_err_storage),
+ .q_o(io_div2_meas_ctrl_shadowed_lo_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_div2_meas_ctrl_shadowed_lo_err_update_sync (
+ .clk_src_i(clk_io_div2_i),
+ .rst_src_ni(rst_io_div2_ni),
+ .src_pulse_i(async_io_div2_meas_ctrl_shadowed_lo_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_div2_meas_ctrl_shadowed_lo_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (9),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (9'he6),
+ .Mubi (1'b0)
+ ) u_io_div2_meas_ctrl_shadowed_lo (
+ .clk_i (clk_io_div2_i),
+ .rst_ni (rst_io_div2_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_div2_io_div2_meas_ctrl_shadowed_re),
+ .we (io_div2_io_div2_meas_ctrl_shadowed_gated_we),
+ .wd (io_div2_io_div2_meas_ctrl_shadowed_wdata[17:9]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_div2_meas_ctrl_shadowed.lo.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_div2_io_div2_meas_ctrl_shadowed_lo_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_div2_meas_ctrl_shadowed_lo_err_update),
+ .err_storage (async_io_div2_meas_ctrl_shadowed_lo_err_storage)
+ );
+
+
+ // R[io_div4_meas_ctrl_en]: V(False)
+ logic [0:0] io_div4_meas_ctrl_en_flds_we;
+ assign io_div4_io_div4_meas_ctrl_en_qe = |io_div4_meas_ctrl_en_flds_we;
+ // Create REGWEN-gated WE signal
+ logic io_div4_io_div4_meas_ctrl_en_gated_we;
+ assign io_div4_io_div4_meas_ctrl_en_gated_we =
+ io_div4_io_div4_meas_ctrl_en_we & io_div4_io_div4_meas_ctrl_en_regwen;
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_io_div4_meas_ctrl_en (
+ .clk_i (clk_io_div4_i),
+ .rst_ni (rst_io_div4_ni),
+
+ // from register interface
+ .we (io_div4_io_div4_meas_ctrl_en_gated_we),
+ .wd (io_div4_io_div4_meas_ctrl_en_wdata[3:0]),
+
+ // from internal hardware
+ .de (hw2reg.io_div4_meas_ctrl_en.de),
+ .d (hw2reg.io_div4_meas_ctrl_en.d),
+
+ // to internal hardware
+ .qe (io_div4_meas_ctrl_en_flds_we[0]),
+ .q (reg2hw.io_div4_meas_ctrl_en.q),
+ .ds (io_div4_io_div4_meas_ctrl_en_ds_int),
+
+ // to register interface (read)
+ .qs (io_div4_io_div4_meas_ctrl_en_qs_int)
+ );
+
+
+ // R[io_div4_meas_ctrl_shadowed]: V(False)
+ // Create REGWEN-gated WE signal
+ logic io_div4_io_div4_meas_ctrl_shadowed_gated_we;
+ assign io_div4_io_div4_meas_ctrl_shadowed_gated_we =
+ io_div4_io_div4_meas_ctrl_shadowed_we & io_div4_io_div4_meas_ctrl_shadowed_regwen;
+ // F[hi]: 7:0
+ logic async_io_div4_meas_ctrl_shadowed_hi_err_update;
+ logic async_io_div4_meas_ctrl_shadowed_hi_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_div4_meas_ctrl_shadowed_hi_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_div4_meas_ctrl_shadowed_hi_err_storage),
+ .q_o(io_div4_meas_ctrl_shadowed_hi_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_div4_meas_ctrl_shadowed_hi_err_update_sync (
+ .clk_src_i(clk_io_div4_i),
+ .rst_src_ni(rst_io_div4_ni),
+ .src_pulse_i(async_io_div4_meas_ctrl_shadowed_hi_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_div4_meas_ctrl_shadowed_hi_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (8),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (8'h82),
+ .Mubi (1'b0)
+ ) u_io_div4_meas_ctrl_shadowed_hi (
+ .clk_i (clk_io_div4_i),
+ .rst_ni (rst_io_div4_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_div4_io_div4_meas_ctrl_shadowed_re),
+ .we (io_div4_io_div4_meas_ctrl_shadowed_gated_we),
+ .wd (io_div4_io_div4_meas_ctrl_shadowed_wdata[7:0]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_div4_meas_ctrl_shadowed.hi.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_div4_io_div4_meas_ctrl_shadowed_hi_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_div4_meas_ctrl_shadowed_hi_err_update),
+ .err_storage (async_io_div4_meas_ctrl_shadowed_hi_err_storage)
+ );
+
+ // F[lo]: 15:8
+ logic async_io_div4_meas_ctrl_shadowed_lo_err_update;
+ logic async_io_div4_meas_ctrl_shadowed_lo_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_io_div4_meas_ctrl_shadowed_lo_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_io_div4_meas_ctrl_shadowed_lo_err_storage),
+ .q_o(io_div4_meas_ctrl_shadowed_lo_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_io_div4_meas_ctrl_shadowed_lo_err_update_sync (
+ .clk_src_i(clk_io_div4_i),
+ .rst_src_ni(rst_io_div4_ni),
+ .src_pulse_i(async_io_div4_meas_ctrl_shadowed_lo_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(io_div4_meas_ctrl_shadowed_lo_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (8),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (8'h6e),
+ .Mubi (1'b0)
+ ) u_io_div4_meas_ctrl_shadowed_lo (
+ .clk_i (clk_io_div4_i),
+ .rst_ni (rst_io_div4_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (io_div4_io_div4_meas_ctrl_shadowed_re),
+ .we (io_div4_io_div4_meas_ctrl_shadowed_gated_we),
+ .wd (io_div4_io_div4_meas_ctrl_shadowed_wdata[15:8]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.io_div4_meas_ctrl_shadowed.lo.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (io_div4_io_div4_meas_ctrl_shadowed_lo_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_io_div4_meas_ctrl_shadowed_lo_err_update),
+ .err_storage (async_io_div4_meas_ctrl_shadowed_lo_err_storage)
+ );
+
+
+ // R[main_meas_ctrl_en]: V(False)
+ logic [0:0] main_meas_ctrl_en_flds_we;
+ assign main_main_meas_ctrl_en_qe = |main_meas_ctrl_en_flds_we;
+ // Create REGWEN-gated WE signal
+ logic main_main_meas_ctrl_en_gated_we;
+ assign main_main_meas_ctrl_en_gated_we =
+ main_main_meas_ctrl_en_we & main_main_meas_ctrl_en_regwen;
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_main_meas_ctrl_en (
+ .clk_i (clk_main_i),
+ .rst_ni (rst_main_ni),
+
+ // from register interface
+ .we (main_main_meas_ctrl_en_gated_we),
+ .wd (main_main_meas_ctrl_en_wdata[3:0]),
+
+ // from internal hardware
+ .de (hw2reg.main_meas_ctrl_en.de),
+ .d (hw2reg.main_meas_ctrl_en.d),
+
+ // to internal hardware
+ .qe (main_meas_ctrl_en_flds_we[0]),
+ .q (reg2hw.main_meas_ctrl_en.q),
+ .ds (main_main_meas_ctrl_en_ds_int),
+
+ // to register interface (read)
+ .qs (main_main_meas_ctrl_en_qs_int)
+ );
+
+
+ // R[main_meas_ctrl_shadowed]: V(False)
+ // Create REGWEN-gated WE signal
+ logic main_main_meas_ctrl_shadowed_gated_we;
+ assign main_main_meas_ctrl_shadowed_gated_we =
+ main_main_meas_ctrl_shadowed_we & main_main_meas_ctrl_shadowed_regwen;
+ // F[hi]: 9:0
+ logic async_main_meas_ctrl_shadowed_hi_err_update;
+ logic async_main_meas_ctrl_shadowed_hi_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_main_meas_ctrl_shadowed_hi_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_main_meas_ctrl_shadowed_hi_err_storage),
+ .q_o(main_meas_ctrl_shadowed_hi_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_main_meas_ctrl_shadowed_hi_err_update_sync (
+ .clk_src_i(clk_main_i),
+ .rst_src_ni(rst_main_ni),
+ .src_pulse_i(async_main_meas_ctrl_shadowed_hi_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(main_meas_ctrl_shadowed_hi_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (10),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (10'h1fe),
+ .Mubi (1'b0)
+ ) u_main_meas_ctrl_shadowed_hi (
+ .clk_i (clk_main_i),
+ .rst_ni (rst_main_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (main_main_meas_ctrl_shadowed_re),
+ .we (main_main_meas_ctrl_shadowed_gated_we),
+ .wd (main_main_meas_ctrl_shadowed_wdata[9:0]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.main_meas_ctrl_shadowed.hi.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (main_main_meas_ctrl_shadowed_hi_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_main_meas_ctrl_shadowed_hi_err_update),
+ .err_storage (async_main_meas_ctrl_shadowed_hi_err_storage)
+ );
+
+ // F[lo]: 19:10
+ logic async_main_meas_ctrl_shadowed_lo_err_update;
+ logic async_main_meas_ctrl_shadowed_lo_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_main_meas_ctrl_shadowed_lo_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_main_meas_ctrl_shadowed_lo_err_storage),
+ .q_o(main_meas_ctrl_shadowed_lo_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_main_meas_ctrl_shadowed_lo_err_update_sync (
+ .clk_src_i(clk_main_i),
+ .rst_src_ni(rst_main_ni),
+ .src_pulse_i(async_main_meas_ctrl_shadowed_lo_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(main_meas_ctrl_shadowed_lo_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (10),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (10'h1ea),
+ .Mubi (1'b0)
+ ) u_main_meas_ctrl_shadowed_lo (
+ .clk_i (clk_main_i),
+ .rst_ni (rst_main_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (main_main_meas_ctrl_shadowed_re),
+ .we (main_main_meas_ctrl_shadowed_gated_we),
+ .wd (main_main_meas_ctrl_shadowed_wdata[19:10]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.main_meas_ctrl_shadowed.lo.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (main_main_meas_ctrl_shadowed_lo_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_main_meas_ctrl_shadowed_lo_err_update),
+ .err_storage (async_main_meas_ctrl_shadowed_lo_err_storage)
+ );
+
+
+ // R[usb_meas_ctrl_en]: V(False)
+ logic [0:0] usb_meas_ctrl_en_flds_we;
+ assign usb_usb_meas_ctrl_en_qe = |usb_meas_ctrl_en_flds_we;
+ // Create REGWEN-gated WE signal
+ logic usb_usb_meas_ctrl_en_gated_we;
+ assign usb_usb_meas_ctrl_en_gated_we = usb_usb_meas_ctrl_en_we & usb_usb_meas_ctrl_en_regwen;
+ prim_subreg #(
+ .DW (4),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (4'h9),
+ .Mubi (1'b1)
+ ) u_usb_meas_ctrl_en (
+ .clk_i (clk_usb_i),
+ .rst_ni (rst_usb_ni),
+
+ // from register interface
+ .we (usb_usb_meas_ctrl_en_gated_we),
+ .wd (usb_usb_meas_ctrl_en_wdata[3:0]),
+
+ // from internal hardware
+ .de (hw2reg.usb_meas_ctrl_en.de),
+ .d (hw2reg.usb_meas_ctrl_en.d),
+
+ // to internal hardware
+ .qe (usb_meas_ctrl_en_flds_we[0]),
+ .q (reg2hw.usb_meas_ctrl_en.q),
+ .ds (usb_usb_meas_ctrl_en_ds_int),
+
+ // to register interface (read)
+ .qs (usb_usb_meas_ctrl_en_qs_int)
+ );
+
+
+ // R[usb_meas_ctrl_shadowed]: V(False)
+ // Create REGWEN-gated WE signal
+ logic usb_usb_meas_ctrl_shadowed_gated_we;
+ assign usb_usb_meas_ctrl_shadowed_gated_we =
+ usb_usb_meas_ctrl_shadowed_we & usb_usb_meas_ctrl_shadowed_regwen;
+ // F[hi]: 8:0
+ logic async_usb_meas_ctrl_shadowed_hi_err_update;
+ logic async_usb_meas_ctrl_shadowed_hi_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_usb_meas_ctrl_shadowed_hi_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_usb_meas_ctrl_shadowed_hi_err_storage),
+ .q_o(usb_meas_ctrl_shadowed_hi_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_usb_meas_ctrl_shadowed_hi_err_update_sync (
+ .clk_src_i(clk_usb_i),
+ .rst_src_ni(rst_usb_ni),
+ .src_pulse_i(async_usb_meas_ctrl_shadowed_hi_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(usb_meas_ctrl_shadowed_hi_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (9),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (9'hfa),
+ .Mubi (1'b0)
+ ) u_usb_meas_ctrl_shadowed_hi (
+ .clk_i (clk_usb_i),
+ .rst_ni (rst_usb_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (usb_usb_meas_ctrl_shadowed_re),
+ .we (usb_usb_meas_ctrl_shadowed_gated_we),
+ .wd (usb_usb_meas_ctrl_shadowed_wdata[8:0]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.usb_meas_ctrl_shadowed.hi.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (usb_usb_meas_ctrl_shadowed_hi_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_usb_meas_ctrl_shadowed_hi_err_update),
+ .err_storage (async_usb_meas_ctrl_shadowed_hi_err_storage)
+ );
+
+ // F[lo]: 17:9
+ logic async_usb_meas_ctrl_shadowed_lo_err_update;
+ logic async_usb_meas_ctrl_shadowed_lo_err_storage;
+
+ // storage error is persistent and can be sampled at any time
+ prim_flop_2sync #(
+ .Width(1),
+ .ResetValue('0)
+ ) u_usb_meas_ctrl_shadowed_lo_err_storage_sync (
+ .clk_i,
+ .rst_ni,
+ .d_i(async_usb_meas_ctrl_shadowed_lo_err_storage),
+ .q_o(usb_meas_ctrl_shadowed_lo_storage_err)
+ );
+
+ // update error is transient and must be immediately captured
+ prim_pulse_sync u_usb_meas_ctrl_shadowed_lo_err_update_sync (
+ .clk_src_i(clk_usb_i),
+ .rst_src_ni(rst_usb_ni),
+ .src_pulse_i(async_usb_meas_ctrl_shadowed_lo_err_update),
+ .clk_dst_i(clk_i),
+ .rst_dst_ni(rst_ni),
+ .dst_pulse_o(usb_meas_ctrl_shadowed_lo_update_err)
+ );
+ prim_subreg_shadow #(
+ .DW (9),
+ .SwAccess(prim_subreg_pkg::SwAccessRW),
+ .RESVAL (9'he6),
+ .Mubi (1'b0)
+ ) u_usb_meas_ctrl_shadowed_lo (
+ .clk_i (clk_usb_i),
+ .rst_ni (rst_usb_ni),
+ .rst_shadowed_ni (rst_shadowed_ni),
+
+ // from register interface
+ .re (usb_usb_meas_ctrl_shadowed_re),
+ .we (usb_usb_meas_ctrl_shadowed_gated_we),
+ .wd (usb_usb_meas_ctrl_shadowed_wdata[17:9]),
+
+ // from internal hardware
+ .de (1'b0),
+ .d ('0),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.usb_meas_ctrl_shadowed.lo.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (usb_usb_meas_ctrl_shadowed_lo_qs_int),
+
+ // Shadow register phase. Relevant for hwext only.
+ .phase (),
+
+ // Shadow register error conditions
+ .err_update (async_usb_meas_ctrl_shadowed_lo_err_update),
+ .err_storage (async_usb_meas_ctrl_shadowed_lo_err_storage)
+ );
+
+
+ // R[recov_err_code]: V(False)
+ // F[shadow_update_err]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_shadow_update_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_shadow_update_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.shadow_update_err.de),
+ .d (hw2reg.recov_err_code.shadow_update_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_shadow_update_err_qs)
+ );
+
+ // F[io_measure_err]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_measure_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_measure_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_measure_err.de),
+ .d (hw2reg.recov_err_code.io_measure_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_measure_err_qs)
+ );
+
+ // F[io_div2_measure_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_div2_measure_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_div2_measure_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_div2_measure_err.de),
+ .d (hw2reg.recov_err_code.io_div2_measure_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_div2_measure_err_qs)
+ );
+
+ // F[io_div4_measure_err]: 3:3
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_div4_measure_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_div4_measure_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_div4_measure_err.de),
+ .d (hw2reg.recov_err_code.io_div4_measure_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_div4_measure_err_qs)
+ );
+
+ // F[main_measure_err]: 4:4
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_main_measure_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_main_measure_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.main_measure_err.de),
+ .d (hw2reg.recov_err_code.main_measure_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_main_measure_err_qs)
+ );
+
+ // F[usb_measure_err]: 5:5
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_usb_measure_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_usb_measure_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.usb_measure_err.de),
+ .d (hw2reg.recov_err_code.usb_measure_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_usb_measure_err_qs)
+ );
+
+ // F[io_timeout_err]: 6:6
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_timeout_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_timeout_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_timeout_err.de),
+ .d (hw2reg.recov_err_code.io_timeout_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_timeout_err_qs)
+ );
+
+ // F[io_div2_timeout_err]: 7:7
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_div2_timeout_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_div2_timeout_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_div2_timeout_err.de),
+ .d (hw2reg.recov_err_code.io_div2_timeout_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_div2_timeout_err_qs)
+ );
+
+ // F[io_div4_timeout_err]: 8:8
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_io_div4_timeout_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_io_div4_timeout_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.io_div4_timeout_err.de),
+ .d (hw2reg.recov_err_code.io_div4_timeout_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_io_div4_timeout_err_qs)
+ );
+
+ // F[main_timeout_err]: 9:9
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_main_timeout_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_main_timeout_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.main_timeout_err.de),
+ .d (hw2reg.recov_err_code.main_timeout_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_main_timeout_err_qs)
+ );
+
+ // F[usb_timeout_err]: 10:10
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessW1C),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_recov_err_code_usb_timeout_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (recov_err_code_we),
+ .wd (recov_err_code_usb_timeout_err_wd),
+
+ // from internal hardware
+ .de (hw2reg.recov_err_code.usb_timeout_err.de),
+ .d (hw2reg.recov_err_code.usb_timeout_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (),
+ .ds (),
+
+ // to register interface (read)
+ .qs (recov_err_code_usb_timeout_err_qs)
+ );
+
+
+ // R[fatal_err_code]: V(False)
+ // F[reg_intg]: 0:0
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_fatal_err_code_reg_intg (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.fatal_err_code.reg_intg.de),
+ .d (hw2reg.fatal_err_code.reg_intg.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.fatal_err_code.reg_intg.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (fatal_err_code_reg_intg_qs)
+ );
+
+ // F[idle_cnt]: 1:1
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_fatal_err_code_idle_cnt (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.fatal_err_code.idle_cnt.de),
+ .d (hw2reg.fatal_err_code.idle_cnt.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.fatal_err_code.idle_cnt.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (fatal_err_code_idle_cnt_qs)
+ );
+
+ // F[shadow_storage_err]: 2:2
+ prim_subreg #(
+ .DW (1),
+ .SwAccess(prim_subreg_pkg::SwAccessRO),
+ .RESVAL (1'h0),
+ .Mubi (1'b0)
+ ) u_fatal_err_code_shadow_storage_err (
+ .clk_i (clk_i),
+ .rst_ni (rst_ni),
+
+ // from register interface
+ .we (1'b0),
+ .wd ('0),
+
+ // from internal hardware
+ .de (hw2reg.fatal_err_code.shadow_storage_err.de),
+ .d (hw2reg.fatal_err_code.shadow_storage_err.d),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.fatal_err_code.shadow_storage_err.q),
+ .ds (),
+
+ // to register interface (read)
+ .qs (fatal_err_code_shadow_storage_err_qs)
+ );
+
+
+
+ logic [21:0] addr_hit;
+ always_comb begin
+ addr_hit = '0;
+ addr_hit[ 0] = (reg_addr == CLKMGR_ALERT_TEST_OFFSET);
+ addr_hit[ 1] = (reg_addr == CLKMGR_EXTCLK_CTRL_REGWEN_OFFSET);
+ addr_hit[ 2] = (reg_addr == CLKMGR_EXTCLK_CTRL_OFFSET);
+ addr_hit[ 3] = (reg_addr == CLKMGR_EXTCLK_STATUS_OFFSET);
+ addr_hit[ 4] = (reg_addr == CLKMGR_JITTER_REGWEN_OFFSET);
+ addr_hit[ 5] = (reg_addr == CLKMGR_JITTER_ENABLE_OFFSET);
+ addr_hit[ 6] = (reg_addr == CLKMGR_CLK_ENABLES_OFFSET);
+ addr_hit[ 7] = (reg_addr == CLKMGR_CLK_HINTS_OFFSET);
+ addr_hit[ 8] = (reg_addr == CLKMGR_CLK_HINTS_STATUS_OFFSET);
+ addr_hit[ 9] = (reg_addr == CLKMGR_MEASURE_CTRL_REGWEN_OFFSET);
+ addr_hit[10] = (reg_addr == CLKMGR_IO_MEAS_CTRL_EN_OFFSET);
+ addr_hit[11] = (reg_addr == CLKMGR_IO_MEAS_CTRL_SHADOWED_OFFSET);
+ addr_hit[12] = (reg_addr == CLKMGR_IO_DIV2_MEAS_CTRL_EN_OFFSET);
+ addr_hit[13] = (reg_addr == CLKMGR_IO_DIV2_MEAS_CTRL_SHADOWED_OFFSET);
+ addr_hit[14] = (reg_addr == CLKMGR_IO_DIV4_MEAS_CTRL_EN_OFFSET);
+ addr_hit[15] = (reg_addr == CLKMGR_IO_DIV4_MEAS_CTRL_SHADOWED_OFFSET);
+ addr_hit[16] = (reg_addr == CLKMGR_MAIN_MEAS_CTRL_EN_OFFSET);
+ addr_hit[17] = (reg_addr == CLKMGR_MAIN_MEAS_CTRL_SHADOWED_OFFSET);
+ addr_hit[18] = (reg_addr == CLKMGR_USB_MEAS_CTRL_EN_OFFSET);
+ addr_hit[19] = (reg_addr == CLKMGR_USB_MEAS_CTRL_SHADOWED_OFFSET);
+ addr_hit[20] = (reg_addr == CLKMGR_RECOV_ERR_CODE_OFFSET);
+ addr_hit[21] = (reg_addr == CLKMGR_FATAL_ERR_CODE_OFFSET);
+ end
+
+ assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+ // Check sub-word write is permitted
+ always_comb begin
+ wr_err = (reg_we &
+ ((addr_hit[ 0] & (|(CLKMGR_PERMIT[ 0] & ~reg_be))) |
+ (addr_hit[ 1] & (|(CLKMGR_PERMIT[ 1] & ~reg_be))) |
+ (addr_hit[ 2] & (|(CLKMGR_PERMIT[ 2] & ~reg_be))) |
+ (addr_hit[ 3] & (|(CLKMGR_PERMIT[ 3] & ~reg_be))) |
+ (addr_hit[ 4] & (|(CLKMGR_PERMIT[ 4] & ~reg_be))) |
+ (addr_hit[ 5] & (|(CLKMGR_PERMIT[ 5] & ~reg_be))) |
+ (addr_hit[ 6] & (|(CLKMGR_PERMIT[ 6] & ~reg_be))) |
+ (addr_hit[ 7] & (|(CLKMGR_PERMIT[ 7] & ~reg_be))) |
+ (addr_hit[ 8] & (|(CLKMGR_PERMIT[ 8] & ~reg_be))) |
+ (addr_hit[ 9] & (|(CLKMGR_PERMIT[ 9] & ~reg_be))) |
+ (addr_hit[10] & (|(CLKMGR_PERMIT[10] & ~reg_be))) |
+ (addr_hit[11] & (|(CLKMGR_PERMIT[11] & ~reg_be))) |
+ (addr_hit[12] & (|(CLKMGR_PERMIT[12] & ~reg_be))) |
+ (addr_hit[13] & (|(CLKMGR_PERMIT[13] & ~reg_be))) |
+ (addr_hit[14] & (|(CLKMGR_PERMIT[14] & ~reg_be))) |
+ (addr_hit[15] & (|(CLKMGR_PERMIT[15] & ~reg_be))) |
+ (addr_hit[16] & (|(CLKMGR_PERMIT[16] & ~reg_be))) |
+ (addr_hit[17] & (|(CLKMGR_PERMIT[17] & ~reg_be))) |
+ (addr_hit[18] & (|(CLKMGR_PERMIT[18] & ~reg_be))) |
+ (addr_hit[19] & (|(CLKMGR_PERMIT[19] & ~reg_be))) |
+ (addr_hit[20] & (|(CLKMGR_PERMIT[20] & ~reg_be))) |
+ (addr_hit[21] & (|(CLKMGR_PERMIT[21] & ~reg_be)))));
+ end
+
+ // Generate write-enables
+ assign alert_test_we = addr_hit[0] & reg_we & !reg_error;
+
+ assign alert_test_recov_fault_wd = reg_wdata[0];
+
+ assign alert_test_fatal_fault_wd = reg_wdata[1];
+ assign extclk_ctrl_regwen_we = addr_hit[1] & reg_we & !reg_error;
+
+ assign extclk_ctrl_regwen_wd = reg_wdata[0];
+ assign extclk_ctrl_we = addr_hit[2] & reg_we & !reg_error;
+
+ assign extclk_ctrl_sel_wd = reg_wdata[3:0];
+
+ assign extclk_ctrl_hi_speed_sel_wd = reg_wdata[7:4];
+ assign extclk_status_re = addr_hit[3] & reg_re & !reg_error;
+ assign jitter_regwen_we = addr_hit[4] & reg_we & !reg_error;
+
+ assign jitter_regwen_wd = reg_wdata[0];
+ assign jitter_enable_we = addr_hit[5] & reg_we & !reg_error;
+
+ assign jitter_enable_wd = reg_wdata[3:0];
+ assign clk_enables_we = addr_hit[6] & reg_we & !reg_error;
+
+ assign clk_enables_clk_io_div4_peri_en_wd = reg_wdata[0];
+
+ assign clk_enables_clk_io_div2_peri_en_wd = reg_wdata[1];
+
+ assign clk_enables_clk_io_peri_en_wd = reg_wdata[2];
+
+ assign clk_enables_clk_usb_peri_en_wd = reg_wdata[3];
+ assign clk_hints_we = addr_hit[7] & reg_we & !reg_error;
+
+ assign clk_hints_clk_main_aes_hint_wd = reg_wdata[0];
+
+ assign clk_hints_clk_main_hmac_hint_wd = reg_wdata[1];
+
+ assign clk_hints_clk_main_kmac_hint_wd = reg_wdata[2];
+
+ assign clk_hints_clk_main_otbn_hint_wd = reg_wdata[3];
+ assign measure_ctrl_regwen_we = addr_hit[9] & reg_we & !reg_error;
+
+ assign measure_ctrl_regwen_wd = reg_wdata[0];
+ assign io_meas_ctrl_en_we = addr_hit[10] & reg_we & !reg_error;
+
+ assign io_meas_ctrl_shadowed_re = addr_hit[11] & reg_re & !reg_error;
+ assign io_meas_ctrl_shadowed_we = addr_hit[11] & reg_we & !reg_error;
+
+
+ assign io_div2_meas_ctrl_en_we = addr_hit[12] & reg_we & !reg_error;
+
+ assign io_div2_meas_ctrl_shadowed_re = addr_hit[13] & reg_re & !reg_error;
+ assign io_div2_meas_ctrl_shadowed_we = addr_hit[13] & reg_we & !reg_error;
+
+
+ assign io_div4_meas_ctrl_en_we = addr_hit[14] & reg_we & !reg_error;
+
+ assign io_div4_meas_ctrl_shadowed_re = addr_hit[15] & reg_re & !reg_error;
+ assign io_div4_meas_ctrl_shadowed_we = addr_hit[15] & reg_we & !reg_error;
+
+
+ assign main_meas_ctrl_en_we = addr_hit[16] & reg_we & !reg_error;
+
+ assign main_meas_ctrl_shadowed_re = addr_hit[17] & reg_re & !reg_error;
+ assign main_meas_ctrl_shadowed_we = addr_hit[17] & reg_we & !reg_error;
+
+
+ assign usb_meas_ctrl_en_we = addr_hit[18] & reg_we & !reg_error;
+
+ assign usb_meas_ctrl_shadowed_re = addr_hit[19] & reg_re & !reg_error;
+ assign usb_meas_ctrl_shadowed_we = addr_hit[19] & reg_we & !reg_error;
+
+
+ assign recov_err_code_we = addr_hit[20] & reg_we & !reg_error;
+
+ assign recov_err_code_shadow_update_err_wd = reg_wdata[0];
+
+ assign recov_err_code_io_measure_err_wd = reg_wdata[1];
+
+ assign recov_err_code_io_div2_measure_err_wd = reg_wdata[2];
+
+ assign recov_err_code_io_div4_measure_err_wd = reg_wdata[3];
+
+ assign recov_err_code_main_measure_err_wd = reg_wdata[4];
+
+ assign recov_err_code_usb_measure_err_wd = reg_wdata[5];
+
+ assign recov_err_code_io_timeout_err_wd = reg_wdata[6];
+
+ assign recov_err_code_io_div2_timeout_err_wd = reg_wdata[7];
+
+ assign recov_err_code_io_div4_timeout_err_wd = reg_wdata[8];
+
+ assign recov_err_code_main_timeout_err_wd = reg_wdata[9];
+
+ assign recov_err_code_usb_timeout_err_wd = reg_wdata[10];
+
+ // Assign write-enables to checker logic vector.
+ always_comb begin
+ reg_we_check = '0;
+ reg_we_check[0] = alert_test_we;
+ reg_we_check[1] = extclk_ctrl_regwen_we;
+ reg_we_check[2] = extclk_ctrl_gated_we;
+ reg_we_check[3] = 1'b0;
+ reg_we_check[4] = jitter_regwen_we;
+ reg_we_check[5] = jitter_enable_we;
+ reg_we_check[6] = clk_enables_we;
+ reg_we_check[7] = clk_hints_we;
+ reg_we_check[8] = 1'b0;
+ reg_we_check[9] = measure_ctrl_regwen_we;
+ reg_we_check[10] = io_meas_ctrl_en_we;
+ reg_we_check[11] = io_meas_ctrl_shadowed_we;
+ reg_we_check[12] = io_div2_meas_ctrl_en_we;
+ reg_we_check[13] = io_div2_meas_ctrl_shadowed_we;
+ reg_we_check[14] = io_div4_meas_ctrl_en_we;
+ reg_we_check[15] = io_div4_meas_ctrl_shadowed_we;
+ reg_we_check[16] = main_meas_ctrl_en_we;
+ reg_we_check[17] = main_meas_ctrl_shadowed_we;
+ reg_we_check[18] = usb_meas_ctrl_en_we;
+ reg_we_check[19] = usb_meas_ctrl_shadowed_we;
+ reg_we_check[20] = recov_err_code_we;
+ reg_we_check[21] = 1'b0;
+ end
+
+ // Read data return
+ always_comb begin
+ reg_rdata_next = '0;
+ unique case (1'b1)
+ addr_hit[0]: begin
+ reg_rdata_next[0] = '0;
+ reg_rdata_next[1] = '0;
+ end
+
+ addr_hit[1]: begin
+ reg_rdata_next[0] = extclk_ctrl_regwen_qs;
+ end
+
+ addr_hit[2]: begin
+ reg_rdata_next[3:0] = extclk_ctrl_sel_qs;
+ reg_rdata_next[7:4] = extclk_ctrl_hi_speed_sel_qs;
+ end
+
+ addr_hit[3]: begin
+ reg_rdata_next[3:0] = extclk_status_qs;
+ end
+
+ addr_hit[4]: begin
+ reg_rdata_next[0] = jitter_regwen_qs;
+ end
+
+ addr_hit[5]: begin
+ reg_rdata_next[3:0] = jitter_enable_qs;
+ end
+
+ addr_hit[6]: begin
+ reg_rdata_next[0] = clk_enables_clk_io_div4_peri_en_qs;
+ reg_rdata_next[1] = clk_enables_clk_io_div2_peri_en_qs;
+ reg_rdata_next[2] = clk_enables_clk_io_peri_en_qs;
+ reg_rdata_next[3] = clk_enables_clk_usb_peri_en_qs;
+ end
+
+ addr_hit[7]: begin
+ reg_rdata_next[0] = clk_hints_clk_main_aes_hint_qs;
+ reg_rdata_next[1] = clk_hints_clk_main_hmac_hint_qs;
+ reg_rdata_next[2] = clk_hints_clk_main_kmac_hint_qs;
+ reg_rdata_next[3] = clk_hints_clk_main_otbn_hint_qs;
+ end
+
+ addr_hit[8]: begin
+ reg_rdata_next[0] = clk_hints_status_clk_main_aes_val_qs;
+ reg_rdata_next[1] = clk_hints_status_clk_main_hmac_val_qs;
+ reg_rdata_next[2] = clk_hints_status_clk_main_kmac_val_qs;
+ reg_rdata_next[3] = clk_hints_status_clk_main_otbn_val_qs;
+ end
+
+ addr_hit[9]: begin
+ reg_rdata_next[0] = measure_ctrl_regwen_qs;
+ end
+
+ addr_hit[10]: begin
+ reg_rdata_next = DW'(io_meas_ctrl_en_qs);
+ end
+ addr_hit[11]: begin
+ reg_rdata_next = DW'(io_meas_ctrl_shadowed_qs);
+ end
+ addr_hit[12]: begin
+ reg_rdata_next = DW'(io_div2_meas_ctrl_en_qs);
+ end
+ addr_hit[13]: begin
+ reg_rdata_next = DW'(io_div2_meas_ctrl_shadowed_qs);
+ end
+ addr_hit[14]: begin
+ reg_rdata_next = DW'(io_div4_meas_ctrl_en_qs);
+ end
+ addr_hit[15]: begin
+ reg_rdata_next = DW'(io_div4_meas_ctrl_shadowed_qs);
+ end
+ addr_hit[16]: begin
+ reg_rdata_next = DW'(main_meas_ctrl_en_qs);
+ end
+ addr_hit[17]: begin
+ reg_rdata_next = DW'(main_meas_ctrl_shadowed_qs);
+ end
+ addr_hit[18]: begin
+ reg_rdata_next = DW'(usb_meas_ctrl_en_qs);
+ end
+ addr_hit[19]: begin
+ reg_rdata_next = DW'(usb_meas_ctrl_shadowed_qs);
+ end
+ addr_hit[20]: begin
+ reg_rdata_next[0] = recov_err_code_shadow_update_err_qs;
+ reg_rdata_next[1] = recov_err_code_io_measure_err_qs;
+ reg_rdata_next[2] = recov_err_code_io_div2_measure_err_qs;
+ reg_rdata_next[3] = recov_err_code_io_div4_measure_err_qs;
+ reg_rdata_next[4] = recov_err_code_main_measure_err_qs;
+ reg_rdata_next[5] = recov_err_code_usb_measure_err_qs;
+ reg_rdata_next[6] = recov_err_code_io_timeout_err_qs;
+ reg_rdata_next[7] = recov_err_code_io_div2_timeout_err_qs;
+ reg_rdata_next[8] = recov_err_code_io_div4_timeout_err_qs;
+ reg_rdata_next[9] = recov_err_code_main_timeout_err_qs;
+ reg_rdata_next[10] = recov_err_code_usb_timeout_err_qs;
+ end
+
+ addr_hit[21]: begin
+ reg_rdata_next[0] = fatal_err_code_reg_intg_qs;
+ reg_rdata_next[1] = fatal_err_code_idle_cnt_qs;
+ reg_rdata_next[2] = fatal_err_code_shadow_storage_err_qs;
+ end
+
+ default: begin
+ reg_rdata_next = '1;
+ end
+ endcase
+ end
+
+ // shadow busy
+ logic shadow_busy;
+ logic rst_done;
+ logic shadow_rst_done;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ rst_done <= '0;
+ end else begin
+ rst_done <= 1'b1;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_shadowed_ni) begin
+ if (!rst_shadowed_ni) begin
+ shadow_rst_done <= '0;
+ end else begin
+ shadow_rst_done <= 1'b1;
+ end
+ end
+
+ // both shadow and normal resets have been released
+ assign shadow_busy = ~(rst_done & shadow_rst_done);
+
+ // Collect up storage and update errors
+ assign shadowed_storage_err_o = |{
+ io_meas_ctrl_shadowed_hi_storage_err,
+ io_meas_ctrl_shadowed_lo_storage_err,
+ io_div2_meas_ctrl_shadowed_hi_storage_err,
+ io_div2_meas_ctrl_shadowed_lo_storage_err,
+ io_div4_meas_ctrl_shadowed_hi_storage_err,
+ io_div4_meas_ctrl_shadowed_lo_storage_err,
+ main_meas_ctrl_shadowed_hi_storage_err,
+ main_meas_ctrl_shadowed_lo_storage_err,
+ usb_meas_ctrl_shadowed_hi_storage_err,
+ usb_meas_ctrl_shadowed_lo_storage_err
+ };
+ assign shadowed_update_err_o = |{
+ io_meas_ctrl_shadowed_hi_update_err,
+ io_meas_ctrl_shadowed_lo_update_err,
+ io_div2_meas_ctrl_shadowed_hi_update_err,
+ io_div2_meas_ctrl_shadowed_lo_update_err,
+ io_div4_meas_ctrl_shadowed_hi_update_err,
+ io_div4_meas_ctrl_shadowed_lo_update_err,
+ main_meas_ctrl_shadowed_hi_update_err,
+ main_meas_ctrl_shadowed_lo_update_err,
+ usb_meas_ctrl_shadowed_hi_update_err,
+ usb_meas_ctrl_shadowed_lo_update_err
+ };
+
+ // register busy
+ logic reg_busy_sel;
+ assign reg_busy = reg_busy_sel | shadow_busy;
+ always_comb begin
+ reg_busy_sel = '0;
+ unique case (1'b1)
+ addr_hit[10]: begin
+ reg_busy_sel = io_meas_ctrl_en_busy;
+ end
+ addr_hit[11]: begin
+ reg_busy_sel = io_meas_ctrl_shadowed_busy;
+ end
+ addr_hit[12]: begin
+ reg_busy_sel = io_div2_meas_ctrl_en_busy;
+ end
+ addr_hit[13]: begin
+ reg_busy_sel = io_div2_meas_ctrl_shadowed_busy;
+ end
+ addr_hit[14]: begin
+ reg_busy_sel = io_div4_meas_ctrl_en_busy;
+ end
+ addr_hit[15]: begin
+ reg_busy_sel = io_div4_meas_ctrl_shadowed_busy;
+ end
+ addr_hit[16]: begin
+ reg_busy_sel = main_meas_ctrl_en_busy;
+ end
+ addr_hit[17]: begin
+ reg_busy_sel = main_meas_ctrl_shadowed_busy;
+ end
+ addr_hit[18]: begin
+ reg_busy_sel = usb_meas_ctrl_en_busy;
+ end
+ addr_hit[19]: begin
+ reg_busy_sel = usb_meas_ctrl_shadowed_busy;
+ end
+ default: begin
+ reg_busy_sel = '0;
+ end
+ endcase
+ end
+
+
+ // Unused signal tieoff
+
+ // wdata / byte enable are not always fully used
+ // add a blanket unused statement to handle lint waivers
+ logic unused_wdata;
+ logic unused_be;
+ assign unused_wdata = ^reg_wdata;
+ assign unused_be = ^reg_be;
+
+ // Assertions for Register Interface
+ `ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
+ `ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
+
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o_pre.d_valid, clk_i, !rst_ni)
+
+ `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
+
+ // 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.chk_en == tlul_pkg::CheckDis)
+
+endmodule
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_root_ctrl.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_root_ctrl.sv
new file mode 100644
index 00000000000000..6d54298eb162cd
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_root_ctrl.sv
@@ -0,0 +1,41 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Wrapper for scan sync and clock gating cell
+
+module clkmgr_root_ctrl
+ import clkmgr_pkg::*;
+ import prim_mubi_pkg::mubi4_t;
+(
+ input clk_i,
+ input rst_ni,
+
+ input mubi4_t scanmode_i,
+ input async_en_i,
+
+ output logic en_o,
+ output logic clk_o
+);
+
+ mubi4_t scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0) // clock/reset below is only used for SVAs.
+ ) u_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o({scanmode})
+ );
+
+ prim_clock_gating_sync u_cg (
+ .clk_i,
+ .rst_ni,
+ .test_en_i(prim_mubi_pkg::mubi4_test_true_strict(scanmode)),
+ .async_en_i,
+ .en_o,
+ .clk_o
+ );
+
+endmodule // clkmgr_root_ctrl
diff --git a/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_trans.sv b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_trans.sv
new file mode 100644
index 00000000000000..f2000c26edec48
--- /dev/null
+++ b/hw/top_earlgrey/ip_autogen/clkmgr/rtl/clkmgr_trans.sv
@@ -0,0 +1,175 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Handle clock manager transactional clocks
+
+module clkmgr_trans
+ import clkmgr_pkg::*;
+ import prim_mubi_pkg::mubi4_t;
+# (
+ parameter bit FpgaBufGlobal = 1
+) (
+ input clk_i,
+ input clk_gated_i,
+ input rst_ni,
+ input en_i,
+ input mubi4_t idle_i,
+ input sw_hint_i,
+ input mubi4_t scanmode_i,
+ output mubi4_t alert_cg_en_o,
+ output logic clk_o,
+
+ // interface to regfile
+ input clk_reg_i,
+ input rst_reg_ni,
+ output logic reg_en_o,
+ output logic reg_cnt_err_o
+);
+
+ import prim_mubi_pkg::MuBi4False;
+ import prim_mubi_pkg::MuBi4True;
+ import prim_mubi_pkg::mubi4_test_true_strict;
+ import prim_mubi_pkg::mubi4_test_false_loose;
+
+ // Note this value is specifically chosen.
+ // The binary value is 1010, which is a balanced 4-bit value
+ // that should in theory be resistant to all 0 or all 1 attacks.
+ localparam int unsigned TransIdleCnt = 10;
+ localparam int IdleCntWidth = $clog2(TransIdleCnt + 1);
+
+ logic [IdleCntWidth-1:0] idle_cnt;
+ logic idle_valid;
+ logic sw_hint_synced;
+ logic local_en;
+ assign idle_valid = (idle_cnt == IdleCntWidth'(TransIdleCnt));
+ assign local_en = sw_hint_synced | ~idle_valid;
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_hint_sync (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .d_i(sw_hint_i),
+ .q_o(sw_hint_synced)
+ );
+
+ // Idle sync: Idle signal comes from IP module. The reset of the Idle signal
+ // may differ from the reset here. Adding mubi sync to synchronize.
+ prim_mubi_pkg::mubi4_t [0:0] idle;
+ prim_mubi4_sync #(
+ .NumCopies ( 1 ),
+ .AsyncOn ( 1'b 1 ),
+ .StabilityCheck ( 1'b 1 )
+ ) u_idle_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i (idle_i),
+ .mubi_o (idle)
+ );
+
+ // SEC_CM: IDLE.CTR.REDUN
+ logic cnt_err;
+ prim_count #(
+ .Width(IdleCntWidth)
+ ) u_idle_cnt (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ // the default condition is to keep the clock enabled
+ .clr_i(mubi4_test_false_loose(idle[0])),
+ .set_i('0),
+ .set_cnt_i('0),
+ .incr_en_i(mubi4_test_true_strict(idle[0]) & ~idle_valid),
+ .decr_en_i(1'b0),
+ .step_i(IdleCntWidth'(1'b1)),
+ .commit_i(1'b1),
+ .cnt_o(idle_cnt),
+ .cnt_after_commit_o(),
+ .err_o(cnt_err)
+ );
+
+ // Declared as size 1 packed array to avoid FPV warning.
+ prim_mubi_pkg::mubi4_t [0:0] scanmode;
+ prim_mubi4_sync #(
+ .NumCopies(1),
+ .AsyncOn(0)
+ ) u_scanmode_sync (
+ .clk_i,
+ .rst_ni,
+ .mubi_i(scanmode_i),
+ .mubi_o(scanmode)
+ );
+
+ // Add a prim buf here to make sure the CG and the lc sender inputs
+ // are derived from the same physical signal.
+ logic combined_en_d, combined_en_q;
+ prim_buf u_prim_buf_en (
+ .in_i(local_en & en_i),
+ .out_o(combined_en_d)
+ );
+
+ // clk_gated_i is already controlled by en_i, so there is no need
+ // to use it in the below gating function
+ prim_clock_gating #(
+ .FpgaBufGlobal(FpgaBufGlobal)
+ ) u_cg (
+ .clk_i(clk_gated_i),
+ .en_i(local_en),
+ .test_en_i(mubi4_test_true_strict(scanmode[0])),
+ .clk_o(clk_o)
+ );
+
+ // clock gated indication for alert handler
+ prim_mubi4_sender #(
+ .ResetValue(MuBi4True)
+ ) u_prim_mubi4_sender (
+ .clk_i(clk_i),
+ .rst_ni(rst_ni),
+ .mubi_i(combined_en_d ? MuBi4False : MuBi4True),
+ .mubi_o(alert_cg_en_o)
+ );
+
+ // we hold the error because there is no guarantee on
+ // what the timing of cnt_err looks like, it may be a
+ // pulse or it may be level. If it's for former,
+ // prim_sync_reqack may miss it, if it's the latter,
+ // prim_pulse_sync may miss it. As a result, just
+ // latch forever and sync it over.
+ logic hold_err;
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ hold_err <= '0;
+ end else if (cnt_err) begin
+ hold_err <= 1'b1;
+ end
+ end
+
+ // register facing domain
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_err_sync (
+ .clk_i(clk_reg_i),
+ .rst_ni(rst_reg_ni),
+ .d_i(hold_err),
+ .q_o(reg_cnt_err_o)
+ );
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ combined_en_q <= '0;
+ end else begin
+ combined_en_q <= combined_en_d;
+ end
+ end
+
+ prim_flop_2sync #(
+ .Width(1)
+ ) u_en_sync (
+ .clk_i(clk_reg_i),
+ .rst_ni(rst_reg_ni),
+ .d_i(combined_en_q),
+ .q_o(reg_en_o)
+ );
+
+
+endmodule
diff --git a/util/topgen.py b/util/topgen.py
index 54e0c1b6b2f9c9..476fdb96635006 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -34,7 +34,7 @@
from topgen import lib as lib
from topgen import merge_top, search_ips, secure_prng, validate_top
from topgen.c_test import TopGenCTest
-from topgen.clocks import Clocks
+from topgen.clocks import Clocks, ClockSignal
from topgen.gen_dv import gen_dv
from topgen.gen_top_docs import gen_top_docs
from topgen.merge import connect_clocks, create_alert_lpgs, extract_clocks
@@ -428,6 +428,37 @@ def generate_clkmgr(top: Dict[str, object], cfg_path: Path,
generate_regfile_from_path(hjson_out, rtl_path, original_rtl_path)
+# generate clkmgr with ipgen
+def generate_ipgen_clkmgr(topcfg: Dict[str, object], out_path: Path) -> None:
+ log.info("Generating clkmgr with ipgen")
+ topname = topcfg["name"]
+
+ clocks = topcfg["clocks"]
+ assert isinstance(clocks, Clocks)
+
+ typed_clocks = clocks.typed_clocks()
+ hint_names = typed_clocks.hint_names()
+
+ typed_clks = OrderedDict({
+ ty: {nm: {"src_name": sig.src.name, "endpoint_ip": sig.endpoints[0][0]}
+ for nm, sig in mp.items() if isinstance(sig, ClockSignal)}
+ for ty, mp in typed_clocks._asdict().items() if isinstance(mp, dict)})
+ params = {
+ "src_clks": OrderedDict({
+ name: vars(obj) for name, obj in clocks.srcs.items()}),
+ "derived_clks": OrderedDict({
+ name: vars(obj) for name, obj in clocks.derived_srcs.items()}),
+ "typed_clocks": OrderedDict({
+ ty: d for ty, d in typed_clks.items() if d}),
+ "hint_names": hint_names,
+ "parent_child_clks": typed_clocks.parent_child_clks,
+ "exported_clks": topcfg["exported_clks"],
+ "number_of_clock_groups": len(clocks.groups)
+ }
+
+ ipgen_render("clkmgr", topname, params, out_path)
+
+
def generate_pwrmgr(top: Dict[str, object], out_path: Path) -> None:
log.info("Generating pwrmgr with ipgen")
topname = top["name"]
@@ -770,6 +801,7 @@ def _process_top(topcfg: Dict[str, object], args: argparse.Namespace,
topcfg["clocks"] = Clocks(topcfg["clocks"])
extract_clocks(topcfg)
generate_clkmgr(topcfg, cfg_path, out_path)
+ generate_ipgen_clkmgr(topcfg, out_path)
# It may require two passes to check if the module is needed.
# TODO: first run of topgen will fail due to the absent of rv_plic.
@@ -1140,7 +1172,8 @@ def main():
log.debug("Generation pass {}".format(pass_idx))
if pass_idx < process_dependencies:
cfg_copy = deepcopy(topcfg)
- _process_top(cfg_copy, args, cfg_path, out_path_gen, pass_idx)
+ _, _ = _process_top(cfg_copy, args, cfg_path, out_path_gen,
+ pass_idx)
else:
completecfg, name_to_block = _process_top(topcfg, args, cfg_path,
out_path_gen, pass_idx)