@@ -22,26 +22,38 @@ def _camelcase(value: str) -> str:
2222 return "" .join (word .capitalize () for word in words )
2323
2424
25- def run (root_node : node .AddrmapNode , out_dir : Path ) -> None :
26- """Export RDL to opentitan RTL."""
25+ def run (root_node : node .AddrmapNode , out_dir : Path , is_soc : bool = False ) -> None :
26+ """Export RDL to opentitan RTL.
27+
28+ IS_SOC: True if the root node is a SoC with peripherals/devices.
29+ """
2730 factory = OtInterfaceBuilder ()
28- data = factory .parse_root (root_node )
31+ data = factory .parse_soc ( root_node ) if is_soc else factory . parse_ip_block (root_node )
2932
3033 Path (out_dir / "rdl.json" ).write_text (json .dumps (data , indent = 2 ), encoding = "utf-8" )
3134
35+ if not is_soc :
36+ _export (data , out_dir )
37+ return
38+
39+ for ip_block in data ["devices" ]:
40+ _export (ip_block , out_dir )
41+
42+
43+ def _export (ip_block : dict , out_dir : Path ) -> None :
3244 file_loader = FileSystemLoader (TEMPLATES_DIR )
3345 env = Environment (loader = file_loader )
3446 env .filters ["camelcase" ] = _camelcase
3547
36- ip_name = data ["ip_name" ]
48+ ip_name = ip_block ["ip_name" ]. lower ()
3749 reg_pkg_tpl = env .get_template ("reg_pkg.sv.tpl" )
38- stream = reg_pkg_tpl .render (data )
50+ stream = reg_pkg_tpl .render (ip_block )
3951 path = out_dir / f"{ ip_name } _reg_pkg.sv"
4052 path .open ("w" ).write (stream )
4153 print (f"Generated { path } ." )
4254
4355 reg_top_tpl = env .get_template ("reg_top.sv.tpl" )
44- for interface in data ["interfaces" ]:
56+ for interface in ip_block ["interfaces" ]:
4557 name = "_{}" .format (interface ["name" ].lower ()) if "name" in interface else ""
4658 data_ = {"ip_name" : ip_name , "interface" : interface }
4759 stream = reg_top_tpl .render (data_ ).replace (" \n " , "\n " )
@@ -193,14 +205,10 @@ def get_interface(self, addrmap: node.AddrmapNode, defalt_name: None | str = Non
193205 self .any_shadowed_reg = False
194206 self .async_registers .clear ()
195207
196- if addrmap .is_array :
197- print (f"WARNING: Unsupported array type: { type (addrmap )} , skiping..." )
198-
199208 interface = {}
200209 if defalt_name :
201210 interface ["name" ] = addrmap .inst_name or defalt_name
202211
203- interface ["offset" ] = addrmap .address_offset
204212 interface ["regs" ] = []
205213 interface ["windows" ] = []
206214 for child in addrmap .children ():
@@ -247,25 +255,26 @@ def get_interface(self, addrmap: node.AddrmapNode, defalt_name: None | str = Non
247255 ]
248256 return interface
249257
250- def parse_root (self , root : node .AddrmapNode ) -> dict :
251- """Parse the root node and return a dictionary representing a window."""
252- if root .is_array :
253- print ("Error: Unsupported array type on the top" )
254- raise RuntimeError
255- if not isinstance (root , node .AddrmapNode ):
256- print ("Error: Top level must be an addrmap" )
257- raise TypeError
258-
258+ def parse_ip_block (self , ip_block : node .AddrmapNode ) -> dict :
259+ """Parse the ip_block node of an IP block and return a dictionary."""
259260 obj = {}
260- params = self .get_paramesters (root )
261+ params = self .get_paramesters (ip_block )
261262 if params :
262263 obj ["parameters" ] = params
263- obj ["ip_name" ] = root .inst_name
264- obj ["offset" ] = root .address_offset
264+ obj ["ip_name" ] = ip_block .inst_name
265+
266+ obj ["offsets" ] = []
267+ if ip_block .is_array :
268+ offset = ip_block .raw_address_offset
269+ for _idx in range (ip_block .array_dimensions [0 ]):
270+ obj ["offsets" ].append (offset )
271+ offset += ip_block .array_stride
272+ else :
273+ obj ["offsets" ].append (ip_block .address_offset )
265274
266275 obj ["interfaces" ] = []
267276 obj ["alerts" ] = []
268- for child in root .children ():
277+ for child in ip_block .children ():
269278 if isinstance (child , node .AddrmapNode ):
270279 child_obj = self .get_interface (child , DEFAULT_INTERFACE_NAME )
271280 obj ["interfaces" ].append (child_obj )
@@ -279,10 +288,24 @@ def parse_root(self, root: node.AddrmapNode) -> dict:
279288 )
280289 raise TypeError
281290
282- # If the root contain imediate registers, use a default interface name
283- if len (root .registers ()) > 0 :
284- interface = self .get_interface (root )
291+ # If the ip_block contain imediate registers, use a default interface name
292+ if len (ip_block .registers ()) > 0 :
293+ interface = self .get_interface (ip_block )
285294 obj ["interfaces" ].append (interface )
286295 obj ["alerts" ].extend (interface ["alerts" ])
287296
288297 return obj
298+
299+ def parse_soc (self , root : node .AddrmapNode ) -> dict :
300+ """Parse the SoC root node and return a dictionary."""
301+ if root .is_array :
302+ print ("Error: Unsupported array type on the top" )
303+ raise RuntimeError
304+ if not isinstance (root , node .AddrmapNode ):
305+ print ("Error: Top level must be an addrmap" )
306+ raise TypeError
307+
308+ obj = {"devices" : []}
309+ for child in root .children ():
310+ obj ["devices" ].append (self .parse_ip_block (child ))
311+ return obj
0 commit comments