floogen 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. floogen/__init__.py +3 -0
  2. floogen/cli.py +266 -0
  3. floogen/config_parser.py +116 -0
  4. floogen/examples/axi_mesh_id.yml +69 -0
  5. floogen/examples/axi_mesh_src.yml +69 -0
  6. floogen/examples/axi_mesh_xy.yml +69 -0
  7. floogen/examples/collective.yml +99 -0
  8. floogen/examples/mcast.yml +86 -0
  9. floogen/examples/nw_mesh_id.yml +86 -0
  10. floogen/examples/nw_mesh_src.yml +86 -0
  11. floogen/examples/nw_mesh_xy.yml +86 -0
  12. floogen/examples/occamy_mesh_src.yml +119 -0
  13. floogen/examples/occamy_mesh_xy.yml +125 -0
  14. floogen/examples/occamy_tree.yml +106 -0
  15. floogen/examples/single_cluster.yml +96 -0
  16. floogen/examples/terapool.yml +130 -0
  17. floogen/model/__init__.py +3 -0
  18. floogen/model/connection.py +64 -0
  19. floogen/model/endpoint.py +126 -0
  20. floogen/model/graph.py +310 -0
  21. floogen/model/link.py +180 -0
  22. floogen/model/network.py +801 -0
  23. floogen/model/network_interface.py +98 -0
  24. floogen/model/protocol.py +167 -0
  25. floogen/model/router.py +103 -0
  26. floogen/model/routing.py +948 -0
  27. floogen/query.py +73 -0
  28. floogen/templates/floo_addrmap.rdl.mako +19 -0
  29. floogen/templates/floo_axi_chimney.sv.mako +63 -0
  30. floogen/templates/floo_axi_router.sv.mako +88 -0
  31. floogen/templates/floo_axi_tile.sv.mako +133 -0
  32. floogen/templates/floo_noc.sv.mako +27 -0
  33. floogen/templates/floo_noc_pkg.sv.mako +63 -0
  34. floogen/templates/floo_nw_chimney.sv.mako +111 -0
  35. floogen/templates/floo_nw_router.sv.mako +124 -0
  36. floogen/utils.py +303 -0
  37. floogen-0.8.0.dist-info/METADATA +72 -0
  38. floogen-0.8.0.dist-info/RECORD +41 -0
  39. floogen-0.8.0.dist-info/WHEEL +4 -0
  40. floogen-0.8.0.dist-info/entry_points.txt +3 -0
  41. floogen-0.8.0.dist-info/licenses/LICENSE-APACHE +201 -0
