diff --git a/CHANGELOG.md b/CHANGELOG.md index 683ae44a..d950cae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - All the various `*Cfg`'s is now rendered by _FlooGen_, either in the `*_noc_pkg` or in the `*_noc` module itself. - Added support for single-AXI configuration networks. - Support for negative increments when specifying a `src_range` or `dst_range` in the `connections` schema. +- Add support for multiple non-contiguous address ranges for endpoints. ### Changed diff --git a/floogen/examples/terapool.yml b/floogen/examples/terapool.yml index c9a4d748..87da3999 100644 --- a/floogen/examples/terapool.yml +++ b/floogen/examples/terapool.yml @@ -51,13 +51,15 @@ endpoints: array: [16] addr_range: base: 0x0000_8000_0000 - size: 0x0000_4000_0000 + size: 0x0000_0400_0000 sbr_port_protocol: - "wide_out" - name: "peripherals" addr_range: - start: 0x0000_0000_0000 - end: 0x0000_0fff_ffff + - start: 0x0000_0000_0000 + end: 0x0000_7fff_ffff + - start: 0x0000_C000_0000 + end: 0x0000_C000_ffff mgr_port_protocol: - "wide_in" sbr_port_protocol: diff --git a/floogen/model/endpoint.py b/floogen/model/endpoint.py index 7fa51348..935972dc 100644 --- a/floogen/model/endpoint.py +++ b/floogen/model/endpoint.py @@ -21,7 +21,7 @@ class EndpointDesc(BaseModel): name: str description: Optional[str] = "" array: Optional[Union[Tuple[int], Tuple[int, int]]] = None - addr_range: Optional[AddrRange] = None + addr_range: List[AddrRange] = [] xy_id_offset: Optional[Id] = None mgr_port_protocol: Optional[List[str]] = None sbr_port_protocol: Optional[List[str]] = None @@ -44,6 +44,14 @@ def dict_to_coord_obj(cls, v): case {"x": x, "y": y}: return Coord(x=x, y=y) + @field_validator("addr_range", mode="before") + @classmethod + def addr_range_to_list(cls, v): + """Convert single AddrRange to list.""" + if not isinstance(v, List): + return [v] + return v + @model_validator(mode="after") def check_addr_range(self): """Check if the address range is valid.""" diff --git a/floogen/model/network.py b/floogen/model/network.py index 81024141..9a9c32ea 100644 --- a/floogen/model/network.py +++ b/floogen/model/network.py @@ -489,7 +489,7 @@ def compile_nis(self): "name": f"{ni_name}", "endpoint": ep_desc, "routing": self.routing, - "addr_range": ep_desc.addr_range.model_copy() if ep_desc.addr_range else None, + "addr_range": [rng.model_copy() for rng in ep_desc.addr_range], "id": self.graph.get_node_id(node_name=ni_name).model_copy(), "uid": self.graph.get_node_uid(node_name=ni_name).model_copy(), } @@ -505,7 +505,9 @@ def compile_nis(self): case (_,): node_idx = self.graph.get_node_arr_idx(ni_name)[0] if ep_desc.is_sbr(): - ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(node_idx) + ni_dict["addr_range"] = [ + rng.model_copy().set_idx(node_idx) for rng in ep_desc.addr_range + ] # 2D array case case (_, n): @@ -513,8 +515,9 @@ def compile_nis(self): idx = x * n + y ni_dict["arr_idx"] = Coord(x=x, y=y) if ep_desc.is_sbr(): - ni_dict["addr_range"] = ep_desc.addr_range.model_copy().set_idx(idx) - + ni_dict["addr_range"] = [ + rng.model_copy().set_idx(idx) for rng in ep_desc.addr_range + ] # Invalid case case _: raise ValueError("Invalid endpoint array description") @@ -605,7 +608,7 @@ def gen_xy_routing_info(self): min_y = min(ni.id.y for ni in ni_nodes) max_x = max(ni.id.x for ni in ni_nodes) max_y = max(ni.id.y for ni in ni_nodes) - max_address = max(ni.addr_range.end for ni in ni_sbr_nodes) + max_address = max(max(rng.end for rng in ni.addr_range) for ni in ni_sbr_nodes) xy_routing_info = {} xy_routing_info["num_x_bits"] = clog2(max_x - min_x + 1) xy_routing_info["num_y_bits"] = clog2(max_y - min_y + 1) @@ -654,9 +657,9 @@ def gen_sam(self): dest = ni.id if self.routing.xy_id_offset is not None: dest -= self.routing.xy_id_offset - addr_range = ni.addr_range - addr_rule = RouteMapRule(dest=dest, addr_range=addr_range, desc=ni.name) - addr_table.append(addr_rule) + for addr_range in ni.addr_range: + addr_rule = RouteMapRule(dest=dest, addr_range=addr_range, desc=ni.name) + addr_table.append(addr_rule) return RouteMap(name="sam", rules=addr_table) def render_ports(self, pkg_name=""): diff --git a/floogen/model/network_interface.py b/floogen/model/network_interface.py index 82b60c4e..dff6e905 100644 --- a/floogen/model/network_interface.py +++ b/floogen/model/network_interface.py @@ -5,7 +5,7 @@ # # Author: Tim Fischer -from typing import Optional, ClassVar +from typing import Optional, ClassVar, List from importlib.resources import files, as_file from pydantic import BaseModel @@ -29,7 +29,7 @@ class NetworkInterface(BaseModel): id: Optional[Id] = None uid: Optional[SimpleId] = None arr_idx: Optional[Id] = None - addr_range: Optional[AddrRange] = None + addr_range: Optional[List[AddrRange]] = None def is_sbr(self) -> bool: """Return true if the network interface is a subordinate.""" diff --git a/floogen/model/routing.py b/floogen/model/routing.py index 20bb73d5..4d59e781 100644 --- a/floogen/model/routing.py +++ b/floogen/model/routing.py @@ -207,7 +207,7 @@ def validate_input(self): def validate_output(self): """Validate the address range.""" if self.start >= self.end: - raise ValueError("Invalid address range") + raise ValueError("Address range start must be less than end") return self def set_idx(self, idx):