[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