[top] First draft of reset controller integration
- This PR does not implement the actual reset controller, but
simply wires up the top level resets as if the controller existed
- The purpose of this PR is to get agreement on the general connectivity
or reset nets and ports
diff --git a/hw/Makefile b/hw/Makefile
index 8277ea0..aab067a 100644
--- a/hw/Makefile
+++ b/hw/Makefile
@@ -16,6 +16,14 @@
TOPS ?= top_earlgrey
+# conditional flags
+VERBOSE ?= 0
+toolflags ?=
+ifeq ($(VERBOSE),1)
+ toolflags += -v
+endif
+
+
ips_reg = $(addsuffix _reg, $(IPS))
tops_gen = $(addsuffix _gen,$(TOPS))
@@ -44,8 +52,8 @@
$(eval $@_TOP := $(strip $(foreach top,$(TOPS),$(findstring $(top),$@))))
${PRJ_DIR}/util/topgen.py -t ${PRJ_DIR}/hw/$($@_TOP)/doc/$($@_TOP).hjson \
--tpl ${PRJ_DIR}/hw/$($@_TOP)/doc/ \
- -o ${PRJ_DIR}/hw/$($@_TOP)/
+ -o ${PRJ_DIR}/hw/$($@_TOP)/ ${toolflags}
${PRJ_DIR}/util/topgen.py -t ${PRJ_DIR}/hw/$($@_TOP)/doc/$($@_TOP).hjson \
- -r -o ${PRJ_DIR}/hw/$($@_TOP)/dv/env/
+ -r -o ${PRJ_DIR}/hw/$($@_TOP)/dv/env/ ${toolflags}
.PHONY: all $(ips_reg) $(tops_gen)
diff --git a/hw/top_earlgrey/doc/top_earlgrey.gen.hjson b/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
index b31b81c..37dd6af 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
+++ b/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
@@ -16,6 +16,25 @@
freq: "100000000"
}
]
+ resets:
+ [
+ {
+ name: lc
+ type: root
+ clk: main
+ }
+ {
+ name: sys
+ type: root
+ clk: main
+ }
+ {
+ name: spi_device
+ type: leaf
+ root: sys
+ clk: main
+ }
+ ]
num_cores: "1"
module:
[
@@ -23,6 +42,10 @@
name: uart
type: uart
clock: main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
base_addr: 0x40000000
size: 0x1000
ip_clock: main
@@ -94,6 +117,10 @@
name: gpio
type: gpio
clock: main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
base_addr: 0x40010000
size: 0x1000
ip_clock: main
@@ -123,6 +150,10 @@
name: spi_device
type: spi_device
clock: main
+ reset_connections:
+ {
+ rst_ni: spi_device
+ }
base_addr: 0x40020000
size: 0x1000
ip_clock: main
@@ -194,6 +225,10 @@
name: flash_ctrl
type: flash_ctrl
clock: main
+ reset_connections:
+ {
+ rst_ni: lc
+ }
base_addr: 0x40030000
size: 0x1000
ip_clock: main
@@ -241,6 +276,10 @@
name: rv_timer
type: rv_timer
clock: main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
base_addr: 0x40080000
size: 0x1000
ip_clock: main
@@ -263,6 +302,10 @@
name: hmac
type: hmac
clock: main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
base_addr: 0x40120000
size: 0x1000
ip_clock: main
@@ -290,6 +333,10 @@
name: rv_plic
type: rv_plic
clock: main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
base_addr: 0x40090000
generated: "true"
parameter:
@@ -311,18 +358,30 @@
[
{
name: rom
+ reset_connections:
+ {
+ rst_ni: sys
+ }
type: rom
base_addr: 0x00008000
size: 0x2000
}
{
name: ram_main
+ reset_connections:
+ {
+ rst_ni: sys
+ }
type: ram_1p
base_addr: 0x10000000
size: 0x10000
}
{
name: eflash
+ reset_connections:
+ {
+ rst_ni: lc
+ }
type: eflash
base_addr: 0x20000000
size: 0x80000
@@ -333,6 +392,11 @@
{
name: main
clock: main
+ reset: sys
+ reset_connections:
+ {
+ rst_main_ni: sys
+ }
connections:
{
corei:
diff --git a/hw/top_earlgrey/doc/top_earlgrey.hjson b/hw/top_earlgrey/doc/top_earlgrey.hjson
index 9a56d44..281455b 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.hjson
+++ b/hw/top_earlgrey/doc/top_earlgrey.hjson
@@ -12,6 +12,17 @@
{ name: "main", freq: "100000000" }
]
+ // Reset attributes
+ // name: name of reset. Real name is `name`_rst_n
+ // type: reset type, either root or leaf
+ // root: if reset type not root, the root reset it is related to
+ // clk: related clock domain for synchronous release
+ resets: [
+ { name: "lc", type: "root", clk: "main"}
+ { name: "sys", type: "root", clk: "main"}
+ { name: "spi_device", type: "leaf", root: "sys", clk: "main"}
+ ]
+
// Number of cores: used in rv_plic and timer
num_cores: "1",
@@ -22,39 +33,50 @@
{ name: "uart", // instance name
type: "uart", // Must be matched to the ip name in `ip.hson` (_reg, _cfg permitted)
// and `hw/ip/{type}`
+
clock: "main", // `ip.hjson` clock is internal name, here top determines
// actual clock (signal matched at the top)
+
+ // reset connections defines the port to top level reset connection
+ // the ip.hjson will declare the reset port names
+ reset_connections: {rst_ni: "sys"},
base_addr: "0x40000000",
},
{ name: "gpio",
type: "gpio",
clock: "main",
+ reset_connections: {rst_ni: "sys"},
base_addr: "0x40010000",
}
{ name: "spi_device",
type: "spi_device",
clock: "main",
+ reset_connections: {rst_ni: "spi_device"},
base_addr: "0x40020000",
},
{ name: "flash_ctrl",
type: "flash_ctrl",
clock: "main",
+ reset_connections: {rst_ni: "lc"},
base_addr: "0x40030000",
},
{ name: "rv_timer",
type: "rv_timer",
clock: "main",
+ reset_connections: {rst_ni: "sys"},
base_addr: "0x40080000",
},
{ name: "hmac",
type: "hmac",
clock: "main",
+ reset_connections: {rst_ni: "sys"},
base_addr: "0x40120000",
},
{ name: "rv_plic",
type: "rv_plic",
clock: "main",
+ reset_connections: {rst_ni: "sys"},
base_addr: "0x40090000",
generated: "true" // Indicate this module is generated in the topgen
parameter: {
@@ -68,9 +90,9 @@
// Memories (ROM, RAM, eFlash) are defined at the top.
// It utilizes the primitive cells but configurable
memory: [
- { name: "rom", type: "rom", base_addr: "0x00008000", size: "0x2000" },
- { name: "ram_main", type: "ram_1p", base_addr: "0x10000000", size: "0x10000" },
- { name: "eflash", type: "eflash", base_addr: "0x20000000", size: "0x80000" },
+ { name: "rom", reset_connections: {rst_ni: "sys"}, type: "rom", base_addr: "0x00008000", size: "0x2000" },
+ { name: "ram_main", reset_connections: {rst_ni: "sys"}, type: "ram_1p", base_addr: "0x10000000", size: "0x10000" },
+ { name: "eflash", reset_connections: {rst_ni: "lc"}, type: "eflash", base_addr: "0x20000000", size: "0x80000" },
],
debug_mem_base_addr: "0x1A110000",
@@ -81,6 +103,8 @@
xbar: [
{ name: "main",
clock: "main", // Main clock, used in sockets
+ reset: "sys",
+ reset_connections: {rst_main_ni: "sys"}
},
],
diff --git a/hw/top_earlgrey/doc/top_earlgrey.tpl.sv b/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
index d2bc994..8ce39f8 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
+++ b/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
@@ -76,6 +76,12 @@
tl_h2d_t tl_${m["name"]}_d_h2d;
tl_d2h_t tl_${m["name"]}_d_d2h;
% endfor
+
+ //reset wires declaration
+% for reset in top['resets']:
+ logic ${reset['name']}_rst_n;
+% endfor
+
<%
interrupt_num = sum([x["width"] if "width" in x else 1 for x in top["interrupt"]])
%>\
@@ -96,12 +102,24 @@
logic [${(interrupt_num).bit_length()-1}:0] irq_id[1];
logic [0:0] msip;
- // Non-debug module reset == reset for everything except for the debug module
- // and the logic required to access it.
- logic ndmreset_n;
- logic ndmreset_from_dm;
- assign ndmreset_n = (scanmode_i) ? rst_ni : ~ndmreset_from_dm & rst_ni;
+ // Non-debug module reset == reset for everything except for the debug module
+ logic ndmreset_req;
+
+ // root resets
+ // TODO: lc_rst_n is not the true root reset. It will be differentiated once the
+ // the reset controller logic is present
+ assign lc_rst_n = rst_ni;
+ assign sys_rst_n = (scanmode_i) ? lc_rst_n : ~ndmreset_req & lc_rst_n;
+
+ //non-root reset assignments
+% for reset in top['resets']:
+ % if reset['type'] in ['leaf']:
+ assign ${reset['name']}_rst_n = ${reset['root']}_rst_n;
+ % endif
+% endfor
+
+ // debug request from rv_dm to core
logic debug_req;
// processor core
@@ -116,7 +134,7 @@
) core (
// clock and reset
.clk_i (clk_i),
- .rst_ni (ndmreset_n),
+ .rst_ni (sys_rst_n),
.test_en_i (1'b0),
// static pinning
.hart_id_i (32'b0),
@@ -151,9 +169,9 @@
// 1 required by standard
) u_dm_top (
.clk_i (clk_i),
- .rst_ni (rst_ni),
+ .rst_ni (lc_rst_n),
.testmode_i (1'b0),
- .ndmreset_o (ndmreset_from_dm),
+ .ndmreset_o (ndmreset_req),
.dmactive_o (),
.debug_req_o (debug_req),
.unavailable_i (1'b0),
@@ -177,12 +195,16 @@
## Memory Instantiation
% for m in top["memory"]:
+<%
+ resets = m['reset_connections']
+%>\
% if m["type"] == "ram_1p":
<%
data_width = int(top["datawidth"])
dw_byte = data_width // 8
addr_width = ((int(m["size"], 0) // dw_byte) -1).bit_length()
sram_depth = (int(m["size"], 0) // dw_byte)
+
%>\
// sram device
logic ${m["name"]}_req;
@@ -199,8 +221,9 @@
.Outstanding(1)
) tl_adapter_${m["name"]} (
.clk_i,
- .rst_ni (ndmreset_n),
-
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.tl_i (tl_${m["name"]}_d_h2d),
.tl_o (tl_${m["name"]}_d_d2h),
@@ -222,7 +245,9 @@
.DataBitsPerMask(${int(data_width/4)})
) u_ram1p_${m["name"]} (
.clk_i,
- .rst_ni (ndmreset_n),
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.req_i (${m["name"]}_req),
.write_i (${m["name"]}_we),
@@ -252,7 +277,9 @@
.ErrOnWrite(1)
) tl_adapter_${m["name"]} (
.clk_i,
- .rst_ni (ndmreset_n),
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.tl_i (tl_${m["name"]}_d_h2d),
.tl_o (tl_${m["name"]}_d_d2h),
@@ -274,7 +301,9 @@
.Depth(${rom_depth})
) u_rom_${m["name"]} (
.clk_i,
- .rst_ni (ndmreset_n),
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.cs_i (${m["name"]}_req),
.addr_i (${m["name"]}_addr),
.dout_o (${m["name"]}_rdata),
@@ -302,7 +331,9 @@
.ErrOnWrite(1)
) tl_adapter_${m["name"]} (
.clk_i,
- .rst_ni (ndmreset_n),
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.tl_i (tl_${m["name"]}_d_h2d),
.tl_o (tl_${m["name"]}_d_d2h),
@@ -325,7 +356,9 @@
.DataWidth(${data_width})
) u_flash_${m["name"]} (
.clk_i,
- .rst_ni,
+ % for key in resets:
+ .${key} (${resets[key]}_rst_n),
+ % endfor
.host_req_i (flash_host_req),
.host_addr_i (flash_host_addr),
.host_req_rdy_o (flash_host_req_rdy),
@@ -339,9 +372,12 @@
// flash memory is embedded within controller
% endif
% endfor
-
## Peripheral Instantiation
+
% for m in top["module"]:
+<%
+
+%>\
% if "parameter" in m:
${m["type"]} #(
% for k, v in m["parameter"].items():
@@ -389,11 +425,18 @@
.irq_id_o (irq_id),
.msip_o (msip),
% endif
+
% if m["scan"] == "true":
.scanmode_i (scanmode_i),
% endif
- .clk_i(${"clk_i" if m["clock"] == "main" else "clk_"+ m["clock"] + "_i"}),
- .rst_ni(${"ndmreset_n" if m["clock"] == "main" else "rst_" + m["clock"] + "_ni"})
+ .clk_i (${"clk_i" if m["clock"] == "main" else "clk_"+ m["clock"] + "_i"}),
+ % for k, v in m["reset_connections"].items():
+ % if loop.last:
+ .${k} (${v}_rst_n)
+ % else:
+ .${k} (${v}_rst_n),
+ % endif
+ % endfor
);
% endfor
@@ -410,10 +453,8 @@
// TL-UL Crossbar
logic clk_main;
- logic ndmreset_sync_main_n; // ndmreset synchronized to clk_main
-
assign clk_main = clk_i;
- assign ndmreset_sync_main_n = ndmreset_n;
+
% for xbar in top["xbar"]:
<%
@@ -421,11 +462,11 @@
%>\
xbar_${xbar["name"]} u_xbar_${xbar["name"]} (
% for clock in xbar["clocks"]:
- ## TODO: How we can handle the reset?
.clk_${clock}_i (clk_${clock}),
- .rst_${clock}_ni (ndmreset_sync_${clock}_n),
% endfor
-
+ % for k, v in xbar["reset_connections"].items():
+ .${k} (${v}_rst_n),
+ % endfor
% for node in xbar["nodes"]:
% if node["type"] == "device":
.tl_${(node["name"]+"_o").ljust(name_len+2)} (tl_${node["name"]}_d_h2d),
diff --git a/hw/top_earlgrey/doc/xbar_main.hjson b/hw/top_earlgrey/doc/xbar_main.hjson
index 6694c7c..2c49d87 100644
--- a/hw/top_earlgrey/doc/xbar_main.hjson
+++ b/hw/top_earlgrey/doc/xbar_main.hjson
@@ -1,6 +1,7 @@
{ name: "main",
type: "xbar",
clock: "main", // Main clock, used in sockets
+ reset_primary: "rst_main_ni", // Main reset, used in sockets
nodes: [
{ name: "corei",
type: "host",
diff --git a/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson b/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson
index ee7e552..c246a2b 100644
--- a/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson
+++ b/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson
@@ -9,6 +9,11 @@
{
name: main
clock: main
+ reset: sys
+ reset_connections:
+ {
+ rst_main_ni: sys
+ }
connections:
{
corei:
diff --git a/hw/top_earlgrey/rtl/top_earlgrey.sv b/hw/top_earlgrey/rtl/top_earlgrey.sv
index d18e26f..5e46916 100644
--- a/hw/top_earlgrey/rtl/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/top_earlgrey.sv
@@ -76,6 +76,12 @@
tl_d2h_t tl_ram_main_d_d2h;
tl_h2d_t tl_eflash_d_h2d;
tl_d2h_t tl_eflash_d_d2h;
+
+ //reset wires declaration
+ logic lc_rst_n;
+ logic sys_rst_n;
+ logic spi_device_rst_n;
+
logic [53:0] intr_vector;
// Interrupt source list
logic intr_uart_tx_watermark;
@@ -108,12 +114,20 @@
logic [5:0] irq_id[1];
logic [0:0] msip;
- // Non-debug module reset == reset for everything except for the debug module
- // and the logic required to access it.
- logic ndmreset_n;
- logic ndmreset_from_dm;
- assign ndmreset_n = (scanmode_i) ? rst_ni : ~ndmreset_from_dm & rst_ni;
+ // Non-debug module reset == reset for everything except for the debug module
+ logic ndmreset_req;
+
+ // root resets
+ // TODO: lc_rst_n is not the true root reset. It will be differentiated once the
+ // the reset controller logic is present
+ assign lc_rst_n = rst_ni;
+ assign sys_rst_n = (scanmode_i) ? lc_rst_n : ~ndmreset_req & lc_rst_n;
+
+ //non-root reset assignments
+ assign spi_device_rst_n = sys_rst_n;
+
+ // debug request from rv_dm to core
logic debug_req;
// processor core
@@ -128,7 +142,7 @@
) core (
// clock and reset
.clk_i (clk_i),
- .rst_ni (ndmreset_n),
+ .rst_ni (sys_rst_n),
.test_en_i (1'b0),
// static pinning
.hart_id_i (32'b0),
@@ -163,9 +177,9 @@
// 1 required by standard
) u_dm_top (
.clk_i (clk_i),
- .rst_ni (rst_ni),
+ .rst_ni (lc_rst_n),
.testmode_i (1'b0),
- .ndmreset_o (ndmreset_from_dm),
+ .ndmreset_o (ndmreset_req),
.dmactive_o (),
.debug_req_o (debug_req),
.unavailable_i (1'b0),
@@ -200,7 +214,7 @@
.ErrOnWrite(1)
) tl_adapter_rom (
.clk_i,
- .rst_ni (ndmreset_n),
+ .rst_ni (sys_rst_n),
.tl_i (tl_rom_d_h2d),
.tl_o (tl_rom_d_d2h),
@@ -221,7 +235,7 @@
.Depth(2048)
) u_rom_rom (
.clk_i,
- .rst_ni (ndmreset_n),
+ .rst_ni (sys_rst_n),
.cs_i (rom_req),
.addr_i (rom_addr),
.dout_o (rom_rdata),
@@ -243,8 +257,7 @@
.Outstanding(1)
) tl_adapter_ram_main (
.clk_i,
- .rst_ni (ndmreset_n),
-
+ .rst_ni (sys_rst_n),
.tl_i (tl_ram_main_d_h2d),
.tl_o (tl_ram_main_d_d2h),
@@ -265,7 +278,7 @@
.DataBitsPerMask(8)
) u_ram1p_ram_main (
.clk_i,
- .rst_ni (ndmreset_n),
+ .rst_ni (sys_rst_n),
.req_i (ram_main_req),
.write_i (ram_main_we),
@@ -295,7 +308,7 @@
.ErrOnWrite(1)
) tl_adapter_eflash (
.clk_i,
- .rst_ni (ndmreset_n),
+ .rst_ni (lc_rst_n),
.tl_i (tl_eflash_d_h2d),
.tl_o (tl_eflash_d_d2h),
@@ -318,7 +331,7 @@
.DataWidth(32)
) u_flash_eflash (
.clk_i,
- .rst_ni,
+ .rst_ni (lc_rst_n),
.host_req_i (flash_host_req),
.host_addr_i (flash_host_addr),
.host_req_rdy_o (flash_host_req_rdy),
@@ -343,8 +356,9 @@
.intr_rx_break_err_o (intr_uart_rx_break_err),
.intr_rx_timeout_o (intr_uart_rx_timeout),
.intr_rx_parity_err_o (intr_uart_rx_parity_err),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (sys_rst_n)
);
gpio gpio (
@@ -354,8 +368,9 @@
.cio_gpio_o (cio_gpio_gpio_d2p_o),
.cio_gpio_en_o (cio_gpio_gpio_en_d2p_o),
.intr_gpio_o (intr_gpio_gpio),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (sys_rst_n)
);
spi_device spi_device (
@@ -372,9 +387,10 @@
.intr_rxerr_o (intr_spi_device_rxerr),
.intr_rxoverflow_o (intr_spi_device_rxoverflow),
.intr_txunderflow_o (intr_spi_device_txunderflow),
+
.scanmode_i (scanmode_i),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+ .clk_i (clk_i),
+ .rst_ni (spi_device_rst_n)
);
flash_ctrl flash_ctrl (
@@ -388,16 +404,18 @@
.intr_op_error_o (intr_flash_ctrl_op_error),
.flash_o(flash_c2m),
.flash_i(flash_m2c),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (lc_rst_n)
);
rv_timer rv_timer (
.tl_i (tl_rv_timer_d_h2d),
.tl_o (tl_rv_timer_d_d2h),
.intr_timer_expired_0_0_o (intr_rv_timer_timer_expired_0_0),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (sys_rst_n)
);
hmac hmac (
@@ -405,8 +423,9 @@
.tl_o (tl_hmac_d_d2h),
.intr_hmac_done_o (intr_hmac_hmac_done),
.intr_fifo_full_o (intr_hmac_fifo_full),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (sys_rst_n)
);
rv_plic #(
@@ -418,8 +437,9 @@
.irq_o (irq_plic),
.irq_id_o (irq_id),
.msip_o (msip),
- .clk_i(clk_i),
- .rst_ni(ndmreset_n)
+
+ .clk_i (clk_i),
+ .rst_ni (sys_rst_n)
);
// interrupt assignments
@@ -451,15 +471,12 @@
// TL-UL Crossbar
logic clk_main;
- logic ndmreset_sync_main_n; // ndmreset synchronized to clk_main
-
assign clk_main = clk_i;
- assign ndmreset_sync_main_n = ndmreset_n;
+
xbar_main u_xbar_main (
.clk_main_i (clk_main),
- .rst_main_ni (ndmreset_sync_main_n),
-
+ .rst_main_ni (sys_rst_n),
.tl_corei_i (tl_corei_h_h2d),
.tl_corei_o (tl_corei_h_d2h),
.tl_cored_i (tl_cored_h_h2d),
diff --git a/util/tlgen/elaborate.py b/util/tlgen/elaborate.py
index 55ab994..31e0f2d 100644
--- a/util/tlgen/elaborate.py
+++ b/util/tlgen/elaborate.py
@@ -29,7 +29,7 @@
## Build address map
## Each socket_1n should have address map
- ## Gather clocks
+ ## Gather clocks and resets
xbar.clocks = {xbar.clock
} | {clk
for node in xbar.nodes for clk in node.clocks}
diff --git a/util/tlgen/item.py b/util/tlgen/item.py
index b26b54e..6c40360 100644
--- a/util/tlgen/item.py
+++ b/util/tlgen/item.py
@@ -44,6 +44,7 @@
clocks = [] # Clocks # Clock domain of the node
# e.g. async_fifo in : clk_core , out : clk_main
+
# If NodeType is Socket out from 1:N then address steering is used
# But this value is also propagated up to a Host from multiple Devices
# Device Node should have address_from, address_to
diff --git a/util/tlgen/xbar.py b/util/tlgen/xbar.py
index 04dc39f..8dfae7a 100644
--- a/util/tlgen/xbar.py
+++ b/util/tlgen/xbar.py
@@ -20,6 +20,7 @@
clock = "" # str # Main clock remove 'clk_' prefix
name = "" # str # e.g. "main" --> main_xbar
clocks = [] # Clocks
+
# prefix is useful if SoC has more than one Xbar
# variables after elaboration. Shouldn't be touched by outside
diff --git a/util/topgen.py b/util/topgen.py
index 0431c66..388c2b0 100755
--- a/util/topgen.py
+++ b/util/topgen.py
@@ -58,7 +58,7 @@
if not tlgen.elaborate(xbar):
log.error("Elaboration failed." + repr(xbar))
- # Add clocks to the top configuration
+ # Add clocks/resets to the top configuration
obj["clocks"] = xbar.clocks
try:
out_rtl, out_pkg, out_bind = tlgen.generate(xbar)
@@ -347,7 +347,7 @@
(", ".join([x["name"] for x in xbar_objs])))
# TODO: Add validate
- topcfg, error = validate_top(topcfg)
+ topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
if error != 0:
raise SystemExit("Error occured while validating top.hjson")
diff --git a/util/topgen/validate.py b/util/topgen/validate.py
index 4f45aba..3f1e1a4 100644
--- a/util/topgen/validate.py
+++ b/util/topgen/validate.py
@@ -1,7 +1,6 @@
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-
import logging as log
from reggen.validate import val_types, check_keys
@@ -84,8 +83,101 @@
def check_pinmux(top, prefix):
return 0
+def check_resets(top, ipobjs, xbarobjs):
+ # all defined reset nets
+ reset_nets = [reset['name'] for reset in top['resets']]
+ error = 0
-def validate_top(top):
+ # Check reset port connection for all IPs
+ for ipcfg in top['module']:
+ log.info("Checking resets for %s" % ipcfg['name'].lower())
+ ipdef = [ip for ip in ipobjs if ipcfg['type'] == ip['name'].lower()]
+ error += check_rst_def(ipdef, ipcfg['type'])
+ error += validate_reset(ipcfg, ipdef[0], reset_nets)
+
+ if error:
+ log.error("module reset checking failed")
+ break
+
+ # Check reset port connection for all xbars
+ for xbarcfg in top['xbar']:
+ log.info("Checking resets for %s" % xbarcfg['name'].lower())
+ xbardef = [
+ xbar for xbar in xbarobjs
+ if xbarcfg['name'] == xbar['name'].lower()
+ ]
+ error += check_rst_def(xbardef, xbarcfg['name'])
+ error += validate_reset(xbarcfg, xbardef[0], reset_nets, "xbar")
+
+ if error:
+ log.error("xbar reset checking failed")
+ break
+
+ return error
+
+def check_rst_def(inst_def, name):
+ error = 0
+ if not inst_def:
+ log.error("Could not find %s.hjson for" % name)
+ error += 1
+
+ if len(inst_def) > 1:
+ log.error("Duplicate %s.hjson" % name)
+ error += 1
+
+ return error
+
+# Checks the following
+# For each defined reset connection in top*.hjson, there exists a defined port at the destination
+# and defined reset net
+# There are the same number of defined connections as there are ports
+def validate_reset(top, inst, reset_nets, prefix=""):
+ # Gather inst port list
+ error = 0
+ inst_port_list = []
+ if 'reset_primary' not in inst.keys():
+ log.info("%s %s does not have a reset_primary defined, default used" %
+ (prefix, inst['name']))
+ inst_port_list.append("rst_ni")
+ else:
+ inst_port_list.append(inst['reset_primary'])
+
+ if 'other_reset_list' in inst.keys():
+ inst_port_list.extend(inst['other_reset_list'])
+ log.info("%s %s resets are %s" %
+ (prefix, inst['name'].lower(), inst_port_list))
+
+ if len(top['reset_connections'].keys()) != len(inst_port_list):
+ error += 1
+ log.error("%s %s mismatched number of ports and nets" %
+ (prefix, inst['name']))
+
+ missing_port = [
+ port for port in top['reset_connections'].keys()
+ if port not in inst_port_list
+ ]
+
+ if missing_port:
+ error += 1
+ log.error("%s %s Following reset ports do not exist:" %
+ (prefix, inst['name']))
+ [log.error("%s" % port) for port in missing_port]
+
+ missing_net = [
+ net for port, net in top['reset_connections'].items()
+ if net not in reset_nets
+ ]
+
+ if missing_net:
+ error += 1
+ log.error("%s %s Following reset nets do not exist:" %
+ (prefix, inst['name']))
+ [log.error("%s" % net) for net in missing_net]
+
+ return error
+
+
+def validate_top(top, ipobjs, xbarobjs):
# return as it is for now
error = check_keys(top, top_required, top_optional, top_added, "top")
@@ -95,6 +187,9 @@
component = top['name']
+ ## Reset check
+ error += check_resets(top, ipobjs, xbarobjs)
+
## MODULE check
## MEMORY check