]>
Commit | Line | Data |
---|---|---|
5effab05 | 1 | #!/usr/bin/env python3 |
002c634c SG |
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 | ||
19 | import csv | |
20 | import re | |
21 | import sys | |
22 | ||
23 | tab_to_col = 3 | |
24 | ||
25 | class 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): | |
5effab05 SG |
46 | print(self) |
47 | print() | |
002c634c SG |
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 | ||
54 | class 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): | |
5effab05 SG |
68 | print('/* %s */' % self.name) |
69 | print('enum {') | |
002c634c SG |
70 | |
71 | def output_footer(self): | |
5effab05 | 72 | print('};'); |
002c634c SG |
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: | |
5effab05 | 100 | print() |
002c634c SG |
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 | ||
114 | def 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 | ||
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 | ||
167 | ||
168 | def 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) | |
5effab05 | 178 | print('\t%s,' % str) |
002c634c SG |
179 | |
180 | # Process a CSV file, e.g. from tabula | |
181 | def 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 | ||
203 | ||
204 | fname = sys.argv[1] | |
205 | name = sys.argv[2] | |
206 | ||
207 | # Read output from pdftotext -layout | |
208 | if 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. | |
216 | if 0: | |
217 | with open(fname, 'r') as fd: | |
218 | process_csv(name, fd) |