-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate_sv.py
executable file
·96 lines (74 loc) · 3.49 KB
/
generate_sv.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
#!/usr/bin/env python3
import sys
from pathlib import Path
from typing import Dict, List
from systemrdl import RDLCompileError, RDLCompiler
from systemrdl.node import AddressableNode, RegfileNode
processed: List[AddressableNode] = []
def _collect_registers(node: AddressableNode, offset: int) -> Dict[int, str]:
registers = {}
# add the registers of the current node
for reg in node.registers():
if not (reg in processed):
processed.append(reg)
if str(reg.inst_name) != "RFU":
addr = int(offset + node.raw_address_offset + reg.raw_address_offset)
registers[addr] = str(reg.inst_name)
# flatten the register space and include any registers in children nodes that are not arrays
for child in node.children():
if isinstance(child, RegfileNode):
if not (child in processed):
if not child.is_array:
processed.append(child)
registers = {**registers, **_collect_registers(child, offset)}
return registers
def _generate_system_verilog(node: AddressableNode, alignment: int) -> str:
contents = ""
# create localparam of the top nodes
registers = _collect_registers(node, 0)
if registers:
contents = " localparam\n"
for addr, name in sorted(registers.items()):
contents = contents + f" {name} = {int(addr / alignment)},\n"
contents = contents[:-2] + ";\n"
# create localparam out of register array nodes
for child in node.children():
if isinstance(child, RegfileNode):
if not (child in processed):
if child.is_array:
processed.append(child)
start = int(child.raw_address_offset)
repeat = int(child.array_dimensions[0])
stride = int(child.array_stride)
# create array offset localparam
contents = contents + f"\n localparam [({repeat}*32)-1:0] {child.inst_name}_OFFSET = {{\n"
for x in range(repeat, 0, -1):
contents = contents + f" 32'd{int((start + ((x - 1) * stride)) / alignment)},\n"
contents = contents[:-2] + "\n };\n"
# create array register localparam
registers = _collect_registers(child, -start)
if registers:
contents = contents + "\n localparam\n"
for addr, name in sorted(registers.items()):
contents = contents + f" {name} = {int(addr / alignment)},\n"
contents = contents[:-2] + ";\n"
return contents
if __name__ == "__main__":
"""Generates SystemVerilog code from a single SystemRDL file."""
# the first argument must be the SystemRDL file
system_rdl = sys.argv[1]
if Path(system_rdl).suffix != ".rdl":
sys.exit(1)
# parse SystemRDL config file and produce a node tree
rdlc = RDLCompiler()
try:
rdlc.compile_file(system_rdl)
root = rdlc.elaborate()
except RDLCompileError:
sys.exit(1)
# name of the root node becomes the file name of the SystemVerilog header
filename = root.top.inst_name
alignment = root.top.get_property('alignment', default=1)
# parse SystemRDL node tree and generate SystemVerilog code
with open(f'{filename}.svh', 'w') as code:
code.write(_generate_system_verilog(root.top, alignment))