gadget-kspconsole/unicore-mx/scripts/uc-def/uc-def
Daniele Lacamera b8a7ffcd31 Initial import
2023-11-27 15:16:45 +01:00

733 lines
20 KiB
Python
Executable file

#!/usr/bin/env python
#
# This file is part of unicore-mx.
# Copyright (C) 2014-2016 Kuldeep Singh Dhaka <kuldeepdhaka9@gmail.com>
#
# uc-def is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# uc-def is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with uc-def. If not, see <http://www.gnu.org/licenses/>.
#
# Special exception (same as GNU Bison)
# As a special exception, you may create a larger work that contains
# part or all of the uc-def parser skeleton and distribute that work
# under terms of your choice, so long as that work isn't itself a
# parser generator using the skeleton or a modified version thereof
# as a parser skeleton. Alternatively, if you modify or redistribute
# the parser skeleton itself, you may (at your option) remove this
# special exception, which will cause the skeleton and the resulting
# uc-def output files to be licensed under the GNU General Public
# License without this special exception.
# uC Def.
# Microcontroller register defination
import sys
import logging
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)
STRICT_C_OUTPUT = False
def verify_access_flags(data):
for i in data:
if i not in ('r', 'w', 'c', 's', 'h'):
raise Exception("'%c' flag of flags '%s' not valid" % (i, data))
def next_useful_line(tag, strip_newline=True, strip_comment=True):
while True:
tag['last_useful_pos'] = tag['input_file'].tell()
tag['last_line_number'] = tag['line_number']
inp = tag['input_file'].readline()
if not len(inp):
break
if strip_newline:
inp = inp.rstrip()
if not len(inp):
logger.debug("** SKIPPING NEWLINE at %i ***" % tag['line_number'])
tag['line_number'] += 1
continue
if strip_comment:
if inp[0] == "%":
tag['line_number'] += 1
logger.debug("** SKIPPING %i '%s' ***" % (tag['line_number'], inp))
continue
logger.debug("** LINE %i '%s' ***" % (tag['line_number'], inp))
tag['line_number'] += 1
return inp
logger.debug("** END OF FILE ***")
return ''
def restore_last_useful_line(tag):
tag['line_number'] = tag['last_line_number']
tag['input_file'].seek(tag['last_useful_pos'])
def get_line_number(tag):
return tag['line_number']
def we_have_problem(msg, tag):
raise Exception("%s [line: %i]" % (msg, get_line_number(tag)))
# this will return the last readed line. (if it could not parse it)
def parse_family_member(tag):
family = {
'name': None,
'instance': None,
'register': None,
'internal_only': False
}
while True:
inp = next_useful_line(tag)
if inp == '': break
if not inp[0] == ' ':
# revese back and return
restore_last_useful_line(tag)
break
data = inp.split()
assert(len(data) >= 1)
if data[0] == "name":
# name <name>
family['name'] = data[1]
elif data[0] == "instance":
# instance <address>
assert(family['instance'] is None)
family['instance'] = " ".join(data[1:])
elif data[0] == "instance_by_id":
# instance <id> <address>
if family['instance'] is None:
family['instance'] = []
assert(type(family['instance']) == list)
family['instance'].append({
'id': data[1],
'address': " ".join(data[2:])
})
elif data[0] == "register":
assert(2 <= len(data) <= 3)
family['register'] = {
'size': data[1],
'stride': data[2] if len(data) > 2 else None
}
elif data[0] == "internal_only":
family['internal_only'] = bool(data[1])
assert(family['name'] is not None)
return family
def parse_family(tag):
inp = next_useful_line(tag)
if inp == '':
return None
if not inp[0] == 'f':
restore_last_useful_line(tag)
return None
if not inp == "family":
# fam <name> <address>
data = inp.slit()
assert(len(data) < 2 and data[0] == "fam")
return {
'name': data[1],
'instance': data[2] if len(data) > 2 else None,
'register': None,
'internal_only': False
}
else:
return parse_family_member(tag)
def parse_register_member(tag):
register = {
'name': [],
'offset': None,
'size': None,
'access': None,
'bit_name': [],
'bits_name': [],
'variable': [],
'internal_only': False
}
while True:
inp = next_useful_line(tag)
if inp == '': break
if not inp[0] == ' ':
# revese back and return
restore_last_useful_line(tag)
break
data = inp.split()
assert(len(data) >= 1)
if data[0] == "name":
# name <name>
register['name'].append(data[1])
elif data[0] == "offset":
# offset <offset>
assert(register['offset'] is None)
register['offset'] = " ".join(data[1:])
elif data[0] == "offset_by_id":
# offset_by_id <id> <offset>
if register['offset'] is None:
register['offset'] = []
assert(type(register['offset']) == list)
register['offset'].append({
'id': data[1],
'offset': " ".join(data[2:])
})
elif data[0] == "size":
# size <size>
register['size'] = data[1]
elif data[0] == "access":
# access <access>
for c in data[1]:
assert(c in ('r', 'w', 'h'))
register['access'] = data[1]
elif data[0] == "bit_name":
# bit_name <bit-name>
register['bit_name'].append(data[1])
elif data[0] == "bits_name":
# bits_name <bits-name>
register['bits_name'].append(data[1])
elif data[0] == "variable":
# variable <variable-name> <variable-equation>
register['variable'].append({
'name': data[1],
'equation': ' '.join(data[2:])
})
elif data[0] == "internal_only":
register['internal_only'] = bool(data[1])
assert(len(register['name']))
if not len(register['bit_name']):
# <bit_name> not provided, fallback and use <name>
register['bit_name'] = register['name']
if not len(register['bits_name']):
# <bits_name> not provided, fallback and use <name>
register['bits_name'] = register['name']
return register
def parse_register(tag):
inp = next_useful_line(tag)
if inp == '':
return None
if inp[0] is not 'r':
restore_last_useful_line(tag)
return None
if inp[3] == ' ':
# reg <name> <offset> <size>
data = inp.split()
assert(2 <= len(data) <= 4)
assert(data[0] == "reg")
return {
'name': [ data[1] ],
'offset': data[2] if len(data) > 2 else None,
'size': data[3] if len(data) > 3 else None,
'access': None,
'bit_name': [ data[1] ],
'bits_name': [ data[1] ],
'variable': [],
'internal_only': False
}
else:
assert(inp == "register")
return parse_register_member(tag)
def parse_bit_member(tag):
bit = {
'name': [],
'offset': None,
'access': None,
'variable': []
}
while True:
inp = next_useful_line(tag)
if inp == '': break
if not inp[0] == ' ':
# revese back and return
restore_last_useful_line(tag)
break
data = inp.split()
assert(len(data) >= 1)
# name <name>
if data[0] == "name":
bit['name'].append(data[1])
elif data[0] == "offset":
if len(data) == 2:
# offset <offset>
assert(bit['offset'] is None)
bit['offset'] = data[1]
elif len(data) == 3:
# offset <id> <offset>
if bit['offset'] is None:
bit['offset'] = []
assert(type(bit['offset']) == list)
bit['offset'].append({'id': data[1], 'offset': data[2]})
else:
we_have_problem("unknown design of offset", tag)
elif data[0] == "access":
# access <access>
verify_access_flags(data[1])
bit['access'] = data[1]
elif data[0] == "variable":
# variable <variable-name> <variable-equation>
bit['variable'].append({
'name': data[1],
'equation': ' '.join(data[2:])
})
assert(len(bit['name']))
return bit
def parse_bit(tag):
inp = next_useful_line(tag)
if inp == '':
return None
data = inp.split()
if data[0] != "bit":
restore_last_useful_line(tag)
return None
if len(data) > 1:
# bit <name> <offset>
return {
'name' : [ data[1] ],
'offset': data[2] if len(data) > 2 else None,
'access': None,
'variable': []
}
else:
return parse_bit_member(tag)
def parse_bits_member(tag):
bits = {
'name': [],
'offset': None,
'size': None,
'access': None,
'values': [],
'variable': []
}
while True:
inp = next_useful_line(tag)
if inp == '': break
if not inp[0] == ' ':
# revese back and return
restore_last_useful_line(tag)
break
data = inp.split()
assert(len(data) >= 1)
# name <name>
if data[0] == "name":
bits['name'].append(data[1])
elif data[0] == "offset":
if len(data) == 2:
# offset <offset>
assert(bits['offset'] is None)
bits['offset'] = data[1]
elif len(data) == 3:
# offset <id> <offset>
if bits['offset'] is None:
bits['offset'] = []
assert(type(bits['offset']) == list)
bits['offset'].append({'id': data[1], 'offset': data[2]})
else:
we_have_problem("unknown design of offset", tag)
elif data[0] == "size":
# size <size>
bits['size'] = data[1]
elif data[0] == "value":
assert(len(data) >= 1)
# value <value-name> <value-value>
bits['values'].append({
'name': data[1],
'value': data[2] if len(data) > 2 else None
})
elif data[0] == "access":
# access <access>
verify_access_flags(data[1])
bits['access'] = data[1]
elif data[0] == "variable":
# variable <variable-name> <variable-equation>
bits['variable'].append({
'name': data[1],
'equation': ' '.join(data[2:])
})
assert(bits['name'] is not None)
assert(bits['size'] is not None)
return bits
def parse_bits(tag):
inp = next_useful_line(tag)
if inp == '':
return None
data = inp.split()
if data[0] != "bits":
restore_last_useful_line(tag)
return None
if len(data) > 1:
assert(len(data) > 2)
# bits <name> <size> <offset>
return {
'name' : [ data[1] ] ,
'size': data[2],
'offset': data[3] if len(data) > 3 else None,
'access': None,
'values': [],
'variable': []
}
else:
return parse_bits_member(tag)
def parse_input(input_file):
data = []
inside_block = False
tag = {
'input_file': input_file,
'last_line_number': 1,
'line_number': 1,
'last_useful_pos': 0
}
while True:
inp = next_useful_line(tag, strip_newline=inside_block, \
strip_comment=False)
if not len(inp):
break
if inside_block:
if inp.strip()[0:6] == "#endif":
inside_block = False
continue
elif inp.strip()[0:3] == "#if" and inp.find("__UCD__") != -1:
inside_block = True
continue
else:
data.append({'type': 'extra', 'payload': inp})
continue
# parse code
if inp[0] == "%":
fmt = "/* %s */" if STRICT_C_OUTPUT else "// %s"
res = fmt % inp[1:].strip()
data.append({'type': 'extra', 'payload': res + "\n\n"})
continue
restore_last_useful_line(tag)
if inp[0] == "f":
family = parse_family(tag)
if family is None:
break
data.append({'type': 'family', 'payload': family})
elif inp[0] == "r":
register = parse_register(tag)
if register is None:
break
data.append({'type': 'register', 'payload': register})
elif inp[0] == "b":
bit = parse_bit(tag)
if bit is not None:
data.append({'type': 'bit', 'payload': bit})
else:
bits = parse_bits(tag)
if bits is None:
break
data.append({'type': 'bits', 'payload': bits})
else:
we_have_problem("unknown input: \"%s\"" % inp, tag)
break
return data
def generate_family(family, output_file):
# if instance are not provided
if family['instance'] is None:
return
if not family['internal_only']:
if type(family['instance']) == list:
for i in family['instance']:
fam_id = '%s%s' % (family['name'], i['id'])
output_file.write("#define %s (%s)\n" % (fam_id, i['address']))
else:
addr = str(family['instance'])
name = family['name']
output_file.write("#define %s (%s)\n" % (name, addr))
# a final newline to seperate things
output_file.write("\n")
def generate_register(register, family, offset, output_file):
# calculate register size
size = 32
if register['size'] is not None:
size = int(register['size'], 0)
elif family['register'] is not None and family['register']['size'] is not None:
size = int(family['register']['size'], 0)
mmio = "MMIO%i" % size
# calculate register offset
if register['offset'] is not None:
offset = register['offset']
if not register['internal_only']:
extra_arg = ""
extra_body = ""
if register['variable']:
for i in register['variable']:
extra_arg += ", %s" % i['name']
extra_body += " + (%s)" % i['equation']
#base macros of style PERPH_REG(base)
# if not instance is provided or multiple instance are there
if family['instance'] is None or type(family['instance']) is list:
register_name = register['name'][0]
actual_name = "%s_%s" % (family['name'], register_name)
output_file.write("#define %s(base%s) %s((base) + (%s)%s)\n" % (actual_name, extra_arg, mmio, offset, extra_body))
output_file.write("\n")
# alias of regiser (that accept base)
if len(register['name'][1:]):
output_file.write("/* Alias of %s */\n" % actual_name)
for register_name in register['name'][1:]:
alias_name = "%s_%s" % (family['name'], register_name)
output_file.write("#define %s(base%s) %s(base%s)\n" % \
(alias_name, extra_arg, actual_name, extra_arg))
if len(register['name'][1:]):
output_file.write("\n")
# instace that send base to above macros
if family['instance'] is not None: # ie family['instance'] type is of list
for instance in family['instance']:
for register_name in register['name']:
frm = "%s%s_%s" % (family['name'], instance['id'], register_name)
to = "%s_%s" % (family['name'], register_name)
addr = "%s%s" % (family['name'], instance['id'])
_extra_arg = "(%s)" % extra_arg[2:] if len(extra_arg) else ""
output_file.write("#define %s%s %s(%s%s)\n" % (frm, _extra_arg, to, addr, extra_arg))
output_file.write("\n")
else:
#single instance
register_name = register['name'][0]
actual_name = "%s_%s" % (family['name'], register_name)
_extra_arg = "(%s)" % extra_arg[2:] if len(extra_arg) else ""
output_file.write("#define %s%s %s((%s) + (%s)%s)\n" % \
(actual_name, _extra_arg, mmio, family['instance'], offset, extra_body))
output_file.write("\n")
if len(register['name'][1:]):
output_file.write("/* Alias of %s */\n" % actual_name)
for register_name in register['name'][1:]:
alias_name = "%s_%s" % (family['name'], register_name)
output_file.write("#define %s%s %s%s" % (alias_name, _extra_arg, actual_name, _extra_arg))
output_file.write("\n")
if len(register['name'][1:]):
output_file.write("\n")
stride = size
if family['register'] is not None and family['register']['stride'] is not None:
stride = int(family['register']['stride'], 0)
try: next_offset = int(offset) + stride
except ValueError: next_offset = "%s + %i" % (offset, stride)
return next_offset, size
def generate_bit(bit, register, family, offset, register_size, output_file):
if bit['offset'] is not None:
offset = bit['offset']
try: assert(int(offset) < register_size)
except ValueError: pass # cannot be converted to integer
extra_arg = ""
extra_offset = ""
if bit["variable"]:
extra_arg = []
for v in bit["variable"]:
extra_arg.append(v['name'])
extra_offset += " + (" + v['equation'] + ")"
extra_arg = ", ".join(extra_arg)
extra_arg = "(%s)" % extra_arg
actual_name = None
for register_name in register['bit_name']:
for bit_name in bit['name']:
if register['bit_name'].index(register_name) == bit['name'].index(bit_name) == 0:
actual_name = "%s_%s_%s" % (family['name'], register_name, bit_name)
output_file.write("#define %s_SHIFT%s (%s%s)\n" % (actual_name, extra_arg, offset, extra_offset))
output_file.write("#define %s%s (1 << %s_SHIFT%s)\n" % (actual_name, extra_arg, actual_name, extra_arg))
else:
alias_name = "%s_%s_%s" % (family['name'], register_name, bit_name)
output_file.write("/* Alias of %s */\n" % actual_name)
output_file.write("#define %s_SHIFT%s %s_SHIFT%s\n" % (alias_name, extra_arg, actual_name, extra_arg))
output_file.write("#define %s%s %s%s\n" % (alias_name, extra_arg, actual_name, extra_arg))
output_file.write("\n")
output_file.write("\n")
try: return (int(offset) + 1)
except ValueError: return "%s + 1" % offset
def generate_bits(bits, register, family, offset, register_size, output_file):
if bits['offset'] is not None:
offset = bits['offset']
size = int(bits['size'], 0)
try: assert((int(offset) + size) <= register_size)
except ValueError: pass # offset not a integer value
mask = hex(pow(2, size) - 1)
extra_arg = ""
bracketed_extra_arg = "" #if len(extra_arg) > 0
all_arg = "v"
extra_offset = ""
if bits["variable"]:
extra_arg = []
for v in bits["variable"]:
extra_arg.append(v['name'])
extra_offset += " + (" + v['equation'] + ")"
extra_arg = ", ".join(extra_arg)
all_arg = "v, %s" % extra_arg
bracketed_extra_arg = "(%s)" % extra_arg
actual_name = None
for register_name in register['bits_name']:
for bits_name in bits['name']:
if (bits['name'].index(bits_name) == 0) and \
(register['bits_name'].index(register_name) == 0):
#print original macro
actual_name = "%s_%s_%s" % (family['name'], register_name, bits_name)
output_file.write("#define %s_SHIFT%s (%s%s)\n" % (actual_name, bracketed_extra_arg, offset, extra_offset))
output_file.write("#define %s_MASK%s (%s << (%s_SHIFT%s))\n" % \
(actual_name, bracketed_extra_arg, mask, actual_name, bracketed_extra_arg))
output_file.write("#define %s(%s) (((v) << (%s_SHIFT%s)) & (%s_MASK%s))\n" % \
(actual_name, all_arg, actual_name, bracketed_extra_arg, actual_name, bracketed_extra_arg))
output_file.write("#define %s_GET(%s) (((v) & (%s_MASK%s)) >> (%s_SHIFT%s))\n" % \
(actual_name, all_arg, actual_name, bracketed_extra_arg, actual_name, bracketed_extra_arg))
# values
value_value = 0
for v in bits['values']:
if v['value'] is not None:
value_value = int(v['value'], 0)
_arg = hex(value_value)
if len(extra_arg):
_arg = "%s, %s" % (_arg, extra_arg)
output_file.write("#define %s_%s%s %s(%s)\n" % \
(actual_name, v['name'], bracketed_extra_arg, actual_name, _arg))
value_value += 1
else:
#print alias macro
alias_name = "%s_%s_%s" % (family['name'], register_name, bits_name)
output_file.write("/* Alias of %s */\n" % actual_name)
output_file.write("#define %s_SHIFT%s %s_SHIFT%s\n" %
(alias_name, bracketed_extra_arg, actual_name, bracketed_extra_arg))
output_file.write("#define %s_MASK%s %s_MASK%s\n" %
(alias_name, bracketed_extra_arg, actual_name, bracketed_extra_arg))
output_file.write("#define %s(%s) %s(%s)\n" %
(alias_name, all_arg, actual_name, all_arg))
output_file.write("#define %s_GET(%s) %s_GET(%s)\n" %
(alias_name, all_arg, actual_name, all_arg))
# alias values
for v in bits['values']:
output_file.write("#define %s_%s%s %s_%s%s\n" % \
(alias_name, v['name'], bracketed_extra_arg, actual_name,
v['name'], bracketed_extra_arg))
output_file.write("\n")
output_file.write("\n")
try: return (int(offset) + size)
except ValueError: return "%s + %i" % (offset, size)
def generate_output(data, output_file):
family = None
register = None
register_size = None
register_offset = None
register_next_bit = None
for d in data:
if d['type'] == 'extra':
output_file.write(d['payload'])
elif d['type'] == 'family':
family = d['payload']
register_offset = 0 # reset register offset
generate_family(family, output_file)
elif d['type'] == 'register':
register = d['payload']
register_next_bit = 0
register_offset, register_size = generate_register( \
register, family, register_offset, output_file)
elif d['type'] == 'bit':
register_next_bit = generate_bit(d['payload'], register, family, \
register_next_bit, register_size, output_file)
elif d['type'] == 'bits':
register_next_bit = generate_bits(d['payload'], register, family, \
register_next_bit, register_size, output_file)
if __name__ == "__main__":
assert (len(sys.argv) > 1)
input_file = open(sys.argv[1])
output_file = open(sys.argv[2], 'w+') if len(sys.argv) > 2 else sys.stdout
data = parse_input(input_file)
generate_output(data, output_file)