[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