1717DEFAULT_INTERFACE_NAME = "regs"
1818
1919
20- def run (root_node : node .AddrmapNode , out_dir : Path ) -> None :
21- """Export RDL to opentitan RTL."""
20+ def _camelcase (value : str ) -> str :
21+ words = value .split ("_" )
22+ return "" .join (word .capitalize () for word in words )
23+
24+
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+ """
2230 factory = OtInterfaceBuilder ()
23- data = factory .parse_root (root_node )
31+ data = factory .parse_soc ( root_node ) if is_soc else factory . parse_ip_block (root_node )
2432
2533 Path (out_dir / "rdl.json" ).write_text (json .dumps (data , indent = 2 ), encoding = "utf-8" )
2634
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 :
2744 file_loader = FileSystemLoader (TEMPLATES_DIR )
2845 env = Environment (loader = file_loader )
46+ env .filters ["camelcase" ] = _camelcase
2947
30- ip_name = data ["ip_name" ]
48+ ip_name = ip_block ["ip_name" ]. lower ()
3149 reg_pkg_tpl = env .get_template ("reg_pkg.sv.tpl" )
32- stream = reg_pkg_tpl .render (data )
50+ stream = reg_pkg_tpl .render (ip_block )
3351 path = out_dir / f"{ ip_name } _reg_pkg.sv"
3452 path .open ("w" ).write (stream )
3553 print (f"Generated { path } ." )
3654
3755 reg_top_tpl = env .get_template ("reg_top.sv.tpl" )
38- for interface in data ["interfaces" ]:
56+ for interface in ip_block ["interfaces" ]:
3957 name = "_{}" .format (interface ["name" ].lower ()) if "name" in interface else ""
4058 data_ = {"ip_name" : ip_name , "interface" : interface }
4159 stream = reg_top_tpl .render (data_ ).replace (" \n " , "\n " )
@@ -187,14 +205,10 @@ def get_interface(self, addrmap: node.AddrmapNode, defalt_name: None | str = Non
187205 self .any_shadowed_reg = False
188206 self .async_registers .clear ()
189207
190- if addrmap .is_array :
191- print (f"WARNING: Unsupported array type: { type (addrmap )} , skiping..." )
192-
193208 interface = {}
194209 if defalt_name :
195210 interface ["name" ] = addrmap .inst_name or defalt_name
196211
197- interface ["offset" ] = addrmap .address_offset
198212 interface ["regs" ] = []
199213 interface ["windows" ] = []
200214 for child in addrmap .children ():
@@ -233,29 +247,38 @@ def get_interface(self, addrmap: node.AddrmapNode, defalt_name: None | str = Non
233247 interface ["any_integrity_bypass" ] = any (
234248 win ["integrity_bypass" ] for win in interface ["windows" ]
235249 )
250+ interface ["alerts" ] = [
251+ f ["name" ]
252+ for reg in interface ["regs" ]
253+ for f in reg ["fields" ]
254+ if reg ["name" ] == "ALERT_TEST"
255+ ]
236256 return interface
237257
238- def parse_root (self , root : node .AddrmapNode ) -> dict :
239- """Parse the root node and return a dictionary representing a window."""
240- if root .is_array :
241- print ("Error: Unsupported array type on the top" )
242- raise RuntimeError
243- if not isinstance (root , node .AddrmapNode ):
244- print ("Error: Top level must be an addrmap" )
245- raise TypeError
246-
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."""
247260 obj = {}
248- params = self .get_paramesters (root )
261+ params = self .get_paramesters (ip_block )
249262 if params :
250263 obj ["parameters" ] = params
251- obj ["ip_name" ] = root .inst_name
252- 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 )
253274
254275 obj ["interfaces" ] = []
255- for child in root .children ():
276+ obj ["alerts" ] = []
277+ for child in ip_block .children ():
256278 if isinstance (child , node .AddrmapNode ):
257279 child_obj = self .get_interface (child , DEFAULT_INTERFACE_NAME )
258280 obj ["interfaces" ].append (child_obj )
281+ obj ["alerts" ].extend (child_obj ["alerts" ])
259282 elif isinstance (child , node .RegNode | node .MemNode | node .RegfileNode ):
260283 continue
261284 else :
@@ -265,9 +288,24 @@ def parse_root(self, root: node.AddrmapNode) -> dict:
265288 )
266289 raise TypeError
267290
268- # If the root contain imediate registers, use a default interface name
269- if len (root .registers ()) > 0 :
270- 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 )
271294 obj ["interfaces" ].append (interface )
295+ obj ["alerts" ].extend (interface ["alerts" ])
296+
297+ return obj
272298
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 ))
273311 return obj
0 commit comments