1#!/usr/bin/python 2 3# Script to create enums from datasheet register tables 4# 5# Usage: 6# 7# First, create a text file from the datasheet: 8# pdftotext -layout /path/to/rockchip-3288-trm.pdf /tmp/asc 9# 10# Then use this script to output the #defines for a particular register: 11# ./tools/rkmux.py GRF_GPIO4C_IOMUX 12# 13# It will create output suitable for putting in a header file, with SHIFT and 14# MASK values for each bitfield in the register. 15# 16# Note: this tool is not perfect and you may need to edit the resulting code. 17# But it should speed up the process. 18 19import csv 20import re 21import sys 22 23tab_to_col = 3 24 25class RegField: 26 def __init__(self, cols=None): 27 if cols: 28 self.bits, self.attr, self.reset_val, self.desc = ( 29 [x.strip() for x in cols]) 30 self.desc = [self.desc] 31 else: 32 self.bits = '' 33 self.attr = '' 34 self.reset_val = '' 35 self.desc = [] 36 37 def Setup(self, cols): 38 self.bits, self.attr, self.reset_val = cols[0:3] 39 if len(cols) > 3: 40 self.desc.append(cols[3]) 41 42 def AddDesc(self, desc): 43 self.desc.append(desc) 44 45 def Show(self): 46 print self 47 print 48 self.__init__() 49 50 def __str__(self): 51 return '%s,%s,%s,%s' % (self.bits, self.attr, self.reset_val, 52 '\n'.join(self.desc)) 53 54class Printer: 55 def __init__(self, name): 56 self.first = True 57 self.name = name 58 self.re_sel = re.compile("[1-9]'b([01]+): (.*)") 59 60 def __enter__(self): 61 return self 62 63 def __exit__(self, type, value, traceback): 64 if not self.first: 65 self.output_footer() 66 67 def output_header(self): 68 print '/* %s */' % self.name 69 print 'enum {' 70 71 def output_footer(self): 72 print '};'; 73 74 def output_regfield(self, regfield): 75 lines = regfield.desc 76 field = lines[0] 77 #print 'field:', field 78 if field in ['reserved', 'reserve', 'write_enable', 'write_mask']: 79 return 80 if field.endswith('_sel') or field.endswith('_con'): 81 field = field[:-4] 82 elif field.endswith(' iomux'): 83 field = field[:-6] 84 elif field.endswith('_mode') or field.endswith('_mask'): 85 field = field[:-5] 86 #else: 87 #print 'bad field %s' % field 88 #return 89 field = field.upper() 90 if ':' in regfield.bits: 91 bit_high, bit_low = [int(x) for x in regfield.bits.split(':')] 92 else: 93 bit_high = bit_low = int(regfield.bits) 94 bit_width = bit_high - bit_low + 1 95 mask = (1 << bit_width) - 1 96 if self.first: 97 self.first = False 98 self.output_header() 99 else: 100 print 101 out_enum(field, 'shift', bit_low) 102 out_enum(field, 'mask', mask) 103 next_val = -1 104 #print 'lines: %s', lines 105 for line in lines: 106 m = self.re_sel.match(line) 107 if m: 108 val, enum = int(m.group(1), 2), m.group(2) 109 if enum not in ['reserved', 'reserve']: 110 out_enum(field, enum, val, val == next_val) 111 next_val = val + 1 112 113 114def process_file(name, fd): 115 field = RegField() 116 reg = '' 117 118 fields = [] 119 120 def add_it(field): 121 if field.bits: 122 if reg == name: 123 fields.append(field) 124 field = RegField() 125 return field 126 127 def is_field_start(line): 128 if '=' in line or '+' in line: 129 return False 130 if (line.startswith('gpio') or line.startswith('peri_') or 131 line.endswith('_sel') or line.endswith('_con')): 132 return True 133 if not ' ' in line: # and '_' in line: 134 return True 135 return False 136 137 for line in fd: 138 line = line.rstrip() 139 if line[:4] in ['GRF_', 'PMU_', 'CRU_']: 140 field = add_it(field) 141 reg = line 142 do_this = name == reg 143 elif not line or not line.startswith(' '): 144 continue 145 line = line.replace('\xe2\x80\x99', "'") 146 leading = len(line) - len(line.lstrip()) 147 line = line.lstrip() 148 cols = re.split(' *', line, 3) 149 if leading > 15 or (len(cols) > 3 and is_field_start(cols[3])): 150 if is_field_start(line): 151 field = add_it(field) 152 field.AddDesc(line) 153 else: 154 if cols[0] == 'Bit' or len(cols) < 3: 155 continue 156 #print 157 #print field 158 field = add_it(field) 159 field.Setup(cols) 160 field = add_it(field) 161 162 with Printer(name) as printer: 163 for field in fields: 164 #print field 165 printer.output_regfield(field) 166 #print 167 168def out_enum(field, suffix, value, skip_val=False): 169 str = '%s_%s' % (field.upper(), suffix.upper()) 170 if not skip_val: 171 tabs = tab_to_col - len(str) / 8 172 if value > 9: 173 val_str = '%#x' % value 174 else: 175 val_str = '%d' % value 176 177 str += '%s= %s' % ('\t' * tabs, val_str) 178 print '\t%s,' % str 179 180# Process a CSV file, e.g. from tabula 181def process_csv(name, fd): 182 reader = csv.reader(fd) 183 184 rows = [] 185 186 field = RegField() 187 for row in reader: 188 #print field.desc 189 if not row[0]: 190 field.desc.append(row[3]) 191 continue 192 if field.bits: 193 if field.bits != 'Bit': 194 rows.append(field) 195 #print row 196 field = RegField(row) 197 198 with Printer(name) as printer: 199 for row in rows: 200 #print field 201 printer.output_regfield(row) 202 #print 203 204fname = sys.argv[1] 205name = sys.argv[2] 206 207# Read output from pdftotext -layout 208if 1: 209 with open(fname, 'r') as fd: 210 process_file(name, fd) 211 212# Use tabula 213# It seems to be better at outputting text for an entire cell in one cell. 214# But it does not always work. E.g. GRF_GPIO7CH_IOMUX. 215# So there is no point in using it. 216if 0: 217 with open(fname, 'r') as fd: 218 process_csv(name, fd) 219