blob: 105cd90254dbaf9857a34735dfc928c406733dba [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
Michael Schaffner60157962020-05-01 19:11:28 -070020
Cindy Chenc30dad22020-03-19 13:26:13 -070021from reggen import gen_dv, gen_rtl, gen_fpv, validate
Timothy Chenf56c1b52020-04-28 17:00:43 -070022from topgen import get_hjsonobj_xbars, merge_top, search_ips, validate_top, amend_clocks
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 Kimc7452942019-12-19 17:04:37 -080066 out_rtl, out_pkg, out_core = tlgen.generate(xbar)
Eunchan Kim6599ba92020-04-13 15:27:16 -070067 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070068 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010069
Eunchan Kimc7452942019-12-19 17:04:37 -080070 rtl_path = out_path / 'ip/xbar_{}/rtl/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010071 rtl_path.mkdir(parents=True, exist_ok=True)
Eunchan Kimc7452942019-12-19 17:04:37 -080072 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010073 dv_path.mkdir(parents=True, exist_ok=True)
74
75 rtl_filename = "xbar_%s.sv" % (xbar.name)
76 rtl_filepath = rtl_path / rtl_filename
77 with rtl_filepath.open(mode='w', encoding='UTF-8') as fout:
78 fout.write(out_rtl)
79
80 pkg_filename = "tl_%s_pkg.sv" % (xbar.name)
81 pkg_filepath = rtl_path / pkg_filename
82 with pkg_filepath.open(mode='w', encoding='UTF-8') as fout:
83 fout.write(out_pkg)
84
Eunchan Kimc7452942019-12-19 17:04:37 -080085 core_filename = "xbar_%s.core" % (xbar.name)
86 core_filepath = rtl_path / core_filename
87 with core_filepath.open(mode='w', encoding='UTF-8') as fout:
88 fout.write(out_core)
89
Weicai Yange4315d22020-01-09 10:37:42 -080090 # generate testbench for xbar
91 tlgen.generate_tb(xbar, dv_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +010092
Eunchan Kim6a4b49e2020-02-18 10:33:39 -080093
Michael Schaffner666dde12019-10-25 11:57:54 -070094def generate_alert_handler(top, out_path):
95 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -080096 esc_cnt_dw = 32
97 accu_cnt_dw = 16
98 lfsr_seed = 2**31 - 1
99 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700100 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800101 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700102
Eunchan Kimba970df2020-04-17 10:21:01 -0700103 topname = top["name"]
104
Michael Schaffner666dde12019-10-25 11:57:54 -0700105 # check if there are any params to be passed through reggen and placed into
106 # the generated package
107 ip_list_in_top = [x["name"].lower() for x in top["module"]]
108 ah_idx = ip_list_in_top.index("alert_handler")
109 if 'localparam' in top['module'][ah_idx]:
110 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
111 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
112 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
113 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
114 if 'LfsrSeed' in top['module'][ah_idx]['localparam']:
115 lfsr_seed = int(top['module'][ah_idx]['localparam']['LfsrSeed'], 0)
116
117 if esc_cnt_dw < 1:
118 log.error("EscCntDw must be larger than 0")
119 if accu_cnt_dw < 1:
120 log.error("AccuCntDw must be larger than 0")
121 if (lfsr_seed & 0xFFFFFFFF) == 0 or lfsr_seed > 2**32:
122 log.error("LFSR seed out of range or zero")
123
124 # Count number of interrupts
125 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
126
127 if n_alerts < 1:
128 # set number of alerts to 1 such that the config is still valid
129 # that input will be tied off
130 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800131 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700132 else:
133 async_on = ""
134 for alert in top['alert']:
135 async_on = str(alert['async']) + async_on
136 async_on = ("%d'b" % n_alerts) + async_on
137
138 log.info("alert handler parameterization:")
139 log.info("NAlerts = %d" % n_alerts)
140 log.info("EscCntDw = %d" % esc_cnt_dw)
141 log.info("AccuCntDw = %d" % accu_cnt_dw)
142 log.info("LfsrSeed = %d" % lfsr_seed)
143 log.info("AsyncOn = %s" % async_on)
144
Michael Schaffner666dde12019-10-25 11:57:54 -0700145 # Define target path
146 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
147 rtl_path.mkdir(parents=True, exist_ok=True)
148 doc_path = out_path / 'ip/alert_handler/data/autogen'
149 doc_path.mkdir(parents=True, exist_ok=True)
150
151 # Generating IP top module script is not generalized yet.
152 # So, topgen reads template files from alert_handler directory directly.
153 tpl_path = out_path / '../ip/alert_handler/data'
154 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
155
156 # Generate Register Package and RTLs
157 out = StringIO()
158 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
159 hjson_tpl = Template(fin.read())
160 try:
161 out = hjson_tpl.render(n_alerts=n_alerts,
162 esc_cnt_dw=esc_cnt_dw,
163 accu_cnt_dw=accu_cnt_dw,
164 lfsr_seed=lfsr_seed,
165 async_on=async_on,
166 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700167 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700168 log.error(exceptions.text_error_template().render())
169 log.info("alert_handler hjson: %s" % out)
170
171 if out == "":
172 log.error("Cannot generate alert_handler config file")
173 return
174
175 hjson_gen_path = doc_path / "alert_handler.hjson"
176 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700177 "// util/topgen.py -t hw/top_{topname}/doc/top_{topname}.hjson --alert-handler-only "
178 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700179 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
180 fout.write(genhdr + gencmd + out)
181
182 # Generate register RTLs (currently using shell execute)
183 # TODO: More secure way to gneerate RTL
184 hjson_obj = hjson.loads(out,
185 use_decimal=True,
186 object_pairs_hook=validate.checking_dict)
187 validate.validate(hjson_obj)
188 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
189
190
lowRISC Contributors802543a2019-08-31 12:12:56 +0100191def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700192 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100193 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700194 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
195 # So, total number of interrupts are the number of entries in the list + 1
196 src = sum([x["width"] if "width" in x else 1
197 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100198
199 # Target and priority: Currently fixed
200 target = int(top["num_cores"], 0) if "num_cores" in top else 1
201 prio = 3
202
203 # Define target path
204 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700205 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700206 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100207 rtl_path.mkdir(parents=True, exist_ok=True)
Cindy Chenc30dad22020-03-19 13:26:13 -0700208 fpv_path = out_path / 'ip/rv_plic/fpv/autogen'
209 fpv_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700210 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100211 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800212 hjson_path = out_path / 'ip/rv_plic/data/autogen'
213 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100214
215 # Generating IP top module script is not generalized yet.
216 # So, topgen reads template files from rv_plic directory directly.
217 # Next, if the ip top gen tool is placed in util/ we can import the library.
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +0200218 tpl_path = out_path / '../ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700219 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
220 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
Eunchan Kimba970df2020-04-17 10:21:01 -0700221 fpv_tpl_names = [
222 'rv_plic_bind_fpv.sv', 'rv_plic_fpv.sv', 'rv_plic_fpv.core'
223 ]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100224
225 # Generate Register Package and RTLs
226 out = StringIO()
227 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
228 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700229 try:
230 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700231 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700232 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100233 log.info("RV_PLIC hjson: %s" % out)
234
235 if out == "":
236 log.error("Cannot generate interrupt controller config file")
237 return
238
Michael Schaffner7f134962019-11-03 12:44:50 -0800239 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700240 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700241 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
242 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100243 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
244 fout.write(genhdr + gencmd + out)
245
246 # Generate register RTLs (currently using shell execute)
247 # TODO: More secure way to gneerate RTL
248 hjson_obj = hjson.loads(out,
249 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800250 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100251 validate.validate(hjson_obj)
252 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Cindy Chenc30dad22020-03-19 13:26:13 -0700253 gen_fpv.gen_fpv(hjson_obj, str(fpv_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100254
255 # Generate RV_PLIC Top Module
256 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
257 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700258 try:
259 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700260 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700261 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100262 log.info("RV_PLIC RTL: %s" % out)
263
264 if out == "":
265 log.error("Cannot generate interrupt controller RTL")
266 return
267
268 rtl_gen_path = rtl_path / "rv_plic.sv"
269 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
270 fout.write(genhdr + gencmd + out)
271
Cindy Chenc30dad22020-03-19 13:26:13 -0700272 # Generate RV_PLIC FPV testbench
273 for file_name in fpv_tpl_names:
274 tpl_name = file_name + ".tpl"
275 path = tpl_path / tpl_name
276 with path.open(mode='r', encoding='UTF-8') as fin:
277 fpv_tpl = Template(fin.read())
278 try:
279 out = fpv_tpl.render(src=src, target=target, prio=prio)
Eunchan Kimba970df2020-04-17 10:21:01 -0700280 except: # noqa : E722
Cindy Chenc30dad22020-03-19 13:26:13 -0700281 log.error(exceptions.text_error_template().render())
282 log.info("RV_PLIC FPV: %s" % out)
283 if out == "":
284 log.error("Cannot generate rv_plic FPV testbench")
285 return
286
287 fpv_gen_path = fpv_path / file_name
288 with fpv_gen_path.open(mode='w', encoding='UTF-8') as fout:
289 fout.write(out)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100290
Eunchan Kimba970df2020-04-17 10:21:01 -0700291
Michael Schaffner60157962020-05-01 19:11:28 -0700292def generate_pinmux_and_padctrl(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700293 topname = top["name"]
Eunchan Kim436d2242019-10-29 17:25:51 -0700294 # MIO Pads
Michael Schaffner57c490d2020-04-29 15:08:55 -0700295 n_mio_pads = top["pinmux"]["num_mio"]
296 if n_mio_pads <= 0:
297 # TODO: add support for no MIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700298 log.error("Topgen does currently not support generation of a top " +
299 "without a pinmux.")
300 return
301
302 if "padctrl" not in top:
303 # TODO: add support for no MIO case
304 log.error("Topgen does currently not support generation of a top " +
305 "without a padctrl instance.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700306 return
307
308 # Get number of wakeup detectors
309 if "num_wkup_detect" in top["pinmux"]:
310 num_wkup_detect = top["pinmux"]["num_wkup_detect"]
311 else:
312 num_wkup_detect = 1
313
314 if num_wkup_detect <= 0:
315 # TODO: add support for no wakeup counter case
Michael Schaffner60157962020-05-01 19:11:28 -0700316 log.error("Topgen does currently not support generation of a top " +
317 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700318 return
319
320 if "wkup_cnt_width" in top["pinmux"]:
321 wkup_cnt_width = top["pinmux"]["wkup_cnt_width"]
322 else:
323 wkup_cnt_width = 8
324
325 if wkup_cnt_width <= 1:
326 log.error("Wakeup counter width must be greater equal 2.")
Eunchan Kim436d2242019-10-29 17:25:51 -0700327 return
328
329 # Total inputs/outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700330 # Validation ensures that the width field is present.
Michael Schaffner60157962020-05-01 19:11:28 -0700331 num_mio_inputs = sum([x["width"] for x in top["pinmux"]["inputs"]])
332 num_mio_outputs = sum([x["width"] for x in top["pinmux"]["outputs"]])
333 num_mio_inouts = sum([x["width"] for x in top["pinmux"]["inouts"]])
Eunchan Kim436d2242019-10-29 17:25:51 -0700334
Michael Schaffner60157962020-05-01 19:11:28 -0700335 num_dio_inputs = sum([
336 x["width"] if x["type"] == "input" else 0 for x in top["pinmux"]["dio"]
337 ])
338 num_dio_outputs = sum([
339 x["width"] if x["type"] == "output" else 0
340 for x in top["pinmux"]["dio"]
341 ])
342 num_dio_inouts = sum([
343 x["width"] if x["type"] == "inout" else 0 for x in top["pinmux"]["dio"]
344 ])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700345
346 n_mio_periph_in = num_mio_inouts + num_mio_inputs
347 n_mio_periph_out = num_mio_inouts + num_mio_outputs
348 n_dio_periph_in = num_dio_inouts + num_dio_inputs
349 n_dio_periph_out = num_dio_inouts + num_dio_outputs
350 n_dio_pads = num_dio_inouts + num_dio_inputs + num_dio_outputs
351
352 if n_dio_pads <= 0:
353 # TODO: add support for no DIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700354 log.error("Topgen does currently not support generation of a top " +
355 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700356 return
357
358 log.info("Generating pinmux with following info from hjson:")
359 log.info("num_mio_inputs: %d" % num_mio_inputs)
360 log.info("num_mio_outputs: %d" % num_mio_outputs)
361 log.info("num_mio_inouts: %d" % num_mio_inouts)
362 log.info("num_dio_inputs: %d" % num_dio_inputs)
363 log.info("num_dio_outputs: %d" % num_dio_outputs)
364 log.info("num_dio_inouts: %d" % num_dio_inouts)
365 log.info("num_wkup_detect: %d" % num_wkup_detect)
366 log.info("wkup_cnt_width: %d" % wkup_cnt_width)
367 log.info("This translates to:")
368 log.info("n_mio_periph_in: %d" % n_mio_periph_in)
369 log.info("n_mio_periph_out: %d" % n_mio_periph_out)
370 log.info("n_dio_periph_in: %d" % n_dio_periph_in)
371 log.info("n_dio_periph_out: %d" % n_dio_periph_out)
372 log.info("n_dio_pads: %d" % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700373
374 # Target path
375 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
376 # data: pinmux.hjson
377 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
378 rtl_path.mkdir(parents=True, exist_ok=True)
379 data_path = out_path / 'ip/pinmux/data/autogen'
380 data_path.mkdir(parents=True, exist_ok=True)
381
382 # Template path
383 tpl_path = out_path / '../ip/pinmux/data/pinmux.hjson.tpl'
384
385 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700386 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
387 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700388
389 hjson_gen_path = data_path / "pinmux.hjson"
390
391 out = StringIO()
392 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
393 hjson_tpl = Template(fin.read())
394 try:
Michael Schaffner57c490d2020-04-29 15:08:55 -0700395 # TODO: pass in information about always-on peripherals
396 # TODO: pass in information on which DIOs can be selected
397 # as wakeup signals
398 # TODO: pass in signal names such that we can introduce
399 # named enums for select signals
Michael Schaffner60157962020-05-01 19:11:28 -0700400 out = hjson_tpl.render(
401 n_mio_periph_in=n_mio_periph_in,
402 n_mio_periph_out=n_mio_periph_out,
403 n_mio_pads=n_mio_pads,
404 # each DIO has in, out and oe wires
405 # some of these have to be tied off in the
406 # top, depending on the type.
407 n_dio_periph_in=n_dio_pads,
408 n_dio_periph_out=n_dio_pads,
409 n_dio_pads=n_dio_pads,
410 n_wkup_detect=num_wkup_detect,
411 wkup_cnt_width=wkup_cnt_width)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700412 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700413 log.error(exceptions.text_error_template().render())
414 log.info("PINMUX HJSON: %s" % out)
415
416 if out == "":
417 log.error("Cannot generate pinmux HJSON")
418 return
419
420 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
421 fout.write(genhdr + gencmd + out)
422
423 hjson_obj = hjson.loads(out,
424 use_decimal=True,
425 object_pairs_hook=validate.checking_dict)
426 validate.validate(hjson_obj)
427 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
428
Michael Schaffner60157962020-05-01 19:11:28 -0700429 # Target path
430 # rtl: padctrl_reg_pkg.sv & padctrl_reg_top.sv
431 # data: padctrl.hjson
432 rtl_path = out_path / 'ip/padctrl/rtl/autogen'
433 rtl_path.mkdir(parents=True, exist_ok=True)
434 data_path = out_path / 'ip/padctrl/data/autogen'
435 data_path.mkdir(parents=True, exist_ok=True)
436
437 # Template path
438 tpl_path = out_path / '../ip/padctrl/data/padctrl.hjson.tpl'
439
440 # Generate register package and RTLs
441 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
442 "-o hw/top_{topname}/\n\n".format(topname=topname))
443
444 hjson_gen_path = data_path / "padctrl.hjson"
445
446 out = StringIO()
447 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
448 hjson_tpl = Template(fin.read())
449 try:
450 out = hjson_tpl.render(n_mio_pads=n_mio_pads,
451 n_dio_pads=n_dio_pads,
452 attr_dw=8)
453 except: # noqa: E722
454 log.error(exceptions.text_error_template().render())
455 log.info("PADCTRL HJSON: %s" % out)
456
457 if out == "":
458 log.error("Cannot generate padctrl HJSON")
459 return
460
461 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
462 fout.write(genhdr + gencmd + out)
463
464 hjson_obj = hjson.loads(out,
465 use_decimal=True,
466 object_pairs_hook=validate.checking_dict)
467 validate.validate(hjson_obj)
468 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
469
470
Timothy Chenf56c1b52020-04-28 17:00:43 -0700471def generate_clkmgr(top, cfg_path, out_path):
472
473 # Target paths
474 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
475 rtl_path.mkdir(parents=True, exist_ok=True)
476 data_path = out_path / 'ip/clkmgr/data/autogen'
477 data_path.mkdir(parents=True, exist_ok=True)
478
479 # Template paths
480 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
481 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
482 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
483
484 hjson_out = data_path / 'clkmgr.hjson'
485 rtl_out = rtl_path / 'clkmgr.sv'
486 pkg_out = rtl_path / 'clkmgr_pkg.sv'
487
488 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
489 outputs = [hjson_out, rtl_out, pkg_out]
490 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
491
492 # clock classification
493 grps = top['clocks']['groups']
494
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700495 src_aon_attr = OrderedDict()
Timothy Chenf56c1b52020-04-28 17:00:43 -0700496 ft_clks = OrderedDict()
497 rg_clks = OrderedDict()
498 sw_clks = OrderedDict()
499 hint_clks = OrderedDict()
500
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700501 # construct a dictionary of the aon attribute for easier lookup
502 # ie, src_name_A: True, src_name_B: False
503 for src in top['clocks']['srcs']:
504 if src['aon'] == 'yes':
505 src_aon_attr[src['name']] = True
506 else:
507 src_aon_attr[src['name']] = False
508
509 rg_srcs = [src for (src, attr) in src_aon_attr.items() if not attr]
510
511 # clocks fed through clkmgr but are not disturbed in any way
512 # This maintains the clocking structure consistency
Timothy Chenf56c1b52020-04-28 17:00:43 -0700513 ft_clks = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700514 if src_aon_attr[src]}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700515
516 # root-gate clocks
517 rg_clks = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700518 if grp['name'] != 'powerup' and grp['sw_cg'] == 'no' and not src_aon_attr[src]}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700519
520 # direct sw control clocks
521 sw_clks = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700522 if grp['sw_cg'] == 'yes' and not src_aon_attr[src]}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700523
524 # sw hint clocks
525 hint_clks = {clk:src for grp in grps for (clk,src) in grp['clocks'].items()
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700526 if grp['sw_cg'] == 'hint' and not src_aon_attr[src]}
Timothy Chenf56c1b52020-04-28 17:00:43 -0700527
528
529 out = StringIO()
530 for idx, tpl in enumerate(tpls):
531 with tpl.open(mode='r', encoding='UTF-8') as fin:
532 tpl = Template(fin.read())
533 try:
534 out = tpl.render(cfg=top,
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700535 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700536 ft_clks=ft_clks,
537 rg_clks=rg_clks,
538 sw_clks=sw_clks,
539 hint_clks=hint_clks)
540 except: # noqa: E722
541 log.error(exceptions.text_error_template().render())
542
543 if out == "":
544 log.error("Cannot generate {}".format(names[idx]))
545 return
546
547 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
548 fout.write(genhdr + out)
549
550 # Generate reg files
551 with open(str(hjson_out), 'r') as out:
552 hjson_obj = hjson.load(out,
553 use_decimal=True,
554 object_pairs_hook=OrderedDict)
555 validate.validate(hjson_obj)
556 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700557
lowRISC Contributors802543a2019-08-31 12:12:56 +0100558def generate_top_ral(top, ip_objs, out_path):
559 # construct top ral block
560 top_block = gen_rtl.Block()
561 top_block.name = "chip"
562 top_block.base_addr = 0
563 top_block.width = int(top["datawidth"])
564
565 # add blocks
566 for ip_obj in ip_objs:
567 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
568
569 # add memories
570 if "memory" in top.keys():
571 for item in list(top["memory"]):
572 mem = gen_rtl.Window()
573 mem.name = item["name"]
574 mem.base_addr = int(item["base_addr"], 0)
575 mem.limit_addr = int(item["base_addr"], 0) + int(item["size"], 0)
Weicai Yang55b2cdf2020-04-10 15:40:30 -0700576 if "swaccess" in item.keys():
577 mem.dvrights = item["swaccess"]
578 else:
579 mem.dvrights = "RW"
lowRISC Contributors802543a2019-08-31 12:12:56 +0100580 mem.n_bits = top_block.width
581 top_block.wins.append(mem)
582
583 # get sub-block base addresses from top cfg
584 for block in top_block.blocks:
585 for module in top["module"]:
586 if block.name == module["name"]:
587 block.base_addr = module["base_addr"]
588 break
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700589
590 top_block.blocks.sort(key=lambda block: block.base_addr)
591 top_block.wins.sort(key=lambda win: win.base_addr)
592
lowRISC Contributors802543a2019-08-31 12:12:56 +0100593 # generate the top ral model with template
594 gen_dv.gen_ral(top_block, str(out_path))
595
596
597def main():
598 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700599 parser.add_argument('--topcfg',
600 '-t',
601 required=True,
602 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700603 parser.add_argument(
604 '--tpl',
605 '-c',
606 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -0700607 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100608 parser.add_argument(
609 '--outdir',
610 '-o',
611 help='''Target TOP directory.
612 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700613 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100614 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
615
616 # Generator options: 'no' series. cannot combined with 'only' series
617 parser.add_argument(
618 '--no-top',
619 action='store_true',
620 help="If defined, topgen doesn't generate top_{name} RTLs.")
621 parser.add_argument(
622 '--no-xbar',
623 action='store_true',
624 help="If defined, topgen doesn't generate crossbar RTLs.")
625 parser.add_argument(
626 '--no-plic',
627 action='store_true',
628 help="If defined, topgen doesn't generate the interrup controller RTLs."
629 )
630 parser.add_argument(
631 '--no-gen-hjson',
632 action='store_true',
633 help='''If defined, the tool assumes topcfg as a generated hjson.
634 So it bypasses the validation step and doesn't read ip and
635 xbar configurations
636 ''')
637
638 # Generator options: 'only' series. cannot combined with 'no' series
639 parser.add_argument(
640 '--top-only',
641 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700642 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100643 parser.add_argument(
644 '--xbar-only',
645 action='store_true',
646 help="If defined, the tool generates crossbar RTLs only")
647 parser.add_argument(
648 '--plic-only',
649 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000650 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100651 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700652 '--alert-handler-only',
653 action='store_true',
654 help="If defined, the tool generates alert handler hjson only")
655 parser.add_argument(
lowRISC Contributors802543a2019-08-31 12:12:56 +0100656 '--hjson-only',
657 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000658 help="If defined, the tool generates complete Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100659 # Generator options: generate dv ral model
660 parser.add_argument(
661 '--top_ral',
662 '-r',
663 default=False,
664 action='store_true',
665 help="If set, the tool generates top level RAL model for DV")
666
667 args = parser.parse_args()
668
669 # check combinations
670 if args.top_ral:
671 args.hjson_only = True
672 args.no_top = True
673
674 if args.hjson_only:
675 args.no_gen_hjson = False
676
677 if (args.no_top or args.no_xbar or
678 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -0700679 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100680 log.error(
681 "'no' series options cannot be used with 'only' series options")
682 raise SystemExit(sys.exc_info()[1])
683
Eunchan Kimc7452942019-12-19 17:04:37 -0800684 if not (args.hjson_only or args.plic_only or args.alert_handler_only or
685 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100686 log.error(
687 "Template file can be omitted only if '--hjson-only' is true")
688 raise SystemExit(sys.exc_info()[1])
689
690 if args.verbose:
691 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
692 else:
693 log.basicConfig(format="%(levelname)s: %(message)s")
694
695 if not args.outdir:
696 outdir = Path(args.topcfg).parent / ".."
697 log.info("TOP directory not given. Use %s", (outdir))
698 elif not Path(args.outdir).is_dir():
699 log.error("'--outdir' should point to writable directory")
700 raise SystemExit(sys.exc_info()[1])
701 else:
702 outdir = Path(args.outdir)
703
704 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700705 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100706
707 if not args.no_gen_hjson or args.hjson_only:
708 # load top configuration
709 try:
710 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800711 topcfg = hjson.load(ftop,
712 use_decimal=True,
713 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100714 except ValueError:
715 raise SystemExit(sys.exc_info()[1])
716
Timothy Chenf56c1b52020-04-28 17:00:43 -0700717 # Create filtered list
718 filter_list = [module['name'] for module in topcfg['module']
719 if 'generated' in module and module['generated'] == 'true']
720 log.info("Filtered list is {}".format(filter_list))
721
Eunchan Kimba970df2020-04-17 10:21:01 -0700722 topname = topcfg["name"]
723
lowRISC Contributors802543a2019-08-31 12:12:56 +0100724 # Sweep the IP directory and gather the config files
725 ip_dir = Path(__file__).parents[1] / 'hw/ip'
726 ips = search_ips(ip_dir)
727
Timothy Chenf56c1b52020-04-28 17:00:43 -0700728 # exclude filtered IPs (to use top_${topname} one) and
lowRISC Contributors802543a2019-08-31 12:12:56 +0100729 ips = [x for x in ips if not x.parents[1].name in filter_list]
730
Timothy Chenf56c1b52020-04-28 17:00:43 -0700731 # Hack alert
732 # Generate clkmgr.hjson here so that it can be included below
733 # Unlike other generated hjsons, clkmgr thankfully does not require
734 # ip.hjson information. All the information is embedded within
735 # the top hjson file
736 amend_clocks(topcfg)
737 generate_clkmgr(topcfg, cfg_path, out_path)
738
lowRISC Contributors802543a2019-08-31 12:12:56 +0100739 # It may require two passes to check if the module is needed.
740 # TODO: first run of topgen will fail due to the absent of rv_plic.
741 # It needs to run up to amend_interrupt in merge_top function
742 # then creates rv_plic.hjson then run xbar generation.
743 hjson_dir = Path(args.topcfg).parent
lowRISC Contributors802543a2019-08-31 12:12:56 +0100744
Timothy Chenf56c1b52020-04-28 17:00:43 -0700745 for ip in filter_list:
746 log.info("Appending {}".format(ip))
747 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(ip,ip)
748 ips.append(ip_hjson)
Cindy Chenecc70ea2020-04-08 14:17:48 -0700749
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000750 # load Hjson and pass validate from reggen
lowRISC Contributors802543a2019-08-31 12:12:56 +0100751 try:
752 ip_objs = []
753 for x in ips:
754 # Skip if it is not in the module list
Eunchan Kim6599ba92020-04-13 15:27:16 -0700755 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100756 log.info(
757 "Skip module %s as it isn't in the top module list" %
758 x.stem)
759 continue
760
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700761 obj = hjson.load(x.open('r'),
762 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800763 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100764 if validate.validate(obj) != 0:
765 log.info("Parsing IP %s configuration failed. Skip" % x)
766 continue
767 ip_objs.append(obj)
768
769 except ValueError:
770 raise SystemExit(sys.exc_info()[1])
771
772 # Read the crossbars under the top directory
773 xbar_objs = get_hjsonobj_xbars(hjson_dir)
774
775 log.info("Detected crossbars: %s" %
776 (", ".join([x["name"] for x in xbar_objs])))
777
Timothy Chen3193b002019-10-04 16:56:05 -0700778 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700779 if error != 0:
780 raise SystemExit("Error occured while validating top.hjson")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100781
lowRISC Contributors802543a2019-08-31 12:12:56 +0100782 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
783
Eunchan Kim1a95dd92019-10-11 11:18:13 -0700784 genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
785 completecfg["name"])
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700786 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700787 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --hjson-only "
788 "-o hw/top_{topname}/\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100789
790 if args.top_ral:
791 generate_top_ral(completecfg, ip_objs, out_path)
792 else:
793 genhjson_path.write_text(genhdr + gencmd +
794 hjson.dumps(completecfg, for_json=True))
795
796 if args.hjson_only:
797 log.info("hjson is generated. Exiting...")
798 sys.exit()
799
800 if args.no_gen_hjson:
801 # load top.complete configuration
802 try:
803 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800804 completecfg = hjson.load(ftop,
805 use_decimal=True,
806 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100807 except ValueError:
808 raise SystemExit(sys.exc_info()[1])
809
810 # Generate PLIC
Eunchan Kim6599ba92020-04-13 15:27:16 -0700811 if not args.no_plic and \
Michael Schaffner666dde12019-10-25 11:57:54 -0700812 not args.alert_handler_only and \
813 not args.xbar_only:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100814 generate_plic(completecfg, out_path)
Michael Schaffner666dde12019-10-25 11:57:54 -0700815 if args.plic_only:
816 sys.exit()
817
818 # Generate Alert Handler
819 if not args.xbar_only:
820 generate_alert_handler(completecfg, out_path)
821 if args.alert_handler_only:
822 sys.exit()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100823
Timothy Chenf56c1b52020-04-28 17:00:43 -0700824 # Generate Pinmux
Michael Schaffner60157962020-05-01 19:11:28 -0700825 generate_pinmux_and_padctrl(completecfg, out_path)
Eunchan Kim436d2242019-10-29 17:25:51 -0700826
lowRISC Contributors802543a2019-08-31 12:12:56 +0100827 # Generate xbars
828 if not args.no_xbar or args.xbar_only:
829 generate_xbars(completecfg, out_path)
830
lowRISC Contributors802543a2019-08-31 12:12:56 +0100831 top_name = completecfg["name"]
832
833 if not args.no_top or args.top_only:
Eunchan Kim632c6f72019-09-30 11:11:51 -0700834 tpl_path = Path(args.tpl)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700835
Sam Elliott7e36bd72020-04-22 14:05:49 +0100836 def render_template(out_name_tpl, out_dir, **other_info):
837 top_tplpath = tpl_path / ((out_name_tpl + '.tpl') % (top_name))
Eunchan Kimfd561be2020-04-24 15:42:11 -0700838 template_contents = generate_top(completecfg, str(top_tplpath),
839 **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100840
Sam Elliott7e36bd72020-04-22 14:05:49 +0100841 rendered_dir = out_path / out_dir
842 rendered_dir.mkdir(parents=True, exist_ok=True)
843 rendered_path = rendered_dir / (out_name_tpl % (top_name))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100844
Sam Elliott7e36bd72020-04-22 14:05:49 +0100845 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
846 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -0700847
Sam Elliott7e36bd72020-04-22 14:05:49 +0100848 return rendered_path
Eunchan Kim436d2242019-10-29 17:25:51 -0700849
Sam Elliott7e36bd72020-04-22 14:05:49 +0100850 # SystemVerilog Top:
851 # 'top_earlgrey.sv.tpl' -> 'rtl/autogen/top_earlgrey.sv'
852 render_template('top_%s.sv', 'rtl/autogen')
Eunchan Kim436d2242019-10-29 17:25:51 -0700853
Sam Elliott2a4448b2020-04-23 11:15:43 +0100854 # C Header + C File + Clang-format file
Sam Elliott7e36bd72020-04-22 14:05:49 +0100855 # The C file needs some information from when the header is generated,
856 # so we keep this in a dictionary here.
857 c_gen_info = {}
858
Sam Elliott2a4448b2020-04-23 11:15:43 +0100859 # 'clang-format' -> 'sw/autogen/.clang-format'
860 cformat_tplpath = tpl_path / 'clang-format'
861 cformat_dir = out_path / 'sw/autogen'
862 cformat_dir.mkdir(parents=True, exist_ok=True)
863 cformat_path = cformat_dir / '.clang-format'
864 cformat_path.write_text(cformat_tplpath.read_text())
865
Sam Elliott7e36bd72020-04-22 14:05:49 +0100866 # 'top_earlgrey.h.tpl' -> 'sw/autogen/top_earlgrey.h'
Eunchan Kimfd561be2020-04-24 15:42:11 -0700867 cheader_path = render_template('top_%s.h',
868 'sw/autogen',
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +0100869 c_gen_info=c_gen_info).resolve()
Sam Elliott7e36bd72020-04-22 14:05:49 +0100870
871 # Save the relative header path into `c_gen_info`
872 rel_header_path = cheader_path.relative_to(SRCTREE_TOP)
873 c_gen_info["header_path"] = str(rel_header_path)
874
875 # 'top_earlgrey.c.tpl' -> 'sw/autogen/top_earlgrey.c'
Eunchan Kimfd561be2020-04-24 15:42:11 -0700876 render_template('top_%s.c', 'sw/autogen', c_gen_info=c_gen_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100877
Sam Elliott37d4fbe2020-04-22 14:05:49 +0100878 # Fix the C header guard, which will have the wrong name
Eunchan Kimfd561be2020-04-24 15:42:11 -0700879 subprocess.run(["util/fix_include_guard.py",
880 str(cheader_path)],
881 universal_newlines=True,
882 stdout=subprocess.DEVNULL,
883 stderr=subprocess.DEVNULL,
884 check=True,
885 cwd=str(SRCTREE_TOP))
Sam Elliott37d4fbe2020-04-22 14:05:49 +0100886
887
lowRISC Contributors802543a2019-08-31 12:12:56 +0100888if __name__ == "__main__":
889 main()