[ pwm, rtl ] Initial implementation for PWM

Signed-off-by: Martin Lueker-Boden <martin.lueker-boden@wdc.com>
diff --git a/hw/ip/pwm/data/pwm.hjson b/hw/ip/pwm/data/pwm.hjson
index 8b674b4..6150161 100644
--- a/hw/ip/pwm/data/pwm.hjson
+++ b/hw/ip/pwm/data/pwm.hjson
@@ -13,7 +13,7 @@
   param_list: [
     { name: "NOutputs",
       desc: "Number of PWM outputs",
-       type: "int",
+      type: "int",
       default: "6",
     }
   ]
diff --git a/hw/ip/pwm/doc/_index.md b/hw/ip/pwm/doc/_index.md
index c75d33e..ea7c1d6 100644
--- a/hw/ip/pwm/doc/_index.md
+++ b/hw/ip/pwm/doc/_index.md
@@ -108,13 +108,13 @@
 
 $$DC(x)=\frac{x}{2^{16}}.$$
 
-Thus the allowed duty cycle in principle ranges from 0 to 99.998% (i.e. 1-(&frac12;)<sup>16</sup>).
+Thus the allowed duty cycle in principle ranges from 0 to 99.998% (i.e. <nobr>1-(&frac12;)<sup>16</sup></nobr>).
 
 However, the actual phase resolution may be smaller.
-In order to support faster pulse rates, the phase resolution can be set to less than 16-bits, in which case the observed duty cycle will be rounded down to the next lowest multiple of 2<sup>-({{< regref "CFG.DC_RESN" >}}+1)</sup>.
-In other words, the {{< regref "CFG.DC_RESN" >}} register effectively limits the duty cycle resolution, such that only the {{< regref "CFG.DC_RESN" >}}+1 most significant bits are relevant:
+In order to support faster pulse rates, the phase resolution can be set to less than 16-bits, in which case the observed duty cycle will be rounded down to the next lowest multiple of <nobr>2<sup>-({{< regref "CFG.DC_RESN" >}}+1)</sup></nobr>.
+In other words, the {{< regref "CFG.DC_RESN" >}} register effectively limits the duty cycle resolution, such that only the <nobr>{{< regref "CFG.DC_RESN" >}}+1</nobr> most significant bits are relevant:
 
-$$DC(x; \textrm{DC_RESN})=\frac{\textrm{MSB}(x; \textrm{DC_RESN}+1)}{2^{\textrm{DC_RESN}+1}},$$
+$$DC(x; \textrm{DC_RESN})=\frac{\textrm{MSB}(x; \textrm{DC_RESN}+1)}{2^{(\textrm{DC_RESN}+1)}},$$
 
 where here we use the notation MSB(<i>x</i>; <i>y</i>), to mean the <i>y</i> most significant bits of the binary value <i>x</i>.
 
@@ -124,7 +124,7 @@
 As we discuss in the next section, each channel has a comparator which compares these values to the current duty cycle and phase value and generates the appropriate pulse.
 Since all phase or duty cycle related quantities are represented as 16-bit fixed point fractions-regardless of whether they are calculated by the PWM IP or determined by firmware-the phase counter is also a 16-bit quantity.
 
-Each PWM pulse cycle is divided into 2<sup>DC_RESN+1</sup> beats.
+Each PWM pulse cycle is divided into <nobr>2<sup>DC_RESN+1</sup></nobr> beats.
 During each beat, the 16-bit phase counter increments by 2<sup>(16-DC_RESN-1)</sup> (modulo 65536).
 The beat period is defined by the {{< regref "CFG.CLK_DIV" >}} register:
 
