blob: 0ead8a4e865dbb22e3f2c5ca2117beaeadcce91e [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
9import sys
Weicai Yanga60ae7d2020-02-21 14:32:50 -080010from collections import OrderedDict
lowRISC Contributors802543a2019-08-31 12:12:56 +010011from io import StringIO
12from pathlib import Path
13
14import hjson
Eunchan Kimcb28a172019-10-08 16:35:48 -070015from mako import exceptions
Weicai Yanga60ae7d2020-02-21 14:32:50 -080016from mako.template import Template
lowRISC Contributors802543a2019-08-31 12:12:56 +010017
18import tlgen
Weicai Yanga60ae7d2020-02-21 14:32:50 -080019from reggen import gen_dv, gen_rtl, validate
lowRISC Contributors802543a2019-08-31 12:12:56 +010020from topgen import get_hjsonobj_xbars, merge_top, search_ips, validate_top
21
22# Filter from IP list but adding generated hjson
Cindy Chenecc70ea2020-04-08 14:17:48 -070023filter_list = ['rv_plic', 'pinmux', 'alert_handler']
lowRISC Contributors802543a2019-08-31 12:12:56 +010024
25# Common header for generated files
26genhdr = '''// Copyright lowRISC contributors.
27// Licensed under the Apache License, Version 2.0, see LICENSE for details.
28// SPDX-License-Identifier: Apache-2.0
29//
30// ------------------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! -------------------//
31// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE FOLLOWING COMMAND:
32'''
33
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -070034
Eunchan Kim436d2242019-10-29 17:25:51 -070035def generate_top(top, tpl_filename):
lowRISC Contributors802543a2019-08-31 12:12:56 +010036 top_rtl_tpl = Template(filename=tpl_filename)
37
Eunchan Kimcb28a172019-10-08 16:35:48 -070038 try:
39 out_rtl = top_rtl_tpl.render(top=top)
Eunchan Kim6599ba92020-04-13 15:27:16 -070040 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070041 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010042 return out_rtl
43
44
45def generate_xbars(top, out_path):
Michael Schaffner7f134962019-11-03 12:44:50 -080046 gencmd = ("// util/topgen.py -t hw/top_earlgrey/data/top_earlgrey.hjson "
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070047 "-o hw/top_earlgrey/\n\n")
48
lowRISC Contributors802543a2019-08-31 12:12:56 +010049 for obj in top["xbar"]:
Eunchan Kimc7452942019-12-19 17:04:37 -080050 xbar_path = out_path / 'ip/xbar_{}/data/autogen'.format(obj["name"])
51 xbar_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +010052 xbar = tlgen.validate(obj)
Weicai Yanga60ae7d2020-02-21 14:32:50 -080053 xbar.ip_path = 'hw/top_' + top["name"] + '/ip/{dut}'
lowRISC Contributors802543a2019-08-31 12:12:56 +010054
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070055 # Generate output of crossbar with complete fields
56 xbar_hjson_path = xbar_path / "xbar_{}.gen.hjson".format(xbar.name)
57 xbar_hjson_path.write_text(genhdr + gencmd +
Eunchan Kim2af98ed2019-10-09 15:33:27 -070058 hjson.dumps(obj, for_json=True))
Eunchan Kim6df9a1f2019-10-09 14:46:05 -070059
lowRISC Contributors802543a2019-08-31 12:12:56 +010060 if not tlgen.elaborate(xbar):
61 log.error("Elaboration failed." + repr(xbar))
62
Eunchan Kimcb28a172019-10-08 16:35:48 -070063 try:
Eunchan Kimc7452942019-12-19 17:04:37 -080064 out_rtl, out_pkg, out_core = tlgen.generate(xbar)
Eunchan Kim6599ba92020-04-13 15:27:16 -070065 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -070066 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +010067
Eunchan Kimc7452942019-12-19 17:04:37 -080068 rtl_path = out_path / 'ip/xbar_{}/rtl/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010069 rtl_path.mkdir(parents=True, exist_ok=True)
Eunchan Kimc7452942019-12-19 17:04:37 -080070 dv_path = out_path / 'ip/xbar_{}/dv/autogen'.format(obj["name"])
lowRISC Contributors802543a2019-08-31 12:12:56 +010071 dv_path.mkdir(parents=True, exist_ok=True)
72
73 rtl_filename = "xbar_%s.sv" % (xbar.name)
74 rtl_filepath = rtl_path / rtl_filename
75 with rtl_filepath.open(mode='w', encoding='UTF-8') as fout:
76 fout.write(out_rtl)
77
78 pkg_filename = "tl_%s_pkg.sv" % (xbar.name)
79 pkg_filepath = rtl_path / pkg_filename
80 with pkg_filepath.open(mode='w', encoding='UTF-8') as fout:
81 fout.write(out_pkg)
82
Eunchan Kimc7452942019-12-19 17:04:37 -080083 core_filename = "xbar_%s.core" % (xbar.name)
84 core_filepath = rtl_path / core_filename
85 with core_filepath.open(mode='w', encoding='UTF-8') as fout:
86 fout.write(out_core)
87
Weicai Yange4315d22020-01-09 10:37:42 -080088 # generate testbench for xbar
89 tlgen.generate_tb(xbar, dv_path)
lowRISC Contributors802543a2019-08-31 12:12:56 +010090
Eunchan Kim6a4b49e2020-02-18 10:33:39 -080091
Michael Schaffner666dde12019-10-25 11:57:54 -070092def generate_alert_handler(top, out_path):
93 # default values
Eunchan Kimc7452942019-12-19 17:04:37 -080094 esc_cnt_dw = 32
95 accu_cnt_dw = 16
96 lfsr_seed = 2**31 - 1
97 async_on = "'0"
Michael Schaffner666dde12019-10-25 11:57:54 -070098 # leave this constant
Eunchan Kimc7452942019-12-19 17:04:37 -080099 n_classes = 4
Michael Schaffner666dde12019-10-25 11:57:54 -0700100
101 # check if there are any params to be passed through reggen and placed into
102 # the generated package
103 ip_list_in_top = [x["name"].lower() for x in top["module"]]
104 ah_idx = ip_list_in_top.index("alert_handler")
105 if 'localparam' in top['module'][ah_idx]:
106 if 'EscCntDw' in top['module'][ah_idx]['localparam']:
107 esc_cnt_dw = int(top['module'][ah_idx]['localparam']['EscCntDw'])
108 if 'AccuCntDw' in top['module'][ah_idx]['localparam']:
109 accu_cnt_dw = int(top['module'][ah_idx]['localparam']['AccuCntDw'])
110 if 'LfsrSeed' in top['module'][ah_idx]['localparam']:
111 lfsr_seed = int(top['module'][ah_idx]['localparam']['LfsrSeed'], 0)
112
113 if esc_cnt_dw < 1:
114 log.error("EscCntDw must be larger than 0")
115 if accu_cnt_dw < 1:
116 log.error("AccuCntDw must be larger than 0")
117 if (lfsr_seed & 0xFFFFFFFF) == 0 or lfsr_seed > 2**32:
118 log.error("LFSR seed out of range or zero")
119
120 # Count number of interrupts
121 n_alerts = sum([x["width"] if "width" in x else 1 for x in top["alert"]])
122
123 if n_alerts < 1:
124 # set number of alerts to 1 such that the config is still valid
125 # that input will be tied off
126 n_alerts = 1
Eunchan Kimc7452942019-12-19 17:04:37 -0800127 log.warning("no alerts are defined in the system")
Michael Schaffner666dde12019-10-25 11:57:54 -0700128 else:
129 async_on = ""
130 for alert in top['alert']:
131 async_on = str(alert['async']) + async_on
132 async_on = ("%d'b" % n_alerts) + async_on
133
134 log.info("alert handler parameterization:")
135 log.info("NAlerts = %d" % n_alerts)
136 log.info("EscCntDw = %d" % esc_cnt_dw)
137 log.info("AccuCntDw = %d" % accu_cnt_dw)
138 log.info("LfsrSeed = %d" % lfsr_seed)
139 log.info("AsyncOn = %s" % async_on)
140
Michael Schaffner666dde12019-10-25 11:57:54 -0700141 # Define target path
142 rtl_path = out_path / 'ip/alert_handler/rtl/autogen'
143 rtl_path.mkdir(parents=True, exist_ok=True)
144 doc_path = out_path / 'ip/alert_handler/data/autogen'
145 doc_path.mkdir(parents=True, exist_ok=True)
146
147 # Generating IP top module script is not generalized yet.
148 # So, topgen reads template files from alert_handler directory directly.
149 tpl_path = out_path / '../ip/alert_handler/data'
150 hjson_tpl_path = tpl_path / 'alert_handler.hjson.tpl'
151
152 # Generate Register Package and RTLs
153 out = StringIO()
154 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
155 hjson_tpl = Template(fin.read())
156 try:
157 out = hjson_tpl.render(n_alerts=n_alerts,
158 esc_cnt_dw=esc_cnt_dw,
159 accu_cnt_dw=accu_cnt_dw,
160 lfsr_seed=lfsr_seed,
161 async_on=async_on,
162 n_classes=n_classes)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700163 except: # noqa: E722
Michael Schaffner666dde12019-10-25 11:57:54 -0700164 log.error(exceptions.text_error_template().render())
165 log.info("alert_handler hjson: %s" % out)
166
167 if out == "":
168 log.error("Cannot generate alert_handler config file")
169 return
170
171 hjson_gen_path = doc_path / "alert_handler.hjson"
172 gencmd = (
173 "// util/topgen.py -t hw/top_earlgrey/doc/top_earlgrey.hjson --alert-handler-only "
174 "-o hw/top_earlgrey/\n\n")
175 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
176 fout.write(genhdr + gencmd + out)
177
178 # Generate register RTLs (currently using shell execute)
179 # TODO: More secure way to gneerate RTL
180 hjson_obj = hjson.loads(out,
181 use_decimal=True,
182 object_pairs_hook=validate.checking_dict)
183 validate.validate(hjson_obj)
184 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
185
186
lowRISC Contributors802543a2019-08-31 12:12:56 +0100187def generate_plic(top, out_path):
188 # Count number of interrupts
Eunchan Kim88a86152020-04-13 16:12:08 -0700189 # Interrupt source 0 is tied to 0 to conform RISC-V PLIC spec.
190 # So, total number of interrupts are the number of entries in the list + 1
191 src = sum([x["width"] if "width" in x else 1
192 for x in top["interrupt"]]) + 1
lowRISC Contributors802543a2019-08-31 12:12:56 +0100193
194 # Target and priority: Currently fixed
195 target = int(top["num_cores"], 0) if "num_cores" in top else 1
196 prio = 3
197
198 # Define target path
199 # rtl: rv_plic.sv & rv_plic_reg_pkg.sv & rv_plic_reg_top.sv
Eunchan Kim436d2242019-10-29 17:25:51 -0700200 # data: rv_plic.hjson
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700201 rtl_path = out_path / 'ip/rv_plic/rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100202 rtl_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner666dde12019-10-25 11:57:54 -0700203 doc_path = out_path / 'ip/rv_plic/data/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100204 doc_path.mkdir(parents=True, exist_ok=True)
Michael Schaffner7f134962019-11-03 12:44:50 -0800205 hjson_path = out_path / 'ip/rv_plic/data/autogen'
206 hjson_path.mkdir(parents=True, exist_ok=True)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100207
208 # Generating IP top module script is not generalized yet.
209 # So, topgen reads template files from rv_plic directory directly.
210 # Next, if the ip top gen tool is placed in util/ we can import the library.
Tobias Wölfel4c5fbec2019-10-23 12:43:17 +0200211 tpl_path = out_path / '../ip/rv_plic/data'
Michael Schaffnerc7039362019-10-22 16:16:06 -0700212 hjson_tpl_path = tpl_path / 'rv_plic.hjson.tpl'
213 rtl_tpl_path = tpl_path / 'rv_plic.sv.tpl'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100214
215 # Generate Register Package and RTLs
216 out = StringIO()
217 with hjson_tpl_path.open(mode='r', encoding='UTF-8') as fin:
218 hjson_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700219 try:
220 out = hjson_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700221 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700222 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100223 log.info("RV_PLIC hjson: %s" % out)
224
225 if out == "":
226 log.error("Cannot generate interrupt controller config file")
227 return
228
Michael Schaffner7f134962019-11-03 12:44:50 -0800229 hjson_gen_path = hjson_path / "rv_plic.hjson"
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700230 gencmd = (
Michael Schaffner7f134962019-11-03 12:44:50 -0800231 "// util/topgen.py -t hw/top_earlgrey/data/top_earlgrey.hjson --plic-only "
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700232 "-o hw/top_earlgrey/\n\n")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100233 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
234 fout.write(genhdr + gencmd + out)
235
236 # Generate register RTLs (currently using shell execute)
237 # TODO: More secure way to gneerate RTL
238 hjson_obj = hjson.loads(out,
239 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800240 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100241 validate.validate(hjson_obj)
242 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
243
244 # Generate RV_PLIC Top Module
245 with rtl_tpl_path.open(mode='r', encoding='UTF-8') as fin:
246 rtl_tpl = Template(fin.read())
Eunchan Kimcb28a172019-10-08 16:35:48 -0700247 try:
248 out = rtl_tpl.render(src=src, target=target, prio=prio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700249 except: # noqa: E722
Eunchan Kimcb28a172019-10-08 16:35:48 -0700250 log.error(exceptions.text_error_template().render())
lowRISC Contributors802543a2019-08-31 12:12:56 +0100251 log.info("RV_PLIC RTL: %s" % out)
252
253 if out == "":
254 log.error("Cannot generate interrupt controller RTL")
255 return
256
257 rtl_gen_path = rtl_path / "rv_plic.sv"
258 with rtl_gen_path.open(mode='w', encoding='UTF-8') as fout:
259 fout.write(genhdr + gencmd + out)
260
261
Eunchan Kim436d2242019-10-29 17:25:51 -0700262def generate_pinmux(top, out_path):
263 # MIO Pads
264 num_mio = top["pinmux"]["num_mio"]
265 if num_mio <= 0:
266 log.warning(
267 "No PINMUX is generated. The top %s has no multiplexed IO ports." %
268 top["name"])
269 return
270
271 # Total inputs/outputs
272 num_inputs = sum(
273 [x["width"] if "width" in x else 1 for x in top["pinmux"]["inputs"]])
274 num_outputs = sum(
275 [x["width"] if "width" in x else 1 for x in top["pinmux"]["outputs"]])
276 num_inouts = sum(
277 [x["width"] if "width" in x else 1 for x in top["pinmux"]["inouts"]])
278
279 n_periph_in = num_inouts + num_inputs
280 n_periph_out = num_inouts + num_outputs
281
282 # Target path
283 # rtl: pinmux_reg_pkg.sv & pinmux_reg_top.sv
284 # data: pinmux.hjson
285 rtl_path = out_path / 'ip/pinmux/rtl/autogen'
286 rtl_path.mkdir(parents=True, exist_ok=True)
287 data_path = out_path / 'ip/pinmux/data/autogen'
288 data_path.mkdir(parents=True, exist_ok=True)
289
290 # Template path
291 tpl_path = out_path / '../ip/pinmux/data/pinmux.hjson.tpl'
292
293 # Generate register package and RTLs
Michael Schaffner7f134962019-11-03 12:44:50 -0800294 gencmd = ("// util/topgen.py -t hw/top_earlgrey/data/top_earlgrey.hjson "
Eunchan Kim436d2242019-10-29 17:25:51 -0700295 "-o hw/top_earlgrey/\n\n")
296
297 hjson_gen_path = data_path / "pinmux.hjson"
298
299 out = StringIO()
300 with tpl_path.open(mode='r', encoding='UTF-8') as fin:
301 hjson_tpl = Template(fin.read())
302 try:
303 out = hjson_tpl.render(n_periph_in=n_periph_in,
304 n_periph_out=n_periph_out,
305 n_mio_pads=num_mio)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700306 except: # noqa: E722
Eunchan Kim436d2242019-10-29 17:25:51 -0700307 log.error(exceptions.text_error_template().render())
308 log.info("PINMUX HJSON: %s" % out)
309
310 if out == "":
311 log.error("Cannot generate pinmux HJSON")
312 return
313
314 with hjson_gen_path.open(mode='w', encoding='UTF-8') as fout:
315 fout.write(genhdr + gencmd + out)
316
317 hjson_obj = hjson.loads(out,
318 use_decimal=True,
319 object_pairs_hook=validate.checking_dict)
320 validate.validate(hjson_obj)
321 gen_rtl.gen_rtl(hjson_obj, str(rtl_path))
322
323
lowRISC Contributors802543a2019-08-31 12:12:56 +0100324def generate_top_ral(top, ip_objs, out_path):
325 # construct top ral block
326 top_block = gen_rtl.Block()
327 top_block.name = "chip"
328 top_block.base_addr = 0
329 top_block.width = int(top["datawidth"])
330
331 # add blocks
332 for ip_obj in ip_objs:
333 top_block.blocks.append(gen_rtl.json_to_reg(ip_obj))
334
335 # add memories
336 if "memory" in top.keys():
337 for item in list(top["memory"]):
338 mem = gen_rtl.Window()
339 mem.name = item["name"]
340 mem.base_addr = int(item["base_addr"], 0)
341 mem.limit_addr = int(item["base_addr"], 0) + int(item["size"], 0)
342 # TODO: need to add mem access info for memories in topcfg
343 mem.dvrights = "RW"
344 mem.n_bits = top_block.width
345 top_block.wins.append(mem)
346
347 # get sub-block base addresses from top cfg
348 for block in top_block.blocks:
349 for module in top["module"]:
350 if block.name == module["name"]:
351 block.base_addr = module["base_addr"]
352 break
Srikrishna Iyer1c0171a2019-10-29 11:59:46 -0700353
354 top_block.blocks.sort(key=lambda block: block.base_addr)
355 top_block.wins.sort(key=lambda win: win.base_addr)
356
lowRISC Contributors802543a2019-08-31 12:12:56 +0100357 # generate the top ral model with template
358 gen_dv.gen_ral(top_block, str(out_path))
359
360
361def main():
362 parser = argparse.ArgumentParser(prog="topgen")
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700363 parser.add_argument('--topcfg',
364 '-t',
365 required=True,
366 help="`top_{name}.hjson` file.")
Eunchan Kim632c6f72019-09-30 11:11:51 -0700367 parser.add_argument(
368 '--tpl',
369 '-c',
370 help=
Michael Schaffnerc7039362019-10-22 16:16:06 -0700371 "The directory having top_{name}_core.sv.tpl and top_{name}.tpl.sv.")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100372 parser.add_argument(
373 '--outdir',
374 '-o',
375 help='''Target TOP directory.
376 Module is created under rtl/. (default: dir(topcfg)/..)
Eunchan Kim6599ba92020-04-13 15:27:16 -0700377 ''') # yapf: disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100378 parser.add_argument('--verbose', '-v', action='store_true', help="Verbose")
379
380 # Generator options: 'no' series. cannot combined with 'only' series
381 parser.add_argument(
382 '--no-top',
383 action='store_true',
384 help="If defined, topgen doesn't generate top_{name} RTLs.")
385 parser.add_argument(
386 '--no-xbar',
387 action='store_true',
388 help="If defined, topgen doesn't generate crossbar RTLs.")
389 parser.add_argument(
390 '--no-plic',
391 action='store_true',
392 help="If defined, topgen doesn't generate the interrup controller RTLs."
393 )
394 parser.add_argument(
395 '--no-gen-hjson',
396 action='store_true',
397 help='''If defined, the tool assumes topcfg as a generated hjson.
398 So it bypasses the validation step and doesn't read ip and
399 xbar configurations
400 ''')
401
402 # Generator options: 'only' series. cannot combined with 'no' series
403 parser.add_argument(
404 '--top-only',
405 action='store_true',
Eunchan Kim6599ba92020-04-13 15:27:16 -0700406 help="If defined, the tool generates top RTL only") # yapf:disable
lowRISC Contributors802543a2019-08-31 12:12:56 +0100407 parser.add_argument(
408 '--xbar-only',
409 action='store_true',
410 help="If defined, the tool generates crossbar RTLs only")
411 parser.add_argument(
412 '--plic-only',
413 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000414 help="If defined, the tool generates RV_PLIC RTL and Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100415 parser.add_argument(
Michael Schaffner666dde12019-10-25 11:57:54 -0700416 '--alert-handler-only',
417 action='store_true',
418 help="If defined, the tool generates alert handler hjson only")
419 parser.add_argument(
lowRISC Contributors802543a2019-08-31 12:12:56 +0100420 '--hjson-only',
421 action='store_true',
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000422 help="If defined, the tool generates complete Hjson only")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100423 # Generator options: generate dv ral model
424 parser.add_argument(
425 '--top_ral',
426 '-r',
427 default=False,
428 action='store_true',
429 help="If set, the tool generates top level RAL model for DV")
430
431 args = parser.parse_args()
432
433 # check combinations
434 if args.top_ral:
435 args.hjson_only = True
436 args.no_top = True
437
438 if args.hjson_only:
439 args.no_gen_hjson = False
440
441 if (args.no_top or args.no_xbar or
442 args.no_plic) and (args.top_only or args.xbar_only or
Michael Schaffner666dde12019-10-25 11:57:54 -0700443 args.plic_only or args.alert_handler_only):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100444 log.error(
445 "'no' series options cannot be used with 'only' series options")
446 raise SystemExit(sys.exc_info()[1])
447
Eunchan Kimc7452942019-12-19 17:04:37 -0800448 if not (args.hjson_only or args.plic_only or args.alert_handler_only or
449 args.tpl):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100450 log.error(
451 "Template file can be omitted only if '--hjson-only' is true")
452 raise SystemExit(sys.exc_info()[1])
453
454 if args.verbose:
455 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
456 else:
457 log.basicConfig(format="%(levelname)s: %(message)s")
458
459 if not args.outdir:
460 outdir = Path(args.topcfg).parent / ".."
461 log.info("TOP directory not given. Use %s", (outdir))
462 elif not Path(args.outdir).is_dir():
463 log.error("'--outdir' should point to writable directory")
464 raise SystemExit(sys.exc_info()[1])
465 else:
466 outdir = Path(args.outdir)
467
468 out_path = Path(outdir)
469
470 if not args.no_gen_hjson or args.hjson_only:
471 # load top configuration
472 try:
473 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800474 topcfg = hjson.load(ftop,
475 use_decimal=True,
476 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100477 except ValueError:
478 raise SystemExit(sys.exc_info()[1])
479
480 # Sweep the IP directory and gather the config files
481 ip_dir = Path(__file__).parents[1] / 'hw/ip'
482 ips = search_ips(ip_dir)
483
484 # exclude rv_plic (to use top_earlgrey one) and
485 ips = [x for x in ips if not x.parents[1].name in filter_list]
486
487 # It may require two passes to check if the module is needed.
488 # TODO: first run of topgen will fail due to the absent of rv_plic.
489 # It needs to run up to amend_interrupt in merge_top function
490 # then creates rv_plic.hjson then run xbar generation.
491 hjson_dir = Path(args.topcfg).parent
Michael Schaffner7f134962019-11-03 12:44:50 -0800492 rv_plic_hjson = hjson_dir.parent / 'ip/rv_plic/data/autogen/rv_plic.hjson'
Eunchan Kima7fac5b2019-10-04 11:56:25 -0700493 ips.append(rv_plic_hjson)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100494
Eunchan Kim436d2242019-10-29 17:25:51 -0700495 pinmux_hjson = hjson_dir.parent / 'ip/pinmux/data/autogen/pinmux.hjson'
496 ips.append(pinmux_hjson)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700497
Cindy Chenecc70ea2020-04-08 14:17:48 -0700498 alert_handler_hjson = hjson_dir.parent / 'ip/alert_handler/data/autogen/alert_handler.hjson'
499 ips.append(alert_handler_hjson)
500
Philipp Wagner14a3fee2019-11-21 10:07:02 +0000501 # load Hjson and pass validate from reggen
lowRISC Contributors802543a2019-08-31 12:12:56 +0100502 try:
503 ip_objs = []
504 for x in ips:
505 # Skip if it is not in the module list
Eunchan Kim6599ba92020-04-13 15:27:16 -0700506 if x.stem not in [ip["type"] for ip in topcfg["module"]]:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100507 log.info(
508 "Skip module %s as it isn't in the top module list" %
509 x.stem)
510 continue
511
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700512 obj = hjson.load(x.open('r'),
513 use_decimal=True,
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800514 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100515 if validate.validate(obj) != 0:
516 log.info("Parsing IP %s configuration failed. Skip" % x)
517 continue
518 ip_objs.append(obj)
519
520 except ValueError:
521 raise SystemExit(sys.exc_info()[1])
522
523 # Read the crossbars under the top directory
524 xbar_objs = get_hjsonobj_xbars(hjson_dir)
525
526 log.info("Detected crossbars: %s" %
527 (", ".join([x["name"] for x in xbar_objs])))
528
Timothy Chen3193b002019-10-04 16:56:05 -0700529 topcfg, error = validate_top(topcfg, ip_objs, xbar_objs)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700530 if error != 0:
531 raise SystemExit("Error occured while validating top.hjson")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100532
lowRISC Contributors802543a2019-08-31 12:12:56 +0100533 completecfg = merge_top(topcfg, ip_objs, xbar_objs)
534
Eunchan Kim1a95dd92019-10-11 11:18:13 -0700535 genhjson_path = hjson_dir / ("autogen/top_%s.gen.hjson" %
536 completecfg["name"])
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700537 gencmd = (
Michael Schaffner7f134962019-11-03 12:44:50 -0800538 "// util/topgen.py -t hw/top_earlgrey/data/top_earlgrey.hjson --hjson-only "
Eunchan Kimc6a6a3b2019-09-12 14:27:43 -0700539 "-o hw/top_earlgrey/\n")
lowRISC Contributors802543a2019-08-31 12:12:56 +0100540
541 if args.top_ral:
542 generate_top_ral(completecfg, ip_objs, out_path)
543 else:
544 genhjson_path.write_text(genhdr + gencmd +
545 hjson.dumps(completecfg, for_json=True))
546
547 if args.hjson_only:
548 log.info("hjson is generated. Exiting...")
549 sys.exit()
550
551 if args.no_gen_hjson:
552 # load top.complete configuration
553 try:
554 with open(args.topcfg, 'r') as ftop:
Eunchan Kim6a4b49e2020-02-18 10:33:39 -0800555 completecfg = hjson.load(ftop,
556 use_decimal=True,
557 object_pairs_hook=OrderedDict)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100558 except ValueError:
559 raise SystemExit(sys.exc_info()[1])
560
561 # Generate PLIC
Eunchan Kim6599ba92020-04-13 15:27:16 -0700562 if not args.no_plic and \
Michael Schaffner666dde12019-10-25 11:57:54 -0700563 not args.alert_handler_only and \
564 not args.xbar_only:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100565 generate_plic(completecfg, out_path)
Michael Schaffner666dde12019-10-25 11:57:54 -0700566 if args.plic_only:
567 sys.exit()
568
569 # Generate Alert Handler
570 if not args.xbar_only:
571 generate_alert_handler(completecfg, out_path)
572 if args.alert_handler_only:
573 sys.exit()
lowRISC Contributors802543a2019-08-31 12:12:56 +0100574
Eunchan Kim436d2242019-10-29 17:25:51 -0700575 generate_pinmux(completecfg, out_path)
576
lowRISC Contributors802543a2019-08-31 12:12:56 +0100577 # Generate xbars
578 if not args.no_xbar or args.xbar_only:
579 generate_xbars(completecfg, out_path)
580
lowRISC Contributors802543a2019-08-31 12:12:56 +0100581 top_name = completecfg["name"]
582
583 if not args.no_top or args.top_only:
Eunchan Kim632c6f72019-09-30 11:11:51 -0700584 tpl_path = Path(args.tpl)
Michael Schaffnerc7039362019-10-22 16:16:06 -0700585 top_tplpath = tpl_path / ("top_%s.sv.tpl" % (top_name))
Eunchan Kim436d2242019-10-29 17:25:51 -0700586 out_top = generate_top(completecfg, str(top_tplpath))
Eunchan Kim632c6f72019-09-30 11:11:51 -0700587
Eunchan Kim1a95dd92019-10-11 11:18:13 -0700588 rtl_path = out_path / 'rtl/autogen'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100589 rtl_path.mkdir(parents=True, exist_ok=True)
Eunchan Kim632c6f72019-09-30 11:11:51 -0700590 top_path = rtl_path / ("top_%s.sv" % top_name)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100591
Eunchan Kim632c6f72019-09-30 11:11:51 -0700592 with top_path.open(mode='w', encoding='UTF-8') as fout:
593 fout.write(out_top)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100594
Eunchan Kim436d2242019-10-29 17:25:51 -0700595 # C header
596 top_tplpath = tpl_path / ("top_%s.h.tpl" % top_name)
597 out_cheader = generate_top(completecfg, str(top_tplpath))
598
599 sw_path = out_path / "sw/autogen"
600 sw_path.mkdir(parents=True, exist_ok=True)
601 cheader_path = sw_path / ("top_%s.h" % top_name)
602
603 with cheader_path.open(mode='w', encoding='UTF-8') as fout:
604 fout.write(out_cheader)
605
lowRISC Contributors802543a2019-08-31 12:12:56 +0100606
607if __name__ == "__main__":
608 main()