#!/usr/bin/perl # SPDX-License-Identifier: Apache-2.0 # Copyright 2020 Western Digital Corporation or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # use Getopt::Long; $helpusage = "placeholder"; GetOptions ('legal' => \$legal, 'in=s' => \$in, 'out=s' => \$out, 'view=s' => \$view ) || die("$helpusage"); if (!defined($in)) { die("must define -in=input"); } if (!defined($out)) { $out="${in}.out"; } if ($in eq "decode") { $view="rv32i"; } elsif ($in eq "cdecode") { $view="rv32c"; } elsif ($in eq "csrdecode") { $view="csr"; } if (defined($in)) { printf("in=$in\n"); } if (defined($out)) { printf("out=$out\n"); } if (defined($view)) { printf("view=$view\n"); } @in=`cat $in`; $gather=0; $TIMEOUT=50; foreach $line (@in) { #printf("$pstate: $line"); if ($line=~/^\s*\#/) { #printf("skip $line"); next; } if ($gather==1) { if ($line=~/(\S+)/) { if ($line=~/}/) { $gather=0; $position=0; next; } $label=$1; $label=~s/,//g; if ($pstate==2) { if (defined($INPUT{$CVIEW}{$label})) { die("input $label already defined"); } $INPUT{$CVIEW}{$label}=$position++; $INPUTLEN{$CVIEW}++; $INPUTSTR{$CVIEW}.=" $label"; } elsif ($pstate==3) { if (defined($OUTPUT{$CVIEW}{$label})) { die("output $label already defined"); } $OUTPUT{$CVIEW}{$label}=$position++; $OUTPUTLEN{$CVIEW}++; $OUTPUTSTR{$CVIEW}.=" $label"; } else { die("unknown pstate $pstate in gather"); } } } if ($line=~/^.definition/) { $pstate=1; next; } if ($pstate==1) { # definition if ($line!~/^.output/) { if ($line=~/(\S+)\s*=\s*(\S+)/) { $key=$1; $value=$2; $value=~s/\./-/g; $value=~s/\[//g; $value=~s/\]//g; $DEFINITION{$key}=$value; } } else { $pstate=2; next; } } if ($line=~/^.input/) { $pstate=2; next; } if ($pstate==2) { # input if ($line=~/(\S+)\s*=\s*\{/) { $CVIEW=$1; $gather=1; next; } } if ($line=~/^.output/) { $pstate=3; next; } if ($pstate==3) { # output if ($line=~/(\S+)\s*=\s*\{/) { $CVIEW=$1; $gather=1; next; } } if ($line=~/^.decode/) { $pstate=4; next; } if ($pstate==4) { # decode if ($line=~/([^\[]+)\[([^\]]+)\]\s*=\s*\{([^\}]+)\}/) { $dview=$1; $inst=$2; $body=$3; $dview=~s/\s+//g; $inst=~s/\s+//g; #printf("$dview $inst $body\n"); if ($inst=~/([^\{]+)\{([^-]+)-([^\}]+)\}/) { $base=$1; $lo=$2; $hi=$3; $hi++; for ($i=0; $i<$TIMEOUT && $lo ne $hi; $i++) { #printf("decode $dview $base$lo\n"); $expand=$base.$lo; if (!defined($DEFINITION{$expand})) { die("could not find instruction definition for inst $expand"); } $DECODE{$dview}{$expand}=$body; $lo++; } if ($i == $TIMEOUT) { die("timeout in decode expansion"); } } else { if (!defined($DEFINITION{$inst})) { die("could not find instruction definition for inst $inst"); } $DECODE{$dview}{$inst}=$body; } } } } #printf("view $view len %d\n",$OUTPUTLEN{$view}); #printf("$OUTPUTSTR{$view}\n"); # need to switch this somehow based on 16/32 printf(".i %d\n",$INPUTLEN{$view}); if (defined($legal)) { printf(".o 1\n"); } else { printf(".o %d\n",$OUTPUTLEN{$view}); } printf(".ilb %s\n",$INPUTSTR{$view}); if (defined($legal)) { printf(".ob legal\n"); } else { printf(".ob %s\n",$OUTPUTSTR{$view}); } if (defined($legal)) { printf(".type fd\n"); } else { printf(".type fr\n"); } $DEFAULT_TEMPLATE='0'x$OUTPUTLEN{$view}; foreach $inst (sort keys %{ $DECODE{$view} }) { $body=$DECODE{$view}{$inst}; @sigs=split(' ',$body); $template=$DEFAULT_TEMPLATE; foreach $sig (@sigs) { if (!defined($OUTPUT{$view}{$sig})) { die("could not find output definition for sig $sig in view $view"); } $position=$OUTPUT{$view}{$sig}; substr($template,$position,1,1); } # if (!defined($DEFINITION{$inst})) { die("could not find instruction defintion for inst $inst"); } printf("# $inst\n"); if (defined($legal)) { printf("$DEFINITION{$inst} 1\n"); } else { printf("$DEFINITION{$inst} $template\n"); } } exit; foreach $inst (sort keys %DEFINITION) { $value=$DEFINITION{$inst}; printf("%-10s = $value\n",$inst); } foreach $sig (sort keys %{ $OUTPUT{$view} }) { $position=$OUTPUT{$view}{$sig}; printf("$sig $position\n"); }