[topgen] Rework pinmux datastructure and templatize tops
This is a complete overhaul of the pinmux / padctrl configuration
datastructure in the top Hjson.
The new datastructures are used to provide more control over the
DIO/MIO configuration, pinout and target-specific differences
(ASIC vs FPGA vs Verilator).
The chip-level files are now generated from one common template,
and all regular DIO/MIO connections are made automatically.
Signed-off-by: Michael Schaffner <msf@google.com>
diff --git a/util/topgen/templates/toplevel_pkg.sv.tpl b/util/topgen/templates/toplevel_pkg.sv.tpl
index a4346e3..ffd60ed 100644
--- a/util/topgen/templates/toplevel_pkg.sv.tpl
+++ b/util/topgen/templates/toplevel_pkg.sv.tpl
@@ -4,30 +4,8 @@
${gencmd}
<%
import topgen.lib as lib
-
-
-def camelcase(str):
- """Turns a string from 'snake_case' to 'CamelCase'."""
- return "".join([part.capitalize() for part in str.split("_")])
-
-
-def get_dio_pin_enum_literal(sig, start_idx):
- """Returns the DIO pin enum literal with value assignment"""
- if "width" in sig and sig["width"] > 1:
- return_str = ""
- for i in range(int(sig["width"])):
- if i > 0:
- return_str += "\n "
- return_str += camelcase("top_{}_dio_pin_{}_{} = {},".format(
- top["name"], sig["name"], i, start_idx + i))
- return return_str
- return camelcase("top_{}_dio_pin_{} = {},".format(
- top["name"], sig["name"], start_idx))
-
-top_name = top["name"]
-
%>\
-package top_${top_name}_pkg;
+package top_${top["name"]}_pkg;
% for (inst_name, if_name), region in helper.devices():
<%
if_desc = inst_name if if_name is None else '{} device on {}'.format(if_name, inst_name)
@@ -35,12 +13,12 @@
hex_size_bytes = "32'h{:X}".format(region.size_bytes)
%>\
/**
- * Peripheral base address for ${if_desc} in top ${top_name}.
+ * Peripheral base address for ${if_desc} in top ${top["name"]}.
*/
parameter int unsigned ${region.base_addr_name().as_c_define()} = ${hex_base_addr};
/**
- * Peripheral size in bytes for ${if_desc} in top ${top_name}.
+ * Peripheral size in bytes for ${if_desc} in top ${top["name"]}.
*/
parameter int unsigned ${region.size_bytes_name().as_c_define()} = ${hex_size_bytes};
@@ -51,25 +29,82 @@
hex_size_bytes = "32'h{:x}".format(region.size_bytes)
%>\
/**
- * Memory base address for ${name} in top ${top_name}.
+ * Memory base address for ${name} in top ${top["name"]}.
*/
parameter int unsigned ${region.base_addr_name().as_c_define()} = ${hex_base_addr};
/**
- * Memory size for ${name} in top ${top_name}.
+ * Memory size for ${name} in top ${top["name"]}.
*/
parameter int unsigned ${region.size_bytes_name().as_c_define()} = ${hex_size_bytes};
% endfor
- // Enumeration for DIO pins.
+
+ // Enumeration of IO power domains.
+ // Only used in ASIC target.
typedef enum {
- <% pin_cnt = 0 %>\
- % for sig in reversed(top["pinmux"]["dio"]):
- ${get_dio_pin_enum_literal(sig, pin_cnt)}
- <% pin_cnt += int(sig["width"]) if "width" in sig else 1 %>\
- % endfor
- ${camelcase("top_{}_dio_pin_count".format(top_name))} = ${pin_cnt}
- } top_${top_name}_dio_pin_e;
+% for bank in top["pinout"]["banks"]:
+ ${lib.Name(['io', 'bank', bank]).as_camel_case()} = ${loop.index},
+% endfor
+ IoBankCount = ${len(top["pinout"]["banks"])}
+ } pwr_dom_e;
+
+ // Enumeration for MIO signals on the top-level.
+ typedef enum {
+% for sig in top["pinmux"]["ios"]:
+ % if sig['type'] in ['inout', 'input'] and sig['connection'] == 'muxed':
+ ${lib.get_io_enum_literal(sig, 'mio_in')} = ${sig['glob_idx']},
+ % endif
+% endfor
+<% total = top["pinmux"]['io_counts']['muxed']['inouts'] + \
+ top["pinmux"]['io_counts']['muxed']['inputs'] %>\
+ ${lib.Name.from_snake_case("mio_in_count").as_camel_case()} = ${total}
+ } mio_in_e;
+
+ typedef enum {
+% for sig in top["pinmux"]["ios"]:
+ % if sig['type'] in ['inout', 'output'] and sig['connection'] == 'muxed':
+ ${lib.get_io_enum_literal(sig, 'mio_out')} = ${sig['glob_idx']},
+ % endif
+% endfor
+<% total = top["pinmux"]['io_counts']['muxed']['inouts'] + \
+ top["pinmux"]['io_counts']['muxed']['outputs'] %>\
+ ${lib.Name.from_snake_case("mio_out_count").as_camel_case()} = ${total}
+ } mio_out_e;
+
+ // Enumeration for DIO signals, used on both the top and chip-levels.
+ typedef enum {
+% for sig in top["pinmux"]["ios"]:
+ % if sig['connection'] != 'muxed':
+ ${lib.get_io_enum_literal(sig, 'dio')} = ${sig['glob_idx']},
+ % endif
+% endfor
+<% total = top["pinmux"]['io_counts']['dedicated']['inouts'] + \
+ top["pinmux"]['io_counts']['dedicated']['inputs'] + \
+ top["pinmux"]['io_counts']['dedicated']['outputs'] %>\
+ ${lib.Name.from_snake_case("dio_count").as_camel_case()} = ${total}
+ } dio_e;
+
+ // Raw MIO/DIO input array indices on chip-level.
+ // TODO: Does not account for target specific stubbed/added pads.
+ // Need to make a target-specific package for those.
+ typedef enum {
+% for pad in top["pinout"]["pads"]:
+ % if pad["connection"] == "muxed":
+ ${lib.Name.from_snake_case("mio_pad_" + pad["name"]).as_camel_case()} = ${pad["idx"]},
+ % endif
+% endfor
+ ${lib.Name.from_snake_case("mio_pad_count").as_camel_case()}
+ } mio_pad_e;
+
+ typedef enum {
+% for pad in top["pinout"]["pads"]:
+ % if pad["connection"] != "muxed":
+ ${lib.Name.from_snake_case("dio_pad_" + pad["name"]).as_camel_case()} = ${pad["idx"]},
+ % endif
+% endfor
+ ${lib.Name.from_snake_case("dio_pad_count").as_camel_case()}
+ } dio_pad_e;
// TODO: Enumeration for PLIC Interrupt source peripheral.
// TODO: Enumeration for PLIC Interrupt Ids.