blob: 2062473043a1d537344528e83b4b3ad1e5007c22 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
5r"""Top Module Generator
6"""
7import argparse
8import logging as log
Weicai Yanga6670362020-11-24 17:19:52 -08009import random
Sam Elliott37d4fbe2020-04-22 14:05:49 +010010import subprocess
Michael Schaffner60157962020-05-01 19:11:28 -070011import sys
Weicai Yanga60ae7d2020-02-21 14:32:50 -080012from collections import OrderedDict
Weicai Yanga6670362020-11-24 17:19:52 -080013from copy import deepcopy
lowRISC Contributors802543a2019-08-31 12:12:56 +010014from io import StringIO
15from pathlib import Path
16
17import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070018from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080019from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010020
21import tlgen
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +000022from reggen import access, gen_dv, gen_rtl, validate, window
Rupert Swarbrickb6500262021-02-23 15:16:16 +000023from reggen.inter_signal import InterSignal
24from reggen.lib import check_list
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +000025from reggen.reg_block import RegBlock
Weicai Yanga6670362020-11-24 17:19:52 -080026from topgen import amend_clocks, get_hjsonobj_xbars
Eunchan Kim2c813b42020-08-03 16:22:56 -070027from topgen import intermodule as im
Timothy Chen94432212021-03-01 22:29:18 -080028from topgen import lib as lib
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +000029from topgen import merge_top, search_ips, validate_top
Sam Elliotte74c6292020-07-24 21:40:00 +010030from topgen.c import TopGenC
lowRISC Contributors802543a2019-08-31 12:12:56 +010031
32# Common header for generated files
Michael Schaffner7b0807d2020-10-27 19:54:52 -070033warnhdr = '''//
lowRISC Contributors802543a2019-08-31 12:12:56 +010034// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
35// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
36'''
Michael Schaffner7b0807d2020-10-27 19:54:52 -070037genhdr = '''// Copyright lowRISC contributors.
38// Licensed under the Apache License, Version 2.0, see LICENSE for details.
39// SPDX-License-Identifier: Apache-2.0
40''' + warnhdr
lowRISC Contributors802543a2019-08-31 12:12:56 +010041
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010042SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070043
Eunchan Kimfd561be2020-04-24 15:42:11 -070044
Sam Elliott7e36bd72020-04-22 14:05:49 +010045def generate_top(top, tpl_filename, **kwargs):
46 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010047
Eunchan Kimcb28a172019-10-08 16:35:48 -070048 try:
Sam Elliott7e36bd72020-04-22 14:05:49 +010049 return top_tpl.render(top=top, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070050 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070051 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010052 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010053
54
55def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070056 topname = top["name"]
57 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
58 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070059
lowRISC Contributors802543a2019-08-31 12:12:56 +010060 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080061 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
62 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010063 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080064 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010065
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070066 # Generate output of crossbar with complete fields
67 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
68 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070069 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070070
lowRISC Contributors802543a2019-08-31 12:12:56 +010071 if not tlgen.elaborate(xbar):
72 log.error("Elaboration failed." + repr(xbar))
73
Eunchan Kimcb28a172019-10-08 16:35:48 -070074 try:
Eunchan Kim9191f262020-07-30 16:37:40 -070075 results = tlgen.generate(xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -070076 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070077 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010078
Eunchan Kim9191f262020-07-30 16:37:40 -070079 ip_path = out_path / 'ip/xbar_{}'.format(obj["name"])
80
81 for filename, filecontent in results:
82 filepath = ip_path / filename
83 filepath.parent.mkdir(parents=True, exist_ok=True)
84 with filepath.open(mode='w', encoding='UTF-8') as fout:
85 fout.write(filecontent)
86
Eunchan Kimc7452942019-12-19 17:04:37 -080087 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010088 dv_path.mkdir(parents=True, exist_ok=True)
89
Weicai Yange4315d22020-01-09 10:37:42 -080090 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -070091 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010092
Eunchan Kime0d37fe2020-08-03 12:05:21 -070093 # Read back the comportable IP and amend to Xbar
94 xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
95 with xbar_ipfile.open() as fxbar:
96 xbar_ipobj = hjson.load(fxbar,
97 use_decimal=True,
98 object_pairs_hook=OrderedDict)
99
Rupert Swarbrickb6500262021-02-23 15:16:16 +0000100 r_inter_signal_list = check_list(xbar_ipobj.get('inter_signal_list', []),
101 'inter_signal_list field')
102 obj['inter_signal_list'] = [
103 InterSignal.from_raw('entry {} of the inter_signal_list field'
104 .format(idx + 1),
105 entry)
106 for idx, entry in enumerate(r_inter_signal_list)
107 ]
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700108
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800109
Michael Schaffner666dde12019-10-25 11:57:54 -0700110def generate_alert_handler(top, out_path):
111 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -0800112 esc_cnt_dw = 32
113 accu_cnt_dw = 16
Eunchan Kimc7452942019-12-19 17:04:37 -0800114 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -0700115 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800116 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700117
Eunchan Kimba970df2020-04-17 10:21:01 -0700118 topname = top["name"]
119
Michael Schaffner666dde12019-10-25 11:57:54 -0700120 # check if there are any params to be passed through reggen and placed into
121 # the generated package
122 ip_list_in_top = [x["name"].lower() for x in top["module"]]
123 ah_idx = ip_list_in_top.index("alert_handler")
124 if 'localparam' in top['module'][ah_idx]:
125 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
126 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
127 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
128 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
Michael Schaffner666dde12019-10-25 11:57:54 -0700129
130 if esc_cnt_dw < 1:
131 log.error("EscCntDw must be larger than 0")
132 if accu_cnt_dw < 1:
133 log.error("AccuCntDw must be larger than 0")
Michael Schaffner666dde12019-10-25 11:57:54 -0700134
Michael Schaffner5ae4a232020-10-06 19:03:43 -0700135 # Count number of alerts
Michael Schaffner666dde12019-10-25 11:57:54 -0700136 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
137
138 if n_alerts < 1:
139 # set number of alerts to 1 such that the config is still valid
140 # that input will be tied off
141 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800142 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700143 else:
144 async_on = ""
145 for alert in top['alert']:
Timothy Chen322f2542020-08-05 16:28:18 -0700146 for k in range(alert['width']):
147 async_on = str(alert['async']) + async_on
Michael Schaffner666dde12019-10-25 11:57:54 -0700148 async_on = ("%d'b" % n_alerts) + async_on
149
150 log.info("alert handler parameterization:")
151 log.info("NAlerts = %d" % n_alerts)
152 log.info("EscCntDw = %d" % esc_cnt_dw)
153 log.info("AccuCntDw = %d" % accu_cnt_dw)
Michael Schaffner666dde12019-10-25 11:57:54 -0700154 log.info("AsyncOn = %s" % async_on)
155
Michael Schaffner666dde12019-10-25 11:57:54 -0700156 # Define target path
157 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
158 rtl_path.mkdir(parents=True, exist_ok=True)
159 doc_path = out_path / 'ip/alert_handler/data/autogen'
160 doc_path.mkdir(parents=True, exist_ok=True)
161
162 # Generating IP top module script is not generalized yet.
163 # So, topgen reads template files from alert_handler directory directly.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100164 tpl_path = Path(__file__).resolve().parent / '../hw/ip/alert_handler/data'
Michael Schaffner666dde12019-10-25 11:57:54 -0700165 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
166
167 # Generate Register Package and RTLs
168 out = StringIO()
169 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
170 hjson_tpl = Template(fin.read())
171 try:
172 out = hjson_tpl.render(n_alerts=n_alerts,
173 esc_cnt_dw=esc_cnt_dw,
174 accu_cnt_dw=accu_cnt_dw,
Michael Schaffner666dde12019-10-25 11:57:54 -0700175 async_on=async_on,
176 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700177 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700178 log.error(exceptions.text_error_template().render())
179 log.info("alert_handler hjson: %s" % out)
180
181 if out == "":
182 log.error("Cannot generate alert_handler config file")
183 return
184
185 hjson_gen_path = doc_path / "alert_handler.hjson"
186 gencmd = (
Cindy Chenbd401c32020-07-31 12:09:52 -0700187 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --alert-handler-only "
Eunchan Kimba970df2020-04-17 10:21:01 -0700188 "-o hw/top_{topname}/\n\n".format(topname=topname))
Michael Schaffner666dde12019-10-25 11:57:54 -0700189 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
190 fout.write(genhdr + gencmd + out)
191
192 # Generate register RTLs (currently using shell execute)
193 # TODO: More secure way to gneerate RTL
194 hjson_obj = hjson.loads(out,
195 use_decimal=True,
196 object_pairs_hook=validate.checking_dict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000197 validate.validate(hjson_obj, params=[])
Michael Schaffner666dde12019-10-25 11:57:54 -0700198 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
199
200
lowRISC Contributors802543a2019-08-31 12:12:56 +0100201def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700202 topname = top["name"]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100203 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700204 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
205 # So, total number of interrupts are the number of entries in the list + 1
206 src = sum([x["width"] if "width" in x else 1
207 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100208
209 # Target and priority: Currently fixed
210 target = int(top["num_cores"], 0) if "num_cores" in top else 1
211 prio = 3
212
213 # Define target path
214 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700215 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700216 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100217 rtl_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700218 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100219 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800220 hjson_path = out_path / 'ip/rv_plic/data/autogen'
221 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100222
223 # Generating IP top module script is not generalized yet.
224 # So, topgen reads template files from rv_plic directory directly.
225 # Next, if the ip top gen tool is placed in util/ we can import the library.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100226 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700227 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
228 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100229
230 # Generate Register Package and RTLs
231 out = StringIO()
232 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
233 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700234 try:
235 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700236 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700237 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100238 log.info("RV_PLIC hjson: %s" % out)
239
240 if out == "":
241 log.error("Cannot generate interrupt controller config file")
242 return
243
Michael Schaffner7f134962019-11-03 12:44:50 -0800244 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700245 gencmd = (
Eunchan Kimba970df2020-04-17 10:21:01 -0700246 "// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson --plic-only "
247 "-o hw/top_{topname}/\n\n".format(topname=topname))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100248 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
249 fout.write(genhdr + gencmd + out)
250
251 # Generate register RTLs (currently using shell execute)
Cindy Chene27c6c62020-05-18 16:06:28 -0700252 # TODO: More secure way to generate RTL
lowRISC Contributors802543a2019-08-31 12:12:56 +0100253 hjson_obj = hjson.loads(out,
254 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800255 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000256 validate.validate(hjson_obj, params=[])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100257 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
258
259 # Generate RV_PLIC Top Module
260 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
261 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700262 try:
263 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700264 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700265 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100266 log.info("RV_PLIC RTL: %s" % out)
267
268 if out == "":
269 log.error("Cannot generate interrupt controller RTL")
270 return
271
272 rtl_gen_path = rtl_path / "rv_plic.sv"
273 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
274 fout.write(genhdr + gencmd + out)
275
Eunchan Kimba970df2020-04-17 10:21:01 -0700276
Timothy Chenc2b279a2021-01-14 18:53:34 -0800277# returns the dedicated pin positions of a particular module
278# For example, if a module is connected to 6:1 of the dio connections,
279# [6, 1] will be returned.
280def _calc_dio_pin_pos(top, mname):
281 dios = top["pinmux"]["dio"]
282
283 last_index = dios.index(dios[-1])
284 bit_pos = []
285 first_index = False
286
287 for dio in dios:
288 if dio['module_name'] == mname and not first_index:
289 bit_pos.append(last_index - dios.index(dio))
290 first_index = True
291 elif first_index and dio['module_name'] != mname:
292 bit_pos.append(last_index - dios.index(dio) - 1)
293
294 # The last one, need to insert last element if only the msb
295 # position is found
296 if len(bit_pos) == 1:
297 bit_pos.append(0)
298
299 log.debug("bit pos {}".format(bit_pos))
300 return bit_pos
301
302
303def _find_dio_pin_pos(top, sname):
304 dios = top["pinmux"]["dio"]
305
306 last_index = dios.index(dios[-1])
307 bit_pos = -1
308
309 for dio in dios:
310 if dio['name'] == sname:
311 bit_pos = last_index - dios.index(dio)
312
313 if bit_pos < 0:
314 log.error("Could not find bit position of {} in dios".format(sname))
315
316 return bit_pos
317
318
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800319def generate_pinmux(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700320 topname = top["name"]
Eunchan Kim436d2242019-10-29 17:25:51 -0700321 # MIO Pads
Michael Schaffner57c490d2020-04-29 15:08:55 -0700322 n_mio_pads = top["pinmux"]["num_mio"]
323 if n_mio_pads <= 0:
324 # TODO: add support for no MIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700325 log.error("Topgen does currently not support generation of a top " +
326 "without a pinmux.")
327 return
328
329 if "padctrl" not in top:
330 # TODO: add support for no MIO case
331 log.error("Topgen does currently not support generation of a top " +
332 "without a padctrl instance.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700333 return
334
335 # Get number of wakeup detectors
336 if "num_wkup_detect" in top["pinmux"]:
337 num_wkup_detect = top["pinmux"]["num_wkup_detect"]
338 else:
339 num_wkup_detect = 1
340
341 if num_wkup_detect <= 0:
342 # TODO: add support for no wakeup counter case
Michael Schaffner60157962020-05-01 19:11:28 -0700343 log.error("Topgen does currently not support generation of a top " +
344 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700345 return
346
347 if "wkup_cnt_width" in top["pinmux"]:
348 wkup_cnt_width = top["pinmux"]["wkup_cnt_width"]
349 else:
350 wkup_cnt_width = 8
351
352 if wkup_cnt_width <= 1:
353 log.error("Wakeup counter width must be greater equal 2.")
Eunchan Kim436d2242019-10-29 17:25:51 -0700354 return
355
356 # Total inputs/outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700357 # Validation ensures that the width field is present.
Michael Schaffner60157962020-05-01 19:11:28 -0700358 num_mio_inputs = sum([x["width"] for x in top["pinmux"]["inputs"]])
359 num_mio_outputs = sum([x["width"] for x in top["pinmux"]["outputs"]])
Eunchan Kim436d2242019-10-29 17:25:51 -0700360
Michael Schaffner60157962020-05-01 19:11:28 -0700361 num_dio_inputs = sum([
362 x["width"] if x["type"] == "input" else 0 for x in top["pinmux"]["dio"]
363 ])
364 num_dio_outputs = sum([
365 x["width"] if x["type"] == "output" else 0
366 for x in top["pinmux"]["dio"]
367 ])
368 num_dio_inouts = sum([
369 x["width"] if x["type"] == "inout" else 0 for x in top["pinmux"]["dio"]
370 ])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700371
Michael Schaffnerb5b8eba2021-02-09 20:07:04 -0800372 n_mio_periph_in = num_mio_inputs
373 n_mio_periph_out = num_mio_outputs
Michael Schaffner57c490d2020-04-29 15:08:55 -0700374 n_dio_periph_in = num_dio_inouts + num_dio_inputs
375 n_dio_periph_out = num_dio_inouts + num_dio_outputs
376 n_dio_pads = num_dio_inouts + num_dio_inputs + num_dio_outputs
377
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800378 # TODO: derive this value
379 attr_dw = 10
380
Michael Schaffner57c490d2020-04-29 15:08:55 -0700381 if n_dio_pads <= 0:
382 # TODO: add support for no DIO case
Michael Schaffner60157962020-05-01 19:11:28 -0700383 log.error("Topgen does currently not support generation of a top " +
384 "without DIOs.")
Michael Schaffner57c490d2020-04-29 15:08:55 -0700385 return
386
Timothy Chenc2b279a2021-01-14 18:53:34 -0800387 # find the start and end pin positions for usbdev
388 usb_pin_pos = _calc_dio_pin_pos(top, "usbdev")
389 usb_start_pos = usb_pin_pos[-1]
390 n_usb_pins = usb_pin_pos[0] - usb_pin_pos[-1] + 1
391 usb_dp_sel = _find_dio_pin_pos(top, "usbdev_dp")
392 usb_dn_sel = _find_dio_pin_pos(top, "usbdev_dn")
393 usb_dp_pull_sel = _find_dio_pin_pos(top, "usbdev_dp_pullup")
394 usb_dn_pull_sel = _find_dio_pin_pos(top, "usbdev_dn_pullup")
395
Michael Schaffner57c490d2020-04-29 15:08:55 -0700396 log.info("Generating pinmux with following info from hjson:")
397 log.info("num_mio_inputs: %d" % num_mio_inputs)
398 log.info("num_mio_outputs: %d" % num_mio_outputs)
Michael Schaffner57c490d2020-04-29 15:08:55 -0700399 log.info("num_dio_inputs: %d" % num_dio_inputs)
400 log.info("num_dio_outputs: %d" % num_dio_outputs)
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800401 log.info("attr_dw: %d" % attr_dw)
Michael Schaffner57c490d2020-04-29 15:08:55 -0700402 log.info("num_wkup_detect: %d" % num_wkup_detect)
403 log.info("wkup_cnt_width: %d" % wkup_cnt_width)
404 log.info("This translates to:")
405 log.info("n_mio_periph_in: %d" % n_mio_periph_in)
406 log.info("n_mio_periph_out: %d" % n_mio_periph_out)
407 log.info("n_dio_periph_in: %d" % n_dio_periph_in)
408 log.info("n_dio_periph_out: %d" % n_dio_periph_out)
409 log.info("n_dio_pads: %d" % n_dio_pads)
Timothy Chenc2b279a2021-01-14 18:53:34 -0800410 log.info("usb_start_pos: %d" % usb_start_pos)
411 log.info("n_usb_pins: %d" % n_usb_pins)
Eunchan Kim436d2242019-10-29 17:25:51 -0700412
413 # Target path
414 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
415 # data: pinmux.hjson
416 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
417 rtl_path.mkdir(parents=True, exist_ok=True)
418 data_path = out_path / 'ip/pinmux/data/autogen'
419 data_path.mkdir(parents=True, exist_ok=True)
420
421 # Template path
Weicai Yang5c02d782020-12-08 12:17:51 -0800422 tpl_path = Path(
423 __file__).resolve().parent / '../hw/ip/pinmux/data/pinmux.hjson.tpl'
Eunchan Kim436d2242019-10-29 17:25:51 -0700424
425 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700426 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
427 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700428
429 hjson_gen_path = data_path / "pinmux.hjson"
430
431 out = StringIO()
432 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
433 hjson_tpl = Template(fin.read())
434 try:
Michael Schaffner57c490d2020-04-29 15:08:55 -0700435 # TODO: pass in information about always-on peripherals
436 # TODO: pass in information on which DIOs can be selected
437 # as wakeup signals
438 # TODO: pass in signal names such that we can introduce
439 # named enums for select signals
Michael Schaffner60157962020-05-01 19:11:28 -0700440 out = hjson_tpl.render(
441 n_mio_periph_in=n_mio_periph_in,
442 n_mio_periph_out=n_mio_periph_out,
443 n_mio_pads=n_mio_pads,
444 # each DIO has in, out and oe wires
445 # some of these have to be tied off in the
446 # top, depending on the type.
447 n_dio_periph_in=n_dio_pads,
448 n_dio_periph_out=n_dio_pads,
449 n_dio_pads=n_dio_pads,
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800450 attr_dw=attr_dw,
Michael Schaffner60157962020-05-01 19:11:28 -0700451 n_wkup_detect=num_wkup_detect,
Timothy Chenc2b279a2021-01-14 18:53:34 -0800452 wkup_cnt_width=wkup_cnt_width,
453 usb_start_pos=usb_start_pos,
454 n_usb_pins=n_usb_pins,
455 usb_dp_sel=usb_dp_sel,
456 usb_dn_sel=usb_dn_sel,
457 usb_dp_pull_sel=usb_dp_pull_sel,
458 usb_dn_pull_sel=usb_dn_pull_sel
459 )
Eunchan Kim6599ba92020-04-13 15:27:16 -0700460 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700461 log.error(exceptions.text_error_template().render())
462 log.info("PINMUX HJSON: %s" % out)
463
464 if out == "":
465 log.error("Cannot generate pinmux HJSON")
466 return
467
468 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
469 fout.write(genhdr + gencmd + out)
470
471 hjson_obj = hjson.loads(out,
472 use_decimal=True,
473 object_pairs_hook=validate.checking_dict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000474 validate.validate(hjson_obj, params=[])
Eunchan Kim436d2242019-10-29 17:25:51 -0700475 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
476
Michael Schaffner60157962020-05-01 19:11:28 -0700477
Timothy Chenf56c1b52020-04-28 17:00:43 -0700478def generate_clkmgr(top, cfg_path, out_path):
479
480 # Target paths
481 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
482 rtl_path.mkdir(parents=True, exist_ok=True)
483 data_path = out_path / 'ip/clkmgr/data/autogen'
484 data_path.mkdir(parents=True, exist_ok=True)
485
486 # Template paths
487 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700488 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
489 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700490
491 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700492 rtl_out = rtl_path / 'clkmgr.sv'
493 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700494
495 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
496 outputs = [hjson_out, rtl_out, pkg_out]
497 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
498
499 # clock classification
500 grps = top['clocks']['groups']
501
502 ft_clks = OrderedDict()
503 rg_clks = OrderedDict()
504 sw_clks = OrderedDict()
Timothy Chenc8f30042020-09-25 16:59:47 -0700505 src_aon_attr = OrderedDict()
Timothy Chenf56c1b52020-04-28 17:00:43 -0700506 hint_clks = OrderedDict()
507
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700508 # construct a dictionary of the aon attribute for easier lookup
509 # ie, src_name_A: True, src_name_B: False
Timothy Chenb63f3b82020-06-30 17:10:57 -0700510 for src in top['clocks']['srcs'] + top['clocks']['derived_srcs']:
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700511 if src['aon'] == 'yes':
512 src_aon_attr[src['name']] = True
513 else:
514 src_aon_attr[src['name']] = False
515
516 rg_srcs = [src for (src, attr) in src_aon_attr.items() if not attr]
517
518 # clocks fed through clkmgr but are not disturbed in any way
519 # This maintains the clocking structure consistency
Timothy Chenb63f3b82020-06-30 17:10:57 -0700520 # This includes two groups of clocks
521 # Clocks fed from the always-on source
522 # Clocks fed to the powerup group
Weicai Yanga6670362020-11-24 17:19:52 -0800523 ft_clks = OrderedDict([(clk, src) for grp in grps
524 for (clk, src) in grp['clocks'].items()
525 if src_aon_attr[src] or grp['name'] == 'powerup'])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700526
527 # root-gate clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800528 rg_clks = OrderedDict([(clk, src) for grp in grps
529 for (clk, src) in grp['clocks'].items()
530 if grp['name'] != 'powerup' and
531 grp['sw_cg'] == 'no' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700532
533 # direct sw control clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800534 sw_clks = OrderedDict([(clk, src) for grp in grps
535 for (clk, src) in grp['clocks'].items()
536 if grp['sw_cg'] == 'yes' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700537
538 # sw hint clocks
Weicai Yanga6670362020-11-24 17:19:52 -0800539 hints = OrderedDict([(clk, src) for grp in grps
540 for (clk, src) in grp['clocks'].items()
541 if grp['sw_cg'] == 'hint' and not src_aon_attr[src]])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700542
Timothy Chenc8f30042020-09-25 16:59:47 -0700543 # hint clocks dict
544 for clk, src in hints.items():
Timothy Chen455afcb2020-10-01 11:46:35 -0700545 # the clock is constructed as clk_{src_name}_{module_name}.
Timothy Chenc8f30042020-09-25 16:59:47 -0700546 # so to get the module name we split from the right and pick the last entry
547 hint_clks[clk] = OrderedDict()
548 hint_clks[clk]['name'] = (clk.rsplit('_', 1)[-1])
549 hint_clks[clk]['src'] = src
550
Timothy Chenf56c1b52020-04-28 17:00:43 -0700551 for idx, tpl in enumerate(tpls):
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100552 out = ""
Timothy Chenf56c1b52020-04-28 17:00:43 -0700553 with tpl.open(mode='r', encoding='UTF-8') as fin:
554 tpl = Template(fin.read())
555 try:
556 out = tpl.render(cfg=top,
Timothy Chenb63f3b82020-06-30 17:10:57 -0700557 div_srcs=top['clocks']['derived_srcs'],
Timothy Chen33b3b9d2020-05-08 10:14:17 -0700558 rg_srcs=rg_srcs,
Timothy Chenf56c1b52020-04-28 17:00:43 -0700559 ft_clks=ft_clks,
560 rg_clks=rg_clks,
561 sw_clks=sw_clks,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700562 export_clks=top['exported_clks'],
Timothy Chenf56c1b52020-04-28 17:00:43 -0700563 hint_clks=hint_clks)
564 except: # noqa: E722
565 log.error(exceptions.text_error_template().render())
566
567 if out == "":
568 log.error("Cannot generate {}".format(names[idx]))
569 return
570
571 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
572 fout.write(genhdr + out)
573
574 # Generate reg files
575 with open(str(hjson_out), 'r') as out:
576 hjson_obj = hjson.load(out,
577 use_decimal=True,
578 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000579 validate.validate(hjson_obj, params=[])
Timothy Chenf56c1b52020-04-28 17:00:43 -0700580 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700581
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700582
Timothy Chen4ba25312020-06-17 13:08:57 -0700583# generate pwrmgr
584def generate_pwrmgr(top, out_path):
585 log.info("Generating pwrmgr")
586
Timothy Chen6faf4f12020-09-18 18:52:47 -0700587 # Count number of wakeups
Timothy Chen4ba25312020-06-17 13:08:57 -0700588 n_wkups = len(top["wakeups"])
589 log.info("Found {} wakeup signals".format(n_wkups))
590
Timothy Chen6faf4f12020-09-18 18:52:47 -0700591 # Count number of reset requests
592 n_rstreqs = len(top["reset_requests"])
593 log.info("Found {} reset request signals".format(n_rstreqs))
594
Timothy Chen4ba25312020-06-17 13:08:57 -0700595 if n_wkups < 1:
596 n_wkups = 1
Eunchan Kim9191f262020-07-30 16:37:40 -0700597 log.warning(
598 "The design has no wakeup sources. Low power not supported")
Timothy Chen4ba25312020-06-17 13:08:57 -0700599
600 # Define target path
601 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
602 rtl_path.mkdir(parents=True, exist_ok=True)
603 doc_path = out_path / 'ip/pwrmgr/data/autogen'
604 doc_path.mkdir(parents=True, exist_ok=True)
605
606 # So, read template files from ip directory.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100607 tpl_path = Path(__file__).resolve().parent / '../hw/ip/pwrmgr/data'
Timothy Chen4ba25312020-06-17 13:08:57 -0700608 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
609
610 # Render and write out hjson
611 out = StringIO()
612 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
613 hjson_tpl = Template(fin.read())
614 try:
Timothy Chenbea7b6a2021-01-21 13:59:20 -0800615 out = hjson_tpl.render(NumWkups=n_wkups,
616 Wkups=top["wakeups"],
617 NumRstReqs=n_rstreqs)
Timothy Chen4ba25312020-06-17 13:08:57 -0700618
619 except: # noqa: E722
620 log.error(exceptions.text_error_template().render())
621 log.info("pwrmgr hjson: %s" % out)
622
623 if out == "":
624 log.error("Cannot generate pwrmgr config file")
625 return
626
627 hjson_path = doc_path / "pwrmgr.hjson"
628 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
629 fout.write(genhdr + out)
630
631 # Generate reg files
632 with open(str(hjson_path), 'r') as out:
633 hjson_obj = hjson.load(out,
634 use_decimal=True,
635 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000636 validate.validate(hjson_obj, params=[])
Timothy Chen4ba25312020-06-17 13:08:57 -0700637 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
638
639
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700640# generate rstmgr
641def generate_rstmgr(topcfg, out_path):
642 log.info("Generating rstmgr")
643
644 # Define target path
645 rtl_path = out_path / 'ip/rstmgr/rtl/autogen'
646 rtl_path.mkdir(parents=True, exist_ok=True)
647 doc_path = out_path / 'ip/rstmgr/data/autogen'
648 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100649 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rstmgr/data'
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700650
651 # Read template files from ip directory.
652 tpls = []
653 outputs = []
654 names = ['rstmgr.hjson', 'rstmgr.sv', 'rstmgr_pkg.sv']
655
656 for x in names:
657 tpls.append(tpl_path / Path(x + ".tpl"))
658 if "hjson" in x:
659 outputs.append(doc_path / Path(x))
660 else:
661 outputs.append(rtl_path / Path(x))
662
663 # Parameters needed for generation
664 clks = []
665 output_rsts = OrderedDict()
666 sw_rsts = OrderedDict()
667 leaf_rsts = OrderedDict()
668
669 # unique clocks
Timothy Chenc6233932020-08-19 15:34:07 -0700670 for rst in topcfg["resets"]["nodes"]:
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700671 if rst['type'] != "ext" and rst['clk'] not in clks:
672 clks.append(rst['clk'])
673
674 # resets sent to reset struct
Weicai Yanga6670362020-11-24 17:19:52 -0800675 output_rsts = [
676 rst for rst in topcfg["resets"]["nodes"] if rst['type'] == "top"
677 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700678
679 # sw controlled resets
Weicai Yanga6670362020-11-24 17:19:52 -0800680 sw_rsts = [
681 rst for rst in topcfg["resets"]["nodes"]
682 if 'sw' in rst and rst['sw'] == 1
683 ]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700684
685 # leaf resets
Timothy Chenc6233932020-08-19 15:34:07 -0700686 leaf_rsts = [rst for rst in topcfg["resets"]["nodes"] if rst['gen']]
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700687
688 log.info("output resets {}".format(output_rsts))
689 log.info("software resets {}".format(sw_rsts))
690 log.info("leaf resets {}".format(leaf_rsts))
691
Timothy Chen6faf4f12020-09-18 18:52:47 -0700692 # Number of reset requests
693 n_rstreqs = len(topcfg["reset_requests"])
694
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700695 # Generate templated files
696 for idx, t in enumerate(tpls):
697 out = StringIO()
698 with t.open(mode='r', encoding='UTF-8') as fin:
699 tpl = Template(fin.read())
700 try:
701 out = tpl.render(clks=clks,
Timothy Chen7f8cc8e2020-11-11 13:15:57 -0800702 power_domains=topcfg['power']['domains'],
Timothy Chen6faf4f12020-09-18 18:52:47 -0700703 num_rstreqs=n_rstreqs,
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700704 sw_rsts=sw_rsts,
705 output_rsts=output_rsts,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700706 leaf_rsts=leaf_rsts,
707 export_rsts=topcfg['exported_rsts'])
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700708
709 except: # noqa: E722
710 log.error(exceptions.text_error_template().render())
711
712 if out == "":
713 log.error("Cannot generate {}".format(names[idx]))
714 return
715
716 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
717 fout.write(genhdr + out)
718
719 # Generate reg files
720 hjson_path = outputs[0]
721 with open(str(hjson_path), 'r') as out:
722 hjson_obj = hjson.load(out,
723 use_decimal=True,
724 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000725 validate.validate(hjson_obj, params=[])
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700726 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
727
728
Timothy Chen1daf5822020-10-26 17:28:15 -0700729# generate flash
730def generate_flash(topcfg, out_path):
731 log.info("Generating flash")
732
733 # Define target path
734 rtl_path = out_path / 'ip/flash_ctrl/rtl/autogen'
735 rtl_path.mkdir(parents=True, exist_ok=True)
736 doc_path = out_path / 'ip/flash_ctrl/data/autogen'
737 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100738 tpl_path = Path(__file__).resolve().parent / '../hw/ip/flash_ctrl/data'
Timothy Chen1daf5822020-10-26 17:28:15 -0700739
740 # Read template files from ip directory.
741 tpls = []
742 outputs = []
743 names = ['flash_ctrl.hjson', 'flash_ctrl.sv', 'flash_ctrl_pkg.sv']
744
745 for x in names:
746 tpls.append(tpl_path / Path(x + ".tpl"))
747 if "hjson" in x:
748 outputs.append(doc_path / Path(x))
749 else:
750 outputs.append(rtl_path / Path(x))
751
752 # Parameters needed for generation
753 flash_mems = [mem for mem in topcfg['memory'] if mem['type'] == 'eflash']
754 if len(flash_mems) > 1:
755 log.error("This design does not currently support multiple flashes")
756 return
757
758 cfg = flash_mems[0]
759
760 # Generate templated files
761 for idx, t in enumerate(tpls):
762 out = StringIO()
763 with t.open(mode='r', encoding='UTF-8') as fin:
764 tpl = Template(fin.read())
765 try:
766 out = tpl.render(cfg=cfg)
767
768 except: # noqa: E722
769 log.error(exceptions.text_error_template().render())
770
771 if out == "":
772 log.error("Cannot generate {}".format(names[idx]))
773 return
774
775 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
776 fout.write(genhdr + out)
777
778 # Generate reg files
779 hjson_path = outputs[0]
780 with open(str(hjson_path), 'r') as out:
781 hjson_obj = hjson.load(out,
782 use_decimal=True,
783 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000784 validate.validate(hjson_obj, params=[])
Timothy Chen1daf5822020-10-26 17:28:15 -0700785 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
786
787
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100788def generate_top_only(top_only_list, out_path, topname):
Timothy Chen322f2542020-08-05 16:28:18 -0700789 log.info("Generating top only modules")
790
791 for ip in top_only_list:
Weicai Yang5c02d782020-12-08 12:17:51 -0800792 hjson_path = Path(__file__).resolve(
793 ).parent / "../hw/top_{}/ip/{}/data/{}.hjson".format(topname, ip, ip)
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100794 genrtl_dir = out_path / "ip/{}/rtl".format(ip)
795 genrtl_dir.mkdir(parents=True, exist_ok=True)
Timothy Chen322f2542020-08-05 16:28:18 -0700796 log.info("Generating top modules {}, hjson: {}, output: {}".format(
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100797 ip, hjson_path, genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700798
799 # Generate reg files
800 with open(str(hjson_path), 'r') as out:
801 hjson_obj = hjson.load(out,
802 use_decimal=True,
803 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000804 validate.validate(hjson_obj, params=[])
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100805 gen_rtl.gen_rtl(hjson_obj, str(genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700806
807
Srikrishna Iyerd2341c22021-01-11 22:31:18 -0800808def generate_top_ral(top, ip_objs, dv_base_prefix, out_path):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100809 # construct top ral block
810 top_block = gen_rtl.Block()
811 top_block.name = "chip"
812 top_block.base_addr = 0
813 top_block.width = int(top["datawidth"])
814
Weicai Yang2f881702020-11-24 17:22:02 -0800815 # add all the IPs into blocks
lowRISC Contributors802543a2019-08-31 12:12:56 +0100816 for ip_obj in ip_objs:
817 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
818
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000819 assert top_block.width % 8 == 0
820 reg_width_in_bytes = top_block.width // 8
821
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000822 top_block.reg_block = RegBlock(reg_width_in_bytes,
823 top_block.width,
824 [])
825
826 # Add memories (in order)
827 mems = []
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000828 for item in list(top.get("memory", [])):
829 byte_write = ('byte_write' in item and
830 item["byte_write"].lower() == "true")
831 size_in_bytes = int(item['size'], 0)
832 num_regs = size_in_bytes // reg_width_in_bytes
833 swaccess = access.SWAccess('top-level memory',
834 item.get('swaccess', 'rw'))
835
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000836 mems.append(window.Window(name=item['name'],
837 desc='(generated from top-level)',
838 unusual=False,
839 byte_write=byte_write,
840 validbits=top_block.width,
841 items=num_regs,
842 size_in_bytes=size_in_bytes,
843 offset=int(item["base_addr"], 0),
844 swaccess=swaccess))
845 mems.sort(key=lambda w: w.offset)
846 for mem in mems:
847 top_block.reg_block.add_window(mem)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100848
Weicai Yang2f881702020-11-24 17:22:02 -0800849 # get sub-block base addresses, instance names from top cfg
lowRISC Contributors802543a2019-08-31 12:12:56 +0100850 for block in top_block.blocks:
851 for module in top["module"]:
Weicai Yang2f881702020-11-24 17:22:02 -0800852 if block.name == module["type"]:
853 block.base_addr[module["name"]] = int(module["base_addr"], 0)
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700854
Weicai Yang2f881702020-11-24 17:22:02 -0800855 # sort by the base_addr of 1st instance of the block
856 top_block.blocks.sort(key=lambda block: next(iter(block.base_addr))[1])
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700857
lowRISC Contributors802543a2019-08-31 12:12:56 +0100858 # generate the top ral model with template
Srikrishna Iyerd2341c22021-01-11 22:31:18 -0800859 gen_dv.gen_ral(top_block, dv_base_prefix, str(out_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100860
861
Timothy Chen315b1212021-01-22 11:08:03 -0800862def _process_top(topcfg, args, cfg_path, out_path, pass_idx):
863 # Create generated list
864 # These modules are generated through topgen
865 generated_list = [
866 module['type'] for module in topcfg['module']
Timothy Chen94432212021-03-01 22:29:18 -0800867 if lib.is_templated(module)
Timothy Chen315b1212021-01-22 11:08:03 -0800868 ]
869 log.info("Filtered list is {}".format(generated_list))
870
871 # These modules are NOT generated but belong to a specific top
872 # and therefore not part of "hw/ip"
873 top_only_list = [
874 module['type'] for module in topcfg['module']
Timothy Chen94432212021-03-01 22:29:18 -0800875 if lib.is_top_reggen(module)
Timothy Chen315b1212021-01-22 11:08:03 -0800876 ]
877 log.info("Filtered list is {}".format(top_only_list))
878
879 topname = topcfg["name"]
880
881 # Sweep the IP directory and gather the config files
882 ip_dir = Path(__file__).parents[1] / 'hw/ip'
883 ips = search_ips(ip_dir)
884
885 # exclude filtered IPs (to use top_${topname} one) and
886 exclude_list = generated_list + top_only_list
887 ips = [x for x in ips if not x.parents[1].name in exclude_list]
888
889 # Hack alert
890 # Generate clkmgr.hjson here so that it can be included below
891 # Unlike other generated hjsons, clkmgr thankfully does not require
892 # ip.hjson information. All the information is embedded within
893 # the top hjson file
894 amend_clocks(topcfg)
895 generate_clkmgr(topcfg, cfg_path, out_path)
896
897 # It may require two passes to check if the module is needed.
898 # TODO: first run of topgen will fail due to the absent of rv_plic.
899 # It needs to run up to amend_interrupt in merge_top function
900 # then creates rv_plic.hjson then run xbar generation.
901 hjson_dir = Path(args.topcfg).parent
902
903 for ip in generated_list:
Timothy Chen744c3c02021-01-20 20:23:22 -0800904 # For modules that are generated prior to gathering, we need to take it from
Timothy Chen5302fff2021-01-22 14:36:54 -0800905 # the output path. For modules not generated before, it may exist in a
Timothy Chen744c3c02021-01-20 20:23:22 -0800906 # pre-defined area already.
Timothy Chen315b1212021-01-22 11:08:03 -0800907 log.info("Appending {}".format(ip))
908 if ip == 'clkmgr' or (pass_idx > 0):
909 ip_hjson = Path(out_path) / "ip/{}/data/autogen/{}.hjson".format(
910 ip, ip)
911 else:
912 ip_hjson = hjson_dir.parent / "ip/{}/data/autogen/{}.hjson".format(
913 ip, ip)
914 ips.append(ip_hjson)
915
916 for ip in top_only_list:
917 log.info("Appending {}".format(ip))
918 ip_hjson = hjson_dir.parent / "ip/{}/data/{}.hjson".format(ip, ip)
919 ips.append(ip_hjson)
920
921 # load Hjson and pass validate from reggen
922 try:
923 ip_objs = []
924 for x in ips:
925 # Skip if it is not in the module list
926 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
927 log.info("Skip module %s as it isn't in the top module list" %
928 x.stem)
929 continue
930
931 # The auto-generated hjson might not yet exist. It will be created
932 # later, see generate_{ip_name}() calls below. For the initial
933 # validation, use the template in hw/ip/{ip_name}/data .
934 if x.stem in generated_list and not x.is_file():
935 hjson_file = ip_dir / "{}/data/{}.hjson".format(x.stem, x.stem)
936 log.info(
937 "Auto-generated hjson %s does not yet exist. " % str(x) +
938 "Falling back to template %s for initial validation." %
939 str(hjson_file))
940 else:
941 hjson_file = x
942
943 obj = hjson.load(hjson_file.open('r'),
944 use_decimal=True,
945 object_pairs_hook=OrderedDict)
Rupert Swarbrick611a6422021-02-12 11:56:48 +0000946 if validate.validate(obj, params=[]) != 0:
Timothy Chen315b1212021-01-22 11:08:03 -0800947 log.info("Parsing IP %s configuration failed. Skip" % x)
948 continue
949 ip_objs.append(obj)
950
951 except ValueError:
952 raise SystemExit(sys.exc_info()[1])
953
954 # Read the crossbars under the top directory
955 xbar_objs = get_hjsonobj_xbars(hjson_dir)
956
957 log.info("Detected crossbars: %s" %
958 (", ".join([x["name"] for x in xbar_objs])))
959
960 # If specified, override the seed for random netlist constant computation.
961 if args.rnd_cnst_seed:
962 log.warning('Commandline override of rnd_cnst_seed with {}.'.format(
963 args.rnd_cnst_seed))
964 topcfg['rnd_cnst_seed'] = args.rnd_cnst_seed
965 # Otherwise, we either take it from the top_{topname}.hjson if present, or
966 # randomly generate a new seed if not.
967 else:
968 random.seed()
969 new_seed = random.getrandbits(64)
970 if topcfg.setdefault('rnd_cnst_seed', new_seed) == new_seed:
971 log.warning(
972 'No rnd_cnst_seed specified, setting to {}.'.format(new_seed))
973
974 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
975 if error != 0:
976 raise SystemExit("Error occured while validating top.hjson")
977
978 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
979
Timothy Chen744c3c02021-01-20 20:23:22 -0800980 # Generate flash controller and flash memory
981 generate_flash(topcfg, out_path)
982
Timothy Chen315b1212021-01-22 11:08:03 -0800983 # Generate PLIC
984 if not args.no_plic and \
985 not args.alert_handler_only and \
986 not args.xbar_only:
987 generate_plic(completecfg, out_path)
988 if args.plic_only:
989 sys.exit()
990
991 # Generate Alert Handler
992 if not args.xbar_only:
993 generate_alert_handler(completecfg, out_path)
994 if args.alert_handler_only:
995 sys.exit()
996
997 # Generate Pinmux
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800998 generate_pinmux(completecfg, out_path)
Timothy Chen315b1212021-01-22 11:08:03 -0800999
1000 # Generate Pwrmgr
1001 generate_pwrmgr(completecfg, out_path)
1002
1003 # Generate rstmgr
1004 generate_rstmgr(completecfg, out_path)
1005
Timothy Chen315b1212021-01-22 11:08:03 -08001006 # Generate top only modules
1007 # These modules are not templated, but are not in hw/ip
1008 generate_top_only(top_only_list, out_path, topname)
1009
1010 if pass_idx > 0 and args.top_ral:
1011 generate_top_ral(completecfg, ip_objs, args.dv_base_prefix, out_path)
1012 sys.exit()
1013
1014 return completecfg
1015
1016
lowRISC Contributors802543a2019-08-31 12:12:56 +01001017def main():
1018 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -07001019 parser.add_argument('--topcfg',
1020 '-t',
1021 required=True,
1022 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -07001023 parser.add_argument(
1024 '--tpl',
1025 '-c',
1026 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -07001027 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001028 parser.add_argument(
1029 '--outdir',
1030 '-o',
1031 help='''Target TOP directory.
1032 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -07001033 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +01001034 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
1035
1036 # Generator options: 'no' series. cannot combined with 'only' series
1037 parser.add_argument(
1038 '--no-top',
1039 action='store_true',
1040 help="If defined, topgen doesn't generate top_{name} RTLs.")
1041 parser.add_argument(
1042 '--no-xbar',
1043 action='store_true',
1044 help="If defined, topgen doesn't generate crossbar RTLs.")
1045 parser.add_argument(
1046 '--no-plic',
1047 action='store_true',
1048 help="If defined, topgen doesn't generate the interrup controller RTLs."
1049 )
lowRISC Contributors802543a2019-08-31 12:12:56 +01001050
1051 # Generator options: 'only' series. cannot combined with 'no' series
1052 parser.add_argument(
1053 '--top-only',
1054 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -07001055 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +01001056 parser.add_argument(
1057 '--xbar-only',
1058 action='store_true',
1059 help="If defined, the tool generates crossbar RTLs only")
1060 parser.add_argument(
1061 '--plic-only',
1062 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +00001063 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001064 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -07001065 '--alert-handler-only',
1066 action='store_true',
1067 help="If defined, the tool generates alert handler hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +01001068 # Generator options: generate dv ral model
1069 parser.add_argument(
1070 '--top_ral',
1071 '-r',
1072 default=False,
1073 action='store_true',
1074 help="If set, the tool generates top level RAL model for DV")
Srikrishna Iyerd2341c22021-01-11 22:31:18 -08001075 parser.add_argument('--dv-base-prefix',
1076 default='dv_base',
1077 help='Prefix for the DV register classes from which '
1078 'the register models are derived.')
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001079 # Generator options for compile time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -08001080 parser.add_argument(
1081 '--rnd_cnst_seed',
1082 type=int,
1083 metavar='<seed>',
1084 help='Custom seed for RNG to compute netlist constants.')
lowRISC Contributors802543a2019-08-31 12:12:56 +01001085
1086 args = parser.parse_args()
1087
1088 # check combinations
1089 if args.top_ral:
lowRISC Contributors802543a2019-08-31 12:12:56 +01001090 args.no_top = True
1091
lowRISC Contributors802543a2019-08-31 12:12:56 +01001092 if (args.no_top or args.no_xbar or
1093 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -07001094 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +01001095 log.error(
1096 "'no' series options cannot be used with 'only' series options")
1097 raise SystemExit(sys.exc_info()[1])
1098
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001099 if not (args.top_ral or args.plic_only or args.alert_handler_only or
Eunchan Kimc7452942019-12-19 17:04:37 -08001100 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +01001101 log.error(
1102 "Template file can be omitted only if '--hjson-only' is true")
1103 raise SystemExit(sys.exc_info()[1])
1104
1105 if args.verbose:
1106 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
1107 else:
1108 log.basicConfig(format="%(levelname)s: %(message)s")
1109
1110 if not args.outdir:
1111 outdir = Path(args.topcfg).parent / ".."
1112 log.info("TOP directory not given. Use %s", (outdir))
1113 elif not Path(args.outdir).is_dir():
1114 log.error("'--outdir' should point to writable directory")
1115 raise SystemExit(sys.exc_info()[1])
1116 else:
1117 outdir = Path(args.outdir)
1118
1119 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001120 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001121
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001122 try:
1123 with open(args.topcfg, 'r') as ftop:
1124 topcfg = hjson.load(ftop,
1125 use_decimal=True,
1126 object_pairs_hook=OrderedDict)
1127 except ValueError:
1128 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +01001129
Timothy Chen315b1212021-01-22 11:08:03 -08001130 # TODO, long term, the levels of dependency should be automatically determined instead
1131 # of hardcoded. The following are a few examples:
1132 # Example 1: pinmux depends on amending all modules before calculating the correct number of
1133 # pins.
1134 # This would be 1 level of dependency and require 2 passes.
1135 # Example 2: pinmux depends on amending all modules, and pwrmgr depends on pinmux generation to
1136 # know correct number of wakeups. This would be 2 levels of dependency and require 3
1137 # passes.
1138 #
1139 # How does mulit-pass work?
1140 # In example 1, the first pass gathers all modules and merges them. However, the merge process
1141 # uses a stale pinmux. The correct pinmux is then generated using the merged configuration. The
1142 # second pass now merges all the correct modules (including the generated pinmux) and creates
1143 # the final merged config.
1144 #
1145 # In example 2, the first pass gathers all modules and merges them. However, the merge process
1146 # uses a stale pinmux and pwrmgr. The correct pinmux is then generated using the merged
1147 # configuration. However, since pwrmgr is dependent on this new pinmux, it is still generated
1148 # incorrectly. The second pass merge now has an updated pinmux but stale pwrmgr. The correct
1149 # pwrmgr can now be generated. The final pass then merges all the correct modules and creates
1150 # the final configuration.
1151 #
1152 # This fix is related to #2083
1153 process_dependencies = 1
1154 for pass_idx in range(process_dependencies + 1):
1155 log.debug("Generation pass {}".format(pass_idx))
1156 if pass_idx < process_dependencies:
1157 cfg_copy = deepcopy(topcfg)
1158 _process_top(cfg_copy, args, cfg_path, out_path, pass_idx)
1159 else:
1160 completecfg = _process_top(topcfg, args, cfg_path, out_path, pass_idx)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001161
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001162 topname = topcfg["name"]
Eunchan Kimba970df2020-04-17 10:21:01 -07001163
lowRISC Contributors802543a2019-08-31 12:12:56 +01001164 # Generate xbars
1165 if not args.no_xbar or args.xbar_only:
1166 generate_xbars(completecfg, out_path)
1167
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001168 # All IPs are generated. Connect phase now
Eunchan Kim2c813b42020-08-03 16:22:56 -07001169 # Find {memory, module} <-> {xbar} connections first.
1170 im.autoconnect(completecfg)
1171
1172 # Generic Inter-module connection
1173 im.elab_intermodule(completecfg)
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001174
lowRISC Contributors802543a2019-08-31 12:12:56 +01001175 top_name = completecfg["name"]
1176
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001177 # Generate top.gen.hjson right before rendering
Pirmin Vogel71bfd9b2020-11-24 17:28:20 +01001178 genhjson_dir = Path(out_path) / "data/autogen"
1179 genhjson_dir.mkdir(parents=True, exist_ok=True)
1180 genhjson_path = genhjson_dir / ("top_%s.gen.hjson" % completecfg["name"])
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001181
1182 # Header for HJSON
1183 gencmd = '''//
1184// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
1185// -o hw/top_{topname}/ \\
1186// --hjson-only \\
1187// --rnd_cnst_seed {seed}
1188'''.format(topname=topname, seed=completecfg['rnd_cnst_seed'])
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001189
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001190 genhjson_path.write_text(genhdr + gencmd +
1191 hjson.dumps(completecfg, for_json=True))
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001192
lowRISC Contributors802543a2019-08-31 12:12:56 +01001193 if not args.no_top or args.top_only:
Eunchan Kim632c6f72019-09-30 11:11:51 -07001194 tpl_path = Path(args.tpl)
Eunchan Kim632c6f72019-09-30 11:11:51 -07001195
Sam Elliott7e36bd72020-04-22 14:05:49 +01001196 def render_template(out_name_tpl, out_dir, **other_info):
1197 top_tplpath = tpl_path / ((out_name_tpl + '.tpl') % (top_name))
Eunchan Kimfd561be2020-04-24 15:42:11 -07001198 template_contents = generate_top(completecfg, str(top_tplpath),
1199 **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001200
Sam Elliott7e36bd72020-04-22 14:05:49 +01001201 rendered_dir = out_path / out_dir
1202 rendered_dir.mkdir(parents=True, exist_ok=True)
1203 rendered_path = rendered_dir / (out_name_tpl % (top_name))
lowRISC Contributors802543a2019-08-31 12:12:56 +01001204
Sam Elliott7e36bd72020-04-22 14:05:49 +01001205 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1206 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -07001207
Tobias Wölfelea1903d2020-09-23 12:48:57 +02001208 return rendered_path.resolve()
Eunchan Kim436d2242019-10-29 17:25:51 -07001209
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001210 # Header for SV files
1211 gencmd = warnhdr + '''//
1212// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
Pirmin Vogel0d713282020-11-23 18:35:44 +01001213// --tpl hw/top_{topname}/data/ \\
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001214// -o hw/top_{topname}/ \\
1215// --rnd_cnst_seed {seed}
1216'''.format(topname=topname, seed=topcfg['rnd_cnst_seed'])
1217
Sam Elliott7e36bd72020-04-22 14:05:49 +01001218 # SystemVerilog Top:
Weicai Yanga6670362020-11-24 17:19:52 -08001219 render_template('top_%s.sv', 'rtl/autogen', gencmd=gencmd)
Pirmin Vogel0d713282020-11-23 18:35:44 +01001220 # 'top_{topname}.sv.tpl' -> 'rtl/autogen/top_{topname}.sv'
Eunchan Kim436d2242019-10-29 17:25:51 -07001221
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001222 # The C / SV file needs some complex information, so we initialize this
Sam Elliottd1790472020-07-24 23:25:10 +01001223 # object to store it.
Sam Elliotte74c6292020-07-24 21:40:00 +01001224 c_helper = TopGenC(completecfg)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001225
Pirmin Vogel0d713282020-11-23 18:35:44 +01001226 # 'top_{topname}_pkg.sv.tpl' -> 'rtl/autogen/top_{topname}_pkg.sv'
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001227 render_template('top_%s_pkg.sv',
1228 'rtl/autogen',
1229 helper=c_helper,
Weicai Yanga6670362020-11-24 17:19:52 -08001230 gencmd=gencmd)
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001231
1232 # compile-time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -08001233 render_template('top_%s_rnd_cnst_pkg.sv', 'rtl/autogen', gencmd=gencmd)
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001234
1235 # C Header + C File + Clang-format file
1236
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001237 # Since SW does not use FuseSoC and instead expects those files always
1238 # to be in hw/top_{topname}/sw/autogen, we currently create these files
1239 # twice:
1240 # - Once under out_path/sw/autogen
1241 # - Once under hw/top_{topname}/sw/autogen
1242 for path in [Path(out_path).resolve(),
1243 (SRCTREE_TOP / 'hw/top_{}/'.format(topname)).resolve()]:
Sam Elliott2a4448b2020-04-23 11:15:43 +01001244
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001245 # 'clang-format' -> 'sw/autogen/.clang-format'
1246 cformat_tplpath = tpl_path / 'clang-format'
1247 cformat_dir = path / 'sw/autogen'
1248 cformat_dir.mkdir(parents=True, exist_ok=True)
1249 cformat_path = cformat_dir / '.clang-format'
1250 cformat_path.write_text(cformat_tplpath.read_text())
Sam Elliott7e36bd72020-04-22 14:05:49 +01001251
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001252 # 'top_{topname}.h.tpl' -> 'sw/autogen/top_{topname}.h'
1253 cheader_path = render_template('top_%s.h',
1254 cformat_dir,
1255 helper=c_helper)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001256
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001257 # Save the relative header path into `c_gen_info`
1258 rel_header_path = cheader_path.relative_to(path.parents[1])
1259 c_helper.header_path = str(rel_header_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001260
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001261 # 'top_{topname}.c.tpl' -> 'sw/autogen/top_{topname}.c'
1262 render_template('top_%s.c', cformat_dir, helper=c_helper)
Sam Elliott519f7462020-05-11 16:53:24 +01001263
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001264 # 'top_{topname}_memory.ld.tpl' -> 'sw/autogen/top_{topname}_memory.ld'
1265 render_template('top_%s_memory.ld', cformat_dir)
Sam Elliottf7cb5f42020-07-27 21:29:26 +01001266
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001267 # 'top_{topname}_memory.h.tpl' -> 'sw/autogen/top_{topname}_memory.h'
1268 memory_cheader_path = render_template('top_%s_memory.h', cformat_dir)
1269
Pirmin Vogel2f42ccd2020-12-22 20:19:30 +01001270 try:
1271 cheader_path.relative_to(SRCTREE_TOP)
1272 except ValueError:
1273 log.error("cheader_path %s is not within SRCTREE_TOP %s",
1274 cheader_path, SRCTREE_TOP)
1275 log.error("Thus skipping util/fix_include_guard.py")
1276 continue
1277
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001278 # Fix the C header guards, which will have the wrong name
1279 subprocess.run(["util/fix_include_guard.py",
1280 str(cheader_path),
1281 str(memory_cheader_path)],
1282 universal_newlines=True,
1283 stdout=subprocess.DEVNULL,
1284 stderr=subprocess.DEVNULL,
1285 check=True,
1286 cwd=str(SRCTREE_TOP)) # yapf: disable
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001287
Cindy Chene1184aa2020-09-01 11:45:07 -07001288 # generate chip level xbar and alert_handler TB
Weicai Yanga6670362020-11-24 17:19:52 -08001289 tb_files = [
1290 "xbar_env_pkg__params.sv", "tb__xbar_connect.sv",
1291 "tb__alert_handler_connect.sv"
1292 ]
Weicai Yang1777ebb2020-05-19 17:32:24 -07001293 for fname in tb_files:
1294 tpl_fname = "%s.tpl" % (fname)
1295 xbar_chip_data_path = tpl_path / tpl_fname
1296 template_contents = generate_top(completecfg,
1297 str(xbar_chip_data_path))
1298
Pirmin Vogelf80120a2020-11-27 09:55:11 +01001299 rendered_dir = Path(out_path) / 'dv/autogen'
Weicai Yang1777ebb2020-05-19 17:32:24 -07001300 rendered_dir.mkdir(parents=True, exist_ok=True)
1301 rendered_path = rendered_dir / fname
1302
1303 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1304 fout.write(template_contents)
1305
Philipp Wagner44071092021-03-05 19:29:12 +00001306 # generate parameters for chip-level environment package
1307 tpl_fname = 'chip_env_pkg__params.sv.tpl'
Cindy Chene1184aa2020-09-01 11:45:07 -07001308 alert_handler_chip_data_path = tpl_path / tpl_fname
1309 template_contents = generate_top(completecfg,
1310 str(alert_handler_chip_data_path))
1311
Pirmin Vogelf80120a2020-11-27 09:55:11 +01001312 rendered_dir = Path(out_path) / 'dv/env/autogen'
Cindy Chene1184aa2020-09-01 11:45:07 -07001313 rendered_dir.mkdir(parents=True, exist_ok=True)
Philipp Wagner44071092021-03-05 19:29:12 +00001314 rendered_path = rendered_dir / 'chip_env_pkg__params.sv'
Cindy Chene1184aa2020-09-01 11:45:07 -07001315
1316 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1317 fout.write(template_contents)
1318
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001319
lowRISC Contributors802543a2019-08-31 12:12:56 +01001320if __name__ == "__main__":
1321 main()