diff --git a/.DS_Store b/.DS_Store index 72ae914635d8697f0b99c0deb7f434552ca941ea..ed95a0055d70ad3b2451ab6627c1423893718c47 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/flow/fm2conv.pl b/flow/fm2conv.pl new file mode 100755 index 0000000000000000000000000000000000000000..523b8598f20f6d2d9df059dc8940f9cfcbc56fc1 --- /dev/null +++ b/flow/fm2conv.pl @@ -0,0 +1,3198 @@ +eval "exec perl -w -S $0 $@" # -*- Perl -*- + if ($running_under_some_sh); + undef ($running_under_some_sh); + +# ------------------------------------------------------------------------------ +# The confidential and proprietary information contained in this file may +# only be used by a person authorised under and to the extent permitted +# by a subsisting licensing agreement from Arm Limited or its affiliates. +# +# (C) COPYRIGHT 2001-2013 Arm Limited or its affiliates. +# ALL RIGHTS RESERVED +# +# This entire notice must be reproduced on all copies of this file +# and copies of this file may only be made by a person if such person is +# permitted to do so under the terms of a subsisting license agreement +# from Arm Limited or its affiliates. +# +# ------------------------------------------------------------------------------ +# Version and Release Control Information: +# +# File Name : fm2conv.pl,v +# File Revision : $Revision: 371321 $ +# +# Release Information : Cortex-M System Design Kit-r1p1-00rel0 +# +# ------------------------------------------------------------------------------ +# Purpose : Converts an ASCII command file into a hex format, +# suitable for import by the FileReader bus master. +# Checks that the specified commands are compatible +# with the FileReader. +# +# Options: +# -help +# -quiet +# -adk1 +# -busWidth=<databus width> 32 or 64(default) +# -endian=<endianness> big or little(default) +# Note: big-endian is BE-32 (a.k.a. ARM big-endian) +# -stimarraysize=<size> default = 5000 (words) +# -infile=<input text file> default = filestim.m2i +# -outfile=<output hex file> default = filestim.m2d +# ------------------------------------------------------------------------------ + +package main; + +use strict; +use Getopt::Long; + + +# Global variables + +# default values for command-line options +my $help = 0; +my $verbose = 1; +my $adk1 = 0; +my $endian = 'little'; +my $busWidth = 64; +$main::infile = 'filestim.m2i'; +$main::outfile = ''; +my $arch = 'ahb2'; +my $stimarraysize = 5000; + + +my %command; # hash to store stimulus fields +my %sequence; # hash to store start of burst info +my $fileErrors = 0; # number of errors in input file +my $fileWarnings = 0; # number of warnings in input file +my $numCmds = 0; # number of commands in input file + +my $currCmd = 0; # current command +my $prevCmd = 0; # previous command, used in case of loop commands +my $error = 0; # command causing current error +my $memorySize = 0; # counts memory size required by FRBM + +my $transCount = 0; # no. of transfers remaining in defined-length burst +my $incrCount = 0; # number of transfers for incr burst +my $loopCount = 0; # number of looped S vectors to be expanded +my $errorsBefore = 0; # number of errors before looped S vector + + +my $lineNum = 0; # line number +my $prevLineNum = 0; # line number of previous command + +my $mismatch = 0; # addr/size mismatch warning is pending + +my $numLanesBus = 0; # Number of lanes determined from the specified + # bus width + +my $maxBytesBus = 8; # Number of byte-lanes in the internal bus: + # this is a global and is constant for a particular + # version of FileReadCore + +my $commentString = ''; # Stores any quoted string in a line of stimulus + +# default values for stimulus fields +$command{'LINE'} = 0; +$command{'DIFF'} = '000000'; +$command{'CMD'} = '00000000'; # idle +$command{'ADDR'} = '00000000'; +$command{'DATA'} = '0000000000000000'; +$command{'MASK'} = ''; +$command{'SIZE'} = '000'; +$command{'BUR'} = '000'; +$command{'PROT'} = '000000'; +$command{'LOCK'} = '0'; +$command{'DIR'} = '0'; +$command{'RESP'} = '00'; +$command{'WAIT'} = '0'; +$command{'NUM'} = 0; +$command{'UNALIGN'} = '0'; +$command{'BSTRB'} = ''; +$command{'FRAMEERR'} = 0; +$command{'WRITEBS'} = '0'; + +%sequence = %command; + +# Get run date +my ($sec, $min, $hour, $mday, $mon, $year) = localtime(time); +$year += 1900; +$mon += 01; + + +# check Perl version not older than 5.005 as switches not supported +if ($] < 5.005) { + warn "******************* WARNING 128 *******************\n". + "No command line switches supported!\n". + "Default values will be used.\n". + "Recommend upgrading to Perl version 5.005 or higher\n\n"; + +# Get command line options +} else { + GetOptions( "help" => \$help, + "quiet" => sub {$verbose = 0}, + "adk1" => \$adk1, + "infile=s" => \$main::infile, + "outfile=s" => \$main::outfile, + "buswidth=s" => \$busWidth, + "arch=s" => \$arch, + "stimarraysize=s" => \$stimarraysize, + "endian=s" => \$endian + ); +} + + +if ($verbose == 1) { + print "\n================================================================\n". + "= The confidential and proprietary information contained in this file may\n". + "= only be used by a person authorised under and to the extent permitted\n". + "= by a subsisting licensing agreement from Arm Limited or its affiliates.\n". + "=\n". + "= (C) COPYRIGHT 2001-2013 Arm Limited or its affiliates.\n". + "= ALL RIGHTS RESERVED\n". + "=\n". + "= This entire notice must be reproduced on all copies of this file\n". + "= and copies of this file may only be made by a person if such person is\n". + "= permitted to do so under the terms of a subsisting license agreement\n". + "= from Arm Limited or its affiliates.\n". + "=\n". + "= Script version : ADK2\n"; + printf "= Run Date : %02d/%02d/%04d %02d:%02d:%02d", + $mday, $mon, $year, $hour, $min, $sec; + print "\n================================================================\n\n"; +} + +# Help message +if ($help == 1) { + print "Purpose:\n". + " Converts an ASCII command file into a hex format,\n". + " suitable for import by the File Reader Bus Master.\n". + " Checks that the specified commands are compatible\n". + " with the File Reader Bus Master.\n". + "\nUsage:\n". + " Reads stimulus from a text file.\n". + " Writes hex data to a text file.\n". + "\nOptions:\n". + " -help display this help message\n". + " -quiet display only ERROR messages\n". + " -adk1 read an ADK1v1 input stimulus\n". + " -busWidth=<32|64> default = 64\n". + " -endian=<little|big> default = little\n". + " (big-endian is BE-32 'ARM big-endian')\n". + " -stimarraysize=<size> default = 5000\n". + " -infile=<input file> default = filestim.m2i\n". + " -outfile=<output file> default = filestim.m2d\n". + "\n================================================================\n"; + exit(1); +} + + +# Check that an invalid architecture has not been entered +$arch = lc($arch); +if ($arch ne 'ahb2' and $arch ne 'v6') { + $arch = 'ahb2'; + warn "******************* WARNING 133 *******************\n". + "The architecture selected is invalid\n". + "Architecture must be ahb2 or V6.\n". + "ahb2 will be used by default.\n\n"; +} + +# Check for options incompatible with ADK1 stimulus +if ($adk1 == 1) { + # Check bus width is 32 bits + if ($busWidth != 32) { + $busWidth = 32; + warn "******************* WARNING 134 *******************\n". + "ADK1v1 stimulus format has been selected.\n". + "Data bus width of 32 bits will be used by default.\n\n"; + } + + # Check architecture is AHB2 + if ($arch eq 'v6') { + $arch = 'ahb2'; + warn "******************* WARNING 135 *******************\n". + "ADK1v1 stimulus format has been selected.\n". + "ahb2 architecture will be used by default.\n\n"; + } +} + +# check an invalid busWidth has not been entered +if ($busWidth != 32 && $busWidth != 64) { + $busWidth = 64; + warn "******************* WARNING 132 *******************\n". + "Data bus width has been selected to be $busWidth bits.\n". + "Data bus width must be either 32 or 64 bits.\n". + "64 bits will be used by default.\n\n" +} + +$numLanesBus = $busWidth >> 3; + +# calculate default output file name +if ($main::outfile eq '') { + + if($main::infile =~ /([\w\\\/]+)\.\w+/) { + $main::outfile = $1.'.m2d'; + } else { + $main::outfile = $main::infile.'.f2d'; + } +} + + + +# Report options selected +if ($verbose == 1) { + print "Input file $main::infile\n"; + print "Output file $main::outfile\n"; + print "ADK1v1 stimulus format selected\n" + if ($adk1 == 1); + print "ADK2 stimulus format selected\n" + if ($adk1 == 0); + print "$busWidth-bit data bus selected\n"; + print "ARMv6 AMBA extensions are supported\n" + if ($arch eq 'v6'); + print "${endian}-endian data organisation selected\n"; + print "\n"; +} + +# Check that input and output filenames are not the same +if ($main::infile eq $main::outfile) { + printf "ERROR 20: Input and output file names are identical\n\n"; + $fileErrors++; + +} else { + # Open input file + unless (open(INPUTFILE, "$main::infile") ) { + + # failed to open input file + printf "ERROR 17: Input file does not exist". + " or cannot be accessed\n"; + $fileErrors++; + } + + # Open output file + unless (open (FILEOUT, ">$main::outfile") ) { + + # failed to open output file + printf "ERROR 21: Cannot create output file $main::outfile\n"; + $fileErrors++; + } +} + +# Only continue if no errors +if ($fileErrors) { + die "\nExit with $fileErrors error(s) and $fileWarnings warning(s).\n\n"; + +} elsif ($verbose == 1) { + printf "Reading from text file: %s\n\n", $main::infile; + +} + +# ------------------------------------------------------------------------------ +# +# Stimulus file parsing +# +# Commands are detected by searching for the first non-whitespace character on +# a line. +# +# For each command, first the required fields are retrieved and checked, then +# any optional fields which are present. If a required field is invalid or +# missing then an error is raised. If an optional field is invalid or not +# recognised then a warning is raised. +# ------------------------------------------------------------------------------ + +# Process each line of stimulus +# while there are lines remaining to be read from the file +while (<INPUTFILE>) { + + # Keep track of stimulus file line numbers + $lineNum++; + + # If a character exists on this line and it is not whitespace... + if (/\S/) { + $commentString = ''; + + # Strip comment command text first, if any + s/"([\w+|\W+|s+]+)"// and + $commentString = $1; + + # Strip comments from end of line + s/\s*(\#|\/\/|;|--).*//; + + # Check for adk1 option switch in the stimulus file + if (s/^\s*-adk1\b//i) { + + $adk1 = 1; + + if ($verbose == 1) { + printf "ADK1v1 stimulus format selected ". + "in stimulus file\n", $lineNum; + } + + + # Check bus width is 32 bits + if ($busWidth != 32) { + $busWidth = 32; + $numLanesBus = $busWidth >> 3; + warn "******************* WARNING 134 *******************\n". + "ADK1v1 stimulus format has been selected.\n". + "Data bus width of 32 bits will be used by default.\n\n"; + } + + # Check architecture is AHB2 + if ($arch eq 'v6') { + $arch = 'ahb2'; + warn "******************* WARNING 135 *******************\n". + "ADK1v1 stimulus format has been selected.\n". + "ahb2 architecture will be used by default.\n\n"; + } + + # Check for anything left on the line + CheckInvalidFields(); + CheckInvalidComment($commentString); + + # If the AltMaster field is present, the entire command is ignored + } elsif (/\baltmaster\b/i and $verbose == 1) { + + printf "Line %4d: WARNING 241: AltMaster field is not supported:". + " entire line will be ignored\n", $lineNum; + $fileWarnings++; + + + # Comment commands are handled separately, because they occur in zero + # simulation time and cannot be looped + } elsif(s/^\s*(C|comm|comment)\b//i) { + + $numCmds++; # increment command counter + + $command{'LINE'} = $lineNum; # get line number + $command{'DIFF'} = GetLineDiff(); # calculate line number increment + + # Parse the line + ParseC($commentString); + + # Check for anything left on the line + CheckInvalidFields(); + + # add size on memory required for command to stimulus total + CalcMemory('C'); + + # write the line to the output file + OutputHex(); + + + # If line starts with any other valid command then decode command + } elsif(s/^\s*(W|R|S|B|I|P|L|Q|write|read|seq|sequential|busy|idle|poll|loop|quit)\b//i) { + + + $prevCmd = $currCmd; # save previous command in case of Loop commands + $currCmd = uc(substr($1,0,1)); # get the current command + + $numCmds++; # increment command counter + + + $command{'LINE'} = $lineNum; # get line number + $command{'DIFF'} = GetLineDiff(); # calculate line number increment + + + # S or B command + if ($currCmd eq 'S' or $currCmd eq 'B') { + + # if a burst is not in progress (defined- or undefined-length) + if (GetTransCount() == 0 && (GetIncrCount() == 0)) { + + printf "Line %4d: ERROR 84: $currCmd command outside burst". + " (check burst size)\n", $lineNum; + $fileErrors++; + } + + } + + # Parse the line + if ($currCmd eq 'W') { ParseW() } + elsif ($currCmd eq 'R') { ParseR() } + elsif ($currCmd eq 'S') { ParseS() } + elsif ($currCmd eq 'B') { ParseB() } + elsif ($currCmd eq 'I') { ParseI() } + elsif ($currCmd eq 'P') { ParseP() } + elsif ($currCmd eq 'L') { ParseL() } + elsif ($currCmd eq 'Q') { ParseQ() } + + # Check for anything left on the line + CheckInvalidFields(); + CheckInvalidComment($commentString); + + # Unfold looped S vectors + if ($loopCount > 0) { + + while($loopCount-- > 0) { + + # align data and mask and check Bstrb + LoopedSeq(); + + # add size on memory required for command to stimulus total + CalcMemory('S'); + + # write the line to the output file + OutputHex(); + + # looped S vectors are on same line of stimulus so increment is zero + $command{'DIFF'} = '000000'; + } + + } else { + # add size on memory required for command to stimulus total + CalcMemory($currCmd); + + # write the line to the output file + OutputHex(); + + } + + # Commands not supported by File Read Master are ignored: + # M Memory command + # D Degrant options + # E XVC master event + } elsif (/^\s*([MED])\b/i and $verbose == 1) { + + printf "Line %4d: WARNING 240: $1 command is not supported". + " and will be ignored\n", $lineNum; + $fileWarnings++; + + # Syntax error if any other non-whitespace character is on the line + } elsif (/^\s*(\S+.*)/) { + + $error = $1; + $currCmd = '$error'; + printf "Line %4d: ERROR 32: Unknown command :". + " \"%s\"\n", $lineNum, $error; + $fileErrors++; + } + + } + + # exit loop if Q command has been detected + if ($currCmd eq 'Q') { last } + +} + +# At End Of File, check for an unfinished defined-length burst (unless errcanc) +if (GetTransCount() > 0 and $sequence{'RESP'} ne '10' and ($verbose == 1)) { + printf "Line %4d: WARNING 144: End of file: Expected further". + " transfers in burst\n", $lineNum; + $fileWarnings++; +} + +close(INPUTFILE); +close (FILEOUT); + +# End of stimulus error-checking +CheckArraySize($memorySize, $stimarraysize); + +PrintSummary() if ($verbose == 1); + +# error code is 1 if any errors +($fileErrors == 0) ? exit(0) : exit(1); + + +# ------------------------------------------------------------------------------ +# +# Check size of stimulus does not exceed size of File Read Master array length +# +# ------------------------------------------------------------------------------ + +sub CheckArraySize { + + my $memorySize = shift; + my $stimarraysize = shift; + + if (($verbose == 1) and ($memorySize > $stimarraysize)) { + print "\n"; + print "================================================================\n"; + print "WARNING 136: The compiled stimulus exceeds the specified size of\n"; + print " the FileReader array. Increase the FileReader\n"; + print " StimArraySize generic/parameter and use script\n"; + print " with the -stimarraysize switch.\n"; + print "\n"; + printf "Compiled stimulus size = %d x 32-bit\n",$memorySize; + printf "FileReader array size = %d x 32-bit\n",$stimarraysize; + print "================================================================\n"; + $fileWarnings++; + } +} + + +# ------------------------------------------------------------------------------ +# +# Print a summary of the file conversion process +# +# ------------------------------------------------------------------------------ +sub PrintSummary { + print "\n"; + print "================================================================\n"; + printf "Total Warnings = %d\n",$fileWarnings; + printf "Total Errors = %d\n",$fileErrors; + printf "Total commands = %d\n",$numCmds; + printf "FileReader min array size required = %d x 32-bit\n",$memorySize; + printf "Output file name = %s\n",$main::outfile; + print "================================================================\n"; +} + +# ------------------------------------------------------------------------------ +# +# Write a command to the output (hex) file +# +# ------------------------------------------------------------------------------ + +sub OutputHex { + + # save output format and handle so that they can be restored + my $savedFormat = $~; + my $savedFileHandle = select FILEOUT; + + # generate the Function word + $command{'FUNCTION'} = BinToHex( + $command{'CMD'}. + $command{'SIZE'}. + $command{'BUR'}. + $command{'PROT'}. + $command{'LOCK'}. + $command{'DIR'}. + $command{'RESP'}. + $command{'UNALIGN'}. + $command{'WRITEBS'}. + $command{'DIFF'} + ); + + # select output stimulus format for current command type + if ($command{'CMD'} eq '00000000') {$~ = 'WRITECMD'} + elsif ($command{'CMD'} eq '00010000') {$~ = 'READCMD'} + elsif ($command{'CMD'} eq '00100000') {$~ = 'SEQCMD'} + elsif ($command{'CMD'} eq '00110000') {$~ = 'BUSYCMD'} + elsif ($command{'CMD'} eq '01000000') {$~ = 'IDLECMD'} + elsif ($command{'CMD'} eq '01010000') {$~ = 'POLLCMD'} + elsif ($command{'CMD'} eq '01100000') {$~ = 'LOOPCMD'} + elsif ($command{'CMD'} eq '01110000') {$~ = 'COMMCMD'} + elsif ($command{'CMD'} eq '10000000') {$~ = 'QUITCMD'} + else { + # default - should never happen + printf "WARNING 255: Command undefined, defaulting to IDLE"; + $~ = 'IDLECMD'; + } + + write (FILEOUT); + + # reset format and output stream + $~ = $savedFormat; + select $savedFileHandle; + +} + + +# ------------------------------------------------------------------------------ +# +# W command decoding +# +# ------------------------------------------------------------------------------ +sub ParseW { + + $command{'CMD'} = '00000000'; + + # Get mandatory fields + $command{'ADDR'} = GetAddrField(); + $command{'DATA'} = GetDataField(); + + + # get optional fields + $command{'MASK'} = ''; # clear mask, otherwise could get a mismatch from old value + $command{'SIZE'} = GetSizeField(); + $command{'BUR'} = GetBurstField(); + $command{'PROT'} = GetProtField(); + $command{'LOCK'} = GetLockField(); + $command{'RESP'} = GetWriteRespField(); + $command{'UNALIGN'} = GetUnalignField(); + $command{'BSTRB'} = GetBstrbField(); + + # Check that response and prot agree for Write command + CheckWriteProtResp ( + $command{'PROT'}, + $command{'RESP'} + ); + + # Check that size/mask/data agree + ($command{'SIZE'}, $command{'DATA'}, $command{'MASK'}) + = CheckSizeDataMask ( + $numLanesBus, + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'BSTRB'}, + ); + + # Shift data/mask into correct byte lanes + ($command{'DATAH'}, $command{'DATAL'}, $command{'MASKH'}, $command{'MASKL'}) + = AlignDataMask ( + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'ADDR'} + ); + + # New burst, so check for early burst termination and reset burst counters + ResetBurstCount(); + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + 0, # not end of unaligned burst + 0, # sequence address is not relevant + 0 # not an idle transfer + ); + + # Check address/size alignment + $command{'FRAMEERR'} + = CheckAddrAlign( + $command{'SIZE'}, + $command{'ADDR'}, + $command{'UNALIGN'} + ); + + + # Check any exclusive access is aligned + CheckProtUnalign($command{'PROT'}, $command{'UNALIGN'}); + + # Initialise burst counters for the remaining transfers in the burst + SetBurstCount($command{'BUR'}, $command{'FRAMEERR'}); + + # check for burst exceeding 1kB boundary + Check1kBdy($command{'SIZE'}, $command{'BUR'}, $command{'ADDR'}, GetTransCount()); + + # Save address and control information for start of burst + %sequence = %command; + + # Reset unused fields + $command{'WAIT'} = '0'; + $command{'DIR'} = '0'; + $command{'NUM'} = 0; +} + + +# ------------------------------------------------------------------------------ +# +# R command decoding +# +# ------------------------------------------------------------------------------ +sub ParseR { + + $command{'CMD'} = '00010000'; + + # get mandatory fields + $command{'ADDR'} = GetAddrField(); + $command{'DATA'} = GetDataField(); + + # get optional fields + $command{'SIZE'} = GetSizeField(); + $command{'MASK'} = GetMaskField(); + $command{'BUR'} = GetBurstField(); + $command{'LOCK'} = GetLockField(); + $command{'PROT'} = GetProtField(); + $command{'RESP'} = GetRespField(); + $command{'UNALIGN'}= GetUnalignField(); + $command{'BSTRB'} = GetBstrbField(); + + + # Check that size/mask/data agree + ($command{'SIZE'}, $command{'DATA'}, $command{'MASK'}) + = CheckSizeDataMask ( + $numLanesBus, + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'BSTRB'}, + ); + + # Shift data/mask into correct byte lanes + ($command{'DATAH'}, $command{'DATAL'}, $command{'MASKH'}, $command{'MASKL'}) + = AlignDataMask ( + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'ADDR'} + ); + + # New burst, so check for early burst termination and reset burst counters + ResetBurstCount(); + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + 0, # not end of unaligned burst + 0, # sequence address is not relevant + 0 # not an idle transfer + ); + + # Check address/size alignment + $command{'FRAMEERR'} + = CheckAddrAlign( + $command{'SIZE'}, + $command{'ADDR'}, + $command{'UNALIGN'} + ); + + # Check any exclusive access is aligned + CheckProtUnalign($command{'PROT'}, $command{'UNALIGN'}); + + # Initialise burst counters for the remaining transfers in the burst + SetBurstCount($command{'BUR'}, $command{'FRAMEERR'}); + + # check for burst exceeding 1kB boundary + Check1kBdy($command{'SIZE'}, $command{'BUR'}, $command{'ADDR'}, GetTransCount()); + + # Save address and control information for start of burst + %sequence = %command; + + # Reset unused fields + $command{'WAIT'} = '0'; + $command{'DIR'} = '0'; + $command{'NUM'} = 0; +} + + +# ------------------------------------------------------------------------------ +# +# S command decoding +# +# ------------------------------------------------------------------------------ +sub ParseS { + + my $endUnalignedBurst; + + $command{'CMD'} = '00100000'; + + # get mandatory data field + $command{'DATA'} = GetDataField(); + + # retrieve control information from previous W or R command + $command{'SIZE'} = $sequence{'SIZE'}; + $command{'BUR'} = $sequence{'BUR'}; + $command{'PROT'} = $sequence{'PROT'}; + $command{'UNALIGN'} = $sequence{'UNALIGN'}; + + # Calculate and save next address in sequence + # for purpose of data alignment + $command{'ADDR'} = IncAddr( $command{'ADDR'}, + $command{'SIZE'}, + $command{'BUR'} + ); + + # Get optional fields + $command{'MASK'} = GetMaskField(); + $command{'RESP'} = GetRespField(); + $command{'BSTRB'} = GetBstrbField(); + + # If an error cancel response, mark the burst to suppress warning of + # early burst termination + if ($command{'RESP'} eq '10' ) { + $sequence{'RESP'} = $command{'RESP'}; + } + + # Check that size/mask/data agree + ($command{'SIZE'}, $command{'DATA'}, $command{'MASK'}) + = CheckSizeDataMask ( + $numLanesBus, + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'BSTRB'} + ); + + # Shift data/mask into correct byte lanes + ($command{'DATAH'}, $command{'DATAL'}, $command{'MASKH'}, $command{'MASKL'}) + = AlignDataMask ( + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'ADDR'} + ); + + + # Resets warning for Addr/Size alignment + ResetMismatch(); + + # Test for the end of an unaligned burst + $endUnalignedBurst = + (GetTransCount() == 1 and $sequence{'FRAMEERR'} == 1) ? 1 : 0; + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + $endUnalignedBurst, + $sequence{'ADDR'}, + 0 # not an idle transfer + ); + + # if undefined length (INCR) burst + if ($sequence{'BUR'} eq '001') { + + # check for burst exceeding 1kB boundary + Check1kBdy($sequence{'SIZE'}, $sequence{'BUR'}, $sequence{'ADDR'}, GetIncrCount()); + + IncIncrCount(); + + } else { + + DecTransCount(); + + } + + # Reset unused fields + $command{'WAIT'} = '0'; + $command{'DIR'} = '0'; + $command{'LOCK'} = '0'; + $command{'NUM'} = 0; + +} + + +# ------------------------------------------------------------------------------ +# +# B command decoding +# +# ------------------------------------------------------------------------------ +sub ParseB { + + my $addrTemp; + my $endUnalignedBurst; + + $command{'CMD'} = '00110000'; + + # retrieve control information from previous W or R command + $command{'SIZE'} = $sequence{'SIZE'}; + $command{'BUR'} = $sequence{'BUR'}; + $command{'PROT'} = $sequence{'PROT'}; + $command{'UNALIGN'} = $sequence{'UNALIGN'}; + + # Get optional fields + $command{'WAIT'} = GetWaitField(); + $command{'BSTRB'}= GetBstrbField(); + + # Calculate - but do not save - next address in sequence + # for purpose of data alignment + $addrTemp = IncAddr( $command{'ADDR'}, + $command{'SIZE'}, + $command{'BUR'} + ); + + + # Test for the end of an unaligned burst + $endUnalignedBurst = + (GetTransCount() == 1 and $sequence{'FRAMEERR'} == 1) ? 1 : 0; + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($addrTemp), + $command{'SIZE'}, + $endUnalignedBurst, + $sequence{'ADDR'}, + 0 # not an idle transfer + ); + + # Wait and Resp fields share bits, as they are never both used + $command{'RESP'} = '0'.$command{'WAIT'}; + + # if undefined length (INCR) burst + if ($sequence{'BUR'} eq '001') { + # check for burst exceeding 1kB boundary + Check1kBdy($sequence{'SIZE'}, $sequence{'BUR'}, $sequence{'ADDR'}, GetIncrCount()); + } + + # Reset unused fields + $command{'DIR'} = '0'; + $command{'LOCK'} = '0'; + $command{'NUM'} = 0; + # Note: Address field must not be updated, in case of following S vectors +} + + +# ------------------------------------------------------------------------------ +# +# I command decoding +# +# ------------------------------------------------------------------------------ +sub ParseI { + + $command{'CMD'} = '01000000'; + + # Get optional fields + $command{'ADDR'} = GetIdleAddrField(); + $command{'DIR'} = GetDirField(); + $command{'SIZE'} = GetSizeField(); + $command{'BUR'} = GetBurstField(); + $command{'LOCK'} = GetLockField(); + $command{'PROT'} = GetProtField(); + $command{'WAIT'} = GetWaitField(); + $command{'UNALIGN'}= GetUnalignField(); + $command{'BSTRB'} = GetBstrbField(); + + # Default Size to bus width if not specified + $command{'SIZE'} = BytesToHsize($numLanesBus) unless ($command{'SIZE'} ne ''); + + # Do not check address/size alignment for idle transfer + $command{'FRAMEERR'} = 0; + + # Idle command implies no sequential transfers following + # (also checks for early burst termination) + ResetBurstCount(); + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + 0, # not end of unaligned burst + 0, # sequence address is not relevant + 1 # is an idle transfer, so no errors reported + ); + + # Save address and control information for start of burst + %sequence = %command; + + # Wait and Resp fields share bits, as they are never both used + $command{'RESP'} = '0'.$command{'WAIT'}; + + # Reset unused fields + $command{'NUM'} = 0; +} + +# ------------------------------------------------------------------------------ +# +# P command decoding +# +# ------------------------------------------------------------------------------ +sub ParseP { + + $command{'CMD'} = '01010000'; + + # get mandatory fields + $command{'ADDR'} = GetAddrField(); + $command{'DATA'} = GetDataField(); + + # get optional fields + $command{'SIZE'} = GetSizeField(); + $command{'MASK'} = GetMaskField(); + $command{'BUR'} = GetPollBurstField(); + $command{'PROT'} = GetProtField(); + $command{'TOUT'} = GetToutField(); + $command{'UNALIGN'}= GetUnalignField(); + $command{'BSTRB'} = GetBstrbField(); + + # Check that size/mask/data agree + ($command{'SIZE'}, $command{'DATA'}, $command{'MASK'}) + = CheckSizeDataMask ( + $numLanesBus, + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'BSTRB'} + ); + + # Shift data/mask into correct byte lanes + ($command{'DATAH'}, $command{'DATAL'}, $command{'MASKH'}, $command{'MASKL'}) + = AlignDataMask ( + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'ADDR'} + ); + + + # Burst type can only be SIGN or INCR therefore no S vectors are implied + # (also checks for early burst termination) + ResetBurstCount(); + + # Check ARMv6 extensions to AMBA2.0 + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + 0, # not end of unaligned burst + 0, # sequence address is not relevant + 0 # not an idle transfer + ); + + # Check address/size alignment + $command{'FRAMEERR'} + = CheckAddrAlign( + $command{'SIZE'}, + $command{'ADDR'}, + $command{'UNALIGN'} + ); + + # check address alignment + if ($command{'FRAMEERR'} == 1) { + printf "Line %4d: ERROR 108: Cannot poll". + " an unaligned address\n", $lineNum; + $fileErrors++; + } + + # Save address and control information for start of burst + %sequence = %command; + + # Reset unused fields + $command{'WAIT'} = '0'; + $command{'LOCK'} = '0'; + $command{'DIR'} = '0'; + $command{'RESP'} = '00'; +} + + +# ------------------------------------------------------------------------------ +# +# L command decoding +# +# ------------------------------------------------------------------------------ +sub ParseL { + + $command{'CMD'} = '01100000'; + + # get mandatory field + $command{'NUM'} = GetNumberField(); + + # Looped S vectors must be expanded, because of data alignment + if ($prevCmd eq 'S') { + + # Set command to S because loop will be unfolded + $command{'CMD'} = '00100000'; + + # Set global counter for number of looped vectors remaining + $loopCount = hex($command{'NUM'}); + + if ($sequence{'BUR'} ne '001') { + + # defined burst length + if (GetTransCount() - $loopCount < 0) { + printf "Line %4d: ERROR 89: Loop number exceeds". + " number of remaining transfers\n", $lineNum; + $fileErrors++; + } + + } else { + + # undefined length burst + # check for burst exceeding 1kB boundary + Check1kBdy($sequence{'SIZE'}, $sequence{'BUR'}, $sequence{'ADDR'}, GetIncrCount() + $loopCount - 1); + } + + + } else { + # Reset unused fields + $command{'SIZE'} = '000'; + $command{'UNALIGN'} = '0'; + $command{'BSTRB'} = ''; + $command{'WAIT'} = '0'; + $command{'BUR'} = '000'; + $command{'PROT'} = '000000'; + $command{'LOCK'} = '0'; + $command{'DIR'} = '0'; + $command{'RESP'} = '00'; + $command{'WRITEBS'} = '0'; + } + + # Record current number of errors to suppress multiple error reporting in loops + $errorsBefore = $fileErrors; + +} + + +# ------------------------------------------------------------------------------ +# +# One iteration of looped Sequential command unfolding +# +# ------------------------------------------------------------------------------ +sub LoopedSeq { + + my $endUnalignedBurst; + + + $command{'ADDR'} = IncAddr( $command{'ADDR'}, + $command{'SIZE'}, + $command{'BUR'} + ); + + # Test for the end of an unaligned burst + $endUnalignedBurst = + (GetTransCount() == 1 and $sequence{'FRAMEERR'} == 1) ? 1 : 0; + + + # Data and mask will need realigning for new address unless full bus + # width is specified. Shift data/mask into correct byte lanes + ($command{'DATAH'}, $command{'DATAL'}, $command{'MASKH'}, $command{'MASKL'}) + = AlignDataMask ( + $command{'SIZE'}, + $command{'DATA'}, + $command{'MASK'}, + $command{'ADDR'} + ); + + # If not already detected a Bstrb error, perform an additional check on + # the extra transfer at the end of an unaligned burst + ($command{'UNALIGN'}, $command{'BSTRBHEX'}, $command{'WRITEBS'}) + = CheckUnalignBstrb ( + $command{'UNALIGN'}, + $command{'BSTRB'}, + hex($command{'ADDR'}), + $command{'SIZE'}, + $endUnalignedBurst, + $sequence{'ADDR'}, + $fileErrors<=>$errorsBefore # only report error once + ); + + # if undefined length (INCR) burst + if ($sequence{'BUR'} eq '001') { + IncIncrCount(); + + } else { + DecTransCount(); + + } +} + + +# ------------------------------------------------------------------------------ +# +# C command decoding +# +# ------------------------------------------------------------------------------ +sub ParseC { + + my $commentString = shift; + my @commentPacked; + my $word; + my $i; + + $command{'CMD'} = '01110000'; + + # Check comment for illegal characters + $commentString = CheckComment($commentString); + + # Pack the comment string into words + @commentPacked = PackComment($commentString); + + # Length of array is the number of words + $command{'COUNT'} = @commentPacked; + + # Store value in Number field in hex format + $command{'NUM'} = ToHex32($command{'COUNT'}); + + # Store the packed comment into the appropriate elements of %command + $i = 1; + foreach $word ( @commentPacked ) { + $command{"WORD$i"} = ToHex32($word); + $i++; + } + + # Note: Unused fields must not be reset, in case comment occurs + # inside burst or loop +} + + +# ------------------------------------------------------------------------------ +# +# Q command decoding +# +# ------------------------------------------------------------------------------ +sub ParseQ { + + $command{'CMD'} = '10000000'; + + # Reset unused fields + $command{'UNALIGN'} = '0'; + $command{'BSTRB'} = ''; + $command{'WAIT'} = '0'; + $command{'SIZE'} = '000'; + $command{'BUR'} = '000'; + $command{'PROT'} = '000000'; + $command{'LOCK'} = '0'; + $command{'DIR'} = '0'; + $command{'RESP'} = '00'; + $command{'NUM'} = '0000'; + $command{'ADDR'} = '00000000'; + $command{'WRITEBS'} = '0'; +} + + +# ------------------------------------------------------------------------------ +# Get mandatory address field value +# +# I/O: searches from start of line for the address field +# returns the value of the address field, or reports an error +# ------------------------------------------------------------------------------ +sub GetAddrField { + + my $addr; + + + if (s/\b(?:0x)?([0-9A-F]{8})\b//i) { + $addr = $1; + + } else { + # mandatory field missing + $addr = 0; + printf "Line %4d: ERROR 36: Required field is missing or". + " in wrong format\n", $lineNum; + $fileErrors++; + + } + + return $addr; +} + + +# ------------------------------------------------------------------------------ +# Get optional address field value +# +# I/O: searches along line for the address field +# returns the value of the address field +# ------------------------------------------------------------------------------ +sub GetIdleAddrField { + + my $addr; + + if (s/\b(?:0x)?([0-9A-F]{8})\b//i ) { + $addr = $1; + + } else { + # default + $addr = '00000000'; + + } + + return $addr; +} + + +# ------------------------------------------------------------------------------ +# Get mandatory data field value +# +# I/O: searches from start of line for the data field +# returns the value of the data field, or reports an error +# ------------------------------------------------------------------------------ +sub GetDataField { + + my $data; # (hex string) value of data field in stimulus + my $dataFieldWidth; # width of data field, i.e. number of hex digits + + # Note 'X' is allowed, but may cause an error in the FileReadCore + if ($adk1 == 0 and s/\b(?:0x)?([0-9A-FX]{2,32})\b//i) { + $data = $1; + + } elsif ($adk1 == 1 and s/\b([0-9A-FX]{8})\b//i) { + $data = $1; + + } else { + # mandatory field missing + $data = 0; + printf "Line %4d: ERROR 36: Required field is missing or". + " in wrong format\n", $lineNum; + $fileErrors++; + } + + + # if data field exists + if ($data) { + + $dataFieldWidth = length($data); + + # check if data field width is greater than busWidth + if (($dataFieldWidth << 2) > $busWidth) { + printf "\nLine %4d: ERROR 48: Data field length exceeds". + " data bus width\n", $lineNum; + $fileErrors++; + + # check data field width is either 2,4,8 or 16 hex digits + } elsif (($dataFieldWidth != 2) && ($dataFieldWidth != 4) && + ($dataFieldWidth != 8) && ($dataFieldWidth != 16)) { + printf "\nLine %4d: ERROR 49: Data field is an". + " invalid length\n", $lineNum; + $fileErrors++; + + } + + } + + return $data; +} + + +# ------------------------------------------------------------------------------ +# Get mask field value +# +# I/O: searches along the current line for a valid mask field value +# returns the value of the mask field +# ------------------------------------------------------------------------------ +sub GetMaskField { + + my $mask; + my $maskFieldWidth = 0; # width of mask field read from stimulus + + if ($adk1 == 0 and s/\b(?:0x)?([0-9A-F]{2,32})\b//i ) { + $mask = $1; + + } elsif ($adk1 == 1 and s/\b([0-9A-F]{8})\b//i) { + $mask = $1; + + } else { + $mask = ''; + } + + $maskFieldWidth = length($mask); + + # if mask field exists + unless ($mask eq '') { + + # check if mask field width is greater than busWidth + if (($maskFieldWidth << 2) > $busWidth) { + + printf "\nLine %4d: ERROR 52: Mask field length exceeds". + " data bus width\n", $lineNum; + $fileErrors++; + $mask = ''; + + + # check mask field width is either 2,4,8 or 16 hex digits + } elsif (($maskFieldWidth != 2) && ($maskFieldWidth != 4) && + ($maskFieldWidth != 8) && ($maskFieldWidth != 16)) { + + printf "\nLine %4d: ERROR 53: Mask field is an". + " invalid length\n", $lineNum; + $fileErrors++; + $mask = ''; + + } + } + + return $mask; +} + + +# ------------------------------------------------------------------------------ +# Get size field value +# +# I/O: searches along the current line for a valid size field value +# returns the value of the size field +# ------------------------------------------------------------------------------ +sub GetSizeField { + + my $size; + + if (s/\bb\b|\bbyte\b|\bsize8\b//i) { + $size = '000'; + + } elsif (s/\bh\b|\bhword\b|\bsize16\b//i) { + $size = '001'; + + } elsif (s/\bw\b|\bword\b|\bsize32\b//i) { + $size = '010'; + + } elsif (s/\bd\b|\bdword\b|\bsize64\b//i) { + # 64-bit transfer size not supported in ADK1 + if($adk1 == 1) { + printf "Line %4d: ERROR 40: size64 not supported". + " in FileReader ADK1 stimulus\n", $lineNum; + $fileErrors++; + $size = '010'; + + # 64-bit transfer not supported when busWidth set to 32-bit + } elsif (($busWidth == 32)) { + printf "Line %4d: ERROR 40: size64 not valid". + " when outputting to 32-bit busWidth\n", $lineNum; + $fileErrors++; + $size = ''; # size will be determined later + + } else { + $size = '011'; + + } + + } elsif (s/\bq\b|\bqword\b|\bsize128\b//i) { + printf "Line %4d: ERROR 40: size128 not supported". + " by AHB File Reader Master\n", $lineNum; + $fileErrors++; + $size = ''; # size will be determined later + + } else { + $size = ''; # size will be determined later + + } + + return $size; +} + + +# ------------------------------------------------------------------------------ +# Get burst type +# +# I/O: searches along the current line for a valid burst field value +# returns the value of the burst field +# ------------------------------------------------------------------------------ +sub GetBurstField { + + my $burst; + + if (s/\bsing\b|\bsingle\b//i) { + $burst = '000'; + + } elsif (s/\bincr\b//i) { + $burst = '001'; + + } elsif (s/\bwrap4\b//i) { + $burst = '010'; + + } elsif (s/\bincr4\b//i) { + $burst = '011'; + + } elsif (s/\bwrap8\b//i) { + $burst = '100'; + + } elsif (s/\bincr8\b//i) { + $burst = '101'; + + } elsif (s/\bwrap16\b//i) { + $burst = '110'; + + } elsif (s/\bincr16\b//i) { + $burst = '111'; + + } else { + # default to INCR + $burst = '001'; + } + + return $burst; +} + + +# ------------------------------------------------------------------------------ +# Get burst type for Poll commands +# +# I/O: searches along the current line for a valid burst field value +# returns the value of the burst field +# Only Incr and Single are allowed +# ------------------------------------------------------------------------------ +sub GetPollBurstField { + + my $burst; + + if (s/\bsing\b|\bsingle\b//i) { + $burst = '000'; + + } elsif (s/\bincr\b//i) { + $burst = '001'; + + } elsif (s/\b((wrap|incr)(4|8|16))\b//i) { + # invalid burst type for Poll command + printf "Line %4d: ERROR 80: Burst type \"$1\" is". + " incompatible with P command\n", $lineNum; + $fileErrors++; + + # default to INCR + $burst = '001'; + + } else { + # default to INCR + $burst = '001'; + } + + return $burst; +} + + +# ------------------------------------------------------------------------------ +# Get protection field value +# +# I/O: searches along the current line for a valid protection field value +# returns the value of the protection field +# ------------------------------------------------------------------------------ +sub GetProtField { + + my $prot; + + if ($adk1 == 0 ) { + # reading adk2 stimulus + if (s/\bp([0-1]{6})\b//i) { + $prot = $1; + + if ($arch eq 'v6') { + + # Prot[4] should only be asserted if Prot[3] is asserted + if ( substr($prot, 1, 2) eq '10') { + printf "Line %4d: ERROR 105: HPROT[4] can only be asserted". + " if HPROT[3] is asserted \n", $lineNum; + $fileErrors++; + # The value of $prot is not changed, to allow the testing + # of invalid values + } + } else { + + printf "Line %4d: ERROR 96: ARMv6 AMBA extensions are not allowed". + " unless V6 architecture is selected: Prot field\n", $lineNum; + $fileErrors++; + # The value of $prot is not changed, to allow the testing + # of invalid values + + } + + } elsif ($arch ne 'v6' and s/\bp([0-1]{4})\b//i) { + # add extra leading zeros to ahb2 prot value + $prot = '00'.$1; + + } else { + # default value + $prot = '000000'; + + } + + # reading adk1 stimulus + } elsif (s/\b([0-1]{4})\b//i) { + # add extra leading zeros to ahb2 prot value + $prot = '00'.$1; + + } else { + # default value + $prot = '000000'; + + } + + return $prot; +} + + +# ------------------------------------------------------------------------------ +# Get lock field value +# +# I/O: searches along the current line for a valid lock field value +# returns the value of the lock field +# ------------------------------------------------------------------------------ +sub GetLockField { + + my $lock; + + if (s/\block\b//i){ + $lock = '1'; + + } elsif (s/\bnolock\b//i) { + $lock = '0'; + + } else { + $lock = '0'; + + } + + return $lock; +} + + +# ------------------------------------------------------------------------------ +# Get Direction field value +# +# I/O: searches along the current line for a valid direction field value +# returns the value of the direction field +# ------------------------------------------------------------------------------ +sub GetDirField { + + my $dir; + + if (s/\bread\b//i) { + $dir = '0'; + + } elsif (s/\bwrite\b//i) { + $dir = '1'; + + } else { + $dir = '0'; + + } + + return $dir; +} + + +# ------------------------------------------------------------------------------ +# Get Resp field value +# +# I/O: searches along the current line for a valid error field value +# returns the value of the error field +# ------------------------------------------------------------------------------ +sub GetRespField { + + my $resp; + + + if (s/\bok\b|\bokay\b//i) { + $resp = '00'; + + } elsif (s/\berrcont|errorcont\b//i) { + $resp = '01'; + + } elsif (s/\berrcanc|errorcanc\b//i) { + $resp = '10'; + + } elsif (s/\bxfail\b//i and $adk1 == 0) { + # Reading ADK2 stimulus + + $resp = '00'; + + if ($arch eq 'v6') { + printf "Line %4d: ERROR 104: XFAIL response can only be specified". + " for a W command with Prot[5] asserted\n", $lineNum; + $fileErrors++; + + } else { + printf "Line %4d: ERROR 96: ARMv6 AMBA extensions are not allowed". + " unless V6 architecture is selected: Resp field\n", $lineNum; + $fileErrors++; + + } + + } else { + $resp = '00'; + + } + + return $resp; +} + + +# ------------------------------------------------------------------------------ +# Get Resp field value for Write command +# +# I/O: searches along the current line for a valid error field value +# returns the value of the error field +# ------------------------------------------------------------------------------ +sub GetWriteRespField { + + my $resp; + + + if (s/\bok\b|\bokay\b//i) { + $resp = '00'; + + } elsif (s/\berrcont|errorcont\b//i) { + $resp = '01'; + + } elsif (s/\berrcanc|errorcanc\b//i) { + $resp = '10'; + + } elsif (s/\bxfail\b//i and $adk1 == 0) { + # Reading ADK2 stimulus + + if ($arch eq 'v6') { + $resp = '11'; + + } else { + $resp = '00'; + printf "Line %4d: ERROR 96: ARMv6 AMBA extensions are not allowed". + " unless V6 architecture is selected: Resp field\n", $lineNum; + $fileErrors++; + + } + + } else { + $resp = '00'; + + } + + return $resp; +} + + +# ------------------------------------------------------------------------------ +# Get Wait field value +# +# I/O: searches along the current line for a valid Wait field value +# returns the value of the wait field +# ------------------------------------------------------------------------------ +sub GetWaitField { + + my($wait) = '0'; + + if ($adk1 == 0) { + # reading adk2 stimulus + + if (s/\bwait\b//i) { + $wait = '1'; + + } elsif (s/\bnowait\b//i) { + $wait = '0'; + + } + + } else { + # reading adk1 stimulus + $wait = '0'; + + } + + return $wait; +} + + +# ------------------------------------------------------------------------------ +# Get Loop mandatory number field value +# +# I/O: searches along the current line for a valid number field value +# returns a string of the hex value of the number field, +# or reports an error an defaults to zero +# ------------------------------------------------------------------------------ +sub GetNumberField { + + my $num; + my $hexNum = '00000000'; + + if (s/\b([0-9]{1,10})\b//i) { + + $num = $1; + + if ($num > 2**32-1 or $num < 1) { + # number is out of range + printf "Line %4d: ERROR 43: Loop number out". + " of range [1 to 2^32-1]\n", $lineNum; + $fileErrors++; + $hexNum = '00000000'; + + } else { + # convert to hex string + $hexNum = ToHex32($num); + + } + + } else { + printf "Line %4d: ERROR 37: Loop command must". + " have number specified\n", $lineNum;; + $fileErrors++; + $hexNum = '00000000'; + + } + + return $hexNum; +} + + +# ------------------------------------------------------------------------------ +# Get TimeOut field value +# +# I/O: searches along the current line for a valid repeat field value +# returns the value of the repeat field +# ------------------------------------------------------------------------------ +sub GetToutField { + + my $num; + my $hexNum = '00000000'; + + # TimeOut field is not allowed for ADK1 stimulus + if ($adk1 == 0 and s/\b[t|T]([0-9]{1,10})\b//i) { + + $num = $1; + + if ($num > 2**32-1) { + # number is out of range + printf "Line %4d: ERROR 44: Time out value out". + " of range [0 to 2^32-1]\n", $lineNum; + $fileErrors++; + $hexNum = '00000000'; + + } else { + # convert to hex string + $hexNum = ToHex32($num); + + } + + } else { + $hexNum = '00000000'; + + } + + return $hexNum; +} + + +# ------------------------------------------------------------------------------ +# Get Unalign field value +# +# I/O: searches along the current line for a valid Unalign field value +# returns the value of the Unalign field +# ------------------------------------------------------------------------------ +sub GetUnalignField { + + my $unalign; + + if (s/\balign\b//i) { + $unalign = '0'; + + } elsif (s/\bunalign\b//i) { + $unalign = '1'; + + } else { + $unalign = ''; + + } + + if ( $arch ne 'v6' and $unalign ne '' ) { + printf "Line %4d: ERROR 96: ARMv6 AMBA extensions are not allowed". + " unless V6 architecture is selected: Unalign field\n", $lineNum; + $fileErrors++; + } + + return $unalign; +} + + +# ------------------------------------------------------------------------------ +# Get Bstrb field value +# +# I/O: Searches along the current line for a valid Bstrb field value +# Returns the value of the Bstrb field as a numeric value +# or empty string if not present or in error +# ------------------------------------------------------------------------------ +sub GetBstrbField { + + my $bstrb; + my $bstrbFieldWidth = 0; + + # If Bstrb field found + if (s/\b[s|S]([0|1]{1,16})\b//i) { + + $bstrb = $1; + $bstrbFieldWidth = length($bstrb); + + if ( $arch ne 'v6' ) { + printf "Line %4d: ERROR 96: ARMv6 AMBA extensions are not allowed". + " unless V6 architecture is selected: Bstrb field\n", $lineNum; + $fileErrors++; + $bstrb = ''; + + # check that Bstrb is a valid length for the selected databus width + } elsif ($bstrbFieldWidth > $numLanesBus) { + + printf "Line %4d: ERROR 100: Byte Lane Strobe is not". + " valid for selected busWidth.\n", $lineNum; + $fileErrors++; + $bstrb = ''; + + # check Bstrb field width is either 1,2,4 or 8 binary digits + } elsif (($bstrbFieldWidth != 1) && ($bstrbFieldWidth != 2) && + ($bstrbFieldWidth != 4) && ($bstrbFieldWidth != 8)) { + + printf "Line %4d: ERROR 100: Byte Lane Strobe is an". + " invalid length\n", $lineNum; + $fileErrors++; + $bstrb = ''; + + } + + } else { + $bstrb = ''; + + } + + return $bstrb; +} + + +# ------------------------------------------------------------------------------ +# Calculate line difference +# +# I/O: reads current line number and finds the difference from the last command +# returns the difference +# ------------------------------------------------------------------------------ +sub GetLineDiff { + + my $lineDiffBin; + my $lineDiff; + + $lineDiff = ($lineNum - $prevLineNum); + $prevLineNum = $lineNum; + + # if there are more than 63 blank or comment lines between two commands + # issue a warning to decrease gap, or add a blank C command i.e. C "" + if ($lineDiff > 63) { + $lineDiff = 63; + if ($verbose == 1) { + printf "Line %4d: WARNING 169: Number of blank or comment lines". + " before command exceeds 63\n", $lineNum; + $fileWarnings++; + } + } + + # convert $lineDiff into 6-digits binary + $lineDiffBin = substr ToBin8($lineDiff), 2, 6; + + return $lineDiffBin; +} + + +# ------------------------------------------------------------------------------ +# Check invalid fields +# +# Reports any non-whitespace words as errors +# ------------------------------------------------------------------------------ +sub CheckInvalidFields { + + my $item; + + # First check for unsupported fields that may be ignored + if (s/\bdegrant\b//i and $verbose == 1) { + + printf "Line %4d: WARNING 242: DeGrant field is not supported". + " and will be ignored\n", $lineNum; + $fileWarnings++; + } + + + # If there is anything but whitespace left on the line, it is invalid. + # Only report warnings if verbose is requested + if (($verbose == 1) and /\S/) { + + foreach $item ( split ) { + printf "Line %4d: WARNING 164: \"$item\" is an". + " invalid or duplicate field\n", $lineNum; + $fileWarnings++; + } + } +} + + +# ------------------------------------------------------------------------------ +# Check invalid comment +# +# Reports error if comment string is found where not expected +# ------------------------------------------------------------------------------ +sub CheckInvalidComment { + + my $item = shift; + + if ($item ne '') { + printf "Line %4d: WARNING 164: \"$item\" is an". + " invalid or duplicate field\n", $lineNum; + $fileWarnings++; + } +} + + +# ------------------------------------------------------------------------------ +# Pack comment +# +# Converts a character string to a list of up to 20 32-bit words +# Pads with whitespace +# Reports error for zero-length string +# ------------------------------------------------------------------------------ +sub PackComment { + + my $commentString = shift; + my @words; + + my $length; + + $length = length($commentString); + + if ($length == 0) { + + # Error if zero-length string + printf "Line %4d: ERROR 38: Comment command requires". + " a string within double quotes\n", $lineNum; + $fileErrors++; + $commentString = "\x00"; # Use a NULL character instead of the empty string + + } elsif ($length > 80 and $verbose == 1) { + + # warn if string longer than 80 chars + printf "Line %4d: WARNING 168: Comment exceeds limit". + " of 80 characters. Message will be truncated\n", $lineNum; + $fileWarnings++; + + } + + + # Convert string to up to 20 32-bit words + # String is first padded with 3 null characters + @words = unpack ( 'L20', $commentString."\x00\x00\x00" ); + + return @words +} + +# ------------------------------------------------------------------------------ +# Check comment +# +# Replaces invalid comment characters with a dash (-) and warns. +# ------------------------------------------------------------------------------ +sub CheckComment { + + my $commentString = shift; + my $item; + + # Report invalid characters in comment string. + # Note: every match character has been escaped (using \) because most of + # these characters have a special meaning inside a regular expression + if ($verbose == 1) { + for $item ($commentString =~ + /[^\w\!\$\%\^\&\*\(\)\-\+\=\{\}\[\]\:\;\@\'\~\#\<\>\,\.\?\/\|\ ]/cg) { + + printf "Line %4d: WARNING 165: $item is an". + " invalid character\n", $lineNum; + $fileWarnings++; + } + } + + # Replace invalid characters with a dash (-). + # Note: every match character has been escaped (using \) because most of + # these characters have a special meaning inside a regular expression + $commentString =~ + s/[^\w\!\$\%\^\&\*\(\)\-\+\=\{\}\[\]\:\;\@\'\~\#\<\>\,\.\?\/\|\ ]/-/g; + + return $commentString; +} + + +# ------------------------------------------------------------------------------ +# Check Prot and Resp fields for write command +# +# Can only expect XFAIL for a Write command with Prot[5] set +# ------------------------------------------------------------------------------ +sub CheckWriteProtResp { + +my $prot = shift; +my $resp = shift; + + if ($resp eq '11' and $prot !~ '1[0-1]{5}') { + printf "Line %4d: ERROR 104: XFAIL response can only be specified". + " for a W command with Prot[5] asserted\n", $lineNum; + $fileErrors++; + } +} + + +# ------------------------------------------------------------------------------ +# Increment address +# +# Calculate next address in sequence +# +# ------------------------------------------------------------------------------ +sub IncAddr { + + my $incrAddr = hex(shift); + my $sizeBytes = HsizeToBytes(shift); + my $burst = shift; + + my $burstLength = 0; + my $wrapBytes = 0; # number of bytes in burst + + # calculate beats in wrapping bursts + if ($command{'BUR'} eq '010') { + + $burstLength = 4; + + } elsif ($command{'BUR'} eq '100') { + + $burstLength = 8; + + } elsif ($command{'BUR'} eq '110') { + + $burstLength = 16; + } + + # Address is always incremented from an aligned version + $incrAddr &= (0xFFFFFFFF - $sizeBytes + 1); + + # Increment address by size of transfer + $incrAddr += $sizeBytes; + + # Trap boundaries for wrapping bursts + if ($burstLength > 0) { + + # number of bytes in burst (size * beats) + $wrapBytes = $sizeBytes * $burstLength; + + if ($incrAddr % $wrapBytes == 0) { + $incrAddr -= $wrapBytes; + } + } + + $incrAddr = ToHex32($incrAddr); + + return $incrAddr; +} + + +# ------------------------------------------------------------------------------ +# Determine the transfer size +# +# Check transfer size integrity +# Checks there are no discrepancies in transfer size by comparing values of +# the Size, Data and Mask field. +# Assumes Data and Mask size not > bus width +# ------------------------------------------------------------------------------ + +sub CheckSizeDataMask { + + my $bytesBus = shift; + my $size = shift; + my $data = shift; + my $mask = shift; + my $bstrb = shift; + + # Lengths of fields (in bytes) + my $bytesSize = $size eq '' ? 0 : HsizeToBytes($size); + my $bytesData = length($data) >> 1; # Number of bytes is number of hex digits /2 + my $bytesMask = length($mask) >> 1; # Number of bytes is number of hex digits /2 + my $bytesBstrb = length($bstrb); # Number of bytes is number of binary digits + my $bytesResult = 0; + + my $mismatchError = 0; + + + # Size field sets size whenever specified + if ( ($bytesSize > 0) ) { + $bytesResult = $bytesSize; + } + + # Data only sets size if data field is specified and + # size implied by data < busWidth + if ( ($bytesData > 0) and ($bytesData < $bytesBus) ) { + if ($bytesResult == 0) { # resultant size not already set + # size of data sets transfer size + $bytesResult = $bytesData; + } elsif ($bytesResult != $bytesData) { + $mismatchError = 1; # set mismatch error flag + } + } + + + # Mask only sets size if size implied by mask < busWidth + if ( ($bytesMask > 0) and ($bytesMask < $bytesBus) ) { + if ($bytesResult == 0) { # resultant size not already set + # size of mask sets transfer size + $bytesResult = $bytesMask; + } elsif ($bytesResult != $bytesMask) { + $mismatchError = 1; # set mismatch error flag + } + } + + # Bstrb only sets size if size implied by Bstrb < busWidth + if ( ($bytesBstrb > 0) and ($bytesBstrb < $bytesBus) ) { + if ($bytesResult == 0) { # resultant size not already set + # size of Bstrb sets transfer size + $bytesResult = $bytesBstrb; + } elsif ($bytesResult != $bytesBstrb) { + printf "Line %4d: ERROR 57: Transfer size mismatch:". + " Check Bstrb\n", $lineNum; + $fileErrors++; + } + } + + # Default resultant size is the bus width + $bytesResult = $bytesBus unless $bytesResult > 0; + + # Default size is the resultant size + $bytesSize = $bytesResult unless $bytesSize > 0; + + # If a transfer size mismatch occurred, display Error else + # check if Data/Mask needs aligning within busWidth + if ($mismatchError == 1) { + printf "Line %4d: ERROR 56: Transfer size mismatch:". + " Check Size/Data/Mask\n", $lineNum; + $fileErrors++; + } + + # Convert resultant size back to binary string + $size = BytesToHsize($bytesSize); + + # Default data if data not specified + if ($data eq '' ) { + $bytesData = $bytesBus; # default data is zero across entire bus + $data = '0' x ($bytesData << 1); # Number of hex digits is number of bytes *2 + } + + # Default mask if mask not specified + if ($mask eq '') { + if ($adk1 == 0) { + $bytesMask = $bytesResult; # inactive byte lanes are masked out for ADK2 + } else { + $bytesMask = $bytesBus; # entire bus is compared with data for ADK1 + } + $mask = 'F' x ($bytesMask << 1); # Number of hex digits is number of bytes *2 + } + + return ($size, $data, $mask); + +} + +# ------------------------------------------------------------------------------ +# Shifts the data and mask to the correct byte lanes +# ------------------------------------------------------------------------------ +sub AlignDataMask { + + my $size = shift; + my $data = shift; + my $mask = shift; + my $address = shift; + + # Lengths of fields (in bytes) + my $bytesSize = HsizeToBytes($size); + my $bytesData = length($data) >> 1; # Number of bytes is number of hex digits /2 + my $bytesMask = length($mask) >> 1; # Number of bytes is number of hex digits /2 + + # intermediate variables for data alignment + my $dataH; + my $dataL; + + # intermediate variables for mask alignment + my $maskH; + my $maskL; + + # low order address bits + my $offset; + + # Calculate position within the hex string that the data/mask will start + $offset = hex($address) + & (($maxBytesBus-1) << FromBin8($size)) & ($maxBytesBus-1); + + # Modify the offset according to the endianness of the transfer + $offset = MakeOffsetBigEndian( $offset ) if ($endian eq 'big'); + + # Shift the data to the correct byte lanes + ($dataH, $dataL) = ShiftData( $data, $bytesData, $offset ); + + # Shift the mask to the correct byte lanes + ($maskH, $maskL) = ShiftData( $mask, $bytesMask, $offset ); + + return ($dataH, $dataL, $maskH, $maskL); +} + + +# ------------------------------------------------------------------------------ +# Shift data or mask into correct byte lanes +# and split into High and Low words +# +# Assumes 64 bit data representation +# ------------------------------------------------------------------------------ +sub ShiftData { + + my $value = shift; + my $numLanes = shift; + my $offset = shift; + + my $wordH; + my $wordL; + + # mask and data are zero outside the specified transfer + my $fullWidth = '0000000000000000'; + + # align the address offset with the length of the data + $offset &= (0x100 - $numLanes); # Note 0x100 will cope up to HSIZE =1024 bits + + # Shift the mask or data to the correct byte lanes + substr $fullWidth, ($maxBytesBus-$offset-$numLanes) << 1, $numLanes << 1, $value; + + # Split the data into high and low words + $wordH = substr $fullWidth, 0, $maxBytesBus; + $wordL = substr $fullWidth, $maxBytesBus, $maxBytesBus; + + return ($wordH, $wordL); +} + + +# ------------------------------------------------------------------------------ +# Check for burst exceeding 1kB boundary +# +# Arguments: HSIZE, HBURST, HADDR, number of transfer to check +# ------------------------------------------------------------------------------ +sub Check1kBdy { + + my $transSize = TransSize(shift); + my $currBurst = shift; + my $startAddr = hex(shift); + my $numTransfers = shift; + + + # test only non-wrapping bursts + if ( + ( + $currBurst eq '000' || + $currBurst eq '001' || + $currBurst eq '011' || + $currBurst eq '101' || + $currBurst eq '111' + ) + # Check that last transfer in burst is within the same 1k partition + and ( + ( ($numTransfers * $transSize + $startAddr) & hex('FFFFFC00') ) + != ($startAddr & hex('FFFFFC00')) + ) + ) { + printf "Line %4d: ERROR 88: Burst would exceed". + " 1kB boundary : R\n", $lineNum; + $fileErrors++; + } +} + + +# ------------------------------------------------------------------------------ +# Convert size field to Number of transfers +# +# ------------------------------------------------------------------------------ +sub TransSize { + + my $sizeField = shift; + my $transSize = 1; + + # assign TransSize + if ($sizeField eq '000') {$transSize = 1;} + elsif ($sizeField eq '001') {$transSize = 2;} + elsif ($sizeField eq '010') {$transSize = 4;} + elsif ($sizeField eq '011') {$transSize = 8;} + + return $transSize; +} + + +# ------------------------------------------------------------------------------ +# Check Bstrb and Unalign field integrity +# Checks there are no discrepancies in values specified by Bstrb and Unalign +# fields. Also generates correct value of Bstrb where necessary. +# Returns updated Unalign and Bstrb fields. +# The parameter $seqAddress only need be passed if $endOfUnaligned == 1 +# +# Note! this function must be called before $transCount is updated +# ------------------------------------------------------------------------------ +sub CheckUnalignBstrb { + + my $unalign = shift; + my $bstrb = shift; + my $address = shift; + my $size = shift; + my $endOfUnaligned = shift; + my $seqAddress = shift; + my $idleTransfer = shift; # if true, suppresses error checks + + + my $offset; + my $offsetAligned; + my $seqOffset; + + my $numLanesTrans; + my $numLanesUnalign; + + my $bstrbAligned; + my $bstrbDefault; + my $bstrbCore; + + my $unalignImplied; + my $writeBstrb; + + + # Calculate the number of byte lanes in the transfer + $numLanesTrans = HsizeToBytes($size); + + # Calculate the lower order address bits of an equivalent aligned transfer + $offsetAligned = + $address & + (($maxBytesBus - 1) << (FromBin8($size))) & + ($maxBytesBus - 1); + + # Calculate aligned, little-endian Bstrb which is the default in the FileReadCore + $bstrbCore = CalcBstrb($offsetAligned, $numLanesTrans); # Bstrb in FileRdCore + + # Modify the offset according to the endianness of the transfer, and + # must again align the address offset with the size of the transfer + $offsetAligned = MakeOffsetBigEndian( $offsetAligned ) if ($endian eq 'big'); + $offsetAligned &= (($maxBytesBus - 1) << (FromBin8($size))) & + ($maxBytesBus - 1); + + # Calculate Bstrb based on the aligned address + $bstrbAligned = CalcBstrb($offsetAligned, $numLanesTrans); # aligned version of Bstrb + + # Shift specified Bstrb into the correct byte lanes lanes + if ($bstrb ne '') { + $bstrb = ShiftBstrb($bstrb, $offsetAligned); + } + + # The following section of code checks the rules described in the + # AHB ARMv6 File Reader Bus Master Technical Reference Manual + + # Computes default byte lane strobes based on size and address + # of the transfer if byte lane strobes are not specified by the user + + + # Calculate Bstrb for the unaligned transfer + if ($endian eq 'big') { + + # If big-endian, default Bstrb must be aligned + $bstrbDefault = $bstrbAligned; + + } else { + + # Only interested in lower-order address bits up to width of data bus + $offset = $address & ($maxBytesBus - 1); + + # Modify the offset according to the endianness of the transfer, and + # must again align the address offset with the size of the transfer + $offset = MakeOffsetBigEndian( $offset ) if ($endian eq 'big'); + + # Calculate the number of byte lanes in the transfer for unaligned transfer + $numLanesUnalign = $numLanesTrans - ($offset & ($numLanesTrans - 1)); + + # Special case of Bstrb value generated at the end of an unaligned burst + if ($endOfUnaligned == 1) { + + # Address offset of original transfer in unaligned burst + $seqOffset = hex($seqAddress) & ($maxBytesBus - 1); + + # Calculate the number of byte lanes left over because of unaligned transfer + $numLanesUnalign = $seqOffset & ($numLanesUnalign - 1); + } + + # If little,endian, Bstrb may be unaligned + $bstrbDefault = CalcBstrb($offset, $numLanesUnalign); # default Bstrb for the transfer + } + + if ($bstrb ne '') { + # If Bstrb is specified, check that the specified Bstrb value is legal + CheckBstrbFrame($bstrb, $bstrbDefault) + if (not $idleTransfer); + + # Checks if the specified Bstrb value implies an unaligned transfer + $unalignImplied = UnalignImplied($bstrb, $bstrbAligned); + + # Bstrb may imply Unalign + if ($unalign eq '' ) { + $unalign = $unalignImplied; + } else { + # Verify any specified Unalign field + CheckUnalign($unalign, $unalignImplied) + if (not $idleTransfer); + } + + } else { + # If Bstrb is not specified, use default + $bstrb = $bstrbDefault; + + # Checks if the default Bstrb value implies an unaligned transfer + $unalignImplied = UnalignImplied($bstrbDefault, $bstrbAligned); + + # In this case, Unalign may not be implied + if ($unalign eq '' ) { + $unalign = '0'; + } else { + # Verify any specified Unalign field + CheckUnalign($unalign, $unalignImplied) + if (not $idleTransfer); + } + } + + # Not allowed to have a sparse/unaligned transfer in big-endian mode + if ($endian eq 'big' and not $idleTransfer and $unalign eq '1') { + printf "Line %4d: ERROR 103: Transfer cannot be unaligned or sparse". + " in big-endian mode\n", $lineNum; + $fileErrors++; + } + + # If Bstrb is not equal to the default in the FileRdCore, it must be encoded in the file + $writeBstrb = ($bstrb == $bstrbCore) ? 0 : 1; + + if ($writeBstrb eq '1') { + # Convert to 8-digit hex string for output to data file + $bstrb = ToHex32($bstrb) + } + + return ($unalign, $bstrb, $writeBstrb); +} + + +# ------------------------------------------------------------------------------ +# Shift Bstrb into correct byte lanes +# +# Assumes 64 bit data representation +# Input Bstrb is a string of 1 or 0 +# Output Bstrb is numeric +# ------------------------------------------------------------------------------ +sub ShiftBstrb { + + my $bstrb = shift; + my $offset = shift; + + my $numLanes = length($bstrb); + + # mask and data are zero outside the specified transfer + my $fullBstrb = '00000000'; + + # align the address offset with the length of Bstrb + $offset &= (0x100 - $numLanes); # Note 0x100 will cope up to HSIZE =1024 bits + + # Shift Bstrb value to the correct byte lanes + substr $fullBstrb, ($maxBytesBus-$offset-$numLanes), $numLanes, $bstrb; + + # Convert to numeric + return (FromBin8($fullBstrb)); +} + + +# ------------------------------------------------------------------------------ +# Calculate Bstrb +# +# Arguments: address offset, number of byte lanes in the transfer +# Output Bstrb is numeric +# ------------------------------------------------------------------------------ +sub CalcBstrb { + + my $offset = shift; + my $numLanesTrans = shift; + + my $bstrb; + + # (1 << $numLanesTrans) - 1) is the correct number of strobes for the transfer, + # but shifted into the low order end of the data bus. The final shift left + # by $offset shifts this value into the correct address lanes. + $bstrb = ((1 << $numLanesTrans) - 1) << $offset; + + return $bstrb; +} + +# ------------------------------------------------------------------------------ +# Convert the address offset to big-endian +# +# Copes with address offsets up to 0xFF +# Note! returned offset will need aligning with the data width +# ------------------------------------------------------------------------------ +sub MakeOffsetBigEndian { + + my $offset = shift; + + # Endianness boundary is the number of bytes within each endianness group + # for little endian, value is 1 (i.e. no effect) + # for ARM (legacy) big-endian, value is always 4 (BE-32: 32-bits) + # for true big-endian, value is equal to the databus width in bytes + my $endBdy = 4; + + # Modify the offset according to the endianness of the transfer, + # taking into account endianness granularity $endBdy: + $offset = ( $offset & (0x100 - $endBdy) ) # preserve high bits + | ( ($endBdy - 1) - ($offset & ($endBdy - 1)) ); # reverse low bits + + return $offset; +} + +# ------------------------------------------------------------------------------ +# Checks user-entered Bstrb is within allowed frame +# +# ------------------------------------------------------------------------------ +sub CheckBstrbFrame { + + my $bstrb = shift; + my $bstrbDefault = shift; + + # Check that the byte lane strobes are valid, + # i.e zero outside the size/address frame + if (($bstrb & (((1 << $maxBytesBus) - 1) ^ $bstrbDefault)) != 0) { + printf "Line %4d: ERROR 102: Byte lane strobes are asserted". + " outside the transfer address size frame\n", $lineNum; + + # Un-comment for Debug: + # my $bstrbDefBin = ToBin8($bstrbDefault); + # my $bstrbActBin = ToBin8($bstrb); + # print " Bstrb default = $bstrbDefBin\n". + # " Bstrb actual = $bstrbActBin\n"; + + $fileErrors++; + } + +} + + +# ------------------------------------------------------------------------------ +# Calculate if Bstrb implies Unaligned transfer +# +# If the user has specified a byte lane strobe value, it implies +# an unaligned or aligned transfer. The implied transfer value is obtained +# by comparing the user defined value with the value that will be +# calculated for an aligned transfer by the file reader. +# +# ------------------------------------------------------------------------------ +sub UnalignImplied { + + my $bstrb = shift; + my $bstrbAligned = shift; + + my $unalignImp = '0'; + + + # Generate the implied Unalign value + if ($bstrb eq '' or $bstrb == $bstrbAligned) { + $unalignImp = '0'; + + } else { + $unalignImp = '1'; + } + + return $unalignImp; +} + +# ------------------------------------------------------------------------------ +# Check if the entered UNALIGN values is legal +# +# Compare the user defined value with the implied aligned value +# +# An error condition arises if the user's Unalign input is set to align (0) +# and the calculated value is set to Unalign (1). +# +# ------------------------------------------------------------------------------ +sub CheckUnalign { + + my $unalign = shift; + my $unalignImp = shift; + + + if (($unalign eq '0') & ($unalignImp eq '1')) { + + printf "Line %4d: ERROR 101: Transfer is specified as aligned but". + " Bstrb field implies unaligned\n", $lineNum; + $fileErrors++; + } + +} + + +# ------------------------------------------------------------------------------ +# Check that Exclusive access is aligned +# +# ------------------------------------------------------------------------------ +sub CheckProtUnalign { + + my $prot = shift; + my $unalign = shift; + + # Only applies to v6 stimuli + if ( ($arch eq 'v6') and + ($unalign eq '1') and + (substr($prot, 0, 1) eq '1') + ) { + printf "Line %4d: ERROR 107: Exclusive access cannot be". + " unaligned\n", $lineNum; + $fileErrors++; + } +} + + +# ------------------------------------------------------------------------------ +# Address Alignment Checks +# +# ------------------------------------------------------------------------------ +sub CheckAddrAlign { + + my $size = shift; + my $addr = shift; + my $unalign = shift; + + my $addrSizeErr; + + # Check if there is an Address/Size mismatch + # Tests if address == address & (0xffffffff << 'HSIZE'); + if ( $addr and ( + ( ($size eq '011') && ($addr !~ /([0-9A-Fa-f]{7})[0|8]/i) ) or + ( ($size eq '010') && ($addr !~ /([0-9A-Fa-f]{7})[0|4|8|C]/i) ) or + ( ($size eq '001') && ($addr !~ /([0-9A-Fa-f]{7})[0|2|4|6|8|A|C|E|]/i) ) + ) ) { + + $addrSizeErr = 1; + + if ( $arch eq 'v6' and $unalign eq '1' ) { + # set pending addr/size mismatch error flag + SetMismatch(); + + } else { + # report error + ResetMismatch(); + $fileErrors++; + AddrSizeErrorRpt($size); + } + + } else { + $addrSizeErr = 0; + + } + + return $addrSizeErr +} + + +# ------------------------------------------------------------------------------ +# Report address / size mismatch error +# +# ------------------------------------------------------------------------------ +sub AddrSizeErrorRpt { + + my $size = shift; + + # check address alignment + if ($size eq '011') { + printf "Line %4d: ERROR 64: Address is not". + " dword aligned\n", $lineNum; + $fileErrors++; + + } elsif ($size eq '010') { + printf "Line %4d: ERROR 64: Address is not". + " word aligned\n", $lineNum; + $fileErrors++; + + } elsif ($size eq '001') { + printf "Line %4d: ERROR 64: Address is not". + " halfword aligned\n", $lineNum; + $fileErrors++; + + } else { + printf "Line %4d: ERROR 64: Address is not aligned with size". + " of transfer\n", $lineNum; + $fileErrors++; + } +} + + + +# ------------------------------------------------------------------------------ +# Check for early burst termination +# +# Assumes a new burst is starting +# Arguments: Number of transfers remaining +# +# ------------------------------------------------------------------------------ +sub CheckBurstTerm { + + my $count = shift; + + # If there are remaining transfers and burst is not expected to be cancelled + if ( ($verbose == 1) and ($count > 0) and $sequence{'RESP'} ne '10') { + + printf "Line %4d: WARNING 216: Burst terminated early by". + " insufficient Sequence commands\n", $lineNum; + $fileWarnings++; + } + + # if pending addr/size mismatch error + if (GetMismatch() == 1 and $arch eq 'v6') + { + ResetMismatch(); + if ($verbose == 1) { + printf "Line %4d: WARNING 236: Unaligned transfer crossing address". + " size boundary.\n", $sequence{'LINE'}; + $fileWarnings++; + } + } + +} + + +# ------------------------------------------------------------------------------ +# Set burst counters for the remaining number of transfers in a burst +# +# ------------------------------------------------------------------------------ +sub SetBurstCount { + + my $currBurst = shift; + my $mismatch = shift; + + my $transCount; + my $incrCount; + + # Set the bust counters according to the burst type + if ($currBurst eq '000') {$transCount = 0; $incrCount = 0;} # single + elsif ($currBurst eq '001') {$transCount = 0; $incrCount = 1;} # incr + elsif ($currBurst eq '010') {$transCount = 3; $incrCount = 0;} # wrap4 + elsif ($currBurst eq '011') {$transCount = 3; $incrCount = 0;} # incr4 + elsif ($currBurst eq '100') {$transCount = 7; $incrCount = 0;} # wrap8 + elsif ($currBurst eq '101') {$transCount = 7; $incrCount = 0;} # incr8 + elsif ($currBurst eq '110') {$transCount = 15; $incrCount = 0;} # wrap16 + elsif ($currBurst eq '111') {$transCount = 15; $incrCount = 0;} # incr16 + else {$transCount = 0; $incrCount = 1;} # incr + + # If a defined-length unaligned burst (i.e. not INCR) is taking place, + # there will be an extra transfer + if (GetMismatch() == 1 and $currBurst ne '001') { + $transCount++; + } + + SetTransCount($transCount); + SetIncrCount($incrCount); + + return ($transCount, $incrCount); +} + + +# ------------------------------------------------------------------------------ +# Reset burst counters and check for early burst termination +# +# ------------------------------------------------------------------------------ +sub ResetBurstCount +{ + # Check that previous burst was not terminated early + CheckBurstTerm(GetTransCount()); + + # Reset the bust counters to zero + SetTransCount(0); + SetIncrCount(0); +} + +# Set the transCount counter +sub SetTransCount +{ + $transCount = shift; +} + +# Decrement the transCount counter +sub DecTransCount +{ + # Only valid to decrement the counter if a burst is in progress + if ($transCount > 0) { + $transCount--; + } +} + + +# Get the value of the transCount counter +sub GetTransCount +{ + return $transCount; +} + +# Increment the incrCount counter +sub IncIncrCount +{ + # Only valid to increment the counter if a burst is in progress + if ($incrCount > 0) { + $incrCount++; + } +} + +# Set the Incr counter +sub SetIncrCount +{ + $incrCount = shift; +} + + +# Get the value of the incrCount counter +sub GetIncrCount +{ + return $incrCount; +} + + +# ------------------------------------------------------------------------------ +# Subroutines to set and reset global flag mismatch +# +# ------------------------------------------------------------------------------ +sub SetMismatch +{ + $mismatch = 1; +} + +sub ResetMismatch +{ + $mismatch = 0; +} + +sub GetMismatch +{ + return $mismatch; +} + + +# ------------------------------------------------------------------------------ +# Calculate memory size required for FileReader +# Adds up the total number of 32-bit words required to hold the stimulus +# output +# +# ------------------------------------------------------------------------------ +sub CalcMemory { + +my $cmd = shift; + + if ($cmd eq 'W') { + $memorySize += 4; # Write + + } elsif ($cmd eq 'R') { + $memorySize += 6; # Read + + } elsif ($cmd eq 'S') { + $memorySize += 5; # Seq + + } elsif ($cmd eq 'B') { + $memorySize += 1; # Busy + + } elsif ($cmd eq 'I') { + $memorySize += 2; # Idle + + } elsif ($cmd eq 'P') { + $memorySize += 7; # Poll + + } elsif ($cmd eq 'L') { + $memorySize += 2; # Loop + + } elsif ($cmd eq 'C') { + $memorySize += 2 + $command{'COUNT'}; # Comment + + } elsif ($cmd eq 'Q') { + $memorySize += 1; # Quit + + } else { + # Error - invalid command found - should not happen + warn "WARNING 255: Invalid Command $currCmd for calculating Memory Size". + " at stimulus line $lineNum\n"; + } + + if ($command{'WRITEBS'} eq '1' ) + { + $memorySize ++; + } +} + + +# ------------------------------------------------------------------------------ +# Converts 3-bit binary string representation of Hsize value to number of bytes +# +# ------------------------------------------------------------------------------ +sub HsizeToBytes { + return 1 << unpack("C", pack("B8","00000". shift)); +} + + +# ------------------------------------------------------------------------------ +# Converts number of bytes to binary string representation of Hsize +# +# ------------------------------------------------------------------------------ +sub BytesToHsize { + + my $transferWidth = shift; + my $size = ''; + + if ($transferWidth == 1) {$size = '000'} + elsif ($transferWidth == 2) {$size = '001'} + elsif ($transferWidth == 4) {$size = '010'} + elsif ($transferWidth == 8) {$size = '011'} + else { + # Transfer wider than 64 bits not supported - should not happen + warn "WARNING 254: Unsupported transfer width of $transferWidth bytes". + " at stimulus line $lineNum\n"; + } + + return $size; +} + + +# ------------------------------------------------------------------------------ +# Converts an n-bit binary string to hex with n/4 digits +# Note: Only works for whole bytes. +# +# ------------------------------------------------------------------------------ +sub BinToHex { + unpack('H*', pack('B*', shift)); +} + +# ------------------------------------------------------------------------------ +# Converts an numeric value to 8 hex digits +# +# ------------------------------------------------------------------------------ +sub ToHex32 { + sprintf("%08X", shift); +} + +# ------------------------------------------------------------------------------ +# Converts up to 8 bits binary to a number +# Note: Wraps at 256 +# +# ------------------------------------------------------------------------------ +sub FromBin8 { + unpack('C', pack('B8',substr('0' x 8 . shift, -8))); +} + + +# ------------------------------------------------------------------------------ +# Converts a number to an 8-bit binary string +# Note: Wraps at 256 +# +# ------------------------------------------------------------------------------ +sub ToBin8 { + return unpack( "B8", pack ('C', shift)); +} + + +# ------------------------------------------------------------------------------ +# Output format definitions +# +# ------------------------------------------------------------------------------ + + +format WRITECMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'ADDR'} +@<<<<<<< +$command{'DATAH'} +@<<<<<<< +$command{'DATAL'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format READCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'ADDR'} +@<<<<<<< +$command{'DATAH'} +@<<<<<<< +$command{'DATAL'} +@<<<<<<< +$command{'MASKH'} +@<<<<<<< +$command{'MASKL'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format SEQCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'DATAH'} +@<<<<<<< +$command{'DATAL'} +@<<<<<<< +$command{'MASKH'} +@<<<<<<< +$command{'MASKL'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format BUSYCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format IDLECMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'ADDR'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format POLLCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'TOUT'} +@<<<<<<< +$command{'ADDR'} +@<<<<<<< +$command{'DATAH'} +@<<<<<<< +$command{'DATAL'} +@<<<<<<< +$command{'MASKH'} +@<<<<<<< +$command{'MASKL'} +@<<<<<<< +$command{'BSTRBHEX'} if ($command{'WRITEBS'} eq '1') +. + + +format LOOPCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'NUM'} +. + + +format COMMCMD = +@<<<<<<< +$command{'FUNCTION'} +@<<<<<<< +$command{'NUM'} +@<<<<<<< +$command{'WORD1'} +@<<<<<<< +$command{'WORD2'} if ($command{'COUNT'} > 1) +@<<<<<<< +$command{'WORD3'} if ($command{'COUNT'} > 2) +@<<<<<<< +$command{'WORD4'} if ($command{'COUNT'} > 3) +@<<<<<<< +$command{'WORD5'} if ($command{'COUNT'} > 4) +@<<<<<<< +$command{'WORD6'} if ($command{'COUNT'} > 5) +@<<<<<<< +$command{'WORD7'} if ($command{'COUNT'} > 6) +@<<<<<<< +$command{'WORD8'} if ($command{'COUNT'} > 7) +@<<<<<<< +$command{'WORD9'} if ($command{'COUNT'} > 8) +@<<<<<<< +$command{'WORD10'} if ($command{'COUNT'} > 9) +@<<<<<<< +$command{'WORD11'} if ($command{'COUNT'} > 10) +@<<<<<<< +$command{'WORD12'} if ($command{'COUNT'} > 11) +@<<<<<<< +$command{'WORD13'} if ($command{'COUNT'} > 12) +@<<<<<<< +$command{'WORD14'} if ($command{'COUNT'} > 13) +@<<<<<<< +$command{'WORD15'} if ($command{'COUNT'} > 14) +@<<<<<<< +$command{'WORD16'} if ($command{'COUNT'} > 15) +@<<<<<<< +$command{'WORD17'} if ($command{'COUNT'} > 16) +@<<<<<<< +$command{'WORD18'} if ($command{'COUNT'} > 17) +@<<<<<<< +$command{'WORD19'} if ($command{'COUNT'} > 18) +@<<<<<<< +$command{'WORD20'} if ($command{'COUNT'} > 19) +. + + +format QUITCMD = +@<<<<<<< +$command{'FUNCTION'} +. + +__END__