diff --git a/hw/ip/pwm/lint/pwm.vlt b/hw/ip/pwm/lint/pwm.vlt
new file mode 100644
index 0000000..6f84d10
--- /dev/null
+++ b/hw/ip/pwm/lint/pwm.vlt
@@ -0,0 +1,6 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// waiver file for pwm
+
diff --git a/hw/ip/pwm/lint/pwm.waiver b/hw/ip/pwm/lint/pwm.waiver
new file mode 100644
index 0000000..7930c42
--- /dev/null
+++ b/hw/ip/pwm/lint/pwm.waiver
@@ -0,0 +1,6 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+#
+# waiver file for pwm
+
diff --git a/hw/ip/pwm/pwm.core b/hw/ip/pwm/pwm.core
new file mode 100644
index 0000000..fbd7de8
--- /dev/null
+++ b/hw/ip/pwm/pwm.core
@@ -0,0 +1,70 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:ip:pwm:0.1"
+description: "pwm"
+filesets:
+  files_rtl:
+    depend:
+      - lowrisc:prim:assert
+      - lowrisc:ip:tlul
+      - lowrisc:prim:all
+    files:
+      - rtl/pwm_reg_pkg.sv
+      - rtl/pwm_reg_top.sv
+      - rtl/pwm_chan.sv
+      - rtl/pwm_cdc.sv
+      - rtl/pwm_core.sv
+      - rtl/pwm.sv
+    file_type: systemVerilogSource
+
+  files_verilator_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+    files:
+      - lint/pwm.vlt
+    file_type: vlt
+
+  files_ascentlint_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+    files:
+      - lint/pwm.waiver
+    file_type: waiver
+
+  files_veriblelint_waiver:
+    depend:
+      # common waivers
+      - lowrisc:lint:common
+      - lowrisc:lint:comportable
+
+parameters:
+  SYNTHESIS:
+    datatype: bool
+    paramtype: vlogdefine
+
+
+targets:
+  default: &default_target
+    filesets:
+      - tool_verilator   ? (files_verilator_waiver)
+      - tool_ascentlint  ? (files_ascentlint_waiver)
+      - tool_veriblelint ? (files_veriblelint_waiver)
+      - files_rtl
+    toplevel: pwm
+
+  lint:
+    <<: *default_target
+    default_tool: verilator
+    parameters:
+      - SYNTHESIS=true
+    tools:
+      verilator:
+        mode: lint-only
+        verilator_options:
+          - "-Wall"
diff --git a/hw/ip/pwm/rtl/pwm.sv b/hw/ip/pwm/rtl/pwm.sv
new file mode 100644
index 0000000..fee97cb
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm.sv
@@ -0,0 +1,53 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "prim_assert.sv"
+
+module pwm #(
+  parameter int NOutputs = 6
+) (
+  input                       clk_i,
+  input                       rst_ni,
+
+  input                       clk_core_i,
+  input                       rst_core_ni,
+
+  input                       tlul_pkg::tl_h2d_t tl_i,
+  output                      tlul_pkg::tl_d2h_t tl_o,
+
+  output logic [NOutputs-1:0] cio_pwm_o,
+  output logic [NOutputs-1:0] cio_pwm_en_o
+);
+
+  // TODO: Deal with Regen in this block, on TLUL clock domain
+  logic                      regen;
+  pwm_reg_pkg::pwm_reg2hw_t reg2hw;
+
+  assign regen = reg2hw.regen.q;
+
+  pwm_reg_top u_reg (
+    .clk_i,
+    .rst_ni,
+    .tl_i,
+    .tl_o,
+    .reg2hw,
+    .intg_err_o (),
+    .devmode_i  (1'b1)
+  );
+
+  assign cio_pwm_en_o = {NOutputs{1'b1}};
+
+  pwm_core #(.NOutputs(NOutputs)) u_pwm_core (
+    .clk_core_i,
+    .rst_core_ni,
+    .reg2hw,
+    .pwm_o       (cio_pwm_o)
+  );
+
+  `ASSERT_KNOWN(TlDValidKnownO_A, tl_o.d_valid)
+  `ASSERT_KNOWN(TlAReadyKnownO_A, tl_o.a_ready)
+
+  `ASSERT_KNOWN(CioPWMKnownO_A, cio_pwm_o)
+
+endmodule : pwm
diff --git a/hw/ip/pwm/rtl/pwm_cdc.sv b/hw/ip/pwm/rtl/pwm_cdc.sv
new file mode 100644
index 0000000..ae1af4a
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm_cdc.sv
@@ -0,0 +1,107 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: CDC for PWM
+
+module pwm_cdc #(
+  parameter int NOutputs = 6
+) (
+  input                            clk_core_i,
+  input                            rst_core_ni,
+  input  pwm_reg_pkg::pwm_reg2hw_t reg2hw,
+  output pwm_reg_pkg::pwm_reg2hw_t reg2hw_sync,
+  output logic                     clr_phase_cntr,
+  output logic [NOutputs-1:0]      clr_blink_cntr
+);
+
+  wire [31:0] common_sync_in  = {reg2hw.cfg.clk_div.q,
+                                 reg2hw.cfg.dc_resn.q,
+                                 reg2hw.cfg.cntr_en.q};
+
+  wire [31:0] common_sync_out;
+  assign {reg2hw_sync.cfg.clk_div.q,
+          reg2hw_sync.cfg.dc_resn.q,
+          reg2hw_sync.cfg.cntr_en.q} = common_sync_out;
+
+  // Regen field does not need syncing, but assign it a value for completeness.
+  assign reg2hw_sync.regen.q = 1'b0;
+
+  reg [31:0] common_sync_q;
+
+  prim_generic_flop_2sync #(
+    .Width(32),
+    .ResetValue(32'h0)
+  ) u_common_sync (
+    .clk_i  (clk_core_i),
+    .rst_ni (rst_core_ni),
+    .d_i    (common_sync_in),
+    .q_o    (common_sync_out)
+  );
+
+  always_ff @(posedge clk_core_i or negedge rst_core_ni) begin
+    if (!rst_core_ni) begin
+      common_sync_q <= 32'h0;
+    end else begin
+      common_sync_q <= common_sync_out;
+    end
+  end
+
+  // Reset internal counters whenever parameters change. Though this may cause a single clock
+  // nondeterministic delay as the buses wind though the CDC, this does not matter, particularly
+  // since all channels will experience the same delay.
+
+  assign clr_phase_cntr = (common_sync_q != common_sync_out);
+
+  for (genvar ii = 0; ii < NOutputs; ii++) begin : chan_cdc
+
+    wire [83:0] chan_sync_in  = {reg2hw.pwm_en[ii].q,
+                                 reg2hw.invert[ii].q,
+                                 reg2hw.pwm_param[ii].phase_delay.q,
+                                 reg2hw.pwm_param[ii].htbt_en.q,
+                                 reg2hw.pwm_param[ii].blink_en.q,
+                                 reg2hw.duty_cycle[ii].a.q,
+                                 reg2hw.duty_cycle[ii].b.q,
+                                 reg2hw.blink_param[ii].x.q,
+                                 reg2hw.blink_param[ii].y.q};
+
+    wire [83:0] chan_sync_out;
+
+    assign {reg2hw_sync.pwm_en[ii].q,
+            reg2hw_sync.invert[ii].q,
+            reg2hw_sync.pwm_param[ii].phase_delay.q,
+            reg2hw_sync.pwm_param[ii].htbt_en.q,
+            reg2hw_sync.pwm_param[ii].blink_en.q,
+            reg2hw_sync.duty_cycle[ii].a.q,
+            reg2hw_sync.duty_cycle[ii].b.q,
+            reg2hw_sync.blink_param[ii].x.q,
+            reg2hw_sync.blink_param[ii].y.q} = chan_sync_out;
+
+    reg [83:0] chan_sync_q;
+
+    prim_generic_flop_2sync #(
+      .Width(84),
+      .ResetValue(84'h0)
+    ) u_common_sync (
+      .clk_i  (clk_core_i),
+      .rst_ni (rst_core_ni),
+      .d_i    (chan_sync_in),
+      .q_o    (chan_sync_out)
+    );
+
+    always_ff @(posedge clk_core_i or negedge rst_core_ni) begin
+      if (!rst_core_ni) begin
+        chan_sync_q <= 84'h0;
+      end else begin
+        chan_sync_q <= chan_sync_out;
+      end
+    end
+
+    // Though it may be a bit overkill, we reset the internal blink counters whenever any channel
+    // specific parameters change.
+
+    assign clr_blink_cntr[ii] = (chan_sync_q != chan_sync_out);
+
+  end : chan_cdc
+
+endmodule : pwm_cdc
diff --git a/hw/ip/pwm/rtl/pwm_chan.sv b/hw/ip/pwm/rtl/pwm_chan.sv
new file mode 100644
index 0000000..550f7ca
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm_chan.sv
@@ -0,0 +1,51 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module pwm_chan (
+  input        clk_i,
+  input        rst_ni,
+
+  input        pwm_en_i,
+  input        invert_i,
+  input        blink_en_i,
+  input        htbt_en_i,
+  input [15:0] phase_delay_i,
+  input [15:0] duty_cycle_a_i,
+  input [15:0] duty_cycle_b_i,
+  input [15:0] blink_param_x_i,
+  input [15:0] blink_param_y_i,
+
+  input [15:0] phase_ctr_i,
+  input        cycle_end_i,
+  input        clr_blink_cntr_i,
+
+  output logic pwm_o
+);
+
+   logic [15:0] duty_cycle_actual;
+   logic [15:0] on_phase;
+   logic [15:0] off_phase;
+   logic        phase_wrap;
+   logic        pwm_int;
+
+   // TODO: Implement blink modes
+   assign duty_cycle_actual = duty_cycle_a_i;
+
+   assign on_phase = phase_delay_i;
+   assign {phase_wrap, off_phase} = {1'b0, phase_delay_i} + {1'b0, duty_cycle_actual};
+
+   logic on_phase_exceeded;
+   logic off_phase_exceeded;
+
+   assign on_phase_exceeded  = (phase_ctr_i >= on_phase);
+   assign off_phase_exceeded = (phase_ctr_i >= off_phase);
+
+
+   assign pwm_int = pwm_en_i   ? 1'b0 :
+                    phase_wrap ? on_phase_exceeded | ~off_phase_exceeded :
+                                 on_phase_exceeded & ~off_phase_exceeded;
+
+   assign pwm_o = invert_i ? ~pwm_int : pwm_int;
+
+endmodule : pwm_chan
diff --git a/hw/ip/pwm/rtl/pwm_core.sv b/hw/ip/pwm/rtl/pwm_core.sv
new file mode 100644
index 0000000..fbd3bf4
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm_core.sv
@@ -0,0 +1,116 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Description: PWM Core Module
+
+module pwm_core #(
+  parameter int NOutputs = 6
+) (
+  input                           clk_core_i,
+  input                           rst_core_ni,
+
+  input pwm_reg_pkg::pwm_reg2hw_t reg2hw,
+
+  output logic [NOutputs-1:0]     pwm_o
+);
+
+  logic                           regen;
+
+  // TODO: implement register locking
+  assign regen = reg2hw.regen.q;
+
+  pwm_reg_pkg::pwm_reg2hw_t       reg2hw_sync;
+  logic                           clr_phase_cntr;
+  logic [NOutputs-1:0]            clr_blink_cntr;
+
+  pwm_cdc u_pwm_cdc (
+    .clk_core_i,
+    .rst_core_ni,
+    .reg2hw,
+    .reg2hw_sync,
+    .clr_phase_cntr,
+    .clr_blink_cntr
+  );
+
+  //
+  // Beat and phase counters (in core clock domain)
+  //
+
+  logic        cntr_en_sync;
+  logic [26:0] clk_div_sync;
+  logic [3:0]  dc_resn_sync;
+
+  logic [26:0] beat_ctr_q;
+  logic [26:0] beat_ctr_d;
+  logic        beat_ctr_en;
+  logic        beat_end;
+
+  logic [15:0] phase_ctr_q;
+  logic [15:0] phase_ctr_d;
+  logic [15:0] phase_ctr_incr;
+  logic [15:0] phase_ctr_next;
+  logic        phase_ctr_overflow;
+  logic        phase_ctr_en;
+  logic        cycle_end;
+
+  assign cntr_en_sync = reg2hw_sync.cfg.cntr_en.q;
+  assign dc_resn_sync = reg2hw_sync.cfg.dc_resn.q;
+  assign clk_div_sync = reg2hw_sync.cfg.clk_div.q;
+
+  assign beat_ctr_d = (clr_phase_cntr) ? 27'h0 :
+                      (beat_ctr_q == clk_div_sync) ? 27'h0 : (beat_ctr_q + 27'h1);
+  assign beat_ctr_en = clr_phase_cntr | cntr_en_sync;
+  assign beat_end = (beat_ctr_q == clk_div_sync);
+
+  always_ff @(posedge clk_core_i or negedge rst_core_ni) begin
+    if (!rst_core_ni) begin
+      beat_ctr_q <= 27'h0;
+    end else begin
+      beat_ctr_q <= beat_ctr_en ? beat_ctr_d : beat_ctr_q;
+    end
+  end
+
+  // Only update phase_ctr at the end of each beat
+  // Exception: allow reset to zero whenever not enabled
+  assign phase_ctr_en = beat_end & (clr_phase_cntr | cntr_en_sync);
+  assign phase_ctr_incr =  16'h1 << (15 - dc_resn_sync);
+  assign {phase_ctr_overflow, phase_ctr_next} = phase_ctr_q + phase_ctr_incr;
+  assign phase_ctr_d = clr_phase_cntr ? 16'h0 : phase_ctr_next;
+  assign cycle_end = beat_end & phase_ctr_overflow;
+
+  always_ff @(posedge clk_core_i or negedge rst_core_ni) begin
+    if (!rst_core_ni) begin
+      phase_ctr_q <= 16'h0;
+    end else begin
+      phase_ctr_q <= phase_ctr_en ? phase_ctr_d : phase_ctr_q;
+    end
+  end
+
+  for (genvar ii = 0; ii < NOutputs; ii++) begin : chan_insts
+
+    //
+    // PWM Channel Instantiation
+    //
+
+    pwm_chan u_chan (
+      .clk_i            (clk_core_i),
+      .rst_ni           (rst_core_ni),
+      .pwm_en_i         (reg2hw_sync.pwm_en[ii].q),
+      .invert_i         (reg2hw_sync.invert[ii].q),
+      .phase_delay_i    (reg2hw_sync.pwm_param[ii].phase_delay.q),
+      .blink_en_i       (reg2hw_sync.pwm_param[ii].blink_en.q),
+      .htbt_en_i        (reg2hw_sync.pwm_param[ii].htbt_en.q),
+      .duty_cycle_a_i   (reg2hw_sync.duty_cycle[ii].a.q),
+      .duty_cycle_b_i   (reg2hw_sync.duty_cycle[ii].b.q),
+      .blink_param_x_i  (reg2hw_sync.blink_param[ii].x.q),
+      .blink_param_y_i  (reg2hw_sync.blink_param[ii].y.q),
+      .phase_ctr_i      (phase_ctr_q),
+      .clr_blink_cntr_i (clr_blink_cntr[ii]),
+      .cycle_end_i      (cycle_end),
+      .pwm_o            (pwm_o[ii])
+    );
+
+  end : chan_insts
+
+endmodule : pwm_core
diff --git a/hw/ip/pwm/rtl/pwm_reg_pkg.sv b/hw/ip/pwm/rtl/pwm_reg_pkg.sv
new file mode 100644
index 0000000..29ed498
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm_reg_pkg.sv
@@ -0,0 +1,167 @@
+// 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 pwm_reg_pkg;
+
+  // Param list
+  parameter int NOutputs = 6;
+
+  // Address width within the block
+  parameter int BlockAw = 7;
+
+  ////////////////////////////
+  // Typedefs for registers //
+  ////////////////////////////
+  typedef struct packed {
+    logic        q;
+  } pwm_reg2hw_regen_reg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic [26:0] q;
+    } clk_div;
+    struct packed {
+      logic [3:0]  q;
+    } dc_resn;
+    struct packed {
+      logic        q;
+    } cntr_en;
+  } pwm_reg2hw_cfg_reg_t;
+
+  typedef struct packed {
+    logic        q;
+  } pwm_reg2hw_pwm_en_mreg_t;
+
+  typedef struct packed {
+    logic        q;
+  } pwm_reg2hw_invert_mreg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic [15:0] q;
+    } phase_delay;
+    struct packed {
+      logic        q;
+    } htbt_en;
+    struct packed {
+      logic        q;
+    } blink_en;
+  } pwm_reg2hw_pwm_param_mreg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic [15:0] q;
+    } a;
+    struct packed {
+      logic [15:0] q;
+    } b;
+  } pwm_reg2hw_duty_cycle_mreg_t;
+
+  typedef struct packed {
+    struct packed {
+      logic [15:0] q;
+    } x;
+    struct packed {
+      logic [15:0] q;
+    } y;
+  } pwm_reg2hw_blink_param_mreg_t;
+
+
+
+  ///////////////////////////////////////
+  // Register to internal design logic //
+  ///////////////////////////////////////
+  typedef struct packed {
+    pwm_reg2hw_regen_reg_t regen; // [536:536]
+    pwm_reg2hw_cfg_reg_t cfg; // [535:504]
+    pwm_reg2hw_pwm_en_mreg_t [5:0] pwm_en; // [503:498]
+    pwm_reg2hw_invert_mreg_t [5:0] invert; // [497:492]
+    pwm_reg2hw_pwm_param_mreg_t [5:0] pwm_param; // [491:384]
+    pwm_reg2hw_duty_cycle_mreg_t [5:0] duty_cycle; // [383:192]
+    pwm_reg2hw_blink_param_mreg_t [5:0] blink_param; // [191:0]
+  } pwm_reg2hw_t;
+
+  ///////////////////////////////////////
+  // Internal design logic to register //
+  ///////////////////////////////////////
+
+  // Register Address
+  parameter logic [BlockAw-1:0] PWM_REGEN_OFFSET = 7'h 0;
+  parameter logic [BlockAw-1:0] PWM_CFG_OFFSET = 7'h 4;
+  parameter logic [BlockAw-1:0] PWM_PWM_EN_OFFSET = 7'h 8;
+  parameter logic [BlockAw-1:0] PWM_INVERT_OFFSET = 7'h c;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_0_OFFSET = 7'h 10;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_1_OFFSET = 7'h 14;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_2_OFFSET = 7'h 18;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_3_OFFSET = 7'h 1c;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_4_OFFSET = 7'h 20;
+  parameter logic [BlockAw-1:0] PWM_PWM_PARAM_5_OFFSET = 7'h 24;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_0_OFFSET = 7'h 28;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_1_OFFSET = 7'h 2c;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_2_OFFSET = 7'h 30;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_3_OFFSET = 7'h 34;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_4_OFFSET = 7'h 38;
+  parameter logic [BlockAw-1:0] PWM_DUTY_CYCLE_5_OFFSET = 7'h 3c;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_0_OFFSET = 7'h 40;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_1_OFFSET = 7'h 44;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_2_OFFSET = 7'h 48;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_3_OFFSET = 7'h 4c;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_4_OFFSET = 7'h 50;
+  parameter logic [BlockAw-1:0] PWM_BLINK_PARAM_5_OFFSET = 7'h 54;
+
+  // Register Index
+  typedef enum int {
+    PWM_REGEN,
+    PWM_CFG,
+    PWM_PWM_EN,
+    PWM_INVERT,
+    PWM_PWM_PARAM_0,
+    PWM_PWM_PARAM_1,
+    PWM_PWM_PARAM_2,
+    PWM_PWM_PARAM_3,
+    PWM_PWM_PARAM_4,
+    PWM_PWM_PARAM_5,
+    PWM_DUTY_CYCLE_0,
+    PWM_DUTY_CYCLE_1,
+    PWM_DUTY_CYCLE_2,
+    PWM_DUTY_CYCLE_3,
+    PWM_DUTY_CYCLE_4,
+    PWM_DUTY_CYCLE_5,
+    PWM_BLINK_PARAM_0,
+    PWM_BLINK_PARAM_1,
+    PWM_BLINK_PARAM_2,
+    PWM_BLINK_PARAM_3,
+    PWM_BLINK_PARAM_4,
+    PWM_BLINK_PARAM_5
+  } pwm_id_e;
+
+  // Register width information to check illegal writes
+  parameter logic [3:0] PWM_PERMIT [22] = '{
+    4'b 0001, // index[ 0] PWM_REGEN
+    4'b 1111, // index[ 1] PWM_CFG
+    4'b 0001, // index[ 2] PWM_PWM_EN
+    4'b 0001, // index[ 3] PWM_INVERT
+    4'b 1111, // index[ 4] PWM_PWM_PARAM_0
+    4'b 1111, // index[ 5] PWM_PWM_PARAM_1
+    4'b 1111, // index[ 6] PWM_PWM_PARAM_2
+    4'b 1111, // index[ 7] PWM_PWM_PARAM_3
+    4'b 1111, // index[ 8] PWM_PWM_PARAM_4
+    4'b 1111, // index[ 9] PWM_PWM_PARAM_5
+    4'b 1111, // index[10] PWM_DUTY_CYCLE_0
+    4'b 1111, // index[11] PWM_DUTY_CYCLE_1
+    4'b 1111, // index[12] PWM_DUTY_CYCLE_2
+    4'b 1111, // index[13] PWM_DUTY_CYCLE_3
+    4'b 1111, // index[14] PWM_DUTY_CYCLE_4
+    4'b 1111, // index[15] PWM_DUTY_CYCLE_5
+    4'b 1111, // index[16] PWM_BLINK_PARAM_0
+    4'b 1111, // index[17] PWM_BLINK_PARAM_1
+    4'b 1111, // index[18] PWM_BLINK_PARAM_2
+    4'b 1111, // index[19] PWM_BLINK_PARAM_3
+    4'b 1111, // index[20] PWM_BLINK_PARAM_4
+    4'b 1111  // index[21] PWM_BLINK_PARAM_5
+  };
+endpackage
+
diff --git a/hw/ip/pwm/rtl/pwm_reg_top.sv b/hw/ip/pwm/rtl/pwm_reg_top.sv
new file mode 100644
index 0000000..8e50a69
--- /dev/null
+++ b/hw/ip/pwm/rtl/pwm_reg_top.sv
@@ -0,0 +1,2247 @@
+// 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 pwm_reg_top (
+  input clk_i,
+  input rst_ni,
+
+  // Below Regster interface can be changed
+  input  tlul_pkg::tl_h2d_t tl_i,
+  output tlul_pkg::tl_d2h_t tl_o,
+  // To HW
+  output pwm_reg_pkg::pwm_reg2hw_t reg2hw, // Write
+
+  // Integrity check errors
+  output logic intg_err_o,
+
+  // Config
+  input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+  import pwm_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;
+
+  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,
+    .err_o(intg_err)
+  );
+
+  logic intg_err_q;
+  always_ff @(posedge clk_i or negedge rst_ni) begin
+    if (!rst_ni) begin
+      intg_err_q <= '0;
+    end else if (intg_err) begin
+      intg_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 = intg_err_q | intg_err;
+
+  // outgoing integrity generation
+  tlul_pkg::tl_d2h_t tl_o_pre;
+  tlul_rsp_intg_gen u_rsp_intg_gen (
+    .tl_i(tl_o_pre),
+    .tl_o
+  );
+
+  assign tl_reg_h2d = tl_i;
+  assign tl_o_pre   = tl_reg_d2h;
+
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
+
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
+
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
+
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = (devmode_i & addrmiss) | wr_err | intg_err;
+
+  // Define SW related signals
+  // Format: <reg>_<field>_{wd|we|qs}
+  //        or <reg>_{wd|we|qs} if field == 1 or 0
+  logic regen_qs;
+  logic regen_wd;
+  logic regen_we;
+  logic [26:0] cfg_clk_div_qs;
+  logic [26:0] cfg_clk_div_wd;
+  logic cfg_clk_div_we;
+  logic [3:0] cfg_dc_resn_qs;
+  logic [3:0] cfg_dc_resn_wd;
+  logic cfg_dc_resn_we;
+  logic cfg_cntr_en_qs;
+  logic cfg_cntr_en_wd;
+  logic cfg_cntr_en_we;
+  logic pwm_en_en_0_qs;
+  logic pwm_en_en_0_wd;
+  logic pwm_en_en_0_we;
+  logic pwm_en_en_1_qs;
+  logic pwm_en_en_1_wd;
+  logic pwm_en_en_1_we;
+  logic pwm_en_en_2_qs;
+  logic pwm_en_en_2_wd;
+  logic pwm_en_en_2_we;
+  logic pwm_en_en_3_qs;
+  logic pwm_en_en_3_wd;
+  logic pwm_en_en_3_we;
+  logic pwm_en_en_4_qs;
+  logic pwm_en_en_4_wd;
+  logic pwm_en_en_4_we;
+  logic pwm_en_en_5_qs;
+  logic pwm_en_en_5_wd;
+  logic pwm_en_en_5_we;
+  logic invert_invert_0_qs;
+  logic invert_invert_0_wd;
+  logic invert_invert_0_we;
+  logic invert_invert_1_qs;
+  logic invert_invert_1_wd;
+  logic invert_invert_1_we;
+  logic invert_invert_2_qs;
+  logic invert_invert_2_wd;
+  logic invert_invert_2_we;
+  logic invert_invert_3_qs;
+  logic invert_invert_3_wd;
+  logic invert_invert_3_we;
+  logic invert_invert_4_qs;
+  logic invert_invert_4_wd;
+  logic invert_invert_4_we;
+  logic invert_invert_5_qs;
+  logic invert_invert_5_wd;
+  logic invert_invert_5_we;
+  logic [15:0] pwm_param_0_phase_delay_0_qs;
+  logic [15:0] pwm_param_0_phase_delay_0_wd;
+  logic pwm_param_0_phase_delay_0_we;
+  logic pwm_param_0_htbt_en_0_qs;
+  logic pwm_param_0_htbt_en_0_wd;
+  logic pwm_param_0_htbt_en_0_we;
+  logic pwm_param_0_blink_en_0_qs;
+  logic pwm_param_0_blink_en_0_wd;
+  logic pwm_param_0_blink_en_0_we;
+  logic [15:0] pwm_param_1_phase_delay_1_qs;
+  logic [15:0] pwm_param_1_phase_delay_1_wd;
+  logic pwm_param_1_phase_delay_1_we;
+  logic pwm_param_1_htbt_en_1_qs;
+  logic pwm_param_1_htbt_en_1_wd;
+  logic pwm_param_1_htbt_en_1_we;
+  logic pwm_param_1_blink_en_1_qs;
+  logic pwm_param_1_blink_en_1_wd;
+  logic pwm_param_1_blink_en_1_we;
+  logic [15:0] pwm_param_2_phase_delay_2_qs;
+  logic [15:0] pwm_param_2_phase_delay_2_wd;
+  logic pwm_param_2_phase_delay_2_we;
+  logic pwm_param_2_htbt_en_2_qs;
+  logic pwm_param_2_htbt_en_2_wd;
+  logic pwm_param_2_htbt_en_2_we;
+  logic pwm_param_2_blink_en_2_qs;
+  logic pwm_param_2_blink_en_2_wd;
+  logic pwm_param_2_blink_en_2_we;
+  logic [15:0] pwm_param_3_phase_delay_3_qs;
+  logic [15:0] pwm_param_3_phase_delay_3_wd;
+  logic pwm_param_3_phase_delay_3_we;
+  logic pwm_param_3_htbt_en_3_qs;
+  logic pwm_param_3_htbt_en_3_wd;
+  logic pwm_param_3_htbt_en_3_we;
+  logic pwm_param_3_blink_en_3_qs;
+  logic pwm_param_3_blink_en_3_wd;
+  logic pwm_param_3_blink_en_3_we;
+  logic [15:0] pwm_param_4_phase_delay_4_qs;
+  logic [15:0] pwm_param_4_phase_delay_4_wd;
+  logic pwm_param_4_phase_delay_4_we;
+  logic pwm_param_4_htbt_en_4_qs;
+  logic pwm_param_4_htbt_en_4_wd;
+  logic pwm_param_4_htbt_en_4_we;
+  logic pwm_param_4_blink_en_4_qs;
+  logic pwm_param_4_blink_en_4_wd;
+  logic pwm_param_4_blink_en_4_we;
+  logic [15:0] pwm_param_5_phase_delay_5_qs;
+  logic [15:0] pwm_param_5_phase_delay_5_wd;
+  logic pwm_param_5_phase_delay_5_we;
+  logic pwm_param_5_htbt_en_5_qs;
+  logic pwm_param_5_htbt_en_5_wd;
+  logic pwm_param_5_htbt_en_5_we;
+  logic pwm_param_5_blink_en_5_qs;
+  logic pwm_param_5_blink_en_5_wd;
+  logic pwm_param_5_blink_en_5_we;
+  logic [15:0] duty_cycle_0_a_0_qs;
+  logic [15:0] duty_cycle_0_a_0_wd;
+  logic duty_cycle_0_a_0_we;
+  logic [15:0] duty_cycle_0_b_0_qs;
+  logic [15:0] duty_cycle_0_b_0_wd;
+  logic duty_cycle_0_b_0_we;
+  logic [15:0] duty_cycle_1_a_1_qs;
+  logic [15:0] duty_cycle_1_a_1_wd;
+  logic duty_cycle_1_a_1_we;
+  logic [15:0] duty_cycle_1_b_1_qs;
+  logic [15:0] duty_cycle_1_b_1_wd;
+  logic duty_cycle_1_b_1_we;
+  logic [15:0] duty_cycle_2_a_2_qs;
+  logic [15:0] duty_cycle_2_a_2_wd;
+  logic duty_cycle_2_a_2_we;
+  logic [15:0] duty_cycle_2_b_2_qs;
+  logic [15:0] duty_cycle_2_b_2_wd;
+  logic duty_cycle_2_b_2_we;
+  logic [15:0] duty_cycle_3_a_3_qs;
+  logic [15:0] duty_cycle_3_a_3_wd;
+  logic duty_cycle_3_a_3_we;
+  logic [15:0] duty_cycle_3_b_3_qs;
+  logic [15:0] duty_cycle_3_b_3_wd;
+  logic duty_cycle_3_b_3_we;
+  logic [15:0] duty_cycle_4_a_4_qs;
+  logic [15:0] duty_cycle_4_a_4_wd;
+  logic duty_cycle_4_a_4_we;
+  logic [15:0] duty_cycle_4_b_4_qs;
+  logic [15:0] duty_cycle_4_b_4_wd;
+  logic duty_cycle_4_b_4_we;
+  logic [15:0] duty_cycle_5_a_5_qs;
+  logic [15:0] duty_cycle_5_a_5_wd;
+  logic duty_cycle_5_a_5_we;
+  logic [15:0] duty_cycle_5_b_5_qs;
+  logic [15:0] duty_cycle_5_b_5_wd;
+  logic duty_cycle_5_b_5_we;
+  logic [15:0] blink_param_0_x_0_qs;
+  logic [15:0] blink_param_0_x_0_wd;
+  logic blink_param_0_x_0_we;
+  logic [15:0] blink_param_0_y_0_qs;
+  logic [15:0] blink_param_0_y_0_wd;
+  logic blink_param_0_y_0_we;
+  logic [15:0] blink_param_1_x_1_qs;
+  logic [15:0] blink_param_1_x_1_wd;
+  logic blink_param_1_x_1_we;
+  logic [15:0] blink_param_1_y_1_qs;
+  logic [15:0] blink_param_1_y_1_wd;
+  logic blink_param_1_y_1_we;
+  logic [15:0] blink_param_2_x_2_qs;
+  logic [15:0] blink_param_2_x_2_wd;
+  logic blink_param_2_x_2_we;
+  logic [15:0] blink_param_2_y_2_qs;
+  logic [15:0] blink_param_2_y_2_wd;
+  logic blink_param_2_y_2_we;
+  logic [15:0] blink_param_3_x_3_qs;
+  logic [15:0] blink_param_3_x_3_wd;
+  logic blink_param_3_x_3_we;
+  logic [15:0] blink_param_3_y_3_qs;
+  logic [15:0] blink_param_3_y_3_wd;
+  logic blink_param_3_y_3_we;
+  logic [15:0] blink_param_4_x_4_qs;
+  logic [15:0] blink_param_4_x_4_wd;
+  logic blink_param_4_x_4_we;
+  logic [15:0] blink_param_4_y_4_qs;
+  logic [15:0] blink_param_4_y_4_wd;
+  logic blink_param_4_y_4_we;
+  logic [15:0] blink_param_5_x_5_qs;
+  logic [15:0] blink_param_5_x_5_wd;
+  logic blink_param_5_x_5_we;
+  logic [15:0] blink_param_5_y_5_qs;
+  logic [15:0] blink_param_5_y_5_wd;
+  logic blink_param_5_y_5_we;
+
+  // Register instances
+  // R[regen]: V(False)
+
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("W1C"),
+    .RESVAL  (1'h1)
+  ) u_regen (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (regen_we),
+    .wd     (regen_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.regen.q ),
+
+    // to register interface (read)
+    .qs     (regen_qs)
+  );
+
+
+  // R[cfg]: V(False)
+
+  //   F[clk_div]: 26:0
+  prim_subreg #(
+    .DW      (27),
+    .SWACCESS("RW"),
+    .RESVAL  (27'h8000)
+  ) u_cfg_clk_div (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (cfg_clk_div_we),
+    .wd     (cfg_clk_div_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.cfg.clk_div.q ),
+
+    // to register interface (read)
+    .qs     (cfg_clk_div_qs)
+  );
+
+
+  //   F[dc_resn]: 30:27
+  prim_subreg #(
+    .DW      (4),
+    .SWACCESS("RW"),
+    .RESVAL  (4'h7)
+  ) u_cfg_dc_resn (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (cfg_dc_resn_we),
+    .wd     (cfg_dc_resn_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.cfg.dc_resn.q ),
+
+    // to register interface (read)
+    .qs     (cfg_dc_resn_qs)
+  );
+
+
+  //   F[cntr_en]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_cfg_cntr_en (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (cfg_cntr_en_we),
+    .wd     (cfg_cntr_en_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.cfg.cntr_en.q ),
+
+    // to register interface (read)
+    .qs     (cfg_cntr_en_qs)
+  );
+
+
+
+  // Subregister 0 of Multireg pwm_en
+  // R[pwm_en]: V(False)
+
+  // F[en_0]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_0_we),
+    .wd     (pwm_en_en_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[0].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_0_qs)
+  );
+
+
+  // F[en_1]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_1_we),
+    .wd     (pwm_en_en_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[1].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_1_qs)
+  );
+
+
+  // F[en_2]: 2:2
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_2_we),
+    .wd     (pwm_en_en_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[2].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_2_qs)
+  );
+
+
+  // F[en_3]: 3:3
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_3_we),
+    .wd     (pwm_en_en_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[3].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_3_qs)
+  );
+
+
+  // F[en_4]: 4:4
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_4_we),
+    .wd     (pwm_en_en_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[4].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_4_qs)
+  );
+
+
+  // F[en_5]: 5:5
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_en_en_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_en_en_5_we),
+    .wd     (pwm_en_en_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_en[5].q ),
+
+    // to register interface (read)
+    .qs     (pwm_en_en_5_qs)
+  );
+
+
+
+
+  // Subregister 0 of Multireg invert
+  // R[invert]: V(False)
+
+  // F[invert_0]: 0:0
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_0_we),
+    .wd     (invert_invert_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[0].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_0_qs)
+  );
+
+
+  // F[invert_1]: 1:1
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_1_we),
+    .wd     (invert_invert_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[1].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_1_qs)
+  );
+
+
+  // F[invert_2]: 2:2
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_2_we),
+    .wd     (invert_invert_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[2].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_2_qs)
+  );
+
+
+  // F[invert_3]: 3:3
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_3_we),
+    .wd     (invert_invert_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[3].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_3_qs)
+  );
+
+
+  // F[invert_4]: 4:4
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_4_we),
+    .wd     (invert_invert_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[4].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_4_qs)
+  );
+
+
+  // F[invert_5]: 5:5
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_invert_invert_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (invert_invert_5_we),
+    .wd     (invert_invert_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.invert[5].q ),
+
+    // to register interface (read)
+    .qs     (invert_invert_5_qs)
+  );
+
+
+
+
+  // Subregister 0 of Multireg pwm_param
+  // R[pwm_param_0]: V(False)
+
+  // F[phase_delay_0]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_0_phase_delay_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_0_phase_delay_0_we),
+    .wd     (pwm_param_0_phase_delay_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[0].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_0_phase_delay_0_qs)
+  );
+
+
+  // F[htbt_en_0]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_0_htbt_en_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_0_htbt_en_0_we),
+    .wd     (pwm_param_0_htbt_en_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[0].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_0_htbt_en_0_qs)
+  );
+
+
+  // F[blink_en_0]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_0_blink_en_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_0_blink_en_0_we),
+    .wd     (pwm_param_0_blink_en_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[0].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_0_blink_en_0_qs)
+  );
+
+
+  // Subregister 1 of Multireg pwm_param
+  // R[pwm_param_1]: V(False)
+
+  // F[phase_delay_1]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_1_phase_delay_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_1_phase_delay_1_we),
+    .wd     (pwm_param_1_phase_delay_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[1].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_1_phase_delay_1_qs)
+  );
+
+
+  // F[htbt_en_1]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_1_htbt_en_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_1_htbt_en_1_we),
+    .wd     (pwm_param_1_htbt_en_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[1].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_1_htbt_en_1_qs)
+  );
+
+
+  // F[blink_en_1]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_1_blink_en_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_1_blink_en_1_we),
+    .wd     (pwm_param_1_blink_en_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[1].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_1_blink_en_1_qs)
+  );
+
+
+  // Subregister 2 of Multireg pwm_param
+  // R[pwm_param_2]: V(False)
+
+  // F[phase_delay_2]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_2_phase_delay_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_2_phase_delay_2_we),
+    .wd     (pwm_param_2_phase_delay_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[2].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_2_phase_delay_2_qs)
+  );
+
+
+  // F[htbt_en_2]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_2_htbt_en_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_2_htbt_en_2_we),
+    .wd     (pwm_param_2_htbt_en_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[2].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_2_htbt_en_2_qs)
+  );
+
+
+  // F[blink_en_2]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_2_blink_en_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_2_blink_en_2_we),
+    .wd     (pwm_param_2_blink_en_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[2].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_2_blink_en_2_qs)
+  );
+
+
+  // Subregister 3 of Multireg pwm_param
+  // R[pwm_param_3]: V(False)
+
+  // F[phase_delay_3]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_3_phase_delay_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_3_phase_delay_3_we),
+    .wd     (pwm_param_3_phase_delay_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[3].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_3_phase_delay_3_qs)
+  );
+
+
+  // F[htbt_en_3]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_3_htbt_en_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_3_htbt_en_3_we),
+    .wd     (pwm_param_3_htbt_en_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[3].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_3_htbt_en_3_qs)
+  );
+
+
+  // F[blink_en_3]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_3_blink_en_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_3_blink_en_3_we),
+    .wd     (pwm_param_3_blink_en_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[3].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_3_blink_en_3_qs)
+  );
+
+
+  // Subregister 4 of Multireg pwm_param
+  // R[pwm_param_4]: V(False)
+
+  // F[phase_delay_4]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_4_phase_delay_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_4_phase_delay_4_we),
+    .wd     (pwm_param_4_phase_delay_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[4].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_4_phase_delay_4_qs)
+  );
+
+
+  // F[htbt_en_4]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_4_htbt_en_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_4_htbt_en_4_we),
+    .wd     (pwm_param_4_htbt_en_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[4].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_4_htbt_en_4_qs)
+  );
+
+
+  // F[blink_en_4]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_4_blink_en_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_4_blink_en_4_we),
+    .wd     (pwm_param_4_blink_en_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[4].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_4_blink_en_4_qs)
+  );
+
+
+  // Subregister 5 of Multireg pwm_param
+  // R[pwm_param_5]: V(False)
+
+  // F[phase_delay_5]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_pwm_param_5_phase_delay_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_5_phase_delay_5_we),
+    .wd     (pwm_param_5_phase_delay_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[5].phase_delay.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_5_phase_delay_5_qs)
+  );
+
+
+  // F[htbt_en_5]: 30:30
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_5_htbt_en_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_5_htbt_en_5_we),
+    .wd     (pwm_param_5_htbt_en_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[5].htbt_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_5_htbt_en_5_qs)
+  );
+
+
+  // F[blink_en_5]: 31:31
+  prim_subreg #(
+    .DW      (1),
+    .SWACCESS("RW"),
+    .RESVAL  (1'h0)
+  ) u_pwm_param_5_blink_en_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (pwm_param_5_blink_en_5_we),
+    .wd     (pwm_param_5_blink_en_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.pwm_param[5].blink_en.q ),
+
+    // to register interface (read)
+    .qs     (pwm_param_5_blink_en_5_qs)
+  );
+
+
+
+
+  // Subregister 0 of Multireg duty_cycle
+  // R[duty_cycle_0]: V(False)
+
+  // F[a_0]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_0_a_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_0_a_0_we),
+    .wd     (duty_cycle_0_a_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[0].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_0_a_0_qs)
+  );
+
+
+  // F[b_0]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_0_b_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_0_b_0_we),
+    .wd     (duty_cycle_0_b_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[0].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_0_b_0_qs)
+  );
+
+
+  // Subregister 1 of Multireg duty_cycle
+  // R[duty_cycle_1]: V(False)
+
+  // F[a_1]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_1_a_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_1_a_1_we),
+    .wd     (duty_cycle_1_a_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[1].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_1_a_1_qs)
+  );
+
+
+  // F[b_1]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_1_b_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_1_b_1_we),
+    .wd     (duty_cycle_1_b_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[1].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_1_b_1_qs)
+  );
+
+
+  // Subregister 2 of Multireg duty_cycle
+  // R[duty_cycle_2]: V(False)
+
+  // F[a_2]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_2_a_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_2_a_2_we),
+    .wd     (duty_cycle_2_a_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[2].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_2_a_2_qs)
+  );
+
+
+  // F[b_2]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_2_b_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_2_b_2_we),
+    .wd     (duty_cycle_2_b_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[2].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_2_b_2_qs)
+  );
+
+
+  // Subregister 3 of Multireg duty_cycle
+  // R[duty_cycle_3]: V(False)
+
+  // F[a_3]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_3_a_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_3_a_3_we),
+    .wd     (duty_cycle_3_a_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[3].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_3_a_3_qs)
+  );
+
+
+  // F[b_3]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_3_b_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_3_b_3_we),
+    .wd     (duty_cycle_3_b_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[3].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_3_b_3_qs)
+  );
+
+
+  // Subregister 4 of Multireg duty_cycle
+  // R[duty_cycle_4]: V(False)
+
+  // F[a_4]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_4_a_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_4_a_4_we),
+    .wd     (duty_cycle_4_a_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[4].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_4_a_4_qs)
+  );
+
+
+  // F[b_4]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_4_b_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_4_b_4_we),
+    .wd     (duty_cycle_4_b_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[4].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_4_b_4_qs)
+  );
+
+
+  // Subregister 5 of Multireg duty_cycle
+  // R[duty_cycle_5]: V(False)
+
+  // F[a_5]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_5_a_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_5_a_5_we),
+    .wd     (duty_cycle_5_a_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[5].a.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_5_a_5_qs)
+  );
+
+
+  // F[b_5]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h7fff)
+  ) u_duty_cycle_5_b_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (duty_cycle_5_b_5_we),
+    .wd     (duty_cycle_5_b_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.duty_cycle[5].b.q ),
+
+    // to register interface (read)
+    .qs     (duty_cycle_5_b_5_qs)
+  );
+
+
+
+
+  // Subregister 0 of Multireg blink_param
+  // R[blink_param_0]: V(False)
+
+  // F[x_0]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_0_x_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_0_x_0_we),
+    .wd     (blink_param_0_x_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[0].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_0_x_0_qs)
+  );
+
+
+  // F[y_0]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_0_y_0 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_0_y_0_we),
+    .wd     (blink_param_0_y_0_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[0].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_0_y_0_qs)
+  );
+
+
+  // Subregister 1 of Multireg blink_param
+  // R[blink_param_1]: V(False)
+
+  // F[x_1]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_1_x_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_1_x_1_we),
+    .wd     (blink_param_1_x_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[1].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_1_x_1_qs)
+  );
+
+
+  // F[y_1]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_1_y_1 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_1_y_1_we),
+    .wd     (blink_param_1_y_1_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[1].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_1_y_1_qs)
+  );
+
+
+  // Subregister 2 of Multireg blink_param
+  // R[blink_param_2]: V(False)
+
+  // F[x_2]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_2_x_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_2_x_2_we),
+    .wd     (blink_param_2_x_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[2].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_2_x_2_qs)
+  );
+
+
+  // F[y_2]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_2_y_2 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_2_y_2_we),
+    .wd     (blink_param_2_y_2_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[2].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_2_y_2_qs)
+  );
+
+
+  // Subregister 3 of Multireg blink_param
+  // R[blink_param_3]: V(False)
+
+  // F[x_3]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_3_x_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_3_x_3_we),
+    .wd     (blink_param_3_x_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[3].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_3_x_3_qs)
+  );
+
+
+  // F[y_3]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_3_y_3 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_3_y_3_we),
+    .wd     (blink_param_3_y_3_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[3].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_3_y_3_qs)
+  );
+
+
+  // Subregister 4 of Multireg blink_param
+  // R[blink_param_4]: V(False)
+
+  // F[x_4]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_4_x_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_4_x_4_we),
+    .wd     (blink_param_4_x_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[4].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_4_x_4_qs)
+  );
+
+
+  // F[y_4]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_4_y_4 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_4_y_4_we),
+    .wd     (blink_param_4_y_4_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[4].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_4_y_4_qs)
+  );
+
+
+  // Subregister 5 of Multireg blink_param
+  // R[blink_param_5]: V(False)
+
+  // F[x_5]: 15:0
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_5_x_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_5_x_5_we),
+    .wd     (blink_param_5_x_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[5].x.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_5_x_5_qs)
+  );
+
+
+  // F[y_5]: 31:16
+  prim_subreg #(
+    .DW      (16),
+    .SWACCESS("RW"),
+    .RESVAL  (16'h0)
+  ) u_blink_param_5_y_5 (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    // from register interface
+    .we     (blink_param_5_y_5_we),
+    .wd     (blink_param_5_y_5_wd),
+
+    // from internal hardware
+    .de     (1'b0),
+    .d      ('0  ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (reg2hw.blink_param[5].y.q ),
+
+    // to register interface (read)
+    .qs     (blink_param_5_y_5_qs)
+  );
+
+
+
+
+
+  logic [21:0] addr_hit;
+  always_comb begin
+    addr_hit = '0;
+    addr_hit[ 0] = (reg_addr == PWM_REGEN_OFFSET);
+    addr_hit[ 1] = (reg_addr == PWM_CFG_OFFSET);
+    addr_hit[ 2] = (reg_addr == PWM_PWM_EN_OFFSET);
+    addr_hit[ 3] = (reg_addr == PWM_INVERT_OFFSET);
+    addr_hit[ 4] = (reg_addr == PWM_PWM_PARAM_0_OFFSET);
+    addr_hit[ 5] = (reg_addr == PWM_PWM_PARAM_1_OFFSET);
+    addr_hit[ 6] = (reg_addr == PWM_PWM_PARAM_2_OFFSET);
+    addr_hit[ 7] = (reg_addr == PWM_PWM_PARAM_3_OFFSET);
+    addr_hit[ 8] = (reg_addr == PWM_PWM_PARAM_4_OFFSET);
+    addr_hit[ 9] = (reg_addr == PWM_PWM_PARAM_5_OFFSET);
+    addr_hit[10] = (reg_addr == PWM_DUTY_CYCLE_0_OFFSET);
+    addr_hit[11] = (reg_addr == PWM_DUTY_CYCLE_1_OFFSET);
+    addr_hit[12] = (reg_addr == PWM_DUTY_CYCLE_2_OFFSET);
+    addr_hit[13] = (reg_addr == PWM_DUTY_CYCLE_3_OFFSET);
+    addr_hit[14] = (reg_addr == PWM_DUTY_CYCLE_4_OFFSET);
+    addr_hit[15] = (reg_addr == PWM_DUTY_CYCLE_5_OFFSET);
+    addr_hit[16] = (reg_addr == PWM_BLINK_PARAM_0_OFFSET);
+    addr_hit[17] = (reg_addr == PWM_BLINK_PARAM_1_OFFSET);
+    addr_hit[18] = (reg_addr == PWM_BLINK_PARAM_2_OFFSET);
+    addr_hit[19] = (reg_addr == PWM_BLINK_PARAM_3_OFFSET);
+    addr_hit[20] = (reg_addr == PWM_BLINK_PARAM_4_OFFSET);
+    addr_hit[21] = (reg_addr == PWM_BLINK_PARAM_5_OFFSET);
+  end
+
+  assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
+
+  // Check sub-word write is permitted
+  always_comb begin
+    wr_err = 1'b0;
+    if (addr_hit[ 0] && reg_we && (PWM_PERMIT[ 0] != (PWM_PERMIT[ 0] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 1] && reg_we && (PWM_PERMIT[ 1] != (PWM_PERMIT[ 1] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 2] && reg_we && (PWM_PERMIT[ 2] != (PWM_PERMIT[ 2] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 3] && reg_we && (PWM_PERMIT[ 3] != (PWM_PERMIT[ 3] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 4] && reg_we && (PWM_PERMIT[ 4] != (PWM_PERMIT[ 4] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 5] && reg_we && (PWM_PERMIT[ 5] != (PWM_PERMIT[ 5] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 6] && reg_we && (PWM_PERMIT[ 6] != (PWM_PERMIT[ 6] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 7] && reg_we && (PWM_PERMIT[ 7] != (PWM_PERMIT[ 7] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 8] && reg_we && (PWM_PERMIT[ 8] != (PWM_PERMIT[ 8] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[ 9] && reg_we && (PWM_PERMIT[ 9] != (PWM_PERMIT[ 9] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[10] && reg_we && (PWM_PERMIT[10] != (PWM_PERMIT[10] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[11] && reg_we && (PWM_PERMIT[11] != (PWM_PERMIT[11] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[12] && reg_we && (PWM_PERMIT[12] != (PWM_PERMIT[12] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[13] && reg_we && (PWM_PERMIT[13] != (PWM_PERMIT[13] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[14] && reg_we && (PWM_PERMIT[14] != (PWM_PERMIT[14] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[15] && reg_we && (PWM_PERMIT[15] != (PWM_PERMIT[15] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[16] && reg_we && (PWM_PERMIT[16] != (PWM_PERMIT[16] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[17] && reg_we && (PWM_PERMIT[17] != (PWM_PERMIT[17] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[18] && reg_we && (PWM_PERMIT[18] != (PWM_PERMIT[18] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[19] && reg_we && (PWM_PERMIT[19] != (PWM_PERMIT[19] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[20] && reg_we && (PWM_PERMIT[20] != (PWM_PERMIT[20] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[21] && reg_we && (PWM_PERMIT[21] != (PWM_PERMIT[21] & reg_be))) wr_err = 1'b1 ;
+  end
+
+  assign regen_we = addr_hit[0] & reg_we & !reg_error;
+  assign regen_wd = reg_wdata[0];
+
+  assign cfg_clk_div_we = addr_hit[1] & reg_we & !reg_error;
+  assign cfg_clk_div_wd = reg_wdata[26:0];
+
+  assign cfg_dc_resn_we = addr_hit[1] & reg_we & !reg_error;
+  assign cfg_dc_resn_wd = reg_wdata[30:27];
+
+  assign cfg_cntr_en_we = addr_hit[1] & reg_we & !reg_error;
+  assign cfg_cntr_en_wd = reg_wdata[31];
+
+  assign pwm_en_en_0_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_0_wd = reg_wdata[0];
+
+  assign pwm_en_en_1_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_1_wd = reg_wdata[1];
+
+  assign pwm_en_en_2_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_2_wd = reg_wdata[2];
+
+  assign pwm_en_en_3_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_3_wd = reg_wdata[3];
+
+  assign pwm_en_en_4_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_4_wd = reg_wdata[4];
+
+  assign pwm_en_en_5_we = addr_hit[2] & reg_we & !reg_error;
+  assign pwm_en_en_5_wd = reg_wdata[5];
+
+  assign invert_invert_0_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_0_wd = reg_wdata[0];
+
+  assign invert_invert_1_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_1_wd = reg_wdata[1];
+
+  assign invert_invert_2_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_2_wd = reg_wdata[2];
+
+  assign invert_invert_3_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_3_wd = reg_wdata[3];
+
+  assign invert_invert_4_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_4_wd = reg_wdata[4];
+
+  assign invert_invert_5_we = addr_hit[3] & reg_we & !reg_error;
+  assign invert_invert_5_wd = reg_wdata[5];
+
+  assign pwm_param_0_phase_delay_0_we = addr_hit[4] & reg_we & !reg_error;
+  assign pwm_param_0_phase_delay_0_wd = reg_wdata[15:0];
+
+  assign pwm_param_0_htbt_en_0_we = addr_hit[4] & reg_we & !reg_error;
+  assign pwm_param_0_htbt_en_0_wd = reg_wdata[30];
+
+  assign pwm_param_0_blink_en_0_we = addr_hit[4] & reg_we & !reg_error;
+  assign pwm_param_0_blink_en_0_wd = reg_wdata[31];
+
+  assign pwm_param_1_phase_delay_1_we = addr_hit[5] & reg_we & !reg_error;
+  assign pwm_param_1_phase_delay_1_wd = reg_wdata[15:0];
+
+  assign pwm_param_1_htbt_en_1_we = addr_hit[5] & reg_we & !reg_error;
+  assign pwm_param_1_htbt_en_1_wd = reg_wdata[30];
+
+  assign pwm_param_1_blink_en_1_we = addr_hit[5] & reg_we & !reg_error;
+  assign pwm_param_1_blink_en_1_wd = reg_wdata[31];
+
+  assign pwm_param_2_phase_delay_2_we = addr_hit[6] & reg_we & !reg_error;
+  assign pwm_param_2_phase_delay_2_wd = reg_wdata[15:0];
+
+  assign pwm_param_2_htbt_en_2_we = addr_hit[6] & reg_we & !reg_error;
+  assign pwm_param_2_htbt_en_2_wd = reg_wdata[30];
+
+  assign pwm_param_2_blink_en_2_we = addr_hit[6] & reg_we & !reg_error;
+  assign pwm_param_2_blink_en_2_wd = reg_wdata[31];
+
+  assign pwm_param_3_phase_delay_3_we = addr_hit[7] & reg_we & !reg_error;
+  assign pwm_param_3_phase_delay_3_wd = reg_wdata[15:0];
+
+  assign pwm_param_3_htbt_en_3_we = addr_hit[7] & reg_we & !reg_error;
+  assign pwm_param_3_htbt_en_3_wd = reg_wdata[30];
+
+  assign pwm_param_3_blink_en_3_we = addr_hit[7] & reg_we & !reg_error;
+  assign pwm_param_3_blink_en_3_wd = reg_wdata[31];
+
+  assign pwm_param_4_phase_delay_4_we = addr_hit[8] & reg_we & !reg_error;
+  assign pwm_param_4_phase_delay_4_wd = reg_wdata[15:0];
+
+  assign pwm_param_4_htbt_en_4_we = addr_hit[8] & reg_we & !reg_error;
+  assign pwm_param_4_htbt_en_4_wd = reg_wdata[30];
+
+  assign pwm_param_4_blink_en_4_we = addr_hit[8] & reg_we & !reg_error;
+  assign pwm_param_4_blink_en_4_wd = reg_wdata[31];
+
+  assign pwm_param_5_phase_delay_5_we = addr_hit[9] & reg_we & !reg_error;
+  assign pwm_param_5_phase_delay_5_wd = reg_wdata[15:0];
+
+  assign pwm_param_5_htbt_en_5_we = addr_hit[9] & reg_we & !reg_error;
+  assign pwm_param_5_htbt_en_5_wd = reg_wdata[30];
+
+  assign pwm_param_5_blink_en_5_we = addr_hit[9] & reg_we & !reg_error;
+  assign pwm_param_5_blink_en_5_wd = reg_wdata[31];
+
+  assign duty_cycle_0_a_0_we = addr_hit[10] & reg_we & !reg_error;
+  assign duty_cycle_0_a_0_wd = reg_wdata[15:0];
+
+  assign duty_cycle_0_b_0_we = addr_hit[10] & reg_we & !reg_error;
+  assign duty_cycle_0_b_0_wd = reg_wdata[31:16];
+
+  assign duty_cycle_1_a_1_we = addr_hit[11] & reg_we & !reg_error;
+  assign duty_cycle_1_a_1_wd = reg_wdata[15:0];
+
+  assign duty_cycle_1_b_1_we = addr_hit[11] & reg_we & !reg_error;
+  assign duty_cycle_1_b_1_wd = reg_wdata[31:16];
+
+  assign duty_cycle_2_a_2_we = addr_hit[12] & reg_we & !reg_error;
+  assign duty_cycle_2_a_2_wd = reg_wdata[15:0];
+
+  assign duty_cycle_2_b_2_we = addr_hit[12] & reg_we & !reg_error;
+  assign duty_cycle_2_b_2_wd = reg_wdata[31:16];
+
+  assign duty_cycle_3_a_3_we = addr_hit[13] & reg_we & !reg_error;
+  assign duty_cycle_3_a_3_wd = reg_wdata[15:0];
+
+  assign duty_cycle_3_b_3_we = addr_hit[13] & reg_we & !reg_error;
+  assign duty_cycle_3_b_3_wd = reg_wdata[31:16];
+
+  assign duty_cycle_4_a_4_we = addr_hit[14] & reg_we & !reg_error;
+  assign duty_cycle_4_a_4_wd = reg_wdata[15:0];
+
+  assign duty_cycle_4_b_4_we = addr_hit[14] & reg_we & !reg_error;
+  assign duty_cycle_4_b_4_wd = reg_wdata[31:16];
+
+  assign duty_cycle_5_a_5_we = addr_hit[15] & reg_we & !reg_error;
+  assign duty_cycle_5_a_5_wd = reg_wdata[15:0];
+
+  assign duty_cycle_5_b_5_we = addr_hit[15] & reg_we & !reg_error;
+  assign duty_cycle_5_b_5_wd = reg_wdata[31:16];
+
+  assign blink_param_0_x_0_we = addr_hit[16] & reg_we & !reg_error;
+  assign blink_param_0_x_0_wd = reg_wdata[15:0];
+
+  assign blink_param_0_y_0_we = addr_hit[16] & reg_we & !reg_error;
+  assign blink_param_0_y_0_wd = reg_wdata[31:16];
+
+  assign blink_param_1_x_1_we = addr_hit[17] & reg_we & !reg_error;
+  assign blink_param_1_x_1_wd = reg_wdata[15:0];
+
+  assign blink_param_1_y_1_we = addr_hit[17] & reg_we & !reg_error;
+  assign blink_param_1_y_1_wd = reg_wdata[31:16];
+
+  assign blink_param_2_x_2_we = addr_hit[18] & reg_we & !reg_error;
+  assign blink_param_2_x_2_wd = reg_wdata[15:0];
+
+  assign blink_param_2_y_2_we = addr_hit[18] & reg_we & !reg_error;
+  assign blink_param_2_y_2_wd = reg_wdata[31:16];
+
+  assign blink_param_3_x_3_we = addr_hit[19] & reg_we & !reg_error;
+  assign blink_param_3_x_3_wd = reg_wdata[15:0];
+
+  assign blink_param_3_y_3_we = addr_hit[19] & reg_we & !reg_error;
+  assign blink_param_3_y_3_wd = reg_wdata[31:16];
+
+  assign blink_param_4_x_4_we = addr_hit[20] & reg_we & !reg_error;
+  assign blink_param_4_x_4_wd = reg_wdata[15:0];
+
+  assign blink_param_4_y_4_we = addr_hit[20] & reg_we & !reg_error;
+  assign blink_param_4_y_4_wd = reg_wdata[31:16];
+
+  assign blink_param_5_x_5_we = addr_hit[21] & reg_we & !reg_error;
+  assign blink_param_5_x_5_wd = reg_wdata[15:0];
+
+  assign blink_param_5_y_5_we = addr_hit[21] & reg_we & !reg_error;
+  assign blink_param_5_y_5_wd = reg_wdata[31:16];
+
+  // Read data return
+  always_comb begin
+    reg_rdata_next = '0;
+    unique case (1'b1)
+      addr_hit[0]: begin
+        reg_rdata_next[0] = regen_qs;
+      end
+
+      addr_hit[1]: begin
+        reg_rdata_next[26:0] = cfg_clk_div_qs;
+        reg_rdata_next[30:27] = cfg_dc_resn_qs;
+        reg_rdata_next[31] = cfg_cntr_en_qs;
+      end
+
+      addr_hit[2]: begin
+        reg_rdata_next[0] = pwm_en_en_0_qs;
+        reg_rdata_next[1] = pwm_en_en_1_qs;
+        reg_rdata_next[2] = pwm_en_en_2_qs;
+        reg_rdata_next[3] = pwm_en_en_3_qs;
+        reg_rdata_next[4] = pwm_en_en_4_qs;
+        reg_rdata_next[5] = pwm_en_en_5_qs;
+      end
+
+      addr_hit[3]: begin
+        reg_rdata_next[0] = invert_invert_0_qs;
+        reg_rdata_next[1] = invert_invert_1_qs;
+        reg_rdata_next[2] = invert_invert_2_qs;
+        reg_rdata_next[3] = invert_invert_3_qs;
+        reg_rdata_next[4] = invert_invert_4_qs;
+        reg_rdata_next[5] = invert_invert_5_qs;
+      end
+
+      addr_hit[4]: begin
+        reg_rdata_next[15:0] = pwm_param_0_phase_delay_0_qs;
+        reg_rdata_next[30] = pwm_param_0_htbt_en_0_qs;
+        reg_rdata_next[31] = pwm_param_0_blink_en_0_qs;
+      end
+
+      addr_hit[5]: begin
+        reg_rdata_next[15:0] = pwm_param_1_phase_delay_1_qs;
+        reg_rdata_next[30] = pwm_param_1_htbt_en_1_qs;
+        reg_rdata_next[31] = pwm_param_1_blink_en_1_qs;
+      end
+
+      addr_hit[6]: begin
+        reg_rdata_next[15:0] = pwm_param_2_phase_delay_2_qs;
+        reg_rdata_next[30] = pwm_param_2_htbt_en_2_qs;
+        reg_rdata_next[31] = pwm_param_2_blink_en_2_qs;
+      end
+
+      addr_hit[7]: begin
+        reg_rdata_next[15:0] = pwm_param_3_phase_delay_3_qs;
+        reg_rdata_next[30] = pwm_param_3_htbt_en_3_qs;
+        reg_rdata_next[31] = pwm_param_3_blink_en_3_qs;
+      end
+
+      addr_hit[8]: begin
+        reg_rdata_next[15:0] = pwm_param_4_phase_delay_4_qs;
+        reg_rdata_next[30] = pwm_param_4_htbt_en_4_qs;
+        reg_rdata_next[31] = pwm_param_4_blink_en_4_qs;
+      end
+
+      addr_hit[9]: begin
+        reg_rdata_next[15:0] = pwm_param_5_phase_delay_5_qs;
+        reg_rdata_next[30] = pwm_param_5_htbt_en_5_qs;
+        reg_rdata_next[31] = pwm_param_5_blink_en_5_qs;
+      end
+
+      addr_hit[10]: begin
+        reg_rdata_next[15:0] = duty_cycle_0_a_0_qs;
+        reg_rdata_next[31:16] = duty_cycle_0_b_0_qs;
+      end
+
+      addr_hit[11]: begin
+        reg_rdata_next[15:0] = duty_cycle_1_a_1_qs;
+        reg_rdata_next[31:16] = duty_cycle_1_b_1_qs;
+      end
+
+      addr_hit[12]: begin
+        reg_rdata_next[15:0] = duty_cycle_2_a_2_qs;
+        reg_rdata_next[31:16] = duty_cycle_2_b_2_qs;
+      end
+
+      addr_hit[13]: begin
+        reg_rdata_next[15:0] = duty_cycle_3_a_3_qs;
+        reg_rdata_next[31:16] = duty_cycle_3_b_3_qs;
+      end
+
+      addr_hit[14]: begin
+        reg_rdata_next[15:0] = duty_cycle_4_a_4_qs;
+        reg_rdata_next[31:16] = duty_cycle_4_b_4_qs;
+      end
+
+      addr_hit[15]: begin
+        reg_rdata_next[15:0] = duty_cycle_5_a_5_qs;
+        reg_rdata_next[31:16] = duty_cycle_5_b_5_qs;
+      end
+
+      addr_hit[16]: begin
+        reg_rdata_next[15:0] = blink_param_0_x_0_qs;
+        reg_rdata_next[31:16] = blink_param_0_y_0_qs;
+      end
+
+      addr_hit[17]: begin
+        reg_rdata_next[15:0] = blink_param_1_x_1_qs;
+        reg_rdata_next[31:16] = blink_param_1_y_1_qs;
+      end
+
+      addr_hit[18]: begin
+        reg_rdata_next[15:0] = blink_param_2_x_2_qs;
+        reg_rdata_next[31:16] = blink_param_2_y_2_qs;
+      end
+
+      addr_hit[19]: begin
+        reg_rdata_next[15:0] = blink_param_3_x_3_qs;
+        reg_rdata_next[31:16] = blink_param_3_y_3_qs;
+      end
+
+      addr_hit[20]: begin
+        reg_rdata_next[15:0] = blink_param_4_x_4_qs;
+        reg_rdata_next[31:16] = blink_param_4_y_4_qs;
+      end
+
+      addr_hit[21]: begin
+        reg_rdata_next[15:0] = blink_param_5_x_5_qs;
+        reg_rdata_next[31:16] = blink_param_5_y_5_qs;
+      end
+
+      default: begin
+        reg_rdata_next = '1;
+      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)
+  `ASSERT_PULSE(rePulse, reg_re)
+
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+  // this is formulated as an assumption such that the FPV testbenches do disprove this
+  // property by mistake
+  //`ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.chk_en == tlul_pkg::CheckDis)
+
+endmodule