blob: 6b31bbeeac4bd150fda1421744e4ab4101ebbf83 [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
Sam Elliott37d4fbe2020-04-22 14:05:49 +01009import subprocess
Michael Schaffner60157962020-05-01 19:11:28 -070010import sys
Weicai Yanga60ae7d2020-02-21 14:32:50 -080011from collections import OrderedDict
lowRISC Contributors802543a2019-08-31 12:12:56 +010012from io import StringIO
13from pathlib import Path
14
15import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070016from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080017from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010018
19import tlgen
Weicai Yang1777ebb2020-05-19 17:32:24 -070020from reggen import gen_dv, gen_fpv, gen_rtl, validate
21from topgen import (amend_clocks, get_hjsonobj_xbars, merge_top, search_ips,
22 validate_top)
lowRISC Contributors802543a2019-08-31 12:12:56 +010023
24# Common header for generated files
25genhdr = '''// Copyright lowRISC contributors.
26// Licensed under the Apache License, Version 2.0, see LICENSE for details.
27// SPDX-License-Identifier: Apache-2.0
28//
29// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
30// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
31'''
32
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010033SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070034
Eunchan Kimfd561be2020-04-24 15:42:11 -070035
Sam Elliott7e36bd72020-04-22 14:05:49 +010036def generate_top(top, tpl_filename, **kwargs):
37 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010038
Eunchan Kimcb28a172019-10-08 16:35:48 -070039 try:
Sam Elliott7e36bd72020-04-22 14:05:49 +010040 return top_tpl.render(top=top, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070041 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070042 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010043 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010044
45
46def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070047 topname = top["name"]
48 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
49 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070050
lowRISC Contributors802543a2019-08-31 12:12:56 +010051 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080052 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
53 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010054 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080055 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010056
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070057 # Generate output of crossbar with complete fields
58 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
59 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070060 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070061
lowRISC Contributors802543a2019-08-31 12:12:56 +010062 if not tlgen.elaborate(xbar):
63 log.error("Elaboration failed." + repr(xbar))
64
Eunchan Kimcb28a172019-10-08 16:35:48 -070065 try:
Eunchan Kim8f2cb382020-05-13 11:53:09 -070066 out_rtl, out_pkg, out_core = tlgen.generate(
67 xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -070068 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070069 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010070
Eunchan Kimc7452942019-12-19 17:04:37 -080071 rtl_path = out_path / 'ip/xbar_{}/rtl/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010072 rtl_path.mkdir(parents=True, exist_ok=True)
Eunchan Kimc7452942019-12-19 17:04:37 -080073 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010074 dv_path.mkdir(parents=True, exist_ok=True)
75
76 rtl_filename = "xbar_%s.sv" % (xbar.name)
77 rtl_filepath = rtl_path / rtl_filename
78 with rtl_filepath.open(mode='w', encoding='UTF-8') as fout:
79 fout.write(out_rtl)
80
81 pkg_filename = "tl_%s_pkg.sv" % (xbar.name)
82 pkg_filepath = rtl_path / pkg_filename
83 with pkg_filepath.open(mode='w', encoding='UTF-8') as fout:
84 fout.write(out_pkg)
85
Eunchan Kimc7452942019-12-19 17:04:37 -080086 core_filename = "xbar_%s.core" % (xbar.name)
87 core_filepath = rtl_path / core_filename
88 with core_filepath.open(mode='w', encoding='UTF-8') as fout:
89 fout.write(out_core)
90
Weicai Yange4315d22020-01-09 10:37:42 -080091 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -070092 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010093
Eunchan Kim6a4b49e2020-02-18 10:33:39 -080094
Michael Schaffner666dde12019-10-25 11:57:54 -070095def generate_alert_handler(top, out_path):
96 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -080097 esc_cnt_dw = 32
98 accu_cnt_dw = 16
99 lfsr_seed = 2**31 - 1
100 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700101 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800102 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700103
Eunchan Kimba970df2020-04-17 10:21:01 -0700104 topname = top["name"]
105
Michael Schaffner666dde12019-10-25 11:57:54 -0700106 # check if there are any params to be passed through reggen and placed into
107 # the generated package
108 ip_list_in_top = [x["name"].lower() for x in top["module"]]
109 ah_idx = ip_list_in_top.index("alert_handler")
110 if 'localparam' in top['module'][ah_idx]:
111 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
112 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
113 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
114 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
115 if 'LfsrSeed' in top['module'][ah_idx]['localparam']:
116 lfsr_seed = int(top['module'][ah_idx]['localparam']['LfsrSeed'], 0)
117
118 if esc_cnt_dw < 1:
119 log.error("EscCntDw must be larger than 0")
120 if accu_cnt_dw < 1:
121 log.error("AccuCntDw must be larger than 0")
122 if (lfsr_seed & 0xFFFFFFFF) == 0 or lfsr_seed > 2**32:
123 log.error("LFSR seed out of range or zero")
124
125 # Count number of interrupts
126 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
127
128 if n_alerts < 1:
129 # set number of alerts to 1 such that the config is still valid
130 # that input will be tied off
131 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800132 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700133 else:
134 async_on = ""
135 for alert in top['alert']:
136 async_on = str(alert['async']) + async_on
137 async_on = ("%d'b" % n_alerts) + async_on
138
139 log.info("alert handler parameterization:")
140 log.info("NAlerts = %d" % n_alerts)
141 log.info("EscCntDw = %d" % esc_cnt_dw)
142 log.info("AccuCntDw = %d" % accu_cnt_dw)
143 log.info("LfsrSeed = %d" % lfsr_seed)
144 log.info("AsyncOn = %s" % async_on)
145
Michael Schaffner666dde12019-10-25 11:57:54 -0700146 # Define target path
147 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
148 rtl_path.mkdir(parents=True, exist_ok=True)
149 doc_path = out_path / 'ip/alert_handler/data/autogen'
150 doc_path.mkdir(parents=True, exist_ok=True)
Cindy Chene27c6c62020-05-18 16:06:28 -0700151 dv_path = out_path / 'ip/alert_handler/dv'
152 dv_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700153
154 # Generating IP top module script is not generalized yet.
155 # So, topgen reads template files from alert_handler directory directly.
156 tpl_path = out_path / '../ip/alert_handler/data'
157 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
Cindy Chene27c6c62020-05-18 16:06:28 -0700158 dv_tpl_path = tpl_path / 'alert_handler_env_pkg__params.sv.tpl'
Michael Schaffner666dde12019-10-25 11:57:54 -0700159
160 # Generate Register Package and RTLs
161 out = StringIO()
162 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
163 hjson_tpl = Template(fin.read())
164 try:
165 out = hjson_tpl.render(n_alerts=n_alerts,
166 esc_cnt_dw=esc_cnt_dw,
167 accu_cnt_dw=accu_cnt_dw,
168 lfsr_seed=lfsr_seed,
169 async_on=async_on,
170 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700171 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700172 log.error(exceptions.text_error_template().render())
173 log.info("alert_handler hjson: %s" % out)
174
175 if out == "":
176 log.error("Cannot generate alert_handler config file")
177 return
178
179 hjson_gen_path = doc_path / "alert_handler.hjson"
180 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700181 "// util/topgen.py -t hw/top_{topname}/doc/top_{topname}.hjson --alert-handler-only "
182 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700183 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
184 fout.write(genhdr + gencmd + out)
185
186 # Generate register RTLs (currently using shell execute)
187 # TODO: More secure way to gneerate RTL
188 hjson_obj = hjson.loads(out,
189 use_decimal=True,
190 object_pairs_hook=validate.checking_dict)
191 validate.validate(hjson_obj)
192 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
193
Cindy Chene27c6c62020-05-18 16:06:28 -0700194 # generate testbench for alert_handler
195 with dv_tpl_path.open(mode='r', encoding='UTF-8') as fin:
196 dv_tpl = Template(fin.read())
197 try:
198 out = dv_tpl.render(n_alerts=n_alerts, async_on=async_on)
199 except: # noqa : E722
200 log.error(exceptions.text_error_template().render())
201 log.info("ALERT_HANDLER DV: %s" % out)
202 if out == "":
203 log.error("Cannot generate dv alert_handler parameter file")
204 return
205
206 dv_gen_path = dv_path / 'alert_handler_env_pkg__params.sv'
207 with dv_gen_path.open(mode='w', encoding='UTF-8') as fout:
208 fout.write(genhdr + gencmd + out)
209
Michael Schaffner666dde12019-10-25 11:57:54 -0700210
lowRISC Contributors802543a2019-08-31 12:12:56 +0100211def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700212 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100213 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700214 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
215 # So, total number of interrupts are the number of entries in the list + 1
216 src = sum([x["width"] if "width" in x else 1
217 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100218
219 # Target and priority: Currently fixed
220 target = int(top["num_cores"], 0) if "num_cores" in top else 1
221 prio = 3
222
223 # Define target path
224 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700225 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700226 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100227 rtl_path.mkdir(parents=True, exist_ok=True)
Cindy Chenc30dad22020-03-19 13:26:13 -0700228 fpv_path = out_path / 'ip/rv_plic/fpv/autogen'
229 fpv_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700230 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100231 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800232 hjson_path = out_path / 'ip/rv_plic/data/autogen'
233 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100234
235 # Generating IP top module script is not generalized yet.
236 # So, topgen reads template files from rv_plic directory directly.
237 # Next, if the ip top gen tool is placed in util/ we can import the library.
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +0200238 tpl_path = out_path / '../ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700239 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
240 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
Eunchan Kimba970df2020-04-17 10:21:01 -0700241 fpv_tpl_names = [
242 'rv_plic_bind_fpv.sv', 'rv_plic_fpv.sv', 'rv_plic_fpv.core'
243 ]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100244
245 # Generate Register Package and RTLs
246 out = StringIO()
247 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
248 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700249 try:
250 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700251 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700252 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100253 log.info("RV_PLIC hjson: %s" % out)
254
255 if out == "":
256 log.error("Cannot generate interrupt controller config file")
257 return
258
Michael Schaffner7f134962019-11-03 12:44:50 -0800259 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700260 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700261 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
262 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100263 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
264 fout.write(genhdr + gencmd + out)
265
266 # Generate register RTLs (currently using shell execute)
Cindy Chene27c6c62020-05-18 16:06:28 -0700267 # TODO: More secure way to generate RTL
lowRISC Contributors802543a2019-08-31 12:12:56 +0100268 hjson_obj = hjson.loads(out,
269 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800270 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100271 validate.validate(hjson_obj)
272 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Cindy Chenc30dad22020-03-19 13:26:13 -0700273 gen_fpv.gen_fpv(hjson_obj, str(fpv_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100274
275 # Generate RV_PLIC Top Module
276 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
277 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700278 try:
279 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700280 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700281 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100282 log.info("RV_PLIC RTL: %s" % out)
283
284 if out == "":
285 log.error("Cannot generate interrupt controller RTL")
286 return
287
288 rtl_gen_path = rtl_path / "rv_plic.sv"
289 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
290 fout.write(genhdr + gencmd + out)
291
Cindy Chenc30dad22020-03-19 13:26:13 -0700292 # Generate RV_PLIC FPV testbench
293 for file_name in fpv_tpl_names:
294 tpl_name = file_name + ".tpl"
295 path = tpl_path / tpl_name
296 with path.open(mode='r', encoding='UTF-8') as fin:
297 fpv_tpl = Template(fin.read())
298 try:
299 out = fpv_tpl.render(src=src, target=target, prio=prio)
Eunchan Kimba970df2020-04-17 10:21:01 -0700300 except: # noqa : E722
Cindy Chenc30dad22020-03-19 13:26:13 -0700301 log.error(exceptions.text_error_template().render())
302 log.info("RV_PLIC FPV: %s" % out)
303 if out == "":
304 log.error("Cannot generate rv_plic FPV testbench")
305 return
306
307 fpv_gen_path = fpv_path / file_name
308 with fpv_gen_path.open(mode='w', encoding='UTF-8') as fout:
309 fout.write(out)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100310
Eunchan Kimba970df2020-04-17 10:21:01 -0700311
Michael Schaffner60157962020-05-01 19:11:28 -0700312def generate_pinmux_and_padctrl(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700313 topname = top["name"]
Eunchan Kim436d2242019-10-29 17:25:51 -0700314 # MIO Pads
Michael Schaffner57c490d2020-04-29 15:08:55 -0700315 n_mio_pads = top["pinmux"]["num_mio"]
316 if n_mio_pads <= 0:
317 # TODO: add support for no MIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700318 log.error("Topgen does currently not support generation of a top " +
319 "without a pinmux.")
320 return
321
322 if "padctrl" not in top:
323 # TODO: add support for no MIO case
324 log.error("Topgen does currently not support generation of a top " +
325 "without a padctrl instance.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700326 return
327
328 # Get number of wakeup detectors
329 if "num_wkup_detect" in top["pinmux"]:
330 num_wkup_detect = top["pinmux"]["num_wkup_detect"]
331 else:
332 num_wkup_detect = 1
333
334 if num_wkup_detect <= 0:
335 # TODO: add support for no wakeup counter case
Michael Schaffner60157962020-05-01 19:11:28 -0700336 log.error("Topgen does currently not support generation of a top " +
337 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700338 return
339
340 if "wkup_cnt_width" in top["pinmux"]:
341 wkup_cnt_width = top["pinmux"]["wkup_cnt_width"]
342 else:
343 wkup_cnt_width = 8
344
345 if wkup_cnt_width <= 1:
346 log.error("Wakeup counter width must be greater equal 2.")
Eunchan Kim436d2242019-10-29 17:25:51 -0700347 return
348
349 # Total inputs/outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700350 # Validation ensures that the width field is present.
Michael Schaffner60157962020-05-01 19:11:28 -0700351 num_mio_inputs = sum([x["width"] for x in top["pinmux"]["inputs"]])
352 num_mio_outputs = sum([x["width"] for x in top["pinmux"]["outputs"]])
353 num_mio_inouts = sum([x["width"] for x in top["pinmux"]["inouts"]])
Eunchan Kim436d2242019-10-29 17:25:51 -0700354
Michael Schaffner60157962020-05-01 19:11:28 -0700355 num_dio_inputs = sum([
356 x["width"] if x["type"] == "input" else 0 for x in top["pinmux"]["dio"]
357 ])
358 num_dio_outputs = sum([
359 x["width"] if x["type"] == "output" else 0
360 for x in top["pinmux"]["dio"]
361 ])
362 num_dio_inouts = sum([
363 x["width"] if x["type"] == "inout" else 0 for x in top["pinmux"]["dio"]
364 ])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700365
366 n_mio_periph_in = num_mio_inouts + num_mio_inputs
367 n_mio_periph_out = num_mio_inouts + num_mio_outputs
368 n_dio_periph_in = num_dio_inouts + num_dio_inputs
369 n_dio_periph_out = num_dio_inouts + num_dio_outputs
370 n_dio_pads = num_dio_inouts + num_dio_inputs + num_dio_outputs
371
372 if n_dio_pads <= 0:
373 # TODO: add support for no DIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700374 log.error("Topgen does currently not support generation of a top " +
375 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700376 return
377
378 log.info("Generating pinmux with following info from hjson:")
379 log.info("num_mio_inputs: %d" % num_mio_inputs)
380 log.info("num_mio_outputs: %d" % num_mio_outputs)
381 log.info("num_mio_inouts: %d" % num_mio_inouts)
382 log.info("num_dio_inputs: %d" % num_dio_inputs)
383 log.info("num_dio_outputs: %d" % num_dio_outputs)
384 log.info("num_dio_inouts: %d" % num_dio_inouts)
385 log.info("num_wkup_detect: %d" % num_wkup_detect)
386 log.info("wkup_cnt_width: %d" % wkup_cnt_width)
387 log.info("This translates to:")
388 log.info("n_mio_periph_in: %d" % n_mio_periph_in)
389 log.info("n_mio_periph_out: %d" % n_mio_periph_out)
390 log.info("n_dio_periph_in: %d" % n_dio_periph_in)
391 log.info("n_dio_periph_out: %d" % n_dio_periph_out)
392 log.info("n_dio_pads: %d" % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700393
394 # Target path
395 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
396 # data: pinmux.hjson
397 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
398 rtl_path.mkdir(parents=True, exist_ok=True)
399 data_path = out_path / 'ip/pinmux/data/autogen'
400 data_path.mkdir(parents=True, exist_ok=True)
401
402 # Template path
403 tpl_path = out_path / '../ip/pinmux/data/pinmux.hjson.tpl'
404
405 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700406 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
407 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700408
409 hjson_gen_path = data_path / "pinmux.hjson"
410
411 out = StringIO()
412 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
413 hjson_tpl = Template(fin.read())
414 try:
Michael Schaffner57c490d2020-04-29 15:08:55 -0700415 # TODO: pass in information about always-on peripherals
416 # TODO: pass in information on which DIOs can be selected
417 # as wakeup signals
418 # TODO: pass in signal names such that we can introduce
419 # named enums for select signals
Michael Schaffner60157962020-05-01 19:11:28 -0700420 out = hjson_tpl.render(
421 n_mio_periph_in=n_mio_periph_in,
422 n_mio_periph_out=n_mio_periph_out,
423 n_mio_pads=n_mio_pads,
424 # each DIO has in, out and oe wires
425 # some of these have to be tied off in the
426 # top, depending on the type.
427 n_dio_periph_in=n_dio_pads,
428 n_dio_periph_out=n_dio_pads,
429 n_dio_pads=n_dio_pads,
430 n_wkup_detect=num_wkup_detect,
431 wkup_cnt_width=wkup_cnt_width)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700432 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700433 log.error(exceptions.text_error_template().render())
434 log.info("PINMUX HJSON: %s" % out)
435
436 if out == "":
437 log.error("Cannot generate pinmux HJSON")
438 return
439
440 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
441 fout.write(genhdr + gencmd + out)
442
443 hjson_obj = hjson.loads(out,
444 use_decimal=True,
445 object_pairs_hook=validate.checking_dict)
446 validate.validate(hjson_obj)
447 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
448
Michael Schaffner60157962020-05-01 19:11:28 -0700449 # Target path
450 # rtl: padctrl_reg_pkg.sv & padctrl_reg_top.sv
451 # data: padctrl.hjson
452 rtl_path = out_path / 'ip/padctrl/rtl/autogen'
453 rtl_path.mkdir(parents=True, exist_ok=True)
454 data_path = out_path / 'ip/padctrl/data/autogen'
455 data_path.mkdir(parents=True, exist_ok=True)
456
457 # Template path
458 tpl_path = out_path / '../ip/padctrl/data/padctrl.hjson.tpl'
459
460 # Generate register package and RTLs
461 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
462 "-o hw/top_{topname}/\n\n".format(topname=topname))
463
464 hjson_gen_path = data_path / "padctrl.hjson"
465
466 out = StringIO()
467 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
468 hjson_tpl = Template(fin.read())
469 try:
470 out = hjson_tpl.render(n_mio_pads=n_mio_pads,
471 n_dio_pads=n_dio_pads,
Michael Schaffner15b1bc92020-06-29 21:37:14 -0700472 attr_dw=10)
Michael Schaffner60157962020-05-01 19:11:28 -0700473 except: # noqa: E722
474 log.error(exceptions.text_error_template().render())
475 log.info("PADCTRL HJSON: %s" % out)
476
477 if out == "":
478 log.error("Cannot generate padctrl HJSON")
479 return
480
481 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
482 fout.write(genhdr + gencmd + out)
483
484 hjson_obj = hjson.loads(out,
485 use_decimal=True,
486 object_pairs_hook=validate.checking_dict)
487 validate.validate(hjson_obj)
488 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
489
490
Timothy Chenf56c1b52020-04-28 17:00:43 -0700491def generate_clkmgr(top, cfg_path, out_path):
492
493 # Target paths
494 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
495 rtl_path.mkdir(parents=True, exist_ok=True)
496 data_path = out_path / 'ip/clkmgr/data/autogen'
497 data_path.mkdir(parents=True, exist_ok=True)
498
499 # Template paths
500 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700501 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
502 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700503
504 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700505 rtl_out = rtl_path / 'clkmgr.sv'
506 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700507
508 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
509 outputs = [hjson_out, rtl_out, pkg_out]
510 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
511
512 # clock classification
513 grps = top['clocks']['groups']
514
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700515 src_aon_attr = OrderedDict()
Timothy Chenf56c1b52020-04-28 17:00:43 -0700516 ft_clks = OrderedDict()
517 rg_clks = OrderedDict()
518 sw_clks = OrderedDict()
519 hint_clks = OrderedDict()
520
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700521 # construct a dictionary of the aon attribute for easier lookup
522 # ie, src_name_A: True, src_name_B: False
Timothy Chenb63f3b82020-06-30 17:10:57 -0700523 for src in top['clocks']['srcs'] + top['clocks']['derived_srcs']:
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700524 if src['aon'] == 'yes':
525 src_aon_attr[src['name']] = True
526 else:
527 src_aon_attr[src['name']] = False
528
529 rg_srcs = [src for (src, attr) in src_aon_attr.items() if not attr]
530
531 # clocks fed through clkmgr but are not disturbed in any way
532 # This maintains the clocking structure consistency
Timothy Chenb63f3b82020-06-30 17:10:57 -0700533 # This includes two groups of clocks
534 # Clocks fed from the always-on source
535 # Clocks fed to the powerup group
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700536 ft_clks = {
537 clk: src
538 for grp in grps for (clk, src) in grp['clocks'].items()
Timothy Chenb63f3b82020-06-30 17:10:57 -0700539 if src_aon_attr[src] or grp['name'] == 'powerup'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700540 }
Timothy Chenf56c1b52020-04-28 17:00:43 -0700541
542 # root-gate clocks
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700543 rg_clks = {
544 clk: src
545 for grp in grps for (clk, src) in grp['clocks'].items()
546 if grp['name'] != 'powerup' and grp['sw_cg'] == 'no' and
547 not src_aon_attr[src]
548 }
Timothy Chenf56c1b52020-04-28 17:00:43 -0700549
550 # direct sw control clocks
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700551 sw_clks = {
552 clk: src
553 for grp in grps for (clk, src) in grp['clocks'].items()
554 if grp['sw_cg'] == 'yes' and not src_aon_attr[src]
555 }
Timothy Chenf56c1b52020-04-28 17:00:43 -0700556
557 # sw hint clocks
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700558 hint_clks = {
559 clk: src
560 for grp in grps for (clk, src) in grp['clocks'].items()
561 if grp['sw_cg'] == 'hint' and not src_aon_attr[src]
562 }
Timothy Chenf56c1b52020-04-28 17:00:43 -0700563
564 out = StringIO()
565 for idx, tpl in enumerate(tpls):
566 with tpl.open(mode='r', encoding='UTF-8') as fin:
567 tpl = Template(fin.read())
568 try:
569 out = tpl.render(cfg=top,
Timothy Chenb63f3b82020-06-30 17:10:57 -0700570 div_srcs=top['clocks']['derived_srcs'],
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700571 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700572 ft_clks=ft_clks,
573 rg_clks=rg_clks,
574 sw_clks=sw_clks,
575 hint_clks=hint_clks)
576 except: # noqa: E722
577 log.error(exceptions.text_error_template().render())
578
579 if out == "":
580 log.error("Cannot generate {}".format(names[idx]))
581 return
582
583 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
584 fout.write(genhdr + out)
585
586 # Generate reg files
587 with open(str(hjson_out), 'r') as out:
588 hjson_obj = hjson.load(out,
589 use_decimal=True,
590 object_pairs_hook=OrderedDict)
591 validate.validate(hjson_obj)
592 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700593
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700594
Timothy Chen4ba25312020-06-17 13:08:57 -0700595# generate pwrmgr
596def generate_pwrmgr(top, out_path):
597 log.info("Generating pwrmgr")
598
599 # Count number of interrupts
600 n_wkups = len(top["wakeups"])
601 log.info("Found {} wakeup signals".format(n_wkups))
602
603 if n_wkups < 1:
604 n_wkups = 1
605 log.warning("The design has no wakeup sources. Low power not supported")
606
607 # Define target path
608 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
609 rtl_path.mkdir(parents=True, exist_ok=True)
610 doc_path = out_path / 'ip/pwrmgr/data/autogen'
611 doc_path.mkdir(parents=True, exist_ok=True)
612
613 # So, read template files from ip directory.
614 tpl_path = out_path / '../ip/pwrmgr/data'
615 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
616
617 # Render and write out hjson
618 out = StringIO()
619 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
620 hjson_tpl = Template(fin.read())
621 try:
622 out = hjson_tpl.render(NumWkups=n_wkups)
623
624 except: # noqa: E722
625 log.error(exceptions.text_error_template().render())
626 log.info("pwrmgr hjson: %s" % out)
627
628 if out == "":
629 log.error("Cannot generate pwrmgr config file")
630 return
631
632 hjson_path = doc_path / "pwrmgr.hjson"
633 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
634 fout.write(genhdr + out)
635
636 # Generate reg files
637 with open(str(hjson_path), 'r') as out:
638 hjson_obj = hjson.load(out,
639 use_decimal=True,
640 object_pairs_hook=OrderedDict)
641 validate.validate(hjson_obj)
642 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
643
644
lowRISC Contributors802543a2019-08-31 12:12:56 +0100645def generate_top_ral(top, ip_objs, out_path):
646 # construct top ral block
647 top_block = gen_rtl.Block()
648 top_block.name = "chip"
649 top_block.base_addr = 0
650 top_block.width = int(top["datawidth"])
651
652 # add blocks
653 for ip_obj in ip_objs:
654 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
655
656 # add memories
657 if "memory" in top.keys():
658 for item in list(top["memory"]):
659 mem = gen_rtl.Window()
660 mem.name = item["name"]
661 mem.base_addr = int(item["base_addr"], 0)
662 mem.limit_addr = int(item["base_addr"], 0) + int(item["size"], 0)
Weicai Yang55b2cdf2020-04-10 15:40:30 -0700663 if "swaccess" in item.keys():
664 mem.dvrights = item["swaccess"]
665 else:
666 mem.dvrights = "RW"
lowRISC Contributors802543a2019-08-31 12:12:56 +0100667 mem.n_bits = top_block.width
668 top_block.wins.append(mem)
669
670 # get sub-block base addresses from top cfg
671 for block in top_block.blocks:
672 for module in top["module"]:
673 if block.name == module["name"]:
Philipp Wagnercd19f992020-07-02 14:33:59 +0100674 block.base_addr = int(module["base_addr"], 0)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100675 break
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700676
677 top_block.blocks.sort(key=lambda block: block.base_addr)
678 top_block.wins.sort(key=lambda win: win.base_addr)
679
lowRISC Contributors802543a2019-08-31 12:12:56 +0100680 # generate the top ral model with template
681 gen_dv.gen_ral(top_block, str(out_path))
682
683
684def main():
685 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700686 parser.add_argument('--topcfg',
687 '-t',
688 required=True,
689 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700690 parser.add_argument(
691 '--tpl',
692 '-c',
693 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -0700694 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100695 parser.add_argument(
696 '--outdir',
697 '-o',
698 help='''Target TOP directory.
699 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700700 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100701 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
702
703 # Generator options: 'no' series. cannot combined with 'only' series
704 parser.add_argument(
705 '--no-top',
706 action='store_true',
707 help="If defined, topgen doesn't generate top_{name} RTLs.")
708 parser.add_argument(
709 '--no-xbar',
710 action='store_true',
711 help="If defined, topgen doesn't generate crossbar RTLs.")
712 parser.add_argument(
713 '--no-plic',
714 action='store_true',
715 help="If defined, topgen doesn't generate the interrup controller RTLs."
716 )
717 parser.add_argument(
718 '--no-gen-hjson',
719 action='store_true',
720 help='''If defined, the tool assumes topcfg as a generated hjson.
721 So it bypasses the validation step and doesn't read ip and
722 xbar configurations
723 ''')
724
725 # Generator options: 'only' series. cannot combined with 'no' series
726 parser.add_argument(
727 '--top-only',
728 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700729 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100730 parser.add_argument(
731 '--xbar-only',
732 action='store_true',
733 help="If defined, the tool generates crossbar RTLs only")
734 parser.add_argument(
735 '--plic-only',
736 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000737 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100738 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700739 '--alert-handler-only',
740 action='store_true',
741 help="If defined, the tool generates alert handler hjson only")
742 parser.add_argument(
lowRISC Contributors802543a2019-08-31 12:12:56 +0100743 '--hjson-only',
744 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000745 help="If defined, the tool generates complete Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100746 # Generator options: generate dv ral model
747 parser.add_argument(
748 '--top_ral',
749 '-r',
750 default=False,
751 action='store_true',
752 help="If set, the tool generates top level RAL model for DV")
753
754 args = parser.parse_args()
755
756 # check combinations
757 if args.top_ral:
758 args.hjson_only = True
759 args.no_top = True
760
761 if args.hjson_only:
762 args.no_gen_hjson = False
763
764 if (args.no_top or args.no_xbar or
765 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -0700766 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100767 log.error(
768 "'no' series options cannot be used with 'only' series options")
769 raise SystemExit(sys.exc_info()[1])
770
Eunchan Kimc7452942019-12-19 17:04:37 -0800771 if not (args.hjson_only or args.plic_only or args.alert_handler_only or
772 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100773 log.error(
774 "Template file can be omitted only if '--hjson-only' is true")
775 raise SystemExit(sys.exc_info()[1])
776
777 if args.verbose:
778 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
779 else:
780 log.basicConfig(format="%(levelname)s: %(message)s")
781
782 if not args.outdir:
783 outdir = Path(args.topcfg).parent / ".."
784 log.info("TOP directory not given. Use %s", (outdir))
785 elif not Path(args.outdir).is_dir():
786 log.error("'--outdir' should point to writable directory")
787 raise SystemExit(sys.exc_info()[1])
788 else:
789 outdir = Path(args.outdir)
790
791 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700792 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100793
794 if not args.no_gen_hjson or args.hjson_only:
795 # load top configuration
796 try:
797 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800798 topcfg = hjson.load(ftop,
799 use_decimal=True,
800 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100801 except ValueError:
802 raise SystemExit(sys.exc_info()[1])
803
Timothy Chenf56c1b52020-04-28 17:00:43 -0700804 # Create filtered list
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700805 filter_list = [
Eunchan Kimc0c27c02020-06-03 17:11:46 -0700806 module['type'] for module in topcfg['module']
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700807 if 'generated' in module and module['generated'] == 'true'
808 ]
Timothy Chenf56c1b52020-04-28 17:00:43 -0700809 log.info("Filtered list is {}".format(filter_list))
810
Eunchan Kimba970df2020-04-17 10:21:01 -0700811 topname = topcfg["name"]
812
lowRISC Contributors802543a2019-08-31 12:12:56 +0100813 # Sweep the IP directory and gather the config files
814 ip_dir = Path(__file__).parents[1] / 'hw/ip'
815 ips = search_ips(ip_dir)
816
Timothy Chenf56c1b52020-04-28 17:00:43 -0700817 # exclude filtered IPs (to use top_${topname} one) and
lowRISC Contributors802543a2019-08-31 12:12:56 +0100818 ips = [x for x in ips if not x.parents[1].name in filter_list]
819
Timothy Chenf56c1b52020-04-28 17:00:43 -0700820 # Hack alert
821 # Generate clkmgr.hjson here so that it can be included below
822 # Unlike other generated hjsons, clkmgr thankfully does not require
823 # ip.hjson information. All the information is embedded within
824 # the top hjson file
825 amend_clocks(topcfg)
826 generate_clkmgr(topcfg, cfg_path, out_path)
827
lowRISC Contributors802543a2019-08-31 12:12:56 +0100828 # It may require two passes to check if the module is needed.
829 # TODO: first run of topgen will fail due to the absent of rv_plic.
830 # It needs to run up to amend_interrupt in merge_top function
831 # then creates rv_plic.hjson then run xbar generation.
832 hjson_dir = Path(args.topcfg).parent
lowRISC Contributors802543a2019-08-31 12:12:56 +0100833
Timothy Chenf56c1b52020-04-28 17:00:43 -0700834 for ip in filter_list:
835 log.info("Appending {}".format(ip))
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700836 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(
837 ip, ip)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700838 ips.append(ip_hjson)
Cindy Chenecc70ea2020-04-08 14:17:48 -0700839
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000840 # load Hjson and pass validate from reggen
lowRISC Contributors802543a2019-08-31 12:12:56 +0100841 try:
842 ip_objs = []
843 for x in ips:
844 # Skip if it is not in the module list
Eunchan Kim6599ba92020-04-13 15:27:16 -0700845 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100846 log.info(
847 "Skip module %s as it isn't in the top module list" %
848 x.stem)
849 continue
850
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700851 obj = hjson.load(x.open('r'),
852 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800853 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100854 if validate.validate(obj) != 0:
855 log.info("Parsing IP %s configuration failed. Skip" % x)
856 continue
857 ip_objs.append(obj)
858
859 except ValueError:
860 raise SystemExit(sys.exc_info()[1])
861
862 # Read the crossbars under the top directory
863 xbar_objs = get_hjsonobj_xbars(hjson_dir)
864
865 log.info("Detected crossbars: %s" %
866 (", ".join([x["name"] for x in xbar_objs])))
867
Timothy Chen3193b002019-10-04 16:56:05 -0700868 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700869 if error != 0:
870 raise SystemExit("Error occured while validating top.hjson")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100871
lowRISC Contributors802543a2019-08-31 12:12:56 +0100872 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
873
Eunchan Kim1a95dd92019-10-11 11:18:13 -0700874 genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
875 completecfg["name"])
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700876 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700877 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --hjson-only "
878 "-o hw/top_{topname}/\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100879
880 if args.top_ral:
881 generate_top_ral(completecfg, ip_objs, out_path)
882 else:
883 genhjson_path.write_text(genhdr + gencmd +
884 hjson.dumps(completecfg, for_json=True))
885
886 if args.hjson_only:
887 log.info("hjson is generated. Exiting...")
888 sys.exit()
889
890 if args.no_gen_hjson:
891 # load top.complete configuration
892 try:
893 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800894 completecfg = hjson.load(ftop,
895 use_decimal=True,
896 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100897 except ValueError:
898 raise SystemExit(sys.exc_info()[1])
899
900 # Generate PLIC
Eunchan Kim6599ba92020-04-13 15:27:16 -0700901 if not args.no_plic and \
Michael Schaffner666dde12019-10-25 11:57:54 -0700902 not args.alert_handler_only and \
903 not args.xbar_only:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100904 generate_plic(completecfg, out_path)
Michael Schaffner666dde12019-10-25 11:57:54 -0700905 if args.plic_only:
906 sys.exit()
907
908 # Generate Alert Handler
909 if not args.xbar_only:
910 generate_alert_handler(completecfg, out_path)
911 if args.alert_handler_only:
912 sys.exit()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100913
Timothy Chenf56c1b52020-04-28 17:00:43 -0700914 # Generate Pinmux
Michael Schaffner60157962020-05-01 19:11:28 -0700915 generate_pinmux_and_padctrl(completecfg, out_path)
Eunchan Kim436d2242019-10-29 17:25:51 -0700916
Timothy Chen4ba25312020-06-17 13:08:57 -0700917 # Generate Pwrmgr
918 generate_pwrmgr(completecfg, out_path)
919
lowRISC Contributors802543a2019-08-31 12:12:56 +0100920 # Generate xbars
921 if not args.no_xbar or args.xbar_only:
922 generate_xbars(completecfg, out_path)
923
lowRISC Contributors802543a2019-08-31 12:12:56 +0100924 top_name = completecfg["name"]
925
926 if not args.no_top or args.top_only:
Eunchan Kim632c6f72019-09-30 11:11:51 -0700927 tpl_path = Path(args.tpl)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700928
Sam Elliott7e36bd72020-04-22 14:05:49 +0100929 def render_template(out_name_tpl, out_dir, **other_info):
930 top_tplpath = tpl_path / ((out_name_tpl + '.tpl') % (top_name))
Eunchan Kimfd561be2020-04-24 15:42:11 -0700931 template_contents = generate_top(completecfg, str(top_tplpath),
932 **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100933
Sam Elliott7e36bd72020-04-22 14:05:49 +0100934 rendered_dir = out_path / out_dir
935 rendered_dir.mkdir(parents=True, exist_ok=True)
936 rendered_path = rendered_dir / (out_name_tpl % (top_name))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100937
Sam Elliott7e36bd72020-04-22 14:05:49 +0100938 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
939 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -0700940
Sam Elliott7e36bd72020-04-22 14:05:49 +0100941 return rendered_path
Eunchan Kim436d2242019-10-29 17:25:51 -0700942
Sam Elliott7e36bd72020-04-22 14:05:49 +0100943 # SystemVerilog Top:
944 # 'top_earlgrey.sv.tpl' -> 'rtl/autogen/top_earlgrey.sv'
945 render_template('top_%s.sv', 'rtl/autogen')
Eunchan Kim436d2242019-10-29 17:25:51 -0700946
Srikrishna Iyer5b4dde92020-05-14 00:02:15 -0700947 # 'top_earlgrey_pkg.sv.tpl' -> 'rtl/autogen/top_earlgrey_pkg.sv'
948 render_template('top_%s_pkg.sv', 'rtl/autogen')
949
Sam Elliott2a4448b2020-04-23 11:15:43 +0100950 # C Header + C File + Clang-format file
Sam Elliott7e36bd72020-04-22 14:05:49 +0100951 # The C file needs some information from when the header is generated,
952 # so we keep this in a dictionary here.
953 c_gen_info = {}
954
Sam Elliott2a4448b2020-04-23 11:15:43 +0100955 # 'clang-format' -> 'sw/autogen/.clang-format'
956 cformat_tplpath = tpl_path / 'clang-format'
957 cformat_dir = out_path / 'sw/autogen'
958 cformat_dir.mkdir(parents=True, exist_ok=True)
959 cformat_path = cformat_dir / '.clang-format'
960 cformat_path.write_text(cformat_tplpath.read_text())
961
Sam Elliott7e36bd72020-04-22 14:05:49 +0100962 # 'top_earlgrey.h.tpl' -> 'sw/autogen/top_earlgrey.h'
Eunchan Kimfd561be2020-04-24 15:42:11 -0700963 cheader_path = render_template('top_%s.h',
964 'sw/autogen',
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +0100965 c_gen_info=c_gen_info).resolve()
Sam Elliott7e36bd72020-04-22 14:05:49 +0100966
967 # Save the relative header path into `c_gen_info`
968 rel_header_path = cheader_path.relative_to(SRCTREE_TOP)
969 c_gen_info["header_path"] = str(rel_header_path)
970
971 # 'top_earlgrey.c.tpl' -> 'sw/autogen/top_earlgrey.c'
Eunchan Kimfd561be2020-04-24 15:42:11 -0700972 render_template('top_%s.c', 'sw/autogen', c_gen_info=c_gen_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100973
Sam Elliott519f7462020-05-11 16:53:24 +0100974 # 'top_earlgrey_memory.ld.tpl' -> 'sw/autogen/top_earlgrey_memory.ld'
975 render_template('top_%s_memory.ld', 'sw/autogen')
976
Sam Elliott37d4fbe2020-04-22 14:05:49 +0100977 # Fix the C header guard, which will have the wrong name
Eunchan Kimfd561be2020-04-24 15:42:11 -0700978 subprocess.run(["util/fix_include_guard.py",
979 str(cheader_path)],
980 universal_newlines=True,
981 stdout=subprocess.DEVNULL,
982 stderr=subprocess.DEVNULL,
983 check=True,
984 cwd=str(SRCTREE_TOP))
Sam Elliott37d4fbe2020-04-22 14:05:49 +0100985
Weicai Yang1777ebb2020-05-19 17:32:24 -0700986 # generate chip level xbar TB
987 tb_files = ["xbar_env_pkg__params.sv", "tb__xbar_connect.sv"]
988 for fname in tb_files:
989 tpl_fname = "%s.tpl" % (fname)
990 xbar_chip_data_path = tpl_path / tpl_fname
991 template_contents = generate_top(completecfg,
992 str(xbar_chip_data_path))
993
994 rendered_dir = tpl_path / '../dv/autogen'
995 rendered_dir.mkdir(parents=True, exist_ok=True)
996 rendered_path = rendered_dir / fname
997
998 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
999 fout.write(template_contents)
1000
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001001
lowRISC Contributors802543a2019-08-31 12:12:56 +01001002if __name__ == "__main__":
1003 main()