blob: 5d1d81092af97f486d3adc9450bfae98b13e517f [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
Srikrishna Iyer689981e2021-09-16 12:12:37 -070010import shutil
Sam Elliott37d4fbe2020-04-22 14:05:49 +010011import subprocess
Michael Schaffner60157962020-05-01 19:11:28 -070012import sys
Philipp Wagnerf9ee7972021-10-28 16:21:02 +010013import tempfile
Weicai Yanga60ae7d2020-02-21 14:32:50 -080014from collections import OrderedDict
Weicai Yanga6670362020-11-24 17:19:52 -080015from copy import deepcopy
lowRISC Contributors802543a2019-08-31 12:12:56 +010016from io import StringIO
17from pathlib import Path
Cindy Chenc8389ed2021-11-04 10:53:07 -070018from typing import Dict, List, Optional, Tuple
lowRISC Contributors802543a2019-08-31 12:12:56 +010019
20import hjson
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -080021import tlgen
Philipp Wagner270e28b2021-03-16 20:23:04 +000022from ipgen import (IpBlockRenderer, IpConfig, IpDescriptionOnlyRenderer,
23 IpTemplate, TemplateRenderError)
Eunchan Kimcb28a172019-10-08 16:35:48 -070024from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080025from mako.template import Template
Rupert Swarbrick10184102021-03-31 09:12:42 +010026from reggen import access, gen_rtl, window
Rupert Swarbrickb6500262021-02-23 15:16:16 +000027from reggen.inter_signal import InterSignal
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +000028from reggen.ip_block import IpBlock
Rupert Swarbrickb6500262021-02-23 15:16:16 +000029from reggen.lib import check_list
Rupert Swarbrick5aa249f2021-07-19 18:35:11 +010030from topgen import get_hjsonobj_xbars
Eunchan Kim2c813b42020-08-03 16:22:56 -070031from topgen import intermodule as im
Timothy Chen94432212021-03-01 22:29:18 -080032from topgen import lib as lib
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +000033from topgen import merge_top, search_ips, validate_top
Srikrishna Iyer689981e2021-09-16 12:12:37 -070034from topgen.c_test import TopGenCTest
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -080035from topgen.clocks import Clocks
Rupert Swarbrick10184102021-03-31 09:12:42 +010036from topgen.gen_dv import gen_dv
Michael Schaffner426ed202021-08-02 17:44:42 -070037from topgen.gen_top_docs import gen_top_docs
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -080038from topgen.merge import connect_clocks, create_alert_lpgs, extract_clocks
Timothy Chen63c66062021-07-24 00:25:22 -070039from topgen.resets import Resets
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -080040from topgen.top import Top
lowRISC Contributors802543a2019-08-31 12:12:56 +010041
42# Common header for generated files
Michael Schaffner7b0807d2020-10-27 19:54:52 -070043warnhdr = '''//
lowRISC Contributors802543a2019-08-31 12:12:56 +010044// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
45// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
46'''
Michael Schaffner7b0807d2020-10-27 19:54:52 -070047genhdr = '''// Copyright lowRISC contributors.
48// Licensed under the Apache License, Version 2.0, see LICENSE for details.
49// SPDX-License-Identifier: Apache-2.0
50''' + warnhdr
lowRISC Contributors802543a2019-08-31 12:12:56 +010051
Srikrishna Iyer689981e2021-09-16 12:12:37 -070052GENCMD = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson\n"
53 "// -o hw/top_{topname}")
54
Philipp Wagnerea3cd4c2020-05-07 17:28:18 +010055SRCTREE_TOP = Path(__file__).parent.parent.resolve()
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070056
Philipp Wagnerfb443ab2021-03-05 11:10:28 +000057TOPGEN_TEMPLATE_PATH = Path(__file__).parent / 'topgen/templates'
58
Philipp Wagner270e28b2021-03-16 20:23:04 +000059
60def ipgen_render(template_name: str, topname: str, params: Dict,
61 out_path: Path):
62 """ Render an IP template for a specific toplevel using ipgen.
63
64 The generated IP block is placed in the 'ip_autogen' directory of the
65 toplevel.
66
67 Aborts the program execution in case of an error.
68 """
69 instance_name = f'top_{topname}_{template_name}'
70 ip_template = IpTemplate.from_template_path(
71 SRCTREE_TOP / 'hw/ip_templates' / template_name)
72
73 try:
74 ip_config = IpConfig(ip_template.params, instance_name, params)
75 except ValueError as e:
76 log.error(f"Unable to render IP template {template_name!r}: {str(e)}")
77 sys.exit(1)
78
79 try:
80 renderer = IpBlockRenderer(ip_template, ip_config)
81 renderer.render(out_path / 'ip_autogen' / template_name,
82 overwrite_output_dir=True)
83 except TemplateRenderError as e:
84 log.error(e.verbose_str())
85 sys.exit(1)
86
Eunchan Kimfd561be2020-04-24 15:42:11 -070087
Rupert Swarbrickeb619e62021-03-05 15:01:54 +000088def generate_top(top, name_to_block, tpl_filename, **kwargs):
Sam Elliott7e36bd72020-04-22 14:05:49 +010089 top_tpl = Template(filename=tpl_filename)
lowRISC Contributors802543a2019-08-31 12:12:56 +010090
Eunchan Kimcb28a172019-10-08 16:35:48 -070091 try:
Rupert Swarbrickeb619e62021-03-05 15:01:54 +000092 return top_tpl.render(top=top, name_to_block=name_to_block, **kwargs)
Eunchan Kim6599ba92020-04-13 15:27:16 -070093 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070094 log.error(exceptions.text_error_template().render())
Sam Elliott7e36bd72020-04-22 14:05:49 +010095 return ""
lowRISC Contributors802543a2019-08-31 12:12:56 +010096
97
98def generate_xbars(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -070099 topname = top["name"]
100 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
101 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -0700102
lowRISC Contributors802543a2019-08-31 12:12:56 +0100103 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -0800104 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
105 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100106 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -0800107 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100108
Eunchan Kim6df9a1f2019-10-09 14:46:05 -0700109 # Generate output of crossbar with complete fields
110 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
111 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -0700112 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -0700113
lowRISC Contributors802543a2019-08-31 12:12:56 +0100114 if not tlgen.elaborate(xbar):
115 log.error("Elaboration failed." + repr(xbar))
116
Eunchan Kimcb28a172019-10-08 16:35:48 -0700117 try:
Eunchan Kim9191f262020-07-30 16:37:40 -0700118 results = tlgen.generate(xbar, "top_" + top["name"])
Eunchan Kim6599ba92020-04-13 15:27:16 -0700119 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700120 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100121
Eunchan Kim9191f262020-07-30 16:37:40 -0700122 ip_path = out_path / 'ip/xbar_{}'.format(obj["name"])
123
124 for filename, filecontent in results:
125 filepath = ip_path / filename
126 filepath.parent.mkdir(parents=True, exist_ok=True)
127 with filepath.open(mode='w', encoding='UTF-8') as fout:
128 fout.write(filecontent)
129
Eunchan Kimc7452942019-12-19 17:04:37 -0800130 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100131 dv_path.mkdir(parents=True, exist_ok=True)
132
Weicai Yange4315d22020-01-09 10:37:42 -0800133 # generate testbench for xbar
Eunchan Kim8f2cb382020-05-13 11:53:09 -0700134 tlgen.generate_tb(xbar, dv_path, "top_" + top["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100135
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700136 # Read back the comportable IP and amend to Xbar
137 xbar_ipfile = ip_path / ("data/autogen/xbar_%s.hjson" % obj["name"])
138 with xbar_ipfile.open() as fxbar:
139 xbar_ipobj = hjson.load(fxbar,
140 use_decimal=True,
141 object_pairs_hook=OrderedDict)
142
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800143 r_inter_signal_list = check_list(
144 xbar_ipobj.get('inter_signal_list', []),
145 'inter_signal_list field')
Rupert Swarbrickb6500262021-02-23 15:16:16 +0000146 obj['inter_signal_list'] = [
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800147 InterSignal.from_raw(
148 'entry {} of the inter_signal_list field'.format(idx + 1),
149 entry) for idx, entry in enumerate(r_inter_signal_list)
Rupert Swarbrickb6500262021-02-23 15:16:16 +0000150 ]
Eunchan Kime0d37fe2020-08-03 12:05:21 -0700151
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800152
Michael Schaffner666dde12019-10-25 11:57:54 -0700153def generate_alert_handler(top, out_path):
Philipp Wagner0d7bd2c2021-03-19 10:33:52 +0000154 topname = top["name"]
155
Michael Schaffner666dde12019-10-25 11:57:54 -0700156 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -0800157 esc_cnt_dw = 32
158 accu_cnt_dw = 16
Michael Schaffner3b511b82021-10-01 11:11:09 -0700159 async_on = []
Michael Schaffner666dde12019-10-25 11:57:54 -0700160 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -0800161 n_classes = 4
Michael Schaffner4fe78462021-09-28 17:06:07 -0700162 # low power groups
Michael Schaffnerf668fff2021-09-20 17:36:16 -0700163 n_lpg = 1
Michael Schaffner3b511b82021-10-01 11:11:09 -0700164 lpg_map = []
Michael Schaffner666dde12019-10-25 11:57:54 -0700165
Michael Schaffner4fe78462021-09-28 17:06:07 -0700166 # Count number of alerts and LPGs
Michael Schaffner666dde12019-10-25 11:57:54 -0700167 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
Michael Schaffner4fe78462021-09-28 17:06:07 -0700168 n_lpg = len(top['alert_lpgs'])
169 n_lpg_width = n_lpg.bit_length()
Michael Schaffner3b511b82021-10-01 11:11:09 -0700170 # format used to print out indices in binary format
171 async_on_format = "1'b{:01b}"
172 lpg_idx_format = str(n_lpg_width) + "'d{:d}"
Michael Schaffner4fe78462021-09-28 17:06:07 -0700173
174 # Double check that all these values are greated than 0
175 if esc_cnt_dw < 1:
176 raise ValueError("esc_cnt_dw must be larger than 0")
177 if accu_cnt_dw < 1:
178 raise ValueError("accu_cnt_dw must be larger than 0")
179 if n_lpg < 1:
180 raise ValueError("n_lpg must be larger than 0")
Michael Schaffner666dde12019-10-25 11:57:54 -0700181
182 if n_alerts < 1:
183 # set number of alerts to 1 such that the config is still valid
184 # that input will be tied off
185 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800186 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700187 else:
Michael Schaffner3b511b82021-10-01 11:11:09 -0700188 async_on = []
189 lpg_map = []
Michael Schaffner666dde12019-10-25 11:57:54 -0700190 for alert in top['alert']:
Timothy Chen322f2542020-08-05 16:28:18 -0700191 for k in range(alert['width']):
Michael Schaffner3b511b82021-10-01 11:11:09 -0700192 async_on.append(async_on_format.format(int(alert['async'])))
193 lpg_map.append(lpg_idx_format.format(int(alert['lpg_idx'])))
Michael Schaffner666dde12019-10-25 11:57:54 -0700194
Philipp Wagner0d7bd2c2021-03-19 10:33:52 +0000195 params = {
196 'n_alerts': n_alerts,
197 'esc_cnt_dw': esc_cnt_dw,
198 'accu_cnt_dw': accu_cnt_dw,
199 'async_on': async_on,
200 'n_classes': n_classes,
201 'n_lpg': n_lpg,
202 'lpg_map': lpg_map,
203 }
Michael Schaffner666dde12019-10-25 11:57:54 -0700204
Philipp Wagner0d7bd2c2021-03-19 10:33:52 +0000205 ipgen_render('alert_handler', topname, params, out_path)
Michael Schaffner666dde12019-10-25 11:57:54 -0700206
207
lowRISC Contributors802543a2019-08-31 12:12:56 +0100208def generate_plic(top, out_path):
Eunchan Kimba970df2020-04-17 10:21:01 -0700209 topname = top["name"]
Philipp Wagnerc720ac82021-03-03 15:34:53 +0000210 params = {}
211
lowRISC Contributors802543a2019-08-31 12:12:56 +0100212 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700213 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
214 # So, total number of interrupts are the number of entries in the list + 1
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800215 params['src'] = sum(
216 [x["width"] if "width" in x else 1 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100217
218 # Target and priority: Currently fixed
Philipp Wagnerc720ac82021-03-03 15:34:53 +0000219 params['target'] = int(top["num_cores"], 0) if "num_cores" in top else 1
220 params['prio'] = 3
lowRISC Contributors802543a2019-08-31 12:12:56 +0100221
Philipp Wagnerc720ac82021-03-03 15:34:53 +0000222 ipgen_render('rv_plic', topname, params, out_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100223
Eunchan Kimba970df2020-04-17 10:21:01 -0700224
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800225def generate_pinmux(top, out_path):
Michael Schaffner60157962020-05-01 19:11:28 -0700226
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700227 topname = top['name']
228 pinmux = top['pinmux']
229
230 # Generation without pinmux and pinout configuration is not supported.
231 assert 'pinmux' in top
232 assert 'pinout' in top
Michael Schaffner57c490d2020-04-29 15:08:55 -0700233
234 # Get number of wakeup detectors
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700235 if 'num_wkup_detect' in pinmux:
236 num_wkup_detect = pinmux['num_wkup_detect']
Michael Schaffner57c490d2020-04-29 15:08:55 -0700237 else:
238 num_wkup_detect = 1
239
240 if num_wkup_detect <= 0:
241 # TODO: add support for no wakeup counter case
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700242 log.error('Topgen does currently not support generation of a top ' +
243 'without DIOs.')
Michael Schaffner57c490d2020-04-29 15:08:55 -0700244 return
245
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700246 if 'wkup_cnt_width' in pinmux:
247 wkup_cnt_width = pinmux['wkup_cnt_width']
Michael Schaffner57c490d2020-04-29 15:08:55 -0700248 else:
249 wkup_cnt_width = 8
250
251 if wkup_cnt_width <= 1:
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700252 log.error('Wakeup counter width must be greater equal 2.')
Eunchan Kim436d2242019-10-29 17:25:51 -0700253 return
254
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700255 # MIO Pads
256 n_mio_pads = pinmux['io_counts']['muxed']['pads']
257
Eunchan Kim436d2242019-10-29 17:25:51 -0700258 # Total inputs/outputs
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700259 # Reuse the counts from the merge phase
260 n_mio_periph_in = (pinmux['io_counts']['muxed']['inouts'] +
261 pinmux['io_counts']['muxed']['inputs'])
262 n_mio_periph_out = (pinmux['io_counts']['muxed']['inouts'] +
263 pinmux['io_counts']['muxed']['outputs'])
264 n_dio_periph_in = (pinmux['io_counts']['dedicated']['inouts'] +
265 pinmux['io_counts']['dedicated']['inputs'])
266 n_dio_periph_out = (pinmux['io_counts']['dedicated']['inouts'] +
267 pinmux['io_counts']['dedicated']['outputs'])
268 n_dio_pads = (pinmux['io_counts']['dedicated']['inouts'] +
269 pinmux['io_counts']['dedicated']['inputs'] +
270 pinmux['io_counts']['dedicated']['outputs'])
Michael Schaffner57c490d2020-04-29 15:08:55 -0700271
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800272 # TODO: derive this value
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700273 attr_dw = 13
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800274
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700275 # Generation with zero MIO/DIO pads is currently not supported.
276 assert (n_mio_pads > 0)
277 assert (n_dio_pads > 0)
Michael Schaffner57c490d2020-04-29 15:08:55 -0700278
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700279 log.info('Generating pinmux with following info from hjson:')
280 log.info('attr_dw: %d' % attr_dw)
281 log.info('num_wkup_detect: %d' % num_wkup_detect)
282 log.info('wkup_cnt_width: %d' % wkup_cnt_width)
283 log.info('n_mio_periph_in: %d' % n_mio_periph_in)
284 log.info('n_mio_periph_out: %d' % n_mio_periph_out)
285 log.info('n_dio_periph_in: %d' % n_dio_periph_in)
286 log.info('n_dio_periph_out: %d' % n_dio_periph_out)
287 log.info('n_dio_pads: %d' % n_dio_pads)
Eunchan Kim436d2242019-10-29 17:25:51 -0700288
289 # Target path
290 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
291 # data: pinmux.hjson
292 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
293 rtl_path.mkdir(parents=True, exist_ok=True)
294 data_path = out_path / 'ip/pinmux/data/autogen'
295 data_path.mkdir(parents=True, exist_ok=True)
296
297 # Template path
Weicai Yang5c02d782020-12-08 12:17:51 -0800298 tpl_path = Path(
299 __file__).resolve().parent / '../hw/ip/pinmux/data/pinmux.hjson.tpl'
Eunchan Kim436d2242019-10-29 17:25:51 -0700300
301 # Generate register package and RTLs
Eunchan Kimba970df2020-04-17 10:21:01 -0700302 gencmd = ("// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson "
303 "-o hw/top_{topname}/\n\n".format(topname=topname))
Eunchan Kim436d2242019-10-29 17:25:51 -0700304
305 hjson_gen_path = data_path / "pinmux.hjson"
306
307 out = StringIO()
308 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
309 hjson_tpl = Template(fin.read())
310 try:
Michael Schaffner60157962020-05-01 19:11:28 -0700311 out = hjson_tpl.render(
312 n_mio_periph_in=n_mio_periph_in,
313 n_mio_periph_out=n_mio_periph_out,
314 n_mio_pads=n_mio_pads,
315 # each DIO has in, out and oe wires
316 # some of these have to be tied off in the
317 # top, depending on the type.
318 n_dio_periph_in=n_dio_pads,
319 n_dio_periph_out=n_dio_pads,
320 n_dio_pads=n_dio_pads,
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800321 attr_dw=attr_dw,
Michael Schaffner60157962020-05-01 19:11:28 -0700322 n_wkup_detect=num_wkup_detect,
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800323 wkup_cnt_width=wkup_cnt_width)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700324 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700325 log.error(exceptions.text_error_template().render())
326 log.info("PINMUX HJSON: %s" % out)
327
328 if out == "":
329 log.error("Cannot generate pinmux HJSON")
330 return
331
332 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
333 fout.write(genhdr + gencmd + out)
334
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000335 gen_rtl.gen_rtl(IpBlock.from_text(out, [], str(hjson_gen_path)),
336 str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700337
Michael Schaffner60157962020-05-01 19:11:28 -0700338
Timothy Chenf56c1b52020-04-28 17:00:43 -0700339def generate_clkmgr(top, cfg_path, out_path):
340
341 # Target paths
342 rtl_path = out_path / 'ip/clkmgr/rtl/autogen'
343 rtl_path.mkdir(parents=True, exist_ok=True)
344 data_path = out_path / 'ip/clkmgr/data/autogen'
345 data_path.mkdir(parents=True, exist_ok=True)
346
347 # Template paths
348 hjson_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.hjson.tpl'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700349 rtl_tpl = cfg_path / '../ip/clkmgr/data/clkmgr.sv.tpl'
350 pkg_tpl = cfg_path / '../ip/clkmgr/data/clkmgr_pkg.sv.tpl'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700351
352 hjson_out = data_path / 'clkmgr.hjson'
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700353 rtl_out = rtl_path / 'clkmgr.sv'
354 pkg_out = rtl_path / 'clkmgr_pkg.sv'
Timothy Chenf56c1b52020-04-28 17:00:43 -0700355
356 tpls = [hjson_tpl, rtl_tpl, pkg_tpl]
357 outputs = [hjson_out, rtl_out, pkg_out]
358 names = ['clkmgr.hjson', 'clkmgr.sv', 'clkmgr_pkg.sv']
359
Rupert Swarbrick127b1092021-07-16 17:10:39 +0100360 clocks = top['clocks']
361 assert isinstance(clocks, Clocks)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700362
Rupert Swarbrick710e3c92021-07-13 15:28:59 +0100363 typed_clocks = clocks.typed_clocks()
364 hint_names = typed_clocks.hint_names()
Rupert Swarbrick56544b02021-06-17 14:20:40 +0100365
Timothy Chenf56c1b52020-04-28 17:00:43 -0700366 for idx, tpl in enumerate(tpls):
Sam Elliott6dd4e4a2020-07-30 18:52:22 +0100367 out = ""
Timothy Chenf56c1b52020-04-28 17:00:43 -0700368 with tpl.open(mode='r', encoding='UTF-8') as fin:
369 tpl = Template(fin.read())
370 try:
371 out = tpl.render(cfg=top,
Rupert Swarbrickab5c1492021-07-19 13:00:37 +0100372 clocks=clocks,
373 typed_clocks=typed_clocks,
Rupert Swarbrick710e3c92021-07-13 15:28:59 +0100374 hint_names=hint_names)
Timothy Chenf56c1b52020-04-28 17:00:43 -0700375 except: # noqa: E722
376 log.error(exceptions.text_error_template().render())
377
378 if out == "":
379 log.error("Cannot generate {}".format(names[idx]))
380 return
381
382 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
383 fout.write(genhdr + out)
384
385 # Generate reg files
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000386 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_out), []), str(rtl_path))
Eunchan Kim436d2242019-10-29 17:25:51 -0700387
Eunchan Kimc75c6c12020-05-12 12:48:34 -0700388
Timothy Chen4ba25312020-06-17 13:08:57 -0700389# generate pwrmgr
390def generate_pwrmgr(top, out_path):
391 log.info("Generating pwrmgr")
392
Timothy Chen6faf4f12020-09-18 18:52:47 -0700393 # Count number of wakeups
Timothy Chen4ba25312020-06-17 13:08:57 -0700394 n_wkups = len(top["wakeups"])
395 log.info("Found {} wakeup signals".format(n_wkups))
396
Timothy Chen6faf4f12020-09-18 18:52:47 -0700397 # Count number of reset requests
398 n_rstreqs = len(top["reset_requests"])
399 log.info("Found {} reset request signals".format(n_rstreqs))
400
Timothy Chen4ba25312020-06-17 13:08:57 -0700401 if n_wkups < 1:
402 n_wkups = 1
Eunchan Kim9191f262020-07-30 16:37:40 -0700403 log.warning(
Michael Schaffner52bce9f2021-07-13 15:08:08 -0700404 "The design has no wakeup sources. Low power not supported.")
405
406 if n_rstreqs < 1:
407 n_rstreqs = 1
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800408 log.warning("The design has no reset request sources. "
409 "Reset requests are not supported.")
Timothy Chen4ba25312020-06-17 13:08:57 -0700410
411 # Define target path
412 rtl_path = out_path / 'ip/pwrmgr/rtl/autogen'
413 rtl_path.mkdir(parents=True, exist_ok=True)
414 doc_path = out_path / 'ip/pwrmgr/data/autogen'
415 doc_path.mkdir(parents=True, exist_ok=True)
416
417 # So, read template files from ip directory.
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100418 tpl_path = Path(__file__).resolve().parent / '../hw/ip/pwrmgr/data'
Timothy Chen4ba25312020-06-17 13:08:57 -0700419 hjson_tpl_path = tpl_path / 'pwrmgr.hjson.tpl'
420
421 # Render and write out hjson
422 out = StringIO()
423 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
424 hjson_tpl = Template(fin.read())
425 try:
Timothy Chenbea7b6a2021-01-21 13:59:20 -0800426 out = hjson_tpl.render(NumWkups=n_wkups,
427 Wkups=top["wakeups"],
428 NumRstReqs=n_rstreqs)
Timothy Chen4ba25312020-06-17 13:08:57 -0700429
430 except: # noqa: E722
431 log.error(exceptions.text_error_template().render())
432 log.info("pwrmgr hjson: %s" % out)
433
434 if out == "":
435 log.error("Cannot generate pwrmgr config file")
436 return
437
438 hjson_path = doc_path / "pwrmgr.hjson"
439 with hjson_path.open(mode='w', encoding='UTF-8') as fout:
440 fout.write(genhdr + out)
441
442 # Generate reg files
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000443 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chen4ba25312020-06-17 13:08:57 -0700444
445
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700446# generate rstmgr
447def generate_rstmgr(topcfg, out_path):
448 log.info("Generating rstmgr")
449
450 # Define target path
451 rtl_path = out_path / 'ip/rstmgr/rtl/autogen'
452 rtl_path.mkdir(parents=True, exist_ok=True)
453 doc_path = out_path / 'ip/rstmgr/data/autogen'
454 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100455 tpl_path = Path(__file__).resolve().parent / '../hw/ip/rstmgr/data'
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700456
457 # Read template files from ip directory.
458 tpls = []
459 outputs = []
460 names = ['rstmgr.hjson', 'rstmgr.sv', 'rstmgr_pkg.sv']
461
462 for x in names:
463 tpls.append(tpl_path / Path(x + ".tpl"))
464 if "hjson" in x:
465 outputs.append(doc_path / Path(x))
466 else:
467 outputs.append(rtl_path / Path(x))
468
469 # Parameters needed for generation
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700470 reset_obj = topcfg['resets']
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700471
Timothy Chen63c66062021-07-24 00:25:22 -0700472 # The original resets dict is transformed to the reset class
473 assert isinstance(reset_obj, Resets)
474
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700475 # unique clocks
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700476 clks = reset_obj.get_clocks()
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700477
478 # resets sent to reset struct
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700479 output_rsts = reset_obj.get_top_resets()
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700480
481 # sw controlled resets
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700482 sw_rsts = reset_obj.get_sw_resets()
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700483
484 # leaf resets
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700485 leaf_rsts = reset_obj.get_generated_resets()
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700486
Timothy Chen6faf4f12020-09-18 18:52:47 -0700487 # Number of reset requests
488 n_rstreqs = len(topcfg["reset_requests"])
489
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700490 # Generate templated files
491 for idx, t in enumerate(tpls):
492 out = StringIO()
493 with t.open(mode='r', encoding='UTF-8') as fin:
494 tpl = Template(fin.read())
495 try:
496 out = tpl.render(clks=clks,
Timothy Chen7f8cc8e2020-11-11 13:15:57 -0800497 power_domains=topcfg['power']['domains'],
Timothy Chen6faf4f12020-09-18 18:52:47 -0700498 num_rstreqs=n_rstreqs,
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700499 sw_rsts=sw_rsts,
500 output_rsts=output_rsts,
Timothy Chen4c8905e2020-08-26 10:34:33 -0700501 leaf_rsts=leaf_rsts,
Timothy Chen7c3de6e2021-07-19 16:46:45 -0700502 export_rsts=topcfg['exported_rsts'],
503 reset_obj=topcfg['resets'])
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700504
505 except: # noqa: E722
506 log.error(exceptions.text_error_template().render())
507
508 if out == "":
509 log.error("Cannot generate {}".format(names[idx]))
510 return
511
512 with outputs[idx].open(mode='w', encoding='UTF-8') as fout:
513 fout.write(genhdr + out)
514
515 # Generate reg files
516 hjson_path = outputs[0]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000517 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chend5b1c0f2020-08-11 14:10:40 -0700518
519
Timothy Chen1daf5822020-10-26 17:28:15 -0700520# generate flash
521def generate_flash(topcfg, out_path):
522 log.info("Generating flash")
523
524 # Define target path
525 rtl_path = out_path / 'ip/flash_ctrl/rtl/autogen'
526 rtl_path.mkdir(parents=True, exist_ok=True)
527 doc_path = out_path / 'ip/flash_ctrl/data/autogen'
528 doc_path.mkdir(parents=True, exist_ok=True)
Pirmin Vogel4ffc3692020-11-25 17:44:47 +0100529 tpl_path = Path(__file__).resolve().parent / '../hw/ip/flash_ctrl/data'
Timothy Chen1daf5822020-10-26 17:28:15 -0700530
531 # Read template files from ip directory.
532 tpls = []
533 outputs = []
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800534 names = [
535 'flash_ctrl.hjson', 'flash_ctrl.sv', 'flash_ctrl_pkg.sv',
536 'flash_ctrl_region_cfg.sv'
537 ]
Timothy Chen1daf5822020-10-26 17:28:15 -0700538
539 for x in names:
540 tpls.append(tpl_path / Path(x + ".tpl"))
541 if "hjson" in x:
542 outputs.append(doc_path / Path(x))
543 else:
544 outputs.append(rtl_path / Path(x))
545
546 # Parameters needed for generation
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800547 flash_mems = [
548 module for module in topcfg['module'] if module['type'] == 'flash_ctrl'
549 ]
Timothy Chen1daf5822020-10-26 17:28:15 -0700550 if len(flash_mems) > 1:
551 log.error("This design does not currently support multiple flashes")
552 return
553
Timothy Chenfb8a7842021-08-20 00:23:47 -0700554 cfg = flash_mems[0]['memory']['mem']['config']
Timothy Chen1daf5822020-10-26 17:28:15 -0700555
556 # Generate templated files
557 for idx, t in enumerate(tpls):
558 out = StringIO()
559 with t.open(mode='r', encoding='UTF-8') as fin:
560 tpl = Template(fin.read())
561 try:
562 out = tpl.render(cfg=cfg)
563
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 hjson_path = outputs[0]
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000576 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []), str(rtl_path))
Timothy Chen1daf5822020-10-26 17:28:15 -0700577
578
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800579def generate_top_only(top_only_dict, out_path, topname, alt_hjson_path):
Timothy Chen322f2542020-08-05 16:28:18 -0700580 log.info("Generating top only modules")
581
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800582 for ip, reggen_only in top_only_dict.items():
583
584 if reggen_only and alt_hjson_path is not None:
585 hjson_dir = Path(alt_hjson_path)
586 else:
587 hjson_dir = Path(__file__).resolve(
588 ).parent / f"../hw/top_{topname}/ip/{ip}/data/"
589
590 hjson_path = hjson_dir / f"{ip}.hjson"
591
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100592 genrtl_dir = out_path / "ip/{}/rtl".format(ip)
593 genrtl_dir.mkdir(parents=True, exist_ok=True)
Timothy Chen322f2542020-08-05 16:28:18 -0700594 log.info("Generating top modules {}, hjson: {}, output: {}".format(
Pirmin Vogelfb8c4472020-11-25 18:08:34 +0100595 ip, hjson_path, genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700596
597 # Generate reg files
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800598 gen_rtl.gen_rtl(IpBlock.from_path(str(hjson_path), []),
599 str(genrtl_dir))
Timothy Chen322f2542020-08-05 16:28:18 -0700600
601
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800602def generate_top_ral(top: Dict[str, object], name_to_block: Dict[str, IpBlock],
603 dv_base_names: List[str], out_path: str):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100604 # construct top ral block
lowRISC Contributors802543a2019-08-31 12:12:56 +0100605
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000606 regwidth = int(top['datawidth'])
607 assert regwidth % 8 == 0
608 addrsep = regwidth // 8
lowRISC Contributors802543a2019-08-31 12:12:56 +0100609
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000610 # Generate a map from instance name to the block that it instantiates,
611 # together with a map of interface addresses.
612 inst_to_block = {} # type: Dict[str, str]
613 if_addrs = {} # type: Dict[Tuple[str, Optional[str]], int],
Timothy Chen62dabf72021-03-24 12:09:27 -0700614 attrs = {} # type: Dict[str, str]
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000615
616 for module in top['module']:
617 inst_name = module['name']
618 block_name = module['type']
619 block = name_to_block[block_name]
Weicai Yangcf02fd22021-03-22 20:49:45 -0700620 if "attr" in module:
Timothy Chen65ff5102022-01-20 18:42:09 -0800621 if module["attr"] not in ['templated', 'ipgen', 'reggen_top',
622 'reggen_only']:
Michael Schaffner74c4ff22021-03-30 15:43:46 -0700623 raise ValueError('Unsupported value for attr field of {}: {!r}'
624 .format(inst_name, module["attr"]))
Weicai Yangcf02fd22021-03-22 20:49:45 -0700625 attrs[inst_name] = module["attr"]
Rupert Swarbrick200d8b42021-03-08 12:32:11 +0000626
627 inst_to_block[inst_name] = block_name
628 for if_name in block.reg_blocks.keys():
629 if_addr = int(module["base_addrs"][if_name], 0)
630 if_addrs[(inst_name, if_name)] = if_addr
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000631
Rupert Swarbrick269bb3d2021-02-23 15:41:56 +0000632 # Collect up the memories to add
Rupert Swarbrick1db6fcd2021-02-11 14:56:20 +0000633 mems = []
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000634 for item in list(top.get("memory", [])):
Weicai Yang7d2e9942021-07-27 23:16:24 -0700635 mems.append(create_mem(item, addrsep, regwidth))
Rupert Swarbrickbc2bc582021-02-09 13:30:37 +0000636
Weicai Yang7d2e9942021-07-27 23:16:24 -0700637 # Top-level may override the mem setting. Store the new type to name_to_block
638 # If no other instance uses the orignal type, delete it
639 original_types = set()
640 for module in top['module']:
641 if 'memory' in module.keys() and len(module['memory']) > 0:
642 newtype = '{}_{}'.format(module['type'], module['name'])
643 assert newtype not in name_to_block
644
645 block = deepcopy(name_to_block[module['type']])
646 name_to_block[newtype] = block
647 inst_to_block[module['name']] = newtype
648
649 original_types.add(module['type'])
650
651 for mem_name, item in module['memory'].items():
652 assert block.reg_blocks[mem_name]
653 assert len(block.reg_blocks[mem_name].windows) <= 1
654 item['name'] = mem_name
655
656 win = create_mem(item, addrsep, regwidth)
657 if len(block.reg_blocks[mem_name].windows) > 0:
658 blk_win = block.reg_blocks[mem_name].windows[0]
659
660 # Top can only add new info for mem, shouldn't overwrite
661 # existing configuration
662 assert win.items == blk_win.items
663 assert win.byte_write == blk_win.byte_write
664 assert win.data_intg_passthru == blk_win.data_intg_passthru
665
666 block.reg_blocks[mem_name].windows[0] = win
667 else:
668 block.reg_blocks[mem_name].windows.append(win)
669
670 for t in original_types:
671 if t not in inst_to_block.values():
672 del name_to_block[t]
lowRISC Contributors802543a2019-08-31 12:12:56 +0100673
Weicai Yangcf02fd22021-03-22 20:49:45 -0700674 chip = Top(regwidth, name_to_block, inst_to_block, if_addrs, mems, attrs)
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700675
lowRISC Contributors802543a2019-08-31 12:12:56 +0100676 # generate the top ral model with template
Cindy Chene16009b2021-11-01 19:35:51 -0700677 return gen_dv(chip, dv_base_names, str(out_path))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100678
679
Weicai Yang7d2e9942021-07-27 23:16:24 -0700680def create_mem(item, addrsep, regwidth):
681 byte_write = ('byte_write' in item and
682 item["byte_write"].lower() == "true")
683 data_intg_passthru = ('data_intg_passthru' in item and
684 item["data_intg_passthru"].lower() == "true")
685 size_in_bytes = int(item['size'], 0)
686 num_regs = size_in_bytes // addrsep
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800687 swaccess = access.SWAccess('top-level memory', item.get('swaccess', 'rw'))
Weicai Yang7d2e9942021-07-27 23:16:24 -0700688
689 return window.Window(name=item['name'],
690 desc='(generated from top-level)',
691 unusual=False,
692 byte_write=byte_write,
693 data_intg_passthru=data_intg_passthru,
694 validbits=regwidth,
695 items=num_regs,
696 size_in_bytes=size_in_bytes,
697 offset=int(item.get('base_addr', '0'), 0),
698 swaccess=swaccess)
699
700
Timothy Chen315b1212021-01-22 11:08:03 -0800701def _process_top(topcfg, args, cfg_path, out_path, pass_idx):
702 # Create generated list
703 # These modules are generated through topgen
Timothy Chen65ff5102022-01-20 18:42:09 -0800704 templated_list = lib.get_templated_modules(topcfg)
705 log.info("Templated list is {}".format(templated_list))
706
707 ipgen_list = lib.get_ipgen_modules(topcfg)
708 log.info("Ip gen list is {}".format(ipgen_list))
709
710 generated_list = templated_list + ipgen_list
Timothy Chen315b1212021-01-22 11:08:03 -0800711
712 # These modules are NOT generated but belong to a specific top
713 # and therefore not part of "hw/ip"
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800714 top_only_dict = {
715 module['type']: lib.is_reggen_only(module)
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800716 for module in topcfg['module'] if lib.is_top_reggen(module)
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800717 }
718 log.info("Filtered dict is {}".format(top_only_dict))
Timothy Chen315b1212021-01-22 11:08:03 -0800719
720 topname = topcfg["name"]
721
722 # Sweep the IP directory and gather the config files
723 ip_dir = Path(__file__).parents[1] / 'hw/ip'
724 ips = search_ips(ip_dir)
725
726 # exclude filtered IPs (to use top_${topname} one) and
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800727 exclude_list = generated_list + list(top_only_dict.keys())
Timothy Chen315b1212021-01-22 11:08:03 -0800728 ips = [x for x in ips if not x.parents[1].name in exclude_list]
729
730 # Hack alert
731 # Generate clkmgr.hjson here so that it can be included below
732 # Unlike other generated hjsons, clkmgr thankfully does not require
733 # ip.hjson information. All the information is embedded within
734 # the top hjson file
Rupert Swarbrick5aa249f2021-07-19 18:35:11 +0100735 topcfg['clocks'] = Clocks(topcfg['clocks'])
736 extract_clocks(topcfg)
Timothy Chen315b1212021-01-22 11:08:03 -0800737 generate_clkmgr(topcfg, cfg_path, out_path)
738
739 # 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
744
745 for ip in generated_list:
Timothy Chen744c3c02021-01-20 20:23:22 -0800746 # For modules that are generated prior to gathering, we need to take it from
Timothy Chen5302fff2021-01-22 14:36:54 -0800747 # the output path. For modules not generated before, it may exist in a
Timothy Chen744c3c02021-01-20 20:23:22 -0800748 # pre-defined area already.
Timothy Chen315b1212021-01-22 11:08:03 -0800749 log.info("Appending {}".format(ip))
Timothy Chen65ff5102022-01-20 18:42:09 -0800750 if ip in ipgen_list:
Philipp Wagner270e28b2021-03-16 20:23:04 +0000751 ip_relpath = 'ip_autogen'
752 desc_file_relpath = 'data'
Timothy Chen315b1212021-01-22 11:08:03 -0800753 else:
Philipp Wagner270e28b2021-03-16 20:23:04 +0000754 ip_relpath = 'ip'
755 desc_file_relpath = 'data/autogen'
756
757 if ip == 'clkmgr' or (pass_idx > 0):
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800758 ip_hjson = (Path(out_path) / ip_relpath / ip / desc_file_relpath /
759 f"{ip}.hjson")
Philipp Wagner270e28b2021-03-16 20:23:04 +0000760 else:
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800761 ip_hjson = (hjson_dir.parent / ip_relpath / ip /
762 desc_file_relpath / f"{ip}.hjson")
Timothy Chen315b1212021-01-22 11:08:03 -0800763 ips.append(ip_hjson)
764
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800765 for ip, reggen_only in top_only_dict.items():
Timothy Chen315b1212021-01-22 11:08:03 -0800766 log.info("Appending {}".format(ip))
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800767
768 if reggen_only and args.hjson_path:
769 ip_hjson = Path(args.hjson_path) / f"{ip}.hjson"
770 else:
771 ip_hjson = hjson_dir.parent / f"ip/{ip}/data/{ip}.hjson"
772
Timothy Chen315b1212021-01-22 11:08:03 -0800773 ips.append(ip_hjson)
774
775 # load Hjson and pass validate from reggen
776 try:
777 ip_objs = []
Philipp Wagner270e28b2021-03-16 20:23:04 +0000778 for ip_desc_file in ips:
779 ip_name = ip_desc_file.stem
Timothy Chen315b1212021-01-22 11:08:03 -0800780 # Skip if it is not in the module list
Philipp Wagner270e28b2021-03-16 20:23:04 +0000781 if ip_name not in [ip["type"] for ip in topcfg["module"]]:
Timothy Chen315b1212021-01-22 11:08:03 -0800782 log.info("Skip module %s as it isn't in the top module list" %
Philipp Wagner270e28b2021-03-16 20:23:04 +0000783 ip_name)
Timothy Chen315b1212021-01-22 11:08:03 -0800784 continue
785
786 # The auto-generated hjson might not yet exist. It will be created
787 # later, see generate_{ip_name}() calls below. For the initial
Philipp Wagner270e28b2021-03-16 20:23:04 +0000788 # validation, use the Hjson file with default values.
789 # TODO: All of this is a rather ugly hack that we need to get rid
790 # of as soon as we don't arbitrarily template IP description Hjson
791 # files any more.
792 if ip_name in generated_list and not ip_desc_file.is_file():
Timothy Chen65ff5102022-01-20 18:42:09 -0800793 if ip_name in ipgen_list:
Philipp Wagner270e28b2021-03-16 20:23:04 +0000794 log.info(
795 "To-be-auto-generated Hjson %s does not yet exist. "
796 "Falling back to the default configuration of template "
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800797 "%s for initial validation." % (ip_desc_file, ip_name))
Timothy Chen315b1212021-01-22 11:08:03 -0800798
Philipp Wagner270e28b2021-03-16 20:23:04 +0000799 tpl_path = SRCTREE_TOP / 'hw/ip_templates' / ip_name
800 ip_template = IpTemplate.from_template_path(tpl_path)
801 ip_config = IpConfig(ip_template.params,
802 f'top_{topname}_{ip_name}')
803
Philipp Wagner092b7552021-10-27 21:34:09 +0100804 try:
805 ip_desc = IpDescriptionOnlyRenderer(
806 ip_template, ip_config).render()
807 except TemplateRenderError as e:
808 log.error(e.verbose_str())
809 sys.exit(1)
Philipp Wagner270e28b2021-03-16 20:23:04 +0000810 s = 'default description of IP template {}'.format(ip_name)
811 ip_objs.append(IpBlock.from_text(ip_desc, [], s))
812 else:
813 # TODO: Remove this block as soon as all IP templates use
814 # ipgen.
815 template_hjson_file = ip_dir / "{}/data/{}.hjson".format(
816 ip_name, ip_name)
817 log.info(
818 "To-be-auto-generated Hjson %s does not yet exist. "
819 "Falling back to Hjson description file %s shipped "
820 "with the IP template for initial validation." %
821 (ip_desc_file, template_hjson_file))
822
823 ip_objs.append(
824 IpBlock.from_path(str(template_hjson_file), []))
825 else:
826 ip_objs.append(IpBlock.from_path(str(ip_desc_file), []))
Timothy Chen315b1212021-01-22 11:08:03 -0800827
828 except ValueError:
829 raise SystemExit(sys.exc_info()[1])
830
Rupert Swarbrick5aa249f2021-07-19 18:35:11 +0100831 name_to_block = {} # type: Dict[str, IpBlock]
832 for block in ip_objs:
833 lblock = block.name.lower()
834 assert lblock not in name_to_block
835 name_to_block[lblock] = block
836
837 connect_clocks(topcfg, name_to_block)
838
Timothy Chen315b1212021-01-22 11:08:03 -0800839 # Read the crossbars under the top directory
840 xbar_objs = get_hjsonobj_xbars(hjson_dir)
841
842 log.info("Detected crossbars: %s" %
843 (", ".join([x["name"] for x in xbar_objs])))
844
845 # If specified, override the seed for random netlist constant computation.
846 if args.rnd_cnst_seed:
847 log.warning('Commandline override of rnd_cnst_seed with {}.'.format(
848 args.rnd_cnst_seed))
849 topcfg['rnd_cnst_seed'] = args.rnd_cnst_seed
850 # Otherwise, we either take it from the top_{topname}.hjson if present, or
851 # randomly generate a new seed if not.
852 else:
853 random.seed()
854 new_seed = random.getrandbits(64)
855 if topcfg.setdefault('rnd_cnst_seed', new_seed) == new_seed:
856 log.warning(
857 'No rnd_cnst_seed specified, setting to {}.'.format(new_seed))
858
859 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
860 if error != 0:
861 raise SystemExit("Error occured while validating top.hjson")
862
Rupert Swarbrickeb619e62021-03-05 15:01:54 +0000863 completecfg = merge_top(topcfg, name_to_block, xbar_objs)
Timothy Chen315b1212021-01-22 11:08:03 -0800864
Timothy Chen744c3c02021-01-20 20:23:22 -0800865 # Generate flash controller and flash memory
866 generate_flash(topcfg, out_path)
867
Timothy Chen315b1212021-01-22 11:08:03 -0800868 # Generate PLIC
869 if not args.no_plic and \
870 not args.alert_handler_only and \
871 not args.xbar_only:
872 generate_plic(completecfg, out_path)
873 if args.plic_only:
874 sys.exit()
875
Michael Schaffner4fe78462021-09-28 17:06:07 -0700876 # Create Alert Handler LPGs before
877 # generating the Alert Handler
878 create_alert_lpgs(topcfg, name_to_block)
879
Timothy Chen315b1212021-01-22 11:08:03 -0800880 # Generate Alert Handler
881 if not args.xbar_only:
882 generate_alert_handler(completecfg, out_path)
883 if args.alert_handler_only:
884 sys.exit()
885
886 # Generate Pinmux
Michael Schaffner43ce8d52021-02-10 17:04:57 -0800887 generate_pinmux(completecfg, out_path)
Timothy Chen315b1212021-01-22 11:08:03 -0800888
889 # Generate Pwrmgr
890 generate_pwrmgr(completecfg, out_path)
891
892 # Generate rstmgr
893 generate_rstmgr(completecfg, out_path)
894
Timothy Chen315b1212021-01-22 11:08:03 -0800895 # Generate top only modules
896 # These modules are not templated, but are not in hw/ip
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800897 generate_top_only(top_only_dict, out_path, topname, args.hjson_path)
Timothy Chen315b1212021-01-22 11:08:03 -0800898
Rupert Swarbrickeb619e62021-03-05 15:01:54 +0000899 return completecfg, name_to_block
Timothy Chen315b1212021-01-22 11:08:03 -0800900
901
lowRISC Contributors802543a2019-08-31 12:12:56 +0100902def main():
903 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700904 parser.add_argument('--topcfg',
905 '-t',
906 required=True,
907 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700908 parser.add_argument(
lowRISC Contributors802543a2019-08-31 12:12:56 +0100909 '--outdir',
910 '-o',
911 help='''Target TOP directory.
912 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700913 ''') # yapf: disable
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800914 parser.add_argument(
Srikrishna Iyer934ef172021-11-20 21:07:17 -0800915 '--hjson-path',
Timothy Chen4c0e61f2021-11-11 14:32:53 -0800916 help='''
917 If defined, topgen uses supplied path to search for ip hjson.
918 This applies only to ip's with the `reggen_only` attribute.
919 If an hjson is located both in the conventional path and the alternate
920 path, the alternate path has priority.
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800921 ''')
lowRISC Contributors802543a2019-08-31 12:12:56 +0100922 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
923
924 # Generator options: 'no' series. cannot combined with 'only' series
925 parser.add_argument(
926 '--no-top',
927 action='store_true',
928 help="If defined, topgen doesn't generate top_{name} RTLs.")
929 parser.add_argument(
930 '--no-xbar',
931 action='store_true',
932 help="If defined, topgen doesn't generate crossbar RTLs.")
933 parser.add_argument(
934 '--no-plic',
935 action='store_true',
936 help="If defined, topgen doesn't generate the interrup controller RTLs."
937 )
lowRISC Contributors802543a2019-08-31 12:12:56 +0100938
939 # Generator options: 'only' series. cannot combined with 'no' series
940 parser.add_argument(
941 '--top-only',
942 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700943 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100944 parser.add_argument(
945 '--xbar-only',
946 action='store_true',
947 help="If defined, the tool generates crossbar RTLs only")
948 parser.add_argument(
949 '--plic-only',
950 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000951 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100952 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700953 '--alert-handler-only',
954 action='store_true',
955 help="If defined, the tool generates alert handler hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100956 # Generator options: generate dv ral model
957 parser.add_argument(
958 '--top_ral',
959 '-r',
960 default=False,
961 action='store_true',
962 help="If set, the tool generates top level RAL model for DV")
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800963 parser.add_argument(
964 '--dv-base-names',
965 nargs="+",
966 help='Names or prefix for the DV register classes from which '
967 'the register models are derived.')
Michael Schaffner7b0807d2020-10-27 19:54:52 -0700968 # Generator options for compile time random netlist constants
Weicai Yanga6670362020-11-24 17:19:52 -0800969 parser.add_argument(
970 '--rnd_cnst_seed',
971 type=int,
972 metavar='<seed>',
973 help='Custom seed for RNG to compute netlist constants.')
Srikrishna Iyere42c8f62021-08-20 01:06:40 -0700974 # Miscellaneous: only return the list of blocks and exit.
975 parser.add_argument('--get_blocks',
976 default=False,
977 action='store_true',
978 help="Only return the list of blocks and exit.")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100979
980 args = parser.parse_args()
981
982 # check combinations
983 if args.top_ral:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100984 args.no_top = True
985
lowRISC Contributors802543a2019-08-31 12:12:56 +0100986 if (args.no_top or args.no_xbar or
987 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -0700988 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100989 log.error(
990 "'no' series options cannot be used with 'only' series options")
991 raise SystemExit(sys.exc_info()[1])
992
Srikrishna Iyere42c8f62021-08-20 01:06:40 -0700993 # Don't print warnings when querying the list of blocks.
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -0800994 log_level = (log.ERROR
995 if args.get_blocks else log.DEBUG if args.verbose else None)
Rupert Swarbrick9bfdaab2021-08-27 16:16:04 +0100996
Srikrishna Iyere42c8f62021-08-20 01:06:40 -0700997 log.basicConfig(format="%(levelname)s: %(message)s", level=log_level)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100998
999 if not args.outdir:
1000 outdir = Path(args.topcfg).parent / ".."
1001 log.info("TOP directory not given. Use %s", (outdir))
1002 elif not Path(args.outdir).is_dir():
1003 log.error("'--outdir' should point to writable directory")
1004 raise SystemExit(sys.exc_info()[1])
1005 else:
1006 outdir = Path(args.outdir)
1007
Timothy Chen4c0e61f2021-11-11 14:32:53 -08001008 if args.hjson_path is not None:
Srikrishna Iyer934ef172021-11-20 21:07:17 -08001009 log.info(f"Alternate hjson path is {args.hjson_path}")
Timothy Chen4c0e61f2021-11-11 14:32:53 -08001010
lowRISC Contributors802543a2019-08-31 12:12:56 +01001011 out_path = Path(outdir)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001012 cfg_path = Path(args.topcfg).parents[1]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001013
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001014 try:
1015 with open(args.topcfg, 'r') as ftop:
1016 topcfg = hjson.load(ftop,
1017 use_decimal=True,
1018 object_pairs_hook=OrderedDict)
1019 except ValueError:
1020 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +01001021
Timothy Chen315b1212021-01-22 11:08:03 -08001022 # TODO, long term, the levels of dependency should be automatically determined instead
1023 # of hardcoded. The following are a few examples:
1024 # Example 1: pinmux depends on amending all modules before calculating the correct number of
1025 # pins.
1026 # This would be 1 level of dependency and require 2 passes.
1027 # Example 2: pinmux depends on amending all modules, and pwrmgr depends on pinmux generation to
1028 # know correct number of wakeups. This would be 2 levels of dependency and require 3
1029 # passes.
1030 #
1031 # How does mulit-pass work?
1032 # In example 1, the first pass gathers all modules and merges them. However, the merge process
1033 # uses a stale pinmux. The correct pinmux is then generated using the merged configuration. The
1034 # second pass now merges all the correct modules (including the generated pinmux) and creates
1035 # the final merged config.
1036 #
1037 # In example 2, the first pass gathers all modules and merges them. However, the merge process
1038 # uses a stale pinmux and pwrmgr. The correct pinmux is then generated using the merged
1039 # configuration. However, since pwrmgr is dependent on this new pinmux, it is still generated
1040 # incorrectly. The second pass merge now has an updated pinmux but stale pwrmgr. The correct
1041 # pwrmgr can now be generated. The final pass then merges all the correct modules and creates
1042 # the final configuration.
1043 #
1044 # This fix is related to #2083
1045 process_dependencies = 1
Philipp Wagnerf9ee7972021-10-28 16:21:02 +01001046
1047 # topgen generates IP blocks and associated Hjson configuration in multiple
1048 # steps. After each step, the IP Hjson configuration is read back and then
1049 # combined into the toplevel configuration. To generate the chip-level RAL,
1050 # we need to run the full generation step, but ultimately only care about
1051 # the toplevel configuration (a single Hjson file). Since we don't have a
1052 # better way at the moment dump all output into a temporary directory, and
1053 # delete it after the fact, retaining only the toplevel configuration.
1054 if args.top_ral:
1055 out_path_gen = Path(tempfile.mkdtemp())
1056 else:
1057 out_path_gen = out_path
1058
Timothy Chen315b1212021-01-22 11:08:03 -08001059 for pass_idx in range(process_dependencies + 1):
1060 log.debug("Generation pass {}".format(pass_idx))
1061 if pass_idx < process_dependencies:
1062 cfg_copy = deepcopy(topcfg)
Philipp Wagnerf9ee7972021-10-28 16:21:02 +01001063 _process_top(cfg_copy, args, cfg_path, out_path_gen, pass_idx)
Timothy Chen315b1212021-01-22 11:08:03 -08001064 else:
Philipp Wagnerf9ee7972021-10-28 16:21:02 +01001065 completecfg, name_to_block = _process_top(topcfg, args, cfg_path,
1066 out_path_gen, pass_idx)
Timothy Chenf56c1b52020-04-28 17:00:43 -07001067
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001068 topname = topcfg["name"]
Eunchan Kimba970df2020-04-17 10:21:01 -07001069
Philipp Wagnerf9ee7972021-10-28 16:21:02 +01001070 # Create the chip-level RAL only
1071 if args.top_ral:
1072 # See above: we only need `completeconfig` and `name_to_block`, not all
1073 # the other files (e.g. RTL files) generated through topgen.
1074 shutil.rmtree(out_path_gen, ignore_errors=True)
1075
1076 exit_code = generate_top_ral(completecfg, name_to_block,
Cindy Chene16009b2021-11-01 19:35:51 -07001077 args.dv_base_names, out_path)
Philipp Wagnerf9ee7972021-10-28 16:21:02 +01001078 sys.exit(exit_code)
1079
Srikrishna Iyere42c8f62021-08-20 01:06:40 -07001080 if args.get_blocks:
1081 print("\n".join(name_to_block.keys()))
1082 sys.exit(0)
1083
lowRISC Contributors802543a2019-08-31 12:12:56 +01001084 # Generate xbars
1085 if not args.no_xbar or args.xbar_only:
1086 generate_xbars(completecfg, out_path)
1087
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001088 # All IPs are generated. Connect phase now
Eunchan Kim2c813b42020-08-03 16:22:56 -07001089 # Find {memory, module} <-> {xbar} connections first.
Rupert Swarbricka5e687f2021-03-01 11:51:41 +00001090 im.autoconnect(completecfg, name_to_block)
Eunchan Kim2c813b42020-08-03 16:22:56 -07001091
1092 # Generic Inter-module connection
1093 im.elab_intermodule(completecfg)
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001094
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001095 # Generate top.gen.hjson right before rendering
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001096 genhjson_dir = out_path / "data/autogen"
Pirmin Vogel71bfd9b2020-11-24 17:28:20 +01001097 genhjson_dir.mkdir(parents=True, exist_ok=True)
1098 genhjson_path = genhjson_dir / ("top_%s.gen.hjson" % completecfg["name"])
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001099
1100 # Header for HJSON
1101 gencmd = '''//
1102// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
1103// -o hw/top_{topname}/ \\
1104// --hjson-only \\
1105// --rnd_cnst_seed {seed}
1106'''.format(topname=topname, seed=completecfg['rnd_cnst_seed'])
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001107
Eunchan Kim66f7ae22020-08-03 23:24:53 -07001108 genhjson_path.write_text(genhdr + gencmd +
1109 hjson.dumps(completecfg, for_json=True))
Eunchan Kime0d37fe2020-08-03 12:05:21 -07001110
lowRISC Contributors802543a2019-08-31 12:12:56 +01001111 if not args.no_top or args.top_only:
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -08001112
1113 def render_template(template_path: str, rendered_path: Path,
1114 **other_info):
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001115 template_contents = generate_top(completecfg, name_to_block,
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001116 str(template_path), **other_info)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001117
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001118 rendered_path.parent.mkdir(exist_ok=True, parents=True)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001119 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1120 fout.write(template_contents)
Eunchan Kim436d2242019-10-29 17:25:51 -07001121
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001122 # Header for SV files
1123 gencmd = warnhdr + '''//
1124// util/topgen.py -t hw/top_{topname}/data/top_{topname}.hjson \\
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001125// -o hw/top_{topname}/ \\
1126// --rnd_cnst_seed {seed}
1127'''.format(topname=topname, seed=topcfg['rnd_cnst_seed'])
1128
Sam Elliott7e36bd72020-04-22 14:05:49 +01001129 # SystemVerilog Top:
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001130 # 'toplevel.sv.tpl' -> 'rtl/autogen/top_{topname}.sv'
1131 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.sv.tpl",
1132 out_path / f"rtl/autogen/top_{topname}.sv",
1133 gencmd=gencmd)
Eunchan Kim436d2242019-10-29 17:25:51 -07001134
Michael Schaffner74c4ff22021-03-30 15:43:46 -07001135 # Multiple chip-levels (ASIC, FPGA, Verilator, etc)
1136 for target in topcfg['targets']:
1137 render_template(TOPGEN_TEMPLATE_PATH / "chiplevel.sv.tpl",
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -08001138 out_path /
1139 f"rtl/autogen/chip_{topname}_{target['name']}.sv",
Michael Schaffner74c4ff22021-03-30 15:43:46 -07001140 gencmd=gencmd,
1141 target=target)
1142
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001143 # The C / SV file needs some complex information, so we initialize this
Sam Elliottd1790472020-07-24 23:25:10 +01001144 # object to store it.
Srikrishna Iyer689981e2021-09-16 12:12:37 -07001145 c_helper = TopGenCTest(completecfg, name_to_block)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001146
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001147 # 'toplevel_pkg.sv.tpl' -> 'rtl/autogen/top_{topname}_pkg.sv'
1148 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_pkg.sv.tpl",
1149 out_path / f"rtl/autogen/top_{topname}_pkg.sv",
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001150 helper=c_helper,
Weicai Yanga6670362020-11-24 17:19:52 -08001151 gencmd=gencmd)
Michael Schaffner7b0807d2020-10-27 19:54:52 -07001152
1153 # compile-time random netlist constants
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001154 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_rnd_cnst_pkg.sv.tpl",
Srikrishna Iyeraea37dd2021-11-20 21:11:40 -08001155 out_path /
1156 f"rtl/autogen/top_{topname}_rnd_cnst_pkg.sv",
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001157 gencmd=gencmd)
Srikrishna Iyerd7bed872020-10-14 11:51:10 -07001158
1159 # C Header + C File + Clang-format file
1160
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001161 # Since SW does not use FuseSoC and instead expects those files always
1162 # to be in hw/top_{topname}/sw/autogen, we currently create these files
1163 # twice:
1164 # - Once under out_path/sw/autogen
1165 # - Once under hw/top_{topname}/sw/autogen
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001166 for path in [out_path.resolve(),
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001167 (SRCTREE_TOP / 'hw/top_{}/'.format(topname)).resolve()]:
Sam Elliott2a4448b2020-04-23 11:15:43 +01001168
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001169 # 'clang-format' -> 'sw/autogen/.clang-format'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001170 cformat_tplpath = TOPGEN_TEMPLATE_PATH / 'clang-format'
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001171 cformat_dir = path / 'sw/autogen'
1172 cformat_dir.mkdir(parents=True, exist_ok=True)
1173 cformat_path = cformat_dir / '.clang-format'
1174 cformat_path.write_text(cformat_tplpath.read_text())
Sam Elliott7e36bd72020-04-22 14:05:49 +01001175
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001176 # 'top_{topname}.h.tpl' -> 'sw/autogen/top_{topname}.h'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001177 cheader_path = cformat_dir / f"top_{topname}.h"
1178 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.h.tpl",
1179 cheader_path,
1180 helper=c_helper)
Sam Elliott7e36bd72020-04-22 14:05:49 +01001181
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001182 # Save the relative header path into `c_gen_info`
1183 rel_header_path = cheader_path.relative_to(path.parents[1])
1184 c_helper.header_path = str(rel_header_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +01001185
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001186 # 'toplevel.c.tpl' -> 'sw/autogen/top_{topname}.c'
1187 render_template(TOPGEN_TEMPLATE_PATH / "toplevel.c.tpl",
1188 cformat_dir / f"top_{topname}.c",
1189 helper=c_helper)
Sam Elliott519f7462020-05-11 16:53:24 +01001190
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001191 # 'toplevel_memory.ld.tpl' -> 'sw/autogen/top_{topname}_memory.ld'
1192 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_memory.ld.tpl",
1193 cformat_dir / f"top_{topname}_memory.ld")
Sam Elliottf7cb5f42020-07-27 21:29:26 +01001194
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001195 # 'toplevel_memory.h.tpl' -> 'sw/autogen/top_{topname}_memory.h'
1196 memory_cheader_path = cformat_dir / f"top_{topname}_memory.h"
1197 render_template(TOPGEN_TEMPLATE_PATH / "toplevel_memory.h.tpl",
Timothy Chen4ca4a2f2021-03-19 13:51:39 -07001198 memory_cheader_path,
1199 helper=c_helper)
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001200
Pirmin Vogel2f42ccd2020-12-22 20:19:30 +01001201 try:
1202 cheader_path.relative_to(SRCTREE_TOP)
1203 except ValueError:
1204 log.error("cheader_path %s is not within SRCTREE_TOP %s",
1205 cheader_path, SRCTREE_TOP)
1206 log.error("Thus skipping util/fix_include_guard.py")
1207 continue
1208
Pirmin Vogel5c7c19a2020-12-01 13:53:13 +01001209 # Fix the C header guards, which will have the wrong name
1210 subprocess.run(["util/fix_include_guard.py",
1211 str(cheader_path),
1212 str(memory_cheader_path)],
1213 universal_newlines=True,
1214 stdout=subprocess.DEVNULL,
1215 stderr=subprocess.DEVNULL,
1216 check=True,
1217 cwd=str(SRCTREE_TOP)) # yapf: disable
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001218
Cindy Chene1184aa2020-09-01 11:45:07 -07001219 # generate chip level xbar and alert_handler TB
Weicai Yanga6670362020-11-24 17:19:52 -08001220 tb_files = [
1221 "xbar_env_pkg__params.sv", "tb__xbar_connect.sv",
Weicai Yang3a2d0bc2021-08-25 15:41:41 -07001222 "tb__alert_handler_connect.sv", "xbar_tgl_excl.cfg"
Weicai Yanga6670362020-11-24 17:19:52 -08001223 ]
Weicai Yang1777ebb2020-05-19 17:32:24 -07001224 for fname in tb_files:
1225 tpl_fname = "%s.tpl" % (fname)
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001226 xbar_chip_data_path = TOPGEN_TEMPLATE_PATH / tpl_fname
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001227 template_contents = generate_top(completecfg, name_to_block,
Weicai Yang1777ebb2020-05-19 17:32:24 -07001228 str(xbar_chip_data_path))
1229
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001230 rendered_dir = out_path / 'dv/autogen'
Weicai Yang1777ebb2020-05-19 17:32:24 -07001231 rendered_dir.mkdir(parents=True, exist_ok=True)
1232 rendered_path = rendered_dir / fname
1233
1234 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1235 fout.write(template_contents)
1236
Philipp Wagner44071092021-03-05 19:29:12 +00001237 # generate parameters for chip-level environment package
1238 tpl_fname = 'chip_env_pkg__params.sv.tpl'
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001239 alert_handler_chip_data_path = TOPGEN_TEMPLATE_PATH / tpl_fname
Rupert Swarbrickeb619e62021-03-05 15:01:54 +00001240 template_contents = generate_top(completecfg, name_to_block,
Cindy Chene1184aa2020-09-01 11:45:07 -07001241 str(alert_handler_chip_data_path))
1242
Philipp Wagnerfb443ab2021-03-05 11:10:28 +00001243 rendered_dir = out_path / 'dv/env/autogen'
Cindy Chene1184aa2020-09-01 11:45:07 -07001244 rendered_dir.mkdir(parents=True, exist_ok=True)
Philipp Wagner44071092021-03-05 19:29:12 +00001245 rendered_path = rendered_dir / 'chip_env_pkg__params.sv'
Cindy Chene1184aa2020-09-01 11:45:07 -07001246
1247 with rendered_path.open(mode='w', encoding='UTF-8') as fout:
1248 fout.write(template_contents)
1249
Michael Schaffner426ed202021-08-02 17:44:42 -07001250 # generate documentation for toplevel
1251 gen_top_docs(completecfg, c_helper, out_path)
1252
Srikrishna Iyer689981e2021-09-16 12:12:37 -07001253 # Auto-generate tests in 'sw/device/tests/autogen` area.
1254 gencmd = warnhdr + GENCMD.format(topname=topname)
1255 for fname in ["plic_all_irqs_test.c", "meson.build"]:
1256 outfile = SRCTREE_TOP / 'sw/device/tests/autogen' / fname
1257 render_template(TOPGEN_TEMPLATE_PATH / f"{fname}.tpl",
1258 outfile,
1259 helper=c_helper,
1260 gencmd=gencmd)
Srikrishna Iyer689981e2021-09-16 12:12:37 -07001261
Sam Elliott37d4fbe2020-04-22 14:05:49 +01001262
lowRISC Contributors802543a2019-08-31 12:12:56 +01001263if __name__ == "__main__":
1264 main()