Skip to content
Snippets Groups Projects
rkmux.py 5.95 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/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)