Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/perl -w
0002 # SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
0003 # Copyright (C) 2019--2020 Intel Corporation
0004 
0005 use Getopt::Long qw(:config no_ignore_case);
0006 use File::Basename;
0007 
0008 my $ccsregs = "ccs-regs.asc";
0009 my $header;
0010 my $regarray;
0011 my $limitc;
0012 my $limith;
0013 my $kernel;
0014 my $help;
0015 
0016 GetOptions("ccsregs|c=s" => \$ccsregs,
0017        "header|e=s" => \$header,
0018        "regarray|r=s" => \$regarray,
0019        "limitc|l=s" => \$limitc,
0020        "limith|L=s" => \$limith,
0021        "kernel|k" => \$kernel,
0022        "help|h" => \$help) or die "can't parse options";
0023 
0024 $help = 1 if ! defined $header || ! defined $limitc || ! defined $limith;
0025 
0026 if (defined $help) {
0027     print <<EOH
0028 $0 - Create CCS register definitions for C
0029 
0030 usage: $0 -c ccs-regs.asc -e header -r regarray -l limit-c -L limit-header [-k]
0031 
0032     -c ccs register file
0033     -e header file name
0034     -r register description array file name
0035     -l limit and capability array file name
0036     -L limit and capability header file name
0037     -k generate files for kernel space consumption
0038 EOH
0039       ;
0040     exit 0;
0041 }
0042 
0043 my $lh_hdr = ! defined $kernel
0044     ? '#include "ccs-os.h"' . "\n"
0045     : "#include <linux/bits.h>\n#include <linux/types.h>\n";
0046 my $uint32_t = ! defined $kernel ? 'uint32_t' : 'u32';
0047 my $uint16_t = ! defined $kernel ? 'uint16_t' : 'u16';
0048 
0049 open(my $R, "< $ccsregs") or die "can't open $ccsregs";
0050 
0051 open(my $H, "> $header") or die "can't open $header";
0052 my $A;
0053 if (defined $regarray) {
0054     open($A, "> $regarray") or die "can't open $regarray";
0055 }
0056 open(my $LC, "> $limitc") or die "can't open $limitc";
0057 open(my $LH, "> $limith") or die "can't open $limith";
0058 
0059 my %this;
0060 
0061 sub is_limit_reg($) {
0062     my $addr = hex $_[0];
0063 
0064     return 0 if $addr < 0x40; # weed out status registers
0065     return 0 if $addr >= 0x100 && $addr < 0xfff; # weed out configuration registers
0066 
0067     return 1;
0068 }
0069 
0070 my $uc_header = basename uc $header;
0071 $uc_header =~ s/[^A-Z0-9]/_/g;
0072 
0073 my $copyright = "/* Copyright (C) 2019--2020 Intel Corporation */\n";
0074 my $license = "SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause";
0075 my $note = "/*\n * Generated by $0;\n * do not modify.\n */\n";
0076 
0077 for my $fh ($A, $LC) {
0078     print $fh "// $license\n$copyright$note\n" if defined $fh;
0079 }
0080 
0081 for my $fh ($H, $LH) {
0082     print $fh "/* $license */\n$copyright$note\n";
0083 }
0084 
0085 sub bit_def($) {
0086     my $bit = shift @_;
0087 
0088     return "BIT($bit)" if defined $kernel;
0089     return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/;
0090     return "(1U << ($bit))";
0091 }
0092 
0093 print $H <<EOF
0094 #ifndef __${uc_header}__
0095 #define __${uc_header}__
0096 
0097 EOF
0098   ;
0099 
0100 print $H "#include <linux/bits.h>\n\n" if defined $kernel;
0101 
0102 print $H <<EOF
0103 #define CCS_FL_BASE     16
0104 EOF
0105   ;
0106 
0107 print $H "#define CCS_FL_16BIT      " . bit_def("CCS_FL_BASE") . "\n";
0108 print $H "#define CCS_FL_32BIT      " . bit_def("CCS_FL_BASE + 1") . "\n";
0109 print $H "#define CCS_FL_FLOAT_IREAL    " . bit_def("CCS_FL_BASE + 2") . "\n";
0110 print $H "#define CCS_FL_IREAL      " . bit_def("CCS_FL_BASE + 3") . "\n";
0111 
0112 print $H <<EOF
0113 #define CCS_R_ADDR(r)       ((r) & 0xffff)
0114 
0115 EOF
0116   ;
0117 
0118 print $A <<EOF
0119 #include <stdint.h>
0120 #include <stdio.h>
0121 #include "ccs-extra.h"
0122 #include "ccs-regs.h"
0123 
0124 EOF
0125     if defined $A;
0126 
0127 my $uc_limith = basename uc $limith;
0128 $uc_limith =~ s/[^A-Z0-9]/_/g;
0129 
0130 print $LH <<EOF
0131 #ifndef __${uc_limith}__
0132 #define __${uc_limith}__
0133 
0134 $lh_hdr
0135 struct ccs_limit {
0136     $uint32_t reg;
0137     $uint16_t size;
0138     $uint16_t flags;
0139     const char *name;
0140 };
0141 
0142 EOF
0143   ;
0144 print $LH "#define CCS_L_FL_SAME_REG    " . bit_def(0) . "\n\n";
0145 
0146 print $LH <<EOF
0147 extern const struct ccs_limit ccs_limits[];
0148 
0149 EOF
0150   ;
0151 
0152 print $LC <<EOF
0153 #include "ccs-limits.h"
0154 #include "ccs-regs.h"
0155 
0156 const struct ccs_limit ccs_limits[] = {
0157 EOF
0158   ;
0159 
0160 my $limitcount = 0;
0161 my $argdescs;
0162 my $reglist = "const struct ccs_reg_desc ccs_reg_desc[] = {\n";
0163 
0164 sub name_split($$) {
0165     my ($name, $addr) = @_;
0166     my $args;
0167 
0168     $name =~ /([^\(]+?)(\(.*)/;
0169     ($name, $args) = ($1, $2);
0170     $args = [split /,\s*/, $args];
0171     foreach my $t (@$args) {
0172         $t =~ s/[\(\)]//g;
0173         $t =~ s/\//\\\//g;
0174     }
0175 
0176     return ($name, $addr, $args);
0177 }
0178 
0179 sub tabconv($) {
0180     $_ = shift;
0181 
0182     my @l = split "\n", $_;
0183 
0184     map {
0185         s/ {8,8}/\t/g;
0186         s/\t\K +//;
0187     } @l;
0188 
0189     return (join "\n", @l) . "\n";
0190 }
0191 
0192 sub elem_size(@) {
0193     my @flags = @_;
0194 
0195     return 2 if grep /^16$/, @flags;
0196     return 4 if grep /^32$/, @flags;
0197     return 1;
0198 }
0199 
0200 sub arr_size($) {
0201     my $this = $_[0];
0202     my $size = $this->{elsize};
0203     my $h = $this->{argparams};
0204 
0205     foreach my $arg (@{$this->{args}}) {
0206         my $apref = $h->{$arg};
0207 
0208         $size *= $apref->{max} - $apref->{min} + 1;
0209     }
0210 
0211     return $size;
0212 }
0213 
0214 sub print_args($$$) {
0215     my ($this, $postfix, $is_same_reg) = @_;
0216     my ($args, $argparams, $name) =
0217       ($this->{args}, $this->{argparams}, $this->{name});
0218     my $varname = "ccs_reg_arg_" . (lc $name) . $postfix;
0219     my @mins;
0220     my @sorted_args = @{$this->{sorted_args}};
0221     my $lim_arg;
0222     my $size = arr_size($this);
0223 
0224     $argdescs .= "static const struct ccs_reg_arg " . $varname . "[] = {\n";
0225 
0226     foreach my $sorted_arg (@sorted_args) {
0227         push @mins, $argparams->{$sorted_arg}->{min};
0228     }
0229 
0230     foreach my $sorted_arg (@sorted_args) {
0231         my $h = $argparams->{$sorted_arg};
0232 
0233         $argdescs .= "\t{ \"$sorted_arg\", $h->{min}, $h->{max}, $h->{elsize} },\n";
0234 
0235         $lim_arg .= defined $lim_arg ? ", $h->{min}" : "$h->{min}";
0236     }
0237 
0238     $argdescs .= "};\n\n";
0239 
0240     $reglist .= "\t{ CCS_R_" . (uc $name) . "(" . (join ",", (@mins)) .
0241       "), $size, sizeof($varname) / sizeof(*$varname)," .
0242         " \"" . (lc $name) . "\", $varname },\n";
0243 
0244     print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . "($lim_arg), " .
0245       $size . ", " . ($is_same_reg ? "CCS_L_FL_SAME_REG" : "0") .
0246         ", \"$name" . (defined $this->{discontig} ? " $lim_arg" : "") . "\" },\n"
0247           if is_limit_reg $this->{base_addr};
0248 }
0249 
0250 my $hdr_data;
0251 
0252 while (<$R>) {
0253     chop;
0254     s/^\s*//;
0255     next if /^[#;]/ || /^$/;
0256     if (s/^-\s*//) {
0257         if (s/^b\s*//) {
0258             my ($bit, $addr) = split /\t+/;
0259             $bit = uc $bit;
0260             $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) ."_$bit", bit_def($addr) . "\n";
0261         } elsif (s/^f\s*//) {
0262             s/[,\.-]/_/g;
0263             my @a = split /\s+/;
0264             my ($msb, $lsb, $this_field) = reverse @a;
0265                 @a = ( { "name" => "SHIFT", "addr" => $lsb, "fmt" => "%uU", },
0266                    { "name" => "MASK", "addr" => (1 << ($msb + 1)) - 1 - ((1 << $lsb) - 1), "fmt" => "0x%" . join(".", ($this{"elsize"} >> 2) x 2) . "x" } );
0267             $this{"field"} = $this_field;
0268             foreach my $ar (@a) {
0269                 #print $ar->{fmt}."\n";
0270                 $hdr_data .= sprintf "#define %-62s " . $ar->{"fmt"} . "\n", "CCS_" . (uc $this{"name"}) . (defined $this_field ? "_" . uc $this_field : "") . "_" . $ar->{"name"}, $ar->{"addr"} . "\n";
0271             }
0272         } elsif (s/^e\s*//) {
0273             s/[,\.-]/_/g;
0274             my ($enum, $addr) = split /\s+/;
0275             $enum = uc $enum;
0276             $hdr_data .= sprintf "#define %-62s %s", "CCS_" . (uc ${this{name}}) . (defined $this{"field"} ? "_" . uc $this{"field"} : "") ."_$enum", $addr . ($addr =~ /0x/i ? "" : "U") . "\n";
0277         } elsif (s/^l\s*//) {
0278             my ($arg, $min, $max, $elsize, @discontig) = split /\s+/;
0279             my $size;
0280 
0281             foreach my $num ($min, $max) {
0282                 $num = hex $num if $num =~ /0x/i;
0283             }
0284 
0285             $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MIN_$arg"), $min . ($min =~ /0x/i ? "" : "U") . "\n";
0286             $hdr_data .= sprintf "#define %-62s %s", "CCS_LIM_" . (uc ${this{name}} . "_MAX_$arg"), $max . ($max =~ /0x/i ? "" : "U") . "\n";
0287 
0288             my $h = $this{argparams};
0289 
0290             $h->{$arg} = { "min" => $min,
0291                        "max" => $max,
0292                        "elsize" => $elsize =~ /^0x/ ? hex $elsize : $elsize,
0293                        "discontig" => \@discontig };
0294 
0295             $this{discontig} = $arg if @discontig;
0296 
0297             next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}};
0298 
0299             my $reg_formula = "($this{addr}";
0300             my $lim_formula;
0301 
0302             foreach my $arg (@{$this{args}}) {
0303                 my $d = $h->{$arg}->{discontig};
0304                 my $times = $h->{$arg}->{elsize} != 1 ?
0305                   " * " . $h->{$arg}->{elsize} : "";
0306 
0307                 if (@$d) {
0308                     my ($lim, $offset) = split /,/, $d->[0];
0309 
0310                     $reg_formula .= " + (($arg) < $lim ? ($arg)$times : $offset + (($arg) - $lim)$times)";
0311                 } else {
0312                     $reg_formula .= " + ($arg)$times";
0313                 }
0314 
0315                 $lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times";
0316             }
0317 
0318             $reg_formula .= ")\n";
0319             $lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i;
0320 
0321             print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) .
0322               $this{arglist}, $reg_formula);
0323 
0324             print $H tabconv $hdr_data;
0325             undef $hdr_data;
0326 
0327             # Sort arguments in descending order by size
0328             @{$this{sorted_args}} = sort {
0329                 $h->{$a}->{elsize} <= $h->{$b}->{elsize}
0330             } @{$this{args}};
0331 
0332             if (defined $this{discontig}) {
0333                 my $da = $this{argparams}->{$this{discontig}};
0334                 my ($first_discontig) = split /,/, $da->{discontig}->[0];
0335                 my $max = $da->{max};
0336 
0337                 $da->{max} = $first_discontig - 1;
0338                 print_args(\%this, "", 0);
0339 
0340                 $da->{min} = $da->{max} + 1;
0341                 $da->{max} = $max;
0342                 print_args(\%this, $first_discontig, 1);
0343             } else {
0344                 print_args(\%this, "", 0);
0345             }
0346 
0347             next unless is_limit_reg $this{base_addr};
0348 
0349             print $LH tabconv sprintf "#define %-63s%s\n",
0350               "CCS_L_" . (uc $this{name}) . "_OFFSET(" .
0351                 (join ", ", @{$this{args}}) . ")", "($lim_formula)";
0352         }
0353 
0354         if (! @{$this{args}}) {
0355             print $H tabconv($hdr_data);
0356             undef $hdr_data;
0357         }
0358 
0359         next;
0360     }
0361 
0362     my ($name, $addr, @flags) = split /\t+/, $_;
0363     my $args = [];
0364 
0365     my $sp;
0366 
0367     ($name, $addr, $args) = name_split($name, $addr) if /\(.*\)/;
0368 
0369     $name =~ s/[,\.-]/_/g;
0370 
0371     my $flagstring = "";
0372     my $size = elem_size(@flags);
0373     $flagstring .= "| CCS_FL_16BIT " if $size eq "2";
0374     $flagstring .= "| CCS_FL_32BIT " if $size eq "4";
0375     $flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags;
0376     $flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags;
0377     $flagstring =~ s/^\| //;
0378     $flagstring =~ s/ $//;
0379     $flagstring = "($flagstring)" if $flagstring =~ /\|/;
0380     my $base_addr = $addr;
0381     $addr = "($addr | $flagstring)" if $flagstring ne "";
0382 
0383     my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : "";
0384     $hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr
0385       if !@$args;
0386 
0387     $name =~ s/\(.*//;
0388 
0389     %this = ( name => $name,
0390           addr => $addr,
0391           base_addr => $base_addr,
0392           argparams => {},
0393           args => $args,
0394           arglist => $arglist,
0395           elsize => $size,
0396         );
0397 
0398     if (!@$args) {
0399         $reglist .= "\t{ CCS_R_" . (uc $name) . ", 1,  0, \"" . (lc $name) . "\", NULL },\n";
0400         print $H tabconv $hdr_data;
0401         undef $hdr_data;
0402 
0403         print $LC tabconv sprintf "\t{ CCS_R_" . (uc $name) . ", " .
0404           $this{elsize} . ", 0, \"$name\" },\n"
0405             if is_limit_reg $this{base_addr};
0406     }
0407 
0408     print $LH tabconv sprintf "#define %-63s%s\n",
0409       "CCS_L_" . (uc $this{name}), $limitcount++
0410         if is_limit_reg $this{base_addr};
0411 }
0412 
0413 if (defined $A) {
0414     print $A $argdescs, $reglist;
0415 
0416     print $A "\t{ 0 }\n";
0417 
0418     print $A "};\n";
0419 }
0420 
0421 print $H "\n#endif /* __${uc_header}__ */\n";
0422 
0423 print $LH tabconv sprintf "#define %-63s%s\n", "CCS_L_LAST", $limitcount;
0424 
0425 print $LH "\n#endif /* __${uc_limith}__ */\n";
0426 
0427 print $LC "\t{ 0 } /* Guardian */\n";
0428 print $LC "};\n";
0429 
0430 close($R);
0431 close($H);
0432 close($A) if defined $A;
0433 close($LC);
0434 close($LH);