@@ -22,26 +22,38 @@ def _camelcase(value: str) -> str:
22
22
return "" .join (word .capitalize () for word in words )
23
23
24
24
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
+ """
27
30
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 )
29
32
30
33
Path (out_dir / "rdl.json" ).write_text (json .dumps (data , indent = 2 ), encoding = "utf-8" )
31
34
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 :
32
44
file_loader = FileSystemLoader (TEMPLATES_DIR )
33
45
env = Environment (loader = file_loader )
34
46
env .filters ["camelcase" ] = _camelcase
35
47
36
- ip_name = data ["ip_name" ]
48
+ ip_name = ip_block ["ip_name" ]. lower ()
37
49
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 )
39
51
path = out_dir / f"{ ip_name } _reg_pkg.sv"
40
52
path .open ("w" ).write (stream )
41
53
print (f"Generated { path } ." )
42
54
43
55
reg_top_tpl = env .get_template ("reg_top.sv.tpl" )
44
- for interface in data ["interfaces" ]:
56
+ for interface in ip_block ["interfaces" ]:
45
57
name = "_{}" .format (interface ["name" ].lower ()) if "name" in interface else ""
46
58
data_ = {"ip_name" : ip_name , "interface" : interface }
47
59
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
193
205
self .any_shadowed_reg = False
194
206
self .async_registers .clear ()
195
207
196
- if addrmap .is_array :
197
- print (f"WARNING: Unsupported array type: { type (addrmap )} , skiping..." )
198
-
199
208
interface = {}
200
209
if defalt_name :
201
210
interface ["name" ] = addrmap .inst_name or defalt_name
202
211
203
- interface ["offset" ] = addrmap .address_offset
204
212
interface ["regs" ] = []
205
213
interface ["windows" ] = []
206
214
for child in addrmap .children ():
@@ -247,25 +255,26 @@ def get_interface(self, addrmap: node.AddrmapNode, defalt_name: None | str = Non
247
255
]
248
256
return interface
249
257
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."""
259
260
obj = {}
260
- params = self .get_paramesters (root )
261
+ params = self .get_paramesters (ip_block )
261
262
if params :
262
263
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 )
265
274
266
275
obj ["interfaces" ] = []
267
276
obj ["alerts" ] = []
268
- for child in root .children ():
277
+ for child in ip_block .children ():
269
278
if isinstance (child , node .AddrmapNode ):
270
279
child_obj = self .get_interface (child , DEFAULT_INTERFACE_NAME )
271
280
obj ["interfaces" ].append (child_obj )
@@ -279,10 +288,24 @@ def parse_root(self, root: node.AddrmapNode) -> dict:
279
288
)
280
289
raise TypeError
281
290
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 )
285
294
obj ["interfaces" ].append (interface )
286
295
obj ["alerts" ].extend (interface ["alerts" ])
287
296
288
297
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