105 lines
3.1 KiB
Python
105 lines
3.1 KiB
Python
import re
|
|
from typing import Match, Union, Optional
|
|
|
|
from systemrdl.rdltypes.references import PropertyReference
|
|
from systemrdl.node import Node, AddrmapNode
|
|
|
|
from .identifier_filter import kw_filter as kwf
|
|
from .sv_int import SVInt
|
|
|
|
def get_indexed_path(top_node: Node, target_node: Node) -> str:
|
|
"""
|
|
TODO: Add words about indexing and why i'm doing this. Copy from logbook
|
|
"""
|
|
path = target_node.get_rel_path(top_node, empty_array_suffix="[!]")
|
|
|
|
# replace unknown indexes with incrementing iterators i0, i1, ...
|
|
class ReplaceUnknown:
|
|
def __init__(self) -> None:
|
|
self.i = 0
|
|
def __call__(self, match: Match) -> str:
|
|
s = f'i{self.i}'
|
|
self.i += 1
|
|
return s
|
|
path = re.sub(r'!', ReplaceUnknown(), path)
|
|
|
|
# Sanitize any SV keywords
|
|
def kw_filter_repl(m: Match) -> str:
|
|
return kwf(m.group(0))
|
|
path = re.sub(r'\w+', kw_filter_repl, path)
|
|
|
|
return path
|
|
|
|
def clog2(n: int) -> int:
|
|
return (n-1).bit_length()
|
|
|
|
def is_pow2(x: int) -> bool:
|
|
return (x > 0) and ((x & (x - 1)) == 0)
|
|
|
|
def roundup_pow2(x: int) -> int:
|
|
return 1<<(x-1).bit_length()
|
|
|
|
def ref_is_internal(top_node: AddrmapNode, ref: Union[Node, PropertyReference]) -> bool:
|
|
"""
|
|
Determine whether the reference is internal to the top node.
|
|
|
|
For the sake of this exporter, root signals are treated as internal.
|
|
"""
|
|
current_node: Optional[Node]
|
|
if isinstance(ref, Node):
|
|
current_node = ref
|
|
elif isinstance(ref, PropertyReference):
|
|
current_node = ref.node
|
|
else:
|
|
raise RuntimeError
|
|
|
|
while current_node is not None:
|
|
if current_node == top_node:
|
|
# reached top node without finding any external components
|
|
# is internal!
|
|
return True
|
|
|
|
if current_node.external:
|
|
# not internal!
|
|
return False
|
|
|
|
current_node = current_node.parent
|
|
|
|
# A root signal was referenced, which dodged the top addrmap
|
|
# This is considered internal for this exporter
|
|
return True
|
|
|
|
|
|
def do_slice(value: Union[SVInt, str], high: int, low: int) -> Union[SVInt, str]:
|
|
if isinstance(value, str):
|
|
# If string, assume this is an identifier. Append bit-slice
|
|
if high == low:
|
|
return f"{value}[{low}]"
|
|
else:
|
|
return f"{value}[{high}:{low}]"
|
|
else:
|
|
# it is an SVInt literal. Slice it down
|
|
mask = (1 << (high + 1)) - 1
|
|
v = (value.value & mask) >> low
|
|
|
|
if value.width is not None:
|
|
w = high - low + 1
|
|
else:
|
|
w = None
|
|
|
|
return SVInt(v, w)
|
|
|
|
def do_bitswap(value: Union[SVInt, str]) -> Union[SVInt, str]:
|
|
if isinstance(value, str):
|
|
# If string, assume this is an identifier. Wrap in a streaming operator
|
|
return "{<<{" + value + "}}"
|
|
else:
|
|
# it is an SVInt literal. bitswap it
|
|
assert value.width is not None # width must be known!
|
|
v = value.value
|
|
vswap = 0
|
|
for _ in range(value.width):
|
|
vswap = (vswap << 1) + (v & 1)
|
|
v >>= 1
|
|
return SVInt(vswap, value.width)
|