b7538640edcfb210201ca08a46e03300bb56e67d
[fw/openocd] / contrib / loaders / flash / stmqspi / gpio_conf_stm32.pl
1 #!/usr/bin/perl
2 #
3 # Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+
4 # and F1 (for 'stmqspi' and 'cmspi' drivers).
5 #
6 # Each pin is configured by "PortAndBit:Conf:Speed"
7 #  'PortAndBit' specifies Port and bit number
8 #  'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input),
9 #    (each optionally by 'P' (push-pull) or 'O' (open-drain)),
10 #    (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down))
11 #  'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high)
12 #
13 # Port configuration can be given on command line as a single string (pins separated by commas)
14 # or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the
15 # corresponding header. The precise spelling in these files doesn't seem to be consistent, though ...
16 #
17 # Pins have to be ordered this way:
18 #  - I2C: SDA, SCL
19 #  - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI
20 #  - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI
21 #  - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI
22 # For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2
23 # For octal flash: NCS, CLK, DQS, IO7 down to IO0
24
25 use strict;
26 use Getopt::Std;
27
28 my $GPIO_BASE;
29 my $Conf;
30 my $STM32F1 = 0;
31
32 # "Blue-Pill stm32f103cbt6 board w/ cmspi
33 #$STM32F1 = 1;
34 #$GPIO_BASE = 0x40010800;
35 #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V";
36 #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V";
37
38 #$STM32F1 = 1;
39 #$GPIO_BASE = 0x40010800;
40 #$Conf = "PB07:INUP:V, PB06:INUP:V";
41
42 # mini-stm32f030f4p6 board w/ cmspi
43 #$GPIO_BASE = 0x48000000;
44 #$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V";
45
46 # stm32f407vet6 board w/ cmspi
47 #$GPIO_BASE = 0x40020000;
48 #$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V";
49
50 # stm32f412g-disco quad
51 #$GPIO_BASE = 0x40020000;
52 #$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V";
53
54 # stm32f413h-disco
55 #$GPIO_BASE = 0x40020000;
56 #$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V";
57
58 # stm32f469i-disco quad
59 #$GPIO_BASE = 0x40020000;
60 #$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V";
61 # w/ cmspi
62 #$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V";
63
64 # stm32f723e-disco quad
65 #$GPIO_BASE = 0x40020000;
66 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
67
68 # stm32f746g-disco quad
69 #$GPIO_BASE = 0x40020000;
70 #Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
71 # w/ cmspi
72 #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V";
73
74 # stm32f769i-disco quad
75 #$GPIO_BASE = 0x40020000;
76 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
77 # w/ cmspi
78 #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, ";
79
80 # b-l475e-iot01a quad
81 #$GPIO_BASE = 0x48000000;
82 #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
83
84 # stm32l476g-disco quad
85 #$GPIO_BASE = 0x48000000;
86 #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
87
88 # stm32l496g-disco quad
89 #$GPIO_BASE = 0x48000000;
90 #$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V";
91
92 # stm32l4r9i-disco octal
93 #$GPIO_BASE = 0x48000000;
94 #$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, "
95 #      . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V";
96
97 # stm32l4p5g-disco octal/octal
98 #$GPIO_BASE = 0x48000000;
99 #$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, "
100 #      . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V";
101 #$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, "
102 #      . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V";
103
104 # nucleo-f767zi dual quad
105 #$GPIO_BASE = 0x40020000;
106 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
107 #      . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
108 # w/ cmspi
109 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
110 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
111
112 # nucleo-h743zi dual quad
113 #$GPIO_BASE = 0x58020000;
114 #$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
115 #      . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
116 # w/ cmspi
117 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
118 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
119
120 # nucleo-h7a3zi dual quad
121 #$GPIO_BASE = 0x58020000;
122 #$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, "
123 #      . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V";
124 # w/ cmspi
125 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
126 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
127
128 # nucleo-l4r5zi one dual quad single NCS
129 #$GPIO_BASE = 0x48000000;
130 #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
131 #      . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
132 # w/ cmspi
133 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
134 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
135
136 # nucleo-l552ze-q dual quad with single NCS
137 #$GPIO_BASE = 0x42020000;
138 #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
139 #      . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
140 # w/ cmspi
141 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
142 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
143
144 # nucleo-g071rb dual quad
145 #$GPIO_BASE = 0x50000000;
146 #$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H";
147 #$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V";
148
149 # nucleo-g474re dual quad with single NCS
150 #$GPIO_BASE = 0x48000000;
151 #$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, "
152 #      . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V";
153 # w/ cmspi
154 #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V";
155 #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V";
156
157 # stm32h745i-disco dual quad with single NCS
158 #$GPIO_BASE = 0x58020000;
159 #$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
160 #      . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
161
162 # stm32h747i-disco dual quad with single NCS
163 #GPIO_BASE = 0x58020000;
164 #$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
165 #      . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
166
167 # stm32h7b3i-disco octal
168 #$GPIO_BASE = 0x58020000;
169 #$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, "
170 #      . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V";
171
172 # stm32h735g-disco octal
173 #$GPIO_BASE = 0x58020000;
174 #$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, "
175 #      . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
176
177 # stm32l562e-disco octal
178 #$GPIO_BASE = 0x42020000;
179 #$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, "
180 #      . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V";
181
182 &getopts('b:c:f:t');
183 if ($Getopt::Std::opt_b eq '')
184 {
185         if ($GPIO_BASE eq '')
186         {
187                 die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]");
188         }
189 }
190 else
191 {
192         $GPIO_BASE = eval $Getopt::Std::opt_b;
193 }
194
195 if ($Getopt::Std::opt_c eq '')
196 {
197         if (($Conf eq '') && ($Getopt::Std::opt_f eq ''))
198         {
199                 die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )");
200         }
201 }#
202 else
203 {
204         $Conf = $Getopt::Std::opt_c . ',';
205 }
206
207 $STM32F1 = $Getopt::Std::opt_t;
208
209 my $Sep = "\t";
210 my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# ";
211
212 my $GPIO_OFFS;
213 my $GPIO_CRL;
214 my $GPIO_CRH;
215 my $GPIO_MODER;
216 my $GPIO_OTYPER;
217 my $GPIO_OSPEEDR;
218 my $GPIO_PUPDR;
219 my $GPIO_IDR;
220 my $GPIO_ODR;
221 my $GPIO_AFRL;
222 my $GPIO_AFRH;
223
224 if ($STM32F1)
225 {
226         # offsets for F1 devices
227         $GPIO_OFFS = 0x400;
228         $GPIO_CRL = 0x00;
229         $GPIO_CRH = 0x04;
230         $GPIO_IDR = 0x08;
231         $GPIO_ODR = 0x0C;
232 }
233 else
234 {
235         # these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now
236         $GPIO_OFFS = 0x400;
237         $GPIO_MODER = 0x00;
238         $GPIO_OTYPER = 0x04;
239         $GPIO_OSPEEDR = 0x08;
240         $GPIO_PUPDR = 0x0C;
241         $GPIO_IDR = 0x10;
242         $GPIO_ODR = 0x14;
243         $GPIO_AFRL = 0x20;
244         $GPIO_AFRH = 0x24;
245 }
246
247 my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } );
248 my @Port = ( );
249 my $Exor;
250 my %Conf;
251 my $Pins = "${Sep}#";
252
253 my $pins;
254 my $altn;
255 my %defs;
256
257 if ($Getopt::Std::opt_f ne '')
258 {
259         open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f");
260         while (my $line = <CONF_FILE>)
261         {
262                 if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/)
263                 {
264                         if ($line =~ /#define\s+(\w+)\s+(\w+)/)
265                         {
266                                 $defs{$1} = $2;
267                         }
268                         else
269                         {
270                                 die($line);
271                         }
272                 }
273                 elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/)
274                 {
275                         $Conf{$4} = sprintf("%s%02d", $1, $2);
276                 }
277                 elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/)
278                 {
279                         $pins = $1;
280                         while ($line !~ /;/)
281                         {
282                                 $line = <CONF_FILE>;
283                                 $line =~ /^\s*([^;]+\w)/;
284                                 $pins .= $1;
285                         }
286                 }
287                 elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/)
288                 {
289                         $altn = $1;
290                 }
291                 elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/)
292                 {
293                         my $port = $1;
294                         if ($port =~ /GPIO([A-Z])/)
295                         {
296                                 $port = $1;
297                         }
298                         elsif (exists($defs{$port}))
299                         {
300                                 $defs{$port} =~ /GPIO([A-Z])/;
301                                 $port = $1;
302                         }
303                         else
304                         {
305                                 printf("\n");
306                                 next;
307                         }
308                         my @pin = split(/\s*\|\s*/, $pins);
309                         foreach my $pin (@pin)
310                         {
311                                 my $bit;
312                                 if (exists($defs{$pin}))
313                                 {
314                                         $defs{$pin} =~ /GPIO_PIN_([0-9]+)/;
315                                         $bit = $1;
316                                 }
317                                 else
318                                 {
319                                         $pin =~ /GPIO_PIN_([0-9]+)/;
320                                         $bit = $1;
321                                 }
322                                 $Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn);
323                         }
324                         $pins = '';
325                         $altn = 0;
326                 }
327         }
328         close(CONF_FILE);
329 }
330 else
331 {
332         my @names = ( );
333         my @conf = split(/\s*,\s*/, $Conf);
334
335         if (@conf == 2)
336         {
337                 push(@names, 'SDA', 'SCL');
338         } else {
339                 if (@conf == 3)
340                 {
341                         push(@names, 'NCS', 'CLK', 'IO0/DIO');
342                 }
343                 elsif (@conf == 4)
344                 {
345                         push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI');
346                 }
347                 elsif (@conf == 6)
348                 {
349                         push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI');
350                 }
351                 elsif (@conf == 10)
352                 {
353                         push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
354                         push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
355                 }
356                 elsif (@conf == 11)
357                 {
358                         push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
359                         push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
360                 }
361                 else
362                 {
363                         die("invalid config");
364                 }
365         }
366
367         for (my $index = 0; $index < @conf; $index++)
368         {
369                 uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
370                 $Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2);
371         }
372         chop($Pins);
373 }
374
375 if (exists $Conf{'BK1_IO0'})
376 {
377         # QuadSPI on F4, F7, H7
378         my $line;
379         for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0')
380         {
381                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
382         }
383 }
384
385 if (exists $Conf{'BK2_IO0'})
386 {
387         # QuadSPI on F4, F7, H7
388         my $line;
389         for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0')
390         {
391                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
392         }
393 }
394
395 if (exists $Conf{'P1_IO0'})
396 {
397         # OctoSPI on L4+, L5, H7
398         my $line;
399         for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4',
400                            'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0')
401         {
402                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
403         }
404 }
405
406 if (exists $Conf{'P2_IO0'})
407 {
408         # OctoSPI on L4+, H7
409         my $line;
410         for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4',
411                            'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0')
412         {
413                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
414         }
415 }
416
417 my @Col = ( );
418 my @conf = split(/\s*,\s*/, $Conf);
419
420 if (@conf == 3)
421 {
422         splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE');
423 }
424 elsif (@conf == 4)
425 {
426         splice(@conf, 2, 0, 'NONE', 'NONE');
427 }
428
429 foreach my $line (@conf)
430 {
431         $line = uc($line);
432         $line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
433         my $port = $1;
434         my $pin = $2;
435         my $conf = $3;
436         my $speed = $4;
437
438         my $MODER = 0x0;
439         my $OTYPER = 0x0;
440         my $OSPEEDR = 0x0;
441         my $PUPDR = 0x0;
442         my $AFR = 0x0;
443         my $num = ord(${port}) - ord('A');
444         my $out = $Out[$num];
445
446         (exists $$out{'DEF'}) || ($$out{'DEF'} = 0);
447
448         if ($conf eq '')
449         {
450                 if ($line ne 'NONE')
451                 {
452                         printf(STDERR "invalid conf %s\n", $line);
453                 }
454                 next;
455         }
456         elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/)
457         {
458                 if ($STM32F1)
459                 {
460                         printf(STDERR "no alternate %s for F1 family\n", $line);
461                         next;
462                 }
463                 if (($1 < 0) || ($1 > 15))
464                 {
465                         printf(STDERR "invalid alternate %s\n", $line);
466                         next;
467                 }
468                 $MODER = 0x2;
469                 $AFR = $1;
470                 if ($pin <= 7)
471                 {
472                         $$out{'AFRL_H'} |= ($AFR << (${pin} << 2));
473                         $$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2));
474                 }
475                 else
476                 {
477                         $$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2));
478                         $$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2));
479                 }
480                 if ($2 ne '') {
481                         $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
482                         $$out{'OTYPER_H'} |= ($OTYPER << $pin);
483                         $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
484                 }
485                 $PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0);
486                 $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
487                 $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
488                 $conf = sprintf("AF%02d%s%s", $AFR, $2, $3);
489         }
490         elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/)
491         {
492                 if ($STM32F1)
493                 {
494                         $MODER = ($1 eq '') ? 0x4 : 0x8;
495                         ($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin}));
496                         ($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin}));
497                 }
498                 else
499                 {
500                         $MODER = 0x0;
501                         if ($1 ne '')
502                         {
503                                 $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
504                                 $$out{'OTYPER_H'} |= ($OTYPER << $pin);
505                                 $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
506                         }
507                         $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
508                         $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
509                         $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
510                 }
511                 ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
512                 ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
513         }
514         elsif ($conf =~ /^P(P|O)(|UP|DO)$/)
515         {
516                 if ($STM32F1)
517                 {
518                         $MODER = ($1 eq 'O') ? 0x4 : 0x0;
519                         $MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1));
520                         if ($2 ne '')
521                         {
522                                 printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line);
523                         }
524                 }
525                 else
526                 {
527                         $MODER = 0x1;
528                         $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
529                         $$out{'OTYPER_H'} |= ($OTYPER << $pin);
530                         $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
531                         $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
532                         $$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1));
533                         $$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1));
534                 }
535                 ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
536                 ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
537         }
538         else
539         {
540                 printf(STDERR "invalid conf %s\n", $line);
541                 next;
542         }
543
544         if ($$out{'DEF'} & (1<< ${pin}))
545         {
546                 printf(STDERR "redefinition: %s\n", $line);
547         }
548
549         if ($STM32F1)
550         {
551                 if ($pin >= 8)
552                 {
553                         $$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2));
554                         $$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
555                 }
556                 else
557                 {
558                         $$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2));
559                         $$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
560                 }
561
562                 $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port)  - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
563                 my $exor = 0xB << (($pin & 0x7) << 2);
564                 (($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X",
565                         ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF,
566                         ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor));
567         }
568         else
569         {
570                 $$out{'DEF'} |= (1 << ${pin});
571                 $$out{'MODER_H'} |= ($MODER << (${pin} << 1));
572                 $$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1));
573
574                 $OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0)));
575                 $$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1));
576                 $$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1));
577
578                 $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port)  - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
579                 my $exor = (0x1 << ($pin << 1));
580                 ($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF,
581                         (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor));
582         }
583
584         push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed));
585         push(@Col, $Exor);
586 }
587
588 my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF);
589 for (my $i = 0; $i < @Col; $i++)
590 {
591         if (($i != 0) && (($i % 2) == 0))
592         {
593                 (($i + 1) < @Col) && ($Col .= "\\\n${Sep}");
594         }
595         $Col .= sprintf("%s ", $Col[$i]);
596 }
597 printf("%s\n", $Col);
598
599 my @Col = ( );
600 my $Set;
601 for (my $i = 0; $i < @Out; $i++)
602 {
603         my $out = $Out[$i];
604         my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS};
605         my $count = 0;
606
607         if ($STM32F1)
608         {
609                 if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} |
610                                 $$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0)
611                 {
612                         push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
613
614                         $Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
615                                 join(", ", sort({ $b cmp $a } @{$Port[$i]})));
616
617                         (($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) &&
618                                 ($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'}));
619
620                         (($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) &&
621                                 ($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'}));
622
623                         (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
624                                 ($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
625                 }
626         }
627         else
628         {
629                 if (($$out{'MODER_H'} | $$out{'MODER_L'} |
630                         $$out{'OTYPER_H'} | $$out{'OTYPER_L'} |
631                         $$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} |
632                         $$out{'PUPDR_H'} | $$out{'PUPDR_L'} |
633                         $$out{'ODR_H'} | $$out{'ODR_L'} |
634                         $$out{'AFRL_H'} | $$out{'AFRL_L'} |
635                         $$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0)
636                 {
637                         push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
638
639                         $Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
640                                 join(", ", sort({ $b cmp $a } @{$Port[$i]})));
641
642                         (($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) &&
643                                 ($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'}));
644
645                         (($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) &&
646                                 ($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'}));
647
648                         (($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) &&
649                                 ($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'}));
650
651                         (($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) &&
652                                 ($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'}));
653
654                         (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
655                                 ($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
656
657                         (($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) &&
658                                 ($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'}));
659
660                         (($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) &&
661                                 ($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'}));
662                 }
663         }
664 }
665
666 my $Col = '';
667 for (my $i = 0; $i < @Col; $i++)
668 {
669         if (($i % 6) == 0)
670         {
671                 chop($Col);
672                 (($i + 1) < @Col) && ($Col .= "\n${Sep}#");
673         }
674         $Col .= sprintf(" %s,", $Col[$i]);
675 }
676 chop($Col);
677 #printf("\n%s\n", $Pins);
678 printf("%s\n", $Col);
679 printf("%s\n", $Set);