blob: 0f38602b9d5df9c5b7fce774337dcee0001888bd [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
Eunchan Kime0d37fe2020-08-03 12:05:21 -070014from copy import deepcopy
lowRISC Contributors802543a2019-08-31 12:12:56 +010015
16import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070017from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080018from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010019
20import tlgen
Cindy Chen92924942020-08-03 11:59:09 -070021from reggen import gen_dv, gen_rtl, validate
Weicai Yang1777ebb2020-05-19 17:32:24 -070022from topgen import (amend_clocks, get_hjsonobj_xbars, merge_top, search_ips,
23 validate_top)
Eunchan Kim2c813b42020-08-03 16:22:56 -070024from topgen import intermodule as im
lowRISC Contributors802543a2019-08-31 12:12:56 +010025
26# Common header for generated files
27genhdr = '''// Copyright lowRISC contributors.
28// Licensed under the Apache License, Version 2.0, see LICENSE for details.
29// SPDX-License-Identifier: Apache-2.0
30//
31// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
32// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
33'''
34
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010035SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070036
Eunchan Kimfd561be2020-04-24 15:42:11 -070037
Sam Elliott7e36bd72020-04-22 14:05:49 +010038def generate_top(top, tpl_filename, **kwargs):
39 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010040
Eunchan Kimcb28a172019-10-08 16:35:48 -070041 try:
Sam Elliott7e36bd72020-04-22 14:05:49 +010042 return top_tpl.render(top=top, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070043 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070044 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010045 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010046
47
48def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070049 topname = top["name"]
50 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
51 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070052
lowRISC Contributors802543a2019-08-31 12:12:56 +010053 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080054 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
55 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010056 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080057 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010058
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070059 # Generate output of crossbar with complete fields
60 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
61 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070062 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070063
lowRISC Contributors802543a2019-08-31 12:12:56 +010064 if not tlgen.elaborate(xbar):
65 log.error("Elaboration failed." + repr(xbar))
66
Eunchan Kimcb28a172019-10-08 16:35:48 -070067 try:
Eunchan Kim9191f262020-07-30 16:37:40 -070068 results = tlgen.generate(xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -070069 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070070 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010071
Eunchan Kim9191f262020-07-30 16:37:40 -070072 ip_path = out_path / 'ip/xbar_{}'.format(obj["name"])
73
74 for filename, filecontent in results:
75 filepath = ip_path / filename
76 filepath.parent.mkdir(parents=True, exist_ok=True)
77 with filepath.open(mode='w', encoding='UTF-8') as fout:
78 fout.write(filecontent)
79
Eunchan Kimc7452942019-12-19 17:04:37 -080080 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010081 dv_path.mkdir(parents=True, exist_ok=True)
82
Weicai Yange4315d22020-01-09 10:37:42 -080083 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -070084 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010085
Eunchan Kime0d37fe2020-08-03 12:05:21 -070086 # Read back the comportable IP and amend to Xbar
87 xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
88 with xbar_ipfile.open() as fxbar:
89 xbar_ipobj = hjson.load(fxbar,
90 use_decimal=True,
91 object_pairs_hook=OrderedDict)
92
93 # Deepcopy of the inter_signal_list.
94 # As of writing the code, it is not expected to write-back the
95 # read xbar objects into files. Still, as `inter_signal_list` is
96 # modified in the `elab_intermodule()` stage, it is better to keep
97 # the original content.
98 obj["inter_signal_list"] = deepcopy(
99 xbar_ipobj["inter_signal_list"])
100
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800101
Michael Schaffner666dde12019-10-25 11:57:54 -0700102def generate_alert_handler(top, out_path):
103 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -0800104 esc_cnt_dw = 32
105 accu_cnt_dw = 16
106 lfsr_seed = 2**31 - 1
107 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700108 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800109 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700110
Eunchan Kimba970df2020-04-17 10:21:01 -0700111 topname = top["name"]
112
Michael Schaffner666dde12019-10-25 11:57:54 -0700113 # check if there are any params to be passed through reggen and placed into
114 # the generated package
115 ip_list_in_top = [x["name"].lower() for x in top["module"]]
116 ah_idx = ip_list_in_top.index("alert_handler")
117 if 'localparam' in top['module'][ah_idx]:
118 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
119 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
120 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
121 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
122 if 'LfsrSeed' in top['module'][ah_idx]['localparam']:
123 lfsr_seed = int(top['module'][ah_idx]['localparam']['LfsrSeed'], 0)
124
125 if esc_cnt_dw < 1:
126 log.error("EscCntDw must be larger than 0")
127 if accu_cnt_dw < 1:
128 log.error("AccuCntDw must be larger than 0")
129 if (lfsr_seed & 0xFFFFFFFF) == 0 or lfsr_seed > 2**32:
130 log.error("LFSR seed out of range or zero")
131
132 # Count number of interrupts
133 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
134
135 if n_alerts < 1:
136 # set number of alerts to 1 such that the config is still valid
137 # that input will be tied off
138 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800139 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700140 else:
141 async_on = ""
142 for alert in top['alert']:
Timothy Chen322f2542020-08-05 16:28:18 -0700143 for k in range(alert['width']):
144 async_on = str(alert['async']) + async_on
Michael Schaffner666dde12019-10-25 11:57:54 -0700145 async_on = ("%d'b" % n_alerts) + async_on
146
147 log.info("alert handler parameterization:")
148 log.info("NAlerts = %d" % n_alerts)
149 log.info("EscCntDw = %d" % esc_cnt_dw)
150 log.info("AccuCntDw = %d" % accu_cnt_dw)
151 log.info("LfsrSeed = %d" % lfsr_seed)
152 log.info("AsyncOn = %s" % async_on)
153
Michael Schaffner666dde12019-10-25 11:57:54 -0700154 # Define target path
155 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
156 rtl_path.mkdir(parents=True, exist_ok=True)
157 doc_path = out_path / 'ip/alert_handler/data/autogen'
158 doc_path.mkdir(parents=True, exist_ok=True)
Cindy Chene27c6c62020-05-18 16:06:28 -0700159 dv_path = out_path / 'ip/alert_handler/dv'
160 dv_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700161
162 # Generating IP top module script is not generalized yet.
163 # So, topgen reads template files from alert_handler directory directly.
164 tpl_path = out_path / '../ip/alert_handler/data'
165 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
Cindy Chene27c6c62020-05-18 16:06:28 -0700166 dv_tpl_path = tpl_path / 'alert_handler_env_pkg__params.sv.tpl'
Michael Schaffner666dde12019-10-25 11:57:54 -0700167
168 # Generate Register Package and RTLs
169 out = StringIO()
170 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
171 hjson_tpl = Template(fin.read())
172 try:
173 out = hjson_tpl.render(n_alerts=n_alerts,
174 esc_cnt_dw=esc_cnt_dw,
175 accu_cnt_dw=accu_cnt_dw,
176 lfsr_seed=lfsr_seed,
177 async_on=async_on,
178 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700179 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700180 log.error(exceptions.text_error_template().render())
181 log.info("alert_handler hjson: %s" % out)
182
183 if out == "":
184 log.error("Cannot generate alert_handler config file")
185 return
186
187 hjson_gen_path = doc_path / "alert_handler.hjson"
188 gencmd = (
Cindy Chenbd401c32020-07-31 12:09:52 -0700189 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --alert-handler-only "
Eunchan Kimba970df2020-04-17 10:21:01 -0700190 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700191 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
192 fout.write(genhdr + gencmd + out)
193
194 # Generate register RTLs (currently using shell execute)
195 # TODO: More secure way to gneerate RTL
196 hjson_obj = hjson.loads(out,
197 use_decimal=True,
198 object_pairs_hook=validate.checking_dict)
199 validate.validate(hjson_obj)
200 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
201
Cindy Chene27c6c62020-05-18 16:06:28 -0700202 # generate testbench for alert_handler
203 with dv_tpl_path.open(mode='r', encoding='UTF-8') as fin:
204 dv_tpl = Template(fin.read())
205 try:
206 out = dv_tpl.render(n_alerts=n_alerts, async_on=async_on)
207 except: # noqa : E722
208 log.error(exceptions.text_error_template().render())
209 log.info("ALERT_HANDLER DV: %s" % out)
210 if out == "":
211 log.error("Cannot generate dv alert_handler parameter file")
212 return
213
214 dv_gen_path = dv_path / 'alert_handler_env_pkg__params.sv'
215 with dv_gen_path.open(mode='w', encoding='UTF-8') as fout:
216 fout.write(genhdr + gencmd + out)
217
Michael Schaffner666dde12019-10-25 11:57:54 -0700218
lowRISC Contributors802543a2019-08-31 12:12:56 +0100219def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700220 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100221 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700222 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
223 # So, total number of interrupts are the number of entries in the list + 1
224 src = sum([x["width"] if "width" in x else 1
225 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100226
227 # Target and priority: Currently fixed
228 target = int(top["num_cores"], 0) if "num_cores" in top else 1
229 prio = 3
230
231 # Define target path
232 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700233 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700234 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100235 rtl_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700236 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100237 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800238 hjson_path = out_path / 'ip/rv_plic/data/autogen'
239 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100240
241 # Generating IP top module script is not generalized yet.
242 # So, topgen reads template files from rv_plic directory directly.
243 # Next, if the ip top gen tool is placed in util/ we can import the library.
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +0200244 tpl_path = out_path / '../ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700245 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
246 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100247
248 # Generate Register Package and RTLs
249 out = StringIO()
250 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
251 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700252 try:
253 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700254 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700255 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100256 log.info("RV_PLIC hjson: %s" % out)
257
258 if out == "":
259 log.error("Cannot generate interrupt controller config file")
260 return
261
Michael Schaffner7f134962019-11-03 12:44:50 -0800262 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700263 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700264 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
265 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100266 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
267 fout.write(genhdr + gencmd + out)
268
269 # Generate register RTLs (currently using shell execute)
Cindy Chene27c6c62020-05-18 16:06:28 -0700270 # TODO: More secure way to generate RTL
lowRISC Contributors802543a2019-08-31 12:12:56 +0100271 hjson_obj = hjson.loads(out,
272 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800273 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100274 validate.validate(hjson_obj)
275 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
276
277 # Generate RV_PLIC Top Module
278 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
279 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700280 try:
281 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700282 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700283 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100284 log.info("RV_PLIC RTL: %s" % out)
285
286 if out == "":
287 log.error("Cannot generate interrupt controller RTL")
288 return
289
290 rtl_gen_path = rtl_path / "rv_plic.sv"
291 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
292 fout.write(genhdr + gencmd + out)
293
Eunchan Kimba970df2020-04-17 10:21:01 -0700294
Michael Schaffner60157962020-05-01 19:11:28 -0700295def generate_pinmux_and_padctrl(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700296 topname = top["name"]
Eunchan Kim436d2242019-10-29 17:25:51 -0700297 # MIO Pads
Michael Schaffner57c490d2020-04-29 15:08:55 -0700298 n_mio_pads = top["pinmux"]["num_mio"]
299 if n_mio_pads <= 0:
300 # TODO: add support for no MIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700301 log.error("Topgen does currently not support generation of a top " +
302 "without a pinmux.")
303 return
304
305 if "padctrl" not in top:
306 # TODO: add support for no MIO case
307 log.error("Topgen does currently not support generation of a top " +
308 "without a padctrl instance.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700309 return
310
311 # Get number of wakeup detectors
312 if "num_wkup_detect" in top["pinmux"]:
313 num_wkup_detect = top["pinmux"]["num_wkup_detect"]
314 else:
315 num_wkup_detect = 1
316
317 if num_wkup_detect <= 0:
318 # TODO: add support for no wakeup counter case
Michael Schaffner60157962020-05-01 19:11:28 -0700319 log.error("Topgen does currently not support generation of a top " +
320 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700321 return
322
323 if "wkup_cnt_width" in top["pinmux"]:
324 wkup_cnt_width = top["pinmux"]["wkup_cnt_width"]
325 else:
326 wkup_cnt_width = 8
327
328 if wkup_cnt_width <= 1:
329 log.error("Wakeup counter width must be greater equal 2.")
Eunchan Kim436d2242019-10-29 17:25:51 -0700330 return
331
332 # Total inputs/outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700333 # Validation ensures that the width field is present.
Michael Schaffner60157962020-05-01 19:11:28 -0700334 num_mio_inputs = sum([x["width"] for x in top["pinmux"]["inputs"]])
335 num_mio_outputs = sum([x["width"] for x in top["pinmux"]["outputs"]])
336 num_mio_inouts = sum([x["width"] for x in top["pinmux"]["inouts"]])
Eunchan Kim436d2242019-10-29 17:25:51 -0700337
Michael Schaffner60157962020-05-01 19:11:28 -0700338 num_dio_inputs = sum([
339 x["width"] if x["type"] == "input" else 0 for x in top["pinmux"]["dio"]
340 ])
341 num_dio_outputs = sum([
342 x["width"] if x["type"] == "output" else 0
343 for x in top["pinmux"]["dio"]
344 ])
345 num_dio_inouts = sum([
346 x["width"] if x["type"] == "inout" else 0 for x in top["pinmux"]["dio"]
347 ])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700348
349 n_mio_periph_in = num_mio_inouts + num_mio_inputs
350 n_mio_periph_out = num_mio_inouts + num_mio_outputs
351 n_dio_periph_in = num_dio_inouts + num_dio_inputs
352 n_dio_periph_out = num_dio_inouts + num_dio_outputs
353 n_dio_pads = num_dio_inouts + num_dio_inputs + num_dio_outputs
354
355 if n_dio_pads <= 0:
356 # TODO: add support for no DIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700357 log.error("Topgen does currently not support generation of a top " +
358 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700359 return
360
361 log.info("Generating pinmux with following info from hjson:")
362 log.info("num_mio_inputs: %d" % num_mio_inputs)
363 log.info("num_mio_outputs: %d" % num_mio_outputs)
364 log.info("num_mio_inouts: %d" % num_mio_inouts)
365 log.info("num_dio_inputs: %d" % num_dio_inputs)
366 log.info("num_dio_outputs: %d" % num_dio_outputs)
367 log.info("num_dio_inouts: %d" % num_dio_inouts)
368 log.info("num_wkup_detect: %d" % num_wkup_detect)
369 log.info("wkup_cnt_width: %d" % wkup_cnt_width)
370 log.info("This translates to:")
371 log.info("n_mio_periph_in: %d" % n_mio_periph_in)
372 log.info("n_mio_periph_out: %d" % n_mio_periph_out)
373 log.info("n_dio_periph_in: %d" % n_dio_periph_in)
374 log.info("n_dio_periph_out: %d" % n_dio_periph_out)
375 log.info("n_dio_pads: %d" % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700376
377 # Target path
378 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
379 # data: pinmux.hjson
380 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
381 rtl_path.mkdir(parents=True, exist_ok=True)
382 data_path = out_path / 'ip/pinmux/data/autogen'
383 data_path.mkdir(parents=True, exist_ok=True)
384
385 # Template path
386 tpl_path = out_path / '../ip/pinmux/data/pinmux.hjson.tpl'
387
388 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700389 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
390 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700391
392 hjson_gen_path = data_path / "pinmux.hjson"
393
394 out = StringIO()
395 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
396 hjson_tpl = Template(fin.read())
397 try:
Michael Schaffner57c490d2020-04-29 15:08:55 -0700398 # TODO: pass in information about always-on peripherals
399 # TODO: pass in information on which DIOs can be selected
400 # as wakeup signals
401 # TODO: pass in signal names such that we can introduce
402 # named enums for select signals
Michael Schaffner60157962020-05-01 19:11:28 -0700403 out = hjson_tpl.render(
404 n_mio_periph_in=n_mio_periph_in,
405 n_mio_periph_out=n_mio_periph_out,
406 n_mio_pads=n_mio_pads,
407 # each DIO has in, out and oe wires
408 # some of these have to be tied off in the
409 # top, depending on the type.
410 n_dio_periph_in=n_dio_pads,
411 n_dio_periph_out=n_dio_pads,
412 n_dio_pads=n_dio_pads,
413 n_wkup_detect=num_wkup_detect,
414 wkup_cnt_width=wkup_cnt_width)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700415 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700416 log.error(exceptions.text_error_template().render())
417 log.info("PINMUX HJSON: %s" % out)
418
419 if out == "":
420 log.error("Cannot generate pinmux HJSON")
421 return
422
423 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
424 fout.write(genhdr + gencmd + out)
425
426 hjson_obj = hjson.loads(out,
427 use_decimal=True,
428 object_pairs_hook=validate.checking_dict)
429 validate.validate(hjson_obj)
430 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
431
Michael Schaffner60157962020-05-01 19:11:28 -0700432 # Target path
433 # rtl: padctrl_reg_pkg.sv & padctrl_reg_top.sv
434 # data: padctrl.hjson
435 rtl_path = out_path / 'ip/padctrl/rtl/autogen'
436 rtl_path.mkdir(parents=True, exist_ok=True)
437 data_path = out_path / 'ip/padctrl/data/autogen'
438 data_path.mkdir(parents=True, exist_ok=True)
439
440 # Template path
441 tpl_path = out_path / '../ip/padctrl/data/padctrl.hjson.tpl'
442
443 # Generate register package and RTLs
444 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
445 "-o hw/top_{topname}/\n\n".format(topname=topname))
446
447 hjson_gen_path = data_path / "padctrl.hjson"
448
449 out = StringIO()
450 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
451 hjson_tpl = Template(fin.read())
452 try:
453 out = hjson_tpl.render(n_mio_pads=n_mio_pads,
454 n_dio_pads=n_dio_pads,
Michael Schaffner15b1bc92020-06-29 21:37:14 -0700455 attr_dw=10)
Michael Schaffner60157962020-05-01 19:11:28 -0700456 except: # noqa: E722
457 log.error(exceptions.text_error_template().render())
458 log.info("PADCTRL HJSON: %s" % out)
459
460 if out == "":
461 log.error("Cannot generate padctrl HJSON")
462 return
463
464 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
465 fout.write(genhdr + gencmd + out)
466
467 hjson_obj = hjson.loads(out,
468 use_decimal=True,
469 object_pairs_hook=validate.checking_dict)
470 validate.validate(hjson_obj)
471 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
472
473
Timothy Chenf56c1b52020-04-28 17:00:43 -0700474def generate_clkmgr(top, cfg_path, out_path):
475
476 # Target paths
477 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
478 rtl_path.mkdir(parents=True, exist_ok=True)
479 data_path = out_path / 'ip/clkmgr/data/autogen'
480 data_path.mkdir(parents=True, exist_ok=True)
481
482 # Template paths
483 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700484 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
485 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700486
487 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700488 rtl_out = rtl_path / 'clkmgr.sv'
489 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700490
491 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
492 outputs = [hjson_out, rtl_out, pkg_out]
493 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
494
495 # clock classification
496 grps = top['clocks']['groups']
497
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700498 src_aon_attr = OrderedDict()
Timothy Chenf56c1b52020-04-28 17:00:43 -0700499 ft_clks = OrderedDict()
500 rg_clks = OrderedDict()
501 sw_clks = OrderedDict()
502 hint_clks = OrderedDict()
503
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700504 # construct a dictionary of the aon attribute for easier lookup
505 # ie, src_name_A: True, src_name_B: False
Timothy Chenb63f3b82020-06-30 17:10:57 -0700506 for src in top['clocks']['srcs'] + top['clocks']['derived_srcs']:
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700507 if src['aon'] == 'yes':
508 src_aon_attr[src['name']] = True
509 else:
510 src_aon_attr[src['name']] = False
511
512 rg_srcs = [src for (src, attr) in src_aon_attr.items() if not attr]
513
514 # clocks fed through clkmgr but are not disturbed in any way
515 # This maintains the clocking structure consistency
Timothy Chenb63f3b82020-06-30 17:10:57 -0700516 # This includes two groups of clocks
517 # Clocks fed from the always-on source
518 # Clocks fed to the powerup group
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100519 ft_clks = OrderedDict([
520 (clk, src)
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700521 for grp in grps for (clk, src) in grp['clocks'].items()
Timothy Chenb63f3b82020-06-30 17:10:57 -0700522 if src_aon_attr[src] or grp['name'] == 'powerup'
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100523 ])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700524
525 # root-gate clocks
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100526 rg_clks = OrderedDict([
527 (clk, src)
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700528 for grp in grps for (clk, src) in grp['clocks'].items()
529 if grp['name'] != 'powerup' and grp['sw_cg'] == 'no' and
530 not src_aon_attr[src]
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100531 ])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700532
533 # direct sw control clocks
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100534 sw_clks = OrderedDict([
535 (clk, src)
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700536 for grp in grps for (clk, src) in grp['clocks'].items()
537 if grp['sw_cg'] == 'yes' and not src_aon_attr[src]
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100538 ])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700539
540 # sw hint clocks
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100541 hint_clks = OrderedDict([
542 (clk, src)
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700543 for grp in grps for (clk, src) in grp['clocks'].items()
544 if grp['sw_cg'] == 'hint' and not src_aon_attr[src]
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100545 ])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700546
Timothy Chenf56c1b52020-04-28 17:00:43 -0700547 for idx, tpl in enumerate(tpls):
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100548 out = ""
Timothy Chenf56c1b52020-04-28 17:00:43 -0700549 with tpl.open(mode='r', encoding='UTF-8') as fin:
550 tpl = Template(fin.read())
551 try:
552 out = tpl.render(cfg=top,
Timothy Chenb63f3b82020-06-30 17:10:57 -0700553 div_srcs=top['clocks']['derived_srcs'],
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700554 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700555 ft_clks=ft_clks,
556 rg_clks=rg_clks,
557 sw_clks=sw_clks,
558 hint_clks=hint_clks)
559 except: # noqa: E722
560 log.error(exceptions.text_error_template().render())
561
562 if out == "":
563 log.error("Cannot generate {}".format(names[idx]))
564 return
565
566 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
567 fout.write(genhdr + out)
568
569 # Generate reg files
570 with open(str(hjson_out), 'r') as out:
571 hjson_obj = hjson.load(out,
572 use_decimal=True,
573 object_pairs_hook=OrderedDict)
574 validate.validate(hjson_obj)
575 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700576
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700577
Timothy Chen4ba25312020-06-17 13:08:57 -0700578# generate pwrmgr
579def generate_pwrmgr(top, out_path):
580 log.info("Generating pwrmgr")
581
582 # Count number of interrupts
583 n_wkups = len(top["wakeups"])
584 log.info("Found {} wakeup signals".format(n_wkups))
585
586 if n_wkups < 1:
587 n_wkups = 1
Eunchan Kim9191f262020-07-30 16:37:40 -0700588 log.warning(
589 "The design has no wakeup sources. Low power not supported")
Timothy Chen4ba25312020-06-17 13:08:57 -0700590
591 # Define target path
592 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
593 rtl_path.mkdir(parents=True, exist_ok=True)
594 doc_path = out_path / 'ip/pwrmgr/data/autogen'
595 doc_path.mkdir(parents=True, exist_ok=True)
596
597 # So, read template files from ip directory.
598 tpl_path = out_path / '../ip/pwrmgr/data'
599 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
600
601 # Render and write out hjson
602 out = StringIO()
603 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
604 hjson_tpl = Template(fin.read())
605 try:
606 out = hjson_tpl.render(NumWkups=n_wkups)
607
608 except: # noqa: E722
609 log.error(exceptions.text_error_template().render())
610 log.info("pwrmgr hjson: %s" % out)
611
612 if out == "":
613 log.error("Cannot generate pwrmgr config file")
614 return
615
616 hjson_path = doc_path / "pwrmgr.hjson"
617 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
618 fout.write(genhdr + out)
619
620 # Generate reg files
621 with open(str(hjson_path), 'r') as out:
622 hjson_obj = hjson.load(out,
623 use_decimal=True,
624 object_pairs_hook=OrderedDict)
625 validate.validate(hjson_obj)
626 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
627
628
Timothy Chen322f2542020-08-05 16:28:18 -0700629def generate_top_only(top_only_list, out_path):
630 log.info("Generating top only modules")
631
632 for ip in top_only_list:
633 rtl_path = out_path / "ip/{}/rtl".format(ip)
634 hjson_path = out_path / "ip/{}/data/{}.hjson".format(ip, ip)
635 log.info("Generating top modules {}, hjson: {}, output: {}".format(
636 ip, hjson_path, rtl_path))
637
638 # Generate reg files
639 with open(str(hjson_path), 'r') as out:
640 hjson_obj = hjson.load(out,
641 use_decimal=True,
642 object_pairs_hook=OrderedDict)
643 validate.validate(hjson_obj)
644 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
645
646
lowRISC Contributors802543a2019-08-31 12:12:56 +0100647def generate_top_ral(top, ip_objs, out_path):
648 # construct top ral block
649 top_block = gen_rtl.Block()
650 top_block.name = "chip"
651 top_block.base_addr = 0
652 top_block.width = int(top["datawidth"])
653
654 # add blocks
655 for ip_obj in ip_objs:
656 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
657
658 # add memories
659 if "memory" in top.keys():
660 for item in list(top["memory"]):
661 mem = gen_rtl.Window()
662 mem.name = item["name"]
663 mem.base_addr = int(item["base_addr"], 0)
664 mem.limit_addr = int(item["base_addr"], 0) + int(item["size"], 0)
Weicai Yang55b2cdf2020-04-10 15:40:30 -0700665 if "swaccess" in item.keys():
666 mem.dvrights = item["swaccess"]
667 else:
668 mem.dvrights = "RW"
lowRISC Contributors802543a2019-08-31 12:12:56 +0100669 mem.n_bits = top_block.width
670 top_block.wins.append(mem)
671
672 # get sub-block base addresses from top cfg
673 for block in top_block.blocks:
674 for module in top["module"]:
675 if block.name == module["name"]:
Philipp Wagnercd19f992020-07-02 14:33:59 +0100676 block.base_addr = int(module["base_addr"], 0)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100677 break
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700678
679 top_block.blocks.sort(key=lambda block: block.base_addr)
680 top_block.wins.sort(key=lambda win: win.base_addr)
681
lowRISC Contributors802543a2019-08-31 12:12:56 +0100682 # generate the top ral model with template
683 gen_dv.gen_ral(top_block, str(out_path))
684
685
686def main():
687 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700688 parser.add_argument('--topcfg',
689 '-t',
690 required=True,
691 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700692 parser.add_argument(
693 '--tpl',
694 '-c',
695 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -0700696 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100697 parser.add_argument(
698 '--outdir',
699 '-o',
700 help='''Target TOP directory.
701 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700702 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100703 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
704
705 # Generator options: 'no' series. cannot combined with 'only' series
706 parser.add_argument(
707 '--no-top',
708 action='store_true',
709 help="If defined, topgen doesn't generate top_{name} RTLs.")
710 parser.add_argument(
711 '--no-xbar',
712 action='store_true',
713 help="If defined, topgen doesn't generate crossbar RTLs.")
714 parser.add_argument(
715 '--no-plic',
716 action='store_true',
717 help="If defined, topgen doesn't generate the interrup controller RTLs."
718 )
lowRISC Contributors802543a2019-08-31 12:12:56 +0100719
720 # Generator options: 'only' series. cannot combined with 'no' series
721 parser.add_argument(
722 '--top-only',
723 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700724 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100725 parser.add_argument(
726 '--xbar-only',
727 action='store_true',
728 help="If defined, the tool generates crossbar RTLs only")
729 parser.add_argument(
730 '--plic-only',
731 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000732 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100733 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700734 '--alert-handler-only',
735 action='store_true',
736 help="If defined, the tool generates alert handler hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100737 # Generator options: generate dv ral model
738 parser.add_argument(
739 '--top_ral',
740 '-r',
741 default=False,
742 action='store_true',
743 help="If set, the tool generates top level RAL model for DV")
744
745 args = parser.parse_args()
746
747 # check combinations
748 if args.top_ral:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100749 args.no_top = True
750
lowRISC Contributors802543a2019-08-31 12:12:56 +0100751 if (args.no_top or args.no_xbar or
752 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -0700753 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100754 log.error(
755 "'no' series options cannot be used with 'only' series options")
756 raise SystemExit(sys.exc_info()[1])
757
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700758 if not (args.top_ral or args.plic_only or args.alert_handler_only or
Eunchan Kimc7452942019-12-19 17:04:37 -0800759 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100760 log.error(
761 "Template file can be omitted only if '--hjson-only' is true")
762 raise SystemExit(sys.exc_info()[1])
763
764 if args.verbose:
765 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
766 else:
767 log.basicConfig(format="%(levelname)s: %(message)s")
768
769 if not args.outdir:
770 outdir = Path(args.topcfg).parent / ".."
771 log.info("TOP directory not given. Use %s", (outdir))
772 elif not Path(args.outdir).is_dir():
773 log.error("'--outdir' should point to writable directory")
774 raise SystemExit(sys.exc_info()[1])
775 else:
776 outdir = Path(args.outdir)
777
778 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700779 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100780
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700781 try:
782 with open(args.topcfg, 'r') as ftop:
783 topcfg = hjson.load(ftop,
784 use_decimal=True,
785 object_pairs_hook=OrderedDict)
786 except ValueError:
787 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100788
Timothy Chen322f2542020-08-05 16:28:18 -0700789 # Create generated list
790 # These modules are generated through topgen
791 generated_list = [
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700792 module['type'] for module in topcfg['module']
793 if 'generated' in module and module['generated'] == 'true'
794 ]
Timothy Chen322f2542020-08-05 16:28:18 -0700795 log.info("Filtered list is {}".format(generated_list))
796
797 # These modules are NOT generated but belong to a specific top
798 # and therefore not part of "hw/ip"
799 top_only_list = [
800 module['type'] for module in topcfg['module']
801 if 'top_only' in module and module['top_only'] == 'true'
802 ]
803 log.info("Filtered list is {}".format(top_only_list))
Timothy Chenf56c1b52020-04-28 17:00:43 -0700804
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700805 topname = topcfg["name"]
Eunchan Kimba970df2020-04-17 10:21:01 -0700806
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700807 # Sweep the IP directory and gather the config files
808 ip_dir = Path(__file__).parents[1] / 'hw/ip'
809 ips = search_ips(ip_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100810
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700811 # exclude filtered IPs (to use top_${topname} one) and
Timothy Chen322f2542020-08-05 16:28:18 -0700812 exclude_list = generated_list + top_only_list
813 ips = [x for x in ips if not x.parents[1].name in exclude_list]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100814
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700815 # Hack alert
816 # Generate clkmgr.hjson here so that it can be included below
817 # Unlike other generated hjsons, clkmgr thankfully does not require
818 # ip.hjson information. All the information is embedded within
819 # the top hjson file
820 amend_clocks(topcfg)
821 generate_clkmgr(topcfg, cfg_path, out_path)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700822
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700823 # It may require two passes to check if the module is needed.
824 # TODO: first run of topgen will fail due to the absent of rv_plic.
825 # It needs to run up to amend_interrupt in merge_top function
826 # then creates rv_plic.hjson then run xbar generation.
827 hjson_dir = Path(args.topcfg).parent
lowRISC Contributors802543a2019-08-31 12:12:56 +0100828
Timothy Chen322f2542020-08-05 16:28:18 -0700829 for ip in generated_list:
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700830 log.info("Appending {}".format(ip))
831 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(
832 ip, ip)
833 ips.append(ip_hjson)
Cindy Chenecc70ea2020-04-08 14:17:48 -0700834
Timothy Chen322f2542020-08-05 16:28:18 -0700835 for ip in top_only_list:
836 log.info("Appending {}".format(ip))
837 ip_hjson = hjson_dir.parent / "ip/{}/data/{}.hjson".format(
838 ip, ip)
839 ips.append(ip_hjson)
840
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700841 # load Hjson and pass validate from reggen
842 try:
843 ip_objs = []
844 for x in ips:
845 # Skip if it is not in the module list
846 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
847 log.info("Skip module %s as it isn't in the top module list" %
848 x.stem)
849 continue
lowRISC Contributors802543a2019-08-31 12:12:56 +0100850
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700851 obj = hjson.load(x.open('r'),
852 use_decimal=True,
853 object_pairs_hook=OrderedDict)
854 if validate.validate(obj) != 0:
855 log.info("Parsing IP %s configuration failed. Skip" % x)
856 continue
857 ip_objs.append(obj)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100858
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700859 except ValueError:
860 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100861
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700862 # Read the crossbars under the top directory
863 xbar_objs = get_hjsonobj_xbars(hjson_dir)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100864
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700865 log.info("Detected crossbars: %s" %
866 (", ".join([x["name"] for x in xbar_objs])))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100867
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700868 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
869 if error != 0:
870 raise SystemExit("Error occured while validating top.hjson")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100871
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700872 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100873
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700874 if args.top_ral:
875 generate_top_ral(completecfg, ip_objs, out_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100876 sys.exit()
877
lowRISC Contributors802543a2019-08-31 12:12:56 +0100878 # Generate PLIC
Eunchan Kim6599ba92020-04-13 15:27:16 -0700879 if not args.no_plic and \
Michael Schaffner666dde12019-10-25 11:57:54 -0700880 not args.alert_handler_only and \
881 not args.xbar_only:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100882 generate_plic(completecfg, out_path)
Michael Schaffner666dde12019-10-25 11:57:54 -0700883 if args.plic_only:
884 sys.exit()
885
886 # Generate Alert Handler
887 if not args.xbar_only:
888 generate_alert_handler(completecfg, out_path)
889 if args.alert_handler_only:
890 sys.exit()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100891
Timothy Chenf56c1b52020-04-28 17:00:43 -0700892 # Generate Pinmux
Michael Schaffner60157962020-05-01 19:11:28 -0700893 generate_pinmux_and_padctrl(completecfg, out_path)
Eunchan Kim436d2242019-10-29 17:25:51 -0700894
Timothy Chen4ba25312020-06-17 13:08:57 -0700895 # Generate Pwrmgr
896 generate_pwrmgr(completecfg, out_path)
897
Timothy Chen322f2542020-08-05 16:28:18 -0700898 # Generate top only modules
899 # These modules are not templated, but are not in hw/ip
900 generate_top_only(top_only_list, out_path)
901
lowRISC Contributors802543a2019-08-31 12:12:56 +0100902 # Generate xbars
903 if not args.no_xbar or args.xbar_only:
904 generate_xbars(completecfg, out_path)
905
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700906 # All IPs are generated. Connect phase now
Eunchan Kim2c813b42020-08-03 16:22:56 -0700907 # Find {memory, module} <-> {xbar} connections first.
908 im.autoconnect(completecfg)
909
910 # Generic Inter-module connection
911 im.elab_intermodule(completecfg)
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700912
lowRISC Contributors802543a2019-08-31 12:12:56 +0100913 top_name = completecfg["name"]
914
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700915 # Generate top.gen.hjson right before rendering
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700916 hjson_dir = Path(args.topcfg).parent
917 genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
918 completecfg["name"])
919 gencmd = (
920 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --hjson-only "
921 "-o hw/top_{topname}/\n".format(topname=topname))
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700922
Eunchan Kim66f7ae22020-08-03 23:24:53 -0700923 genhjson_path.write_text(genhdr + gencmd +
924 hjson.dumps(completecfg, for_json=True))
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700925
lowRISC Contributors802543a2019-08-31 12:12:56 +0100926 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 Elliottf7cb5f42020-07-27 21:29:26 +0100977 # 'top_earlgrey_memory.h.tpl' -> 'sw/autogen/top_earlgrey_memory.h'
978 memory_cheader_path = render_template('top_%s_memory.h', 'sw/autogen')
979
980 # Fix the C header guards, which will have the wrong name
Eunchan Kimfd561be2020-04-24 15:42:11 -0700981 subprocess.run(["util/fix_include_guard.py",
Sam Elliottf7cb5f42020-07-27 21:29:26 +0100982 str(cheader_path),
983 str(memory_cheader_path)],
Eunchan Kimfd561be2020-04-24 15:42:11 -0700984 universal_newlines=True,
985 stdout=subprocess.DEVNULL,
986 stderr=subprocess.DEVNULL,
987 check=True,
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700988 cwd=str(SRCTREE_TOP)) # yapf: disable
Sam Elliott37d4fbe2020-04-22 14:05:49 +0100989
Weicai Yang1777ebb2020-05-19 17:32:24 -0700990 # generate chip level xbar TB
991 tb_files = ["xbar_env_pkg__params.sv", "tb__xbar_connect.sv"]
992 for fname in tb_files:
993 tpl_fname = "%s.tpl" % (fname)
994 xbar_chip_data_path = tpl_path / tpl_fname
995 template_contents = generate_top(completecfg,
996 str(xbar_chip_data_path))
997
998 rendered_dir = tpl_path / '../dv/autogen'
999 rendered_dir.mkdir(parents=True, exist_ok=True)
1000 rendered_path = rendered_dir / fname
1001
1002 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1003 fout.write(template_contents)
1004
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001005
lowRISC Contributors802543a2019-08-31 12:12:56 +01001006if __name__ == "__main__":
1007 main()