blob: 66d4ae998e75c655424827b93106db00be009258 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
"""
Generate C header from validated register JSON tree
"""
import io
import logging as log
import re
import sys
import textwrap
def genout(outfile, msg):
outfile.write(msg)
def as_define(s):
s = s.upper()
r = ''
for i in range(0, len(s)):
r += s[i] if s[i].isalnum() else '_'
return r
def first_line(s):
"""Returns the first line of a multi-line string"""
return s.splitlines()[0]
def format_comment(s):
"""Formats a string to comment wrapped to an 80 character line width
Returns wrapped string including newline and // comment characters.
"""
return '\n'.join(
textwrap.wrap(
s, width=77, initial_indent='// ', subsequent_indent='// ')) + '\n'
def gen_define(name, args, body, indent=' '):
r"""Produces a #define string, will split into two lines if a single line
has a width greater than 80 characters. Result includes newline.
Arguments:
name - Name of the #define
args - List of arguments for the define, provide an empty list if there are
none
body - Body of the #define
indent - Gives string to prepend on any new lines produced by
wrapping (default ' ')
Example result:
name = 'A_MACRO'
args = ['arg1', 'arg2'],
body = 'arg1 + arg2 + 10'
#define A_MACRO(arg1, arg2) arg1 + arg2 + 10
When the macro is wrapped the break happens after the argument list (or
macro name if there is no argument list
#define A_MACRO(arg1, arg2) \
arg1 + arg2 + 10
"""
if len(args) != 0:
define_declare = '#define ' + name + '(' + ', '.join(args) + ')'
else:
define_declare = '#define ' + name
oneline_define = define_declare + ' ' + body
if len(oneline_define) <= 80:
return oneline_define + '\n'
return define_declare + ' \\\n' + indent + body + '\n'
def gen_cdefine_register(outstr, reg, comp, width, rnames):
rname = reg['name']
offset = reg['genoffset']
genout(outstr, format_comment(first_line(reg['desc'])))
defname = as_define(comp + '_' + rname)
genout(
outstr,
gen_define(
defname, ['id'],
'(' + as_define(comp) + '##id##_BASE_ADDR + ' + hex(offset) + ')'))
genout(outstr, gen_define(defname + '_REG_OFFSET', [], hex(offset)))
for field in reg['fields']:
fieldlsb = field['bitinfo'][2]
fname = field['name']
if fname == rname:
dname = defname
else:
dname = defname + '_' + as_define(fname)
if field['bitinfo'][1] == 1:
# single bit
genout(outstr, gen_define(dname, [], str(fieldlsb)))
else:
# multiple bits (unless it is the whole register)
if field['bitinfo'][1] != width:
mask = field['bitinfo'][0] >> fieldlsb
genout(outstr, gen_define(dname + '_MASK', [], hex(mask)))
genout(outstr, gen_define(dname + '_OFFSET', [],
str(fieldlsb)))
if 'enum' in field:
for enum in field['enum']:
ename = as_define(enum['name'])
genout(
outstr,
gen_define(
defname + '_' + as_define(field['name']) + '_' +
ename, [], enum['value']))
genout(outstr, '\n')
return
def gen_cdefine_window(outstr, win, comp, regwidth, rnames):
wname = win['name']
offset = win['genoffset']
genout(outstr, format_comment('Memory area: ' + first_line(win['desc'])))
defname = as_define(comp + '_' + wname)
genout(
outstr,
gen_define(
defname, ['id'],
'(' + as_define(comp) + '##id##_BASE_ADDR + ' + hex(offset) + ')'))
genout(outstr, gen_define(defname + '_REG_OFFSET', [], hex(offset)))
items = int(win['items'])
genout(outstr, gen_define(defname + '_SIZE_WORDS', [], str(items)))
items = items * (regwidth // 8)
genout(outstr, gen_define(defname + '_SIZE_BYTES', [], str(items)))
wid = win['genvalidbits']
if (wid != regwidth):
mask = (1 << wid) - 1
genout(outstr, gen_define(defname + '_MASK ', [], hex(mask)))
# Must have called validate, so should have no errors
def gen_cdefines(regs, outfile, src_lic, src_copy):
component = regs['name']
registers = regs['registers']
rnames = regs['genrnames']
outstr = io.StringIO()
if 'regwidth' in regs:
regwidth = int(regs['regwidth'], 0)
else:
regwidth = 32
for x in registers:
if 'reserved' in x:
continue
if 'skipto' in x:
continue
if 'sameaddr' in x:
for sareg in x['sameaddr']:
gen_cdefine_register(outstr, sareg, component, regwidth,
rnames)
continue
if 'window' in x:
gen_cdefine_window(outstr, x['window'], component, regwidth,
rnames)
continue
if 'multireg' in x:
for reg in x['multireg']['genregs']:
gen_cdefine_register(outstr, reg, component, regwidth, rnames)
continue
gen_cdefine_register(outstr, x, component, regwidth, rnames)
generated = outstr.getvalue()
outstr.close()
genout(outfile, '// Generated register defines for ' + component + '\n\n')
if src_copy != '':
genout(outfile, '// Copyright information found in source file:\n')
genout(outfile, '// ' + src_copy + '\n\n')
if src_lic != None:
genout(outfile, '// Licensing information found in source file:\n')
for line in src_lic.splitlines():
genout(outfile, '// ' + line + '\n')
genout(outfile, '\n')
genout(outfile, '#ifndef _' + as_define(component) + '_REG_DEFS_\n')
genout(outfile, '#define _' + as_define(component) + '_REG_DEFS_\n\n')
genout(outfile, generated)
genout(outfile, '#endif // _' + as_define(component) + '_REG_DEFS_\n')
genout(outfile, '// End generated register defines for ' + component)
return
def test_gen_define():
basic_oneline = '#define MACRO_NAME body\n'
assert gen_define('MACRO_NAME', [], 'body') == basic_oneline
basic_oneline_with_args = '#define MACRO_NAME(arg1, arg2) arg1 + arg2\n'
assert (gen_define('MACRO_NAME', ['arg1', 'arg2'],
'arg1 + arg2') == basic_oneline_with_args)
long_macro_name = 'A_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_VERY_LONG_MACRO_NAME'
multiline = ('#define ' + long_macro_name + ' \\\n' +
' a_fairly_long_body + something_else + 10\n')
assert (gen_define(
long_macro_name, [],
'a_fairly_long_body + something_else + 10') == multiline)
multiline_with_args = ('#define ' + long_macro_name +
'(arg1, arg2, arg3) \\\n' +
' a_fairly_long_body + arg1 + arg2 + arg3\n')
assert (gen_define(
long_macro_name, ['arg1', 'arg2', 'arg3'],
'a_fairly_long_body + arg1 + arg2 + arg3') == multiline_with_args)
multiline_with_args_big_indent = (
'#define ' + long_macro_name + '(arg1, arg2, arg3) \\\n' +
' a_fairly_long_body + arg1 + arg2 + arg3\n')
assert (gen_define(long_macro_name, ['arg1', 'arg2', 'arg3'],
'a_fairly_long_body + arg1 + arg2 + arg3',
indent=' ') == multiline_with_args_big_indent)