blob: c8d0755d0982a108a0717e7614ade1df3f93e1e4 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4
5import logging as log
lowRISC Contributors802543a2019-08-31 12:12:56 +01006
Eunchan Kim837c7962020-04-30 12:15:49 -07007from .item import Edge, NodeType
lowRISC Contributors802543a2019-08-31 12:12:56 +01008
9
10class Xbar:
11 """Xbar contains configurations to generate TL-UL crossbar.
12 """
lowRISC Contributors802543a2019-08-31 12:12:56 +010013 def __init__(self):
Weicai Yang88ced022020-11-30 15:34:56 -080014 self.clock = "" # str # primary clock of xbar
15 self.reset = "" # str # primary reset of xbar
16 self.name = "" # str # e.g. "main" --> main_xbar
17 self.ip_path = "" # additional path to generated rtl/dv folders: outdir/ip_path/rtl
18
lowRISC Contributors802543a2019-08-31 12:12:56 +010019 self.blocks = []
20 self.nodes = []
21 self.edges = []
22 self.clocks = []
Timothy Chen09d859b2019-11-08 14:01:12 -080023 self.resets = []
lowRISC Contributors802543a2019-08-31 12:12:56 +010024
25 def __repr__(self):
Weicai Yanga60ae7d2020-02-21 14:32:50 -080026 out = "<Xbar(%s) #nodes:%d clock:%s" % (self.name, len(
27 self.nodes), self.clock)
lowRISC Contributors802543a2019-08-31 12:12:56 +010028 out += " #edges:%d>\n" % (len(self.edges))
29
30 # print nodes
31 out += " Nodes:\n"
32 for node in self.nodes:
33 out += " - " + node.name + "\n"
34
35 out += " Edges:\n"
36 for edge in self.edges:
37 out += " - " + edge.us.name + " => " + edge.ds.name + "\n"
38 # print edges
39 return out
40
41 def get_edges_from_node(self, node): # Node -> Edges
42 return [
43 edge for edge in self.edges
44 if node.name in (edge.us.name, edge.ns.name)
45 ]
46
47 def get_node(self, node): # str -> Node
48 result = [x for x in self.nodes if x.name == node]
49 if len(result) != 1:
50 raise # Exception
51
52 return result[0]
53
54 @property
55 def hosts(self):
56 return [x for x in self.nodes if x.node_type == NodeType.HOST]
57
58 @property
59 def devices(self):
60 return [x for x in self.nodes if x.node_type == NodeType.DEVICE]
61
62 @property
63 def socket_1ns(self):
64 return [x for x in self.nodes if x.node_type == NodeType.SOCKET_1N]
65
66 def get_downstream_device(self, node): # Node -> Node
67 if (node.node_type == NodeType.DEVICE):
68 return node
69
70 if len(node.ds) == 0:
Weicai Yanga60ae7d2020-02-21 14:32:50 -080071 log.error(
72 "Node (%s) doesn't have downstream Node: US(%s), DS(%s)" %
73 (node.name, ' '.join(map(repr, node.us)), ' '.join(
74 map(repr, node.ds))))
lowRISC Contributors802543a2019-08-31 12:12:56 +010075 return self.get_downstream_device(node.ds[0].ds)
76
77 def get_downstream_device_from_edge(self, edge): # Edge -> Node
78 return self.get_downstream_device(edge.ds)
79
80 def get_leaf_from_s1n(self, node, idx): # Node -> int -> Node
81 """ get end-device node from Socket_1n's Downstream port
82
83 Current implementation can't have multiple devices under the tree of
84 one downstream port in Socket_1N
85 """
86 return self.get_downstream_device(node.ds[idx].ds)
87
88 def get_s1n_if_exist(self, node): # Node -> Node
89 """ return SOCKET_1N if exists down from the node, if not return itself
90 """
91 if node.node_type == NodeType.DEVICE:
92 log.error("get_s1n_if_exist hits DEVICE type (unexpected)")
93 return node
94 if node.node_type == NodeType.SOCKET_1N:
95 return node
96 return self.get_s1n_if_exist(node.ds[0].ds)
97
98 def get_leaf_from_node(self, node, idx): # Node -> int -> Node
99 """ get end device node from any node, idx is given to look down.
100 """
101 num_dev = len(self.get_s1n_if_exist(node).ds)
102 if idx >= num_dev:
103 log.error(
104 "given index is greater than number of devices under the node")
105
106 return self.get_leaf_from_s1n(self.get_s1n_if_exist(node), idx)
107
108 def get_devices_from_host(self, host): # Node -> Nodes
109 devices = list(
110 map(self.get_downstream_device_from_edge,
111 self.get_s1n_if_exist(host).ds))
112
113 return devices
114
115 def get_addr(self, device): # Node -> Tuple[int,int]
116 if device.node_type != NodeType.DEVICE:
117 log.error("get_addr receives non DEVICE type node")
118
119 return (device.address_from, device.address_to)
120
121 def connect_nodes(self, u_node, d_node): # str -> str -> bool
122 # Create edges between Nodes
123 # Return false if Nodes aren't exist or same connection exists
124 upNode = self.get_node(u_node)
125 dnNode = self.get_node(d_node)
126
127 edge = Edge(upNode, dnNode)
128
129 if any([
130 e.us.name == edge.us.name and e.ds.name == edge.ds.name
131 for e in self.edges
132 ]):
133 return False
134
135 self.edges.append(edge)
136
137 upNode.ds.append(edge)
138 dnNode.us.append(edge)
139
140 return True
141
142 def insert_node(self, new_node, node):
143 if new_node.node_type == NodeType.ASYNC_FIFO:
144 if node.node_type == NodeType.HOST:
145 # Insert node to downstream
146 edge = Edge(node, new_node)
147 new_node.ds = node.ds
148 node.ds = [edge]
149 new_node.us = [edge]
150 self.nodes.append(new_node)
151 self.edges.append(edge)
152 for e in new_node.ds:
153 # replace us to new_node
154 e.us = new_node
155 elif node.node_type == NodeType.DEVICE:
156 # insert node to upstream
157 edge = Edge(new_node, node)
158 new_node.us = node.us
159 new_node.ds = node
160 node.us = [edge]
161 new_node.ds = [edge]
162 self.nodes.append(new_node)
163 self.edges.append(edge)
164 for e in new_node.us:
165 # replace us to new_node
166 e.ds = new_node
167 else:
168 raise
169 elif new_node.node_type == NodeType.SOCKET_M1:
170 # Revise every upstream
171 edge = Edge(new_node, node)
172 new_node.us = node.us
173 node.us = [edge]
174 new_node.ds = [edge]
175 self.nodes.append(new_node)
176 self.edges.append(edge)
177 for e in new_node.us:
178 e.ds = new_node
179
180 elif new_node.node_type == NodeType.SOCKET_1N:
181 # Revise every downstream
182 edge = Edge(node, new_node)
183 new_node.ds = node.ds
184 node.ds = [edge]
185 new_node.us = [edge]
186 # TODO: add new_node.us logic
187 self.nodes.append(new_node)
188 self.edges.append(edge)
189 for e in new_node.ds:
190 e.us = new_node
191 else:
192 # Caller passes HOST or DEVICE as a new node. Error!
193 log.error(
194 "Xbar.insert_node is called with HOST or DEVICE: %s. Ignored" %
195 (new_node.name))
196
197 return self
198
199 def repr_tree(self, node, indent):
200 """string format of tree connection from node to devices
201
202 Desired output:
203 host_a
204 -> asf_nn
205 -> s1n_nn
206 -> sm1_mm
207 -> device_c
208 -> sm1_nn
209 -> device_b
210
211 """
212 out = "// "
213 if indent != 0:
214 # not First
215 out += ' ' * indent + '-> '
216
217 out += node.name
218
219 if node.node_type != NodeType.DEVICE:
220 # still more nodes exist under this node
221 for ds in node.ds:
222 out += '\n'
223 out += self.repr_tree(ds.ds, indent + 2)
224
225 return out