diff --git a/.github/workflows/floogen.yml b/.github/workflows/floogen.yml index 00897fa4..48815b4d 100644 --- a/.github/workflows/floogen.yml +++ b/.github/workflows/floogen.yml @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - examples: ["single_cluster", "occamy_mesh", "occamy_tree"] + examples: ["single_cluster", "occamy_mesh", "occamy_tree", "occamy_mesh_src", "terapool"] steps: - uses: actions/checkout@v4 - name: Set up Python diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce9cfaf..d29994be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added virtual channel router `floo_vc_router` and corresponding `floo_vc_narrow_wide_chimney`. Currently only supports XY-Routing and mesh topologies. - Preliminary support for multiple local ports in the routers. - Additional traffic pattern generation and visualization. +- Added option in `floogen` to define the direction of `connections` to/from routers with `dst_dir` and `src_dir` flags. This replaces the previous `id_offset` flag for that purpose. Specifying the direction of the connection is useful for mesh topologies with `XYRouting`, but also for tile-based implementation, where the order of the ports matters resp. needs to be known. +- `routers` in `floogen` can no be configured with `degree` to overwrite the number of ports. This is manily useful for tile-based implementations, where all tiles should have identical routers. ### Changed @@ -24,6 +26,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Bumped `idma` dependency to `0.6` - Renamed `rsvd` field in flits to `payload` to better reflect its purpose. - Reordered directions in `route_direction_e` to better support multiple local ports. +- Moved all system related rendered parameters from the flit package to its own package in `my_system_floo_noc.sv`. This allows to use the auto-generated routing information for tile-based implementations, that are assembled by hand. +- The `bidirectional` flag for `connections` in `floogen` is set to `true` by default, since uni-directional links are currently not supported. +- The System Address now needs to be passed as a parameter in the `chimneys`, since it is not part of the flit packages anymore. ### Fixed diff --git a/floogen/examples/occamy_mesh.yml b/floogen/examples/occamy_mesh.yml index e1537393..050053a5 100644 --- a/floogen/examples/occamy_mesh.yml +++ b/floogen/examples/occamy_mesh.yml @@ -51,22 +51,16 @@ endpoints: sbr_port_protocol: - "narrow" - "wide" - id_offset: - x: 0 - y: 0 - name: "hbm" - array: [1, 8] + array: [8] addr_range: base: 0x0000_8000_0000 size: 0x0000_4000_0000 sbr_port_protocol: - "narrow" - "wide" - id_offset: - x: -1 - y: 0 - name: "serial_link" - array: [3, 1] + array: [3] addr_range: base: 0x0100_0000_0000 size: 0x0010_000_0000 @@ -76,22 +70,13 @@ endpoints: sbr_port_protocol: - "narrow" - "wide" - id_offset: - x: 0 - y: -1 - name: "cva6" mgr_port_protocol: - "narrow" - id_offset: - x: 0 - y: 8 - name: "peripherals" addr_range: start: 0x0000_0000_0000 end: 0x0000_0fff_ffff - id_offset: - x: 1 - y: 8 mgr_port_protocol: - "narrow" sbr_port_protocol: @@ -100,6 +85,7 @@ endpoints: routers: - name: "router" array: [3, 8] + degree: 5 connections: - src: "cluster" @@ -110,30 +96,28 @@ connections: dst_range: - [0, 2] - [0, 7] - bidirectional: true + dst_dir: "Eject" - src: "hbm" dst: "router" src_range: - - [0, 0] - [0, 7] dst_range: - [0, 0] - [0, 7] - bidirectional: true + dst_dir: "West" - src: "serial_link" dst: "router" src_range: - [0, 2] - - [0, 0] dst_range: - [0, 2] - [0, 0] - bidirectional: true + dst_dir: "South" - src: "cva6" dst: "router" dst_idx: [0, 7] - bidirectional: true + dst_dir: "North" - src: "peripherals" dst: "router" dst_idx: [1, 7] - bidirectional: true + dst_dir: "North" diff --git a/floogen/examples/occamy_mesh_src.yml b/floogen/examples/occamy_mesh_src.yml index 4cca743a..c73c7fc7 100644 --- a/floogen/examples/occamy_mesh_src.yml +++ b/floogen/examples/occamy_mesh_src.yml @@ -2,7 +2,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -name: occamy_mesh +name: occamy_mesh_src description: "Occamy mesh configuration for FlooGen with source-based routing" routing: @@ -85,6 +85,7 @@ endpoints: routers: - name: "router" array: [3, 8] + degree: 5 connections: - src: "cluster" @@ -95,7 +96,6 @@ connections: dst_range: - [0, 2] - [0, 7] - bidirectional: true - src: "hbm" dst: "router" src_range: @@ -103,7 +103,6 @@ connections: dst_range: - [0, 0] - [0, 7] - bidirectional: true - src: "serial_link" dst: "router" src_range: @@ -111,12 +110,9 @@ connections: dst_range: - [0, 2] - [0, 0] - bidirectional: true - src: "cva6" dst: "router" dst_idx: [0, 7] - bidirectional: true - src: "peripherals" dst: "router" dst_idx: [1, 7] - bidirectional: true diff --git a/floogen/examples/occamy_tree.yml b/floogen/examples/occamy_tree.yml index a5b902af..bff07d58 100644 --- a/floogen/examples/occamy_tree.yml +++ b/floogen/examples/occamy_tree.yml @@ -91,19 +91,15 @@ connections: - [0, 3] dst_lvl: 1 allow_multi: true - bidirectional: true - src: "router" dst: "hbm" dst_range: - [0, 7] src_lvl: 0 allow_multi: true - bidirectional: true - src: "router" dst: "serial_link" src_lvl: 0 - bidirectional: true - src: "router" dst: "peripherals" src_lvl: 0 - bidirectional: true diff --git a/floogen/examples/single_cluster.yml b/floogen/examples/single_cluster.yml index 51d2daa9..ad53453a 100644 --- a/floogen/examples/single_cluster.yml +++ b/floogen/examples/single_cluster.yml @@ -85,16 +85,11 @@ routers: connections: - src: "cluster" dst: "router" - bidirectional: true - src: "hbm" dst: "router" - bidirectional: true - src: "serial_link" dst: "router" - bidirectional: true - src: "cva6" dst: "router" - bidirectional: true - src: "peripherals" dst: "router" - bidirectional: true diff --git a/floogen/examples/terapool.yml b/floogen/examples/terapool.yml new file mode 100644 index 00000000..5d46c257 --- /dev/null +++ b/floogen/examples/terapool.yml @@ -0,0 +1,125 @@ +# Copyright 2023 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +name: terapool +description: "Terapool AXI NoC" + +routing: + route_algo: "SRC" + use_id_table: true + +protocols: + - name: "narrow" + type: "AXI4" + direction: "manager" + data_width: 64 + addr_width: 48 + id_width: 4 + user_width: 1 + - name: "narrow" + type: "AXI4" + direction: "subordinate" + data_width: 64 + addr_width: 48 + id_width: 2 + user_width: 1 + - name: "wide" + type: "AXI4" + direction: "manager" + data_width: 512 + addr_width: 48 + id_width: 3 + user_width: 1 + - name: "wide" + type: "AXI4" + direction: "subordinate" + data_width: 512 + addr_width: 48 + id_width: 1 + user_width: 1 + +endpoints: + - name: "group" + array: [4, 4] + mgr_port_protocol: + - "wide" + - name: "hbm" + array: [16] + addr_range: + base: 0x0000_8000_0000 + size: 0x0000_4000_0000 + sbr_port_protocol: + - "wide" + - name: "peripherals" + addr_range: + start: 0x0000_0000_0000 + end: 0x0000_0fff_ffff + mgr_port_protocol: + - "wide" + sbr_port_protocol: + - "wide" + +routers: + - name: "group_router" + array: [4, 4] + degree: 5 + - name: "periph_router" + +connections: + - src: "group" + dst: "group_router" + src_range: + - [0, 3] + - [0, 3] + dst_range: + - [0, 3] + - [0, 3] + dst_dir: "Eject" + # HBM West + - src: "hbm" + dst: "group_router" + src_range: + - [0, 3] + dst_range: + - [0, 0] + - [0, 3] + dst_dir: "West" + # HBM South + - src: "hbm" + dst: "group_router" + src_range: + - [4, 7] + dst_range: + - [0, 3] + - [0, 0] + dst_dir: "South" + # HBM East + - src: "hbm" + dst: "group_router" + src_range: + - [8, 11] + dst_range: + - [3, 3] + - [0, 3] + dst_dir: "East" + # HBM North + - src: "hbm" + dst: "group_router" + src_range: + - [12, 14] + dst_range: + - [0, 2] + - [3, 3] + dst_dir: "North" + # Attach special peripheral/HBM router to the mesh + - src: "periph_router" + dst: "group_router" + dst_idx: [3, 3] + dst_dir: "North" + # Attach last HBM channel and peripherals to the special router + - src: "periph_router" + dst: "hbm" + dst_idx: [15] + - src: "periph_router" + dst: "peripherals" diff --git a/floogen/model/connection.py b/floogen/model/connection.py index 59ab7e18..b31812bb 100644 --- a/floogen/model/connection.py +++ b/floogen/model/connection.py @@ -5,9 +5,11 @@ # # Author: Tim Fischer -from typing import Optional, List, Tuple, Dict +from typing import Optional, List, Tuple from pydantic import BaseModel, field_validator, model_validator +from floogen.model.routing import XYDirections + class ConnectionDesc(BaseModel): """Connection class to describe a connection between routers and endpoints.""" @@ -21,9 +23,10 @@ class ConnectionDesc(BaseModel): dst_idx: Optional[List[int]] = None src_lvl: Optional[int] = None dst_lvl: Optional[int] = None - coord_offset: Optional[Dict] = None + dst_dir: Optional[int] = None + src_dir: Optional[int] = None allow_multi: Optional[bool] = False - bidirectional: Optional[bool] = False + bidirectional: Optional[bool] = True @field_validator("src_idx", "dst_idx", mode="before") @classmethod @@ -41,3 +44,19 @@ def check_indexing(self): if self.dst_idx and self.dst_lvl: raise ValueError("dst_idx and dst_lvl are mutually exclusive") return self + + @field_validator("src_dir", "dst_dir", mode="before") + @classmethod + def str_to_int(cls, v): + """Convert str to int.""" + if isinstance(v, str): + return XYDirections[v.upper()].value + return v + + @field_validator("bidirectional", mode="after") + @classmethod + def check_bidirectional(cls, v): + """Check if bidirectional is valid.""" + if not v: + raise NotImplementedError("Unidirectional connections are not supported yet.") + return v diff --git a/floogen/model/graph.py b/floogen/model/graph.py index c3a115cc..e9424030 100644 --- a/floogen/model/graph.py +++ b/floogen/model/graph.py @@ -9,8 +9,10 @@ import networkx as nx +from floogen.model.routing import XYDirections -class Graph(nx.DiGraph): # pylint: disable=too-many-public-methods + +class Graph(nx.DiGraph): # pylint: disable=too-many-public-methods """Network graph class.""" def __init__(self): @@ -30,9 +32,7 @@ def add_node(self, node_for_adding: str, **attr): def add_edge(self, u_of_edge: str, v_of_edge: str, **attr): """Add an edge to the graph.""" if self.has_edge(u_of_edge, v_of_edge): - raise ValueError( - f"Edge ({u_of_edge}, {v_of_edge}) already exists in the graph." - ) + raise ValueError(f"Edge ({u_of_edge}, {v_of_edge}) already exists in the graph.") assert "type" in attr, "Edge type not provided" if "obj" not in attr: attr["obj"] = None @@ -41,7 +41,7 @@ def add_edge(self, u_of_edge: str, v_of_edge: str, **attr): def add_edge_bidir(self, u_of_edge: str, v_of_edge: str, **attr): """Add a bidirectional edge to the graph.""" self.add_edge(u_of_edge, v_of_edge, **attr) - self.add_edge(v_of_edge, u_of_edge, **attr) # pylint: disable=arguments-out-of-order + self.add_edge(v_of_edge, u_of_edge, **attr) # pylint: disable=arguments-out-of-order def get_node_obj(self, node): """Return the node object.""" @@ -111,21 +111,21 @@ def get_edges_from(self, node, filters=None, with_name=False): """Return the outgoing edges from the node.""" if filters is None: filters = [] - filters.append(lambda e: e[0] == node) + filters = [lambda e: e[0] == node] + filters return self.get_edges(filters=filters, with_name=with_name) def get_edges_to(self, node, filters=None, with_name=False): """Return the incoming edges to the node.""" if filters is None: filters = [] - filters.append(lambda e: e[1] == node) + filters = [lambda e: e[1] == node] + filters return self.get_edges(filters=filters, with_name=with_name) def get_edges_of(self, node, filters=None, with_name=False): """Return the edges of the node.""" if filters is None: filters = [] - filters.append(lambda e: node in e) + filters = [lambda e: node in e] + filters return self.get_edges(filters=filters, with_name=with_name) def get_ni_nodes(self, with_name=False): @@ -194,7 +194,7 @@ def add_nodes_as_tree( tree: List[int], node_type: str, edge_type: str, - lvl: int=0, + lvl: int = 0, node_obj=None, edge_obj=None, connect=True, @@ -206,8 +206,12 @@ def add_nodes_as_tree( node = f"{parent}_{i}" self.add_node(node, type=node_type, lvl=lvl, obj=node_obj) if connect and lvl > 0: - self.add_edge(parent, node, type=edge_type, obj=edge_obj) - self.add_edge(node, parent, type=edge_type, obj=edge_obj) + self.add_edge( + parent, node, type=edge_type, obj=edge_obj, src_dir=None, dst_dir=None + ) + self.add_edge( + node, parent, type=edge_type, obj=edge_obj, src_dir=None, dst_dir=None + ) self.add_nodes_as_tree( node, tree, node_type, edge_type, lvl + 1, node_obj, edge_obj, connect ) @@ -221,7 +225,7 @@ def add_nodes_as_array( node_obj=None, edge_obj=None, connect=True, - ): # pylint: disable=too-many-arguments + ): # pylint: disable=too-many-arguments """Add nodes as an array.""" match array: case [n]: @@ -238,17 +242,37 @@ def add_nodes_as_array( self.add_node(node, type=node_type, arr_idx=(i, j), obj=node_obj) if i > 0 and connect: self.add_edge( - node, f"{name}_{i-1}_{j}", type=edge_type, obj=edge_obj + node, + f"{name}_{i-1}_{j}", + type=edge_type, + obj=edge_obj, + src_dir=XYDirections.WEST.value, + dst_dir=XYDirections.EAST.value, ) self.add_edge( - f"{name}_{i-1}_{j}", node, type=edge_type, obj=edge_obj + f"{name}_{i-1}_{j}", + node, + type=edge_type, + obj=edge_obj, + src_dir=XYDirections.EAST.value, + dst_dir=XYDirections.WEST.value, ) if j > 0 and connect: self.add_edge( - node, f"{name}_{i}_{j-1}", type=edge_type, obj=edge_obj + node, + f"{name}_{i}_{j-1}", + type=edge_type, + obj=edge_obj, + src_dir=XYDirections.SOUTH.value, + dst_dir=XYDirections.NORTH.value, ) self.add_edge( - f"{name}_{i}_{j-1}", node, type=edge_type, obj=edge_obj + f"{name}_{i}_{j-1}", + node, + type=edge_type, + obj=edge_obj, + src_dir=XYDirections.NORTH.value, + dst_dir=XYDirections.SOUTH.value, ) case _: raise NotImplementedError(f"Unsupported array {array}") @@ -258,7 +282,6 @@ def create_unique_ep_id(self, node) -> int: ep_nodes = [name for name, _ in self.get_ep_nodes(with_name=True)] return sorted(ep_nodes).index(node) - def get_node_id(self, node): """Return the node id.""" return self.nodes[node]["id"] diff --git a/floogen/model/link.py b/floogen/model/link.py index a2c0ed45..165f35f3 100644 --- a/floogen/model/link.py +++ b/floogen/model/link.py @@ -5,7 +5,7 @@ # # Author: Tim Fischer -from typing import ClassVar, List, Union, Dict, Optional, NamedTuple +from typing import ClassVar, List, Union, Dict from abc import ABC, abstractmethod from pydantic import BaseModel @@ -140,16 +140,6 @@ def render_link_typedefs(cls) -> str: return string -class XYLinks(NamedTuple): - """Class to describe the directed links of a router.""" - - EAST: Optional[Link] = None - NORTH: Optional[Link] = None - SOUTH: Optional[Link] = None - WEST: Optional[Link] = None - EJECT: Optional[Link] = None - - class NarrowWideLink(Link): """Link class to describe a NarrowWidelink.""" diff --git a/floogen/model/network.py b/floogen/model/network.py index 01816836..270644eb 100644 --- a/floogen/model/network.py +++ b/floogen/model/network.py @@ -15,15 +15,15 @@ from pydantic import BaseModel, ConfigDict, field_validator, model_validator from floogen.model.routing import Routing, RouteAlgo, RouteMapRule, RouteRule, RouteMap, RouteTable -from floogen.model.routing import Coord, SimpleId, AddrRange +from floogen.model.routing import Coord, SimpleId, AddrRange, XYDirections from floogen.model.graph import Graph from floogen.model.endpoint import EndpointDesc, Endpoint -from floogen.model.router import RouterDesc, NarrowWideRouter, NarrowWideXYRouter +from floogen.model.router import RouterDesc, NarrowWideRouter from floogen.model.connection import ConnectionDesc -from floogen.model.link import NarrowWideLink, NarrowWideVCLink, XYLinks, NarrowLink, NarrowVCLink +from floogen.model.link import NarrowWideLink, NarrowWideVCLink, NarrowLink, NarrowVCLink from floogen.model.network_interface import NarrowWideAxiNI from floogen.model.protocol import AXI4, AXI4Bus -from floogen.utils import clog2 +from floogen.utils import clog2, sv_enum_typedef, sv_param_decl import floogen.templates @@ -120,7 +120,6 @@ def create_routers(self): node_obj=rt_desc, connect=rt_desc.auto_connect, ) - # rt.id = Coord(x=x, y=y) # tree case case (None, tree_list): self.graph.add_nodes_as_tree( @@ -277,23 +276,44 @@ def get_ni_of_ep(ep): # Add edges between the nodes for src, dst in zip(srcs, dsts): - self.graph.add_edge(src, dst, type="link") + self.graph.add_edge(src, dst, type="link", + src_dir=con.src_dir, dst_dir=con.dst_dir) if con.bidirectional: - self.graph.add_edge(dst, src, type="link") + self.graph.add_edge(dst, src, type="link", + src_dir=con.dst_dir, dst_dir=con.src_dir) def compile_ids(self): """Infer the id type from the network.""" match self.routing.route_algo: case RouteAlgo.XY: - for node_name, node in self.graph.get_nodes(with_name=True): - if "arr_idx" in self.graph.nodes[node_name]: - x, y = self.graph.get_node_arr_idx(node_name) - else: - x, y = 0, 0 + # 1st stage: Get all router nodes + for node_name, node in self.graph.get_rt_nodes(with_name=True): + x, y = self.graph.get_node_arr_idx(node_name) node_id = Coord(x=x, y=y) if node.id_offset is not None: node_id += node.id_offset self.graph.nodes[node_name]["id"] = node_id + for node_name, node in self.graph.get_ni_nodes(with_name=True): + # Search for a neighbor node *with* an array index + for neighbor in self.graph.neighbors(node_name): + if self.graph.nodes[neighbor].get("id") is not None: + # If it has a directed edge, we can derive the coordinate from there + edge = self.graph.edges[(node_name, neighbor)] + if edge["dst_dir"] is not None: + node_id = self.graph.nodes[neighbor]["id"] + XYDirections.to_coords( + edge["dst_dir"] + ) + break + edge = self.graph.edges[(neighbor, node_name)] + if edge["src_dir"] is not None: + node_id = self.graph.nodes[neighbor]["id"] + XYDirections.to_coords( + edge["src_dir"] + ) + break + assert node_id is not None + if node.id_offset is not None: + node_id += node.id_offset + self.graph.nodes[node_name]["id"] = node_id case RouteAlgo.ID | RouteAlgo.SRC: for ep_name, ep in self.graph.get_ep_nodes(with_name=True): node_id = SimpleId(id=self.graph.create_unique_ep_id(ep_name)) @@ -308,11 +328,6 @@ def compile_links(self): for edge, _ in self.graph.get_link_edges(with_name=True): # Check if link is bidirectional is_bidirectional = self.graph.has_edge(edge[1], edge[0]) - if not is_bidirectional: - raise NotImplementedError( - "Only bidirectional links are \ - supported yet inside the network" - ) link = { "source": edge[0], "dest": edge[1], @@ -325,42 +340,65 @@ def compile_links(self): else: self.graph.set_edge_obj(edge, NarrowWideLink(**link)) - def compile_routers(self): + def compile_routers(self): # pylint: disable=too-many-branches, too-many-locals """Infer the router type from the network.""" - for rt_name, _ in self.graph.get_rt_nodes(with_name=True): - match self.routing.route_algo: - case RouteAlgo.XY: - rt_id = self.graph.get_node_id(rt_name) - incoming, outgoing = {}, {} - for edge in self.graph.get_edges_to(rt_name): - neighbor_id = self.graph.get_node_id(edge.source) - incoming_dir = str(Coord.get_dir(rt_id, neighbor_id)) - if incoming_dir in incoming: - raise ValueError("Incoming direction is already defined") - incoming[incoming_dir] = edge - for edge in self.graph.get_edges_from(rt_name): - neighbor_id = self.graph.get_node_id(edge.dest) - outgoing_dir = str(Coord.get_dir(rt_id, neighbor_id)) - if outgoing_dir in outgoing: - raise ValueError("Outgoing direction is already defined") - outgoing[outgoing_dir] = edge - router_dict = { - "name": rt_name, - "incoming": XYLinks(**incoming), - "outgoing": XYLinks(**outgoing), - "id": rt_id, - } - self.graph.set_node_obj(rt_name, NarrowWideXYRouter(**router_dict)) - - case RouteAlgo.ID | RouteAlgo.SRC: - router_dict = { - "name": rt_name, - "incoming": self.graph.get_edges_to(rt_name), - "outgoing": self.graph.get_edges_from(rt_name), - "degree": len(set(self.graph.neighbors(rt_name))), - "route_algo": self.routing.route_algo, - } - self.graph.set_node_obj(rt_name, NarrowWideRouter(**router_dict)) + for rt_name, rt_obj in self.graph.get_rt_nodes(with_name=True): + dir_in_edges = self.graph.get_edges_to(rt_name, + filters=[lambda e: self.graph.edges[e]["dst_dir"] is not None], with_name=True) + dir_out_edges = self.graph.get_edges_from(rt_name, + filters=[lambda e: self.graph.edges[e]["src_dir"] is not None], with_name=True) + non_dir_in_edges = self.graph.get_edges_to(rt_name, + filters=[lambda e: self.graph.edges[e]["dst_dir"] is None]) + non_dir_out_edges = self.graph.get_edges_from(rt_name, + filters=[lambda e: self.graph.edges[e]["src_dir"] is None]) + if rt_obj.degree is not None: + num_edges = rt_obj.degree + else: + num_edges = len(dir_in_edges) + len(non_dir_in_edges) + + incoming, outgoing = [None] * num_edges, [None] * num_edges + # First, add the directed edges to in_dir_edges and out_dir_edges edges + for edge, edge_obj in dir_in_edges: + in_dir = self.graph.edges[edge]["dst_dir"] + if incoming[in_dir] is not None: + raise ValueError( + f"Trying to set incoming link #{in_dir} of {rt_name} " + + f"to ({edge[0]} -> {edge[1]}), already taken by " + + f"({incoming[in_dir].source} -> {incoming[in_dir].dest})") + incoming[in_dir] = edge_obj + for edge, edge_obj in dir_out_edges: + out_dir = self.graph.edges[edge]["src_dir"] + if outgoing[out_dir] is not None: + raise ValueError( + f"Trying to set outgoing link #{out_dir} of {rt_name} " + + f"to ({edge[0]} -> {edge[1]}), already taken by " + + f"({outgoing[out_dir].source} -> {outgoing[out_dir].dest})") + outgoing[out_dir] = edge_obj + # Second, add the undirected edges to in_dir_edges and out_dir_edges edges + for i, in_edge in enumerate(incoming): + if non_dir_in_edges == []: + break + if in_edge is None: + incoming[i] = non_dir_in_edges.pop(0) + for i, out_edge in enumerate(outgoing): + if non_dir_out_edges == []: + break + if out_edge is None: + outgoing[i] = non_dir_out_edges.pop(0) + + assert non_dir_in_edges == [] + assert non_dir_out_edges == [] + + router_dict = { + "name": rt_name, + "incoming": incoming, + "outgoing": outgoing, + "degree": num_edges, + "route_algo": self.routing.route_algo, + } + if self.routing.route_algo == RouteAlgo.XY: + router_dict["id"] = self.graph.get_node_id(rt_name) + self.graph.set_node_obj(rt_name, NarrowWideRouter(**router_dict)) def compile_endpoints(self): """Infer the endpoint type from the network.""" @@ -423,18 +461,17 @@ def compile_nis(self): # 1D array case case (_,): - if self.routing.route_algo == RouteAlgo.XY: - raise ValueError("Use 2D arrays for XY routing") node_idx = self.graph.get_node_arr_idx(ni_name)[0] - ni_dict["arr_idx"] = SimpleId(id=node_idx) - ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(node_idx) + if ep_desc.is_sbr(): + ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(node_idx) # 2D array case case (_, n): x, y = self.graph.get_node_arr_idx(ni_name) idx = x * n + y ni_dict["arr_idx"] = Coord(x=x, y=y) - ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(idx) + if ep_desc.is_sbr(): + ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(idx) # Invalid case case _: @@ -541,6 +578,7 @@ def gen_routes(self): or (ni_src.is_only_mgr() and ni_dst.is_only_mgr()) or (ni_src.is_only_sbr() and ni_dst.is_only_sbr()) ): + routes.append(RouteRule(route=None, id=ni_dst.id, desc=f"-> {ni_dst.name}")) continue route = nx.shortest_path(self.graph, ni_src.name, ni_dst.name) max_route_bits = 0 @@ -605,6 +643,21 @@ def render_routers(self): string += rt.render() return string + def render_ni_tables(self): + """Render the network interfaces tables in the generated code.""" + string = "" + sorted_ni_list = sorted(self.graph.get_ni_nodes(), key=lambda ni: ni.id.id, reverse=True) + for ni in sorted_ni_list: + string += ni.table.render(num_route_bits=self.routing.num_route_bits, no_decl=True) + string += ",\n" + string = "'{\n" + string[:-2] + "}\n" + return sv_param_decl( + name="RoutingTables", + value=string, + dtype="route_t", + array_size=["NumEndpoints-1", "NumEndpoints-1"], + ) + def render_nis(self): """Render the network interfaces in the generated code.""" string = "" @@ -612,6 +665,13 @@ def render_nis(self): string += ni.render(noc=self) return string + def render_ep_enum(self): + """Render the endpoint enum in the generated code.""" + fields_dict = {ep.name: ep.id.id for ep in self.graph.get_ni_nodes()} + fields_dict = dict(sorted(fields_dict.items(), key=lambda item: item[1])) + fields_dict["num_endpoints"] = len(fields_dict) + return sv_enum_typedef(name="ep_id_e", fields_dict=fields_dict) + def render_network(self): """Render the network in the generated code.""" return self.tpl.render(noc=self) diff --git a/floogen/model/router.py b/floogen/model/router.py index 20e65300..461d26f6 100644 --- a/floogen/model/router.py +++ b/floogen/model/router.py @@ -10,11 +10,11 @@ from importlib.resources import files, as_file from abc import ABC, abstractmethod -from pydantic import BaseModel, field_validator +from pydantic import BaseModel, field_validator, model_validator from mako.lookup import Template from floogen.model.routing import RouteMap, Id, Coord, RouteAlgo -from floogen.model.link import Link, XYLinks +from floogen.model.link import Link import floogen.templates @@ -26,6 +26,7 @@ class RouterDesc(BaseModel): tree: Optional[List[int]] = None id_offset: Optional[Id] = None auto_connect: Optional[bool] = True + degree: Optional[int] = None @field_validator("array", mode="before") @classmethod @@ -48,31 +49,27 @@ class Router(BaseModel, ABC): """Abstract router class of an actual router""" name: str - incoming: List[Link] - outgoing: List[Link] + incoming: List[Optional[Link]] + outgoing: List[Optional[Link]] degree: int route_algo: RouteAlgo table: Optional[RouteMap] = None + id: Optional[Coord] = None @abstractmethod def render(self): """Declare the router in the generated code.""" - -class XYRouter(BaseModel, ABC): - """Abstract router class of an actual router""" - - name: str - incoming: XYLinks - outgoing: XYLinks - degree: int = 5 # XY router always has 5 links - route_algo: RouteAlgo = RouteAlgo.XY - id: Coord - - @abstractmethod - def render(self): - """Declare the router in the generated code.""" - + @model_validator(mode="after") + def check_links(self): + """Check if the number of links is correct.""" + if len(self.incoming) != self.degree: + raise ValueError(f"Router {self.name} has {self.incoming} " + + f"incoming links but should have {self.degree}") + if len(self.outgoing) != self.degree: + raise ValueError(f"Router {self.name} has {self.outgoing} " + + f"outgoing links but should have {self.degree}") + return self class NarrowWideRouter(Router): """Router class to describe a narrow-wide router""" @@ -85,16 +82,3 @@ class NarrowWideRouter(Router): def render(self): """Declare the router in the generated code.""" return self._tpl.render(router=self) + "\n" - - -class NarrowWideXYRouter(XYRouter): - """Router class to describe a narrow-wide router""" - - with as_file( - files(floogen.templates).joinpath("floo_narrow_wide_xy_router.sv.mako") - ) as _tpl_path: - _tpl: ClassVar = Template(filename=str(_tpl_path)) - - def render(self): - """Declare the router in the generated code.""" - return self._tpl.render(router=self) + "\n" diff --git a/floogen/model/routing.py b/floogen/model/routing.py index 09c09841..8f0d6e36 100644 --- a/floogen/model/routing.py +++ b/floogen/model/routing.py @@ -36,15 +36,33 @@ def __str__(self): class XYDirections(Enum): """XY directions enum.""" - NORTH = "North" - EAST = "East" - SOUTH = "South" - WEST = "West" - EJECT = "Eject" + NORTH = 0 + EAST = 1 + SOUTH = 2 + WEST = 3 + EJECT = 4 + + @classmethod + def reverse(cls, direction: int): + """Reverse the direction.""" + return (direction + 2) % 4 if direction != 4 else 4 + + @classmethod + def to_coords(cls, direction: int): + """Convert the direction to coordinates.""" + return { + cls.NORTH.value: Coord(x=0, y=1), + cls.EAST.value: Coord(x=1, y=0), + cls.SOUTH.value: Coord(x=0, y=-1), + cls.WEST.value: Coord(x=-1, y=0), + cls.EJECT.value: Coord(x=0, y=0), + }[direction] def __str__(self): return self.name + def __int__(self): + return self.value class Id(BaseModel, ABC): """ID class.""" @@ -281,7 +299,7 @@ def sort_and_pad(self): self.routes.insert(i, RouteRule(route=None, id=SimpleId(id=i))) return self.routes.reverse() - def render(self, num_route_bits): + def render(self, num_route_bits, no_decl=False): """Render the SystemVerilog route table.""" string = "" rules_str = "" @@ -295,15 +313,17 @@ def render(self, num_route_bits): string += sv_param_decl(f"{snake_to_camel(self.name)}NumRoutes", len(self.routes)) + "\n" for i, rule in enumerate(self.routes): rules_str += f"{rule.render(num_route_bits)}" - rules_str += ',' if i != len(self.routes) - 1 else ' ' + rules_str += "," if i != len(self.routes) - 1 else " " if rule.desc is not None: rules_str += f"// {rule.desc}" rules_str += "\n" + if no_decl: + return "'{\n" + rules_str + "}" string += sv_param_decl( f"{snake_to_camel(self.name)}", value="'{\n" + rules_str + "\n}", dtype="route_t", - array_size=f"{snake_to_camel(self.name)}NumRoutes-1" + array_size=f"{snake_to_camel(self.name)}NumRoutes-1", ) return string diff --git a/floogen/templates/floo_flit_pkg.sv.mako b/floogen/templates/floo_flit_pkg.sv.mako index 410f82e2..c00e0b9f 100644 --- a/floogen/templates/floo_flit_pkg.sv.mako +++ b/floogen/templates/floo_flit_pkg.sv.mako @@ -33,18 +33,6 @@ package floo_${name}_pkg; ${noc.routing.render_flit_header()} - ///////////////////// - // Address Map // - ///////////////////// - -% if noc.routing.use_id_table: - ${noc.routing.sam.render(aw=noc.routing.addr_width)} -% else: - localparam int unsigned SamNumRules = 1; - typedef logic sam_rule_t; - localparam sam_rule_t Sam = '0; -% endif - //////////////////////// // Flits Typedefs // //////////////////////// diff --git a/floogen/templates/floo_narrow_wide_chimney.sv.mako b/floogen/templates/floo_narrow_wide_chimney.sv.mako index 13e3021e..b76659ef 100644 --- a/floogen/templates/floo_narrow_wide_chimney.sv.mako +++ b/floogen/templates/floo_narrow_wide_chimney.sv.mako @@ -1,14 +1,15 @@ <%! from floogen.utils import snake_to_camel %>\ <% actual_xy_id = ni.id - ni.routing.id_offset if ni.routing.id_offset is not None else ni.id %>\ -% if ni.routing.route_algo.value == 'SourceRouting': - ${ni.table.render(num_route_bits=ni.routing.num_route_bits)} -% endif - floo_narrow_wide_chimney #( % if ni.routing.route_algo.value == 'SourceRouting': .NumRoutes(${len(ni.table)}), % endif +% if ni.routing.use_id_table: + .SamNumRules(${len(ni.routing.sam)}), + .sam_rule_t(sam_rule_t), + .Sam(Sam), +% endif % if ni.sbr_narrow_port is None: .EnNarrowSbrPort(1'b0), % else: @@ -68,7 +69,7 @@ floo_narrow_wide_chimney #( .id_i ( id_t'(${ni.id.render()}) ), % endif % if ni.routing.route_algo.value == 'SourceRouting': - .route_table_i ( ${snake_to_camel(ni.table.name)} ), + .route_table_i ( RoutingTables[${snake_to_camel(ni.name)}] ), % else: .route_table_i ( '0 ), % endif diff --git a/floogen/templates/floo_narrow_wide_router.sv.mako b/floogen/templates/floo_narrow_wide_router.sv.mako index aa22390f..e369f297 100644 --- a/floogen/templates/floo_narrow_wide_router.sv.mako +++ b/floogen/templates/floo_narrow_wide_router.sv.mako @@ -1,39 +1,63 @@ +<%! + from floogen.model.routing import XYDirections, RouteAlgo +%>\ <% def camelcase(s): return ''.join(x.capitalize() or '_' for x in s.split('_')) %>\ -% if router.route_algo.value == 'IdTable': +<% req_type = next(d for d in router.incoming if d is not None).req_type %>\ +<% rsp_type = next(d for d in router.incoming if d is not None).rsp_type %>\ +<% wide_type = next(d for d in router.incoming if d is not None).wide_type %>\ +% if router.route_algo == RouteAlgo.ID: ${router.table.render()} % endif -${router.incoming[0].req_type} [${len(router.incoming)-1}:0] ${router.name}_req_in; -${router.incoming[0].rsp_type} [${len(router.incoming)-1}:0] ${router.name}_rsp_out; -${router.outgoing[0].req_type} [${len(router.outgoing)-1}:0] ${router.name}_req_out; -${router.outgoing[0].rsp_type} [${len(router.outgoing)-1}:0] ${router.name}_rsp_in; -${router.incoming[0].wide_type} [${len(router.incoming)-1}:0] ${router.name}_wide_in; -${router.outgoing[0].wide_type} [${len(router.outgoing)-1}:0] ${router.name}_wide_out; +${req_type} [${len(router.incoming)-1}:0] ${router.name}_req_in; +${rsp_type} [${len(router.incoming)-1}:0] ${router.name}_rsp_out; +${req_type} [${len(router.outgoing)-1}:0] ${router.name}_req_out; +${rsp_type} [${len(router.outgoing)-1}:0] ${router.name}_rsp_in; +${wide_type} [${len(router.incoming)-1}:0] ${router.name}_wide_in; +${wide_type} [${len(router.outgoing)-1}:0] ${router.name}_wide_out; % for i, link in enumerate(router.incoming): - assign ${router.name}_req_in[${i}] = ${link.req_name()}; + % if link is not None: + assign ${router.name}_req_in[${i}] = ${link.req_name()}; + % else: + assign ${router.name}_req_in[${i}] = '0; + % endif % endfor % for i, link in enumerate(router.incoming): - assign ${link.rsp_name()} = ${router.name}_rsp_out[${i}]; + % if link is not None: + assign ${link.rsp_name()} = ${router.name}_rsp_out[${i}]; + % endif % endfor % for i, link in enumerate(router.outgoing): - assign ${link.req_name()} = ${router.name}_req_out[${i}]; + % if link is not None: + assign ${link.req_name()} = ${router.name}_req_out[${i}]; + % endif % endfor % for i, link in enumerate(router.outgoing): - assign ${router.name}_rsp_in[${i}] = ${link.rsp_name()}; + % if link is not None: + assign ${router.name}_rsp_in[${i}] = ${link.rsp_name()}; + % else: + assign ${router.name}_rsp_in[${i}] = '0; + % endif % endfor % for i, link in enumerate(router.incoming): - assign ${router.name}_wide_in[${i}] = ${link.wide_name()}; + % if link is not None: + assign ${router.name}_wide_in[${i}] = ${link.wide_name()}; + % else: + assign ${router.name}_wide_in[${i}] = '0; + % endif % endfor % for i, link in enumerate(router.outgoing): - assign ${link.wide_name()} = ${router.name}_wide_out[${i}]; + % if link is not None: + assign ${link.wide_name()} = ${router.name}_wide_out[${i}]; + % endif % endfor floo_narrow_wide_router #( @@ -43,7 +67,7 @@ floo_narrow_wide_router #( .ChannelFifoDepth (2), .OutputFifoDepth (2), .id_t(id_t), -% if router.route_algo.value == 'IdTable': +% if router.route_algo == RouteAlgo.ID: .NumAddrRules (${len(router.table.rules)}), .addr_rule_t (${router.name}_map_rule_t), % endif @@ -52,8 +76,12 @@ floo_narrow_wide_router #( .clk_i, .rst_ni, .test_enable_i, +% if router.route_algo == RouteAlgo.XY: + .id_i (${router.id.render()}), +% else: .id_i ('0), -% if router.route_algo.value == 'IdTable': +% endif +% if router.route_algo == RouteAlgo.ID: .id_route_map_i (${camelcase(router.name + "_map")}), % else: .id_route_map_i ('0), diff --git a/floogen/templates/floo_narrow_wide_xy_router.sv.mako b/floogen/templates/floo_narrow_wide_xy_router.sv.mako deleted file mode 100644 index 00d78fa7..00000000 --- a/floogen/templates/floo_narrow_wide_xy_router.sv.mako +++ /dev/null @@ -1,63 +0,0 @@ -<% def camelcase(s): - return ''.join(x.capitalize() or '_' for x in s.split('_')) -%>\ -<% req_type = next(d for d in router.incoming._asdict().values() if d is not None).req_type %>\ -<% rsp_type = next(d for d in router.incoming._asdict().values() if d is not None).rsp_type %>\ -<% wide_type = next(d for d in router.incoming._asdict().values() if d is not None).wide_type %>\ - -${req_type} [NumDirections-1:0] ${router.name}_req_in; -${rsp_type} [NumDirections-1:0] ${router.name}_rsp_out; -${req_type} [NumDirections-1:0] ${router.name}_req_out; -${rsp_type} [NumDirections-1:0] ${router.name}_rsp_in; -${wide_type} [NumDirections-1:0] ${router.name}_wide_in; -${wide_type} [NumDirections-1:0] ${router.name}_wide_out; - -% for dir, link in router.incoming._asdict().items(): - assign ${router.name}_req_in[${camelcase(dir)}] = ${"'0" if link is None else link.req_name()}; -% endfor - -% for dir, link in router.incoming._asdict().items(): - % if link is not None: - assign ${link.rsp_name()} = ${router.name}_rsp_out[${camelcase(dir)}]; - % endif -% endfor - -% for dir, link in router.outgoing._asdict().items(): - % if link is not None: - assign ${link.req_name()} = ${router.name}_req_out[${camelcase(dir)}]; - % endif -% endfor - -% for dir, link in router.outgoing._asdict().items(): - assign ${router.name}_rsp_in[${camelcase(dir)}] = ${"'0" if link is None else link.rsp_name()}; -% endfor - -% for dir, link in router.incoming._asdict().items(): - assign ${router.name}_wide_in[${camelcase(dir)}] = ${"'0" if link is None else link.wide_name()}; -% endfor - -% for dir, link in router.outgoing._asdict().items(): - % if link is not None: - assign ${link.wide_name()} = ${router.name}_wide_out[${camelcase(dir)}]; - % endif -% endfor - -floo_narrow_wide_router #( - .NumRoutes (NumDirections), - .ChannelFifoDepth (2), - .OutputFifoDepth (2), - .RouteAlgo (XYRouting), - .id_t(id_t) -) ${router.name} ( - .clk_i, - .rst_ni, - .test_enable_i, - .id_i (${router.id.render()}), - .id_route_map_i ('0), - .floo_req_i (${router.name}_req_in), - .floo_rsp_o (${router.name}_rsp_out), - .floo_req_o (${router.name}_req_out), - .floo_rsp_i (${router.name}_rsp_in), - .floo_wide_i (${router.name}_wide_in), - .floo_wide_o (${router.name}_wide_out) -); diff --git a/floogen/templates/floo_noc_top.sv.mako b/floogen/templates/floo_noc_top.sv.mako index 95eb9726..703c9f2f 100644 --- a/floogen/templates/floo_noc_top.sv.mako +++ b/floogen/templates/floo_noc_top.sv.mako @@ -7,9 +7,36 @@ // AUTOMATICALLY GENERATED! DO NOT EDIT! +package ${noc.name}_floo_noc_pkg; + + import floo_narrow_wide_pkg::*; + + ///////////////////// + // Address Map // + ///////////////////// + +% if noc.routing.route_algo.value != "XYRouting": + ${noc.render_ep_enum()} +% endif + +% if noc.routing.use_id_table: + ${noc.routing.sam.render(aw=noc.routing.addr_width)} +% else: + localparam int unsigned SamNumRules = 1; + typedef logic sam_rule_t; + localparam sam_rule_t Sam = '0; +% endif + +% if noc.routing.route_algo.value == "SourceRouting": + ${noc.render_ni_tables()} +% endif + +endpackage + module ${noc.name}_floo_noc import floo_pkg::*; import floo_narrow_wide_pkg::*; + import ${noc.name}_floo_noc_pkg::*; ( input logic clk_i, input logic rst_ni, diff --git a/floogen/utils.py b/floogen/utils.py index 93550664..3611a550 100644 --- a/floogen/utils.py +++ b/floogen/utils.py @@ -8,7 +8,7 @@ import math import shutil import subprocess -from typing import Union +from typing import Union, List def cdiv(x, y) -> int: @@ -51,15 +51,23 @@ def sv_param_decl( value: Union[int, str], ptype: str = "localparam", dtype: str = "int unsigned", - array_size: Union[int, str] = None, + array_size: Union[int, str, List[Union[int, str]]] = None, ) -> str: """Declare a SystemVerilog parameter.""" assert ptype in ["localparam", "parameter"] + def _array_fmt(size): + if isinstance(size, int): + return f"[{size-1}:0]" + return f"[{size}:0]" + if array_size is None: return f"{ptype} {dtype} {name} = {value};\n" - if isinstance(array_size, int): - return f"{ptype} {dtype}[{array_size-1}:0] {name} = {value};\n" - return f"{ptype} {dtype}[{array_size}:0] {name} = {value};\n" + if isinstance(array_size, (int, str)): + return f"{ptype} {dtype}{_array_fmt(array_size)} {name} = {value};\n" + if isinstance(array_size, list): + array_fmt = "".join([_array_fmt(size) for size in array_size]) + return f"{ptype} {dtype}{array_fmt} {name} = {value};\n" + raise ValueError("array_size must be int, str, or list.") def sv_typedef(name: str, dtype: str = "logic", array_size: int = None) -> str: @@ -81,6 +89,25 @@ def sv_struct_typedef(name: str, fields: dict, union=False) -> str: typedef += f"}} {name};\n\n" return typedef +def sv_enum_typedef(name: str, fields_dict: dict=None, fields_list: list=None) -> str: + """Declare a SystemVerilog enum typedef.""" + if fields_dict is not None: + bitwidth = clog2(max(fields_dict.values()) + 1) + typedef = f"typedef enum logic[{bitwidth-1}:0] {{\n" + for field, value in fields_dict.items(): + typedef += f" {snake_to_camel(field)} = {value},\n" + typedef = typedef[:-2] + f"}} {name};\n\n" + elif fields_list is not None: + bitwidth = clog2(len(fields_list)) + typedef = f"typedef enum logic[{bitwidth-1}:0] {{\n" + for i, field in enumerate(fields_list): + typedef += f" {snake_to_camel(field)} = {i},\n" + typedef += f"}} {name};\n\n" + else: + raise ValueError("fields_dict or fields_list must be provided.") + return typedef + + def verible_format(string: str) -> str: """Format the string using verible-verilog-format.""" if shutil.which("verible-verilog-format") is None: diff --git a/hw/floo_axi_chimney.sv b/hw/floo_axi_chimney.sv index 3e44e676..bc22e016 100644 --- a/hw/floo_axi_chimney.sv +++ b/hw/floo_axi_chimney.sv @@ -44,6 +44,12 @@ module floo_axi_chimney parameter bit CutRsp = 1'b1, /// Type for implementation inputs and outputs parameter type sram_cfg_t = logic, + /// Number of System Address Map Rules + parameter int unsigned SamNumRules = 0, + /// Type of System Address Map Rule + parameter type sam_rule_t = logic, + /// System Address Map + parameter sam_rule_t [SamNumRules-1:0] Sam = '0, /// Number of rules in the address map parameter int unsigned NumRoutes = 0 ) ( diff --git a/hw/floo_axi_pkg.sv b/hw/floo_axi_pkg.sv index e0bfb918..76bc6f18 100644 --- a/hw/floo_axi_pkg.sv +++ b/hw/floo_axi_pkg.sv @@ -94,14 +94,6 @@ package floo_axi_pkg; - ///////////////////// - // Address Map // - ///////////////////// - - localparam int unsigned SamNumRules = 1; - typedef logic sam_rule_t; - localparam sam_rule_t Sam = '0; - //////////////////////// // Flits Typedefs // //////////////////////// diff --git a/hw/floo_narrow_wide_chimney.sv b/hw/floo_narrow_wide_chimney.sv index db550d05..f8c00c71 100644 --- a/hw/floo_narrow_wide_chimney.sv +++ b/hw/floo_narrow_wide_chimney.sv @@ -60,6 +60,12 @@ module floo_narrow_wide_chimney parameter bit CutRsp = 1'b1, /// Type for implementation inputs and outputs parameter type sram_cfg_t = logic, + /// Number of System Address Map Rules + parameter int unsigned SamNumRules = 0, + /// Type of System Address Map Rule + parameter type sam_rule_t = logic, + /// System Address Map + parameter sam_rule_t [SamNumRules-1:0] Sam = '0, /// Number of routes in the routing table parameter int unsigned NumRoutes = 0 ) ( diff --git a/hw/floo_narrow_wide_pkg.sv b/hw/floo_narrow_wide_pkg.sv index e3a710aa..90b060cb 100644 --- a/hw/floo_narrow_wide_pkg.sv +++ b/hw/floo_narrow_wide_pkg.sv @@ -132,14 +132,6 @@ package floo_narrow_wide_pkg; - ///////////////////// - // Address Map // - ///////////////////// - - localparam int unsigned SamNumRules = 1; - typedef logic sam_rule_t; - localparam sam_rule_t Sam = '0; - //////////////////////// // Flits Typedefs // //////////////////////// diff --git a/hw/floo_vc_axi_pkg.sv b/hw/floo_vc_axi_pkg.sv index 4a5e223f..cf960b1e 100644 --- a/hw/floo_vc_axi_pkg.sv +++ b/hw/floo_vc_axi_pkg.sv @@ -97,14 +97,6 @@ package floo_vc_axi_pkg; - ///////////////////// - // Address Map // - ///////////////////// - - localparam int unsigned SamNumRules = 1; - typedef logic sam_rule_t; - localparam sam_rule_t Sam = '0; - //////////////////////// // Flits Typedefs // //////////////////////// diff --git a/hw/floo_vc_narrow_wide_chimney.sv b/hw/floo_vc_narrow_wide_chimney.sv index 83017d7b..da7ac272 100644 --- a/hw/floo_vc_narrow_wide_chimney.sv +++ b/hw/floo_vc_narrow_wide_chimney.sv @@ -62,8 +62,6 @@ module floo_vc_narrow_wide_chimney parameter bit CutRsp = 1'b1, /// Type for implementation inputs and outputs parameter type sram_cfg_t = logic, - /// Number of routes in the routing table - parameter int unsigned NumRoutes = 0, /// Used for ID-based and XY routing parameter int unsigned IdWidth = 0, //on which port the chimney is connected to the router (as seen from the router) @@ -80,7 +78,15 @@ module floo_vc_narrow_wide_chimney parameter int WormholeVCDepth = 3, /// Used for ID-based routing parameter int unsigned NumAddrRules = 0, - parameter type addr_rule_t = logic + parameter type addr_rule_t = logic, + /// Number of System Address Map Rules + parameter int unsigned SamNumRules = 0, + /// Type of System Address Map Rule + parameter type sam_rule_t = logic, + /// System Address Map + parameter sam_rule_t [SamNumRules-1:0] Sam = '0, + /// Number of routes in the routing table + parameter int unsigned NumRoutes = 0 ) ( input logic clk_i, input logic rst_ni, @@ -970,8 +976,8 @@ module floo_vc_narrow_wide_chimney .RouteAlgo ( RouteAlgo ), .IdWidth ( IdWidth ), .id_t ( id_t ), - .NumAddrRules ( NumAddrRules ), - .addr_rule_t ( addr_rule_t ) + .NumAddrRules ( SamNumRules ), + .addr_rule_t ( sam_rule_t ) ) i_floo_req_look_ahead_routing ( .clk_i, .rst_ni, @@ -988,8 +994,8 @@ module floo_vc_narrow_wide_chimney .RouteAlgo ( RouteAlgo ), .IdWidth ( IdWidth ), .id_t ( id_t ), - .NumAddrRules ( NumAddrRules ), - .addr_rule_t ( addr_rule_t ) + .NumAddrRules ( SamNumRules ), + .addr_rule_t ( sam_rule_t ) ) i_floo_rsp_look_ahead_routing ( .clk_i, .rst_ni, @@ -1006,8 +1012,8 @@ module floo_vc_narrow_wide_chimney .RouteAlgo ( RouteAlgo ), .IdWidth ( IdWidth ), .id_t ( id_t ), - .NumAddrRules ( NumAddrRules ), - .addr_rule_t ( addr_rule_t) + .NumAddrRules ( SamNumRules ), + .addr_rule_t ( sam_rule_t ) ) i_floo_wide_look_ahead_routing ( .clk_i, .rst_ni, diff --git a/hw/floo_vc_narrow_wide_pkg.sv b/hw/floo_vc_narrow_wide_pkg.sv index b4fd0ec6..56233d68 100644 --- a/hw/floo_vc_narrow_wide_pkg.sv +++ b/hw/floo_vc_narrow_wide_pkg.sv @@ -135,14 +135,6 @@ package floo_vc_narrow_wide_pkg; - ///////////////////// - // Address Map // - ///////////////////// - - localparam int unsigned SamNumRules = 1; - typedef logic sam_rule_t; - localparam sam_rule_t Sam = '0; - //////////////////////// // Flits Typedefs // //////////////////////// diff --git a/pyproject.toml b/pyproject.toml index 45273109..0e4df9ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,6 @@ suggestion-mode = 'yes' [tool.pylint.disable] disable = [ "C0114", # Missing module docstring - "R0801" # Similar lines in 2 files, TODO: Remove this once FlooGen is integrated into FlooNoC ] [tool.black] diff --git a/util/visualize_traffic.py b/util/visualize_traffic.py index 0cb482c3..eee8c3d5 100644 --- a/util/visualize_traffic.py +++ b/util/visualize_traffic.py @@ -37,7 +37,7 @@ def clog2(x: int): def gen_mesh_traffic(): - # pylint: disable=too-many-arguments, too-many-locals, too-many-branches, too-many-statements + # pylint: disable=too-many-arguments, too-many-locals, too-many-branches, too-many-statements, duplicate-code """Generate Mesh traffic.""" jobs = [] for x in range(1, NUM_X + 1):