floogen/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ # Copyright 2023 ETH Zurich and University of Bologna.
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
floogen/cli.py ADDED
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2023 ETH Zurich and University of Bologna.
3
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+ #
6
+ # Author: Tim Fischer <fischeti@iis.ee.ethz.ch>
7
+
8
+ import argparse
9
+ from pathlib import Path
10
+ from importlib.resources import files
11
+
12
+ from mako.template import Template
13
+
14
+ from floogen.config_parser import parse_config
15
+ from floogen.query import handle_query
16
+ from floogen.model.network import Network
17
+ from floogen.utils import verible_format
18
+
19
+ tpl_dir = files("floogen") / "templates"
20
+
21
+ def render_template(context: dict, tpl: Path,
22
+ outdir: Path = None, file_name: str = None,
23
+ format_output: bool=False, verible_fmt_bin: str = None,
24
+ verible_fmt_args: str = None):
25
+ """Render a template, format if requested and write to file or print to stdout."""
26
+ if not tpl.exists():
27
+ # Search in the internal template directory if the template exists there
28
+ if (tpl_dir / tpl.name).exists():
29
+ tpl = tpl_dir / tpl.name
30
+ else:
31
+ raise FileNotFoundError(f"Template not found: {tpl}")
32
+ rendered = Template(filename=str(tpl.resolve())).render(**context)
33
+ if format_output:
34
+ rendered = verible_format(rendered, verible_fmt_bin, verible_fmt_args)
35
+ if outdir:
36
+ outdir.mkdir(parents=True, exist_ok=True)
37
+ if file_name:
38
+ outfile = outdir / file_name
39
+ else:
40
+ outfile = outdir / tpl.stem
41
+ with open(outfile, "w+", encoding="utf-8") as f:
42
+ f.write(rendered)
43
+ else:
44
+ print(rendered)
45
+
46
+
47
+ def build_parser() -> argparse.ArgumentParser:
48
+ """Parse the command line arguments."""
49
+
50
+ # Parser that holds all common options
51
+ common = argparse.ArgumentParser(add_help=False)
52
+ common.add_argument(
53
+ "-c", "--config", type=Path, required=True,
54
+ help="Path to the configuration file."
55
+ )
56
+ common.add_argument(
57
+ "-o", "--outdir", type=Path, required=False,
58
+ help=(
59
+ "Path to the output directory of the generated output files. "
60
+ "If not specified, the files are printed to stdout."
61
+ ),
62
+ )
63
+
64
+ # Parser for SystemVerilog formatting options
65
+ sv_format = argparse.ArgumentParser(add_help=False)
66
+ sv_format.add_argument(
67
+ "--no-format",
68
+ dest="no_format",
69
+ action="store_true",
70
+ help="Do not format the output.",
71
+ )
72
+ sv_format.add_argument(
73
+ "--verible-fmt-bin",
74
+ type=str,
75
+ default=None,
76
+ help="Overwrite default `verible-verilog-format` binary.",
77
+ )
78
+ sv_format.add_argument(
79
+ "--verible-fmt-args",
80
+ type=str,
81
+ default=None,
82
+ help="Additional arguments to pass to `verible-verilog-format`.",
83
+ )
84
+ sv_format.add_argument(
85
+ "--name",
86
+ type=str,
87
+ default=None,
88
+ help="Override the module/package name and prefix for generated files."
89
+ )
90
+
91
+ # Top-level parser
92
+ parser = argparse.ArgumentParser(
93
+ description="FlooGen: A Network-on-Chip Generator for FlooNoC",
94
+ add_help=True,
95
+ )
96
+
97
+ subparsers = parser.add_subparsers(dest="command")
98
+
99
+ # floogen rtl -> pkg + top
100
+ subparsers.add_parser(
101
+ "rtl",
102
+ parents=[common, sv_format],
103
+ add_help=True,
104
+ help="Generate both the NoC package and top-module.",
105
+ )
106
+
107
+ # floogen pkg
108
+ subparsers.add_parser(
109
+ "pkg",
110
+ parents=[common, sv_format],
111
+ add_help=True,
112
+ help="Generate the NoC package.",
113
+ )
114
+
115
+ # floogen top
116
+ subparsers.add_parser(
117
+ "top",
118
+ parents=[common, sv_format],
119
+ add_help=True,
120
+ help="Generate the NoC top-module.",
121
+ )
122
+
123
+ # floogen rdl
124
+ p_rdl = subparsers.add_parser(
125
+ "rdl",
126
+ parents=[common],
127
+ add_help=True,
128
+ help="Generate the SystemRDL of all endpoint address regions.",
129
+ )
130
+ p_rdl.add_argument(
131
+ "--as-mem",
132
+ dest="as_mem",
133
+ action="store_true",
134
+ default=False,
135
+ help="Add memory blocks for address regions without 'rdl_name' declared.",
136
+ )
137
+ p_rdl.add_argument(
138
+ "--memwidth",
139
+ dest="memwidth",
140
+ type=int,
141
+ default=8,
142
+ help="Use the memory width of the RDL address region as the width of the memory block.",
143
+ )
144
+
145
+ # floogen templates <template1> <template2> ...
146
+ p_templates = subparsers.add_parser(
147
+ "template",
148
+ parents=[common, sv_format],
149
+ add_help=True,
150
+ help="Render custom (external) templates.",
151
+ )
152
+ p_templates.add_argument(
153
+ "template",
154
+ type=Path,
155
+ nargs="+",
156
+ help="Path to external template to render. Multiple templates can be specified.",
157
+ )
158
+
159
+ # floogen visualize
160
+ subparsers.add_parser(
161
+ "visualize",
162
+ parents=[common],
163
+ add_help=True,
164
+ help="Visualize the network graph.",
165
+ )
166
+
167
+ # floogen query <key>
168
+ p_query = subparsers.add_parser(
169
+ "query",
170
+ parents=[common],
171
+ add_help=True,
172
+ help="Query a specific key in the configuration.",
173
+ )
174
+ p_query.add_argument(
175
+ "query",
176
+ type=str,
177
+ help="Key to query in the configuration.",
178
+ )
179
+
180
+ return parser
181
+
182
+
183
+ def main():
184
+ """Generates the network."""
185
+
186
+ parser = build_parser()
187
+ args = parser.parse_args()
188
+
189
+ if args.command is None:
190
+ parser.print_help()
191
+ return 0
192
+
193
+ network = parse_config(Network, args.config)
194
+
195
+ network.create_network()
196
+ network.compile_network()
197
+ network.gen_routing_info()
198
+
199
+ # The general context to pass to all templates
200
+ context = {"noc": network}
201
+
202
+ # Additional render arguments
203
+ render_kwargs = {"outdir": args.outdir}
204
+
205
+ # Command specific render arguments
206
+ match args.command:
207
+ case "rtl" | "pkg" | "top" | "template":
208
+ render_kwargs["format_output"] = not args.no_format
209
+ render_kwargs["verible_fmt_bin"] = args.verible_fmt_bin
210
+ render_kwargs["verible_fmt_args"] = args.verible_fmt_args
211
+ context["name"] = args.name or network.name
212
+ pkg_file_name = f"floo_{args.name or network.name}_noc_pkg.sv"
213
+ top_file_name = f"floo_{args.name or network.name}_noc.sv"
214
+ case "rdl":
215
+ rdl_file_name = f"{network.name}_addrmap.rdl"
216
+
217
+
218
+ match args.command:
219
+ case "rtl":
220
+ render_template(context,
221
+ tpl=tpl_dir / "floo_noc_pkg.sv.mako",
222
+ file_name=pkg_file_name,
223
+ **render_kwargs,
224
+ )
225
+ render_template(context,
226
+ tpl=tpl_dir / "floo_noc.sv.mako",
227
+ file_name=top_file_name,
228
+ **render_kwargs,
229
+ )
230
+ case "pkg":
231
+ render_template(context,
232
+ tpl=tpl_dir / "floo_noc_pkg.sv.mako",
233
+ file_name=pkg_file_name,
234
+ **render_kwargs,
235
+ )
236
+ case "top":
237
+ render_template(context,
238
+ tpl=tpl_dir / "floo_noc.sv.mako",
239
+ file_name=top_file_name,
240
+ **render_kwargs,
241
+ )
242
+ case "rdl":
243
+ context["rdl_as_mem"] = args.as_mem
244
+ context["rdl_memwidth"] = args.memwidth
245
+ render_template(context,
246
+ tpl=tpl_dir / "floo_addrmap.rdl.mako",
247
+ file_name=rdl_file_name,
248
+ **render_kwargs,
249
+ )
250
+ case "template":
251
+ for tpl in args.template:
252
+ render_template(context,
253
+ tpl=tpl,
254
+ **render_kwargs,
255
+ )
256
+ case "visualize":
257
+ if args.outdir:
258
+ network.visualize(filename=args.outdir / (network.name + ".pdf"))
259
+ else:
260
+ network.visualize(savefig=False)
261
+ case "query":
262
+ handle_query(network, args.query)
263
+
264
+
265
+ if __name__ == "__main__":
266
+ main()
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ # Copyright 2023 ETH Zurich and University of Bologna.
3
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
4
+ # SPDX-License-Identifier: Apache-2.0
5
+ #
6
+ # Author: Tim Fischer <fischeti@iis.ee.ethz.ch>
7
+
8
+ from pathlib import Path
9
+ import logging
10
+ from typing import List, Union, Tuple, Mapping, TypeVar
11
+
12
+ from pydantic import ValidationError, BaseModel
13
+
14
+ from ruamel.yaml.comments import CommentedMap
15
+ from ruamel.yaml import YAMLError
16
+ import ruamel.yaml
17
+
18
+ import click
19
+
20
+ logger = logging.getLogger("padrick.ConfigParser")
21
+
22
+
23
+ def get_error_context(config_file: Path, line, column, context_before=4, context_after=4):
24
+ """Retrieves the context surrounding an error in a configuration file."""
25
+ lines_to_return = []
26
+ with config_file.open() as file:
27
+ for line_idx, line in enumerate(file.readlines()):
28
+ if line_idx + 1 == line:
29
+ lines_to_return.append(line)
30
+ lines_to_return.append(click.style(column * " " + "^\n", blink=True, fg="yellow"))
31
+ elif line_idx + 1 >= line - context_before and line_idx + 1 <= line + context_after:
32
+ lines_to_return.append(line)
33
+ return "".join(lines_to_return)
34
+
35
+
36
+ def get_human_readable_error_path(config_data: dict, error_location: List[Union[str, int]]):
37
+ """Transforms a list of path segments into a human readable string."""
38
+ transformed_path_segments = []
39
+ node = config_data
40
+ for path_segment in error_location:
41
+ try:
42
+ node = node[path_segment]
43
+ except KeyError:
44
+ transformed_path_segments.append(path_segment)
45
+ break
46
+ if isinstance(path_segment, int):
47
+ transformed_path_segments.append(node.get("name", path_segment))
48
+ else:
49
+ transformed_path_segments.append(path_segment)
50
+ return "->".join(transformed_path_segments)
51
+
52
+
53
+ def get_file_location(
54
+ config_data: CommentedMap, error_location: List[Union[str, int]]
55
+ ) -> Tuple[Tuple[int, int], Mapping]:
56
+ """Retrieves the location of an error in a configuration file."""
57
+ node = config_data
58
+ location = (node.lc.line + 1, node.lc.col)
59
+ subtree = node
60
+ for path_segment in error_location:
61
+ try:
62
+ location = (node.lc.data[path_segment][0] + 1, node.lc.data[path_segment][1])
63
+ node = node[path_segment]
64
+ if isinstance(node, Mapping):
65
+ subtree = node
66
+ except KeyError:
67
+ break
68
+ return location, subtree
69
+
70
+
71
+ T = TypeVar("T", bound=BaseModel)
72
+
73
+
74
+ def parse_config(cls: T, config_file: Path) -> Union[T, None]:
75
+ """Parses a configuration file and returns a validated model."""
76
+ with config_file.open() as file:
77
+ try:
78
+ yaml = ruamel.yaml.YAML(typ="rt")
79
+ # enable support for !include directives (see pyyaml-include package)
80
+ # if not include_base_dir:
81
+ # include_base_dir = config_file.parent
82
+ # if not ignore_includes:
83
+ # include_constructor = YamlIncludeConstructor(base_dir=str(include_base_dir))
84
+ # else:
85
+ # include_constructor = IgnoreIncludeConstructor
86
+ # yaml.register_class(include_constructor)
87
+ config_data = yaml.load(file)
88
+ # config_data = ruamel.yaml.load(file, Loader=ruamel.yaml.RoundTripLoader)
89
+ except YAMLError as e:
90
+ logger.error("Error while parsing config_file:\n %s", e)
91
+ return None
92
+ try:
93
+ model = cls.model_validate(config_data)
94
+ return model
95
+ except ValidationError as e:
96
+ logger.error(
97
+ "Encountered %s validation errors while parsing the configuration file:",
98
+ len(e.errors()),
99
+ )
100
+ for error in e.errors():
101
+ if error["type"] == "extra":
102
+ error[
103
+ "msg"
104
+ ] = f'Unknown field {error["loc"][-1]}. \
105
+ Did you mispell the field name?'
106
+ if error["type"] == "missing":
107
+ error["msg"] = f'Missing field \'{error["loc"][-1]}\''
108
+ else:
109
+ error["msg"] = f'{error["msg"]} (field \'{error["loc"][-1]}\')'
110
+ # error_path = get_human_readable_error_path(config_data, error["loc"])
111
+ (line, column), _ = get_file_location(config_data, error["loc"])
112
+ error_context = get_error_context(config_file, line, column, context_after=10)
113
+ logger.error("Line %s, Column %s:", line, column)
114
+ logger.error("...\n%s\n...", error_context)
115
+ logger.error("Error: %s", error["msg"])
116
+ return None
@@ -0,0 +1,69 @@
1
+ # Copyright 2023 ETH Zurich and University of Bologna.
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ name: axi_mesh
6
+ description: "AXI mesh configuration with table-based routing for FlooGen"
7
+ network_type: "axi"
8
+
9
+ routing:
10
+ route_algo: "ID"
11
+ use_id_table: true
12
+
13
+ protocols:
14
+ - name: "axi_in"
15
+ protocol: "AXI4"
16
+ data_width: 64
17
+ addr_width: 48
18
+ id_width: 4
19
+ user_width: 1
20
+ type_prefix: # prevents `axi_axi` prefix
21
+ - name: "axi_out"
22
+ protocol: "AXI4"
23
+ data_width: 64
24
+ addr_width: 48
25
+ id_width: 2
26
+ user_width: 1
27
+ type_prefix: # prevents `axi_axi` prefix
28
+
29
+ endpoints:
30
+ - name: "cluster"
31
+ array: [4, 4]
32
+ addr_range:
33
+ base: 0x0000_0000_0000
34
+ size: 0x0000_0001_0000
35
+ mgr_port_protocol:
36
+ - "axi_in"
37
+ sbr_port_protocol:
38
+ - "axi_out"
39
+ - name: "hbm"
40
+ array: [4]
41
+ addr_range:
42
+ base: 0x0000_8000_0000
43
+ size: 0x0000_0001_0000
44
+ sbr_port_protocol:
45
+ - "axi_out"
46
+
47
+ routers:
48
+ - name: "router"
49
+ array: [4, 4]
50
+ degree: 5
51
+
52
+ connections:
53
+ - src: "cluster"
54
+ dst: "router"
55
+ src_range:
56
+ - [0, 3]
57
+ - [0, 3]
58
+ dst_range:
59
+ - [0, 3]
60
+ - [0, 3]
61
+ dst_dir: "Eject"
62
+ - src: "hbm"
63
+ dst: "router"
64
+ src_range:
65
+ - [0, 3]
66
+ dst_range:
67
+ - [0, 0]
68
+ - [0, 3]
69
+ dst_dir: "West"
@@ -0,0 +1,69 @@
1
+ # Copyright 2023 ETH Zurich and University of Bologna.
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ name: axi_mesh
6
+ description: "AXI mesh configuration with source-based routing for FlooGen"
7
+ network_type: "axi"
8
+
9
+ routing:
10
+ route_algo: "SRC"
11
+ use_id_table: true
12
+
13
+ protocols:
14
+ - name: "axi_in"
15
+ protocol: "AXI4"
16
+ data_width: 64
17
+ addr_width: 48
18
+ id_width: 4
19
+ user_width: 1
20
+ type_prefix: # prevents `axi_axi` prefix
21
+ - name: "axi_out"
22
+ protocol: "AXI4"
23
+ data_width: 64
24
+ addr_width: 48
25
+ id_width: 2
26
+ user_width: 1
27
+ type_prefix: # prevents `axi_axi` prefix
28
+
29
+ endpoints:
30
+ - name: "cluster"
31
+ array: [4, 4]
32
+ addr_range:
33
+ base: 0x0000_0000_0000
34
+ size: 0x0000_0001_0000
35
+ mgr_port_protocol:
36
+ - "axi_in"
37
+ sbr_port_protocol:
38
+ - "axi_out"
39
+ - name: "hbm"
40
+ array: [4]
41
+ addr_range:
42
+ base: 0x0000_8000_0000
43
+ size: 0x0000_0001_0000
44
+ sbr_port_protocol:
45
+ - "axi_out"
46
+
47
+ routers:
48
+ - name: "router"
49
+ array: [4, 4]
50
+ degree: 5
51
+
52
+ connections:
53
+ - src: "cluster"
54
+ dst: "router"
55
+ src_range:
56
+ - [0, 3]
57
+ - [0, 3]
58
+ dst_range:
59
+ - [0, 3]
60
+ - [0, 3]
61
+ dst_dir: "Eject"
62
+ - src: "hbm"
63
+ dst: "router"
64
+ src_range:
65
+ - [0, 3]
66
+ dst_range:
67
+ - [0, 0]
68
+ - [0, 3]
69
+ dst_dir: "West"
@@ -0,0 +1,69 @@
1
+ # Copyright 2023 ETH Zurich and University of Bologna.
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ name: axi_mesh
6
+ description: "AXI mesh configuration with XY routing for FlooGen"
7
+ network_type: "axi"
8
+
9
+ routing:
10
+ route_algo: "XY"
11
+ use_id_table: true
12
+
13
+ protocols:
14
+ - name: "axi_in"
15
+ protocol: "AXI4"
16
+ data_width: 64
17
+ addr_width: 48
18
+ id_width: 4
19
+ user_width: 1
20
+ type_prefix: # prevents `axi_axi` prefix
21
+ - name: "axi_out"
22
+ protocol: "AXI4"
23
+ data_width: 64
24
+ addr_width: 48
25
+ id_width: 2
26
+ user_width: 1
27
+ type_prefix: # prevents `axi_axi` prefix
28
+
29
+ endpoints:
30
+ - name: "cluster"
31
+ array: [4, 4]
32
+ addr_range:
33
+ base: 0x0000_0000_0000
34
+ size: 0x0000_0001_0000
35
+ mgr_port_protocol:
36
+ - "axi_in"
37
+ sbr_port_protocol:
38
+ - "axi_out"
39
+ - name: "hbm"
40
+ array: [4]
41
+ addr_range:
42
+ base: 0x0000_8000_0000
43
+ size: 0x0000_0001_0000
44
+ sbr_port_protocol:
45
+ - "axi_out"
46
+
47
+ routers:
48
+ - name: "router"
49
+ array: [4, 4]
50
+ degree: 5
51
+
52
+ connections:
53
+ - src: "cluster"
54
+ dst: "router"
55
+ src_range:
56
+ - [0, 3]
57
+ - [0, 3]
58
+ dst_range:
59
+ - [0, 3]
60
+ - [0, 3]
61
+ dst_dir: "Eject"
62
+ - src: "hbm"
63
+ dst: "router"
64
+ src_range:
65
+ - [0, 3]
66
+ dst_range:
67
+ - [0, 0]
68
+ - [0, 3]
69
+ dst_dir: "West"
@@ -0,0 +1,99 @@
1
+ # Copyright 2025 ETH Zurich and University of Bologna.
2
+ # Licensed under the Apache License, Version 2.0, see LICENSE for details.
3
+ # SPDX-License-Identifier: Apache-2.0
4
+ #
5
+ # Example: full collective support
6
+ # - narrow + wide multicast
7
+ # - barrier (LSB-AND)
8
+ # - narrow reduction: all integer ops (Add, Mul, MinS, MinU, MaxS, MaxU)
9
+ # - wide reduction: only Add and Max (selective ops example)
10
+
11
+ name: nw_mesh_collective
12
+ description: "4x4 NW mesh with full collective operation support"
13
+ network_type: "narrow-wide"
14
+
15
+ routing:
16
+ route_algo: "XY"
17
+ use_id_table: true
18
+ collective:
19
+ en_narrow_multicast: true
20
+ en_wide_multicast: true
21
+ en_barrier: true
22
+ en_narrow_reduction:
23
+ rd_pipeline_depth: 1 # all integer ops, custom hw config
24
+ en_wide_reduction: # selective FP ops, default hw config
25
+ ops: [Add, Max]
26
+ rd_pipeline_depth: 5
27
+ cut_offload_intf: true
28
+ # decouple_rw: Phys
29
+ vc_impl: preempt
30
+
31
+ protocols:
32
+ - name: "narrow_in"
33
+ type: "narrow"
34
+ protocol: "AXI4"
35
+ data_width: 64
36
+ addr_width: 48
37
+ id_width: 5
38
+ user_width:
39
+ collective_mask: 48
40
+ collective_op: 4
41
+ user: 5
42
+ - name: "narrow_out"
43
+ type: "narrow"
44
+ protocol: "AXI4"
45
+ data_width: 64
46
+ addr_width: 48
47
+ id_width: 2
48
+ user_width:
49
+ collective_mask: 48
50
+ collective_op: 4
51
+ user: 5
52
+ - name: "wide_in"
53
+ type: "wide"
54
+ protocol: "AXI4"
55
+ data_width: 512
56
+ addr_width: 48
57
+ id_width: 3
58
+ user_width:
59
+ collective_mask: 48
60
+ collective_op: 4
61
+ - name: "wide_out"
62
+ type: "wide"
63
+ protocol: "AXI4"
64
+ data_width: 512
65
+ addr_width: 48
66
+ id_width: 1
67
+ user_width:
68
+ collective_mask: 48
69
+ collective_op: 4
70
+
71
+ endpoints:
72
+ - name: "cluster"
73
+ array: [4, 4]
74
+ addr_range:
75
+ base: 0x2000_0000
76
+ size: 0x0004_0000
77
+ en_collective: true
78
+ mgr_port_protocol:
79
+ - "narrow_in"
80
+ - "wide_in"
81
+ sbr_port_protocol:
82
+ - "narrow_out"
83
+ - "wide_out"
84
+
85
+ routers:
86
+ - name: "router"
87
+ array: [4, 4]
88
+ degree: 5
89
+
90
+ connections:
91
+ - src: "cluster"
92
+ dst: "router"
93
+ src_range:
94
+ - [0, 3]
95
+ - [0, 3]
96
+ dst_range:
97
+ - [0, 3]
98
+ - [0, 3]
99
+ dst_dir: "Eject"