Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/usr/bin/perl -w
2# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
3# Copyright (C) 2019--2020 Intel Corporation
4
5use Getopt::Long qw(:config no_ignore_case);
6use File::Basename;
7
8my $ccsregs = "ccs-regs.asc";
9my $header;
10my $regarray;
11my $limitc;
12my $limith;
13my $kernel;
14my $help;
15
16GetOptions("ccsregs|c=s" => \$ccsregs,
17 "header|e=s" => \$header,
18 "regarray|r=s" => \$regarray,
19 "limitc|l=s" => \$limitc,
20 "limith|L=s" => \$limith,
21 "kernel|k" => \$kernel,
22 "help|h" => \$help) or die "can't parse options";
23
24$help = 1 if ! defined $header || ! defined $limitc || ! defined $limith;
25
26if (defined $help) {
27 print <<EOH
28$0 - Create CCS register definitions for C
29
30usage: $0 -c ccs-regs.asc -e header -r regarray -l limit-c -L limit-header [-k]
31
32 -c ccs register file
33 -e header file name
34 -r register description array file name
35 -l limit and capability array file name
36 -L limit and capability header file name
37 -k generate files for kernel space consumption
38EOH
39 ;
40 exit 0;
41}
42
43my $lh_hdr = ! defined $kernel
44 ? '#include "ccs-os.h"' . "\n"
45 : "#include <linux/bits.h>\n#include <linux/types.h>\n";
46my $uint32_t = ! defined $kernel ? 'uint32_t' : 'u32';
47my $uint16_t = ! defined $kernel ? 'uint16_t' : 'u16';
48
49open(my $R, "< $ccsregs") or die "can't open $ccsregs";
50
51open(my $H, "> $header") or die "can't open $header";
52my $A;
53if (defined $regarray) {
54 open($A, "> $regarray") or die "can't open $regarray";
55}
56open(my $LC, "> $limitc") or die "can't open $limitc";
57open(my $LH, "> $limith") or die "can't open $limith";
58
59my %this;
60
61sub is_limit_reg($) {
62 my $addr = hex $_[0];
63
64 return 0 if $addr < 0x40; # weed out status registers
65 return 0 if $addr >= 0x100 && $addr < 0xfff; # weed out configuration registers
66
67 return 1;
68}
69
70my $uc_header = basename uc $header;
71$uc_header =~ s/[^A-Z0-9]/_/g;
72
73my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n";
74my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause";
75my $note = "/*\n * Generated by $0;\n * do not modify.\n */\n";
76
77for my $fh ($A, $LC) {
78 print $fh "// $license\n$copyright$note\n" if defined $fh;
79}
80
81for my $fh ($H, $LH) {
82 print $fh "/* $license */\n$copyright$note\n";
83}
84
85sub bit_def($) {
86 my $bit = shift @_;
87
88 return "BIT($bit)" if defined $kernel;
89 return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/;
90 return "(1U << ($bit))";
91}
92
93print $H <<EOF
94#ifndef __${uc_header}__
95#define __${uc_header}__
96
97EOF
98 ;
99
100print $H "#include <linux/bits.h>\n\n" if defined $kernel;
101
102print $H <<EOF
103#define CCS_FL_BASE 16
104EOF
105 ;
106
107print $H "#define CCS_FL_16BIT " . bit_def("CCS_FL_BASE") . "\n";
108print $H "#define CCS_FL_32BIT " . bit_def("CCS_FL_BASE + 1") . "\n";
109print $H "#define CCS_FL_FLOAT_IREAL " . bit_def("CCS_FL_BASE + 2") . "\n";
110print $H "#define CCS_FL_IREAL " . bit_def("CCS_FL_BASE + 3") . "\n";
111
112print $H <<EOF
113#define CCS_R_ADDR(r) ((r) & 0xffff)
114
115EOF
116 ;
117
118print $A <<EOF
119#include <stdint.h>
120#include <stdio.h>
121#include "ccs-extra.h"
122#include "ccs-regs.h"
123
124EOF
125 if defined $A;
126
127my $uc_limith = basename uc $limith;
128$uc_limith =~ s/[^A-Z0-9]/_/g;
129
130print $LH <<EOF
131#ifndef __${uc_limith}__
132#define __${uc_limith}__
133
134$lh_hdr
135struct ccs_limit {
136 $uint32_t reg;
137 $uint16_t size;
138 $uint16_t flags;
139 const char *name;
140};
141
142EOF
143 ;
144print $LH "#define CCS_L_FL_SAME_REG " . bit_def(0) . "\n\n";
145
146print $LH <<EOF
147extern const struct ccs_limit ccs_limits[];
148
149EOF
150 ;
151
152print $LC <<EOF
153#include "ccs-limits.h"
154#include "ccs-regs.h"
155
156const struct ccs_limit ccs_limits[] = {
157EOF
158 ;
159
160my $limitcount = 0;
161my $argdescs;
162my $reglist = "const struct ccs_reg_desc ccs_reg_desc[] = {\n";
163
164sub name_split($$) {
165 my ($name, $addr) = @_;
166 my $args;
167
168 $name =~ /([^\(]+?)(\(.*)/;
169 ($name, $args) = ($1, $2);
170 $args = [split /,\s*/, $args];
171 foreach my $t (@$args) {
172 $t =~ s/[\(\)]//g;
173 $t =~ s/\//\\\//g;
174 }
175
176 return ($name, $addr, $args);
177}
178
179sub tabconv($) {
180 $_ = shift;
181
182 my @l = split "\n", $_;
183
184 map {
185 s/ {8,8}/\t/g;
186 s/\t\K +//;
187 } @l;
188
189 return (join "\n", @l) . "\n";
190}
191
192sub elem_size(@) {
193 my @flags = @_;
194
195 return 2 if grep /^16$/, @flags;
196 return 4 if grep /^32$/, @flags;
197 return 1;
198}
199
200sub arr_size($) {
201 my $this = $_[0];
202 my $size = $this->{elsize};
203 my $h = $this->{argparams};
204
205 foreach my $arg (@{$this->{args}}) {
206 my $apref = $h->{$arg};
207
208 $size *= $apref->{max} - $apref->{min} + 1;
209 }
210
211 return $size;
212}
213
214sub print_args($$$) {
215 my ($this, $postfix, $is_same_reg) = @_;
216 my ($args, $argparams, $name) =
217 ($this->{args}, $this->{argparams}, $this->{name});
218 my $varname = "ccs_reg_arg_" . (lc $name) . $postfix;
219 my @mins;
220 my @sorted_args = @{$this->{sorted_args}};
221 my $lim_arg;
222 my $size = arr_size($this);
223
224 $argdescs .= "static const struct ccs_reg_arg " . $varname . "[] = {\n";
225
226 foreach my $sorted_arg (@sorted_args) {
227 push @mins, $argparams->{$sorted_arg}->{min};
228 }
229
230 foreach my $sorted_arg (@sorted_args) {
231 my $h = $argparams->{$sorted_arg};
232
233 $argdescs .= "\t{ \"$sorted_arg\", $h->{min}, $h->{max}, $h->{elsize} },\n";
234
235 $lim_arg .= defined $lim_arg ? ", $h->{min}" : "$h->{min}";
236 }
237
238 $argdescs .= "};\n\n";
239
240 $reglist .= "\t{ CCS_R_" . (uc $name) . "(" . (join ",", (@mins)) .
241 "), $size, sizeof($varname) / sizeof(*$varname)," .
242 " \"" . (lc $name) . "\", $varname },\n";
243
244 print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . "($lim_arg), " .
245 $size . ", " . ($is_same_reg ? "CCS_L_FL_SAME_REG" : "0") .
246 ", \"$name" . (defined $this->{discontig} ? " $lim_arg" : "") . "\" },\n"
247 if is_limit_reg $this->{base_addr};
248}
249
250my $hdr_data;
251
252while (<$R>) {
253 chop;
254 s/^\s*//;
255 next if /^[#;]/ || /^$/;
256 if (s/^-\s*//) {
257 if (s/^b\s*//) {
258 my ($bit, $addr) = split /\t+/;
259 $bit = uc $bit;
260 $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) ."_$bit", bit_def($addr) . "\n";
261 } elsif (s/^f\s*//) {
262 s/[,\.-]/_/g;
263 my @a = split /\s+/;
264 my ($msb, $lsb, $this_field) = reverse @a;
265 @a = ( { "name" => "SHIFT", "addr" => $lsb, "fmt" => "%uU", },
266 { "name" => "MASK", "addr" => (1 << ($msb + 1)) - 1 - ((1 << $lsb) - 1), "fmt" => "0x%" . join(".", ($this{"elsize"} >> 2) x 2) . "x" } );
267 $this{"field"} = $this_field;
268 foreach my $ar (@a) {
269 #print $ar->{fmt}."\n";
270 $hdr_data .= sprintf "#define %-62s " . $ar->{"fmt"} . "\n", "CCS_" . (uc $this{"name"}) . (defined $this_field ? "_" . uc $this_field : "") . "_" . $ar->{"name"}, $ar->{"addr"} . "\n";
271 }
272 } elsif (s/^e\s*//) {
273 s/[,\.-]/_/g;
274 my ($enum, $addr) = split /\s+/;
275 $enum = uc $enum;
276 $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) . (defined $this{"field"} ? "_" . uc $this{"field"} : "") ."_$enum", $addr . ($addr =~ /0x/i ? "" : "U") . "\n";
277 } elsif (s/^l\s*//) {
278 my ($arg, $min, $max, $elsize, @discontig) = split /\s+/;
279 my $size;
280
281 foreach my $num ($min, $max) {
282 $num = hex $num if $num =~ /0x/i;
283 }
284
285 $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MIN_$arg"), $min . ($min =~ /0x/i ? "" : "U") . "\n";
286 $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MAX_$arg"), $max . ($max =~ /0x/i ? "" : "U") . "\n";
287
288 my $h = $this{argparams};
289
290 $h->{$arg} = { "min" => $min,
291 "max" => $max,
292 "elsize" => $elsize =~ /^0x/ ? hex $elsize : $elsize,
293 "discontig" => \@discontig };
294
295 $this{discontig} = $arg if @discontig;
296
297 next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}};
298
299 my $reg_formula = "($this{addr}";
300 my $lim_formula;
301
302 foreach my $arg (@{$this{args}}) {
303 my $d = $h->{$arg}->{discontig};
304 my $times = $h->{$arg}->{elsize} != 1 ?
305 " * " . $h->{$arg}->{elsize} : "";
306
307 if (@$d) {
308 my ($lim, $offset) = split /,/, $d->[0];
309
310 $reg_formula .= " + (($arg) < $lim ? ($arg)$times : $offset + (($arg) - $lim)$times)";
311 } else {
312 $reg_formula .= " + ($arg)$times";
313 }
314
315 $lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times";
316 }
317
318 $reg_formula .= ")\n";
319 $lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i;
320
321 print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) .
322 $this{arglist}, $reg_formula);
323
324 print $H tabconv $hdr_data;
325 undef $hdr_data;
326
327 # Sort arguments in descending order by size
328 @{$this{sorted_args}} = sort {
329 $h->{$a}->{elsize} <= $h->{$b}->{elsize}
330 } @{$this{args}};
331
332 if (defined $this{discontig}) {
333 my $da = $this{argparams}->{$this{discontig}};
334 my ($first_discontig) = split /,/, $da->{discontig}->[0];
335 my $max = $da->{max};
336
337 $da->{max} = $first_discontig - 1;
338 print_args(\%this, "", 0);
339
340 $da->{min} = $da->{max} + 1;
341 $da->{max} = $max;
342 print_args(\%this, $first_discontig, 1);
343 } else {
344 print_args(\%this, "", 0);
345 }
346
347 next unless is_limit_reg $this{base_addr};
348
349 print $LH tabconv sprintf "#define %-63s%s\n",
350 "CCS_L_" . (uc $this{name}) . "_OFFSET(" .
351 (join ", ", @{$this{args}}) . ")", "($lim_formula)";
352 }
353
354 if (! @{$this{args}}) {
355 print $H tabconv($hdr_data);
356 undef $hdr_data;
357 }
358
359 next;
360 }
361
362 my ($name, $addr, @flags) = split /\t+/, $_;
363 my $args = [];
364
365 my $sp;
366
367 ($name, $addr, $args) = name_split($name, $addr) if /\(.*\)/;
368
369 $name =~ s/[,\.-]/_/g;
370
371 my $flagstring = "";
372 my $size = elem_size(@flags);
373 $flagstring .= "| CCS_FL_16BIT " if $size eq "2";
374 $flagstring .= "| CCS_FL_32BIT " if $size eq "4";
375 $flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags;
376 $flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags;
377 $flagstring =~ s/^\| //;
378 $flagstring =~ s/ $//;
379 $flagstring = "($flagstring)" if $flagstring =~ /\|/;
380 my $base_addr = $addr;
381 $addr = "($addr | $flagstring)" if $flagstring ne "";
382
383 my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : "";
384 $hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr
385 if !@$args;
386
387 $name =~ s/\(.*//;
388
389 %this = ( name => $name,
390 addr => $addr,
391 base_addr => $base_addr,
392 argparams => {},
393 args => $args,
394 arglist => $arglist,
395 elsize => $size,
396 );
397
398 if (!@$args) {
399 $reglist .= "\t{ CCS_R_" . (uc $name) . ", 1, 0, \"" . (lc $name) . "\", NULL },\n";
400 print $H tabconv $hdr_data;
401 undef $hdr_data;
402
403 print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . ", " .
404 $this{elsize} . ", 0, \"$name\" },\n"
405 if is_limit_reg $this{base_addr};
406 }
407
408 print $LH tabconv sprintf "#define %-63s%s\n",
409 "CCS_L_" . (uc $this{name}), $limitcount++
410 if is_limit_reg $this{base_addr};
411}
412
413if (defined $A) {
414 print $A $argdescs, $reglist;
415
416 print $A "\t{ 0 }\n";
417
418 print $A "};\n";
419}
420
421print $H "\n#endif /* __${uc_header}__ */\n";
422
423print $LH tabconv sprintf "#define %-63s%s\n", "CCS_L_LAST", $limitcount;
424
425print $LH "\n#endif /* __${uc_limith}__ */\n";
426
427print $LC "\t{ 0 } /* Guardian */\n";
428print $LC "};\n";
429
430close($R);
431close($H);
432close($A) if defined $A;
433close($LC);
434close($LH);