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); 435