blob: cb11dcdd1032aad10a2fa822a571f7f93bf9ff5f [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4"""Generate SystemVerilog designs from validated register json tree
5"""
6
7import logging as log
8import operator
9import sys
10
11from mako.template import Template
Eunchan Kimcb28a172019-10-08 16:35:48 -070012from mako import exceptions
lowRISC Contributors802543a2019-08-31 12:12:56 +010013from pkg_resources import resource_filename
14
Eunchan Kimb9931902019-09-26 14:16:40 -070015from .data import *
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070016from .field_enums import HwAccess, SwAccess, SwRdAccess, SwWrAccess
lowRISC Contributors802543a2019-08-31 12:12:56 +010017
Eunchan Kim51461cd2019-09-18 14:00:49 -070018
lowRISC Contributors802543a2019-08-31 12:12:56 +010019def escape_name(name):
20 return name.lower().replace(' ', '_')
21
22
23def check_field_bool(obj, field, default):
24 if field in obj:
25 return True if obj[field] == "true" else False
26 else:
27 return default
28
29
30def parse_field(obj, reg, nfields):
31 """Convert OrderedDict field into Field class
32 """
33 f = Field()
34 f.name = escape_name(obj["name"])
35 # if name doesn't exist and only one field in a reg
36 if f.name == "" and nfields == 1:
37 f.name = reg.name
38
39 # MSB, LSB
40 f.lsb = obj["bitinfo"][2]
41 f.msb = f.lsb + obj["bitinfo"][1] - 1
42
43 #assert not 'swaccess' in obj, "R[%s] F[%s]: SwAccess in Field not supported" % (reg.name, f.name)
44 f.swaccess = obj["genswaccess"]
45 f.swrdaccess = obj["genswrdaccess"]
46 f.swwraccess = obj["genswwraccess"]
47 f.hwaccess = obj["genhwaccess"]
48 f.hwqe = obj["genhwqe"]
49 f.hwre = obj["genhwre"]
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070050 f.hwext = reg.hwext
lowRISC Contributors802543a2019-08-31 12:12:56 +010051
52 # resval handling. `genresval` has zero value if `resval` field is defined
53 # as unknown 'x'
54 f.resval = obj["genresval"]
55
56 return f
57
58
59def parse_reg(obj):
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070060 """Convert OrderedDict register into Register or MultiRegister object.
61 Supports nested MultiRegisters.
lowRISC Contributors802543a2019-08-31 12:12:56 +010062 """
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070063 if 'multireg' in obj:
64 regs = []
65 for genr in obj['multireg']['genregs']:
66 regs += [parse_reg(genr)]
67 # get register properties of the first register in the multireg and
68 # copy them to the parent
69 # since all regs in a multireg have the same props
70 reg = MultiReg(regs[0].get_reg_flat(0))
71 # since this is a multireg, the list of fields can
72 # contain regs or multiregs
73 reg.fields = regs
Michael Schaffnera2c51d92019-09-27 16:38:24 -070074 # a homogenous multireg contains only one single field that is replicated
75 reg.ishomog = len(obj['multireg']['fields']) == 1
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070076 # TODO: need to rework this once the underlying JSON has been changed
77 reg.name = escape_name(obj['multireg']['name'])
78 # TODO: need to reference proper param here such that it can be used
79 # in the package template for the array declaration
80 # reg.param = ...
81 else:
82 reg = Reg(escape_name(obj['name']))
83 reg.offset = obj["genoffset"]
84 reg.fields = []
lowRISC Contributors802543a2019-08-31 12:12:56 +010085
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070086 reg.hwext = (obj['hwext'] == "true")
87 reg.hwqe = (obj["hwqe"] == "true")
88 reg.hwre = (obj["hwre"] == "true")
89 reg.resval = obj["genresval"]
90 reg.dvrights = obj["gendvrights"]
91 reg.regwen = obj["regwen"].lower()
lowRISC Contributors802543a2019-08-31 12:12:56 +010092
Michael Schaffner9a94b6c2019-09-25 16:17:35 -070093 # Parsing Fields
94 for f in obj["fields"]:
95 field = parse_field(f, reg, len(obj["fields"]))
96 if field != None:
97 reg.fields.append(field)
98 reg.width = max(reg.width, field.msb + 1)
lowRISC Contributors802543a2019-08-31 12:12:56 +010099
Michael Schaffner9a94b6c2019-09-25 16:17:35 -0700100 # TODO(eunchan): Field bitfield overlapping check
101 log.info("R[0x%04x]: %s ", reg.offset, reg.name)
102 for f in reg.fields:
103 log.info(" F[%2d:%2d]: %s", f.msb, f.lsb, f.name)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100104
105 return reg
106
107
108def parse_win(obj, width):
109 # Convert register window fields into Window class
110 # base_addr : genoffset
111 # limit_addr : genoffset + items*width
112 win = Window()
113 win.name = obj["name"]
114 win.base_addr = obj["genoffset"]
115 win.limit_addr = obj["genoffset"] + int(obj["items"]) * (width // 8)
116 win.dvrights = obj["swaccess"]
117 win.n_bits = obj["genvalidbits"]
118
119 # TODO: Generate warnings of `noalign` or `unusual`
120 return win
121
122
123def json_to_reg(obj):
124 """Converts json OrderedDict into structure having useful information for
125 Template to use.
126
127 Main purpose of this function is:
128 - Add Offset value based on auto calculation
129 - Prepare Systemverilog data structure to generate _pkg file
130 """
131 block = Block()
132
133 # Name
134 block.name = escape_name(obj["name"])
135 log.info("Processing module: %s", block.name)
136
137 block.width = int(obj["regwidth"], 0)
138
139 if block.width != 32 and block.width != 64:
140 log.error(
141 "Current reggen tool doesn't support field width that is not 32 nor 64"
142 )
143
144 log.info("Data Width is set to %d bits", block.width)
145
Eunchan Kimc4873f32019-09-25 12:46:12 -0700146 block.params = obj["param_list"] if "param_list" in obj else []
147
lowRISC Contributors802543a2019-08-31 12:12:56 +0100148 for r in obj["registers"]:
149 # Check if any exception condition hit
150 if 'reserved' in r:
151 continue
152 elif 'skipto' in r:
153 continue
154 elif 'sameaddr' in r:
155 log.error("Current tool doesn't support 'sameaddr' type")
156 continue
157 elif 'window' in r:
158 win = parse_win(r['window'], block.width)
159 if win != None:
160 block.wins.append(win)
161 continue
Michael Schaffner9a94b6c2019-09-25 16:17:35 -0700162
163 block.regs += [parse_reg(r)]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100164
165 # Last offset and calculate space
166 # Later on, it could use block.regs[-1].genoffset
167 if "space" in obj:
168 block.addr_width = int(obj["space"], 0).bit_length()
169 else:
170 block.addr_width = (obj["gensize"] - 1).bit_length()
171
172 return block
173
174
175def gen_rtl(obj, outdir):
176 # obj: OrderedDict
177
178 block = json_to_reg(obj)
179
180 # Read Register templates
181 reg_top_tpl = Template(
Michael Schaffnerc7039362019-10-22 16:16:06 -0700182 filename=resource_filename('reggen', 'reg_top.sv.tpl'))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100183 reg_pkg_tpl = Template(
Michael Schaffnerc7039362019-10-22 16:16:06 -0700184 filename=resource_filename('reggen', 'reg_pkg.sv.tpl'))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100185
186 # Generate pkg.sv with block name
187 with open(outdir + "/" + block.name + "_reg_pkg.sv", 'w',
188 encoding='UTF-8') as fout:
Eunchan Kimcb28a172019-10-08 16:35:48 -0700189 try:
190 fout.write(
191 reg_pkg_tpl.render(block=block,
192 HwAccess=HwAccess,
193 SwRdAccess=SwRdAccess,
194 SwWrAccess=SwWrAccess))
195 except:
196 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100197
198 # Generate top.sv
199 with open(outdir + "/" + block.name + "_reg_top.sv", 'w',
200 encoding='UTF-8') as fout:
Eunchan Kimcb28a172019-10-08 16:35:48 -0700201 try:
202 fout.write(
203 reg_top_tpl.render(block=block,
204 HwAccess=HwAccess,
205 SwRdAccess=SwRdAccess,
206 SwWrAccess=SwWrAccess))
207 except:
208 log.error(exceptions.text_error_template().render())