[lc_ctrl] Add initial markdown shell and hjson

This allows us to reference and link to life-cycle collateral.

Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
new file mode 100644
index 0000000..36a78ef
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.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
+//
+
+package lc_ctrl_pkg;
+
+  /////////////////////////////////
+  // General Typedefs and Params //
+  /////////////////////////////////
+
+  parameter int LcValueWidth = 16;
+  parameter int LcTokenWidth = 128;
+  parameter int NumLcStateValues = 12;
+  parameter int LcStateWidth = NumLcStateValues * LcValueWidth;
+  parameter int NumLcCountValues = 32;
+
+  typedef enum logic [LcValueWidth-1:0] {
+    Blk = 16'h0000, // blank
+    Set = 16'hF5FA  // programmed
+  } lc_value_e;
+
+  typedef enum logic [LcStateWidth-1:0] {
+    // Halfword idx   :  11 | 10 |  9 |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 |  0
+    LcStRaw           = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk},
+    LcStTestUnlocked0 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set},
+    LcStTestLocked0   = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set},
+    LcStTestUnlocked1 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set},
+    LcStTestLocked1   = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set},
+    LcStTestUnlocked2 = {Blk, Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set},
+    LcStTestLocked2   = {Blk, Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set},
+    LcStTestUnlocked3 = {Blk, Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
+    LcStDev           = {Blk, Blk, Blk, Blk, Set, Set, Set, Set, Set, Set, Set, Set},
+    LcStProd          = {Blk, Blk, Blk, Set, Blk, Set, Set, Set, Set, Set, Set, Set},
+    LcStProdEnd       = {Blk, Blk, Set, Blk, Blk, Set, Set, Set, Set, Set, Set, Set},
+    LcStRma           = {Set, Set, Blk, Set, Set, Set, Set, Set, Set, Set, Set, Set},
+    LcStScrap         = {Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set, Set}
+  } lc_state_e;
+
+  typedef lc_value_e [NumLcCountValues-1:0] lc_cnt_t;
+
+  ////////////////////////////////
+  // Typedefs for LC Interfaces //
+  ////////////////////////////////
+
+  typedef enum logic [2:0] {
+    On  = 3'b101,
+    Off = 3'b000
+  } lc_tx_e;
+
+  typedef struct packed {
+    lc_tx_e state;
+  } lc_tx_t;
+
+
+endpackage : lc_ctrl_pkg
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.sv
new file mode 100644
index 0000000..696b4bd
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_pkg.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
+//
+// Register Package auto-generated by `reggen` containing data structure
+
+package lc_ctrl_reg_pkg;
+
+  ////////////////////////////
+  // Typedefs for registers //
+  ////////////////////////////
+
+  typedef struct packed {
+    logic [1:0]  d;
+    logic        de;
+  } lc_ctrl_hw2reg_status_reg_t;
+
+  typedef struct packed {
+    logic [1:0]  d;
+    logic        de;
+  } lc_ctrl_hw2reg_ctrl_reg_t;
+
+
+  ///////////////////////////////////////
+  // Register to internal design logic //
+  ///////////////////////////////////////
+
+  ///////////////////////////////////////
+  // Internal design logic to register //
+  ///////////////////////////////////////
+  typedef struct packed {
+    lc_ctrl_hw2reg_status_reg_t status; // [5:6]
+    lc_ctrl_hw2reg_ctrl_reg_t ctrl; // [5:6]
+  } lc_ctrl_hw2reg_t;
+
+  // Register Address
+  parameter logic [2:0] LC_CTRL_STATUS_OFFSET = 3'h 0;
+  parameter logic [2:0] LC_CTRL_CTRL_OFFSET = 3'h 4;
+
+
+  // Register Index
+  typedef enum int {
+    LC_CTRL_STATUS,
+    LC_CTRL_CTRL
+  } lc_ctrl_id_e;
+
+  // Register width information to check illegal writes
+  parameter logic [3:0] LC_CTRL_PERMIT [2] = '{
+    4'b 0001, // index[0] LC_CTRL_STATUS
+    4'b 0001  // index[1] LC_CTRL_CTRL
+  };
+endpackage
+
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
new file mode 100644
index 0000000..40dcded
--- /dev/null
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_reg_top.sv
@@ -0,0 +1,179 @@
+// 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 lc_ctrl_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
+  input  lc_ctrl_reg_pkg::lc_ctrl_hw2reg_t hw2reg, // Read
+
+  // Config
+  input devmode_i // If 1, explicit error return for unmapped register access
+);
+
+  import lc_ctrl_reg_pkg::* ;
+
+  localparam int AW = 3;
+  localparam int DW = 32;
+  localparam int DBW = DW/8;                    // Byte Width
+
+  // register signals
+  logic           reg_we;
+  logic           reg_re;
+  logic [AW-1:0]  reg_addr;
+  logic [DW-1:0]  reg_wdata;
+  logic [DBW-1:0] reg_be;
+  logic [DW-1:0]  reg_rdata;
+  logic           reg_error;
+
+  logic          addrmiss, wr_err;
+
+  logic [DW-1:0] reg_rdata_next;
+
+  tlul_pkg::tl_h2d_t tl_reg_h2d;
+  tlul_pkg::tl_d2h_t tl_reg_d2h;
+
+  assign tl_reg_h2d = tl_i;
+  assign tl_o       = tl_reg_d2h;
+
+  tlul_adapter_reg #(
+    .RegAw(AW),
+    .RegDw(DW)
+  ) u_reg_if (
+    .clk_i,
+    .rst_ni,
+
+    .tl_i (tl_reg_h2d),
+    .tl_o (tl_reg_d2h),
+
+    .we_o    (reg_we),
+    .re_o    (reg_re),
+    .addr_o  (reg_addr),
+    .wdata_o (reg_wdata),
+    .be_o    (reg_be),
+    .rdata_i (reg_rdata),
+    .error_i (reg_error)
+  );
+
+  assign reg_rdata = reg_rdata_next ;
+  assign reg_error = (devmode_i & addrmiss) | wr_err ;
+
+  // Define SW related signals
+  // Format: <reg>_<field>_{wd|we|qs}
+  //        or <reg>_{wd|we|qs} if field == 1 or 0
+  logic [1:0] status_qs;
+  logic [1:0] ctrl_qs;
+
+  // Register instances
+  // R[status]: V(False)
+
+  prim_subreg #(
+    .DW      (2),
+    .SWACCESS("RO"),
+    .RESVAL  (2'h0)
+  ) u_status (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    .we     (1'b0),
+    .wd     ('0  ),
+
+    // from internal hardware
+    .de     (hw2reg.status.de),
+    .d      (hw2reg.status.d ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (status_qs)
+  );
+
+
+  // R[ctrl]: V(False)
+
+  prim_subreg #(
+    .DW      (2),
+    .SWACCESS("RO"),
+    .RESVAL  (2'h0)
+  ) u_ctrl (
+    .clk_i   (clk_i    ),
+    .rst_ni  (rst_ni  ),
+
+    .we     (1'b0),
+    .wd     ('0  ),
+
+    // from internal hardware
+    .de     (hw2reg.ctrl.de),
+    .d      (hw2reg.ctrl.d ),
+
+    // to internal hardware
+    .qe     (),
+    .q      (),
+
+    // to register interface (read)
+    .qs     (ctrl_qs)
+  );
+
+
+
+
+  logic [1:0] addr_hit;
+  always_comb begin
+    addr_hit = '0;
+    addr_hit[0] = (reg_addr == LC_CTRL_STATUS_OFFSET);
+    addr_hit[1] = (reg_addr == LC_CTRL_CTRL_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 && (LC_CTRL_PERMIT[0] != (LC_CTRL_PERMIT[0] & reg_be))) wr_err = 1'b1 ;
+    if (addr_hit[1] && reg_we && (LC_CTRL_PERMIT[1] != (LC_CTRL_PERMIT[1] & reg_be))) wr_err = 1'b1 ;
+  end
+
+
+
+  // Read data return
+  always_comb begin
+    reg_rdata_next = '0;
+    unique case (1'b1)
+      addr_hit[0]: begin
+        reg_rdata_next[1:0] = status_qs;
+      end
+
+      addr_hit[1]: begin
+        reg_rdata_next[1:0] = ctrl_qs;
+      end
+
+      default: begin
+        reg_rdata_next = '1;
+      end
+    endcase
+  end
+
+  // Assertions for Register Interface
+  `ASSERT_PULSE(wePulse, reg_we)
+  `ASSERT_PULSE(rePulse, reg_re)
+
+  `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid)
+
+  `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit))
+
+  // this is formulated as an assumption such that the FPV testbenches do disprove this
+  // property by mistake
+  `ASSUME(reqParity, tl_reg_h2d.a_valid |-> tl_reg_h2d.a_user.parity_en == 1'b0)
+
+endmodule