blob: c4a9a6b2febe09644e5b91b85d903fd6965bdca3 [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
Rupert Swarbrick200d8b42021-03-08 12:32:11 +000016from typing import Dict, Optional, Tuple
lowRISC Contributors802543a2019-08-31 12:12:56 +010017
18import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070019from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080020from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010021
22import tlgen
Rupert Swarbrick10184102021-03-31 09:12:42 +010023from reggen import access, gen_rtl, window
Rupert Swarbrickb6500262021-02-23 15:16:16 +000024from reggen.inter_signal import InterSignal
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000025from reggen.ip_block import IpBlock
Rupert Swarbrickb6500262021-02-23 15:16:16 +000026from reggen.lib import check_list
Weicai Yanga6670362020-11-24 17:19:52 -080027from topgen import amend_clocks, get_hjsonobj_xbars
Eunchan Kim2c813b42020-08-03 16:22:56 -070028from topgen import intermodule as im
Timothy Chen94432212021-03-01 22:29:18 -080029from topgen import lib as lib
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +000030from topgen import merge_top, search_ips, validate_top
Sam Elliotte74c6292020-07-24 21:40:00 +010031from topgen.c import TopGenC
Rupert Swarbrick10184102021-03-31 09:12:42 +010032from topgen.gen_dv import gen_dv
33from topgen.top import Top
lowRISC Contributors802543a2019-08-31 12:12:56 +010034
35# Common header for generated files
Michael Schaffner7b0807d2020-10-27 19:54:52 -070036warnhdr = '''//
lowRISC Contributors802543a2019-08-31 12:12:56 +010037// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
38// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
39'''
Michael Schaffner7b0807d2020-10-27 19:54:52 -070040genhdr = '''// Copyright lowRISC contributors.
41// Licensed under the Apache License, Version 2.0, see LICENSE for details.
42// SPDX-License-Identifier: Apache-2.0
43''' + warnhdr
lowRISC Contributors802543a2019-08-31 12:12:56 +010044
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010045SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070046
Philipp Wagnerfb443ab2021-03-05 11:10:28 +000047TOPGEN_TEMPLATE_PATH = Path(__file__).parent / 'topgen/templates'
48
Eunchan Kimfd561be2020-04-24 15:42:11 -070049
Rupert Swarbrickeb619e62021-03-05 15:01:54 +000050def generate_top(top, name_to_block, tpl_filename, **kwargs):
Sam Elliott7e36bd72020-04-22 14:05:49 +010051 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010052
Eunchan Kimcb28a172019-10-08 16:35:48 -070053 try:
Rupert Swarbrickeb619e62021-03-05 15:01:54 +000054 return top_tpl.render(top=top, name_to_block=name_to_block, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070055 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070056 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010057 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010058
59
60def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070061 topname = top["name"]
62 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
63 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070064
lowRISC Contributors802543a2019-08-31 12:12:56 +010065 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080066 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
67 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010068 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080069 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010070
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070071 # Generate output of crossbar with complete fields
72 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
73 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070074 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070075
lowRISC Contributors802543a2019-08-31 12:12:56 +010076 if not tlgen.elaborate(xbar):
77 log.error("Elaboration failed." + repr(xbar))
78
Eunchan Kimcb28a172019-10-08 16:35:48 -070079 try:
Eunchan Kim9191f262020-07-30 16:37:40 -070080 results = tlgen.generate(xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -070081 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070082 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010083
Eunchan Kim9191f262020-07-30 16:37:40 -070084 ip_path = out_path / 'ip/xbar_{}'.format(obj["name"])
85
86 for filename, filecontent in results:
87 filepath = ip_path / filename
88 filepath.parent.mkdir(parents=True, exist_ok=True)
89 with filepath.open(mode='w', encoding='UTF-8') as fout:
90 fout.write(filecontent)
91
Eunchan Kimc7452942019-12-19 17:04:37 -080092 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010093 dv_path.mkdir(parents=True, exist_ok=True)
94
Weicai Yange4315d22020-01-09 10:37:42 -080095 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -070096 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010097
Eunchan Kime0d37fe2020-08-03 12:05:21 -070098 # Read back the comportable IP and amend to Xbar
99 xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
100 with xbar_ipfile.open() as fxbar:
101 xbar_ipobj = hjson.load(fxbar,
102 use_decimal=True,
103 object_pairs_hook=OrderedDict)
104
Rupert Swarbrickb6500262021-02-23 15:16:16 +0000105 r_inter_signal_list = check_list(xbar_ipobj.get('inter_signal_list', []),
106 'inter_signal_list field')
107 obj['inter_signal_list'] = [
108 InterSignal.from_raw('entry {} of the inter_signal_list field'
109 .format(idx + 1),
110 entry)
111 for idx, entry in enumerate(r_inter_signal_list)
112 ]
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700113
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800114
Michael Schaffner666dde12019-10-25 11:57:54 -0700115def generate_alert_handler(top, out_path):
116 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -0800117 esc_cnt_dw = 32
118 accu_cnt_dw = 16
Eunchan Kimc7452942019-12-19 17:04:37 -0800119 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700120 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800121 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700122
Eunchan Kimba970df2020-04-17 10:21:01 -0700123 topname = top["name"]
124
Michael Schaffner666dde12019-10-25 11:57:54 -0700125 # check if there are any params to be passed through reggen and placed into
126 # the generated package
127 ip_list_in_top = [x["name"].lower() for x in top["module"]]
128 ah_idx = ip_list_in_top.index("alert_handler")
129 if 'localparam' in top['module'][ah_idx]:
130 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
131 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
132 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
133 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
Michael Schaffner666dde12019-10-25 11:57:54 -0700134
135 if esc_cnt_dw < 1:
136 log.error("EscCntDw must be larger than 0")
137 if accu_cnt_dw < 1:
138 log.error("AccuCntDw must be larger than 0")
Michael Schaffner666dde12019-10-25 11:57:54 -0700139
Michael Schaffner5ae4a232020-10-06 19:03:43 -0700140 # Count number of alerts
Michael Schaffner666dde12019-10-25 11:57:54 -0700141 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
142
143 if n_alerts < 1:
144 # set number of alerts to 1 such that the config is still valid
145 # that input will be tied off
146 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800147 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700148 else:
149 async_on = ""
150 for alert in top['alert']:
Timothy Chen322f2542020-08-05 16:28:18 -0700151 for k in range(alert['width']):
152 async_on = str(alert['async']) + async_on
Michael Schaffner666dde12019-10-25 11:57:54 -0700153 async_on = ("%d'b" % n_alerts) + async_on
154
155 log.info("alert handler parameterization:")
156 log.info("NAlerts = %d" % n_alerts)
157 log.info("EscCntDw = %d" % esc_cnt_dw)
158 log.info("AccuCntDw = %d" % accu_cnt_dw)
Michael Schaffner666dde12019-10-25 11:57:54 -0700159 log.info("AsyncOn = %s" % async_on)
160
Michael Schaffner666dde12019-10-25 11:57:54 -0700161 # Define target path
162 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
163 rtl_path.mkdir(parents=True, exist_ok=True)
164 doc_path = out_path / 'ip/alert_handler/data/autogen'
165 doc_path.mkdir(parents=True, exist_ok=True)
166
167 # Generating IP top module script is not generalized yet.
168 # So, topgen reads template files from alert_handler directory directly.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100169 tpl_path = Path(__file__).resolve().parent / '../hw/ip/alert_handler/data'
Michael Schaffner666dde12019-10-25 11:57:54 -0700170 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
171
172 # Generate Register Package and RTLs
173 out = StringIO()
174 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
175 hjson_tpl = Template(fin.read())
176 try:
177 out = hjson_tpl.render(n_alerts=n_alerts,
178 esc_cnt_dw=esc_cnt_dw,
179 accu_cnt_dw=accu_cnt_dw,
Michael Schaffner666dde12019-10-25 11:57:54 -0700180 async_on=async_on,
181 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700182 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700183 log.error(exceptions.text_error_template().render())
184 log.info("alert_handler hjson: %s" % out)
185
186 if out == "":
187 log.error("Cannot generate alert_handler config file")
188 return
189
190 hjson_gen_path = doc_path / "alert_handler.hjson"
191 gencmd = (
Cindy Chenbd401c32020-07-31 12:09:52 -0700192 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --alert-handler-only "
Eunchan Kimba970df2020-04-17 10:21:01 -0700193 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700194 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
195 fout.write(genhdr + gencmd + out)
196
197 # Generate register RTLs (currently using shell execute)
198 # TODO: More secure way to gneerate RTL
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000199 gen_rtl.gen_rtl(IpBlock.from_text(out, [], str(hjson_gen_path)),
200 str(rtl_path))
Michael Schaffner666dde12019-10-25 11:57:54 -0700201
202
lowRISC Contributors802543a2019-08-31 12:12:56 +0100203def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700204 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100205 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700206 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
207 # So, total number of interrupts are the number of entries in the list + 1
208 src = sum([x["width"] if "width" in x else 1
209 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100210
211 # Target and priority: Currently fixed
212 target = int(top["num_cores"], 0) if "num_cores" in top else 1
213 prio = 3
214
215 # Define target path
216 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700217 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700218 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100219 rtl_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700220 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100221 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800222 hjson_path = out_path / 'ip/rv_plic/data/autogen'
223 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100224
225 # Generating IP top module script is not generalized yet.
226 # So, topgen reads template files from rv_plic directory directly.
227 # Next, if the ip top gen tool is placed in util/ we can import the library.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100228 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700229 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
230 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100231
232 # Generate Register Package and RTLs
233 out = StringIO()
234 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
235 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700236 try:
237 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700238 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700239 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100240 log.info("RV_PLIC hjson: %s" % out)
241
242 if out == "":
243 log.error("Cannot generate interrupt controller config file")
244 return
245
Michael Schaffner7f134962019-11-03 12:44:50 -0800246 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700247 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700248 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
249 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100250 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
251 fout.write(genhdr + gencmd + out)
252
253 # Generate register RTLs (currently using shell execute)
Cindy Chene27c6c62020-05-18 16:06:28 -0700254 # TODO: More secure way to generate RTL
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000255 gen_rtl.gen_rtl(IpBlock.from_text(out, [], str(hjson_gen_path)),
256 str(rtl_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100257
258 # Generate RV_PLIC Top Module
259 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
260 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700261 try:
262 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700263 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700264 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100265 log.info("RV_PLIC RTL: %s" % out)
266
267 if out == "":
268 log.error("Cannot generate interrupt controller RTL")
269 return
270
271 rtl_gen_path = rtl_path / "rv_plic.sv"
272 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
273 fout.write(genhdr + gencmd + out)
274
Eunchan Kimba970df2020-04-17 10:21:01 -0700275
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800276def generate_pinmux(top, out_path):
Michael Schaffner60157962020-05-01 19:11:28 -0700277
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700278 topname = top['name']
279 pinmux = top['pinmux']
280
281 # Generation without pinmux and pinout configuration is not supported.
282 assert 'pinmux' in top
283 assert 'pinout' in top
Michael Schaffner57c490d2020-04-29 15:08:55 -0700284
285 # Get number of wakeup detectors
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700286 if 'num_wkup_detect' in pinmux:
287 num_wkup_detect = pinmux['num_wkup_detect']
Michael Schaffner57c490d2020-04-29 15:08:55 -0700288 else:
289 num_wkup_detect = 1
290
291 if num_wkup_detect <= 0:
292 # TODO: add support for no wakeup counter case
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700293 log.error('Topgen does currently not support generation of a top ' +
294 'without DIOs.')
Michael Schaffner57c490d2020-04-29 15:08:55 -0700295 return
296
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700297 if 'wkup_cnt_width' in pinmux:
298 wkup_cnt_width = pinmux['wkup_cnt_width']
Michael Schaffner57c490d2020-04-29 15:08:55 -0700299 else:
300 wkup_cnt_width = 8
301
302 if wkup_cnt_width <= 1:
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700303 log.error('Wakeup counter width must be greater equal 2.')
Eunchan Kim436d2242019-10-29 17:25:51 -0700304 return
305
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700306 # MIO Pads
307 n_mio_pads = pinmux['io_counts']['muxed']['pads']
308
Eunchan Kim436d2242019-10-29 17:25:51 -0700309 # Total inputs/outputs
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700310 # Reuse the counts from the merge phase
311 n_mio_periph_in = (pinmux['io_counts']['muxed']['inouts'] +
312 pinmux['io_counts']['muxed']['inputs'])
313 n_mio_periph_out = (pinmux['io_counts']['muxed']['inouts'] +
314 pinmux['io_counts']['muxed']['outputs'])
315 n_dio_periph_in = (pinmux['io_counts']['dedicated']['inouts'] +
316 pinmux['io_counts']['dedicated']['inputs'])
317 n_dio_periph_out = (pinmux['io_counts']['dedicated']['inouts'] +
318 pinmux['io_counts']['dedicated']['outputs'])
319 n_dio_pads = (pinmux['io_counts']['dedicated']['inouts'] +
320 pinmux['io_counts']['dedicated']['inputs'] +
321 pinmux['io_counts']['dedicated']['outputs'])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700322
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800323 # TODO: derive this value
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700324 attr_dw = 13
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800325
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700326 # Generation with zero MIO/DIO pads is currently not supported.
327 assert (n_mio_pads > 0)
328 assert (n_dio_pads > 0)
Michael Schaffner57c490d2020-04-29 15:08:55 -0700329
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700330 log.info('Generating pinmux with following info from hjson:')
331 log.info('attr_dw: %d' % attr_dw)
332 log.info('num_wkup_detect: %d' % num_wkup_detect)
333 log.info('wkup_cnt_width: %d' % wkup_cnt_width)
334 log.info('n_mio_periph_in: %d' % n_mio_periph_in)
335 log.info('n_mio_periph_out: %d' % n_mio_periph_out)
336 log.info('n_dio_periph_in: %d' % n_dio_periph_in)
337 log.info('n_dio_periph_out: %d' % n_dio_periph_out)
338 log.info('n_dio_pads: %d' % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700339
340 # Target path
341 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
342 # data: pinmux.hjson
343 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
344 rtl_path.mkdir(parents=True, exist_ok=True)
345 data_path = out_path / 'ip/pinmux/data/autogen'
346 data_path.mkdir(parents=True, exist_ok=True)
347
348 # Template path
Weicai Yang5c02d782020-12-08 12:17:51 -0800349 tpl_path = Path(
350 __file__).resolve().parent / '../hw/ip/pinmux/data/pinmux.hjson.tpl'
Eunchan Kim436d2242019-10-29 17:25:51 -0700351
352 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700353 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
354 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700355
356 hjson_gen_path = data_path / "pinmux.hjson"
357
358 out = StringIO()
359 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
360 hjson_tpl = Template(fin.read())
361 try:
Michael Schaffner60157962020-05-01 19:11:28 -0700362 out = hjson_tpl.render(
363 n_mio_periph_in=n_mio_periph_in,
364 n_mio_periph_out=n_mio_periph_out,
365 n_mio_pads=n_mio_pads,
366 # each DIO has in, out and oe wires
367 # some of these have to be tied off in the
368 # top, depending on the type.
369 n_dio_periph_in=n_dio_pads,
370 n_dio_periph_out=n_dio_pads,
371 n_dio_pads=n_dio_pads,
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800372 attr_dw=attr_dw,
Michael Schaffner60157962020-05-01 19:11:28 -0700373 n_wkup_detect=num_wkup_detect,
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700374 wkup_cnt_width=wkup_cnt_width
Timothy Chenc2b279a2021-01-14 18:53:34 -0800375 )
Eunchan Kim6599ba92020-04-13 15:27:16 -0700376 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700377 log.error(exceptions.text_error_template().render())
378 log.info("PINMUX HJSON: %s" % out)
379
380 if out == "":
381 log.error("Cannot generate pinmux HJSON")
382 return
383
384 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
385 fout.write(genhdr + gencmd + out)
386
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000387 gen_rtl.gen_rtl(IpBlock.from_text(out, [], str(hjson_gen_path)),
388 str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700389
Michael Schaffner60157962020-05-01 19:11:28 -0700390
Timothy Chenf56c1b52020-04-28 17:00:43 -0700391def generate_clkmgr(top, cfg_path, out_path):
392
393 # Target paths
394 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
395 rtl_path.mkdir(parents=True, exist_ok=True)
396 data_path = out_path / 'ip/clkmgr/data/autogen'
397 data_path.mkdir(parents=True, exist_ok=True)
398
399 # Template paths
400 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700401 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
402 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700403
404 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700405 rtl_out = rtl_path / 'clkmgr.sv'
406 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700407
408 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
409 outputs = [hjson_out, rtl_out, pkg_out]
410 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
411
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100412 # A dictionary of the aon attribute for easier lookup. src_aon_attr[C] is
413 # True if clock C is always-on and False otherwise.
414 src_aon_attr = {src['name']: (src['aon'] == 'yes')
415 for src in (top['clocks']['srcs'] +
416 top['clocks']['derived_srcs'])}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700417
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100418 # Classify the various clock signals. Here, we build the following
419 # dictionaries, each mapping the derived clock name to its source.
420 #
421 # ft_clks: Clocks fed through clkmgr but are not disturbed in any way.
422 # This maintains the clocking structure consistency.
423 # This includes two groups of clocks:
424 # - Clocks fed from the always-on source
425 # - Clocks fed to the powerup group
426 #
427 # rg_clks: Non-feedthrough clocks that have no software control. These
428 # clocks are root-gated and the root-gated clock is then exposed
429 # directly in clocks_o.
430 #
431 # sw_clks: Non-feedthrough clocks that have direct software control. These
432 # are root-gated, but (unlike rg_clks) then go through a second
433 # clock gate which is controlled by software.
434 #
435 # hints: Non-feedthrough clocks that have "hint" software control (with a
436 # feedback mechanism to allow blocks to avoid being suspended when
437 # they are not idle).
438 ft_clks = {}
439 rg_clks = {}
440 sw_clks = {}
441 hints = {}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700442
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100443 # We also build rg_srcs_set, which is the set of non-always-on clock sources
444 # that are exposed without division. This doesn't include clock sources
445 # that are only used to derive divided clocks (we might gate the divided
446 # clocks, but don't bother gating the upstream source).
447 rg_srcs_set = set()
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700448
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100449 for grp in top['clocks']['groups']:
450 if grp['name'] == 'powerup':
451 # All clocks in the "powerup" group are considered feed-throughs.
452 ft_clks.update(grp['clocks'])
453 continue
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700454
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100455 for clk, src in grp['clocks'].items():
456 if src_aon_attr[src]:
457 # Any always-on clock is a feedthrough
458 ft_clks[clk] = src
459 continue
Timothy Chenf56c1b52020-04-28 17:00:43 -0700460
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100461 rg_srcs_set.add(src)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700462
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100463 if grp['sw_cg'] == 'no':
464 # A non-feedthrough clock with no software control
465 rg_clks[clk] = src
466 continue
Timothy Chenf56c1b52020-04-28 17:00:43 -0700467
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100468 if grp['sw_cg'] == 'yes':
469 # A non-feedthrough clock with direct software control
470 sw_clks[clk] = src
471 continue
Timothy Chenf56c1b52020-04-28 17:00:43 -0700472
Rupert Swarbrick5a5cfc42021-04-16 16:31:53 +0100473 # The only other valid value for the sw_cg field is "hint", which
474 # means a non-feedthrough clock with "hint" software control.
475 assert grp['sw_cg'] == 'hint'
476 hints[clk] = src
477 continue
478
479 # hint clocks dict.
480 #
481 # The clock is constructed as clk_{src_name}_{module_name}. So to get the
482 # module name we split from the right and pick the last entry
483 hint_clks = {clk: {'name': clk.rsplit('_', 1)[-1], 'src': src}
484 for clk, src in hints.items()}
485
486 # Define a canonical ordering for rg_srcs
487 rg_srcs = sorted(rg_srcs_set)
Timothy Chenc8f30042020-09-25 16:59:47 -0700488
Timothy Chenf56c1b52020-04-28 17:00:43 -0700489 for idx, tpl in enumerate(tpls):
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100490 out = ""
Timothy Chenf56c1b52020-04-28 17:00:43 -0700491 with tpl.open(mode='r', encoding='UTF-8') as fin:
492 tpl = Template(fin.read())
493 try:
494 out = tpl.render(cfg=top,
Timothy Chenb63f3b82020-06-30 17:10:57 -0700495 div_srcs=top['clocks']['derived_srcs'],
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700496 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700497 ft_clks=ft_clks,
498 rg_clks=rg_clks,
499 sw_clks=sw_clks,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700500 export_clks=top['exported_clks'],
Timothy Chenf56c1b52020-04-28 17:00:43 -0700501 hint_clks=hint_clks)
502 except: # noqa: E722
503 log.error(exceptions.text_error_template().render())
504
505 if out == "":
506 log.error("Cannot generate {}".format(names[idx]))
507 return
508
509 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
510 fout.write(genhdr + out)
511
512 # Generate reg files
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000513 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_out), []), str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700514
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700515
Timothy Chen4ba25312020-06-17 13:08:57 -0700516# generate pwrmgr
517def generate_pwrmgr(top, out_path):
518 log.info("Generating pwrmgr")
519
Timothy Chen6faf4f12020-09-18 18:52:47 -0700520 # Count number of wakeups
Timothy Chen4ba25312020-06-17 13:08:57 -0700521 n_wkups = len(top["wakeups"])
522 log.info("Found {} wakeup signals".format(n_wkups))
523
Timothy Chen6faf4f12020-09-18 18:52:47 -0700524 # Count number of reset requests
525 n_rstreqs = len(top["reset_requests"])
526 log.info("Found {} reset request signals".format(n_rstreqs))
527
Timothy Chen4ba25312020-06-17 13:08:57 -0700528 if n_wkups < 1:
529 n_wkups = 1
Eunchan Kim9191f262020-07-30 16:37:40 -0700530 log.warning(
531 "The design has no wakeup sources. Low power not supported")
Timothy Chen4ba25312020-06-17 13:08:57 -0700532
533 # Define target path
534 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
535 rtl_path.mkdir(parents=True, exist_ok=True)
536 doc_path = out_path / 'ip/pwrmgr/data/autogen'
537 doc_path.mkdir(parents=True, exist_ok=True)
538
539 # So, read template files from ip directory.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100540 tpl_path = Path(__file__).resolve().parent / '../hw/ip/pwrmgr/data'
Timothy Chen4ba25312020-06-17 13:08:57 -0700541 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
542
543 # Render and write out hjson
544 out = StringIO()
545 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
546 hjson_tpl = Template(fin.read())
547 try:
Timothy Chenbea7b6a2021-01-21 13:59:20 -0800548 out = hjson_tpl.render(NumWkups=n_wkups,
549 Wkups=top["wakeups"],
550 NumRstReqs=n_rstreqs)
Timothy Chen4ba25312020-06-17 13:08:57 -0700551
552 except: # noqa: E722
553 log.error(exceptions.text_error_template().render())
554 log.info("pwrmgr hjson: %s" % out)
555
556 if out == "":
557 log.error("Cannot generate pwrmgr config file")
558 return
559
560 hjson_path = doc_path / "pwrmgr.hjson"
561 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
562 fout.write(genhdr + out)
563
564 # Generate reg files
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000565 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chen4ba25312020-06-17 13:08:57 -0700566
567
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700568# generate rstmgr
569def generate_rstmgr(topcfg, out_path):
570 log.info("Generating rstmgr")
571
572 # Define target path
573 rtl_path = out_path / 'ip/rstmgr/rtl/autogen'
574 rtl_path.mkdir(parents=True, exist_ok=True)
575 doc_path = out_path / 'ip/rstmgr/data/autogen'
576 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100577 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rstmgr/data'
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700578
579 # Read template files from ip directory.
580 tpls = []
581 outputs = []
582 names = ['rstmgr.hjson', 'rstmgr.sv', 'rstmgr_pkg.sv']
583
584 for x in names:
585 tpls.append(tpl_path / Path(x + ".tpl"))
586 if "hjson" in x:
587 outputs.append(doc_path / Path(x))
588 else:
589 outputs.append(rtl_path / Path(x))
590
591 # Parameters needed for generation
592 clks = []
593 output_rsts = OrderedDict()
594 sw_rsts = OrderedDict()
595 leaf_rsts = OrderedDict()
596
597 # unique clocks
Timothy Chenc6233932020-08-19 15:34:07 -0700598 for rst in topcfg["resets"]["nodes"]:
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700599 if rst['type'] != "ext" and rst['clk'] not in clks:
600 clks.append(rst['clk'])
601
602 # resets sent to reset struct
Weicai Yanga6670362020-11-24 17:19:52 -0800603 output_rsts = [
604 rst for rst in topcfg["resets"]["nodes"] if rst['type'] == "top"
605 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700606
607 # sw controlled resets
Weicai Yanga6670362020-11-24 17:19:52 -0800608 sw_rsts = [
609 rst for rst in topcfg["resets"]["nodes"]
610 if 'sw' in rst and rst['sw'] == 1
611 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700612
613 # leaf resets
Timothy Chenc6233932020-08-19 15:34:07 -0700614 leaf_rsts = [rst for rst in topcfg["resets"]["nodes"] if rst['gen']]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700615
616 log.info("output resets {}".format(output_rsts))
617 log.info("software resets {}".format(sw_rsts))
618 log.info("leaf resets {}".format(leaf_rsts))
619
Timothy Chen6faf4f12020-09-18 18:52:47 -0700620 # Number of reset requests
621 n_rstreqs = len(topcfg["reset_requests"])
622
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700623 # Generate templated files
624 for idx, t in enumerate(tpls):
625 out = StringIO()
626 with t.open(mode='r', encoding='UTF-8') as fin:
627 tpl = Template(fin.read())
628 try:
629 out = tpl.render(clks=clks,
Timothy Chen7f8cc8e2020-11-11 13:15:57 -0800630 power_domains=topcfg['power']['domains'],
Timothy Chen6faf4f12020-09-18 18:52:47 -0700631 num_rstreqs=n_rstreqs,
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700632 sw_rsts=sw_rsts,
633 output_rsts=output_rsts,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700634 leaf_rsts=leaf_rsts,
635 export_rsts=topcfg['exported_rsts'])
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700636
637 except: # noqa: E722
638 log.error(exceptions.text_error_template().render())
639
640 if out == "":
641 log.error("Cannot generate {}".format(names[idx]))
642 return
643
644 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
645 fout.write(genhdr + out)
646
647 # Generate reg files
648 hjson_path = outputs[0]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000649 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700650
651
Timothy Chen1daf5822020-10-26 17:28:15 -0700652# generate flash
653def generate_flash(topcfg, out_path):
654 log.info("Generating flash")
655
656 # Define target path
657 rtl_path = out_path / 'ip/flash_ctrl/rtl/autogen'
658 rtl_path.mkdir(parents=True, exist_ok=True)
659 doc_path = out_path / 'ip/flash_ctrl/data/autogen'
660 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100661 tpl_path = Path(__file__).resolve().parent / '../hw/ip/flash_ctrl/data'
Timothy Chen1daf5822020-10-26 17:28:15 -0700662
663 # Read template files from ip directory.
664 tpls = []
665 outputs = []
666 names = ['flash_ctrl.hjson', 'flash_ctrl.sv', 'flash_ctrl_pkg.sv']
667
668 for x in names:
669 tpls.append(tpl_path / Path(x + ".tpl"))
670 if "hjson" in x:
671 outputs.append(doc_path / Path(x))
672 else:
673 outputs.append(rtl_path / Path(x))
674
675 # Parameters needed for generation
676 flash_mems = [mem for mem in topcfg['memory'] if mem['type'] == 'eflash']
677 if len(flash_mems) > 1:
678 log.error("This design does not currently support multiple flashes")
679 return
680
681 cfg = flash_mems[0]
682
683 # Generate templated files
684 for idx, t in enumerate(tpls):
685 out = StringIO()
686 with t.open(mode='r', encoding='UTF-8') as fin:
687 tpl = Template(fin.read())
688 try:
689 out = tpl.render(cfg=cfg)
690
691 except: # noqa: E722
692 log.error(exceptions.text_error_template().render())
693
694 if out == "":
695 log.error("Cannot generate {}".format(names[idx]))
696 return
697
698 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
699 fout.write(genhdr + out)
700
701 # Generate reg files
702 hjson_path = outputs[0]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000703 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chen1daf5822020-10-26 17:28:15 -0700704
705
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100706def generate_top_only(top_only_list, out_path, topname):
Timothy Chen322f2542020-08-05 16:28:18 -0700707 log.info("Generating top only modules")
708
709 for ip in top_only_list:
Weicai Yang5c02d782020-12-08 12:17:51 -0800710 hjson_path = Path(__file__).resolve(
711 ).parent / "../hw/top_{}/ip/{}/data/{}.hjson".format(topname, ip, ip)
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100712 genrtl_dir = out_path / "ip/{}/rtl".format(ip)
713 genrtl_dir.mkdir(parents=True, exist_ok=True)
Timothy Chen322f2542020-08-05 16:28:18 -0700714 log.info("Generating top modules {}, hjson: {}, output: {}".format(
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100715 ip, hjson_path, genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700716
717 # Generate reg files
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000718 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700719
720
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000721def generate_top_ral(top: Dict[str, object],
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000722 name_to_block: Dict[str, IpBlock],
723 dv_base_prefix: str,
724 out_path: str):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100725 # construct top ral block
lowRISC Contributors802543a2019-08-31 12:12:56 +0100726
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000727 regwidth = int(top['datawidth'])
728 assert regwidth % 8 == 0
729 addrsep = regwidth // 8
lowRISC Contributors802543a2019-08-31 12:12:56 +0100730
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000731 # Generate a map from instance name to the block that it instantiates,
732 # together with a map of interface addresses.
733 inst_to_block = {} # type: Dict[str, str]
734 if_addrs = {} # type: Dict[Tuple[str, Optional[str]], int],
Timothy Chen62dabf72021-03-24 12:09:27 -0700735 attrs = {} # type: Dict[str, str]
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000736
737 for module in top['module']:
738 inst_name = module['name']
739 block_name = module['type']
740 block = name_to_block[block_name]
Weicai Yangcf02fd22021-03-22 20:49:45 -0700741 if "attr" in module:
742 if module["attr"] not in ['templated', 'reggen_top', 'reggen_only']:
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700743 raise ValueError('Unsupported value for attr field of {}: {!r}'
744 .format(inst_name, module["attr"]))
Weicai Yangcf02fd22021-03-22 20:49:45 -0700745 attrs[inst_name] = module["attr"]
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000746
747 inst_to_block[inst_name] = block_name
748 for if_name in block.reg_blocks.keys():
749 if_addr = int(module["base_addrs"][if_name], 0)
750 if_addrs[(inst_name, if_name)] = if_addr
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000751
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000752 # Collect up the memories to add
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000753 mems = []
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000754 for item in list(top.get("memory", [])):
755 byte_write = ('byte_write' in item and
756 item["byte_write"].lower() == "true")
Timothy Chen62dabf72021-03-24 12:09:27 -0700757 data_intg_passthru = ('data_intg_passthru' in item and
758 item["data_intg_passthru"].lower() == "true")
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000759 size_in_bytes = int(item['size'], 0)
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000760 num_regs = size_in_bytes // addrsep
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000761 swaccess = access.SWAccess('top-level memory',
762 item.get('swaccess', 'rw'))
763
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000764 mems.append(window.Window(name=item['name'],
765 desc='(generated from top-level)',
766 unusual=False,
767 byte_write=byte_write,
Timothy Chen62dabf72021-03-24 12:09:27 -0700768 data_intg_passthru=data_intg_passthru,
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000769 validbits=regwidth,
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000770 items=num_regs,
771 size_in_bytes=size_in_bytes,
772 offset=int(item["base_addr"], 0),
773 swaccess=swaccess))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100774
Weicai Yangcf02fd22021-03-22 20:49:45 -0700775 chip = Top(regwidth, name_to_block, inst_to_block, if_addrs, mems, attrs)
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700776
lowRISC Contributors802543a2019-08-31 12:12:56 +0100777 # generate the top ral model with template
Rupert Swarbrick10184102021-03-31 09:12:42 +0100778 return gen_dv(chip, dv_base_prefix, str(out_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100779
780
Timothy Chen315b1212021-01-22 11:08:03 -0800781def _process_top(topcfg, args, cfg_path, out_path, pass_idx):
782 # Create generated list
783 # These modules are generated through topgen
784 generated_list = [
785 module['type'] for module in topcfg['module']
Timothy Chen94432212021-03-01 22:29:18 -0800786 if lib.is_templated(module)
Timothy Chen315b1212021-01-22 11:08:03 -0800787 ]
788 log.info("Filtered list is {}".format(generated_list))
789
790 # These modules are NOT generated but belong to a specific top
791 # and therefore not part of "hw/ip"
792 top_only_list = [
793 module['type'] for module in topcfg['module']
Timothy Chen94432212021-03-01 22:29:18 -0800794 if lib.is_top_reggen(module)
Timothy Chen315b1212021-01-22 11:08:03 -0800795 ]
796 log.info("Filtered list is {}".format(top_only_list))
797
798 topname = topcfg["name"]
799
800 # Sweep the IP directory and gather the config files
801 ip_dir = Path(__file__).parents[1] / 'hw/ip'
802 ips = search_ips(ip_dir)
803
804 # exclude filtered IPs (to use top_${topname} one) and
805 exclude_list = generated_list + top_only_list
806 ips = [x for x in ips if not x.parents[1].name in exclude_list]
807
808 # Hack alert
809 # Generate clkmgr.hjson here so that it can be included below
810 # Unlike other generated hjsons, clkmgr thankfully does not require
811 # ip.hjson information. All the information is embedded within
812 # the top hjson file
813 amend_clocks(topcfg)
814 generate_clkmgr(topcfg, cfg_path, out_path)
815
816 # It may require two passes to check if the module is needed.
817 # TODO: first run of topgen will fail due to the absent of rv_plic.
818 # It needs to run up to amend_interrupt in merge_top function
819 # then creates rv_plic.hjson then run xbar generation.
820 hjson_dir = Path(args.topcfg).parent
821
822 for ip in generated_list:
Timothy Chen744c3c02021-01-20 20:23:22 -0800823 # For modules that are generated prior to gathering, we need to take it from
Timothy Chen5302fff2021-01-22 14:36:54 -0800824 # the output path. For modules not generated before, it may exist in a
Timothy Chen744c3c02021-01-20 20:23:22 -0800825 # pre-defined area already.
Timothy Chen315b1212021-01-22 11:08:03 -0800826 log.info("Appending {}".format(ip))
827 if ip == 'clkmgr' or (pass_idx > 0):
828 ip_hjson = Path(out_path) / "ip/{}/data/autogen/{}.hjson".format(
829 ip, ip)
830 else:
831 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(
832 ip, ip)
833 ips.append(ip_hjson)
834
835 for ip in top_only_list:
836 log.info("Appending {}".format(ip))
837 ip_hjson = hjson_dir.parent / "ip/{}/data/{}.hjson".format(ip, ip)
838 ips.append(ip_hjson)
839
840 # load Hjson and pass validate from reggen
841 try:
842 ip_objs = []
843 for x in ips:
844 # Skip if it is not in the module list
845 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
846 log.info("Skip module %s as it isn't in the top module list" %
847 x.stem)
848 continue
849
850 # The auto-generated hjson might not yet exist. It will be created
851 # later, see generate_{ip_name}() calls below. For the initial
852 # validation, use the template in hw/ip/{ip_name}/data .
853 if x.stem in generated_list and not x.is_file():
854 hjson_file = ip_dir / "{}/data/{}.hjson".format(x.stem, x.stem)
855 log.info(
856 "Auto-generated hjson %s does not yet exist. " % str(x) +
857 "Falling back to template %s for initial validation." %
858 str(hjson_file))
859 else:
860 hjson_file = x
861
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000862 ip_objs.append(IpBlock.from_path(str(hjson_file), []))
Timothy Chen315b1212021-01-22 11:08:03 -0800863
864 except ValueError:
865 raise SystemExit(sys.exc_info()[1])
866
867 # Read the crossbars under the top directory
868 xbar_objs = get_hjsonobj_xbars(hjson_dir)
869
870 log.info("Detected crossbars: %s" %
871 (", ".join([x["name"] for x in xbar_objs])))
872
873 # If specified, override the seed for random netlist constant computation.
874 if args.rnd_cnst_seed:
875 log.warning('Commandline override of rnd_cnst_seed with {}.'.format(
876 args.rnd_cnst_seed))
877 topcfg['rnd_cnst_seed'] = args.rnd_cnst_seed
878 # Otherwise, we either take it from the top_{topname}.hjson if present, or
879 # randomly generate a new seed if not.
880 else:
881 random.seed()
882 new_seed = random.getrandbits(64)
883 if topcfg.setdefault('rnd_cnst_seed', new_seed) == new_seed:
884 log.warning(
885 'No rnd_cnst_seed specified, setting to {}.'.format(new_seed))
886
887 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
888 if error != 0:
889 raise SystemExit("Error occured while validating top.hjson")
890
Rupert Swarbrickeb619e62021-03-05 15:01:54 +0000891 name_to_block = {} # type: Dict[str, IpBlock]
892 for block in ip_objs:
893 lblock = block.name.lower()
894 assert lblock not in name_to_block
895 name_to_block[lblock] = block
896
897 completecfg = merge_top(topcfg, name_to_block, xbar_objs)
Timothy Chen315b1212021-01-22 11:08:03 -0800898
Timothy Chen744c3c02021-01-20 20:23:22 -0800899 # Generate flash controller and flash memory
900 generate_flash(topcfg, out_path)
901
Timothy Chen315b1212021-01-22 11:08:03 -0800902 # Generate PLIC
903 if not args.no_plic and \
904 not args.alert_handler_only and \
905 not args.xbar_only:
906 generate_plic(completecfg, out_path)
907 if args.plic_only:
908 sys.exit()
909
910 # Generate Alert Handler
911 if not args.xbar_only:
912 generate_alert_handler(completecfg, out_path)
913 if args.alert_handler_only:
914 sys.exit()
915
916 # Generate Pinmux
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800917 generate_pinmux(completecfg, out_path)
Timothy Chen315b1212021-01-22 11:08:03 -0800918
919 # Generate Pwrmgr
920 generate_pwrmgr(completecfg, out_path)
921
922 # Generate rstmgr
923 generate_rstmgr(completecfg, out_path)
924
Timothy Chen315b1212021-01-22 11:08:03 -0800925 # Generate top only modules
926 # These modules are not templated, but are not in hw/ip
927 generate_top_only(top_only_list, out_path, topname)
928
929 if pass_idx > 0 and args.top_ral:
Rupert Swarbrick1b48dd32021-03-31 10:40:37 +0100930 exit_code = generate_top_ral(completecfg, name_to_block,
Rupert Swarbrick25468b42021-03-11 15:20:10 +0000931 args.dv_base_prefix, out_path)
932 sys.exit(exit_code)
Timothy Chen315b1212021-01-22 11:08:03 -0800933
Rupert Swarbrickeb619e62021-03-05 15:01:54 +0000934 return completecfg, name_to_block
Timothy Chen315b1212021-01-22 11:08:03 -0800935
936
lowRISC Contributors802543a2019-08-31 12:12:56 +0100937def main():
938 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700939 parser.add_argument('--topcfg',
940 '-t',
941 required=True,
942 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700943 parser.add_argument(
lowRISC Contributors802543a2019-08-31 12:12:56 +0100944 '--outdir',
945 '-o',
946 help='''Target TOP directory.
947 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700948 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100949 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
950
951 # Generator options: 'no' series. cannot combined with 'only' series
952 parser.add_argument(
953 '--no-top',
954 action='store_true',
955 help="If defined, topgen doesn't generate top_{name} RTLs.")
956 parser.add_argument(
957 '--no-xbar',
958 action='store_true',
959 help="If defined, topgen doesn't generate crossbar RTLs.")
960 parser.add_argument(
961 '--no-plic',
962 action='store_true',
963 help="If defined, topgen doesn't generate the interrup controller RTLs."
964 )
lowRISC Contributors802543a2019-08-31 12:12:56 +0100965
966 # Generator options: 'only' series. cannot combined with 'no' series
967 parser.add_argument(
968 '--top-only',
969 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700970 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100971 parser.add_argument(
972 '--xbar-only',
973 action='store_true',
974 help="If defined, the tool generates crossbar RTLs only")
975 parser.add_argument(
976 '--plic-only',
977 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000978 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100979 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700980 '--alert-handler-only',
981 action='store_true',
982 help="If defined, the tool generates alert handler hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100983 # Generator options: generate dv ral model
984 parser.add_argument(
985 '--top_ral',
986 '-r',
987 default=False,
988 action='store_true',
989 help="If set, the tool generates top level RAL model for DV")
Srikrishna Iyerd2341c22021-01-11 22:31:18 -0800990 parser.add_argument('--dv-base-prefix',
991 default='dv_base',
992 help='Prefix for the DV register classes from which '
993 'the register models are derived.')
Michael Schaffner7b0807d2020-10-27 19:54:52 -0700994 # Generator options for compile time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -0800995 parser.add_argument(
996 '--rnd_cnst_seed',
997 type=int,
998 metavar='<seed>',
999 help='Custom seed for RNG to compute netlist constants.')
lowRISC Contributors802543a2019-08-31 12:12:56 +01001000
1001 args = parser.parse_args()
1002
1003 # check combinations
1004 if args.top_ral:
lowRISC Contributors802543a2019-08-31 12:12:56 +01001005 args.no_top = True
1006
lowRISC Contributors802543a2019-08-31 12:12:56 +01001007 if (args.no_top or args.no_xbar or
1008 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -07001009 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +01001010 log.error(
1011 "'no' series options cannot be used with 'only' series options")
1012 raise SystemExit(sys.exc_info()[1])
1013
lowRISC Contributors802543a2019-08-31 12:12:56 +01001014 if args.verbose:
1015 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
1016 else:
1017 log.basicConfig(format="%(levelname)s: %(message)s")
1018
1019 if not args.outdir:
1020 outdir = Path(args.topcfg).parent / ".."
1021 log.info("TOP directory not given. Use %s", (outdir))
1022 elif not Path(args.outdir).is_dir():
1023 log.error("'--outdir' should point to writable directory")
1024 raise SystemExit(sys.exc_info()[1])
1025 else:
1026 outdir = Path(args.outdir)
1027
1028 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001029 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001030
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001031 try:
1032 with open(args.topcfg, 'r') as ftop:
1033 topcfg = hjson.load(ftop,
1034 use_decimal=True,
1035 object_pairs_hook=OrderedDict)
1036 except ValueError:
1037 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +01001038
Timothy Chen315b1212021-01-22 11:08:03 -08001039 # TODO, long term, the levels of dependency should be automatically determined instead
1040 # of hardcoded. The following are a few examples:
1041 # Example 1: pinmux depends on amending all modules before calculating the correct number of
1042 # pins.
1043 # This would be 1 level of dependency and require 2 passes.
1044 # Example 2: pinmux depends on amending all modules, and pwrmgr depends on pinmux generation to
1045 # know correct number of wakeups. This would be 2 levels of dependency and require 3
1046 # passes.
1047 #
1048 # How does mulit-pass work?
1049 # In example 1, the first pass gathers all modules and merges them. However, the merge process
1050 # uses a stale pinmux. The correct pinmux is then generated using the merged configuration. The
1051 # second pass now merges all the correct modules (including the generated pinmux) and creates
1052 # the final merged config.
1053 #
1054 # In example 2, the first pass gathers all modules and merges them. However, the merge process
1055 # uses a stale pinmux and pwrmgr. The correct pinmux is then generated using the merged
1056 # configuration. However, since pwrmgr is dependent on this new pinmux, it is still generated
1057 # incorrectly. The second pass merge now has an updated pinmux but stale pwrmgr. The correct
1058 # pwrmgr can now be generated. The final pass then merges all the correct modules and creates
1059 # the final configuration.
1060 #
1061 # This fix is related to #2083
1062 process_dependencies = 1
1063 for pass_idx in range(process_dependencies + 1):
1064 log.debug("Generation pass {}".format(pass_idx))
1065 if pass_idx < process_dependencies:
1066 cfg_copy = deepcopy(topcfg)
1067 _process_top(cfg_copy, args, cfg_path, out_path, pass_idx)
1068 else:
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001069 completecfg, name_to_block = _process_top(topcfg, args, cfg_path, out_path, pass_idx)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001070
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001071 topname = topcfg["name"]
Eunchan Kimba970df2020-04-17 10:21:01 -07001072
lowRISC Contributors802543a2019-08-31 12:12:56 +01001073 # Generate xbars
1074 if not args.no_xbar or args.xbar_only:
1075 generate_xbars(completecfg, out_path)
1076
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001077 # All IPs are generated. Connect phase now
Eunchan Kim2c813b42020-08-03 16:22:56 -07001078 # Find {memory, module} <-> {xbar} connections first.
Rupert Swarbricka5e687f2021-03-01 11:51:41 +00001079 im.autoconnect(completecfg, name_to_block)
Eunchan Kim2c813b42020-08-03 16:22:56 -07001080
1081 # Generic Inter-module connection
1082 im.elab_intermodule(completecfg)
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001083
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001084 # Generate top.gen.hjson right before rendering
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001085 genhjson_dir = out_path / "data/autogen"
Pirmin Vogel71bfd9b2020-11-24 17:28:20 +01001086 genhjson_dir.mkdir(parents=True, exist_ok=True)
1087 genhjson_path = genhjson_dir / ("top_%s.gen.hjson" % completecfg["name"])
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001088
1089 # Header for HJSON
1090 gencmd = '''//
1091// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
1092// -o hw/top_{topname}/ \\
1093// --hjson-only \\
1094// --rnd_cnst_seed {seed}
1095'''.format(topname=topname, seed=completecfg['rnd_cnst_seed'])
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001096
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001097 genhjson_path.write_text(genhdr + gencmd +
1098 hjson.dumps(completecfg, for_json=True))
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001099
lowRISC Contributors802543a2019-08-31 12:12:56 +01001100 if not args.no_top or args.top_only:
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001101 def render_template(template_path: str, rendered_path: Path, **other_info):
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001102 template_contents = generate_top(completecfg, name_to_block,
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001103 str(template_path), **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001104
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001105 rendered_path.parent.mkdir(exist_ok=True, parents=True)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001106 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1107 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -07001108
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001109 # Header for SV files
1110 gencmd = warnhdr + '''//
1111// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001112// -o hw/top_{topname}/ \\
1113// --rnd_cnst_seed {seed}
1114'''.format(topname=topname, seed=topcfg['rnd_cnst_seed'])
1115
Sam Elliott7e36bd72020-04-22 14:05:49 +01001116 # SystemVerilog Top:
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001117 # 'toplevel.sv.tpl' -> 'rtl/autogen/top_{topname}.sv'
1118 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.sv.tpl",
1119 out_path / f"rtl/autogen/top_{topname}.sv",
1120 gencmd=gencmd)
Eunchan Kim436d2242019-10-29 17:25:51 -07001121
Michael Schaffner74c4ff22021-03-30 15:43:46 -07001122 # Multiple chip-levels (ASIC, FPGA, Verilator, etc)
1123 for target in topcfg['targets']:
1124 render_template(TOPGEN_TEMPLATE_PATH / "chiplevel.sv.tpl",
Michael Schaffner93fe50c2021-03-31 16:25:42 -07001125 out_path / f"rtl/autogen/chip_{topname}_{target['name']}.sv",
Michael Schaffner74c4ff22021-03-30 15:43:46 -07001126 gencmd=gencmd,
1127 target=target)
1128
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001129 # The C / SV file needs some complex information, so we initialize this
Sam Elliottd1790472020-07-24 23:25:10 +01001130 # object to store it.
Rupert Swarbrick200d8b42021-03-08 12:32:11 +00001131 c_helper = TopGenC(completecfg, name_to_block)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001132
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001133 # 'toplevel_pkg.sv.tpl' -> 'rtl/autogen/top_{topname}_pkg.sv'
1134 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_pkg.sv.tpl",
1135 out_path / f"rtl/autogen/top_{topname}_pkg.sv",
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001136 helper=c_helper,
Weicai Yanga6670362020-11-24 17:19:52 -08001137 gencmd=gencmd)
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001138
1139 # compile-time random netlist constants
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001140 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_rnd_cnst_pkg.sv.tpl",
1141 out_path / f"rtl/autogen/top_{topname}_rnd_cnst_pkg.sv",
1142 gencmd=gencmd)
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001143
1144 # C Header + C File + Clang-format file
1145
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001146 # Since SW does not use FuseSoC and instead expects those files always
1147 # to be in hw/top_{topname}/sw/autogen, we currently create these files
1148 # twice:
1149 # - Once under out_path/sw/autogen
1150 # - Once under hw/top_{topname}/sw/autogen
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001151 for path in [out_path.resolve(),
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001152 (SRCTREE_TOP / 'hw/top_{}/'.format(topname)).resolve()]:
Sam Elliott2a4448b2020-04-23 11:15:43 +01001153
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001154 # 'clang-format' -> 'sw/autogen/.clang-format'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001155 cformat_tplpath = TOPGEN_TEMPLATE_PATH / 'clang-format'
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001156 cformat_dir = path / 'sw/autogen'
1157 cformat_dir.mkdir(parents=True, exist_ok=True)
1158 cformat_path = cformat_dir / '.clang-format'
1159 cformat_path.write_text(cformat_tplpath.read_text())
Sam Elliott7e36bd72020-04-22 14:05:49 +01001160
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001161 # 'top_{topname}.h.tpl' -> 'sw/autogen/top_{topname}.h'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001162 cheader_path = cformat_dir / f"top_{topname}.h"
1163 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.h.tpl",
1164 cheader_path,
1165 helper=c_helper)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001166
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001167 # Save the relative header path into `c_gen_info`
1168 rel_header_path = cheader_path.relative_to(path.parents[1])
1169 c_helper.header_path = str(rel_header_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001170
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001171 # 'toplevel.c.tpl' -> 'sw/autogen/top_{topname}.c'
1172 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.c.tpl",
1173 cformat_dir / f"top_{topname}.c",
1174 helper=c_helper)
Sam Elliott519f7462020-05-11 16:53:24 +01001175
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001176 # 'toplevel_memory.ld.tpl' -> 'sw/autogen/top_{topname}_memory.ld'
1177 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_memory.ld.tpl",
1178 cformat_dir / f"top_{topname}_memory.ld")
Sam Elliottf7cb5f42020-07-27 21:29:26 +01001179
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001180 # 'toplevel_memory.h.tpl' -> 'sw/autogen/top_{topname}_memory.h'
1181 memory_cheader_path = cformat_dir / f"top_{topname}_memory.h"
1182 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_memory.h.tpl",
Timothy Chen4ca4a2f2021-03-19 13:51:39 -07001183 memory_cheader_path,
1184 helper=c_helper)
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001185
Pirmin Vogel2f42ccd2020-12-22 20:19:30 +01001186 try:
1187 cheader_path.relative_to(SRCTREE_TOP)
1188 except ValueError:
1189 log.error("cheader_path %s is not within SRCTREE_TOP %s",
1190 cheader_path, SRCTREE_TOP)
1191 log.error("Thus skipping util/fix_include_guard.py")
1192 continue
1193
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001194 # Fix the C header guards, which will have the wrong name
1195 subprocess.run(["util/fix_include_guard.py",
1196 str(cheader_path),
1197 str(memory_cheader_path)],
1198 universal_newlines=True,
1199 stdout=subprocess.DEVNULL,
1200 stderr=subprocess.DEVNULL,
1201 check=True,
1202 cwd=str(SRCTREE_TOP)) # yapf: disable
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001203
Cindy Chene1184aa2020-09-01 11:45:07 -07001204 # generate chip level xbar and alert_handler TB
Weicai Yanga6670362020-11-24 17:19:52 -08001205 tb_files = [
1206 "xbar_env_pkg__params.sv", "tb__xbar_connect.sv",
1207 "tb__alert_handler_connect.sv"
1208 ]
Weicai Yang1777ebb2020-05-19 17:32:24 -07001209 for fname in tb_files:
1210 tpl_fname = "%s.tpl" % (fname)
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001211 xbar_chip_data_path = TOPGEN_TEMPLATE_PATH / tpl_fname
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001212 template_contents = generate_top(completecfg, name_to_block,
Weicai Yang1777ebb2020-05-19 17:32:24 -07001213 str(xbar_chip_data_path))
1214
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001215 rendered_dir = out_path / 'dv/autogen'
Weicai Yang1777ebb2020-05-19 17:32:24 -07001216 rendered_dir.mkdir(parents=True, exist_ok=True)
1217 rendered_path = rendered_dir / fname
1218
1219 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1220 fout.write(template_contents)
1221
Philipp Wagner44071092021-03-05 19:29:12 +00001222 # generate parameters for chip-level environment package
1223 tpl_fname = 'chip_env_pkg__params.sv.tpl'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001224 alert_handler_chip_data_path = TOPGEN_TEMPLATE_PATH / tpl_fname
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001225 template_contents = generate_top(completecfg, name_to_block,
Cindy Chene1184aa2020-09-01 11:45:07 -07001226 str(alert_handler_chip_data_path))
1227
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001228 rendered_dir = out_path / 'dv/env/autogen'
Cindy Chene1184aa2020-09-01 11:45:07 -07001229 rendered_dir.mkdir(parents=True, exist_ok=True)
Philipp Wagner44071092021-03-05 19:29:12 +00001230 rendered_path = rendered_dir / 'chip_env_pkg__params.sv'
Cindy Chene1184aa2020-09-01 11:45:07 -07001231
1232 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1233 fout.write(template_contents)
1234
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001235
lowRISC Contributors802543a2019-08-31 12:12:56 +01001236if __name__ == "__main__":
1237 main()