blob: 764bbdc1ff534f9ce593a3617fa24e9ae894386e [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"""Command-line tool to validate and convert register hjson
6
7"""
8import argparse
9import logging as log
lowRISC Contributors802543a2019-08-31 12:12:56 +010010import re
11import sys
12from pathlib import PurePath
13
14import hjson
lowRISC Contributors802543a2019-08-31 12:12:56 +010015
16from reggen import (gen_cheader, gen_ctheader, gen_dv, gen_html, gen_json,
Cindy Chen0bad7832019-11-07 11:25:00 -080017 gen_rtl, gen_fpv, gen_selfdoc, validate, version)
lowRISC Contributors802543a2019-08-31 12:12:56 +010018
Philipp Wagner14a3fee2019-11-21 10:07:02 +000019DESC = """regtool, generate register info from Hjson source"""
lowRISC Contributors802543a2019-08-31 12:12:56 +010020
21USAGE = '''
22 regtool [options]
23 regtool [options] <input>
24 regtool (-h | --help)
25 regtool (-V | --version)
26'''
27
28
29def main():
lowRISC Contributors802543a2019-08-31 12:12:56 +010030 verbose = 0
31
32 parser = argparse.ArgumentParser(
33 prog="regtool",
34 formatter_class=argparse.RawDescriptionHelpFormatter,
35 usage=USAGE,
36 description=DESC)
Eunchan Kim6ec3b892019-10-01 15:02:56 -070037 parser.add_argument('input',
38 nargs='?',
39 metavar='file',
40 type=argparse.FileType('r'),
41 default=sys.stdin,
Philipp Wagner14a3fee2019-11-21 10:07:02 +000042 help='input file in Hjson type')
Eunchan Kim6ec3b892019-10-01 15:02:56 -070043 parser.add_argument('-d',
44 action='store_true',
45 help='Output register documentation (html)')
46 parser.add_argument('--cdefines',
47 '-D',
48 action='store_true',
49 help='Output C defines header')
50 parser.add_argument('--ctdefines',
51 '-T',
52 action='store_true',
53 help='Output C defines header (Titan style)')
54 parser.add_argument('--doc',
55 action='store_true',
56 help='Output source file documentation (gfm)')
57 parser.add_argument('-j',
58 action='store_true',
59 help='Output as formatted JSON')
lowRISC Contributors802543a2019-08-31 12:12:56 +010060 parser.add_argument('-c', action='store_true', help='Output as JSON')
Eunchan Kim6ec3b892019-10-01 15:02:56 -070061 parser.add_argument('-r',
62 action='store_true',
63 help='Output as SystemVerilog RTL')
64 parser.add_argument('-s',
65 action='store_true',
66 help='Output as UVM Register class')
Cindy Chen0bad7832019-11-07 11:25:00 -080067 parser.add_argument('-f',
68 action='store_true',
69 help='Output as FPV CSR rw assertion module')
Eunchan Kim0bd75662020-04-24 10:21:18 -070070 parser.add_argument('--outdir',
71 '-t',
72 help='Target directory for generated RTL; '
73 'tool uses ../rtl if blank.')
Eunchan Kim6ec3b892019-10-01 15:02:56 -070074 parser.add_argument('--outfile',
75 '-o',
76 type=argparse.FileType('w'),
77 default=sys.stdout,
78 help='Target filename for json, html, gfm.')
79 parser.add_argument('--verbose',
80 '-v',
81 action='store_true',
82 help='Verbose and run validate twice')
83 parser.add_argument('--param',
84 '-p',
85 type=str,
Eunchan Kim276af5e2019-10-01 17:02:46 -070086 default="",
Eunchan Kim6ec3b892019-10-01 15:02:56 -070087 help='''Change the Parameter values.
88 Only integer value is supported.
89 You can add multiple param arguments.
90
91 Format: ParamA=ValA;ParamB=ValB
92 ''')
93 parser.add_argument('--version',
94 '-V',
95 action='store_true',
96 help='Show version')
97 parser.add_argument('--novalidate',
98 action='store_true',
99 help='Skip validate, just output json')
lowRISC Contributors802543a2019-08-31 12:12:56 +0100100
101 args = parser.parse_args()
102
103 if args.version:
104 version.show_and_exit(__file__, ["Hjson", "Mako"])
105
106 verbose = args.verbose
lowRISC Contributors802543a2019-08-31 12:12:56 +0100107 if (verbose):
108 log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
109 else:
110 log.basicConfig(format="%(levelname)s: %(message)s")
111
Rupert Swarbrick586b93f2020-11-10 16:25:39 +0000112 # Entries are triples of the form (arg, (format, dirspec)).
113 #
114 # arg is the name of the argument that selects the format. format is the
115 # name of the format. dirspec is None if the output is a single file; if
116 # the output needs a directory, it is a default path relative to the source
117 # file (used when --outdir is not given).
118 arg_to_format = [
119 ('j', ('json', None)),
120 ('c', ('compact', None)),
121 ('d', ('html', None)),
122 ('doc', ('doc', None)),
123 ('r', ('rtl', 'rtl')),
124 ('s', ('dv', 'dv')),
125 ('f', ('fpv', 'fpv/vip')),
126 ('cdefines', ('cdh', None)),
127 ('ctdefines', ('cth', None))
128 ]
129 format = None
130 dirspec = None
131 for arg_name, spec in arg_to_format:
132 if getattr(args, arg_name):
133 if format is not None:
134 log.error('Multiple output formats specified on '
135 'command line ({} and {}).'
136 .format(format, spec[0]))
137 sys.exit(1)
138 format, dirspec = spec
139 if format is None:
140 format = 'hjson'
lowRISC Contributors802543a2019-08-31 12:12:56 +0100141
142 infile = args.input
Eunchan Kim6ec3b892019-10-01 15:02:56 -0700143 params = args.param.split(';')
144
Rupert Swarbrick586b93f2020-11-10 16:25:39 +0000145 # Define either outfile or outdir (but not both), depending on the output
146 # format.
147 outfile = None
148 outdir = None
149 if dirspec is None:
150 if args.outdir is not None:
151 log.error('The {} format expects an output file, '
152 'not an output directory.'
153 .format(format))
154 sys.exit(1)
155
156 outfile = args.outfile
lowRISC Contributors802543a2019-08-31 12:12:56 +0100157 else:
Rupert Swarbrick586b93f2020-11-10 16:25:39 +0000158 if args.outfile is not sys.stdout:
159 log.error('The {} format expects an output directory, '
160 'not an output file.'
161 .format(format))
162 sys.exit(1)
163
164 if args.outdir is not None:
165 outdir = args.outdir
166 elif infile is not sys.stdin:
167 outdir = str(PurePath(infile.name).parents[1].joinpath(dirspec))
168 else:
169 # We're using sys.stdin, so can't infer an output directory name
170 log.error('The {} format writes to an output directory, which '
171 'cannot be inferred automatically if the input comes '
172 'from stdin. Use --outdir to specify it manually.'
173 .format(format))
174 sys.exit(1)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100175
176 if format == 'doc':
177 with outfile:
178 gen_selfdoc.document(outfile)
179 exit(0)
180
Rupert Swarbricka9fdc612020-11-10 16:28:58 +0000181 try:
182 srcfull = infile.read()
183 obj = hjson.loads(srcfull,
184 use_decimal=True,
185 object_pairs_hook=validate.checking_dict)
186 except ValueError:
187 raise SystemExit(sys.exc_info()[1])
lowRISC Contributors802543a2019-08-31 12:12:56 +0100188
189 if args.novalidate:
190 with outfile:
191 gen_json.gen_json(obj, outfile, format)
192 outfile.write('\n')
Eunchan Kim6ec3b892019-10-01 15:02:56 -0700193 elif (validate.validate(obj, params=params) == 0):
lowRISC Contributors802543a2019-08-31 12:12:56 +0100194 if (verbose):
195 log.info("Second validate pass (should show added optional keys)")
Eunchan Kim6ec3b892019-10-01 15:02:56 -0700196 validate.validate(obj, params=params)
lowRISC Contributors802543a2019-08-31 12:12:56 +0100197
198 if format == 'rtl':
199 gen_rtl.gen_rtl(obj, outdir)
200 return 0
201 if format == 'dv':
202 gen_dv.gen_dv(obj, outdir)
203 return 0
Cindy Chen0bad7832019-11-07 11:25:00 -0800204 if format == 'fpv':
205 gen_fpv.gen_fpv(obj, outdir)
206 return 0
lowRISC Contributors802543a2019-08-31 12:12:56 +0100207 src_lic = None
208 src_copy = ''
209 found_spdx = None
210 found_lunder = None
211 copy = re.compile(r'.*(copyright.*)|(.*\(c\).*)', re.IGNORECASE)
212 spdx = re.compile(r'.*(SPDX-License-Identifier:.+)')
213 lunder = re.compile(r'.*(Licensed under.+)', re.IGNORECASE)
214 for line in srcfull.splitlines():
215 mat = copy.match(line)
Eunchan Kim0bd75662020-04-24 10:21:18 -0700216 if mat is not None:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100217 src_copy += mat.group(1)
218 mat = spdx.match(line)
Eunchan Kim0bd75662020-04-24 10:21:18 -0700219 if mat is not None:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100220 found_spdx = mat.group(1)
221 mat = lunder.match(line)
Eunchan Kim0bd75662020-04-24 10:21:18 -0700222 if mat is not None:
lowRISC Contributors802543a2019-08-31 12:12:56 +0100223 found_lunder = mat.group(1)
224 if found_lunder:
225 src_lic = found_lunder
226 if found_spdx:
227 src_lic += '\n' + found_spdx
228
229 with outfile:
230 if format == 'html':
231 gen_html.gen_html(obj, outfile)
232 elif format == 'cdh':
233 gen_cheader.gen_cdefines(obj, outfile, src_lic, src_copy)
234 elif format == 'cth':
235 gen_ctheader.gen_cdefines(obj, outfile, src_lic, src_copy)
236 else:
237 gen_json.gen_json(obj, outfile, format)
238
239 outfile.write('\n')
240
241
242if __name__ == '__main__':
243 main()