[topgen] Handle multi clock ports in topgen/module/xbar
Construction is very similar to reset support.
Each target is defined with a clock_connection that is used to
connect in top_*.sv
Inside validate.py, validate_clock / validate_reset are currently
very similar, but is expected to diverge in the future/
Related to #346
diff --git a/hw/ip/flash_ctrl/doc/flash_ctrl.hjson b/hw/ip/flash_ctrl/doc/flash_ctrl.hjson
index cc56e24..ae12131 100644
--- a/hw/ip/flash_ctrl/doc/flash_ctrl.hjson
+++ b/hw/ip/flash_ctrl/doc/flash_ctrl.hjson
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "FLASH_CTRL",
- clock_primary: "main",
+ clock_primary: "clk_i",
bus_device: "tlul",
interrupt_list: [
{ name: "prog_empty", desc: "Program FIFO empty" },
diff --git a/hw/ip/gpio/doc/gpio.hjson b/hw/ip/gpio/doc/gpio.hjson
index c27a6d7..132917f 100644
--- a/hw/ip/gpio/doc/gpio.hjson
+++ b/hw/ip/gpio/doc/gpio.hjson
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
{
name: "gpio",
- clock_primary: "clk",
+ clock_primary: "clk_i",
bus_device: "tlul",
bus_host: "",
available_inout_list: [
diff --git a/hw/ip/hmac/doc/hmac.hjson b/hw/ip/hmac/doc/hmac.hjson
index b8e5bcd..0bb95d7 100644
--- a/hw/ip/hmac/doc/hmac.hjson
+++ b/hw/ip/hmac/doc/hmac.hjson
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "hmac",
- clock_primary: "clk_fixed",
+ clock_primary: "clk_i",
bus_device: "tlul",
bus_host: "none",
available_input_list: [],
diff --git a/hw/ip/rv_plic/doc/rv_plic.tpl.hjson b/hw/ip/rv_plic/doc/rv_plic.tpl.hjson
index 7b7355c..048637a 100644
--- a/hw/ip/rv_plic/doc/rv_plic.tpl.hjson
+++ b/hw/ip/rv_plic/doc/rv_plic.tpl.hjson
@@ -10,7 +10,7 @@
# - prio: Max value of interrupt priorities
{
name: "RV_PLIC",
- clock_primary: "clk_fixed",
+ clock_primary: "clk_i",
bus_device: "tlul",
param_list: [
diff --git a/hw/ip/rv_timer/doc/rv_timer.hjson b/hw/ip/rv_timer/doc/rv_timer.hjson
index ff6f703..9c10792 100644
--- a/hw/ip/rv_timer/doc/rv_timer.hjson
+++ b/hw/ip/rv_timer/doc/rv_timer.hjson
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
{ name: "rv_timer",
- clock_primary: "clk_fixed",
+ clock_primary: "clk_i",
bus_device: "tlul",
bus_host: "none",
available_input_list: [
@@ -124,4 +124,3 @@
},
],
}
-
diff --git a/hw/ip/spi_device/doc/spi_device.hjson b/hw/ip/spi_device/doc/spi_device.hjson
index 9c38243..f80e663 100644
--- a/hw/ip/spi_device/doc/spi_device.hjson
+++ b/hw/ip/spi_device/doc/spi_device.hjson
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "SPI_DEVICE",
- clock_primary: "main",
+ clock_primary: "clk_i",
bus_device: "tlul",
available_input_list: [
{ name: "sck", desc: "SPI Clock" },
diff --git a/hw/ip/uart/doc/uart.hjson b/hw/ip/uart/doc/uart.hjson
index 3822790..a55f44b 100644
--- a/hw/ip/uart/doc/uart.hjson
+++ b/hw/ip/uart/doc/uart.hjson
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
{ name: "uart",
- clock_primary: "clk_fixed",
+ clock_primary: "clk_i",
bus_device: "tlul",
bus_host: "none",
available_input_list: [
diff --git a/hw/top_earlgrey/doc/top_earlgrey.gen.hjson b/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
index 37dd6af..5515a7d 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
+++ b/hw/top_earlgrey/doc/top_earlgrey.gen.hjson
@@ -41,14 +41,16 @@
{
name: uart
type: uart
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
}
base_addr: 0x40000000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list:
@@ -116,14 +118,16 @@
{
name: gpio
type: gpio
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
}
base_addr: 0x40010000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list: []
@@ -149,14 +153,16 @@
{
name: spi_device
type: spi_device
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: spi_device
}
base_addr: 0x40020000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list:
@@ -224,14 +230,16 @@
{
name: flash_ctrl
type: flash_ctrl
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: lc
}
base_addr: 0x40030000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list: []
@@ -275,14 +283,16 @@
{
name: rv_timer
type: rv_timer
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
}
base_addr: 0x40080000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list: []
@@ -301,14 +311,16 @@
{
name: hmac
type: hmac
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
}
base_addr: 0x40120000
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list: []
@@ -332,7 +344,10 @@
{
name: rv_plic
type: rv_plic
- clock: main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
@@ -344,7 +359,6 @@
FIND_MAX: MATRIX
}
size: 0x1000
- ip_clock: main
bus_device: tlul
bus_host: none
available_input_list: []
@@ -358,6 +372,10 @@
[
{
name: rom
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
@@ -368,6 +386,10 @@
}
{
name: ram_main
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: sys
@@ -378,6 +400,10 @@
}
{
name: eflash
+ clock_connections:
+ {
+ clk_i: main
+ }
reset_connections:
{
rst_ni: lc
@@ -391,7 +417,10 @@
[
{
name: main
- clock: main
+ clock_connections:
+ {
+ clk_main_i: main
+ }
reset: sys
reset_connections:
{
@@ -571,6 +600,7 @@
pipeline: "true"
}
]
+ clock: main
}
]
interrupt_module:
diff --git a/hw/top_earlgrey/doc/top_earlgrey.hjson b/hw/top_earlgrey/doc/top_earlgrey.hjson
index 281455b..c19ce8e 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.hjson
+++ b/hw/top_earlgrey/doc/top_earlgrey.hjson
@@ -34,48 +34,52 @@
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)
+ // clock connections defines the port to top level clock connection
+ // the ip.hjson will declare the clock port names
+ // If none are defined at ip.hjson, clk_i is used by default
+ clock_connections: {clk_i: "main"},
// reset connections defines the port to top level reset connection
// the ip.hjson will declare the reset port names
+ // If none are defined at ip.hjson, rst_ni is used by default
reset_connections: {rst_ni: "sys"},
+
base_addr: "0x40000000",
},
{ name: "gpio",
type: "gpio",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "sys"},
base_addr: "0x40010000",
}
{ name: "spi_device",
type: "spi_device",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "spi_device"},
base_addr: "0x40020000",
},
{ name: "flash_ctrl",
type: "flash_ctrl",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "lc"},
base_addr: "0x40030000",
},
{ name: "rv_timer",
type: "rv_timer",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "sys"},
base_addr: "0x40080000",
},
{ name: "hmac",
type: "hmac",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "sys"},
base_addr: "0x40120000",
},
{ name: "rv_plic",
type: "rv_plic",
- clock: "main",
+ clock_connections: {clk_i: "main"},
reset_connections: {rst_ni: "sys"},
base_addr: "0x40090000",
generated: "true" // Indicate this module is generated in the topgen
@@ -90,9 +94,25 @@
// Memories (ROM, RAM, eFlash) are defined at the top.
// It utilizes the primitive cells but configurable
memory: [
- { 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" },
+ { name: "rom",
+ clock_connections: {clk_i: "main"},
+ reset_connections: {rst_ni: "sys"},
+ type: "rom",
+ base_addr: "0x00008000",
+ size: "0x2000"
+ },
+ { name: "ram_main",
+ clock_connections: {clk_i: "main"},
+ reset_connections: {rst_ni: "sys"},
+ type: "ram_1p",
+ base_addr: "0x10000000",
+ size: "0x10000" },
+ { name: "eflash",
+ clock_connections: {clk_i: "main"},
+ reset_connections: {rst_ni: "lc"},
+ type: "eflash",
+ base_addr: "0x20000000",
+ size: "0x80000" },
],
debug_mem_base_addr: "0x1A110000",
@@ -102,7 +122,7 @@
// Assume xbar.hjson is located in the same directory of top.hjson
xbar: [
{ name: "main",
- clock: "main", // Main clock, used in sockets
+ clock_connections: {clk_main_i: "main"},
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 8ce39f8..9b146cd 100644
--- a/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
+++ b/hw/top_earlgrey/doc/top_earlgrey.tpl.sv
@@ -82,6 +82,11 @@
logic ${reset['name']}_rst_n;
% endfor
+ //clock wires declaration
+% for clock in top['clocks']:
+ logic ${clock['name']}_clk;
+% endfor
+
<%
interrupt_num = sum([x["width"] if "width" in x else 1 for x in top["interrupt"]])
%>\
@@ -103,6 +108,11 @@
logic [0:0] msip;
+ // clock assignments
+% for clock in top['clocks']:
+ assign ${clock['name']}_clk = clk_i;
+% endfor
+
// Non-debug module reset == reset for everything except for the debug module
logic ndmreset_req;
@@ -133,7 +143,7 @@
.PipeLine (IbexPipeLine)
) core (
// clock and reset
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.test_en_i (1'b0),
// static pinning
@@ -168,7 +178,7 @@
// xxxxxxxxxxx manufacturer id
// 1 required by standard
) u_dm_top (
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (lc_rst_n),
.testmode_i (1'b0),
.ndmreset_o (ndmreset_req),
@@ -197,6 +207,7 @@
% for m in top["memory"]:
<%
resets = m['reset_connections']
+ clocks = m['clock_connections']
%>\
% if m["type"] == "ram_1p":
<%
@@ -220,7 +231,9 @@
.SramDw(${data_width}),
.Outstanding(1)
) tl_adapter_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -244,7 +257,9 @@
.Depth(${sram_depth}),
.DataBitsPerMask(${int(data_width/4)})
) u_ram1p_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -276,7 +291,9 @@
.Outstanding(1),
.ErrOnWrite(1)
) tl_adapter_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -300,7 +317,9 @@
.Width(${data_width}),
.Depth(${rom_depth})
) u_rom_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -330,7 +349,9 @@
.ByteAccess(0),
.ErrOnWrite(1)
) tl_adapter_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -355,7 +376,9 @@
.WordsPerPage(FLASH_WORDS_PER_PAGE),
.DataWidth(${data_width})
) u_flash_${m["name"]} (
- .clk_i,
+ % for key in clocks:
+ .${key} (${clocks[key]}_clk),
+ % endfor
% for key in resets:
.${key} (${resets[key]}_rst_n),
% endfor
@@ -429,7 +452,9 @@
% if m["scan"] == "true":
.scanmode_i (scanmode_i),
% endif
- .clk_i (${"clk_i" if m["clock"] == "main" else "clk_"+ m["clock"] + "_i"}),
+ % for k, v in m["clock_connections"].items():
+ .${k} (${v}_clk),
+ % endfor
% for k, v in m["reset_connections"].items():
% if loop.last:
.${k} (${v}_rst_n)
@@ -452,17 +477,13 @@
};
// TL-UL Crossbar
- logic clk_main;
- assign clk_main = clk_i;
-
-
% for xbar in top["xbar"]:
<%
name_len = max([len(x["name"]) for x in xbar["nodes"]]);
%>\
xbar_${xbar["name"]} u_xbar_${xbar["name"]} (
- % for clock in xbar["clocks"]:
- .clk_${clock}_i (clk_${clock}),
+ % for k, v in xbar["clock_connections"].items():
+ .${k} (${v}_clk),
% endfor
% for k, v in xbar["reset_connections"].items():
.${k} (${v}_rst_n),
diff --git a/hw/top_earlgrey/doc/xbar_main.hjson b/hw/top_earlgrey/doc/xbar_main.hjson
index 2c49d87..64c8a6b 100644
--- a/hw/top_earlgrey/doc/xbar_main.hjson
+++ b/hw/top_earlgrey/doc/xbar_main.hjson
@@ -1,7 +1,9 @@
{ name: "main",
type: "xbar",
- clock: "main", // Main clock, used in sockets
+ clock: "main",
+ clock_primary: "clk_main_i", // 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/rv_plic/doc/autogen/rv_plic.hjson b/hw/top_earlgrey/ip/rv_plic/doc/autogen/rv_plic.hjson
index 7a27972..5b35774 100644
--- a/hw/top_earlgrey/ip/rv_plic/doc/autogen/rv_plic.hjson
+++ b/hw/top_earlgrey/ip/rv_plic/doc/autogen/rv_plic.hjson
@@ -18,7 +18,7 @@
# - prio: Max value of interrupt priorities
{
name: "RV_PLIC",
- clock_primary: "clk_fixed",
+ clock_primary: "clk_i",
bus_device: "tlul",
param_list: [
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 c246a2b..955fe76 100644
--- a/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson
+++ b/hw/top_earlgrey/ip/xbar/doc/xbar_main.gen.hjson
@@ -8,7 +8,10 @@
{
name: main
- clock: main
+ clock_connections:
+ {
+ clk_main_i: main
+ }
reset: sys
reset_connections:
{
@@ -188,4 +191,5 @@
pipeline: "true"
}
]
+ clock: main
}
\ No newline at end of file
diff --git a/hw/top_earlgrey/rtl/top_earlgrey.sv b/hw/top_earlgrey/rtl/top_earlgrey.sv
index 5e46916..ac5dda5 100644
--- a/hw/top_earlgrey/rtl/top_earlgrey.sv
+++ b/hw/top_earlgrey/rtl/top_earlgrey.sv
@@ -82,6 +82,9 @@
logic sys_rst_n;
logic spi_device_rst_n;
+ //clock wires declaration
+ logic main_clk;
+
logic [53:0] intr_vector;
// Interrupt source list
logic intr_uart_tx_watermark;
@@ -115,6 +118,9 @@
logic [0:0] msip;
+ // clock assignments
+ assign main_clk = clk_i;
+
// Non-debug module reset == reset for everything except for the debug module
logic ndmreset_req;
@@ -141,7 +147,7 @@
.PipeLine (IbexPipeLine)
) core (
// clock and reset
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.test_en_i (1'b0),
// static pinning
@@ -176,7 +182,7 @@
// xxxxxxxxxxx manufacturer id
// 1 required by standard
) u_dm_top (
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (lc_rst_n),
.testmode_i (1'b0),
.ndmreset_o (ndmreset_req),
@@ -213,7 +219,7 @@
.Outstanding(1),
.ErrOnWrite(1)
) tl_adapter_rom (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.tl_i (tl_rom_d_h2d),
@@ -234,7 +240,7 @@
.Width(32),
.Depth(2048)
) u_rom_rom (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.cs_i (rom_req),
.addr_i (rom_addr),
@@ -256,7 +262,7 @@
.SramDw(32),
.Outstanding(1)
) tl_adapter_ram_main (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.tl_i (tl_ram_main_d_h2d),
.tl_o (tl_ram_main_d_d2h),
@@ -277,7 +283,7 @@
.Depth(16384),
.DataBitsPerMask(8)
) u_ram1p_ram_main (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (sys_rst_n),
.req_i (ram_main_req),
@@ -307,7 +313,7 @@
.ByteAccess(0),
.ErrOnWrite(1)
) tl_adapter_eflash (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (lc_rst_n),
.tl_i (tl_eflash_d_h2d),
@@ -330,7 +336,7 @@
.WordsPerPage(FLASH_WORDS_PER_PAGE),
.DataWidth(32)
) u_flash_eflash (
- .clk_i,
+ .clk_i (main_clk),
.rst_ni (lc_rst_n),
.host_req_i (flash_host_req),
.host_addr_i (flash_host_addr),
@@ -357,7 +363,7 @@
.intr_rx_timeout_o (intr_uart_rx_timeout),
.intr_rx_parity_err_o (intr_uart_rx_parity_err),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n)
);
@@ -369,7 +375,7 @@
.cio_gpio_en_o (cio_gpio_gpio_en_d2p_o),
.intr_gpio_o (intr_gpio_gpio),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n)
);
@@ -389,7 +395,7 @@
.intr_txunderflow_o (intr_spi_device_txunderflow),
.scanmode_i (scanmode_i),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (spi_device_rst_n)
);
@@ -405,7 +411,7 @@
.flash_o(flash_c2m),
.flash_i(flash_m2c),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (lc_rst_n)
);
@@ -414,7 +420,7 @@
.tl_o (tl_rv_timer_d_d2h),
.intr_timer_expired_0_0_o (intr_rv_timer_timer_expired_0_0),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n)
);
@@ -424,7 +430,7 @@
.intr_hmac_done_o (intr_hmac_hmac_done),
.intr_fifo_full_o (intr_hmac_fifo_full),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n)
);
@@ -438,7 +444,7 @@
.irq_id_o (irq_id),
.msip_o (msip),
- .clk_i (clk_i),
+ .clk_i (main_clk),
.rst_ni (sys_rst_n)
);
@@ -470,12 +476,8 @@
};
// TL-UL Crossbar
- logic clk_main;
- assign clk_main = clk_i;
-
-
xbar_main u_xbar_main (
- .clk_main_i (clk_main),
+ .clk_main_i (main_clk),
.rst_main_ni (sys_rst_n),
.tl_corei_i (tl_corei_h_h2d),
.tl_corei_o (tl_corei_h_d2h),
diff --git a/util/topgen/merge.py b/util/topgen/merge.py
index 5071594..bad184f 100644
--- a/util/topgen/merge.py
+++ b/util/topgen/merge.py
@@ -7,6 +7,9 @@
from functools import partial
from .lib import *
+import hjson
+
+
def amend_ip(top, ip):
@@ -42,12 +45,6 @@
"given 'size' field in IP %s is smaller than the required space" %
ip_module["name"])
- # ip_clock
- if "clock" in ip:
- ip_module["ip_clock"] = ip["clock"]
- else:
- ip_module["ip_clock"] = "main"
-
# bus_device
ip_module["bus_device"] = ip["bus_device"]
@@ -121,7 +118,7 @@
host)
obj = {
"name": host,
- "clock": xbar["clock"],
+ "clock": xbar['clock'],
"type": "host",
"inst_type": "",
# The default matches RTL default
@@ -131,7 +128,7 @@
}
topxbar["nodes"].append(obj)
else:
- obj[0]["clock"] = xbar["clock"]
+ obj[0]["clock"] = xbar['clock']
obj[0]["inst_type"] = predefined_modules[
host] if host in predefined_modules else ""
obj[0]["pipeline"] = obj[0]["pipeline"] if "pipeline" in obj[
@@ -183,7 +180,7 @@
xbar["nodes"].append({
"name": "debug_mem",
"type": "device",
- "clock": "main",
+ "clock": xbar['clock'],
"inst_type": predefined_modules["debug_mem"],
"base_addr": top["debug_mem_base_addr"],
"size_byte": "0x1000",
@@ -256,6 +253,9 @@
else:
topxbar["nodes"] = []
+
+ topxbar["clock"] = xbar["clock"]
+
# Build nodes from 'connections'
device_nodes = set()
for host, devices in xbar["connections"].items():
@@ -414,6 +414,7 @@
def merge_top(topcfg, ipobjs, xbarobjs):
gencfg = deepcopy(topcfg)
+
# Combine ip cfg into topcfg
for ip in ipobjs:
amend_ip(gencfg, ip)
diff --git a/util/topgen/validate.py b/util/topgen/validate.py
index 3f1e1a4..dd538e8 100644
--- a/util/topgen/validate.py
+++ b/util/topgen/validate.py
@@ -2,8 +2,10 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
import logging as log
+from enum import Enum
-from reggen.validate import val_types, check_keys
+from reggen.validate import check_keys, val_types
+
# For the reference
# val_types = {
# 'd': ["int", "integer (binary 0b, octal 0o, decimal, hex 0x)"],
@@ -74,6 +76,58 @@
padctrl_added = {}
+class TargetType(Enum):
+ MODULE = "module"
+ XBAR = "xbar"
+
+
+class Target:
+ """Target class informs the checkers if we are validating a module or xbar
+ """
+
+ # The type of this target
+ target_type = ""
+
+ # The key to search against
+ key = ""
+
+ def __init__(self, target_type):
+ self.target_type = target_type
+ if target_type == TargetType.MODULE:
+ self.key = "type"
+ else:
+ self.key = "name"
+
+
+# Check to see if each module/xbar defined in top.hjson exists as ip/xbar.hjson
+# Also check to make sure there are not multiple definitions of ip/xbar.hjson for each
+# top level definition
+# If it does, return a dictionary of instance names to index in ip/xbarobjs
+def check_target(top, objs, tgtobj):
+ error = 0
+ idxs = {}
+
+ for i in range(len(objs)):
+ log.info("%d Order is %s" % (i, objs[i]['name'].lower()))
+
+ tgt_type = tgtobj.target_type.value
+ inst_key = tgtobj.key
+
+ for cfg in top[tgt_type]:
+ cfg_name = cfg['name'].lower()
+ log.info("Checking target %s %s" % (tgt_type, cfg_name))
+ tgt_def = [o for o in objs if cfg[inst_key] == o['name'].lower()]
+ error += check_def(tgt_def, cfg_name)
+ if error:
+ log.error("Target existence check failed")
+ break
+ else:
+ idxs[cfg_name] = objs.index(tgt_def[0])
+
+ log.info("Current state %s" % idxs)
+ return error, idxs
+
+
def check_padctrl(top, prefix):
error = check_keys(top["padctrl"], padctrl_required, padctrl_optional,
padctrl_added, prefix + " PadControl")
@@ -83,42 +137,44 @@
def check_pinmux(top, prefix):
return 0
-def check_resets(top, ipobjs, xbarobjs):
- # all defined reset nets
+
+def check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs):
+ # all defined clock/reset nets
reset_nets = [reset['name'] for reset in top['resets']]
+ clock_nets = [clock['name'] for clock in top['clocks']]
error = 0
- # Check reset port connection for all IPs
+ # Check clock/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)
+ ipcfg_name = ipcfg['name'].lower()
+ log.info("Checking clock/resets for %s" % ipcfg_name)
+ error += validate_reset(ipcfg, ipobjs[ip_idxs[ipcfg_name]], reset_nets)
+ error += validate_clock(ipcfg, ipobjs[ip_idxs[ipcfg_name]], clock_nets)
if error:
- log.error("module reset checking failed")
+ log.error("module clock/reset checking failed")
break
- # Check reset port connection for all xbars
+ # Check clock/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")
+ xbarcfg_name = xbarcfg['name'].lower()
+ log.info("Checking clock/resets for xbar %s" % xbarcfg_name)
+ error += validate_reset(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]],
+ reset_nets, "xbar")
+ error += validate_clock(xbarcfg, xbarobjs[xbar_idxs[xbarcfg_name]],
+ clock_nets, "xbar")
if error:
- log.error("xbar reset checking failed")
+ log.error("xbar clock/reset checking failed")
break
return error
-def check_rst_def(inst_def, name):
+
+def check_def(inst_def, name):
error = 0
if not inst_def:
- log.error("Could not find %s.hjson for" % name)
+ log.error("Could not find %s.hjson" % name)
error += 1
if len(inst_def) > 1:
@@ -127,6 +183,7 @@
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
@@ -149,7 +206,7 @@
if len(top['reset_connections'].keys()) != len(inst_port_list):
error += 1
- log.error("%s %s mismatched number of ports and nets" %
+ log.error("%s %s mismatched number of reset ports and nets" %
(prefix, inst['name']))
missing_port = [
@@ -177,6 +234,56 @@
return error
+# Checks the following
+# For each defined clock connection in top*.hjson, there exists a defined port at the destination
+# and defined clock net
+# There are the same number of defined connections as there are ports
+def validate_clock(top, inst, clock_nets, prefix=""):
+ # Gather inst port list
+ error = 0
+ inst_port_list = []
+ if 'clock_primary' not in inst.keys():
+ log.info("%s %s does not have a clock_primary defined, default used" %
+ (prefix, inst['name']))
+ inst_port_list.append("clk_i")
+ else:
+ inst_port_list.append(inst['clock_primary'])
+
+ if 'other_clock_list' in inst.keys():
+ inst_port_list.extend(inst['other_clock_list'])
+ log.info("%s %s clocks are %s" %
+ (prefix, inst['name'].lower(), inst_port_list))
+
+ if len(top['clock_connections'].keys()) != len(inst_port_list):
+ error += 1
+ log.error("%s %s mismatched number of clock ports and nets" %
+ (prefix, inst['name']))
+
+ missing_port = [
+ port for port in top['clock_connections'].keys()
+ if port not in inst_port_list
+ ]
+
+ if missing_port:
+ error += 1
+ log.error("%s %s Following clock ports do not exist:" %
+ (prefix, inst['name']))
+ [log.error("%s" % port) for port in missing_port]
+
+ missing_net = [
+ net for port, net in top['clock_connections'].items()
+ if net not in clock_nets
+ ]
+
+ if missing_net:
+ error += 1
+ log.error("%s %s Following clock 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")
@@ -187,13 +294,19 @@
component = top['name']
- ## Reset check
- error += check_resets(top, ipobjs, xbarobjs)
-
## MODULE check
+ err, ip_idxs = check_target(top, ipobjs, Target(TargetType.MODULE))
+ error += err
+
+ ## XBAR check
+ err, xbar_idxs = check_target(top, xbarobjs, Target(TargetType.XBAR))
+ error += err
## MEMORY check
+ ## Clock / Reset check
+ error += check_clocks_resets(top, ipobjs, ip_idxs, xbarobjs, xbar_idxs)
+
## RV_PLIC check
## PINMUX & PADS check
@@ -203,7 +316,7 @@
peripherals.")
# Pads configuration check
else:
- error = check_padctrl(top, component)
+ error += check_padctrl(top, component)
if not "pinmux" in top:
log.warning("Top {} has no 'pinmux' field. Please consider specifying \
@@ -213,6 +326,4 @@
error += check_pinmux(top, component)
- ## XBAR check
-
return top, error