blob: 4ac5d73364a561c1e27cfb9dcc01a300af1838d2 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
import logging as log
from .item import Node, NodeType
from .xbar import Xbar
def elaborate(xbar: Xbar) -> bool:
"""elaborate reads all nodes and edges then
construct internal FIFOs, Sockets.
"""
# Condition check
if len(xbar.nodes) <= 1 or len(xbar.edges) == 0:
log.error(
"# of Nodes is less than 2 or no Edge exists. Cannot proceed.")
return False
for host in xbar.hosts:
process_node(host, xbar)
log.info("Node Processed: " + repr(xbar))
# Pipeline
process_pipeline(xbar)
# Build address map
# Each socket_1n should have address map
return True
def process_node(node, xbar): # node: Node -> xbar: Xbar -> Xbar
"""process each node based on algorithm
1. If a node has different clock from main clock and not ASYNC_FIFO:
a. (New Node) Create ASYNC_FIFO node.
b. Revise every edges from the node to have start node as ASYNC_FIFO
node. (New Edge) create a edge from the node to ASYNC_FIFO node.
- Repeat the algorithm with ASYNC_FIFO node.
c. Revise every edges to the node to have end node as ASYNC_FIFO
node. (New Edge) create a edge from ASYNC_FIFO node to the node.
d. If it is not DEVICE, HOST node, raise Error. If it is DEVICE, end
(next item).
2. If a node has multiple edges having it as a end node and not SOCKET_M1:
a. (New node) Create SOCKET_M1 node.
b. Revise every edges to the node to have SOCKET_M1 node as end node.
c. (New Edge) create a edge from SOCKET_M1 to the node.
d. Repeat the algorithm with the node.
3. If a node has multiple edges having it as a start node and not SOCKET_1N:
a. (New node) Create SOCKET_1N node.
b. Revise every edges from the node to have SOCKET_1N node as start node.
c. (New Edge) Create a edge from the node to SOCKET_1N node.
d. (for loop) Repeat the algorithm with SOCKET_1N's other side node.
"""
# If a node has different clock from main clock and not ASYNC_FIFO:
if node.node_type != NodeType.ASYNC_FIFO and node.clocks[0] != xbar.clock:
# (New Node) Create ASYNC_FIFO node
new_node = Node(name="asf_" + str(len(xbar.nodes)),
node_type=NodeType.ASYNC_FIFO,
clock=xbar.clock,
reset=xbar.reset)
# if node is HOST, host clock synchronizes into xbar domain
# if node is DEVICE, xbar synchronizes into device clock domain
if node.node_type == NodeType.HOST:
new_node.clocks.insert(0, node.clocks[0])
new_node.resets.insert(0, node.resets[0])
else:
new_node.clocks.append(node.clocks[0])
new_node.resets.append(node.resets[0])
xbar.insert_node(new_node, node)
process_node(new_node, xbar)
# If a node has multiple edges having it as a end node and not SOCKET_M1:
elif node.node_type != NodeType.SOCKET_M1 and len(node.us) > 1:
# (New node) Create SOCKET_M1 node
new_node = Node(name="sm1_" + str(len(xbar.nodes)),
node_type=NodeType.SOCKET_M1,
clock=xbar.clock,
reset=xbar.reset)
# By default, assume connecting to SOCKET_1N upstream and bypass all FIFOs
# If upstream requires pipelining, it will be added through process pipeline
new_node.hdepth = 0
new_node.hreq_pass = 2**len(node.us) - 1
new_node.hrsp_pass = 2**len(node.us) - 1
new_node.ddepth = 0
new_node.dreq_pass = 1
new_node.drsp_pass = 1
xbar.insert_node(new_node, node)
process_node(new_node, xbar)
# If a node has multiple edges having it as a start node and not SOCKET_1N:
elif node.node_type != NodeType.SOCKET_1N and len(node.ds) > 1:
# (New node) Create SOCKET_1N node
new_node = Node(name="s1n_" + str(len(xbar.nodes)),
node_type=NodeType.SOCKET_1N,
clock=xbar.clock,
reset=xbar.reset)
# By default, assume connecting to SOCKET_M1 downstream and bypass all FIFOs
# If upstream requires pipelining, it will be added through process pipeline
new_node.hdepth = 0
new_node.hreq_pass = 1
new_node.hrsp_pass = 1
new_node.ddepth = 0
new_node.dreq_pass = 2**len(node.ds) - 1
new_node.drsp_pass = 2**len(node.ds) - 1
xbar.insert_node(new_node, node)
# (for loop) Repeat the algorithm with SOCKET_1N's other side node
for edge in new_node.ds:
process_node(edge.ds, xbar)
return xbar
def process_pipeline(xbar):
"""Check if HOST, DEVICE has settings different from default, then propagate it to end
"""
for host in xbar.hosts:
# go downstream and change the HReqPass/Depth at the first instance.
# If it is async, skip.
# If Socket 1N,
# if pipeline True and bypass false, set hpass to 0
# if pipeline is False, set depth to 0
# If Socket M1, find position of the host and follow procedure above
# If it is device, it means host and device are directly connected. Ignore now.
log.info("Processing pipeline for host {}".format(host.name))
fifo_pass = host.req_fifo_pass or host.rsp_fifo_pass
# FIFO present with no passthrough option
# FIFO present with passthrough option
# FIFO not present and full passthrough
full_fifo = False
fifo_passthru = False
full_passthru = True
if host.pipeline is True and fifo_pass is False:
full_fifo = True
elif host.pipeline is True and fifo_pass is True:
fifo_passthru = True
elif host.pipeline is False:
full_passthru = True
dnode = host.ds[0].ds
if dnode.node_type == NodeType.ASYNC_FIFO:
continue
req_pass = 1 if host.req_fifo_pass else 0
rsp_pass = 1 if host.rsp_fifo_pass else 0
if dnode.node_type == NodeType.SOCKET_1N:
if full_fifo:
dnode.hreq_pass = 0
dnode.hrsp_pass = 0
dnode.hdepth = 1
elif fifo_passthru:
dnode.hreq_pass = req_pass
dnode.hrsp_pass = rsp_pass
dnode.hdepth = 1
elif full_passthru:
dnode.hreq_pass = 1
dnode.hrsp_pass = 1
dnode.hdepth = 0
log.info(
"Finished processing socket1n {}, req pass={}, rsp pass={}, depth={}".format(
dnode.name, dnode.hreq_pass, dnode.hrsp_pass, dnode.hdepth))
elif dnode.node_type == NodeType.SOCKET_M1:
idx = dnode.us.index(host.ds[0])
# first clear out entry
dnode.hreq_pass = dnode.hreq_pass & ~(1 << idx)
dnode.hreq_pass = dnode.hreq_pass & ~(1 << idx)
if full_fifo:
log.info("fifo present no bypass")
dnode.hdepth = dnode.hdepth | (1 << idx * 4)
elif fifo_passthru:
log.info("fifo present with bypass")
dnode.hreq_pass = dnode.hreq_pass | (req_pass << idx)
dnode.hreq_pass = dnode.hrsp_pass | (rsp_pass << idx)
dnode.hdepth = dnode.hdepth | (1 << idx * 4)
elif full_passthru:
log.info("fifo not present")
dnode.hreq_pass = dnode.hreq_pass | (1 << idx)
dnode.hreq_pass = dnode.hrsp_pass | (1 << idx)
dnode.hdepth = dnode.hdepth & ~(0xF << idx * 4)
log.info(
"Finished processing socketm1 {}, req pass={}, rsp pass={}, depth={}".format(
dnode.name, dnode.hreq_pass, dnode.hrsp_pass, dnode.hdepth))
for device in xbar.devices:
# go upstream and set DReq/RspPass at the first instance.
# If it is async, skip
# If Socket M1
# If pipeline True and bypass False, set dpass to 0
# If pipeline False, set depth to 0
# If Socket 1N, find position of the device and follow procedure above
# If it is host, ignore
log.info("Processing pipeline for device {}".format(device.name))
# FIFO present with no passthrough option
# FIFO present with passthrough option
# FIFO not present and full passthrough
fifo_pass = device.req_fifo_pass or device.rsp_fifo_pass
full_fifo = False
fifo_passthru = False
full_passthru = True
if device.pipeline is True and fifo_pass is False:
full_fifo = True
elif device.pipeline is True and fifo_pass is True:
fifo_passthru = True
elif device.pipeline is False:
full_passthru = True
unode = device.us[0].us
if unode.node_type == NodeType.ASYNC_FIFO:
continue
req_pass = 1 if device.req_fifo_pass else 0
rsp_pass = 1 if device.rsp_fifo_pass else 0
if unode.node_type == NodeType.SOCKET_1N:
idx = unode.ds.index(device.us[0])
# first clear out entry
unode.dreq_pass = unode.dreq_pass & ~(1 << idx)
unode.drsp_pass = unode.drsp_pass & ~(1 << idx)
if full_fifo:
unode.ddepth = unode.ddepth | (1 << idx * 4)
elif fifo_passthru:
unode.dreq_pass = unode.dreq_pass | (req_pass << idx)
unode.drsp_pass = unode.drsp_pass | (rsp_pass << idx)
unode.ddepth = unode.ddepth | (1 << idx * 4)
elif full_passthru:
unode.dreq_pass = unode.dreq_pass | (1 << idx)
unode.drsp_pass = unode.drsp_pass | (1 << idx)
unode.ddepth = unode.ddepth & ~(0xF << idx * 4)
log.info("Finished processing socket1n {}, req pass={:x}, req pass={:x} depth={:x}".
format(unode.name, unode.dreq_pass, unode.drsp_pass, unode.ddepth))
elif unode.node_type == NodeType.SOCKET_M1:
if full_fifo:
log.info("Fifo present with no passthrough")
unode.dreq_pass = 0
unode.drsp_pass = 0
unode.ddepth = 1
elif fifo_passthru:
log.info("Fifo present with passthrough")
unode.dreq_pass = req_pass
unode.drsp_pass = rsp_pass
unode.ddepth = 1
elif full_passthru:
log.info("No Fifo")
unode.dreq_pass = 1
unode.drsp_pass = 1
unode.ddepth = 0
log.info("Finished processing socketm1 {}, req pass={:x}, rsp pass={:x}, depth={:x}".
format(unode.name, unode.dreq_pass, unode.drsp_pass, unode.ddepth))
return xbar