mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-25 04:23:46 +00:00
219 lines
6 KiB
Python
219 lines
6 KiB
Python
|
#!/usr/bin/python
|
||
|
|
||
|
# Script to create enums from datasheet register tables
|
||
|
#
|
||
|
# Usage:
|
||
|
#
|
||
|
# First, create a text file from the datasheet:
|
||
|
# pdftotext -layout /path/to/rockchip-3288-trm.pdf /tmp/asc
|
||
|
#
|
||
|
# Then use this script to output the #defines for a particular register:
|
||
|
# ./tools/rkmux.py GRF_GPIO4C_IOMUX
|
||
|
#
|
||
|
# It will create output suitable for putting in a header file, with SHIFT and
|
||
|
# MASK values for each bitfield in the register.
|
||
|
#
|
||
|
# Note: this tool is not perfect and you may need to edit the resulting code.
|
||
|
# But it should speed up the process.
|
||
|
|
||
|
import csv
|
||
|
import re
|
||
|
import sys
|
||
|
|
||
|
tab_to_col = 3
|
||
|
|
||
|
class RegField:
|
||
|
def __init__(self, cols=None):
|
||
|
if cols:
|
||
|
self.bits, self.attr, self.reset_val, self.desc = (
|
||
|
[x.strip() for x in cols])
|
||
|
self.desc = [self.desc]
|
||
|
else:
|
||
|
self.bits = ''
|
||
|
self.attr = ''
|
||
|
self.reset_val = ''
|
||
|
self.desc = []
|
||
|
|
||
|
def Setup(self, cols):
|
||
|
self.bits, self.attr, self.reset_val = cols[0:3]
|
||
|
if len(cols) > 3:
|
||
|
self.desc.append(cols[3])
|
||
|
|
||
|
def AddDesc(self, desc):
|
||
|
self.desc.append(desc)
|
||
|
|
||
|
def Show(self):
|
||
|
print self
|
||
|
print
|
||
|
self.__init__()
|
||
|
|
||
|
def __str__(self):
|
||
|
return '%s,%s,%s,%s' % (self.bits, self.attr, self.reset_val,
|
||
|
'\n'.join(self.desc))
|
||
|
|
||
|
class Printer:
|
||
|
def __init__(self, name):
|
||
|
self.first = True
|
||
|
self.name = name
|
||
|
self.re_sel = re.compile("[1-9]'b([01]+): (.*)")
|
||
|
|
||
|
def __enter__(self):
|
||
|
return self
|
||
|
|
||
|
def __exit__(self, type, value, traceback):
|
||
|
if not self.first:
|
||
|
self.output_footer()
|
||
|
|
||
|
def output_header(self):
|
||
|
print '/* %s */' % self.name
|
||
|
print 'enum {'
|
||
|
|
||
|
def output_footer(self):
|
||
|
print '};';
|
||
|
|
||
|
def output_regfield(self, regfield):
|
||
|
lines = regfield.desc
|
||
|
field = lines[0]
|
||
|
#print 'field:', field
|
||
|
if field in ['reserved', 'reserve', 'write_enable', 'write_mask']:
|
||
|
return
|
||
|
if field.endswith('_sel') or field.endswith('_con'):
|
||
|
field = field[:-4]
|
||
|
elif field.endswith(' iomux'):
|
||
|
field = field[:-6]
|
||
|
elif field.endswith('_mode') or field.endswith('_mask'):
|
||
|
field = field[:-5]
|
||
|
#else:
|
||
|
#print 'bad field %s' % field
|
||
|
#return
|
||
|
field = field.upper()
|
||
|
if ':' in regfield.bits:
|
||
|
bit_high, bit_low = [int(x) for x in regfield.bits.split(':')]
|
||
|
else:
|
||
|
bit_high = bit_low = int(regfield.bits)
|
||
|
bit_width = bit_high - bit_low + 1
|
||
|
mask = (1 << bit_width) - 1
|
||
|
if self.first:
|
||
|
self.first = False
|
||
|
self.output_header()
|
||
|
else:
|
||
|
print
|
||
|
out_enum(field, 'shift', bit_low)
|
||
|
out_enum(field, 'mask', mask)
|
||
|
next_val = -1
|
||
|
#print 'lines: %s', lines
|
||
|
for line in lines:
|
||
|
m = self.re_sel.match(line)
|
||
|
if m:
|
||
|
val, enum = int(m.group(1), 2), m.group(2)
|
||
|
if enum not in ['reserved', 'reserve']:
|
||
|
out_enum(field, enum, val, val == next_val)
|
||
|
next_val = val + 1
|
||
|
|
||
|
|
||
|
def process_file(name, fd):
|
||
|
field = RegField()
|
||
|
reg = ''
|
||
|
|
||
|
fields = []
|
||
|
|
||
|
def add_it(field):
|
||
|
if field.bits:
|
||
|
if reg == name:
|
||
|
fields.append(field)
|
||
|
field = RegField()
|
||
|
return field
|
||
|
|
||
|
def is_field_start(line):
|
||
|
if '=' in line or '+' in line:
|
||
|
return False
|
||
|
if (line.startswith('gpio') or line.startswith('peri_') or
|
||
|
line.endswith('_sel') or line.endswith('_con')):
|
||
|
return True
|
||
|
if not ' ' in line: # and '_' in line:
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
for line in fd:
|
||
|
line = line.rstrip()
|
||
|
if line[:4] in ['GRF_', 'PMU_', 'CRU_']:
|
||
|
field = add_it(field)
|
||
|
reg = line
|
||
|
do_this = name == reg
|
||
|
elif not line or not line.startswith(' '):
|
||
|
continue
|
||
|
line = line.replace('\xe2\x80\x99', "'")
|
||
|
leading = len(line) - len(line.lstrip())
|
||
|
line = line.lstrip()
|
||
|
cols = re.split(' *', line, 3)
|
||
|
if leading > 15 or (len(cols) > 3 and is_field_start(cols[3])):
|
||
|
if is_field_start(line):
|
||
|
field = add_it(field)
|
||
|
field.AddDesc(line)
|
||
|
else:
|
||
|
if cols[0] == 'Bit' or len(cols) < 3:
|
||
|
continue
|
||
|
#print
|
||
|
#print field
|
||
|
field = add_it(field)
|
||
|
field.Setup(cols)
|
||
|
field = add_it(field)
|
||
|
|
||
|
with Printer(name) as printer:
|
||
|
for field in fields:
|
||
|
#print field
|
||
|
printer.output_regfield(field)
|
||
|
#print
|
||
|
|
||
|
def out_enum(field, suffix, value, skip_val=False):
|
||
|
str = '%s_%s' % (field.upper(), suffix.upper())
|
||
|
if not skip_val:
|
||
|
tabs = tab_to_col - len(str) / 8
|
||
|
if value > 9:
|
||
|
val_str = '%#x' % value
|
||
|
else:
|
||
|
val_str = '%d' % value
|
||
|
|
||
|
str += '%s= %s' % ('\t' * tabs, val_str)
|
||
|
print '\t%s,' % str
|
||
|
|
||
|
# Process a CSV file, e.g. from tabula
|
||
|
def process_csv(name, fd):
|
||
|
reader = csv.reader(fd)
|
||
|
|
||
|
rows = []
|
||
|
|
||
|
field = RegField()
|
||
|
for row in reader:
|
||
|
#print field.desc
|
||
|
if not row[0]:
|
||
|
field.desc.append(row[3])
|
||
|
continue
|
||
|
if field.bits:
|
||
|
if field.bits != 'Bit':
|
||
|
rows.append(field)
|
||
|
#print row
|
||
|
field = RegField(row)
|
||
|
|
||
|
with Printer(name) as printer:
|
||
|
for row in rows:
|
||
|
#print field
|
||
|
printer.output_regfield(row)
|
||
|
#print
|
||
|
|
||
|
fname = sys.argv[1]
|
||
|
name = sys.argv[2]
|
||
|
|
||
|
# Read output from pdftotext -layout
|
||
|
if 1:
|
||
|
with open(fname, 'r') as fd:
|
||
|
process_file(name, fd)
|
||
|
|
||
|
# Use tabula
|
||
|
# It seems to be better at outputting text for an entire cell in one cell.
|
||
|
# But it does not always work. E.g. GRF_GPIO7CH_IOMUX.
|
||
|
# So there is no point in using it.
|
||
|
if 0:
|
||
|
with open(fname, 'r') as fd:
|
||
|
process_csv(name, fd)
|