[top] Add power attribute to the design
- split reset manager outputs into always-on and non-always-on
- add domain attribute to modules, memories and xbars
- do appropriate checks for power domain
- create appropriate top level paths when referencing reset
Signed-off-by: Timothy Chen <timothytim@google.com>
[util] typo fixes
Signed-off-by: Timothy Chen <timothytim@google.com>
[top] updates to tie off unused resets
Signed-off-by: Timothy Chen <timothytim@google.com>
[util] minor cleanup
Signed-off-by: Timothy Chen <timothytim@google.com>
diff --git a/hw/ip/rstmgr/data/rstmgr.sv.tpl b/hw/ip/rstmgr/data/rstmgr.sv.tpl
index 441e591..5853f19 100644
--- a/hw/ip/rstmgr/data/rstmgr.sv.tpl
+++ b/hw/ip/rstmgr/data/rstmgr.sv.tpl
@@ -51,23 +51,32 @@
// receive POR and stretch
// The por is at first stretched and synced on clk_aon
// The rst_ni and pok_i input will be changed once AST is integrated
- logic rst_por_aon_n;
- rstmgr_por u_rst_por_aon (
- .clk_i(clk_aon_i),
- .rst_ni(ast_i.aon_pok),
- .scan_rst_ni,
- .scanmode_i,
- .rst_no(rst_por_aon_n)
- );
+ logic [PowerDomains-1:0] rst_por_aon_n;
- prim_clock_mux2 #(
- .NoFpgaBufG(1'b1)
- ) u_rst_por_aon_n_mux (
- .clk0_i(rst_por_aon_n),
- .clk1_i(scan_rst_ni),
- .sel_i(scanmode_i),
- .clk_o(resets_o.rst_por_aon_n)
- );
+ for (genvar i = 0; i < PowerDomains; i++) begin : gen_rst_por_aon
+ if (i == DomainAonSel) begin : gen_rst_por_aon_normal
+ rstmgr_por u_rst_por_aon (
+ .clk_i(clk_aon_i),
+ .rst_ni(ast_i.aon_pok),
+ .scan_rst_ni,
+ .scanmode_i,
+ .rst_no(rst_por_aon_n[i])
+ );
+
+ prim_clock_mux2 #(
+ .NoFpgaBufG(1'b1)
+ ) u_rst_por_aon_n_mux (
+ .clk0_i(rst_por_aon_n[i]),
+ .clk1_i(scan_rst_ni),
+ .sel_i(scanmode_i),
+ .clk_o(resets_o.rst_por_aon_n[i])
+ );
+ end else begin : gen_rst_por_aon_tieoff
+ assign rst_por_aon_n[i] = 1'b0;
+ assign resets_o.rst_por_aon_n[i] = rst_por_aon_n[i];
+ end
+ end
+
////////////////////////////////////////////////////
// Register Interface //
@@ -75,7 +84,7 @@
// local_rst_n is the reset used by the rstmgr for its internal logic
logic local_rst_n;
- assign local_rst_n = resets_o.rst_por_io_div2_n;
+ assign local_rst_n = resets_o.rst_por_io_div2_n[DomainAonSel];
rstmgr_reg_pkg::rstmgr_reg2hw_t reg2hw;
rstmgr_reg_pkg::rstmgr_hw2reg_t hw2reg;
@@ -176,37 +185,43 @@
// leaf reset in the system //
// These should all be generated //
////////////////////////////////////////////////////
+ // To simplify generation, each reset generates all associated power domain outputs.
+ // If a reset does not support a particular power domain, that reset is always hard-wired to 0.
% for rst in leaf_rsts:
- logic rst_${rst['name']}_n;
-
+ logic [PowerDomains-1:0] rst_${rst['name']}_n;
+ % for domain in power_domains:
+ % if domain in rst['domains']:
prim_flop_2sync #(
.Width(1),
.ResetValue('0)
- ) u_${rst['name']} (
+ ) u_${domain.lower()}_${rst['name']} (
.clk_i(clk_${rst['clk']}_i),
- % if "domain" in rst:
- .rst_ni(rst_${rst['parent']}_n[${rst['domain']}]),
- % else:
- .rst_ni(rst_${rst['parent']}_n),
- % endif
- % if "sw" in rst:
+ .rst_ni(rst_${rst['parent']}_n[Domain${domain}Sel]),
+ % if "sw" in rst:
.d_i(sw_rst_ctrl_n[${rst['name'].upper()}]),
- % else:
+ % else:
.d_i(1'b1),
- % endif
- .q_o(rst_${rst['name']}_n)
+ % endif
+ .q_o(rst_${rst['name']}_n[Domain${domain}Sel])
);
prim_clock_mux2 #(
.NoFpgaBufG(1'b1)
- ) u_${rst['name']}_mux (
- .clk0_i(rst_${rst['name']}_n),
+ ) u_${domain.lower()}_${rst['name']}_mux (
+ .clk0_i(rst_${rst['name']}_n[Domain${domain}Sel]),
.clk1_i(scan_rst_ni),
.sel_i(scanmode_i),
- .clk_o(resets_o.rst_${rst['name']}_n)
+ .clk_o(resets_o.rst_${rst['name']}_n[Domain${domain}Sel])
);
+ % else:
+ assign rst_${rst['name']}_n[Domain${domain}Sel] = 1'b0;
+ assign resets_o.rst_${rst['name']}_n[Domain${domain}Sel] = rst_${rst['name']}_n[Domain${domain}Sel];
+
+
+ % endif
+ % endfor
% endfor
////////////////////////////////////////////////////
diff --git a/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl b/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
index 538c5a1..0f6c4a3 100644
--- a/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
+++ b/hw/ip/rstmgr/data/rstmgr_pkg.sv.tpl
@@ -8,14 +8,13 @@
package rstmgr_pkg;
- // global constants
- parameter int ALWAYS_ON_SEL = pwrmgr_pkg::ALWAYS_ON_DOMAIN;
+ // Power domain parameters
+ parameter int PowerDomains = ${len(power_domains)};
+ % for power_domain in power_domains:
+ parameter int Domain${power_domain}Sel = ${loop.index};
+ % endfor
- // params that reference pwrmgr, should be replaced once pwrmgr is merged
- parameter int PowerDomains = pwrmgr_pkg::PowerDomains;
- //parameter int HwResetReqs = pwrmgr_pkg::NumRstReqs;
-
- // calculated domains
+ // Number of non-always-on domains
parameter int OffDomains = PowerDomains-1;
// positions of software controllable reset bits
@@ -37,7 +36,7 @@
// This should be templatized and generated
typedef struct packed {
% for rst in output_rsts:
- logic rst_${rst['name']}_n;
+ logic [PowerDomains-1:0] rst_${rst['name']}_n;
% endfor
} rstmgr_out_t;
@@ -52,7 +51,7 @@
typedef struct packed {
% for ep, rsts in eps.items():
% for rst in rsts:
- logic rst_${intf}_${ep}_${rst}_n;
+ logic [PowerDomains-1:0] rst_${intf}_${ep}_${rst}_n;
% endfor
% endfor
} rstmgr_${intf}_out_t;
diff --git a/hw/ip/rstmgr/rtl/rstmgr_ctrl.sv b/hw/ip/rstmgr/rtl/rstmgr_ctrl.sv
index 1bb323f..290d236 100644
--- a/hw/ip/rstmgr/rtl/rstmgr_ctrl.sv
+++ b/hw/ip/rstmgr/rtl/rstmgr_ctrl.sv
@@ -18,12 +18,6 @@
output logic [PowerDomains-1:0] rst_no
);
- // The code below always assumes the always on domain is index 0
- `ASSERT_INIT(AlwaysOnIndex_A, ALWAYS_ON_SEL == 0)
-
- // when there are multiple on domains, the latter 1 should become another parameter
- localparam int OffDomainSelStart = ALWAYS_ON_SEL + 1;
-
// the always on root reset
logic rst_aon_nq;
@@ -47,16 +41,15 @@
prim_flop u_aon_rst (
.clk_i,
.rst_ni,
- .d_i(~rst_req_i[ALWAYS_ON_SEL] & rst_parent_synced[ALWAYS_ON_SEL]),
+ .d_i(~rst_req_i[DomainAonSel] & rst_parent_synced[DomainAonSel]),
.q_o(rst_aon_nq)
);
-
// the non-always-on domains
// These reset whenever the always on domain reset, to ensure power definition consistency.
// By extension, they also reset whenever the root (rst_ni) resets
- assign rst_pd_nd = ~rst_req_i[OffDomainSelStart +: OffDomains] &
- rst_parent_synced[OffDomainSelStart +: OffDomains];
+ assign rst_pd_nd = ~rst_req_i[Domain0Sel +: OffDomains] &
+ rst_parent_synced[Domain0Sel +: OffDomains];
prim_flop u_pd_rst (
.clk_i,
diff --git a/hw/top_earlgrey/data/top_earlgrey.hjson b/hw/top_earlgrey/data/top_earlgrey.hjson
index 6d6b231..ce314ee 100644
--- a/hw/top_earlgrey/data/top_earlgrey.hjson
+++ b/hw/top_earlgrey/data/top_earlgrey.hjson
@@ -15,6 +15,17 @@
// 32-bit datawidth
datawidth: "32",
+ // Power information for the design
+ power: {
+ // Power domains supported by the design
+ // Aon represents domain aon
+ // 0 represents domain 0
+ domains: ["Aon", "0"],
+
+ // Default power domain used for the design
+ default: "0"
+ },
+
// This is the clock data structure of the design.
// The hier path refers to the clock reference path (struct / port)
// - The top/ext desgination follows the same scheme as inter-module
@@ -109,6 +120,7 @@
// gen: whether the reset is generated
// true: it is a generated reset inside rstmgr
// false: it is a hardwired design reset inside rstmgr (roots and por)
+ // For non-generated resets, the parent / domain definitions have no meaning.
//
// type: the reset type [ext, top]
// ext: the reset is coming in from the ports, external to earlgrey
@@ -118,34 +130,32 @@
// parent: The parent reset
// If type is "ext", there is no root, since it is external
//
- // domain: The power domain
- // If no domain, it means there is no choice, just inherits from root.
- // Otherwise, selects the domain to which it is related
- // 0 is defaulted for always on.
- // TBD: This should eventually be changed to a name->index project wide lookup
+ // domains: The power domains of a particular reset
+ // This is a list of of the supported power domains.
+ // Valid values are Aon and (power domain)0 ~ (power domain)1.
+ // If no value is supplied, the default is only the Aon version.
//
// clk: related clock domain for synchronous release
// If type is "por", there is not related clock, since it is
// likely external or generated from a voltage comparator
//
nodes: [
- { name: "rst_ni", gen: false, type: "ext" }
- { name: "por_aon", gen: false, type: "top", parent: "rst_ni", clk: "aon" }
- { name: "lc_src", gen: false, type: "int", parent: "por", clk: "io_div2" }
- { name: "sys_src", gen: false, type: "int", parent: "por", clk: "io_div2" }
- { name: "por", gen: true, type: "top", parent: "por_aon", clk: "main" }
- { name: "por_io", gen: true, type: "top", parent: "por_aon", clk: "io" }
- { name: "por_io_div2", gen: true, type: "top", parent: "por_aon", clk: "io_div2" }
- { name: "por_io_div4", gen: true , type: "top", parent: "por_aon", clk: "io_div4" }
- { name: "por_usb", gen: true, type: "top", parent: "por_aon", clk: "usb" }
- { name: "lc", gen: true, type: "top", domain: "0", parent: "lc_src", clk: "main" }
- { name: "lc_io", gen: true, type: "top", domain: "0", parent: "lc_src", clk: "io_div4" }
- { name: "sys", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "main" }
- { name: "sys_io", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "io_div2" }
- { name: "sys_io_div4", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "io_div4" }
- { name: "sys_aon", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "aon" }
- { name: "spi_device", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "io_div2", sw: 1 }
- { name: "usb", gen: true, type: "top", domain: "0", parent: "sys_src", clk: "usb", sw: 1 }
+ { name: "rst_ni", gen: false, type: "ext", }
+ { name: "por_aon", gen: false, type: "top", domains: ["Aon" ], clk: "aon" }
+ { name: "lc_src", gen: false, type: "int", domains: ["Aon", "0"], clk: "io_div4" }
+ { name: "sys_src", gen: false, type: "int", domains: ["Aon", "0"], clk: "io_div4" }
+ { name: "por", gen: true, type: "top", domains: ["Aon" ], parent: "por_aon", clk: "main" }
+ { name: "por_io", gen: true, type: "top", domains: ["Aon", ], parent: "por_aon", clk: "io" }
+ { name: "por_io_div2", gen: true, type: "top", domains: ["Aon", ], parent: "por_aon", clk: "io_div2" }
+ { name: "por_io_div4", gen: true , type: "top", domains: ["Aon", ], parent: "por_aon", clk: "io_div4" }
+ { name: "por_usb", gen: true, type: "top", domains: ["Aon", ], parent: "por_aon", clk: "usb" }
+ { name: "lc", gen: true, type: "top", domains: [ "0"], parent: "lc_src", clk: "main" }
+ { name: "lc_io_div4", gen: true, type: "top", domains: [ "0"], parent: "lc_src", clk: "io_div4" }
+ { name: "sys", gen: true, type: "top", domains: ["Aon", "0"], parent: "sys_src", clk: "main" }
+ { name: "sys_io_div4", gen: true, type: "top", domains: ["Aon", "0"], parent: "sys_src", clk: "io_div4" }
+ { name: "sys_aon", gen: true, type: "top", domains: ["Aon", ], parent: "sys_src", clk: "aon" }
+ { name: "spi_device", gen: true, type: "top", domains: [ "0"], parent: "sys_src", clk: "io_div2", sw: 1 }
+ { name: "usb", gen: true, type: "top", domains: ["Aon", ], parent: "sys_src", clk: "usb", sw: 1 }
]
}
@@ -241,6 +251,7 @@
clock_srcs: {clk_i: "main", clk_aon_i: "aon"},
clock_group: "secure",
reset_connections: {rst_ni: "sys", rst_aon_ni: "sys_aon"},
+ domain: "Aon",
base_addr: "0x40070000",
generated: "true"
},
@@ -251,6 +262,7 @@
clock_srcs: {clk_i: "main"},
clock_group: "secure",
reset_connections: {rst_ni: "sys"},
+ domain: "Aon",
base_addr: "0x40160000",
generated: "true"
},
@@ -272,6 +284,7 @@
clock_srcs: {clk_i: "io_div4", clk_slow_i: "aon"},
clock_group: "powerup",
reset_connections: {rst_ni: "por", rst_slow_ni: "por_aon"},
+ domain: "Aon",
base_addr: "0x400A0000",
generated: "true" // Indicate this module is generated in the topgen
@@ -282,6 +295,7 @@
clk_io_div2_i: "io_div2", clk_io_div4_i: "io_div4"},
clock_group: "powerup",
reset_connections: {rst_ni: "rst_ni"},
+ domain: "Aon",
base_addr: "0x400B0000",
generated: "true" // Indicate this module is generated in the topgen
},
@@ -289,8 +303,9 @@
type: "clkmgr",
clock_srcs: {clk_i: "io_div4"},
clock_group: "powerup",
- reset_connections: {rst_ni: "por_io", rst_main_ni: "por", rst_io_ni: "por_io", rst_usb_ni: "por_usb"
+ reset_connections: {rst_ni: "por_io_div4", rst_main_ni: "por", rst_io_ni: "por_io", rst_usb_ni: "por_usb"
rst_io_div2_ni: "por_io_div2", rst_io_div4_ni: "por_io_div4"},
+ domain: "Aon",
base_addr: "0x400C0000",
generated: "true"
},
@@ -309,6 +324,7 @@
clock_group: "peri",
clock_reset_export: ["ast"],
reset_connections: {rst_ni: "sys_io_div4", rst_usb_48mhz_ni: "usb"},
+ domain: "Aon",
base_addr: "0x40150000",
},
{ name: "sensor_ctrl",
@@ -317,6 +333,7 @@
clock_group: "secure",
clock_reset_export: ["ast"],
reset_connections: {rst_ni: "sys_io_div4"},
+ domain: "Aon",
base_addr: "0x40170000",
top_only: "true"
},
@@ -331,7 +348,7 @@
type: "otp_ctrl",
clock_srcs: {clk_i: "io_div4"},
clock_group: "timers",
- reset_connections: {rst_ni: "lc_io"},
+ reset_connections: {rst_ni: "lc_io_div4"},
base_addr: "0x401b0000",
},
{ name: "otbn",
@@ -383,9 +400,10 @@
clock_srcs: {clk_i: "io_div4"},
clock_group: "infra",
reset_connections: {rst_ni: "sys_io_div4"},
+ domain: "Aon",
type: "ram_1p",
base_addr: "0x18000000",
- size: "0x1000"
+ size: "0x1000",
inter_signal_list: [
{ struct: "tl"
package: "tlul_pkg"
diff --git a/hw/top_earlgrey/data/top_earlgrey.sv.tpl b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
index 5286036..13e37fe 100644
--- a/hw/top_earlgrey/data/top_earlgrey.sv.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
@@ -28,6 +28,8 @@
cpu_clk = top['clocks']['hier_paths']['top'] + "clk_proc_main"
cpu_rst = top["reset_paths"]["sys"]
dm_rst = top["reset_paths"]["lc"]
+
+unused_resets = lib.get_unused_resets(top)
%>\
module top_${top["name"]} #(
// Auto-inferred parameters
@@ -185,6 +187,14 @@
## Inter-module signal collection
+ // Unused reset signals
+% for k, v in unused_resets.items():
+ logic unused_d${v.lower()}_rst_${k};
+% endfor
+% for k, v in unused_resets.items():
+ assign unused_d${v.lower()}_rst_${k} = ${lib.get_reset_path(k, v, top['resets'])};
+% endfor
+
// Non-debug module reset == reset for everything except for the debug module
logic ndmreset_req;
@@ -215,7 +225,7 @@
) u_rv_core_ibex (
// clock and reset
.clk_i (${cpu_clk}),
- .rst_ni (${cpu_rst}),
+ .rst_ni (${cpu_rst}[rstmgr_pkg::Domain0Sel]),
.test_en_i (1'b0),
// static pinning
.hart_id_i (32'b0),
@@ -247,7 +257,7 @@
.IdcodeValue (JTAG_IDCODE)
) u_dm_top (
.clk_i (${cpu_clk}),
- .rst_ni (${dm_rst}),
+ .rst_ni (${dm_rst}[rstmgr_pkg::Domain0Sel]),
.testmode_i (1'b0),
.ndmreset_o (ndmreset_req),
.dmactive_o (),
@@ -272,7 +282,7 @@
);
assign rstmgr_cpu.ndmreset_req = ndmreset_req;
- assign rstmgr_cpu.rst_cpu_n = ${top["reset_paths"]["sys"]};
+ assign rstmgr_cpu.rst_cpu_n = ${top["reset_paths"]["sys"]}[rstmgr_pkg::Domain0Sel];
## Memory Instantiation
% for m in top["memory"]:
@@ -306,8 +316,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.tl_i (${m["name"]}_tl_req),
.tl_o (${m["name"]}_tl_rsp),
@@ -334,8 +344,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.req_i (${m["name"]}_req),
@@ -371,8 +381,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.tl_i (${m["name"]}_tl_req),
@@ -397,8 +407,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.req_i (${m["name"]}_req),
.addr_i (${m["name"]}_addr),
@@ -427,8 +437,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.tl_i (${m["name"]}_tl_req),
@@ -449,8 +459,8 @@
% for key in clocks:
.${key} (${clocks[key]}),
% endfor
- % for key in resets:
- .${key} (${top["reset_paths"][resets[key]]}),
+ % for key, value in resets.items():
+ .${key} (${value}),
% endfor
.host_req_i (flash_host_req),
.host_addr_i (flash_host_addr),
@@ -599,7 +609,7 @@
.${k} (${v}),
% endfor
% for k, v in m["reset_connections"].items():
- .${k} (${top["reset_paths"][v]})${"," if not loop.last else ""}
+ .${k} (${v})${"," if not loop.last else ""}
% endfor
);
@@ -622,7 +632,7 @@
.${k} (${v}),
% endfor
% for k, v in xbar["reset_connections"].items():
- .${k} (${top["reset_paths"][v]}),
+ .${k} (${v}),
% endfor
## Inter-module signal