blob: 66d4ae998e75c655424827b93106db00be009258 [file] [log] [blame]
lowRISC Contributors802543a2019-08-31 12:12:56 +01001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4"""
Philipp Wagner14a3fee2019-11-21 10:07:02 +00005Generate C header from validated register JSON tree
lowRISC Contributors802543a2019-08-31 12:12:56 +01006"""
7
8import io
9import logging as log
10import re
11import sys
Greg Chadwick45859b72019-10-23 13:06:29 +010012import textwrap
lowRISC Contributors802543a2019-08-31 12:12:56 +010013
14
15def genout(outfile, msg):
16 outfile.write(msg)
17
18
19def as_define(s):
20 s = s.upper()
21 r = ''
22 for i in range(0, len(s)):
23 r += s[i] if s[i].isalnum() else '_'
24 return r
25
26
Greg Chadwick45859b72019-10-23 13:06:29 +010027def first_line(s):
28 """Returns the first line of a multi-line string"""
lowRISC Contributors802543a2019-08-31 12:12:56 +010029 return s.splitlines()[0]
30
31
Greg Chadwick45859b72019-10-23 13:06:29 +010032def format_comment(s):
33 """Formats a string to comment wrapped to an 80 character line width
34
35 Returns wrapped string including newline and // comment characters.
36 """
37 return '\n'.join(
38 textwrap.wrap(
39 s, width=77, initial_indent='// ', subsequent_indent='// ')) + '\n'
40
41
42def gen_define(name, args, body, indent=' '):
43 r"""Produces a #define string, will split into two lines if a single line
44 has a width greater than 80 characters. Result includes newline.
45
46 Arguments:
47 name - Name of the #define
48 args - List of arguments for the define, provide an empty list if there are
49 none
50 body - Body of the #define
51 indent - Gives string to prepend on any new lines produced by
52 wrapping (default ' ')
53
54 Example result:
55 name = 'A_MACRO'
56 args = ['arg1', 'arg2'],
57 body = 'arg1 + arg2 + 10'
58
59 #define A_MACRO(arg1, arg2) arg1 + arg2 + 10
60
61 When the macro is wrapped the break happens after the argument list (or
62 macro name if there is no argument list
63
64 #define A_MACRO(arg1, arg2) \
65 arg1 + arg2 + 10
66
67 """
68 if len(args) != 0:
69 define_declare = '#define ' + name + '(' + ', '.join(args) + ')'
70 else:
71 define_declare = '#define ' + name
72
73 oneline_define = define_declare + ' ' + body
74
75 if len(oneline_define) <= 80:
76 return oneline_define + '\n'
77
78 return define_declare + ' \\\n' + indent + body + '\n'
79
80
lowRISC Contributors802543a2019-08-31 12:12:56 +010081def gen_cdefine_register(outstr, reg, comp, width, rnames):
82 rname = reg['name']
83 offset = reg['genoffset']
84
Greg Chadwick45859b72019-10-23 13:06:29 +010085 genout(outstr, format_comment(first_line(reg['desc'])))
lowRISC Contributors802543a2019-08-31 12:12:56 +010086 defname = as_define(comp + '_' + rname)
87 genout(
Greg Chadwick45859b72019-10-23 13:06:29 +010088 outstr,
89 gen_define(
90 defname, ['id'],
91 '(' + as_define(comp) + '##id##_BASE_ADDR + ' + hex(offset) + ')'))
Miguel Young de la Sota8d3985b2019-12-02 15:51:35 -060092 genout(outstr, gen_define(defname + '_REG_OFFSET', [], hex(offset)))
lowRISC Contributors802543a2019-08-31 12:12:56 +010093
94 for field in reg['fields']:
95 fieldlsb = field['bitinfo'][2]
96 fname = field['name']
97 if fname == rname:
98 dname = defname
99 else:
100 dname = defname + '_' + as_define(fname)
101
102 if field['bitinfo'][1] == 1:
103 # single bit
Greg Chadwick45859b72019-10-23 13:06:29 +0100104 genout(outstr, gen_define(dname, [], str(fieldlsb)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100105 else:
106 # multiple bits (unless it is the whole register)
107 if field['bitinfo'][1] != width:
108 mask = field['bitinfo'][0] >> fieldlsb
Greg Chadwick45859b72019-10-23 13:06:29 +0100109 genout(outstr, gen_define(dname + '_MASK', [], hex(mask)))
110 genout(outstr, gen_define(dname + '_OFFSET', [],
111 str(fieldlsb)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100112 if 'enum' in field:
113 for enum in field['enum']:
114 ename = as_define(enum['name'])
115 genout(
116 outstr,
Greg Chadwick45859b72019-10-23 13:06:29 +0100117 gen_define(
118 defname + '_' + as_define(field['name']) + '_' +
119 ename, [], enum['value']))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100120 genout(outstr, '\n')
121 return
122
123
124def gen_cdefine_window(outstr, win, comp, regwidth, rnames):
125 wname = win['name']
126 offset = win['genoffset']
127
Greg Chadwick45859b72019-10-23 13:06:29 +0100128 genout(outstr, format_comment('Memory area: ' + first_line(win['desc'])))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100129 defname = as_define(comp + '_' + wname)
130 genout(
Greg Chadwick45859b72019-10-23 13:06:29 +0100131 outstr,
132 gen_define(
133 defname, ['id'],
134 '(' + as_define(comp) + '##id##_BASE_ADDR + ' + hex(offset) + ')'))
Miguel Young de la Sota8d3985b2019-12-02 15:51:35 -0600135 genout(outstr, gen_define(defname + '_REG_OFFSET', [], hex(offset)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100136 items = int(win['items'])
Greg Chadwick45859b72019-10-23 13:06:29 +0100137 genout(outstr, gen_define(defname + '_SIZE_WORDS', [], str(items)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100138 items = items * (regwidth // 8)
Greg Chadwick45859b72019-10-23 13:06:29 +0100139 genout(outstr, gen_define(defname + '_SIZE_BYTES', [], str(items)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100140
141 wid = win['genvalidbits']
142 if (wid != regwidth):
143 mask = (1 << wid) - 1
Greg Chadwick45859b72019-10-23 13:06:29 +0100144 genout(outstr, gen_define(defname + '_MASK ', [], hex(mask)))
lowRISC Contributors802543a2019-08-31 12:12:56 +0100145
146
147# Must have called validate, so should have no errors
148
149
150def gen_cdefines(regs, outfile, src_lic, src_copy):
151 component = regs['name']
152 registers = regs['registers']
153 rnames = regs['genrnames']
154 outstr = io.StringIO()
155
156 if 'regwidth' in regs:
157 regwidth = int(regs['regwidth'], 0)
158 else:
159 regwidth = 32
160
161 for x in registers:
162 if 'reserved' in x:
163 continue
164
165 if 'skipto' in x:
166 continue
167
168 if 'sameaddr' in x:
169 for sareg in x['sameaddr']:
170 gen_cdefine_register(outstr, sareg, component, regwidth,
171 rnames)
172 continue
173
174 if 'window' in x:
175 gen_cdefine_window(outstr, x['window'], component, regwidth,
176 rnames)
177 continue
178
179 if 'multireg' in x:
180 for reg in x['multireg']['genregs']:
181 gen_cdefine_register(outstr, reg, component, regwidth, rnames)
182 continue
183
184 gen_cdefine_register(outstr, x, component, regwidth, rnames)
185
186 generated = outstr.getvalue()
187 outstr.close()
188
189 genout(outfile, '// Generated register defines for ' + component + '\n\n')
190 if src_copy != '':
191 genout(outfile, '// Copyright information found in source file:\n')
192 genout(outfile, '// ' + src_copy + '\n\n')
193 if src_lic != None:
194 genout(outfile, '// Licensing information found in source file:\n')
195 for line in src_lic.splitlines():
196 genout(outfile, '// ' + line + '\n')
197 genout(outfile, '\n')
198 genout(outfile, '#ifndef _' + as_define(component) + '_REG_DEFS_\n')
199 genout(outfile, '#define _' + as_define(component) + '_REG_DEFS_\n\n')
200 genout(outfile, generated)
201 genout(outfile, '#endif // _' + as_define(component) + '_REG_DEFS_\n')
202 genout(outfile, '// End generated register defines for ' + component)
203
204 return
Greg Chadwick45859b72019-10-23 13:06:29 +0100205
206
207def test_gen_define():
208 basic_oneline = '#define MACRO_NAME body\n'
209 assert gen_define('MACRO_NAME', [], 'body') == basic_oneline
210
211 basic_oneline_with_args = '#define MACRO_NAME(arg1, arg2) arg1 + arg2\n'
212 assert (gen_define('MACRO_NAME', ['arg1', 'arg2'],
213 'arg1 + arg2') == basic_oneline_with_args)
214
215 long_macro_name = 'A_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_LONG_MACRO_NAME'
216
217 multiline = ('#define ' + long_macro_name + ' \\\n' +
218 ' a_fairly_long_body + something_else + 10\n')
219
220 assert (gen_define(
221 long_macro_name, [],
222 'a_fairly_long_body + something_else + 10') == multiline)
223
224 multiline_with_args = ('#define ' + long_macro_name +
225 '(arg1, arg2, arg3) \\\n' +
226 ' a_fairly_long_body + arg1 + arg2 + arg3\n')
227
228 assert (gen_define(
229 long_macro_name, ['arg1', 'arg2', 'arg3'],
230 'a_fairly_long_body + arg1 + arg2 + arg3') == multiline_with_args)
231
232 multiline_with_args_big_indent = (
233 '#define ' + long_macro_name + '(arg1, arg2, arg3) \\\n' +
234 ' a_fairly_long_body + arg1 + arg2 + arg3\n')
235
236 assert (gen_define(long_macro_name, ['arg1', 'arg2', 'arg3'],
237 'a_fairly_long_body + arg1 + arg2 + arg3',
238 indent=' ') == multiline_with_args_big_indent)