blob: 75b3acd68a618d3e99748a79c9806bfa3b1fc695 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
5r"""Top Module Generator
6"""
7import argparse
8import logging as log
Weicai Yanga6670362020-11-24 17:19:52 -08009import random
Sam Elliott37d4fbe2020-04-22 14:05:49 +010010import subprocess
Michael Schaffner60157962020-05-01 19:11:28 -070011import sys
Weicai Yanga60ae7d2020-02-21 14:32:50 -080012from collections import OrderedDict
Weicai Yanga6670362020-11-24 17:19:52 -080013from copy import deepcopy
lowRISC Contributors802543a2019-08-31 12:12:56 +010014from io import StringIO
15from pathlib import Path
16
17import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070018from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080019from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010020
21import tlgen
Cindy Chen92924942020-08-03 11:59:09 -070022from reggen import gen_dv, gen_rtl, validate
Weicai Yanga6670362020-11-24 17:19:52 -080023from topgen import amend_clocks, get_hjsonobj_xbars
Eunchan Kim2c813b42020-08-03 16:22:56 -070024from topgen import intermodule as im
Timothy Chen744c3c02021-01-20 20:23:22 -080025from topgen import merge_top, search_ips, check_flash, validate_top
Sam Elliotte74c6292020-07-24 21:40:00 +010026from topgen.c import TopGenC
lowRISC Contributors802543a2019-08-31 12:12:56 +010027
28# Common header for generated files
Michael Schaffner7b0807d2020-10-27 19:54:52 -070029warnhdr = '''//
lowRISC Contributors802543a2019-08-31 12:12:56 +010030// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
31// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
32'''
Michael Schaffner7b0807d2020-10-27 19:54:52 -070033genhdr = '''// Copyright lowRISC contributors.
34// Licensed under the Apache License, Version 2.0, see LICENSE for details.
35// SPDX-License-Identifier: Apache-2.0
36''' + warnhdr
lowRISC Contributors802543a2019-08-31 12:12:56 +010037
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010038SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070039
Eunchan Kimfd561be2020-04-24 15:42:11 -070040
Sam Elliott7e36bd72020-04-22 14:05:49 +010041def generate_top(top, tpl_filename, **kwargs):
42 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010043
Eunchan Kimcb28a172019-10-08 16:35:48 -070044 try:
Sam Elliott7e36bd72020-04-22 14:05:49 +010045 return top_tpl.render(top=top, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070046 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070047 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010048 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010049
50
51def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070052 topname = top["name"]
53 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
54 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070055
lowRISC Contributors802543a2019-08-31 12:12:56 +010056 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080057 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
58 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010059 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080060 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010061
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070062 # Generate output of crossbar with complete fields
63 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
64 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070065 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070066
lowRISC Contributors802543a2019-08-31 12:12:56 +010067 if not tlgen.elaborate(xbar):
68 log.error("Elaboration failed." + repr(xbar))
69
Eunchan Kimcb28a172019-10-08 16:35:48 -070070 try:
Eunchan Kim9191f262020-07-30 16:37:40 -070071 results = tlgen.generate(xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -070072 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070073 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010074
Eunchan Kim9191f262020-07-30 16:37:40 -070075 ip_path = out_path / 'ip/xbar_{}'.format(obj["name"])
76
77 for filename, filecontent in results:
78 filepath = ip_path / filename
79 filepath.parent.mkdir(parents=True, exist_ok=True)
80 with filepath.open(mode='w', encoding='UTF-8') as fout:
81 fout.write(filecontent)
82
Eunchan Kimc7452942019-12-19 17:04:37 -080083 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010084 dv_path.mkdir(parents=True, exist_ok=True)
85
Weicai Yange4315d22020-01-09 10:37:42 -080086 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -070087 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010088
Eunchan Kime0d37fe2020-08-03 12:05:21 -070089 # Read back the comportable IP and amend to Xbar
90 xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
91 with xbar_ipfile.open() as fxbar:
92 xbar_ipobj = hjson.load(fxbar,
93 use_decimal=True,
94 object_pairs_hook=OrderedDict)
95
96 # Deepcopy of the inter_signal_list.
97 # As of writing the code, it is not expected to write-back the
98 # read xbar objects into files. Still, as `inter_signal_list` is
99 # modified in the `elab_intermodule()` stage, it is better to keep
100 # the original content.
101 obj["inter_signal_list"] = deepcopy(
102 xbar_ipobj["inter_signal_list"])
103
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800104
Michael Schaffner666dde12019-10-25 11:57:54 -0700105def generate_alert_handler(top, out_path):
106 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -0800107 esc_cnt_dw = 32
108 accu_cnt_dw = 16
Eunchan Kimc7452942019-12-19 17:04:37 -0800109 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700110 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800111 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700112
Eunchan Kimba970df2020-04-17 10:21:01 -0700113 topname = top["name"]
114
Michael Schaffner666dde12019-10-25 11:57:54 -0700115 # check if there are any params to be passed through reggen and placed into
116 # the generated package
117 ip_list_in_top = [x["name"].lower() for x in top["module"]]
118 ah_idx = ip_list_in_top.index("alert_handler")
119 if 'localparam' in top['module'][ah_idx]:
120 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
121 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
122 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
123 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
Michael Schaffner666dde12019-10-25 11:57:54 -0700124
125 if esc_cnt_dw < 1:
126 log.error("EscCntDw must be larger than 0")
127 if accu_cnt_dw < 1:
128 log.error("AccuCntDw must be larger than 0")
Michael Schaffner666dde12019-10-25 11:57:54 -0700129
Michael Schaffner5ae4a232020-10-06 19:03:43 -0700130 # Count number of alerts
Michael Schaffner666dde12019-10-25 11:57:54 -0700131 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
132
133 if n_alerts < 1:
134 # set number of alerts to 1 such that the config is still valid
135 # that input will be tied off
136 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800137 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700138 else:
139 async_on = ""
140 for alert in top['alert']:
Timothy Chen322f2542020-08-05 16:28:18 -0700141 for k in range(alert['width']):
142 async_on = str(alert['async']) + async_on
Michael Schaffner666dde12019-10-25 11:57:54 -0700143 async_on = ("%d'b" % n_alerts) + async_on
144
145 log.info("alert handler parameterization:")
146 log.info("NAlerts = %d" % n_alerts)
147 log.info("EscCntDw = %d" % esc_cnt_dw)
148 log.info("AccuCntDw = %d" % accu_cnt_dw)
Michael Schaffner666dde12019-10-25 11:57:54 -0700149 log.info("AsyncOn = %s" % async_on)
150
Michael Schaffner666dde12019-10-25 11:57:54 -0700151 # Define target path
152 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
153 rtl_path.mkdir(parents=True, exist_ok=True)
154 doc_path = out_path / 'ip/alert_handler/data/autogen'
155 doc_path.mkdir(parents=True, exist_ok=True)
Cindy Chene27c6c62020-05-18 16:06:28 -0700156 dv_path = out_path / 'ip/alert_handler/dv'
157 dv_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700158
159 # Generating IP top module script is not generalized yet.
160 # So, topgen reads template files from alert_handler directory directly.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100161 tpl_path = Path(__file__).resolve().parent / '../hw/ip/alert_handler/data'
Michael Schaffner666dde12019-10-25 11:57:54 -0700162 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
Cindy Chene27c6c62020-05-18 16:06:28 -0700163 dv_tpl_path = tpl_path / 'alert_handler_env_pkg__params.sv.tpl'
Michael Schaffner666dde12019-10-25 11:57:54 -0700164
165 # Generate Register Package and RTLs
166 out = StringIO()
167 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
168 hjson_tpl = Template(fin.read())
169 try:
170 out = hjson_tpl.render(n_alerts=n_alerts,
171 esc_cnt_dw=esc_cnt_dw,
172 accu_cnt_dw=accu_cnt_dw,
Michael Schaffner666dde12019-10-25 11:57:54 -0700173 async_on=async_on,
174 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700175 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700176 log.error(exceptions.text_error_template().render())
177 log.info("alert_handler hjson: %s" % out)
178
179 if out == "":
180 log.error("Cannot generate alert_handler config file")
181 return
182
183 hjson_gen_path = doc_path / "alert_handler.hjson"
184 gencmd = (
Cindy Chenbd401c32020-07-31 12:09:52 -0700185 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --alert-handler-only "
Eunchan Kimba970df2020-04-17 10:21:01 -0700186 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700187 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
188 fout.write(genhdr + gencmd + out)
189
190 # Generate register RTLs (currently using shell execute)
191 # TODO: More secure way to gneerate RTL
192 hjson_obj = hjson.loads(out,
193 use_decimal=True,
194 object_pairs_hook=validate.checking_dict)
195 validate.validate(hjson_obj)
196 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
197
Cindy Chene27c6c62020-05-18 16:06:28 -0700198 # generate testbench for alert_handler
199 with dv_tpl_path.open(mode='r', encoding='UTF-8') as fin:
200 dv_tpl = Template(fin.read())
201 try:
202 out = dv_tpl.render(n_alerts=n_alerts, async_on=async_on)
203 except: # noqa : E722
204 log.error(exceptions.text_error_template().render())
205 log.info("ALERT_HANDLER DV: %s" % out)
206 if out == "":
207 log.error("Cannot generate dv alert_handler parameter file")
208 return
209
210 dv_gen_path = dv_path / 'alert_handler_env_pkg__params.sv'
211 with dv_gen_path.open(mode='w', encoding='UTF-8') as fout:
212 fout.write(genhdr + gencmd + out)
213
Michael Schaffner666dde12019-10-25 11:57:54 -0700214
lowRISC Contributors802543a2019-08-31 12:12:56 +0100215def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700216 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100217 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700218 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
219 # So, total number of interrupts are the number of entries in the list + 1
220 src = sum([x["width"] if "width" in x else 1
221 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100222
223 # Target and priority: Currently fixed
224 target = int(top["num_cores"], 0) if "num_cores" in top else 1
225 prio = 3
226
227 # Define target path
228 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700229 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700230 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100231 rtl_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700232 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100233 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800234 hjson_path = out_path / 'ip/rv_plic/data/autogen'
235 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100236
237 # Generating IP top module script is not generalized yet.
238 # So, topgen reads template files from rv_plic directory directly.
239 # Next, if the ip top gen tool is placed in util/ we can import the library.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100240 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700241 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
242 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100243
244 # Generate Register Package and RTLs
245 out = StringIO()
246 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
247 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700248 try:
249 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700250 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700251 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100252 log.info("RV_PLIC hjson: %s" % out)
253
254 if out == "":
255 log.error("Cannot generate interrupt controller config file")
256 return
257
Michael Schaffner7f134962019-11-03 12:44:50 -0800258 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700259 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700260 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
261 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100262 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
263 fout.write(genhdr + gencmd + out)
264
265 # Generate register RTLs (currently using shell execute)
Cindy Chene27c6c62020-05-18 16:06:28 -0700266 # TODO: More secure way to generate RTL
lowRISC Contributors802543a2019-08-31 12:12:56 +0100267 hjson_obj = hjson.loads(out,
268 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800269 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100270 validate.validate(hjson_obj)
271 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
272
273 # Generate RV_PLIC Top Module
274 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
275 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700276 try:
277 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700278 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700279 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100280 log.info("RV_PLIC RTL: %s" % out)
281
282 if out == "":
283 log.error("Cannot generate interrupt controller RTL")
284 return
285
286 rtl_gen_path = rtl_path / "rv_plic.sv"
287 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
288 fout.write(genhdr + gencmd + out)
289
Eunchan Kimba970df2020-04-17 10:21:01 -0700290
Michael Schaffner60157962020-05-01 19:11:28 -0700291def generate_pinmux_and_padctrl(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700292 topname = top["name"]
Eunchan Kim436d2242019-10-29 17:25:51 -0700293 # MIO Pads
Michael Schaffner57c490d2020-04-29 15:08:55 -0700294 n_mio_pads = top["pinmux"]["num_mio"]
295 if n_mio_pads <= 0:
296 # TODO: add support for no MIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700297 log.error("Topgen does currently not support generation of a top " +
298 "without a pinmux.")
299 return
300
301 if "padctrl" not in top:
302 # TODO: add support for no MIO case
303 log.error("Topgen does currently not support generation of a top " +
304 "without a padctrl instance.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700305 return
306
307 # Get number of wakeup detectors
308 if "num_wkup_detect" in top["pinmux"]:
309 num_wkup_detect = top["pinmux"]["num_wkup_detect"]
310 else:
311 num_wkup_detect = 1
312
313 if num_wkup_detect <= 0:
314 # TODO: add support for no wakeup counter case
Michael Schaffner60157962020-05-01 19:11:28 -0700315 log.error("Topgen does currently not support generation of a top " +
316 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700317 return
318
319 if "wkup_cnt_width" in top["pinmux"]:
320 wkup_cnt_width = top["pinmux"]["wkup_cnt_width"]
321 else:
322 wkup_cnt_width = 8
323
324 if wkup_cnt_width <= 1:
325 log.error("Wakeup counter width must be greater equal 2.")
Eunchan Kim436d2242019-10-29 17:25:51 -0700326 return
327
328 # Total inputs/outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700329 # Validation ensures that the width field is present.
Michael Schaffner60157962020-05-01 19:11:28 -0700330 num_mio_inputs = sum([x["width"] for x in top["pinmux"]["inputs"]])
331 num_mio_outputs = sum([x["width"] for x in top["pinmux"]["outputs"]])
332 num_mio_inouts = sum([x["width"] for x in top["pinmux"]["inouts"]])
Eunchan Kim436d2242019-10-29 17:25:51 -0700333
Michael Schaffner60157962020-05-01 19:11:28 -0700334 num_dio_inputs = sum([
335 x["width"] if x["type"] == "input" else 0 for x in top["pinmux"]["dio"]
336 ])
337 num_dio_outputs = sum([
338 x["width"] if x["type"] == "output" else 0
339 for x in top["pinmux"]["dio"]
340 ])
341 num_dio_inouts = sum([
342 x["width"] if x["type"] == "inout" else 0 for x in top["pinmux"]["dio"]
343 ])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700344
345 n_mio_periph_in = num_mio_inouts + num_mio_inputs
346 n_mio_periph_out = num_mio_inouts + num_mio_outputs
347 n_dio_periph_in = num_dio_inouts + num_dio_inputs
348 n_dio_periph_out = num_dio_inouts + num_dio_outputs
349 n_dio_pads = num_dio_inouts + num_dio_inputs + num_dio_outputs
350
351 if n_dio_pads <= 0:
352 # TODO: add support for no DIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700353 log.error("Topgen does currently not support generation of a top " +
354 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700355 return
356
357 log.info("Generating pinmux with following info from hjson:")
358 log.info("num_mio_inputs: %d" % num_mio_inputs)
359 log.info("num_mio_outputs: %d" % num_mio_outputs)
360 log.info("num_mio_inouts: %d" % num_mio_inouts)
361 log.info("num_dio_inputs: %d" % num_dio_inputs)
362 log.info("num_dio_outputs: %d" % num_dio_outputs)
363 log.info("num_dio_inouts: %d" % num_dio_inouts)
364 log.info("num_wkup_detect: %d" % num_wkup_detect)
365 log.info("wkup_cnt_width: %d" % wkup_cnt_width)
366 log.info("This translates to:")
367 log.info("n_mio_periph_in: %d" % n_mio_periph_in)
368 log.info("n_mio_periph_out: %d" % n_mio_periph_out)
369 log.info("n_dio_periph_in: %d" % n_dio_periph_in)
370 log.info("n_dio_periph_out: %d" % n_dio_periph_out)
371 log.info("n_dio_pads: %d" % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700372
373 # Target path
374 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
375 # data: pinmux.hjson
376 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
377 rtl_path.mkdir(parents=True, exist_ok=True)
378 data_path = out_path / 'ip/pinmux/data/autogen'
379 data_path.mkdir(parents=True, exist_ok=True)
380
381 # Template path
Weicai Yang5c02d782020-12-08 12:17:51 -0800382 tpl_path = Path(
383 __file__).resolve().parent / '../hw/ip/pinmux/data/pinmux.hjson.tpl'
Eunchan Kim436d2242019-10-29 17:25:51 -0700384
385 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700386 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
387 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700388
389 hjson_gen_path = data_path / "pinmux.hjson"
390
391 out = StringIO()
392 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
393 hjson_tpl = Template(fin.read())
394 try:
Michael Schaffner57c490d2020-04-29 15:08:55 -0700395 # TODO: pass in information about always-on peripherals
396 # TODO: pass in information on which DIOs can be selected
397 # as wakeup signals
398 # TODO: pass in signal names such that we can introduce
399 # named enums for select signals
Michael Schaffner60157962020-05-01 19:11:28 -0700400 out = hjson_tpl.render(
401 n_mio_periph_in=n_mio_periph_in,
402 n_mio_periph_out=n_mio_periph_out,
403 n_mio_pads=n_mio_pads,
404 # each DIO has in, out and oe wires
405 # some of these have to be tied off in the
406 # top, depending on the type.
407 n_dio_periph_in=n_dio_pads,
408 n_dio_periph_out=n_dio_pads,
409 n_dio_pads=n_dio_pads,
410 n_wkup_detect=num_wkup_detect,
411 wkup_cnt_width=wkup_cnt_width)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700412 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700413 log.error(exceptions.text_error_template().render())
414 log.info("PINMUX HJSON: %s" % out)
415
416 if out == "":
417 log.error("Cannot generate pinmux HJSON")
418 return
419
420 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
421 fout.write(genhdr + gencmd + out)
422
423 hjson_obj = hjson.loads(out,
424 use_decimal=True,
425 object_pairs_hook=validate.checking_dict)
426 validate.validate(hjson_obj)
427 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
428
Michael Schaffner60157962020-05-01 19:11:28 -0700429 # Target path
430 # rtl: padctrl_reg_pkg.sv & padctrl_reg_top.sv
431 # data: padctrl.hjson
432 rtl_path = out_path / 'ip/padctrl/rtl/autogen'
433 rtl_path.mkdir(parents=True, exist_ok=True)
434 data_path = out_path / 'ip/padctrl/data/autogen'
435 data_path.mkdir(parents=True, exist_ok=True)
436
437 # Template path
Weicai Yang5c02d782020-12-08 12:17:51 -0800438 tpl_path = Path(
439 __file__).resolve().parent / '../hw/ip/padctrl/data/padctrl.hjson.tpl'
Michael Schaffner60157962020-05-01 19:11:28 -0700440
441 # Generate register package and RTLs
442 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
443 "-o hw/top_{topname}/\n\n".format(topname=topname))
444
445 hjson_gen_path = data_path / "padctrl.hjson"
446
447 out = StringIO()
448 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
449 hjson_tpl = Template(fin.read())
450 try:
451 out = hjson_tpl.render(n_mio_pads=n_mio_pads,
452 n_dio_pads=n_dio_pads,
Michael Schaffner15b1bc92020-06-29 21:37:14 -0700453 attr_dw=10)
Michael Schaffner60157962020-05-01 19:11:28 -0700454 except: # noqa: E722
455 log.error(exceptions.text_error_template().render())
456 log.info("PADCTRL HJSON: %s" % out)
457
458 if out == "":
459 log.error("Cannot generate padctrl HJSON")
460 return
461
462 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
463 fout.write(genhdr + gencmd + out)
464
465 hjson_obj = hjson.loads(out,
466 use_decimal=True,
467 object_pairs_hook=validate.checking_dict)
468 validate.validate(hjson_obj)
469 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
470
471
Timothy Chenf56c1b52020-04-28 17:00:43 -0700472def generate_clkmgr(top, cfg_path, out_path):
473
474 # Target paths
475 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
476 rtl_path.mkdir(parents=True, exist_ok=True)
477 data_path = out_path / 'ip/clkmgr/data/autogen'
478 data_path.mkdir(parents=True, exist_ok=True)
479
480 # Template paths
481 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700482 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
483 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700484
485 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700486 rtl_out = rtl_path / 'clkmgr.sv'
487 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700488
489 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
490 outputs = [hjson_out, rtl_out, pkg_out]
491 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
492
493 # clock classification
494 grps = top['clocks']['groups']
495
496 ft_clks = OrderedDict()
497 rg_clks = OrderedDict()
498 sw_clks = OrderedDict()
Timothy Chenc8f30042020-09-25 16:59:47 -0700499 src_aon_attr = OrderedDict()
Timothy Chenf56c1b52020-04-28 17:00:43 -0700500 hint_clks = OrderedDict()
501
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700502 # construct a dictionary of the aon attribute for easier lookup
503 # ie, src_name_A: True, src_name_B: False
Timothy Chenb63f3b82020-06-30 17:10:57 -0700504 for src in top['clocks']['srcs'] + top['clocks']['derived_srcs']:
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700505 if src['aon'] == 'yes':
506 src_aon_attr[src['name']] = True
507 else:
508 src_aon_attr[src['name']] = False
509
510 rg_srcs = [src for (src, attr) in src_aon_attr.items() if not attr]
511
512 # clocks fed through clkmgr but are not disturbed in any way
513 # This maintains the clocking structure consistency
Timothy Chenb63f3b82020-06-30 17:10:57 -0700514 # This includes two groups of clocks
515 # Clocks fed from the always-on source
516 # Clocks fed to the powerup group
Weicai Yanga6670362020-11-24 17:19:52 -0800517 ft_clks = OrderedDict([(clk, src) for grp in grps
518 for (clk, src) in grp['clocks'].items()
519 if src_aon_attr[src] or grp['name'] == 'powerup'])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700520
521 # root-gate clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800522 rg_clks = OrderedDict([(clk, src) for grp in grps
523 for (clk, src) in grp['clocks'].items()
524 if grp['name'] != 'powerup' and
525 grp['sw_cg'] == 'no' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700526
527 # direct sw control clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800528 sw_clks = OrderedDict([(clk, src) for grp in grps
529 for (clk, src) in grp['clocks'].items()
530 if grp['sw_cg'] == 'yes' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700531
532 # sw hint clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800533 hints = OrderedDict([(clk, src) for grp in grps
534 for (clk, src) in grp['clocks'].items()
535 if grp['sw_cg'] == 'hint' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700536
Timothy Chenc8f30042020-09-25 16:59:47 -0700537 # hint clocks dict
538 for clk, src in hints.items():
Timothy Chen455afcb2020-10-01 11:46:35 -0700539 # the clock is constructed as clk_{src_name}_{module_name}.
Timothy Chenc8f30042020-09-25 16:59:47 -0700540 # so to get the module name we split from the right and pick the last entry
541 hint_clks[clk] = OrderedDict()
542 hint_clks[clk]['name'] = (clk.rsplit('_', 1)[-1])
543 hint_clks[clk]['src'] = src
544
Timothy Chenf56c1b52020-04-28 17:00:43 -0700545 for idx, tpl in enumerate(tpls):
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100546 out = ""
Timothy Chenf56c1b52020-04-28 17:00:43 -0700547 with tpl.open(mode='r', encoding='UTF-8') as fin:
548 tpl = Template(fin.read())
549 try:
550 out = tpl.render(cfg=top,
Timothy Chenb63f3b82020-06-30 17:10:57 -0700551 div_srcs=top['clocks']['derived_srcs'],
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700552 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700553 ft_clks=ft_clks,
554 rg_clks=rg_clks,
555 sw_clks=sw_clks,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700556 export_clks=top['exported_clks'],
Timothy Chenf56c1b52020-04-28 17:00:43 -0700557 hint_clks=hint_clks)
558 except: # noqa: E722
559 log.error(exceptions.text_error_template().render())
560
561 if out == "":
562 log.error("Cannot generate {}".format(names[idx]))
563 return
564
565 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
566 fout.write(genhdr + out)
567
568 # Generate reg files
569 with open(str(hjson_out), 'r') as out:
570 hjson_obj = hjson.load(out,
571 use_decimal=True,
572 object_pairs_hook=OrderedDict)
573 validate.validate(hjson_obj)
574 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700575
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700576
Timothy Chen4ba25312020-06-17 13:08:57 -0700577# generate pwrmgr
578def generate_pwrmgr(top, out_path):
579 log.info("Generating pwrmgr")
580
Timothy Chen6faf4f12020-09-18 18:52:47 -0700581 # Count number of wakeups
Timothy Chen4ba25312020-06-17 13:08:57 -0700582 n_wkups = len(top["wakeups"])
583 log.info("Found {} wakeup signals".format(n_wkups))
584
Timothy Chen6faf4f12020-09-18 18:52:47 -0700585 # Count number of reset requests
586 n_rstreqs = len(top["reset_requests"])
587 log.info("Found {} reset request signals".format(n_rstreqs))
588
Timothy Chen4ba25312020-06-17 13:08:57 -0700589 if n_wkups < 1:
590 n_wkups = 1
Eunchan Kim9191f262020-07-30 16:37:40 -0700591 log.warning(
592 "The design has no wakeup sources. Low power not supported")
Timothy Chen4ba25312020-06-17 13:08:57 -0700593
594 # Define target path
595 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
596 rtl_path.mkdir(parents=True, exist_ok=True)
597 doc_path = out_path / 'ip/pwrmgr/data/autogen'
598 doc_path.mkdir(parents=True, exist_ok=True)
599
600 # So, read template files from ip directory.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100601 tpl_path = Path(__file__).resolve().parent / '../hw/ip/pwrmgr/data'
Timothy Chen4ba25312020-06-17 13:08:57 -0700602 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
603
604 # Render and write out hjson
605 out = StringIO()
606 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
607 hjson_tpl = Template(fin.read())
608 try:
Timothy Chen6faf4f12020-09-18 18:52:47 -0700609 out = hjson_tpl.render(NumWkups=n_wkups, NumRstReqs=n_rstreqs)
Timothy Chen4ba25312020-06-17 13:08:57 -0700610
611 except: # noqa: E722
612 log.error(exceptions.text_error_template().render())
613 log.info("pwrmgr hjson: %s" % out)
614
615 if out == "":
616 log.error("Cannot generate pwrmgr config file")
617 return
618
619 hjson_path = doc_path / "pwrmgr.hjson"
620 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
621 fout.write(genhdr + out)
622
623 # Generate reg files
624 with open(str(hjson_path), 'r') as out:
625 hjson_obj = hjson.load(out,
626 use_decimal=True,
627 object_pairs_hook=OrderedDict)
628 validate.validate(hjson_obj)
629 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
630
631
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700632# generate rstmgr
633def generate_rstmgr(topcfg, out_path):
634 log.info("Generating rstmgr")
635
636 # Define target path
637 rtl_path = out_path / 'ip/rstmgr/rtl/autogen'
638 rtl_path.mkdir(parents=True, exist_ok=True)
639 doc_path = out_path / 'ip/rstmgr/data/autogen'
640 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100641 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rstmgr/data'
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700642
643 # Read template files from ip directory.
644 tpls = []
645 outputs = []
646 names = ['rstmgr.hjson', 'rstmgr.sv', 'rstmgr_pkg.sv']
647
648 for x in names:
649 tpls.append(tpl_path / Path(x + ".tpl"))
650 if "hjson" in x:
651 outputs.append(doc_path / Path(x))
652 else:
653 outputs.append(rtl_path / Path(x))
654
655 # Parameters needed for generation
656 clks = []
657 output_rsts = OrderedDict()
658 sw_rsts = OrderedDict()
659 leaf_rsts = OrderedDict()
660
661 # unique clocks
Timothy Chenc6233932020-08-19 15:34:07 -0700662 for rst in topcfg["resets"]["nodes"]:
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700663 if rst['type'] != "ext" and rst['clk'] not in clks:
664 clks.append(rst['clk'])
665
666 # resets sent to reset struct
Weicai Yanga6670362020-11-24 17:19:52 -0800667 output_rsts = [
668 rst for rst in topcfg["resets"]["nodes"] if rst['type'] == "top"
669 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700670
671 # sw controlled resets
Weicai Yanga6670362020-11-24 17:19:52 -0800672 sw_rsts = [
673 rst for rst in topcfg["resets"]["nodes"]
674 if 'sw' in rst and rst['sw'] == 1
675 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700676
677 # leaf resets
Timothy Chenc6233932020-08-19 15:34:07 -0700678 leaf_rsts = [rst for rst in topcfg["resets"]["nodes"] if rst['gen']]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700679
680 log.info("output resets {}".format(output_rsts))
681 log.info("software resets {}".format(sw_rsts))
682 log.info("leaf resets {}".format(leaf_rsts))
683
Timothy Chen6faf4f12020-09-18 18:52:47 -0700684 # Number of reset requests
685 n_rstreqs = len(topcfg["reset_requests"])
686
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700687 # Generate templated files
688 for idx, t in enumerate(tpls):
689 out = StringIO()
690 with t.open(mode='r', encoding='UTF-8') as fin:
691 tpl = Template(fin.read())
692 try:
693 out = tpl.render(clks=clks,
Timothy Chen7f8cc8e2020-11-11 13:15:57 -0800694 power_domains=topcfg['power']['domains'],
Timothy Chen6faf4f12020-09-18 18:52:47 -0700695 num_rstreqs=n_rstreqs,
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700696 sw_rsts=sw_rsts,
697 output_rsts=output_rsts,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700698 leaf_rsts=leaf_rsts,
699 export_rsts=topcfg['exported_rsts'])
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700700
701 except: # noqa: E722
702 log.error(exceptions.text_error_template().render())
703
704 if out == "":
705 log.error("Cannot generate {}".format(names[idx]))
706 return
707
708 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
709 fout.write(genhdr + out)
710
711 # Generate reg files
712 hjson_path = outputs[0]
713 with open(str(hjson_path), 'r') as out:
714 hjson_obj = hjson.load(out,
715 use_decimal=True,
716 object_pairs_hook=OrderedDict)
717 validate.validate(hjson_obj)
718 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
719
720
Timothy Chen1daf5822020-10-26 17:28:15 -0700721# generate flash
722def generate_flash(topcfg, out_path):
723 log.info("Generating flash")
724
725 # Define target path
726 rtl_path = out_path / 'ip/flash_ctrl/rtl/autogen'
727 rtl_path.mkdir(parents=True, exist_ok=True)
728 doc_path = out_path / 'ip/flash_ctrl/data/autogen'
729 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100730 tpl_path = Path(__file__).resolve().parent / '../hw/ip/flash_ctrl/data'
Timothy Chen1daf5822020-10-26 17:28:15 -0700731
732 # Read template files from ip directory.
733 tpls = []
734 outputs = []
735 names = ['flash_ctrl.hjson', 'flash_ctrl.sv', 'flash_ctrl_pkg.sv']
736
737 for x in names:
738 tpls.append(tpl_path / Path(x + ".tpl"))
739 if "hjson" in x:
740 outputs.append(doc_path / Path(x))
741 else:
742 outputs.append(rtl_path / Path(x))
743
744 # Parameters needed for generation
745 flash_mems = [mem for mem in topcfg['memory'] if mem['type'] == 'eflash']
746 if len(flash_mems) > 1:
747 log.error("This design does not currently support multiple flashes")
748 return
749
750 cfg = flash_mems[0]
751
752 # Generate templated files
753 for idx, t in enumerate(tpls):
754 out = StringIO()
755 with t.open(mode='r', encoding='UTF-8') as fin:
756 tpl = Template(fin.read())
757 try:
758 out = tpl.render(cfg=cfg)
759
760 except: # noqa: E722
761 log.error(exceptions.text_error_template().render())
762
763 if out == "":
764 log.error("Cannot generate {}".format(names[idx]))
765 return
766
767 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
768 fout.write(genhdr + out)
769
770 # Generate reg files
771 hjson_path = outputs[0]
772 with open(str(hjson_path), 'r') as out:
773 hjson_obj = hjson.load(out,
774 use_decimal=True,
775 object_pairs_hook=OrderedDict)
776 validate.validate(hjson_obj)
777 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
778
779
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100780def generate_top_only(top_only_list, out_path, topname):
Timothy Chen322f2542020-08-05 16:28:18 -0700781 log.info("Generating top only modules")
782
783 for ip in top_only_list:
Weicai Yang5c02d782020-12-08 12:17:51 -0800784 hjson_path = Path(__file__).resolve(
785 ).parent / "../hw/top_{}/ip/{}/data/{}.hjson".format(topname, ip, ip)
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100786 genrtl_dir = out_path / "ip/{}/rtl".format(ip)
787 genrtl_dir.mkdir(parents=True, exist_ok=True)
Timothy Chen322f2542020-08-05 16:28:18 -0700788 log.info("Generating top modules {}, hjson: {}, output: {}".format(
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100789 ip, hjson_path, genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700790
791 # Generate reg files
792 with open(str(hjson_path), 'r') as out:
793 hjson_obj = hjson.load(out,
794 use_decimal=True,
795 object_pairs_hook=OrderedDict)
796 validate.validate(hjson_obj)
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100797 gen_rtl.gen_rtl(hjson_obj, str(genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700798
799
Srikrishna Iyerd2341c22021-01-11 22:31:18 -0800800def generate_top_ral(top, ip_objs, dv_base_prefix, out_path):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100801 # construct top ral block
802 top_block = gen_rtl.Block()
803 top_block.name = "chip"
804 top_block.base_addr = 0
805 top_block.width = int(top["datawidth"])
806
Weicai Yang2f881702020-11-24 17:22:02 -0800807 # add all the IPs into blocks
lowRISC Contributors802543a2019-08-31 12:12:56 +0100808 for ip_obj in ip_objs:
809 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
810
811 # add memories
812 if "memory" in top.keys():
813 for item in list(top["memory"]):
814 mem = gen_rtl.Window()
815 mem.name = item["name"]
816 mem.base_addr = int(item["base_addr"], 0)
817 mem.limit_addr = int(item["base_addr"], 0) + int(item["size"], 0)
Weicai Yang2ac0dee2020-12-08 12:19:18 -0800818 mem.byte_write = ('byte_write' in item and
819 item["byte_write"].lower() == "true")
Weicai Yang55b2cdf2020-04-10 15:40:30 -0700820 if "swaccess" in item.keys():
821 mem.dvrights = item["swaccess"]
822 else:
823 mem.dvrights = "RW"
lowRISC Contributors802543a2019-08-31 12:12:56 +0100824 mem.n_bits = top_block.width
825 top_block.wins.append(mem)
826
Weicai Yang2f881702020-11-24 17:22:02 -0800827 # get sub-block base addresses, instance names from top cfg
lowRISC Contributors802543a2019-08-31 12:12:56 +0100828 for block in top_block.blocks:
829 for module in top["module"]:
Weicai Yang2f881702020-11-24 17:22:02 -0800830 if block.name == module["type"]:
831 block.base_addr[module["name"]] = int(module["base_addr"], 0)
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700832
Weicai Yang2f881702020-11-24 17:22:02 -0800833 # sort by the base_addr of 1st instance of the block
834 top_block.blocks.sort(key=lambda block: next(iter(block.base_addr))[1])
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700835 top_block.wins.sort(key=lambda win: win.base_addr)
836
lowRISC Contributors802543a2019-08-31 12:12:56 +0100837 # generate the top ral model with template
Srikrishna Iyerd2341c22021-01-11 22:31:18 -0800838 gen_dv.gen_ral(top_block, dv_base_prefix, str(out_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100839
840
Timothy Chen315b1212021-01-22 11:08:03 -0800841def _process_top(topcfg, args, cfg_path, out_path, pass_idx):
842 # Create generated list
843 # These modules are generated through topgen
844 generated_list = [
845 module['type'] for module in topcfg['module']
846 if 'generated' in module and module['generated'] == 'true'
847 ]
848 log.info("Filtered list is {}".format(generated_list))
849
850 # These modules are NOT generated but belong to a specific top
851 # and therefore not part of "hw/ip"
852 top_only_list = [
853 module['type'] for module in topcfg['module']
854 if 'top_only' in module and module['top_only'] == 'true'
855 ]
856 log.info("Filtered list is {}".format(top_only_list))
857
858 topname = topcfg["name"]
859
860 # Sweep the IP directory and gather the config files
861 ip_dir = Path(__file__).parents[1] / 'hw/ip'
862 ips = search_ips(ip_dir)
863
864 # exclude filtered IPs (to use top_${topname} one) and
865 exclude_list = generated_list + top_only_list
866 ips = [x for x in ips if not x.parents[1].name in exclude_list]
867
868 # Hack alert
869 # Generate clkmgr.hjson here so that it can be included below
870 # Unlike other generated hjsons, clkmgr thankfully does not require
871 # ip.hjson information. All the information is embedded within
872 # the top hjson file
873 amend_clocks(topcfg)
874 generate_clkmgr(topcfg, cfg_path, out_path)
875
876 # It may require two passes to check if the module is needed.
877 # TODO: first run of topgen will fail due to the absent of rv_plic.
878 # It needs to run up to amend_interrupt in merge_top function
879 # then creates rv_plic.hjson then run xbar generation.
880 hjson_dir = Path(args.topcfg).parent
881
882 for ip in generated_list:
Timothy Chen744c3c02021-01-20 20:23:22 -0800883 # For modules that are generated prior to gathering, we need to take it from
Timothy Chen5302fff2021-01-22 14:36:54 -0800884 # the output path. For modules not generated before, it may exist in a
Timothy Chen744c3c02021-01-20 20:23:22 -0800885 # pre-defined area already.
Timothy Chen315b1212021-01-22 11:08:03 -0800886 log.info("Appending {}".format(ip))
887 if ip == 'clkmgr' or (pass_idx > 0):
888 ip_hjson = Path(out_path) / "ip/{}/data/autogen/{}.hjson".format(
889 ip, ip)
890 else:
891 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(
892 ip, ip)
893 ips.append(ip_hjson)
894
895 for ip in top_only_list:
896 log.info("Appending {}".format(ip))
897 ip_hjson = hjson_dir.parent / "ip/{}/data/{}.hjson".format(ip, ip)
898 ips.append(ip_hjson)
899
900 # load Hjson and pass validate from reggen
901 try:
902 ip_objs = []
903 for x in ips:
904 # Skip if it is not in the module list
905 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
906 log.info("Skip module %s as it isn't in the top module list" %
907 x.stem)
908 continue
909
910 # The auto-generated hjson might not yet exist. It will be created
911 # later, see generate_{ip_name}() calls below. For the initial
912 # validation, use the template in hw/ip/{ip_name}/data .
913 if x.stem in generated_list and not x.is_file():
914 hjson_file = ip_dir / "{}/data/{}.hjson".format(x.stem, x.stem)
915 log.info(
916 "Auto-generated hjson %s does not yet exist. " % str(x) +
917 "Falling back to template %s for initial validation." %
918 str(hjson_file))
919 else:
920 hjson_file = x
921
922 obj = hjson.load(hjson_file.open('r'),
923 use_decimal=True,
924 object_pairs_hook=OrderedDict)
925 if validate.validate(obj) != 0:
926 log.info("Parsing IP %s configuration failed. Skip" % x)
927 continue
928 ip_objs.append(obj)
929
930 except ValueError:
931 raise SystemExit(sys.exc_info()[1])
932
933 # Read the crossbars under the top directory
934 xbar_objs = get_hjsonobj_xbars(hjson_dir)
935
936 log.info("Detected crossbars: %s" %
937 (", ".join([x["name"] for x in xbar_objs])))
938
939 # If specified, override the seed for random netlist constant computation.
940 if args.rnd_cnst_seed:
941 log.warning('Commandline override of rnd_cnst_seed with {}.'.format(
942 args.rnd_cnst_seed))
943 topcfg['rnd_cnst_seed'] = args.rnd_cnst_seed
944 # Otherwise, we either take it from the top_{topname}.hjson if present, or
945 # randomly generate a new seed if not.
946 else:
947 random.seed()
948 new_seed = random.getrandbits(64)
949 if topcfg.setdefault('rnd_cnst_seed', new_seed) == new_seed:
950 log.warning(
951 'No rnd_cnst_seed specified, setting to {}.'.format(new_seed))
952
953 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
954 if error != 0:
955 raise SystemExit("Error occured while validating top.hjson")
956
957 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
958
Timothy Chen744c3c02021-01-20 20:23:22 -0800959 # Generate flash controller and flash memory
960 generate_flash(topcfg, out_path)
961
Timothy Chen315b1212021-01-22 11:08:03 -0800962 # Generate PLIC
963 if not args.no_plic and \
964 not args.alert_handler_only and \
965 not args.xbar_only:
966 generate_plic(completecfg, out_path)
967 if args.plic_only:
968 sys.exit()
969
970 # Generate Alert Handler
971 if not args.xbar_only:
972 generate_alert_handler(completecfg, out_path)
973 if args.alert_handler_only:
974 sys.exit()
975
976 # Generate Pinmux
977 generate_pinmux_and_padctrl(completecfg, out_path)
978
979 # Generate Pwrmgr
980 generate_pwrmgr(completecfg, out_path)
981
982 # Generate rstmgr
983 generate_rstmgr(completecfg, out_path)
984
Timothy Chen315b1212021-01-22 11:08:03 -0800985 # Generate top only modules
986 # These modules are not templated, but are not in hw/ip
987 generate_top_only(top_only_list, out_path, topname)
988
989 if pass_idx > 0 and args.top_ral:
990 generate_top_ral(completecfg, ip_objs, args.dv_base_prefix, out_path)
991 sys.exit()
992
993 return completecfg
994
995
lowRISC Contributors802543a2019-08-31 12:12:56 +0100996def main():
997 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700998 parser.add_argument('--topcfg',
999 '-t',
1000 required=True,
1001 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -07001002 parser.add_argument(
1003 '--tpl',
1004 '-c',
1005 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -07001006 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001007 parser.add_argument(
1008 '--outdir',
1009 '-o',
1010 help='''Target TOP directory.
1011 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -07001012 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +01001013 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
1014
1015 # Generator options: 'no' series. cannot combined with 'only' series
1016 parser.add_argument(
1017 '--no-top',
1018 action='store_true',
1019 help="If defined, topgen doesn't generate top_{name} RTLs.")
1020 parser.add_argument(
1021 '--no-xbar',
1022 action='store_true',
1023 help="If defined, topgen doesn't generate crossbar RTLs.")
1024 parser.add_argument(
1025 '--no-plic',
1026 action='store_true',
1027 help="If defined, topgen doesn't generate the interrup controller RTLs."
1028 )
lowRISC Contributors802543a2019-08-31 12:12:56 +01001029
1030 # Generator options: 'only' series. cannot combined with 'no' series
1031 parser.add_argument(
1032 '--top-only',
1033 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -07001034 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +01001035 parser.add_argument(
1036 '--xbar-only',
1037 action='store_true',
1038 help="If defined, the tool generates crossbar RTLs only")
1039 parser.add_argument(
1040 '--plic-only',
1041 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +00001042 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001043 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -07001044 '--alert-handler-only',
1045 action='store_true',
1046 help="If defined, the tool generates alert handler hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001047 # Generator options: generate dv ral model
1048 parser.add_argument(
1049 '--top_ral',
1050 '-r',
1051 default=False,
1052 action='store_true',
1053 help="If set, the tool generates top level RAL model for DV")
Srikrishna Iyerd2341c22021-01-11 22:31:18 -08001054 parser.add_argument('--dv-base-prefix',
1055 default='dv_base',
1056 help='Prefix for the DV register classes from which '
1057 'the register models are derived.')
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001058 # Generator options for compile time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -08001059 parser.add_argument(
1060 '--rnd_cnst_seed',
1061 type=int,
1062 metavar='<seed>',
1063 help='Custom seed for RNG to compute netlist constants.')
lowRISC Contributors802543a2019-08-31 12:12:56 +01001064
1065 args = parser.parse_args()
1066
1067 # check combinations
1068 if args.top_ral:
lowRISC Contributors802543a2019-08-31 12:12:56 +01001069 args.no_top = True
1070
lowRISC Contributors802543a2019-08-31 12:12:56 +01001071 if (args.no_top or args.no_xbar or
1072 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -07001073 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +01001074 log.error(
1075 "'no' series options cannot be used with 'only' series options")
1076 raise SystemExit(sys.exc_info()[1])
1077
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001078 if not (args.top_ral or args.plic_only or args.alert_handler_only or
Eunchan Kimc7452942019-12-19 17:04:37 -08001079 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +01001080 log.error(
1081 "Template file can be omitted only if '--hjson-only' is true")
1082 raise SystemExit(sys.exc_info()[1])
1083
1084 if args.verbose:
1085 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
1086 else:
1087 log.basicConfig(format="%(levelname)s: %(message)s")
1088
1089 if not args.outdir:
1090 outdir = Path(args.topcfg).parent / ".."
1091 log.info("TOP directory not given. Use %s", (outdir))
1092 elif not Path(args.outdir).is_dir():
1093 log.error("'--outdir' should point to writable directory")
1094 raise SystemExit(sys.exc_info()[1])
1095 else:
1096 outdir = Path(args.outdir)
1097
1098 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001099 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001100
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001101 try:
1102 with open(args.topcfg, 'r') as ftop:
1103 topcfg = hjson.load(ftop,
1104 use_decimal=True,
1105 object_pairs_hook=OrderedDict)
1106 except ValueError:
1107 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +01001108
Timothy Chen315b1212021-01-22 11:08:03 -08001109 # TODO, long term, the levels of dependency should be automatically determined instead
1110 # of hardcoded. The following are a few examples:
1111 # Example 1: pinmux depends on amending all modules before calculating the correct number of
1112 # pins.
1113 # This would be 1 level of dependency and require 2 passes.
1114 # Example 2: pinmux depends on amending all modules, and pwrmgr depends on pinmux generation to
1115 # know correct number of wakeups. This would be 2 levels of dependency and require 3
1116 # passes.
1117 #
1118 # How does mulit-pass work?
1119 # In example 1, the first pass gathers all modules and merges them. However, the merge process
1120 # uses a stale pinmux. The correct pinmux is then generated using the merged configuration. The
1121 # second pass now merges all the correct modules (including the generated pinmux) and creates
1122 # the final merged config.
1123 #
1124 # In example 2, the first pass gathers all modules and merges them. However, the merge process
1125 # uses a stale pinmux and pwrmgr. The correct pinmux is then generated using the merged
1126 # configuration. However, since pwrmgr is dependent on this new pinmux, it is still generated
1127 # incorrectly. The second pass merge now has an updated pinmux but stale pwrmgr. The correct
1128 # pwrmgr can now be generated. The final pass then merges all the correct modules and creates
1129 # the final configuration.
1130 #
1131 # This fix is related to #2083
1132 process_dependencies = 1
1133 for pass_idx in range(process_dependencies + 1):
1134 log.debug("Generation pass {}".format(pass_idx))
1135 if pass_idx < process_dependencies:
1136 cfg_copy = deepcopy(topcfg)
1137 _process_top(cfg_copy, args, cfg_path, out_path, pass_idx)
1138 else:
1139 completecfg = _process_top(topcfg, args, cfg_path, out_path, pass_idx)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001140
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001141 topname = topcfg["name"]
Eunchan Kimba970df2020-04-17 10:21:01 -07001142
lowRISC Contributors802543a2019-08-31 12:12:56 +01001143 # Generate xbars
1144 if not args.no_xbar or args.xbar_only:
1145 generate_xbars(completecfg, out_path)
1146
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001147 # All IPs are generated. Connect phase now
Eunchan Kim2c813b42020-08-03 16:22:56 -07001148 # Find {memory, module} <-> {xbar} connections first.
1149 im.autoconnect(completecfg)
1150
1151 # Generic Inter-module connection
1152 im.elab_intermodule(completecfg)
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001153
lowRISC Contributors802543a2019-08-31 12:12:56 +01001154 top_name = completecfg["name"]
1155
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001156 # Generate top.gen.hjson right before rendering
Pirmin Vogel71bfd9b2020-11-24 17:28:20 +01001157 genhjson_dir = Path(out_path) / "data/autogen"
1158 genhjson_dir.mkdir(parents=True, exist_ok=True)
1159 genhjson_path = genhjson_dir / ("top_%s.gen.hjson" % completecfg["name"])
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001160
1161 # Header for HJSON
1162 gencmd = '''//
1163// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
1164// -o hw/top_{topname}/ \\
1165// --hjson-only \\
1166// --rnd_cnst_seed {seed}
1167'''.format(topname=topname, seed=completecfg['rnd_cnst_seed'])
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001168
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001169 genhjson_path.write_text(genhdr + gencmd +
1170 hjson.dumps(completecfg, for_json=True))
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001171
lowRISC Contributors802543a2019-08-31 12:12:56 +01001172 if not args.no_top or args.top_only:
Eunchan Kim632c6f72019-09-30 11:11:51 -07001173 tpl_path = Path(args.tpl)
Eunchan Kim632c6f72019-09-30 11:11:51 -07001174
Sam Elliott7e36bd72020-04-22 14:05:49 +01001175 def render_template(out_name_tpl, out_dir, **other_info):
1176 top_tplpath = tpl_path / ((out_name_tpl + '.tpl') % (top_name))
Eunchan Kimfd561be2020-04-24 15:42:11 -07001177 template_contents = generate_top(completecfg, str(top_tplpath),
1178 **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001179
Sam Elliott7e36bd72020-04-22 14:05:49 +01001180 rendered_dir = out_path / out_dir
1181 rendered_dir.mkdir(parents=True, exist_ok=True)
1182 rendered_path = rendered_dir / (out_name_tpl % (top_name))
lowRISC Contributors802543a2019-08-31 12:12:56 +01001183
Sam Elliott7e36bd72020-04-22 14:05:49 +01001184 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1185 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -07001186
Tobias Wölfelea1903d2020-09-23 12:48:57 +02001187 return rendered_path.resolve()
Eunchan Kim436d2242019-10-29 17:25:51 -07001188
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001189 # Header for SV files
1190 gencmd = warnhdr + '''//
1191// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
Pirmin Vogel0d713282020-11-23 18:35:44 +01001192// --tpl hw/top_{topname}/data/ \\
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001193// -o hw/top_{topname}/ \\
1194// --rnd_cnst_seed {seed}
1195'''.format(topname=topname, seed=topcfg['rnd_cnst_seed'])
1196
Sam Elliott7e36bd72020-04-22 14:05:49 +01001197 # SystemVerilog Top:
Weicai Yanga6670362020-11-24 17:19:52 -08001198 render_template('top_%s.sv', 'rtl/autogen', gencmd=gencmd)
Pirmin Vogel0d713282020-11-23 18:35:44 +01001199 # 'top_{topname}.sv.tpl' -> 'rtl/autogen/top_{topname}.sv'
Eunchan Kim436d2242019-10-29 17:25:51 -07001200
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001201 # The C / SV file needs some complex information, so we initialize this
Sam Elliottd1790472020-07-24 23:25:10 +01001202 # object to store it.
Sam Elliotte74c6292020-07-24 21:40:00 +01001203 c_helper = TopGenC(completecfg)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001204
Pirmin Vogel0d713282020-11-23 18:35:44 +01001205 # 'top_{topname}_pkg.sv.tpl' -> 'rtl/autogen/top_{topname}_pkg.sv'
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001206 render_template('top_%s_pkg.sv',
1207 'rtl/autogen',
1208 helper=c_helper,
Weicai Yanga6670362020-11-24 17:19:52 -08001209 gencmd=gencmd)
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001210
1211 # compile-time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -08001212 render_template('top_%s_rnd_cnst_pkg.sv', 'rtl/autogen', gencmd=gencmd)
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001213
1214 # C Header + C File + Clang-format file
1215
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001216 # Since SW does not use FuseSoC and instead expects those files always
1217 # to be in hw/top_{topname}/sw/autogen, we currently create these files
1218 # twice:
1219 # - Once under out_path/sw/autogen
1220 # - Once under hw/top_{topname}/sw/autogen
1221 for path in [Path(out_path).resolve(),
1222 (SRCTREE_TOP / 'hw/top_{}/'.format(topname)).resolve()]:
Sam Elliott2a4448b2020-04-23 11:15:43 +01001223
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001224 # 'clang-format' -> 'sw/autogen/.clang-format'
1225 cformat_tplpath = tpl_path / 'clang-format'
1226 cformat_dir = path / 'sw/autogen'
1227 cformat_dir.mkdir(parents=True, exist_ok=True)
1228 cformat_path = cformat_dir / '.clang-format'
1229 cformat_path.write_text(cformat_tplpath.read_text())
Sam Elliott7e36bd72020-04-22 14:05:49 +01001230
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001231 # 'top_{topname}.h.tpl' -> 'sw/autogen/top_{topname}.h'
1232 cheader_path = render_template('top_%s.h',
1233 cformat_dir,
1234 helper=c_helper)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001235
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001236 # Save the relative header path into `c_gen_info`
1237 rel_header_path = cheader_path.relative_to(path.parents[1])
1238 c_helper.header_path = str(rel_header_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001239
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001240 # 'top_{topname}.c.tpl' -> 'sw/autogen/top_{topname}.c'
1241 render_template('top_%s.c', cformat_dir, helper=c_helper)
Sam Elliott519f7462020-05-11 16:53:24 +01001242
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001243 # 'top_{topname}_memory.ld.tpl' -> 'sw/autogen/top_{topname}_memory.ld'
1244 render_template('top_%s_memory.ld', cformat_dir)
Sam Elliottf7cb5f42020-07-27 21:29:26 +01001245
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001246 # 'top_{topname}_memory.h.tpl' -> 'sw/autogen/top_{topname}_memory.h'
1247 memory_cheader_path = render_template('top_%s_memory.h', cformat_dir)
1248
Pirmin Vogel2f42ccd2020-12-22 20:19:30 +01001249 try:
1250 cheader_path.relative_to(SRCTREE_TOP)
1251 except ValueError:
1252 log.error("cheader_path %s is not within SRCTREE_TOP %s",
1253 cheader_path, SRCTREE_TOP)
1254 log.error("Thus skipping util/fix_include_guard.py")
1255 continue
1256
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001257 # Fix the C header guards, which will have the wrong name
1258 subprocess.run(["util/fix_include_guard.py",
1259 str(cheader_path),
1260 str(memory_cheader_path)],
1261 universal_newlines=True,
1262 stdout=subprocess.DEVNULL,
1263 stderr=subprocess.DEVNULL,
1264 check=True,
1265 cwd=str(SRCTREE_TOP)) # yapf: disable
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001266
Cindy Chene1184aa2020-09-01 11:45:07 -07001267 # generate chip level xbar and alert_handler TB
Weicai Yanga6670362020-11-24 17:19:52 -08001268 tb_files = [
1269 "xbar_env_pkg__params.sv", "tb__xbar_connect.sv",
1270 "tb__alert_handler_connect.sv"
1271 ]
Weicai Yang1777ebb2020-05-19 17:32:24 -07001272 for fname in tb_files:
1273 tpl_fname = "%s.tpl" % (fname)
1274 xbar_chip_data_path = tpl_path / tpl_fname
1275 template_contents = generate_top(completecfg,
1276 str(xbar_chip_data_path))
1277
Pirmin Vogelf80120a2020-11-27 09:55:11 +01001278 rendered_dir = Path(out_path) / 'dv/autogen'
Weicai Yang1777ebb2020-05-19 17:32:24 -07001279 rendered_dir.mkdir(parents=True, exist_ok=True)
1280 rendered_path = rendered_dir / fname
1281
1282 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1283 fout.write(template_contents)
1284
Cindy Chene1184aa2020-09-01 11:45:07 -07001285 # generate chip level alert_handler pkg
1286 tpl_fname = 'alert_handler_env_pkg__params.sv.tpl'
1287 alert_handler_chip_data_path = tpl_path / tpl_fname
1288 template_contents = generate_top(completecfg,
1289 str(alert_handler_chip_data_path))
1290
Pirmin Vogelf80120a2020-11-27 09:55:11 +01001291 rendered_dir = Path(out_path) / 'dv/env/autogen'
Cindy Chene1184aa2020-09-01 11:45:07 -07001292 rendered_dir.mkdir(parents=True, exist_ok=True)
1293 rendered_path = rendered_dir / 'alert_handler_env_pkg__params.sv'
1294
1295 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1296 fout.write(template_contents)
1297
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001298
lowRISC Contributors802543a2019-08-31 12:12:56 +01001299if __name__ == "__main__":
1300 main()