-
Notifications
You must be signed in to change notification settings - Fork 3
/
common.py
103 lines (81 loc) · 3.78 KB
/
common.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# SPDX-License-Identifier: Apache-2.0
import re
from math import log2
class ConfigException(Exception):
pass
# General I3C configuration
# Contains parameters defined in the YAML configuration file
# and is utilized to separate subset of configurations for
# used tooling
# The the properties defined in the i3c_core_config.schema.json
class I3CGenericConfig:
def __init__(self, dict_cfg: dict, schema: dict):
self.__dict__ = dict_cfg
# Go over schema-defined fields
for n in schema:
# If the value for the parameter was passed in the YAML configuration
if n in dict_cfg:
value = dict_cfg[n]
# Otherwise, if schema specifies such, take the default value
elif "default" in schema[n]:
value = schema[n]["default"]
# Otherwise, not applicable
else:
continue
setattr(self, n, value)
def items(self):
return self.__dict__.items()
# Configuration parameters necessary to generate registers from SystemRDL
class RegGenConfig:
_params = {}
def __init__(self, cfg: I3CGenericConfig):
# Convert supplied FIFO depths to I3C CSR representations
self._params["cmd_fifo_size"] = cfg.CmdFifoDepth # Size in entries
self._params["resp_fifo_size"] = cfg.RespFifoDepth # Size in entries
# Size of the TX / RX fifos is encoded in the CSRs as 2^(N+1)
# where N is value in the size CSR
self._params["tx_fifo_size"] = int(log2(cfg.TxFifoDepth) - 1)
self._params["rx_fifo_size"] = int(log2(cfg.RxFifoDepth) - 1)
# Size in entries, or 8*N if `cfg.IbiFifoExtSize`
self._params["ibi_fifo_size"] = cfg.IbiFifoDepth
self._params["ext_ibi_size"] = int(cfg.IbiFifoExtSize)
self._params["dat_depth"] = cfg.DatDepth - 1
self._params["dct_depth"] = cfg.DctDepth - 1
def items(self):
return self._params.items()
# RTL configuration parameters, to be included with I3C top module
class I3CCoreConfig:
_defines = {} # List of parameters to be defined in I3C configuration file
def __init__(self, cfg: I3CGenericConfig) -> None:
bus = cfg.FrontendBusInterface
# Parse to SVH format
for name, value in cfg.items():
# Map BusInterface -> I3C_USE_[AXI|AHB]
if "BusInterface" in name:
self._defines[f"I3C_USE_{bus}"] = 1
continue
# For those parameters that map directly, change the name format:
# PascalCase -> UPPER_SNAKE_CASE
new_name = self._format_name(name).replace("FRONTEND_BUS", bus)
# Resolve the parameter type (i.e. booleans)
self._defines[new_name] = self._py_to_sv_type(value, name)
# Change camel case name format to upper snake case
def _format_name(self, name: str) -> str:
return re.sub(r"(?<!^)(?=[A-Z])", "_", name).upper()
def _py_to_sv_type(self, element: any, name: str) -> int | str:
match element:
case bool(): # Bool is not supported, use 0 or 1
return int(element)
case str(): # Ensure the resulting definition contains ""
return f'"{element}"'
case list(): # Run recursively on each element & return a string
return "{" + ", ".join([self._py_to_sv_type(e) for e in element]) + "}"
case int(): # TODO: Maybe could also handle widths?
return element
case _: # Should've been reported when validating against schema
raise Exception(
f"Encountered an unsupported type {type(element)} for {name}"
"while converting the configuration"
)
def items(self):
return self._defines.items()