| #!/usr/bin/env python2 |
| |
| # 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) |