diff options
Diffstat (limited to 'src/usr/hwpf')
-rwxr-xr-x | src/usr/hwpf/fapi/fapiCreateIfAttrService.pl | 264 | ||||
-rwxr-xr-x | src/usr/hwpf/fapi/fapiParseAttributeInfo.pl | 95 | ||||
-rwxr-xr-x | src/usr/hwpf/hwp/fapiTestHwpAttr.C | 50 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/initfiles/makefile | 44 | ||||
-rw-r--r-- | src/usr/hwpf/hwp/makefile | 1 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initCompiler.C | 311 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initCompiler.H | 106 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initCompiler.lex | 364 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initCompiler.y | 299 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initRpn.C | 1136 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initRpn.H | 303 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initScom.C | 1372 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initScom.H | 247 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initSymbols.C | 1056 | ||||
-rwxr-xr-x | src/usr/hwpf/ifcompiler/initSymbols.H | 269 | ||||
-rw-r--r-- | src/usr/hwpf/makefile | 140 |
16 files changed, 5862 insertions, 195 deletions
diff --git a/src/usr/hwpf/fapi/fapiCreateIfAttrService.pl b/src/usr/hwpf/fapi/fapiCreateIfAttrService.pl new file mode 100755 index 000000000..ab71d80e0 --- /dev/null +++ b/src/usr/hwpf/fapi/fapiCreateIfAttrService.pl @@ -0,0 +1,264 @@ +#!/usr/bin/perl +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/hwpf/fapi/fapiCreateIfAttrService.pl $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2011 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END +# +# Purpose: This perl script will parse HWP Attribute XML files and +# initfile attr files and create the fapiGetInitFileAttr() function +# in a file called fapiAttributeService.C +# +# Author: Mike Jones +# +# Change Log ********************************************************** +# +# Flag Track# Userid Date Description +# ---- -------- -------- -------- ----------- +# mjjones 11/15/11 Copied from fapiParseAttributeInfo +# +# End Change Log ****************************************************** + +use strict; + +#------------------------------------------------------------------------------ +# Print Command Line Help +#------------------------------------------------------------------------------ +my $numArgs = $#ARGV + 1; +if ($numArgs < 4) +{ + print ("Usage: fapiCreateIfAttrService.pl <output dir>\n"); + print (" <if-attr-file1> [<if-attr-file2> ...]\n"); + print (" -a <attr-xml-file1> [<attr-xml-file2> ...]\n"); + print (" This perl script will parse initfile attr files and attribute XML\n"); + print (" files and create the fapiGetInitFileAttr() function in a file\n"); + print (" called fapiAttributeService.C\n"); + exit(1); +} + +#------------------------------------------------------------------------------ +# Specify perl modules to use +#------------------------------------------------------------------------------ +use XML::Simple; +my $xml = new XML::Simple (KeyAttr=>[]); + +# Uncomment to enable debug output +#use Data::Dumper; + +#------------------------------------------------------------------------------ +# Open output file for writing +#------------------------------------------------------------------------------ +my $asFile = $ARGV[0]; +$asFile .= "/"; +$asFile .= "fapiAttributeService.C"; +open(ASFILE, ">", $asFile); + +#------------------------------------------------------------------------------ +# Print Start of file information to fapiAttributeService.C +#------------------------------------------------------------------------------ +print ASFILE "// fapiAttributeService.C\n"; +print ASFILE "// This file is generated by perl script fapiCreateIfAttrService.pl\n\n"; +print ASFILE "#include <fapiAttributeService.H>\n\n"; +print ASFILE "namespace fapi\n"; +print ASFILE "{\n\n"; +print ASFILE "ReturnCode fapiGetInitFileAttr(const AttributeId i_id,\n"; +print ASFILE " const Target * i_pTarget,\n"; +print ASFILE " uint64_t & o_val,\n"; +print ASFILE " const uint32_t i_arrayIndex1,\n"; +print ASFILE " const uint32_t i_arrayIndex2,\n"; +print ASFILE " const uint32_t i_arrayIndex3,\n"; +print ASFILE " const uint32_t i_arrayIndex4)\n"; +print ASFILE "{\n"; +print ASFILE " ReturnCode l_rc;\n\n"; + +my $xmlFiles = 0; +my $attCount = 0; +my @attrIds; + +#------------------------------------------------------------------------------ +# For each argument +#------------------------------------------------------------------------------ +foreach my $argnum (1 .. $#ARGV) +{ + my $infile = $ARGV[$argnum]; + + if ($infile eq '-a') + { + # Start of attribute XML files + $xmlFiles = 1; + next; + } + + if ($xmlFiles == 0) + { + #---------------------------------------------------------------------- + # Process initfile attr file. This file contains the HWPF attributes + # that the initfile uses. + #---------------------------------------------------------------------- + open(ATTRFILE, "<", $infile); + + # Read each line of the file (each line contains an attribute) + while(my $fileAttrId = <ATTRFILE>) + { + # Remove newline + chomp($fileAttrId); + + # Store the attribute in @attrIds if it does not already exist + my $match = 0; + + foreach my $attrId (@attrIds) + { + if ($fileAttrId eq $attrId) + { + $match = 1; + last; + } + } + + if (!($match)) + { + push(@attrIds, $fileAttrId); + } + } + + close(ATTRFILE); + } + else + { + #---------------------------------------------------------------------- + # Process XML file + #---------------------------------------------------------------------- + my $attributes = $xml->XMLin($infile); + + #---------------------------------------------------------------------- + # For each Attribute + #---------------------------------------------------------------------- + foreach my $attr (@{$attributes->{attribute}}) + { + #------------------------------------------------------------------ + # Check that the AttributeId exists + #------------------------------------------------------------------ + if (! exists $attr->{id}) + { + print ("fapiParseAttributeInfo.pl ERROR. Att 'id' missing\n"); + exit(1); + } + + #------------------------------------------------------------------ + # Find if the attribute is used by any initfile + #------------------------------------------------------------------ + my $match = 0; + + foreach my $attrId (@attrIds) + { + if ($attr->{id} eq $attrId) + { + $match = 1; + last; + } + } + + if (!($match)) + { + # Look at the next attribute in the XML file + next; + } + + #------------------------------------------------------------------ + # Figure out the number of attribute array dimensions + #------------------------------------------------------------------ + my $numArrayDimensions = 0; + if ($attr->{array}) + { + # Remove leading whitespace + my $dimText = $attr->{array}; + $dimText =~ s/^\s+//; + + # Split on commas or whitespace + my @vals = split(/\s*,\s*|\s+/, $dimText); + + $numArrayDimensions=@vals; + } + + #------------------------------------------------------------------ + # Print the attribute get code to fapiAttributeService.C + #------------------------------------------------------------------ + if ($attCount > 0) + { + print ASFILE " else "; + } + else + { + print ASFILE " "; + } + $attCount++; + + print ASFILE "if (i_id == $attr->{id})\n"; + print ASFILE " {\n"; + print ASFILE " $attr->{id}_Type l_attr;\n"; + print ASFILE " l_rc = FAPI_ATTR_GET($attr->{id}, i_pTarget, l_attr);\n"; + print ASFILE " o_val = l_attr"; + + if ($numArrayDimensions >= 5) + { + print ("fapiParseAttributeInfo.pl ERROR. More than 4 array dimensions!!\n"); + exit(1); + } + else + { + for (my $i = 0; $i < $numArrayDimensions; $i++) + { + print ASFILE "[i_arrayIndex"; + print ASFILE $i+1; + print ASFILE "]"; + } + } + + print ASFILE ";\n"; + print ASFILE " }\n"; + } + } +} + +#------------------------------------------------------------------------------ +# Print End of file information to fapiAttributeService.C +#-------------------------------------------------------------------------- +if ($attCount > 0) +{ + print ASFILE " else\n"; +} +print ASFILE " {\n"; +print ASFILE " FAPI_ERR(\"fapiGetInitFileAttr: Unrecognized attr: %d\", i_id);\n"; +print ASFILE " ReturnCodeFfdc::addEIFfdc(l_rc, static_cast<uint32_t>(i_id));\n"; +print ASFILE " l_rc = FAPI_RC_INVALID_ATTR_GET;\n"; +print ASFILE " }\n\n"; +print ASFILE " if (l_rc)\n"; +print ASFILE " {\n"; +print ASFILE " FAPI_ERR(\"fapiGetInitFileAttr: Error getting attr\");\n"; +print ASFILE " }\n\n"; +print ASFILE " return l_rc;\n"; +print ASFILE "}\n\n"; +print ASFILE "}\n"; + + +#------------------------------------------------------------------------------ +# Close output file +#------------------------------------------------------------------------------ +close(ASFILE); diff --git a/src/usr/hwpf/fapi/fapiParseAttributeInfo.pl b/src/usr/hwpf/fapi/fapiParseAttributeInfo.pl index 333e68440..e493255ec 100755 --- a/src/usr/hwpf/fapi/fapiParseAttributeInfo.pl +++ b/src/usr/hwpf/fapi/fapiParseAttributeInfo.pl @@ -47,13 +47,11 @@ # camvanng 10/20/11 Changed i_pTarget to "const" ptr # camvanng 11/09/11 Prepend "ENUM_" to attribute # enums +# mjjones 11/15/11 Move gen of fapiAttributeService.C +# to a different file # # End Change Log ****************************************************** -# -# Usage: -# fapiParseAttributeInfo.pl <output dir> <filename1> <filename2> ... - use strict; #------------------------------------------------------------------------------ @@ -62,7 +60,7 @@ use strict; my $numArgs = $#ARGV + 1; if ($numArgs < 2) { - print ("Usage: fapiParseAttributeInfo.pl <output dir> <filename1> <filename2> ...\n"); + print ("Usage: fapiParseAttributeInfo.pl <output dir> <attr-xml-file1> [<attr-xml-file2> ...]\n"); print (" This perl script will parse attribute XML files and add\n"); print (" attribute information to a file called fapiAttributeIds.H\n"); exit(1); @@ -78,18 +76,13 @@ my $xml = new XML::Simple (KeyAttr=>[]); #use Data::Dumper; #------------------------------------------------------------------------------ -# Open output files for writing +# Open output file for writing #------------------------------------------------------------------------------ my $aiFile = $ARGV[0]; $aiFile .= "/"; $aiFile .= "fapiAttributeIds.H"; open(AIFILE, ">", $aiFile); -my $asFile = $ARGV[0]; -$asFile .= "/"; -$asFile .= "fapiAttributeService.C"; -open(ASFILE, ">", $asFile); - #------------------------------------------------------------------------------ # Print Start of file information to fapiAttributeIds.H #------------------------------------------------------------------------------ @@ -105,24 +98,6 @@ print AIFILE " *\/\n"; print AIFILE "enum AttributeId\n{\n"; #------------------------------------------------------------------------------ -# Print Start of file information to fapiAttributeService.C -#------------------------------------------------------------------------------ -print ASFILE "// fapiAttributeService.C\n"; -print ASFILE "// This file is generated by perl script fapiParseAttributeInfo.pl\n\n"; -print ASFILE "#include <fapiAttributeService.H>\n\n"; -print ASFILE "namespace fapi\n"; -print ASFILE "{\n\n"; -print ASFILE "ReturnCode fapiGetInitFileAttr(const AttributeId i_id,\n"; -print ASFILE " const Target * i_pTarget,\n"; -print ASFILE " uint64_t & o_val,\n"; -print ASFILE " const uint32_t i_arrayIndex1,\n"; -print ASFILE " const uint32_t i_arrayIndex2,\n"; -print ASFILE " const uint32_t i_arrayIndex3,\n"; -print ASFILE " const uint32_t i_arrayIndex4)\n"; -print ASFILE "{\n"; -print ASFILE " ReturnCode l_rc;\n\n"; - -#------------------------------------------------------------------------------ # For each XML file #------------------------------------------------------------------------------ foreach my $argnum (1 .. $#ARGV) @@ -287,47 +262,6 @@ foreach my $argnum (1 .. $#ARGV) # Print newline between each attribute's info to fapiAttributeIds.H #---------------------------------------------------------------------- print AIFILE "\n"; - - #---------------------------------------------------------------------- - # Print the attribute get code to fapiAttributeService.C - # *** TODO *** - # Currently, all attributes are supported in fapiGetInitFileAttr() in - # fapiAttributeService.C. Ideally only the initfile attributes should - # be supported to minimize code size. Need to figure out how to do this - #---------------------------------------------------------------------- - if ($attCount > 0) - { - print ASFILE " else "; - } - else - { - print ASFILE " "; - } - $attCount++; - - print ASFILE "if (i_id == $attr->{id})\n"; - print ASFILE " {\n"; - print ASFILE " $attr->{id}_Type l_attr;\n"; - print ASFILE " l_rc = FAPI_ATTR_GET($attr->{id}, i_pTarget, l_attr);\n"; - print ASFILE " o_val = l_attr"; - - if ($numArrayDimensions >= 5) - { - print ("fapiParseAttributeInfo.pl ERROR. More than 4 array dimensions!!\n"); - exit(1); - } - else - { - for (my $i = 0; $i < $numArrayDimensions; $i++) - { - print ASFILE "[i_arrayIndex"; - print ASFILE $i+1; - print ASFILE "]"; - } - } - - print ASFILE ";\n"; - print ASFILE " }\n"; }; } @@ -338,25 +272,6 @@ print AIFILE "}\n\n"; print AIFILE "#endif\n"; #------------------------------------------------------------------------------ -# Print End of file information to fapiAttributeService.C -#-------------------------------------------------------------------------- -print ASFILE " else\n"; -print ASFILE " {\n"; -print ASFILE " FAPI_ERR(\"fapiGetInitFileAttr: Unrecognized attr: %d\", i_id);\n"; -print ASFILE " ReturnCodeFfdc::addEIFfdc(l_rc, static_cast<uint32_t>(i_id));"; -print ASFILE " l_rc = FAPI_RC_INVALID_ATTR_GET;\n"; -print ASFILE " }\n\n"; -print ASFILE " if (l_rc)\n"; -print ASFILE " {\n"; -print ASFILE " FAPI_ERR(\"fapiGetInitFileAttr: Error getting attr\");\n"; -print ASFILE " }\n\n"; -print ASFILE " return l_rc;\n"; -print ASFILE "}\n\n"; -print ASFILE "}\n"; - - -#------------------------------------------------------------------------------ -# Close output files +# Close output file #------------------------------------------------------------------------------ close(AIFILE); -close(ASFILE); diff --git a/src/usr/hwpf/hwp/fapiTestHwpAttr.C b/src/usr/hwpf/hwp/fapiTestHwpAttr.C index df13107dc..55281cf6d 100755 --- a/src/usr/hwpf/hwp/fapiTestHwpAttr.C +++ b/src/usr/hwpf/hwp/fapiTestHwpAttr.C @@ -40,6 +40,7 @@ * camvanng 10/26/2011 Update scratch test * mjjones 10/28/2011 Fix error generation * camvanng 11/09/2011 Update attr enum test + * mjjones 11/17/2011 Removed some initfile attr tests */ #include <fapiTestHwpAttr.H> @@ -805,54 +806,15 @@ fapi::ReturnCode hwpTestAttributes() } //---------------------------------------------------------------------- - // Test getting scratch attributes with the fapiGetInitFileAttr function + // Removed getting scratch attributes using fapiGetInitFileAttr(). This + // now only supports the getting of attributes that are actually used by + // initfiles and those are excercised by the test initfile //---------------------------------------------------------------------- - uint64_t l_val = 0; - fapi::AttributeId l_id; - fapi::AttributeId l_ids[] = {fapi::ATTR_SCRATCH_UINT8_1, - fapi::ATTR_SCRATCH_UINT8_2, - fapi::ATTR_SCRATCH_UINT32_1, - fapi::ATTR_SCRATCH_UINT32_2, - fapi::ATTR_SCRATCH_UINT64_1, - fapi::ATTR_SCRATCH_UINT64_2, - fapi::ATTR_SCRATCH_UINT8_ARRAY_1, - fapi::ATTR_SCRATCH_UINT8_ARRAY_2, - fapi::ATTR_SCRATCH_UINT32_ARRAY_1, - fapi::ATTR_SCRATCH_UINT32_ARRAY_2, - fapi::ATTR_SCRATCH_UINT64_ARRAY_1, - fapi::ATTR_SCRATCH_UINT64_ARRAY_2}; - - for (uint32_t i = 0; i < 12; i++) - { - l_val = 7; - l_id = l_ids[i]; - l_rc = fapiGetInitFileAttr(l_id, NULL, l_val); - - if (l_rc) - { - FAPI_ERR("hwpTestAttributes: ID: %d. Error 0x%x from fapiGetInitFileAttr", - l_ids[i], static_cast<uint32_t>(l_rc)); - break; - } - - if (l_val != 0) - { - FAPI_SET_HWP_ERROR(l_rc, RC_HWP_ATTR_UNIT_TEST_FAIL); - FAPI_ERR("hwpTestAttributes: ID: %d. Get returned %d", - l_ids[i], static_cast<uint32_t>(l_val)); - break; - } - } - - if (l_rc) - { - break; - } //---------------------------------------------------------------------- - // Test getting an invalid scratch attribute with the - // fapiGetInitFileAttr function + // Test getting an invalid attribute using fapiGetInitFileAttr() //---------------------------------------------------------------------- + uint64_t l_val = 0; fapi::AttributeId l_badId = static_cast<fapi::AttributeId>(0xff); l_rc = fapiGetInitFileAttr(l_badId, NULL, l_val); diff --git a/src/usr/hwpf/hwp/initfiles/makefile b/src/usr/hwpf/hwp/initfiles/makefile deleted file mode 100644 index 504deb982..000000000 --- a/src/usr/hwpf/hwp/initfiles/makefile +++ /dev/null @@ -1,44 +0,0 @@ -# IBM_PROLOG_BEGIN_TAG -# This is an automatically generated prolog. -# -# $Source: src/usr/hwpf/hwp/initfiles/makefile $ -# -# IBM CONFIDENTIAL -# -# COPYRIGHT International Business Machines Corp. 2011 -# -# p1 -# -# Object Code Only (OCO) source materials -# Licensed Internal Code Source Materials -# IBM HostBoot Licensed Internal Code -# -# The source code for this program is not published or other- -# wise divested of its trade secrets, irrespective of what has -# been deposited with the U.S. Copyright Office. -# -# Origin: 30 -# -# IBM_PROLOG_END -ROOTPATH = ../../../../../ - -INITFILES_INPUT = sample.initfile -INITFILES_OUTPUT = sample.if - -INITCOMPILER = ${ROOTPATH}/src/build/ifcompiler/bin/initCompiler -ATTR_HEADER = ${ROOTPATH}/obj/genfiles/fapiAttributeIds.H - -EXTRA_PARTS = $(addprefix ${IMGDIR}/, ${INITFILES_OUTPUT}) - -include ${ROOTPATH}/config.mk - -${EXTRA_PARTS}: ${IMGDIR}/% : ${GENDIR}/% - cp -f $^ $@ - -${GENDIR}/%.if: ${INITCOMPILER} ${ATTR_HEADER} %.initfile - ${INITCOMPILER} -init ${INITFILES_INPUT} -outdir ${GENDIR} -attr ${ATTR_HEADER} - - - - - diff --git a/src/usr/hwpf/hwp/makefile b/src/usr/hwpf/hwp/makefile index d027e4b15..cc6d32303 100644 --- a/src/usr/hwpf/hwp/makefile +++ b/src/usr/hwpf/hwp/makefile @@ -20,7 +20,6 @@ # Origin: 30 # # IBM_PROLOG_END -SUBDIRS = initfiles.d ROOTPATH = ../../../.. MODULE = hwp diff --git a/src/usr/hwpf/ifcompiler/initCompiler.C b/src/usr/hwpf/ifcompiler/initCompiler.C new file mode 100755 index 000000000..de8553e6c --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initCompiler.C @@ -0,0 +1,311 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initCompiler.C,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ----- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 D779902 dgilbert 12/08/10 Add ability to specify ouput if file +// andrewg 05/24/11 Port over for VPL/PgP +// andrewg 09/19/11 Updates based on review +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initCompiler.C + * @brief Compile an initfile into bytecode. + */ +#include <stdint.h> +#include <stdio.h> +#include <string> +#include <sstream> +#include <iostream> +#include <fstream> +#include <iomanip> +#include <map> +#include <stdexcept> +#include <initCompiler.H> +#include <initRpn.H> +#include <initSymbols.H> +#include <initScom.H> +//#include <initSpy.H> + +using namespace init; +using namespace std; + +//Globals + +int yyline = 1; +init::ScomList * yyscomlist = NULL; + +ostringstream init::dbg; +ostringstream init::erros; +ostringstream init::stats; // TODO move to Parser + +// Main +int main(int narg, char ** argv) +{ + int rc = 0; + +#if 0 + yyin = fopen("sample.initfile","r"); + if(!yyin) + { + std::cerr << "\nERROR: Failed to open sample.initfile! " << std::endl; + exit(-1); + } + yyparse(); + fclose(yyin); +#endif + + try + { + // Parser: + // - Parse args + // - Set up source location and source type + // - Load & parse Symbols & Spy/Array tables + // - Load & parse the initfile (if there is one) + // + Parser parsed(narg,argv); + + string initfile = parsed.source_fn(); + uint32_t type = parsed.get_source_type(); + + BINSEQ bin_seq; + bin_seq.reserve(0x38000); + + if(type == Parser::IF_TYPE) // input is binary *.if file - build listing from it. + { + + //for(SPY_LIST::iterator i = yyspylist->begin(); i != yyspylist->end(); ++i) + //{ + // cout << (*i)->listing() << endl; + //} + + ifstream ifs(initfile.c_str(), ios_base::in | ios_base::binary); + if(!ifs) + { + string msg("Can't open "); + msg.append(initfile); + throw invalid_argument(msg); + } + while(1) + { + int ch = ifs.get(); + if (!(ifs.good())) break; + bin_seq.push_back(ch); + } + ifs.close(); + + yyscomlist->listing(bin_seq, cout); + + erros << parsed.get_scomlist()->get_symbols()->not_found_listing(); + + } + else // normal initfile processing + { + // Already parsed + yyscomlist->compile(bin_seq); + + + std::cerr << "Compiled size = " << std::dec << bin_seq.size() << endl; + + // if there are missing symbols, SpyList::listing() will add duplicates + // So get the listing now + erros << parsed.get_scomlist()->get_symbols()->not_found_listing(); + + string if_fn = parsed.binseq_fn(); + ofstream ofs(if_fn.c_str(), ios_base::out | ios_base::binary); + if(!ofs) + { + erros << "ERROR - Could not open" << if_fn << endl; + throw invalid_argument(if_fn); + } + else + { + for(BINSEQ::const_iterator bli = bin_seq.begin(); bli != bin_seq.end(); ++bli) + ofs.put((char)(*bli)); + + ofs.close(); + } + //cout << dbg << std::endl; + printf("Generate Listing\n"); + // This builds a listing from the compiled binary sequence + yyscomlist->listing(bin_seq, parsed.listing_ostream()); + yyscomlist->attr_listing(bin_seq, parsed.attr_listing_ostream()); + + // open if file and read in to new SpyList + + printf("Generate Stats\n"); + stats << "*********************************************************\n"; + + cerr << stats.str() << endl; // TODO -> cout + + } + + printf("Generate Debug\n"); + parsed.capture_dbg(); + //if(parsed.debug_mode()) cout << dbg.str() << endl; + } + catch(exception & e) + { + cerr << "ERROR! exception caught: " << e.what() << endl; + rc = 2; + } + + if(erros.str().size()) + { + rc = 1; + cerr << erros.str() << endl; + } + return rc; +} + +// ------------------------------------------------------------------------------------------------ +// Parser: +// Check the args and build the symbol table +// ----------------------------------------------------------------------------------------------- + +Parser::Parser(int narg, char ** argv) +: iv_type(0), iv_scomlist(NULL), iv_dbg(false), iv_ec(0xFFFFFFFF) //dg002c +{ + set<string> header_files; + iv_prog_name = argv[0]; + + stats << iv_prog_name << endl; + --narg; ++argv; + + string type; + + pair<string,string> compare; + + for(int i = 0; i < narg; ++i) + { + string arg(argv[i]); + if(arg.compare(0,5,"-init") == 0) iv_source_path = argv[++i]; + else if (arg.compare(0,3,"-kw") == 0 || + arg.compare(0,4,"-spy") == 0 || + arg.compare(0,5,"-attr") == 0 || + arg.compare(0,6,"-array") == 0 ) header_files.insert(string(argv[++i])); + else if (arg.compare(0,7,"-outdir") == 0) iv_outdir = argv[++i]; + else if (arg.compare(0,2,"-o") == 0) iv_outfile = argv[++i]; //dg003a + else if (arg.compare(0,3,"-if") == 0) iv_source_path = argv[++i]; + else if (arg.compare(0,3,"-ec") == 0) iv_ec = strtoul(argv[++i],NULL,16); //dg002a + else if (arg.compare(0,9,"--compare") == 0) + { + compare.first = argv[++i]; + compare.second = argv[++i]; + } + else if (arg.compare(0,7,"--debug") == 0) iv_dbg = true; + + } + if(iv_source_path.size() == 0) iv_source_path = compare.first; + + if(!narg) // TEST MODE + { + iv_source_path = "p7.initfile"; + header_files.insert("p7_init_spies.h"); + header_files.insert("p7_init_arrays.h"); + header_files.insert("ciniIfSymbols.H"); + } + + size_t pos = iv_source_path.rfind('.'); + if(pos != string::npos) + { + string type = iv_source_path.substr(pos+1); + if(type.compare(0,2,"if") == 0) iv_type = IF_TYPE; + else if(type.compare(0,8,"initfile") == 0) iv_type = INITFILE_TYPE; + + size_t pos1 = iv_source_path.rfind('/',pos); + if(pos1 == string::npos) pos1 = 0; + else ++pos1; + + iv_initfile = iv_source_path.substr(pos1,pos-pos1); + } + + if(iv_outdir.length() == 0) iv_outdir.push_back('.'); + if(iv_outdir.at(iv_outdir.size()-1) != '/') iv_outdir.push_back('/'); + + if(iv_outfile.size() == 0) + { + iv_outfile.append(iv_initfile); + iv_outfile.append(".if"); + } + + iv_outfile.insert(0,iv_outdir); + + stats << "*********************************************************" << endl; + stats << "* source: " << iv_source_path << endl; + stats << "* listing: " << listing_fn() << endl; + stats << "* attr: " << attr_listing_fn() << endl; + stats << "* binary: " << binseq_fn() << endl; + + iv_scomlist = new ScomList(iv_source_path, header_files, stats, iv_ec); //dg002c + if(compare.second.size()) + { + ScomList cmplist(compare.second, header_files, stats, iv_ec); //dg002c + if(iv_scomlist->compare(cmplist)) + { + cout << "Compare SUCCESS" << endl; + } + else + { + cout << stats; + } + } + + iv_list_ostream.open(listing_fn().c_str()); + if(!iv_list_ostream) + { + throw invalid_argument(string("ERROR! Could not open ") + listing_fn()); + } + + iv_attr_list_ostream.open(attr_listing_fn().c_str()); + if(!iv_attr_list_ostream) + { + throw invalid_argument(string("ERROR! Could not open ") + attr_listing_fn()); + } +} + +Parser::~Parser() +{ + iv_list_ostream.close(); + iv_attr_list_ostream.close(); +} + +void Parser::capture_dbg() +{ + if(iv_dbg) + { + string fname(iv_outdir); + fname.append(iv_initfile); + fname.append(".dbg"); + ofstream dbgfs(fname.c_str()); + if(!dbgfs) + { + string msg("Can't open "); + msg.append(fname); + throw invalid_argument(msg); + } + dbgfs << dbg.str() << endl; + dbgfs.close(); + } +} + +// TODO +// - Detect all errors down to a line # ? +// - bad rows/cols check - have already? +// diff --git a/src/usr/hwpf/ifcompiler/initCompiler.H b/src/usr/hwpf/ifcompiler/initCompiler.H new file mode 100755 index 000000000..d49c8e136 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initCompiler.H @@ -0,0 +1,106 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initCompiler.H,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +#if !defined(INITCOMPILER_H) +#define INITCOMPILER_H + +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ----- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 D779902 dgilbert 12/08/10 Ability to specify output if file +// andrewg 05/24/11 Port over for VPL/PgP +// andrewg 09/19/11 Updates based on review +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initCompiler.H + * @brief Compile an initfile into bytecode. + */ + +#include <initRpn.H> +#include <initScom.H> +#include <set> +#include <string> +#include <fstream> + +using namespace std; + + +// bison & flex globals + +extern int yyline; +extern FILE * yyin; +extern int yyparse(); +void yyerror(const char * s); +extern init::ScomList * yyscomlist; + +namespace init +{ + + + extern ostringstream dbg; // debug (verbose) output + extern ostringstream erros; // error output stream + extern ostringstream stats; // Misc info to be displayed + + + + class Parser + { + public: + + enum + { + IF_TYPE = 1, + INITFILE_TYPE = 2 + }; + + Parser(int narg, char ** argv); + ~Parser(); + + string listing_fn() { return (binseq_fn()).append(".list"); } + string attr_listing_fn() { return (binseq_fn()).append(".attr"); } + string source_fn() { return iv_source_path; } + string binseq_fn() { return iv_outfile; } //dg003a + //{ string s(iv_outdir); s.append(iv_initfile); s.append(".if"); return s; } //dg003d + uint32_t get_source_type() { return iv_type; } + + ostream & listing_ostream() { return iv_list_ostream; } + ostream & attr_listing_ostream() { return iv_attr_list_ostream; } + + ScomList * get_scomlist() { return iv_scomlist; } // TODO refactor this out + bool debug_mode() { return iv_dbg; } + + void capture_dbg(); // if iv_dbg then dump the dbg stringstream to a file + + private: + string iv_prog_name; + string iv_source_path; + string iv_initfile; + string iv_outdir; + string iv_outfile; //dg003a + ofstream iv_list_ostream; + ofstream iv_attr_list_ostream; + uint32_t iv_type; + ScomList * iv_scomlist; + bool iv_dbg; + uint32_t iv_ec; // ec filter (if there is one) dg002a + + }; +} + +#endif diff --git a/src/usr/hwpf/ifcompiler/initCompiler.lex b/src/usr/hwpf/ifcompiler/initCompiler.lex new file mode 100755 index 000000000..9abdaded3 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initCompiler.lex @@ -0,0 +1,364 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* fips740 src/engd/initfiles/ifcompiler/initCompiler.lex 1.2 */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* OBJECT CODE ONLY SOURCE MATERIALS */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2010 */ +/* All Rights Reserved */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/* Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ---- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg01 D766229 dgilbert 08/03/10 add check for hex/bin data > 64 bits +// dg02 SW058986 dgilbert 02/28/11 More noticeable fail for missing col headers +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// End Change Log *********************************************************************************/ +/** + * @file initCompiler.lex + * @brief Contains the rules for the lex/flex lexical scanner for scanning initfiles + * + * This code runs as part of the build process to generate a + * byte-coded representation of an initfile + */ +%{ +#include <stdint.h> +#include <iostream> +#include <sstream> +#include <iomanip> +#include <vector> +#include <initRpn.H> +#include <y.tab.h> + +uint64_t bits2int( const char * bitString); +uint64_t hexs2int(const char * hexString, int32_t size); +void pushBackScomBody(); +void push_col(const char *s); +void lex_err(const char *s ); + +std::ostringstream oss; +std::ostringstream t_oss; + +typedef std::vector<std::ostringstream *> OSS_LIST; +OSS_LIST g_colstream; + +inline void clear_colstream() +{ for( OSS_LIST::iterator i = g_colstream.begin(); i != g_colstream.end(); ++i) delete *i; + g_colstream.clear(); +} +uint32_t g_scomcol; +uint32_t g_coltype = 0; +uint32_t g_scomtype = 0; +uint32_t g_paren_level = 0; +bool g_equation = false; // equation inside scomv col +std::string g_scomname; // dg02 + +extern int yyline; + +%} + + + + +NEWLINE \n +FILENAME [A-Za-z][A-Za-z0-9_\.]* +ID [A-Za-z][A-Za-z0-9_]* +ID2 [A-Za-z][A-Za-z0-9_]* +ID3 [0-9]+[A-Za-z_]+[0-9]* +DIGIT [0-9] +COMMENT #.*\n +OP "="|"+"|"-"|"|"|"<"|">"|"*"|"/"|"%" +FLOAT [0-9]+"."[0-9]* +BINARY 0[bB][0-1]+ +SCOM_DATA [ ]*[scom_data][ ]+ +HEX 0[xX][A-Fa-f0-9]+ +SINGLE_HEX [A-Fa-f0-9] +ATTRIBUTE [\[[A-Fa-f0-9]\]] +MULTI_DIGIT [0-9]+ + +%x scomop +%x scomop_array +%x scomop_suffix +%x scomdata +%x when_kw +%x when_expr +%x scomcolname +%x scomrow +%x list +%x enumcol +%x fnames +%x target +%x attribute +%x array + + +%% + +{COMMENT} ++yyline; /* toss comments - need first line */ +\$Id:.*\n ++yyline; /* toss this - read by initCompiler.C */ + + /* Special end-of-file character. */ +<<EOF>> { return 0; } + +SyntaxVersion return INIT_VERSION; + + /* The list of initfile versions is just copied into the *.if file + * so just make it one chunk of string data */ +Versions BEGIN(fnames); +<fnames>[=] oss.str(""); +<fnames>{FLOAT} oss << yytext; +<fnames>[:] oss << yytext; +<fnames>[,] oss << ", "; +<fnames>{FILENAME} oss << yytext; +<fnames>{NEWLINE} { ++yyline; + yylval.str_ptr = new std::string(oss.str()); + BEGIN(INITIAL); + return INIT_VERSIONS; + } + +define { return INIT_DEFINE;} + + +scom { BEGIN(scomop); oss.str(""); return INIT_SCOM; } + +<scomop>{HEX} { + yylval.str_ptr = new std::string(yytext); + oss.str(""); + return INIT_SCOM_ADDR; + } + +<scomop>[\(] {BEGIN(scomop_array); return yytext[0];} + +<scomop_array>{SINGLE_HEX}+ { + yylval.str_ptr = new std::string(yytext); + oss.str(""); + return INIT_INT64_STR; + } + +<scomop_array>[\)] {BEGIN(scomop_suffix); return(yytext[0]);} + +<scomop_suffix>{SINGLE_HEX}+ { + yylval.str_ptr = new std::string(yytext); + oss.str(""); + BEGIN(scomop); + return INIT_SCOM_SUFFIX; + } + +<scomop>[:;\[] { BEGIN(INITIAL); g_coltype = 0; return yytext[0]; } +<scomop>{NEWLINE} { BEGIN(INITIAL); ++yyline; } + +<scomop,scomop_suffix>[\{] { + oss.str(""); + BEGIN(scomcolname); + return yytext[0]; + } + + + + /* The column & row format is really hard to handle in the parser, + * especially since each column can have different parsing rules. + * So fix it here in the scanner by converting the format to + * coltitle1 , row1, row2, ..., row n ; + * coltitle2 , row1, row2, ..., row n ; + * then push it all back into the input stream and scan the new format + */ + +<scomcolname>{COMMENT} ++yyline; +<scomcolname>\n ++yyline; +<scomcolname>{ID} { + g_colstream.push_back(new std::ostringstream()); + *(g_colstream.back()) << yytext; + } +<scomcolname>, {} +<scomcolname>; { BEGIN(scomrow); g_scomcol = 0; } + +<scomrow>{COMMENT} ++yyline; +<scomrow>{NEWLINE} ++yyline; +<scomrow>[^,;\n#\{\}]+ push_col(yytext); +<scomrow>[,] ++g_scomcol; +<scomrow>[;] g_scomcol = 0; +<scomrow>[\}] { + pushBackScomBody(); // create new format and put it back on yyin + BEGIN(INITIAL); + } + + + /* The scombody is the modified format - don't track yyline as it's already + * accounted for. Any errors in here will point back to the last line in the + * 'real' scombody + */ + +bits { g_coltype = INIT_BITS; return INIT_BITS;} +expr { g_coltype = INIT_EXPR; return INIT_EXPR;} +scom_data { g_coltype = INIT_SCOMD; return INIT_SCOMD;} + + /*HEX and Binary numbers in the scombody can be up to 64bit, + * decimal numbers will always fit in 32bit int */ + +{BINARY} { yylval.uint64 = bits2int(yytext); return INIT_INT64; } + +<*>; { g_coltype = 0; return ';'; } + +END_INITFILE return INIT_ENDINITFILE; + +<*>ENUM_{ID} { + yylval.str_ptr = new std::string(yytext); return ATTRIBUTE_ENUM; + } + +<*>{ID} { + yylval.str_ptr = new std::string(yytext); return INIT_ID; + } + +<*>{DIGIT}+ { + sscanf(yytext, "%d", &yylval.integer); return INIT_INTEGER; + } + +<*>{HEX} { + // normal right-justified 64 bit hex integer + yylval.uint64 = hexs2int(yytext,yyleng); + return INIT_INT64; + } + +<*>"&&" return INIT_LOGIC_AND; +<*>"||" return INIT_LOGIC_OR; +<*>"==" return INIT_EQ; +<*>"!=" return INIT_NE; +<*>"<=" return INIT_LE; +<*>">=" return INIT_GE; +<*>">>" return INIT_SHIFT_RIGHT; +<*>"<<" return INIT_SHIFT_LEFT; + +<*>{OP} { g_equation = true; return yytext[0]; } +<*>[\(] { ++g_paren_level; return yytext[0]; } +<*>[\)] { --g_paren_level; return yytext[0]; } + +<*>\[{MULTI_DIGIT}\] { yylval.str_ptr = new std::string(yytext); return ATTRIBUTE_INDEX; } + +<*>[\[\]\{\},:] {g_equation = false; return yytext[0]; } + +<*>[ \t\r]+ /* Eat up whitespace */ +[\n] { BEGIN(INITIAL);++yyline;} + +<*>. lex_err(yytext); + +%% + +int yywrap() { return 1; } + +void lex_err(const char *s ) +{ + std::cerr << "\nERROR: " << s << " -line " << yyline << std::endl; +} + +// Convert left justified bitstring to 64 bit integer +uint64_t bits2int( const char * bitString) +{ + uint32_t idx = 0; + uint64_t mask = 0x8000000000000000ull; + uint64_t val = 0; + do + { + if( (bitString[0] != '0') || + ((bitString[1] != 'b') && (bitString[1] != 'B'))) + { + lex_err("Invalid bit string"); + break; + } + idx = 2; + + while( bitString[idx] != 0 ) + { + char c = bitString[idx]; + if( c == '1') val |= mask; + else if(c != '0') + { + lex_err("Invalid bit string"); + break; + } + ++idx; + mask >>= 1; + } + if(idx > 66) //dg01a 64bits + "0B" prefix + lex_err("Bit string greater than 64 bits!"); + + } while (0); + return val; +} + +// Convert left justified hex string to 64 bit integer +uint64_t hexs2int(const char * hexString, int32_t size) +{ + uint64_t val = 0; + std::string s(hexString); + if(size > 18) //dg01a + { + lex_err("HEX literal greater than 64 bits"); + size = 18; + } + s.append(18-size,'0'); // 0x + 16 digits + val = strtoull(s.c_str(),NULL,16); + return val; +} + +void pushBackScomBody() +{ + std::ostringstream ost; + for(OSS_LIST::iterator i = g_colstream.begin(); i != g_colstream.end(); ++i) + { + ost << (*i)->str() << ';'; + } + ost << '}'; + std::string t = ost.str(); // Was causing weird stuff if I didn't copy the string out first + //std::cout << "<lex comment> Pushing:" << t << std::endl; + //std::cout << "<lex comment> " << std::endl; + + for(std::string::reverse_iterator r = t.rbegin(); + r != t.rend(); + ++r) + { + //std::cout << *r; + unput(*r); + } + //std::cout << std::endl; + clear_colstream(); +} + + +/// help collect column data +void push_col(const char * s) +{ + //dg02a begin + while(g_scomcol >= g_colstream.size()) // more data cols than headers cols + { + // This will force an error in the parser where it can stop the compile. + g_colstream.push_back(new std::ostringstream()); + *(g_colstream.back()) << "MISSING_COLUMN_HEADER"; + lex_err(g_scomname.c_str()); + lex_err("Invalid number of scom cols"); + } + //dgxxa end + //dgxxd remove if(g_colstream < g_colstream.size() + + std::ostringstream & o = *(g_colstream[g_scomcol]); + std::ostringstream token; + std::istringstream iss(s); + std::string t; + //std::cout << "Pushing "; + while(iss >> t) token << t; // get rid of white space + if(token.str().size()) // don't add blank tokens + { + //std::cout << "Pushing ," << token.str() << std::endl; + o << ',' << token.str(); + } +} diff --git a/src/usr/hwpf/ifcompiler/initCompiler.y b/src/usr/hwpf/ifcompiler/initCompiler.y new file mode 100755 index 000000000..4c8da2ca3 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initCompiler.y @@ -0,0 +1,299 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* fips730 src/engd/initfiles/ifcompiler/initCompiler.y 1.1 */ +/* */ +/* IBM CONFIDENTIAL */ +/* */ +/* OBJECT CODE ONLY SOURCE MATERIALS */ +/* */ +/* COPYRIGHT International Business Machines Corp. 2010 */ +/* All Rights Reserved */ +/* */ +/* The source code for this program is not published or otherwise */ +/* divested of its trade secrets, irrespective of what has been */ +/* deposited with the U.S. Copyright Office. */ +/* */ +/* IBM_PROLOG_END_TAG */ +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ---- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// D774126 dgilbert 09/30/10 Add ERROR: to yyerror message +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// andrewg 11/09/11 Refactor to use common include with hwp framework. +// End Change Log ********************************************************************************* +/** + * @file initCompiler.y + * @brief Contains the yacc/bison code for parsing an initfile. + * + * This code runs as part of the build process to generate a + * byte-coded representation of an initfile + */ +%{ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string> +#include <iostream> +#include <iomanip> +#include <sstream> +#include <initCompiler.H> +#include <initSymbols.H> + + +init::Scom * current_scom = NULL; + +extern int yylex(); +void yyerror(const char * s); + +int scom; + +%} + +/* Union for the yylval variable in lex or $$ variables in bsion code. + * Used to store the data associated with a parsed token. + */ +%union{ + uint32_t integer; + uint64_t uint64; + std::string * str_ptr; + init::Rpn * rpn_ptr; +} + + /* indicates the name for the start symbol */ +%start input + + /* Define terminal symbols and the union type + * associated with each. */ + +%token <integer> INIT_INTEGER +%token <uint64> INIT_INT64 +%token <str_ptr> INIT_INT64_STR +%token <str_ptr> INIT_SCOM_ADDR +%token <str_ptr> INIT_SCOM_SUFFIX +%token <uint64> INIT_SCOM_DATA +%token <str_ptr> INIT_ID +%token <str_ptr> INIT_VERSIONS +%token <str_ptr> ATTRIBUTE_INDEX +%token <str_ptr> ATTRIBUTE_ENUM + + + /* Define terminal symbols that don't have any associated data */ + +%token INIT_VERSION +%token INIT_ENDINITFILE +%token INIT_BITS +%token INIT_EXPR +%token INIT_TARG +%token INIT_DEFINE +%token INIT_EQ +%token INIT_NE +%token INIT_LE +%token INIT_GE +%token INIT_SCANINIT +%token INIT_SCOMINIT +%token INIT_SCOM +%token INIT_SCOMD + + + /* non-terminal tokens and the union data-type associated with them */ + +%type <str_ptr> bitsrows +%type <rpn_ptr> expr id_col num_list + + + + + +/* top is lowest precedent - done last */ +%left ATTRIBUTE_INDEX /* irrelevant precedence, but needed for clean compile */ +%left INIT_LOGIC_OR +%left INIT_LOGIC_AND +%left '|' /* bitwise OR */ +%left '^' /* bitwise XOR */ +%left '&' /* bitwise AND */ +%left INIT_EQ INIT_NE +%left INIT_LE INIT_GE '<' '>' +%left INIT_SHIFT_RIGHT INIT_SHIFT_LEFT +%left '-' '+' +%left '*' '/' '%' +%right '!' '~' /* logic negation bitwise complement*/ +/* bottom is highest precedent - done first */ + + + + +%% +/* Grammars */ + /* the 'input' is simply all the lines */ +input: + | input line +; + +line: scom + | cvs_versions + | syntax_version + | define + | INIT_ENDINITFILE { yyscomlist->clear_defines(); } +; + + +cvs_versions: INIT_VERSIONS + { + yyscomlist->set_cvs_versions($1); delete $1; + } +; + +syntax_version: INIT_VERSION '=' INIT_INTEGER + { + yyscomlist->set_syntax_version($3); + } +; + +scom: INIT_SCOM {current_scom = new init::Scom(yyscomlist->get_symbols(),yyline);} + | scom scomaddr '{' scombody '}' + { + /* printf("Found an INIT_SCOM!\n"); */ + /* current_scom = new init::Scom(yyscomlist->get_symbols(),yyline); */ + } +; + +scomaddr: + | INIT_SCOM_ADDR { + /*printf("Found an INIT_SCOM_ADDR 0x%X!\n",$1);*/ + current_scom->set_scom_address(*($1)); delete $1; + yyscomlist->insert(current_scom); + } + | scomaddr '(' scom_list ')' { } + | scomaddr '(' scom_list ')' INIT_SCOM_SUFFIX { current_scom->set_scom_suffix(*($5)); delete $5; } +; + + +scom_list: INIT_INT64_STR { current_scom->dup_scom_address(*($1));delete $1;} + | scom_list ',' INIT_INT64_STR { current_scom->dup_scom_address(*($3));delete $3;} +; + + + /* The scombody was reformatted by the scanner + * colname1 , row1 , row 2, ... , row n ; + * colname2 , row1 , row 2, ... , row n ; + */ + +scombody: scombodyline ';' {} + | scombody scombodyline ';' {} +; + +scombodyline: INIT_SCOMD ',' scomdrows {} + | INIT_BITS ',' bitsrows {} + | INIT_EXPR ',' exprrows { init::dbg << "Add col EXPR" << endl; current_scom->add_col("EXPR"); } + | INIT_ID ',' idrows { + current_scom->add_col(*($1)); + init::dbg << "Add col " << *($1) << endl; + delete $1; + } + +; + + +scomdrows: expr { + /*printf("scomdrows - RPN Address:0x%X\n",$1);*/ + init::dbg << $1->listing("Length scom RPN"); + current_scom->add_scom_rpn($1); + } + | scomdrows ',' expr { init::dbg << $3->listing("Length scom RPN"); current_scom->add_scom_rpn($3); } +; + + +/* +scomdrows: id_col { printf("scomdrows\n"); } +; +*/ + +bitsrows: bitrange {} + | bitsrows ',' bitrange {} +; + +bitrange: INIT_INTEGER { current_scom->add_bit_range($1,$1); } + | INIT_INTEGER ':' INIT_INTEGER + { current_scom->add_bit_range($1,$3); } +; + +exprrows: expr { init::dbg << $1->listing(NULL); current_scom->add_row_rpn($1); } + | exprrows ',' expr + { init::dbg << $3->listing(NULL); current_scom->add_row_rpn($3); } +; + +idrows: id_col { init::dbg << $1->listing(NULL); current_scom->add_row_rpn($1); } + | idrows ',' id_col { init::dbg << $3->listing(NULL); current_scom->add_row_rpn($3); } +; + + + // TODO num_list could be VARs,LITs, or even ranges eg {1,2..5,7} + +id_col: INIT_ID { $$ = new init::Rpn(*($1),yyscomlist->get_symbols()); $$->push_op(EQ); delete $1; } + | INIT_INTEGER { $$ = new init::Rpn($1,yyscomlist->get_symbols()); $$->push_op(EQ); } + | '{' num_list '}' { $$ = $2; $2->push_op(LIST); $2->push_op(EQ); } + | ATTRIBUTE_ENUM { $$ = new init::Rpn((yyscomlist->get_symbols())->get_attr_enum_val(*($1)),yyscomlist->get_symbols()); $$->push_op(EQ); delete $1; } +; + + + +num_list: INIT_INTEGER { $$ = new init::Rpn($1,yyscomlist->get_symbols()); } + | INIT_ID { $$ = new init::Rpn(*($1),yyscomlist->get_symbols()); } + | num_list ',' INIT_INTEGER { $$ = $1; $1->merge(new init::Rpn($3,yyscomlist->get_symbols())); } + | num_list ',' INIT_ID { $$ = $1; $1->merge(new init::Rpn(*($3),yyscomlist->get_symbols())); } + | ATTRIBUTE_ENUM { $$ = new init::Rpn((yyscomlist->get_symbols())->get_attr_enum_val(*($1)),yyscomlist->get_symbols()); } +; + + +define: INIT_DEFINE INIT_ID '=' expr ';' + { + init::dbg << $2 << ':' << endl << $4->listing("Length of rpn for Define"); + yyscomlist->add_define($2,$4); + delete $2; + } +; + + /* expr should return an RPN string of some kind */ +expr: INIT_INTEGER { $$= new init::Rpn($1,yyscomlist->get_symbols()); } + | INIT_ID { $$= new init::Rpn(*($1),yyscomlist->get_symbols()); delete $1; } + | ATTRIBUTE_ENUM { $$= new init::Rpn((yyscomlist->get_symbols())->get_attr_enum_val(*($1)),yyscomlist->get_symbols()); delete $1; } + | INIT_INT64 { $$=new init::Rpn($1,yyscomlist->get_symbols()); } + | expr ATTRIBUTE_INDEX { $1->push_array_index(*($2));} + | expr INIT_LOGIC_OR expr { $$ = $1->push_merge($3,OR); } + | expr INIT_LOGIC_AND expr { $$ = $1->push_merge($3,AND); } + | expr INIT_EQ expr { $$ = $1->push_merge($3,EQ); } + | expr INIT_NE expr { $$ = $1->push_merge($3,NE); } + | expr INIT_LE expr { $$ = $1->push_merge($3,LE); } + | expr INIT_GE expr { $$ = $1->push_merge($3,GE); } + | expr '<' expr { $$ = $1->push_merge($3,LT); } + | expr '>' expr { $$ = $1->push_merge($3,GT); } + | expr INIT_SHIFT_RIGHT expr { $$ = $1->push_merge($3,SHIFTRIGHT); } + | expr INIT_SHIFT_LEFT expr { $$ = $1->push_merge($3,SHIFTLEFT); } + | expr '+' expr { $$ = $1->push_merge($3,PLUS); } + | expr '-' expr { $$ = $1->push_merge($3,MINUS); } + | expr '*' expr { $$ = $1->push_merge($3,MULT); } + | expr '/' expr { $$ = $1->push_merge($3,DIVIDE); } + | expr '%' expr { $$ = $1->push_merge($3,MOD); } + | '!' expr { $$ = $2->push_op(NOT); } + | '(' expr ')' { $$ = $2; } +; + + +%% + +void yyerror(const char * s) +{ + init::erros << setfill('-') << setw(80) << '-' << endl; + init::erros << setfill('0'); + init::erros << "Parse Error line " << dec << setw(4) << yyline << ": yychar = " + << dec << (uint32_t) yychar << " [0x" << hex << (uint32_t) yychar << "] '"; + if(isprint(yychar)) init::erros << (char)yychar; + else init::erros << ' '; + init::erros << "' yylval = " << hex << "0x" << setw(8) << yylval.integer << endl; + init::erros << "ERROR: " << s << endl; + init::erros << setfill('-') << setw(80) << '-' << endl << endl; +} diff --git a/src/usr/hwpf/ifcompiler/initRpn.C b/src/usr/hwpf/ifcompiler/initRpn.C new file mode 100755 index 000000000..39af931a1 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initRpn.C @@ -0,0 +1,1136 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initRpn.C,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +// Change Log ************************************************************************************* +// +// Flag Reason Userid Date Description +// ----- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 SW047506 dgilbert 12/09/10 SERIES filtering +// andrewg 05/24/11 Port over for VPL/PgP +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// andrewg 11/09/11 Multi-dimensional array and move to common fapi include +// End Change Log ********************************************************************************* + +/** + * @file initRpn.C + * @brief Definition of the initRpn class. Handles Reverse Polish Notation equations for initfiles + */ +#include <initRpn.H> +#include <initSymbols.H> +//#include <initSpy.H> +#include <stdlib.h> +#include <sstream> +#include <iomanip> +#include <iostream> +#include <stdexcept> + +using namespace init; + +const char * OP_TXT[] = +{ + "PUSH", + "AND", + "OR", + "NOT", + "EQ", + "NE", + "GT", + "GE", + "LT", + "LE", + "PLUS", + "MINUS", + "MULT", + "DIVIDE", + "MOD", + "LIST", + "SHIFTLEFT", + "SHIFTRIGHT", + "FALSE", //dg003a + "TRUE", //dg003a +}; + +std::string Rpn::cv_empty_str; + +//------------------------------------------------------------------------------------------------- + +Rpn::Rpn(uint32_t i_uint,Symbols * symbols) : iv_symbols(symbols) +{ push_int(i_uint);} + +//------------------------------------------------------------------------------------------------- + +Rpn::Rpn(std::string i_id, Symbols * symbols, TYPE i_type) : iv_symbols(symbols) +{ push_id(i_id, i_type); } + +//------------------------------------------------------------------------------------------------- + +Rpn::Rpn(uint64_t i_uint, Symbols * symbols) : iv_symbols(symbols) +{ + push_int64(i_uint); +} + +//------------------------------------------------------------------------------------------------- + +bool Rpn::operator==(const Rpn & r) +{ + bool result = false; + if (iv_rpnstack.size() == r.iv_rpnstack.size()) + { + if (iv_symbols == r.iv_symbols) + { + result = true; + RPNSTACK::const_iterator c1 = iv_rpnstack.begin(); + RPNSTACK::const_iterator c2 = r.iv_rpnstack.begin(); + for (; c1 != iv_rpnstack.end(); ++c1, ++c2) + { + if (*c1 != *c2) + { + result = false; + break; + } + } + } + else // they have different symbol tables + { + result = true; + RPNSTACK::const_iterator c1 = iv_rpnstack.begin(); + RPNSTACK::const_iterator c2 = r.iv_rpnstack.begin(); + for (; c1 != iv_rpnstack.end(); ++c1, ++c2) + { + uint32_t t1 = (*c1) & TYPE_MASK; + uint32_t t2 = (*c2) & TYPE_MASK; + if(t1 != t2) + { + result = false; + break; + } + switch (t1) + { + case DEFINE: + { + Rpn r1 = iv_symbols->get_define_rpn(*c1); + Rpn r2 = r.iv_symbols->get_define_rpn(*c2); + if (r1 != r2) result = false; + } + break; + case SYMBOL: + { + string s1 = iv_symbols->find_name(*c1); + string s2 = (r.iv_symbols)->find_name(*c2); + if(s1 != s2) result = false; + } + break; + case NUMBER: + { + uint32_t size = 0; + uint64_t data1 = iv_symbols->get_numeric_data(*c1,size); + uint64_t data2 = (r.iv_symbols)->get_numeric_data(*c2,size); + // do we care if the size is different only the value? + if(data1 != data2) result = false; + } + break; + case OPERATION: // independent of symbol table - just compare + default: // just compare + if(*c1 != *c2) result = false; + break; + } + if(result == false) break; + } + } + } + return result; +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::push_int(uint32_t i_uint) +{ + uint32_t rpn_id = iv_symbols->find_numeric_lit(i_uint,4); + iv_rpnstack.push_back(rpn_id); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::push_int64(uint64_t i_uint) +{ + uint32_t rpn_id = iv_symbols->find_numeric_lit(i_uint,8); + iv_rpnstack.push_back(rpn_id); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::push_id(std::string & i_id, TYPE i_type) +{ + uint32_t rpn_id = 0; + std::string s(i_id); + + for (std::string::iterator c = s.begin(); c != s.end(); ++c) + { + *c = toupper(*c); + } + + rpn_id = iv_symbols->use_symbol(s); + + if (rpn_id & DEFINE) + { + Rpn r = iv_symbols->get_define_rpn(rpn_id); + append(r); + } + else + { + iv_rpnstack.push_back(rpn_id); + } +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::push_array_index(std::string &i_array_idx) +{ + string l_idx = i_array_idx; + // strip of leading "[" and last "]" + l_idx = l_idx.substr(1,(l_idx.length() - 2)); + uint32_t l_array_val = atoi(l_idx.c_str()); + + uint32_t rpn_id = iv_symbols->find_numeric_array_lit(l_array_val,4); + iv_rpnstack.push_back(rpn_id); + + // printf("Array Index: %s decimal:%u rpn_id:0x%8X\n",l_idx.c_str(),l_array_val,rpn_id); + +} + +//------------------------------------------------------------------------------------------------- +void Rpn::push_attr_enum(std::string &i_attr_enum) +{ + uint64_t l_attr_enum_val = iv_symbols->get_attr_enum_val(i_attr_enum); + + uint32_t rpn_id = iv_symbols->find_numeric_lit(l_attr_enum_val,8); + iv_rpnstack.push_back(rpn_id); + + //printf("Attribute Enum name: %s Value:%u rpn_id:0x%8X\n",i_attr_enum.c_str(),l_attr_enum_val,rpn_id); +} + +//------------------------------------------------------------------------------------------------- + +bool Rpn::isTrue() const //dg003a +{ + if((iv_rpnstack.size() == 1) && (iv_rpnstack[0] == (TRUE_OP | OPERATION))) return true; + return false; +} + +//------------------------------------------------------------------------------------------------- + +bool Rpn::isFalse() const //dg003a +{ + if((iv_rpnstack.size() == 1) && (iv_rpnstack[0] == (FALSE_OP | OPERATION))) return true; + return false; +} + +//------------------------------------------------------------------------------------------------- + +Rpn * Rpn::push_op(IfRpnOp op) +{ + uint32_t v = op; + if(op == LIST) // calculate list size + { + uint32_t count = 0; + for(RPNSTACK::const_reverse_iterator r = iv_rpnstack.rbegin(); r != iv_rpnstack.rend(); ++r) + { + if(((*r) & TYPE_MASK) == OPERATION) break; + ++count; + } + v |= (count << 8); + } + iv_rpnstack.push_back(v | OPERATION); + + return this; +} + +//------------------------------------------------------------------------------------------------- +// @post i_rpn is deleted + +Rpn * Rpn::push_merge(Rpn * i_rpn, IfRpnOp op) +{ + //dg003a begin + Rpn * result = this; + + // oportunity for Rpn optimization + // rpn && true, -> rpn + // rpn && false, -> false + // rpn || false, -> rpn + // rpn || true, -> true + if(op == AND) + { + if(i_rpn->isTrue()) + { + delete i_rpn; + return result; // leave this RPN alone + } + if(this->isTrue()) + { + iv_rpnstack.clear(); + return merge(i_rpn); // merge deletes i_rpn + } + if(i_rpn->isFalse() || this->isFalse()) + { + iv_rpnstack.clear(); + delete i_rpn; + push_op(FALSE_OP); + return result; + } + } + else if(op == OR) + { + if(i_rpn->isFalse()) + { + delete i_rpn; + return result; + } + if(this->isFalse()) + { + iv_rpnstack.clear(); + return merge(i_rpn); // merge deletes i_rpn + } + if(i_rpn->isTrue() || this->isTrue()) + { + iv_rpnstack.clear(); + delete i_rpn; + push_op(TRUE_OP); + return result; + } + } + + // Filter out SERIES calculations since this is for SERIES_IP only + // There might be a better place/way to do this?? + // TODO - No idea what this is really +#if 0 + Rpn r1("SERIES",iv_symbols); + Rpn r2("SERIES_IP",iv_symbols); + Rpn r3("SERIES_Z",iv_symbols); + if( *this == r1) + { + if((op == EQ && *i_rpn == r2) || (op == NE && *i_rpn == r3)) + { + iv_rpnstack.clear(); + push_op(TRUE_OP); + delete i_rpn; + return result; + } + if((op == EQ && *i_rpn == r3) || (op == NE && *i_rpn == r2)) + { + iv_rpnstack.clear(); + push_op(FALSE_OP); + delete i_rpn; + return result; + } + } +#endif + // These two expressions are seen as a result of macro expansion + // Reduce (expr1 == expr2) == 0 -> expr1 != expr2 + // Reduce (expr1 == expr2) == 1 -> expr1 == expr2 + // Reduce for any logic operation + if(op == EQ) + { + Rpn r_zero((uint32_t)0,iv_symbols); + Rpn r_one((uint32_t)1, iv_symbols); + + if ((*i_rpn) == r_zero) + { + if((*this) == r_zero) + { + delete i_rpn; + iv_rpnstack.pop_back(); + push_op(TRUE_OP); + return result; + } + if((*this) == r_one) + { + delete i_rpn; + iv_rpnstack.pop_back(); + push_op(FALSE_OP); + return result; + } + // else check for logical op + switch (iv_rpnstack.back()) + { + case (AND | OPERATION): + case (OR | OPERATION): + push_op(NOT); + delete i_rpn; + return result; + + case (NOT | OPERATION): // untie the NOT + iv_rpnstack.pop_back(); + delete i_rpn; + return result; + + case (EQ | OPERATION): + iv_rpnstack.back() = (NE | OPERATION); + delete i_rpn; + return result; + + case (NE | OPERATION): + iv_rpnstack.back() = (EQ | OPERATION); + delete i_rpn; + return result; + + case (GT | OPERATION): + iv_rpnstack.back() = (LE | OPERATION); + delete i_rpn; + return result; + + case (GE | OPERATION): + iv_rpnstack.back() = (LT | OPERATION); + delete i_rpn; + return result; + + case (LT | OPERATION): + iv_rpnstack.back() = (GE | OPERATION); + delete i_rpn; + return result; + + case (LE | OPERATION): + iv_rpnstack.back() = (GT | OPERATION); + delete i_rpn; + return result; + + case (TRUE_OP | OPERATION): + iv_rpnstack.back() = (FALSE_OP | OPERATION); + delete i_rpn; + return result; + + case (FALSE_OP | OPERATION): + iv_rpnstack.back() = (TRUE_OP | OPERATION); + delete i_rpn; + return result; + + default: // Not a logic operation - leave it alone + break; + } + } + else if((*i_rpn) == r_one) + { + if((*this) == r_one) + { + delete i_rpn; + iv_rpnstack.pop_back(); + push_op(TRUE_OP); + return result; + } + if((*this) == r_zero) + { + delete i_rpn; + iv_rpnstack.pop_back(); + push_op(FALSE_OP); + return result; + } + // else check for logical op - leave it as is + uint32_t l_op = iv_rpnstack.back(); + if((l_op == (AND | OPERATION)) || + (l_op == (OR | OPERATION)) || + (l_op == (NOT | OPERATION)) || + (l_op == (EQ | OPERATION)) || + (l_op == (NE | OPERATION)) || + (l_op == (GT | OPERATION)) || + (l_op == (GE | OPERATION)) || + (l_op == (LT | OPERATION)) || + (l_op == (LE | OPERATION)) || + (l_op == (TRUE_OP | OPERATION)) || + (l_op == (FALSE_OP | OPERATION))) + { + delete i_rpn; + return result; + } + } + } + + // other stuff i've seen TODO + // (0 == 1) == 1 , reduced already to (0 == 1) used to turn off a row - Could eliminate the row? + // + + + //dg003a end + + iv_rpnstack.insert(iv_rpnstack.end(), i_rpn->iv_rpnstack.begin(), i_rpn->iv_rpnstack.end()); + result = push_op(op); + + delete i_rpn; + return result; +} + +//------------------------------------------------------------------------------------------------- +// @post i_rpn is deleted + +Rpn * Rpn::merge(Rpn * i_rpn) +{ + iv_rpnstack.insert(iv_rpnstack.end(), i_rpn->iv_rpnstack.begin(), i_rpn->iv_rpnstack.end()); + delete i_rpn; + return this; +} + +//------------------------------------------------------------------------------------------------- +// See header file for contract +void Rpn::bin_read(BINSEQ::const_iterator & bli, Symbols * symbols) +{ + + uint32_t size = 2; // Size is always 2 for symbols + + if(symbols) iv_symbols = symbols; + iv_rpnstack.clear(); + + while(size) + { + uint32_t v = *bli++; + if(v < LAST_OP) // operator + { + if(v == LIST) + { + --size; + v |= (*bli++) << 8; + } + iv_rpnstack.push_back(v | OPERATION); + --size; + } + else // tag + { + v = (v << 8) + (*bli++); + --size; + if(size == 0) + { + std::ostringstream errss; + errss << "Rpn::bin_read Invalid RPN binary sequence\n"; + throw std::invalid_argument(errss.str()); + } + --size; + iv_rpnstack.push_back(iv_symbols->get_rpn_id(v)); + } + } +} + +//------------------------------------------------------------------------------------------------- +BINSEQ::const_iterator Rpn::bin_read_one_op(BINSEQ::const_iterator & bli, Symbols * symbols) +{ + if(symbols) iv_symbols = symbols; + while(true) + { + uint32_t v = *bli++; + if(v < LAST_OP) // operator + { + if(v == LIST) // list has a size and another OP associated with it. + { + v |= (*bli++) << 8; // merge size into LIST op + iv_rpnstack.push_back(v | OPERATION); + v = *bli++; // get the list operation (EQ or NE) + } + iv_rpnstack.push_back(v | OPERATION); + // we are done + break; + } + // not op - always two bytes + v = (v << 8) + (*bli++); + iv_rpnstack.push_back(iv_symbols->get_rpn_id(v)); + } + return bli; +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::append(const Rpn & i_rpn) +{ + iv_rpnstack.insert(iv_rpnstack.end(), i_rpn.iv_rpnstack.begin(), i_rpn.iv_rpnstack.end()); +} + +//------------------------------------------------------------------------------------------------- + +std::string Rpn::symbol_names() const +{ + std::string result; + for(RPNSTACK::const_iterator i = iv_rpnstack.begin(); i != iv_rpnstack.end(); ++i) + { + if((*i) & SYMBOL) + { + if(result.size()) result.append(" "); // space or lf?? + result.append(iv_symbols->find_name(*i)); + } + } + return result; +} + +//------------------------------------------------------------------------------------------------- + +std::string Rpn::listing(const char * i_desc, const std::string & spyname, bool i_final) +{ + std::ostringstream odesc; + std::ostringstream oss; + uint32_t rpn_byte_size = 0; + + + oss << std::hex << std::setfill('0'); + + //oss << "0x" << std::setw(2) << iv_rpnstack.size() << '\t' << i_desc << std::endl; + for(RPNSTACK::iterator i = iv_rpnstack.begin(); i != iv_rpnstack.end(); ++i) + { + if( (*i) & OPERATION ) // operator + { + ++rpn_byte_size; + uint32_t op_id = (*i) - OPERATION; + uint32_t count = op_id >> 8; // NOTE: only the LIST operator has a count + op_id &= OP_MASK; + + if(op_id < LAST_OP) + { + oss << "0x" << std::setw(2) << op_id << "\t\t" << OP_TXT[op_id] << std::endl; + if(op_id == LIST) + { + ++rpn_byte_size; + oss << "0x" << std::setw(2) << count << "\t\t" + << std::dec << count << std::hex << std::endl; + } + } + else + { + oss << "0x" << op_id << "\t\t" << "INVALID OPERATION" << std::endl; + } + } + else if((*i) & NUMBER) + { + uint32_t size = 0; + uint64_t data = iv_symbols->get_numeric_data(*i,size); + if(i_final) + { + uint32_t tag = iv_symbols->get_numeric_tag(*i); + rpn_byte_size += 2; + oss << "0x" << std::setw(4) << tag << "\t\t" << "PUSH 0x" + << std::setw(size*2) << data << std::endl; + } + else + { + rpn_byte_size += size; + oss << "0x" << std::setw(size * 2) << data << '\t' << "Numerica Literal" << std::endl; + } + } + else if((*i) & SYMBOL) + { + std::string name = iv_symbols->find_name(*i); + + if(i_final) + { + uint32_t val = iv_symbols->get_tag(*i); + uint32_t type = val & IF_TYPE_MASK; + + if (type == IF_ATTR_TYPE) + { + rpn_byte_size += 2; + oss << "0x" << std::setw(4) << val << "\t\t" << "PUSH " << name << std::endl; + } + else + { + rpn_byte_size +=4; + oss << "0x" << std::setw(8) << val << '\t' << name << "\tUnresolved!" << std::endl; + } + } + else // debug listing + { + rpn_byte_size +=2; + //oss << "0x" << std::setw(8) << *i << '\t' + oss << "\t\t" << "PUSH " << name << std::endl; + + } + } + else + { + oss << "0x" << std::setw(8) << *i << '\t' << "Unknown RPN id" << std::endl; + } + } + + if((iv_rpnstack.size() == 1) && (iv_rpnstack.front() & SYMBOL)) // skip size and desc + { + odesc << oss.str(); + } + else + { + odesc << std::hex << std::setfill('0') + << "0x" << std::setw(4) << rpn_byte_size << "\t\t"; + if(i_desc) odesc << i_desc; + else odesc << std::dec << rpn_byte_size << " BYTES"; + odesc << std::endl; + odesc << oss.str(); + } + + return odesc.str(); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::bin_str(BINSEQ & o_blist, bool i_prepend_count) // binary version to write to file +{ + BINSEQ blist; + uint32_t count = 0; + + + for(RPNSTACK::iterator i = iv_rpnstack.begin(); i != iv_rpnstack.end(); ++i) + { + uint32_t v = *i; + uint32_t type = v & TYPE_MASK; + uint16_t tag; + + switch (type) + { + case OPERATION: blist.push_back((uint8_t)v); + ++count; + if((v & OP_MASK) == LIST) + { + ++count; + blist.push_back((uint8_t)(v >> 8)); + } + break; + + case SYMBOL: tag = iv_symbols->get_tag(v); + blist.push_back((uint8_t)(tag >> 8)); + blist.push_back((uint8_t) tag); + count += 2; + break; + + case NUMBER: tag = iv_symbols->get_numeric_tag(v); + blist.push_back((uint8_t)(tag >> 8)); + blist.push_back((uint8_t) tag); + count += 2; + break; + case ARRAY_INDEX: + tag = iv_symbols->get_numeric_array_tag(v); + blist.push_back((uint8_t)(tag >> 8)); + blist.push_back((uint8_t) tag); + count += 2; + break; + + default: + std::cerr << "ERROR! Rpn::bit_str() Invalid Rpn type: " << v << std::endl; + break; + } + } + + if (i_prepend_count) + { + o_blist.push_back((uint8_t) count); + } + + o_blist.insert(o_blist.end(), blist.begin(), blist.end()); +} + +//------------------------------------------------------------------------------------------------- +// Used for RPN filtering (resolve()) +void Rpn::pop_bool(EVAL_STACK & i_stack, RPN_VALUE & o_value) //dg002a +{ + // convert numbers or any to bool + if(i_stack.size()) + { + o_value = i_stack.back(); + i_stack.pop_back(); + if(o_value.type == RPN_NUMBER) + { + if(o_value.data == 0) o_value.type = RPN_FALSE; + else + { + o_value.type = RPN_TRUE; + if(o_value.data != 1) + { + cerr << "Was expecting a bool, got a number - assume true" << endl; + } + } + } + else if(o_value.type == RPN_ANY) o_value.type = RPN_TRUE; + // else already a bool + } + else + { + o_value.type = RPN_TRUE; + cerr << "Empty stack!" << endl; + } +} +//------------------------------------------------------------------------------------------------- + +void Rpn::pop_number(EVAL_STACK & i_stack, RPN_VALUE & o_value) //dg002a +{ + // Convert bools to ANY if a number is expected (eg true == 1) + if(i_stack.size()) + { + o_value = i_stack.back(); + i_stack.pop_back(); + //if(o_value.type != RPN_NUMBER && o_value.type != RPN_ANY) + //{ + // if(o_value.type == RPN_FALSE) o_value.data = 0; + // else if(o_value.type == RPN_TRUE) o_value.data = 1; + // //o_value.type = RPN_NUMBER; // not safe when just checking EC + // o_value.type = RPN_ANY; + //} + // else leave as is + } + else + { + o_value.type = RPN_ANY; + cerr << "Empty stack!" << endl; + } +} + +//------------------------------------------------------------------------------------------------- + +bool Rpn::resolve_ec(uint32_t i_ec) //dg002a +{ + SYMBOL_VAL_LIST v; + SYMBOL_VAL_PAIR p(string("EC"),i_ec); + v.push_back(p); + + //SYMBOL_VAL_PAIR p1(string("SERIES"),0xA000006C); + //SYMBOL_VAL_PAIR p2(string("SERIES_IP"),0xA000006C); + //SYMBOL_VAL_PAIR p3(string("SERIES_Z"),0xA000006D); + //v.push_back(p1); + //v.push_back(p2); + //v.push_back(p3); + + return resolve(v); +} + +//------------------------------------------------------------------------------------------------- +// Tries to resolve as much of the RPN as possible +// @return false means that based on the given varlist, the RPN will never evaluate to true. +// eg. unconditionally false +// true means RPN either evaluated to true or there is not enough information to evaluate the RPN +// @note SPY RPNs are not supported +// +bool Rpn::resolve(SYMBOL_VAL_LIST & i_varlist) +{ + + bool result = true; + + EVAL_STACK stack; + RPN_VALUE rpn_true(RPN_TRUE); + RPN_VALUE rpn_false(RPN_FALSE); + RPN_VALUE r1; + RPN_VALUE r2; + + for(RPNSTACK::const_iterator i = iv_rpnstack.begin(); i != iv_rpnstack.end(); ++i) + { + if( (*i) & OPERATION ) + { + uint32_t op = (*i) - OPERATION; + uint32_t count = op >> 8; + op &= OP_MASK; + + switch(op) + { + case AND: + pop_bool(stack,r1); + pop_bool(stack,r2); + if(r1.type == RPN_TRUE && r2.type == RPN_TRUE) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + break; + + case OR: + pop_bool(stack,r1); + pop_bool(stack,r2); + if(r1.type == RPN_TRUE || r2.type == RPN_TRUE) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + break; + + case NOT: + pop_bool(stack,r1); + if(r1.type == RPN_TRUE) stack.push_back(rpn_false); + else if(r1.type == RPN_FALSE) stack.push_back(rpn_true); + break; + + case EQ: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + { + if(r1.data == r2.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + else if(r1.type == RPN_TRUE && r2.type == RPN_NUMBER) + { + if(r2.data == 0) stack.push_back(rpn_false); + else stack.push_back(rpn_true); + } + else if(r2.type == RPN_TRUE && r1.type == RPN_NUMBER) + { + if(r1.data == 0) stack.push_back(rpn_false); + else stack.push_back(rpn_true); + } + else if(r1.type == RPN_FALSE && r2.type == RPN_NUMBER) + { + if(r2.data == 0) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + else if(r2.type == RPN_FALSE && r1.type == RPN_NUMBER) + { + if(r1.data == 0) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + else if((r1.type == RPN_TRUE && r2.type == RPN_FALSE) || + (r1.type == RPN_FALSE && r2.type == RPN_TRUE)) stack.push_back(rpn_false); + else stack.push_back(rpn_true); + break; + + case NE: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else + { + if(r1.data != r2.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + break; + + case GT: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else + { + if(r2.data > r1.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + break; + + case GE: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else + { + if(r2.data >= r1.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + break; + + case LT: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else + { + if(r2.data < r1.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + break; + + case LE: + pop_number(stack,r1); + pop_number(stack,r2); + if(r1.type == RPN_ANY || r2.type == RPN_ANY) stack.push_back(rpn_true); + else + { + if(r2.data <= r1.data) stack.push_back(rpn_true); + else stack.push_back(rpn_false); + } + break; + + case PLUS: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r1.data + r2.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator +" << endl; + break; + + case MINUS: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data - r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator -" << endl; + break; + + case MULT: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data * r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator *" << endl; + break; + + case DIVIDE: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data / r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator /" << endl; + break; + + case MOD: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data % r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator %" << endl; + break; + + case LIST: // lists are always true - TODO look for EC list ?? + ++i; + while(count--) stack.pop_back(); + stack.push_back(rpn_true); + break; + + case SHIFTLEFT: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data << r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator <<" << endl; + break; + + case SHIFTRIGHT: + r1 = stack.back(); stack.pop_back(); + r2 = stack.back(); stack.pop_back(); + if(r1.type == RPN_NUMBER && r2.type == RPN_NUMBER) + stack.push_back(RPN_VALUE(r2.data >> r1.data,RPN_NUMBER)); + else cerr << "Was not expecting a non-numeric value for operator >>" << endl; + break; + + case TRUE_OP: //dg003a + stack.push_back(rpn_true); + break; + + case FALSE_OP: //dg003a + stack.push_back(rpn_false); + break; + + default: + cerr << "Invalid operator " << op << endl; + break; + } + } + else if((*i) & NUMBER) + { + uint32_t size = 0; + uint64_t data = iv_symbols->get_numeric_data(*i,size); + stack.push_back(RPN_VALUE(data,RPN_NUMBER)); + } + else if((*i) & SYMBOL) // variables and cini enums + { + std::string name = iv_symbols->find_name(*i); + SYMBOL_VAL_LIST::iterator vvi = i_varlist.begin(); + for(; vvi != i_varlist.end(); ++vvi) + { + if(name == vvi->first) + { + // cerr << name << " = " << vvi->second << endl; + stack.push_back(RPN_VALUE((uint64_t)vvi->second,RPN_NUMBER)); + break; + } + } + if(vvi == i_varlist.end()) + { + // cerr << name << " = ANY" << endl; + stack.push_back(RPN_VALUE(RPN_ANY)); + } + } + } + // an empty RPN is true, if it's not empty then check for false + if(stack.size()) + { + RPN_VALUE r = stack.back(); + if(r.type == RPN_FALSE) result = false; + } + return result; +} + +//------------------------------------------------------------------------------------------------- + +uint8_t Rpn::extract8(BINSEQ::const_iterator & bli) +{ + uint8_t val; + val += (uint8_t)(*bli++); + return val; +} + + +//------------------------------------------------------------------------------------------------- + +uint16_t Rpn::extract16(BINSEQ::const_iterator & bli) +{ + uint16_t val; + val = ((uint16_t)(*bli++)) << 8; + val += (uint16_t)(*bli++); + return val; +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Rpn::extract32(BINSEQ::const_iterator & bli) +{ + uint32_t val = extract16(bli); + val <<= 16; + val += extract16(bli); + return val; +} + + +//------------------------------------------------------------------------------------------------- + +uint64_t Rpn::extract64(BINSEQ::const_iterator & bli) +{ + uint64_t val = extract32(bli); + val <<= 32; + val += extract32(bli); + return val; +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::set8(BINSEQ & bl, uint8_t v) +{ + bl.push_back((uint8_t)(v)); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::set16(BINSEQ & bl, uint16_t v) +{ + bl.push_back((uint8_t)(v >> 8)); + bl.push_back((uint8_t)(v)); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::set32(BINSEQ & bl, uint32_t v) +{ + bl.push_back((uint8_t)(v >> 24)); + bl.push_back((uint8_t)(v >> 16)); + bl.push_back((uint8_t)(v >> 8)); + bl.push_back((uint8_t)(v)); +} + +//------------------------------------------------------------------------------------------------- + +void Rpn::set64(BINSEQ & bl, uint64_t v) +{ + bl.push_back((uint8_t)(v >> 56)); + bl.push_back((uint8_t)(v >> 48)); + bl.push_back((uint8_t)(v >> 40)); + bl.push_back((uint8_t)(v >> 32)); + bl.push_back((uint8_t)(v >> 24)); + bl.push_back((uint8_t)(v >> 16)); + bl.push_back((uint8_t)(v >> 8)); + bl.push_back((uint8_t)(v)); +} + + +//------------------------------------------------------------------------------------------------- + + diff --git a/src/usr/hwpf/ifcompiler/initRpn.H b/src/usr/hwpf/ifcompiler/initRpn.H new file mode 100755 index 000000000..5eba73c62 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initRpn.H @@ -0,0 +1,303 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initRpn.H,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +#if !defined(INITRPN_H) +#define INITRPN_H + +// Change Log ************************************************************************************* +// +// Flag Reason Userid Date Description +// ---- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 SW047506 dgilbert 12/09/10 SERIES filtering +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// andrewg 11/09/11 Multi-dimensional array and move to common fapi include +// End Change Log ********************************************************************************* + +/** + * @file initRpn.H + * @brief Declaration of the initRpn class. Handles Reverse Polish Notation equations for initfiles + */ + +#include <stdint.h> +#include <string> +#include <vector> +#include <map> +#include <fapiHwpInitFileInclude.H> + + +namespace init +{ + class Symbols; + + typedef std::vector<uint8_t> BINSEQ; + + typedef std::pair<std::string,uint32_t> SYMBOL_VAL_PAIR; + typedef std::vector<SYMBOL_VAL_PAIR> SYMBOL_VAL_LIST; + + class Rpn + { + public: + + enum TYPE + { + DEFINE = 0x08000000, + SYMBOL = 0x10000000, + NUMBER = 0x20000000, + ARRAY_INDEX = 0x40000000, + OPERATION = 0x80000000, + TYPE_MASK = 0xF8000000, + + }; + + /** + * @brief Create empty RPN + * + */ + Rpn() : iv_symbols(NULL) {} + + /** + * @brief Create empty RPN w/ symbol table + * + * @param[in] i_symbols Pointer to Symbol Table + */ + Rpn(Symbols * i_symbols) : iv_symbols(i_symbols) {} + + /** + * @brief Create empty RPN w/ symbol table and input integer + * + * @param[in] i_int Integer to populate RPN with + * @param[in] i_symbols Pointer to Symbol Table + */ + Rpn(uint32_t i_int, Symbols * i_symbols); + + Rpn(uint64_t i_int, Symbols * symbols); //<<< Create RPN with single 64 bit integer + Rpn(std::string i_id, Symbols * symbols, TYPE i_type=SYMBOL); //<<< Create RPN with single symbol + Rpn(BINSEQ::const_iterator & bli, Symbols * symbols) //<<< Create RPN from binary sequence + : iv_symbols(symbols) { bin_read(bli); } + + /** + * Compare two Rpn sequences for equivalence + * @note Currently the two Rpn sequences must use the same symbol table to be considered equal. + * @note TODO: Allow different symbol tables and resolve the symbols before comparing. + */ + bool operator==(const Rpn & r); + bool operator!=(const Rpn & r) { return !(this->operator==(r)); } + + void push_int(uint32_t i_val); //<<< Add a 32 bit integer to the Rpn sequence + void push_id(std::string & i_id, TYPE i_type=SYMBOL); //<<Add a symbol or Spy enum to the Rpn sequence + void push_int64(uint64_t i_uint); //<<< Add a 64 bit integer to the Rpn sequence + + /** + * @brief Add an attribute array index + * + * @param[in] i_array_idx Array index for this attribute + * + * @return Void + */ + void push_array_index(std::string &i_array_idx); + + /** + * @brief Add an attribute enum + * + * @param[in] i_attr_enum attribute enum name + * + * @return Void + */ + void push_attr_enum(std::string &i_attr_enum); + + Rpn * push_op(IfRpnOp op); //<<< Add an operation to the Rpn sequence + + /** + * @brief Merge an Rpn to this Rpn sequence with input operation + * + * @param[inout] io_rpn Input RPN to merge into this one. Will be deleted. + * @param[in] i_op Operation to perform between the 2 RPN's + * + * @return Merged RPN + */ + Rpn * push_merge(Rpn * io_rpn, IfRpnOp i_op); + + /** + * Merge (append) Rpn with this Rpn sequence + * @returns this + * @post i_rpn is deleted + */ + Rpn * merge(Rpn * i_rpn); + + /** + * Append a copy of an Rpn sequence to this Rpn sequence + */ + void append(const Rpn & i_rpn); + + void append(uint32_t i_rpn_id) { iv_rpnstack.push_back(i_rpn_id); } + + /** + * isTrue returns true if the RPN has a single element that is RPN_TRUE + * @note Used in RPN optimization + */ + bool isTrue() const; //dg003a + + /** + * isFalse returns true if the RPN has a single element that is RPN_FALSE + * @note Used in RPN optimization + */ + bool isFalse() const; //dg003a + + void clear() { iv_rpnstack.clear(); } //<<< clear the sequence + + /** + * Human readable listing of RPN string + * @param String Description to use; NULL -> use default: "n BYTES" + * @param bool i_final true: convert cini symbol id's to offset tags + * @returns string + * @NOTE i_final should never be set to true until all symbols in the + * init file have been "looked up" + */ + std::string listing(const char * i_desc, + const std::string & spyname = cv_empty_str, + bool i_final = false); + + std::string symbol_names() const; //<<< Return a string of all the SYMBOL names in the Rpn + + /** + * @brief Push all RPN stack entries of object as numerical values onto input blist + * + * @param blist Binary string of RPN to write to file + * @param i_prepend_count Flag to indicate prepend rpn count to binary string + * @PRE should never be called until all symbols in the initfile have been + * "looked up" or the binary tags for Symbols and Numbers may not be accurate + * @return void + */ + void bin_str(BINSEQ & blist, bool i_prepend_count = false); + + /** + * Read binary sequence to recreate this Rpn sequence + * @param bineary sequence interator + * @param symbol table to use + * @pre first byte in binary sequence is the size of the rpn sequence in bytes + * @post if symbols != NULL then iv_rpnstack is replaced + * @post iv_symbols is replace with symbols + */ + void bin_read(BINSEQ::const_iterator & bli, Symbols * symbols = NULL); // read binary sequence to recreate RPN + + /** + * Copy one rpn operation from bli and add to this Rpn sequence + * @returns an iterator one past the last byte used. + * @param iterator of a binary rpn sequence + * @param symbol table to use. + * @pre bli points to a valid rpn sequence - ie the correct number of PUSHES for the operand + * @post this Rpn sequence is appended + * @post Internal symbol table ptr is replace with given symbol table ptr if not NULL + * @note Reads byte sequence from bli sequence until an operation is found. + * @note The input sequence should NOT have a size byte on the front + */ + BINSEQ::const_iterator bin_read_one_op(BINSEQ::const_iterator & bli, Symbols * symbols = NULL); // read one rpn operation from bli to create Rpn + + //dg002a + /** + * Resolve the RPN and returns false if the given EC level causes the RPN expression to be false. + * @returns true | false + * @note This routine will always return true unless the RPN contains an EC comparison that resolves to false. + */ + bool resolve_ec(uint32_t i_ec); + + //dg003a + /** + * Resove as much of the RPN as possible, given the list of Symbol -> value substitutions. Result is true until proven false. + * @returns true | false. False is returned if the Rpn is unconditionally false; otherwise true is returned. + * @note Any Symbol found in the RPN not included in i_varlist resolves to ANY. All comparison operands to ANY resolves to true + * @code + * // Example 1 + * SYMBOL_VAL_PAIR p(string("EC"),0x10); + * SYMBOL_VAL_LIST lst; + * lst.push_back(p); + * if(anRpn.resolve(lst)) { .... } + * // In this example, any instants of the variable "EC" in the RPN will be replaced with the value 0x10. + * // Any other variables will be set to ANY and the RPN will be evaluated. + * // if the RPN does not contain the variable "EC", it will resolve to true. + * + * // Example 2 + * SYMBOL_VAL_PAIR p1(string("SERIES"),0xA000006C); + * SYMBOL_VAL_PAIR p2(string("SERIES_IP"),0xA000006C); + * SYMBOL_VAL_PAIR p3(string("SERIES_Z"),0xA000006D); + * SYMBOL_VAL_LIST lst; + * lst.push_back(p1); + * lst.push_back(p2); + * lst.push_back(p3); + * if(anRpn.resolve(lst)) {.....} // resolves to false if rpn contains SERIES == SERIES_Z + * // or SERIES != SERIES_IP + * @endcode + */ + bool resolve(SYMBOL_VAL_LIST & i_varlist); + + + uint32_t op_count() const { return iv_rpnstack.size(); } + + // Helper functions in reading and writing binary sequences (compiled initfiles *.if) + static uint8_t extract8(BINSEQ::const_iterator & bli); + static uint16_t extract16(BINSEQ::const_iterator & bli); + static uint32_t extract32(BINSEQ::const_iterator & bli); + static uint64_t extract64(BINSEQ::const_iterator & bli); + static void set8(BINSEQ & bl, uint8_t v); + static void set16(BINSEQ & bl, uint16_t v); + static void set32(BINSEQ & bl, uint32_t v); + static void set64(BINSEQ & bl, uint64_t v); + + static std::string cv_empty_str; + + private: // types and data + typedef std::vector<uint32_t> RPNSTACK; + + RPNSTACK iv_rpnstack; ///< Rpn sequence + Symbols * iv_symbols; ///< Symbol table to use + + + + + //dg002a begin Used in resolve operations to interpret the Rpn sequence + enum RPN_TYPE + { + RPN_NUMBER = 0, + RPN_FALSE = 1, + RPN_TRUE = 2, + RPN_ANY = 3, + }; + + // Used in resolve operations to interpret the Rpn sequence + struct RPN_VALUE + { + uint64_t data; + RPN_TYPE type; + RPN_VALUE() : data(0), type(RPN_NUMBER) {} + RPN_VALUE(RPN_TYPE i_type) : data(0), type(i_type) {} + RPN_VALUE(uint64_t i_data, RPN_TYPE i_type) : data(i_data), type(i_type) {} + RPN_VALUE(uint64_t i_data) : data(i_data), type(RPN_NUMBER) {} + }; + + typedef std::vector<RPN_VALUE> EVAL_STACK; + + private: // functions + + // Used in resolve operations to interpret the Rpn sequence + static void pop_bool(EVAL_STACK & i_stack, RPN_VALUE & o_value); + static void pop_number(EVAL_STACK & i_stack, RPN_VALUE & o_value); + // dg002a end + }; +}; + +#endif diff --git a/src/usr/hwpf/ifcompiler/initScom.C b/src/usr/hwpf/ifcompiler/initScom.C new file mode 100755 index 000000000..b37c05182 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initScom.C @@ -0,0 +1,1372 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initScom.C,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG + +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ----- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg001 D774126 dgilbert 09/30/10 Check that colname EXPR is last column in spytable +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 SW047506 dgilbert 12/09/10 More filtering enhancements +// andrewg 05/24/11 Port over for VPL/PgP +// andrewg 09/19/11 Updates based on review +// andrewg 11/09/11 Multi-dimensional array and move to common fapi include +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initSpy.C + * @brief Definition of the initScom Class. Represents the information parsed from an initfile scom + * statement. + */ + +#include <initScom.H> +#include <initSymbols.H> +#include <initCompiler.H> +#include <stdlib.h> +#include <iostream> +#include <iomanip> +#include <sstream> +#include <fstream> +#include <set> +#include <stdexcept> + +extern void yyerror(const char * s); +extern init::ScomList * yyscomlist; // only use this during parsing + +namespace init { +extern ostringstream dbg; // debug output +}; + +using namespace init; + +Scom::WHEN_SUBTYPE_MAP Scom::cv_when_subtypes; + +//------------------------------------------------------------------------------------------------- + +Scom::Scom(BINSEQ::const_iterator & bli, Symbols * i_symbols): + iv_symbols(i_symbols), + iv_when(NONE), + iv_scom_length(0), + iv_scom_offset(0), + iv_when_rpn(i_symbols) + +{ + + iv_scom_length = Rpn::extract16(bli); + iv_scom_offset = Rpn::extract16(bli); + uint32_t id = Rpn::extract16(bli); + uint32_t numcols = Rpn::extract16(bli); + uint32_t numrows = Rpn::extract16(bli); + + numcols &= ~SUBTYPE_MASK; + + // Get our SCOM address + uint32_t l_addr_size = 0; + iv_scom_addr_hex = iv_symbols->get_numeric_data(iv_symbols->get_rpn_id(id),l_addr_size); + + + if( iv_scom_length != 0 && iv_scom_length != 0xffff) // most common values + { + if(iv_scom_length < 65) // max scom len is 64 bits + { + for(size_t i = 0; i < numrows; ++i) + add_bit_range(iv_scom_offset, iv_scom_offset + iv_scom_length - 1); + } + else // What's this? + { + ostringstream errs; + errs << "ERROR: Invalid scom bit length [" << iv_scom_length << "]" << endl; + throw range_error(errs.str()); + } + } + + for(size_t i = 0; i < numrows; ++i) + { + Rpn rpn(bli,iv_symbols); + iv_scom_rpn.push_back(rpn); + } + + if(numcols) + { + for(size_t i = 0; i < numrows; ++i) iv_row_rpn.push_back(Rpn(iv_symbols)); // blank RPNs + + // Read col heads + for(size_t i = 0; i < numcols; ++i) + { + uint32_t var_tag = Rpn::extract16(bli); + Rpn col_name_rpn(iv_symbols); + col_name_rpn.append(iv_symbols->get_rpn_id(var_tag)); + iv_col_vars.push_back(col_name_rpn); + iv_cols_rpn.push_back(iv_row_rpn); // copy in blank row RPNs for this column + } + + for(size_t row_n = 0; row_n < numrows; ++row_n) + { + COL_LIST::iterator cli = iv_cols_rpn.begin(); // *cli is list of row rpns for col + RPN_LIST::iterator rpi = (*cli).begin() + row_n; // *rpi is current row rpn for first col + BINSEQ::const_iterator bli_end = bli + (*bli); // end of rpn in bin seq + ++bli; ++bli_end; // adjust for first byte being len + // The next len bytes belong to this row + // Simple cols are divided by OPs + // LIST op has two additional bytes (len,op) + while(bli < bli_end) + { + // Last col rpn is not limited to one op if it's "expr" - it gets the rest of the RPN + if(cli == (iv_cols_rpn.end() - 1)) + { + while(bli < bli_end) bli = rpi->bin_read_one_op(bli); + break; + } + bli = rpi->bin_read_one_op(bli); + ++cli; + rpi = (*cli).begin() + row_n; + } + } + } + else ++bli; +} + +//------------------------------------------------------------------------------------------------- + +void Scom::set_when(const string * when_str) +{ + + string s(*when_str); + for(string::iterator c = s.begin(); c != s.end(); ++c) *c = toupper(*c); + if(s.size()) + { + size_t i = 0; + for(size_t i = 1; i < sizeof(when_char)/sizeof(when_char[0]); ++i) + { + if(s[0] == when_char[i]) + { + set_when((SCOM_WHEN)i); + break; + } + } + if(i == sizeof(when_char)/sizeof(when_char[0])) + { + string errs("Illegal when="); + errs.append(s); + yyerror(errs.c_str()); + } + s.erase(0,1); + + if(s.size()) + { + WHEN_SUBTYPE_MAP::const_iterator i = cv_when_subtypes.find(s); + if(i != cv_when_subtypes.end()) + { + set_sub_when(i->second); + } + else + { + std::ostringstream oss; + oss << "Illegal 'when=' subvalue: [" << s << ']'; + yyerror(oss.str().c_str()); + } + } + } + else + { + yyerror("Missing 'when =' value"); + } +} + +//------------------------------------------------------------------------------------------------- + +void Scom::add_col(const string & i_colname) +{ + string s(i_colname); + for(string::iterator i = s.begin(); i != s.end(); ++i) *i = toupper(*i); + Rpn col_rpn(s,iv_symbols); // = iv_symbols->use_symbol(s); + + // add check - Can't add any more cols after EXPR column dg001a + if(iv_col_vars.size() && s != "EXPR") + { + Rpn exp_rpn("EXPR",iv_symbols); + if(exp_rpn == iv_col_vars.back()) // expr col already added - can't add any more cols + { + yyerror("EXPR must be the last column"); + } + } + + // if the entire column is unconditionally true it can be left out + // This check will be done later as this scom might be split by bit-ranges. + + iv_col_vars.push_back(col_rpn); + iv_cols_rpn.push_back(iv_row_rpn); // add the collected row RPNs + iv_row_rpn.clear(); +} + +//------------------------------------------------------------------------------------------------- + +void Scom::add_row_rpn(Rpn * i_rpn) +{ + // The row gets parsed before the col name + // So collect the row RPNs and apply them when the col name gets added + + // Replace the Rpn "ANY" EQ with TRUE dg003a + Rpn any_rpn("ANY",iv_symbols); + Rpn true_rpn(iv_symbols); + true_rpn.push_op(TRUE_OP); + + // The column EXPR can have an lone "ANY" rpn - so add EQ. + if(any_rpn == (*i_rpn)) i_rpn->push_op(EQ); + any_rpn.push_op(EQ); + + if(any_rpn == (*i_rpn)) iv_row_rpn.push_back(true_rpn); // Replace col == ANY with TRUE + else + { + iv_row_rpn.push_back(*i_rpn); + } + delete i_rpn; +} + +//------------------------------------------------------------------------------------------------- + +void Scom::add_bit_range(uint32_t start, uint32_t end) +{ + // make sure they are added in order + dbg << "Add bit range " << start << " to " << end; + iv_range_list.push_back(RANGE(start,end)); +} + +//------------------------------------------------------------------------------------------------- +// Range gets parsed before the target symbol (k,n,p,c) - so save it +void Scom::add_target_range(uint32_t r1, uint32_t r2) +{ + if(r1 > r2) + { + uint32_t rt = r1; + r1 = r2; + r2 = rt; + } + iv_target_ranges.push_back(RANGE(r1,r2)); +} + +//------------------------------------------------------------------------------------------------- + +void Scom::make_target(const char * i_symbol) +{ + string s(i_symbol); + Rpn r(iv_symbols); + size_t rsize = iv_target_ranges.size(); + + if(rsize == 0) + { + yyerror("Target given w/o a range"); + } + // if more than one target - use list + else + { + for(RANGE_LIST::iterator iter = iv_target_ranges.begin(); iter != iv_target_ranges.end(); ++iter) + { + for(uint32_t v = iter->first; v <= iter->second; ++v) + { + r.push_int(v); + } + } + if(rsize > 1) r.push_op(LIST); // if more than one target + r.push_op(EQ); + } + + iv_row_rpn.push_back(r); + add_col(s); + iv_target_ranges.clear(); +} + +//------------------------------------------------------------------------------------------------- + +string Scom::list_one(RANGE range) +{ + ostringstream oss; + + uint32_t numcols = iv_col_vars.size() | (iv_when & SUBTYPE_MASK); // WHEN subtype goes in numcols + uint32_t bitlen = range.second + 1 - range.first; + if (bitlen) + { + iv_scom_length = bitlen; // don't overwrite iv_scom_length if bitlen == 0 + iv_scom_offset = range.first; // don't overwrite iv_scom_offset if bitlen == 0 + } + + uint32_t allrows = 0; + uint32_t numrows = 0; + + if(iv_cols_rpn.size()) allrows = iv_cols_rpn.front().size(); + if (allrows == 0) allrows = 1; + + // If there is a bit range we need to select only the rows that apply to this spyname + if(bitlen) + { + for(RANGE_LIST::iterator r = iv_range_list.begin(); r != iv_range_list.end(); ++r) + { + if((*r) == range) ++numrows; + } + } + else numrows = allrows; // else select all the rows + + oss << hex << setfill('0'); + oss << "------------"; + oss << " Scom Address: 0x" << setw(16) << iv_scom_addr_hex; + if(bitlen) + { + oss << '~' << dec << range.first; + if(range.first != range.second) oss << ':' << range.second; + oss << hex; + } + oss << ' ' << "------------" << endl + << "When= " << (iv_when & WHEN_MASK) << endl; + + oss << "0x" << setw(4) << iv_scom_length << "\t\t" << "Scom length" << endl + << "0x" << setw(4) << iv_scom_offset << "\t\t" << "Scom offset" << endl; + + //oss << "0x" << setw(8) << iv_symbols->get_spy_id(spyname) << '\t'; + + oss << "0x" << setw(4) << numcols << "\t\t" << "Number of columns" << endl + << "0x" << setw(4) << numrows << "\t\t" << "Number of rows" << endl; + + // If there is a bit range we need to select only the spyv rows that apply to this spyname + + if(bitlen) + { + RPN_LIST::iterator i = iv_scom_rpn.begin(); + for(RANGE_LIST::iterator r = iv_range_list.begin(); r != iv_range_list.end(); ++r,++i) + { + if ((*r) == range) + { + oss << i->listing("Length of rpn for spyv",Rpn::cv_empty_str,true); + } + } + } + else // get all rows + { + for(RPN_LIST::iterator i = iv_scom_rpn.begin(); i != iv_scom_rpn.end(); ++i) + { + oss << i->listing("Length of rpn for spyv",Rpn::cv_empty_str,true); + } + } + oss << endl; + + + // list the column names that are really CINI VARS + for(RPN_LIST::iterator i = iv_col_vars.begin(); i != iv_col_vars.end(); ++i) + { + oss << i->listing("",Rpn::cv_empty_str,true); + //Rpn col_rpn = *i; + //string desc = iv_symbols->find_name(rpn_id); + //if(desc.size() == 0) desc = "Variable not found!"; + + //oss << "0x" << setw(4) << iv_symbols->get_tag(*i) << "\t\t" << desc << endl; + } + oss << endl << endl; + + + + uint32_t usedrows = 0; + if(iv_cols_rpn.size() == 0) + { + oss << "ROW " << 1 << "\n0x00" << "\t\t" << "0 BYTES" << endl; + } + else + { + for(size_t n = 0; n < allrows; ++n) + { + Rpn rpn(iv_symbols); + if(bitlen) // only get rows that match the current bitrange + { + if(iv_range_list[n] != range) continue; + } + ++usedrows; + oss << "ROW " << usedrows << endl; + + // Build up the row Rpn for row n + for(COL_LIST::iterator i = iv_cols_rpn.begin(); i != iv_cols_rpn.end(); ++i) + { + rpn.append(i->at(n)); + } + oss << rpn.listing(NULL,Rpn::cv_empty_str,true) << endl; + } + } + + return oss.str(); +} + +//------------------------------------------------------------------------------------------------- + +string Scom::listing() +{ + ostringstream oss; + + set<RANGE> ranges; + ranges.insert(iv_range_list.begin(),iv_range_list.end()); + + //oss << list_one(RANGE(1,0)) << endl; + if(ranges.size()) + { + for(set<RANGE>::iterator r = ranges.begin(); r != ranges.end(); ++r) + { + oss << list_one(*r) << endl; + } + } + else + { + oss << list_one(RANGE(1,0)) << endl; + } + + return oss.str(); +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Scom::bin_listing(BINSEQ & blist) +{ + set<RANGE> ranges; + uint32_t scom_count = 0; + + row_optimize(); // delete any rows that are unconditionally false. + merge rows + + ranges.insert(iv_range_list.begin(),iv_range_list.end()); + + SCOM_ADDR::iterator i = iv_scom_addr.begin(); + // if more than one spyname, the first is just the stem of the name - skip it + if(iv_scom_addr.size() > 1) ++i; + + for(; i != iv_scom_addr.end(); ++i) + { + //printf("scom address:%s\n",(*i).c_str()); + if(ranges.size()) + { + for(set<RANGE>::iterator r = ranges.begin(); r != ranges.end(); ++r) + { + ++scom_count; + //bin_list_one(blist,*i,*r); + // The following sequence will optimize the bytecode for this spy + // - Compile the spy into bytecode for a range of bits + // - Recreate the spy from the bytecode + // - Compile the recreated spy back into bytecode. + BINSEQ temp; + bin_list_one(temp,strtoul((*i).c_str(),NULL,16), *r); + BINSEQ::const_iterator bi = temp.begin(); + Scom s(bi,iv_symbols); + s.bin_list_one(blist,strtoul((*i).c_str(),NULL,16), RANGE(1,0)); + } + } + else + { + ++scom_count; + bin_list_one(blist,strtoul((*i).c_str(),NULL,16), RANGE(1,0)); + } + } + + return scom_count; +} + +//------------------------------------------------------------------------------------------------- + +void Scom::bin_list_one(BINSEQ & blist,uint64_t i_addr, RANGE range) +{ + + uint32_t numcols = iv_col_vars.size() | (iv_when & SUBTYPE_MASK); // WHEN subtype goes in numcols + +// No range support + uint32_t bitlen = range.second + 1 - range.first; + + if (bitlen) + { + iv_scom_length = bitlen; // don't overwrite iv_scom_length if bitlen == 0 + iv_scom_offset = range.first; // don't overwrite iv_scom_offset if bitlen == 0 + } + + uint32_t allrows = 0; + uint32_t numrows = 0; + + if(iv_cols_rpn.size()) allrows = iv_cols_rpn.front().size(); + if (allrows == 0) allrows = 1; + + // If there is a bit range we need to select only the rows that apply to this spyname + if(bitlen) + { + for(RANGE_LIST::iterator r = iv_range_list.begin(); r != iv_range_list.end(); ++r) + { + if((*r) == range) ++numrows; + } + } + else numrows = allrows; // else select all the rows + + // If every row rpn in a column is unconditionally true then remove the col. + if(iv_col_vars.size()) + { + vector< pair<RPN_LIST::iterator, COL_LIST::iterator> > deletes; + RPN_LIST::iterator cv = iv_col_vars.begin(); // -> column header Rpn + COL_LIST::iterator cr = iv_cols_rpn.begin(); // -> RPN list of row segments for the column + for(; cv != iv_col_vars.end(); ++cv,++cr) + { + bool remove_it = true; + for(RPN_LIST::const_iterator r = cr->begin(); r != cr->end(); ++r) + { + if(!(r->isTrue())) + { + remove_it = false; + break; + } + } + if(remove_it) + { + deletes.push_back( pair<RPN_LIST::iterator, COL_LIST::iterator>(cv,cr) ); + } + } + while(deletes.size()) + { + pair<RPN_LIST::iterator, COL_LIST::iterator> p = deletes.back(); + deletes.pop_back(); + dbg << "COL is unconditionally true. Removing column " << (p.first)->symbol_names() + << endl; + iv_col_vars.erase(p.first); + iv_cols_rpn.erase(p.second); + --numcols; + } + } + + Rpn::set16(blist,(uint16_t)iv_scom_length); + Rpn::set16(blist,(uint16_t)iv_scom_offset); + + // Just put the SCOM address in place of the spy id + //uint32_t id = iv_symbols->get_spy_id(spyname); + //Rpn::set32(blist,id); + // TODO - Probably need to get scom address id here + //Rpn::set32(blist,(uint32_t)iv_address); + + Rpn *l_scom_addr = new init::Rpn(i_addr,yyscomlist->get_symbols()); + l_scom_addr->bin_str(blist,false); + delete l_scom_addr; + + + Rpn::set16(blist,(uint16_t)numcols); + Rpn::set16(blist,(uint16_t)numrows); + + // If there is a bit range we need to select only the spyv rows that apply to this spyname + if(bitlen) + { + RPN_LIST::iterator i = iv_scom_rpn.begin(); + for(RANGE_LIST::iterator r = iv_range_list.begin(); r != iv_range_list.end(); ++r,++i) + { + if ((*r) == range) + { + i->bin_str(blist,false); + } + } + } + else // get all rows + { + for(RPN_LIST::iterator i = iv_scom_rpn.begin(); i != iv_scom_rpn.end(); ++i) + { + i->bin_str(blist,false); + } + } + + // list the column names that are really CINI VARS + for(RPN_LIST::iterator i = iv_col_vars.begin(); i != iv_col_vars.end(); ++i) + { + i->bin_str(blist,false); // false means don't prepend an RPN byte count to the binary rpn appended. + //uint16_t tag = iv_symbols->get_tag(*i); + //blist.push_back((uint8_t)(tag >> 8)); + //blist.push_back((uint8_t) tag); + } + + if(iv_cols_rpn.size() == 0) blist.push_back(0); + else + { + for(size_t n = 0; n < allrows; ++n) + { + Rpn rpn(iv_symbols); + if(bitlen) // only get rows that match the current bitrange + { + if(iv_range_list[n] != range) continue; + } + + // Build up the row Rpn for row n + for(COL_LIST::iterator i = iv_cols_rpn.begin(); i != iv_cols_rpn.end(); ++i) + { + rpn.append(i->at(n)); + } + rpn.bin_str(blist,true); + } + } +} + +//------------------------------------------------------------------------------------------------- +// Delete any rows that are unconditionally false +// Merge rows that can be merged +// +void Scom::row_optimize() //dg003a +{ + size_t row = 0; + if (iv_cols_rpn.size()) row = iv_cols_rpn.front().size(); + if(row == 0) return; + + // Look for false rows + do + { + bool remove_me = false; + --row; + for(COL_LIST::iterator i = iv_cols_rpn.begin(); i != iv_cols_rpn.end(); ++i) + { + if (i->at(row).isFalse()) + { + remove_me = true; + break; + } + } + if(remove_me) + { + iv_scom_rpn.erase(iv_scom_rpn.begin() + row); //remove spyv + //Need to remove rpn row segment from each iv_cols_rpn rpn list + for(COL_LIST::iterator i = iv_cols_rpn.begin(); i != iv_cols_rpn.end(); ++i) + { + i->erase(i->begin() + row); + } + if(iv_range_list.size()) iv_range_list.erase(iv_range_list.begin() + row); + + //dbg << "ROW is unconditionally false. Removing row " << row+1 << " from " << get_key_name() << endl; + } + } while (row); + + // now look for rows to merge + // for now limit to spies with EXPR as the only column + // Because the interpreter looks down the rows until it finds one that's "true" then stops, the order + // of rows cant't be modified. This means only rows next to each other can be merged. + // This makes for very large Rpn strings - turn on later when we have better redundancy reduction in RPNs +#if defined(__LATER__) + Rpn r_expr("EXPR", iv_symbols); + row = iv_spyv_rpn.size(); + if ((row > 1) && (iv_col_vars.size() == 1) && (iv_col_vars.front() == r_expr)) + { + --row; + do + { + size_t row1 = row - 1; + + if (iv_spyv_rpn.at(row) == iv_spyv_rpn.at(row1)) + { + if (iv_range_list.size() == 0 || (iv_range_list.at(row) == iv_range_list.at(row1))) + { + // merge + Rpn * rp = new Rpn(iv_cols_rpn.back().at(row)); + iv_cols_rpn.back().at(row1).push_merge(rp, Rpn::OR); // this will delete rp + iv_spyv_rpn.erase(iv_spyv_rpn.begin() + row); + if (iv_range_list.size()) iv_range_list.erase(iv_range_list.begin() + row); + for (COL_LIST::iterator i = iv_cols_rpn.begin(); i != iv_cols_rpn.end(); ++i) + { + i->erase(i->begin() + row); + } + dbg << "ROW " << row+1 << " and " << row1+1 << " have been merged in " << get_key_name() << endl; + } + } + } while (--row); + } +#endif +} + + + +//------------------------------------------------------------------------------------------------- + +bool Scom::compare(Scom & that) +{ + bool result = false; //true; +// TODO +#if 0 + ostringstream oss; + oss << hex << setfill('0'); + // spyname(s) should have already been tested + oss << get_key_name() << endl; + if(iv_spy_type != that.iv_spy_type || + iv_when != that.iv_when || + iv_spy_length != that.iv_spy_length || + iv_spy_offset != that.iv_spy_offset || + iv_array_addr != that.iv_array_addr) + { + result = false; + oss << "type: " << setw(8) << iv_spy_type << ' ' << that.iv_spy_type << endl; + oss << "when: " << setw(8) << iv_when << ' ' << that.iv_when << endl; + oss << "len: " << setw(8) << iv_spy_length << ' ' << that.iv_spy_length << endl; + oss << "offset: " << setw(8) << iv_spy_offset << ' ' << that.iv_spy_offset << endl; + oss << "array: " << setw(8) << iv_array_addr << ' ' << that.iv_array_addr << endl; + } + // need to expand all Rpns to verify resolution of vars and lits + // when Rpn + string rpn1 = iv_when_rpn.listing("",iv_spy_names.front(),false); + string rpn2 = that.iv_when_rpn.listing("",iv_spy_names.front(),false); + if(rpn1 != rpn2) + { + result = false; + oss << "this when Rpn:" << endl << rpn1 << endl; + oss << "that when Rpn:" << endl << rpn2 << endl; + } + + // spyv Rpn + if(iv_spyv_rpn.size() != that.iv_spyv_rpn.size()) + { + result = false; + oss << "this spyv Rpn(s):" << endl; + for(RPN_LIST::iterator r1 = iv_spyv_rpn.begin(); r1 != iv_spyv_rpn.end(); ++r1) + oss << r1->listing("",iv_spy_names.front(),false) << endl; + oss << "that spyv Rpn(s):" << endl; + for(RPN_LIST::iterator r1 = that.iv_spyv_rpn.begin(); r1 != that.iv_spyv_rpn.end(); ++r1) + oss << r1->listing("",iv_spy_names.front(),false) << endl; + } + else + { + RPN_LIST::iterator r1 = iv_spyv_rpn.begin(); + RPN_LIST::iterator r2 = that.iv_spyv_rpn.begin(); + for(; r1 != iv_spyv_rpn.end(); ++r1, ++r2) + { + rpn1 = r1->listing("",iv_spy_names.front(),false); + rpn2 = r2->listing("",iv_spy_names.front(),false); + if(rpn1 != rpn2) + { + result = false; + oss << "this spyv Rpn:" << endl << rpn1 << endl; + oss << "that spyv Rpn:" << endl << rpn2 << endl; + } + } + } + + // column names + if(iv_col_vars.size() != that.iv_col_vars.size()) + { + result = false; + oss << "this col names:" << endl; + for(RPN_LIST::iterator i = iv_col_vars.begin(); i != iv_col_vars.end(); ++i) + { + oss << i->symbol_names() << endl; + } + oss << "that col names:" << endl; + for(RPN_LIST::iterator i = that.iv_col_vars.begin(); i != that.iv_col_vars.end(); ++i) + { + oss << i->symbol_names() << endl; + } + } + else + { + RPN_LIST::iterator i = iv_col_vars.begin(); + RPN_LIST::iterator j = that.iv_col_vars.begin(); + for(;i != iv_col_vars.end(); ++i, ++j) + { + //string s1 = iv_symbols->find_name(*i); + //string s2 = that.iv_symbols->find_name(*j); + if((*i) != (*j)) + { + result = false; + oss << "this col name: " << i->symbol_names() << endl; + oss << "that col name: " << j->symbol_names() << endl; + } + } + } + + // row Rpns + Rpn r1(iv_symbols); + Rpn r2(that.iv_symbols); + for(COL_LIST::iterator c = iv_cols_rpn.begin(); c != iv_cols_rpn.end(); ++c) + { + for(RPN_LIST::iterator r = c->begin(); r != c->end(); ++r) + { + r1.append(*r); + } + } + for(COL_LIST::iterator c = that.iv_cols_rpn.begin(); c != that.iv_cols_rpn.end(); ++c) + { + for(RPN_LIST::iterator r = c->begin(); r != c->end(); ++r) + { + r2.append(*r); + } + } + rpn1 = r1.listing("",iv_spy_names.front(),false); + rpn2 = r2.listing("",iv_spy_names.front(),false); + if(rpn1 != rpn2) + { + result = false; + oss << "this row/col rpn:" << endl; + oss << rpn1 << endl; + oss << "that row/col rpn:" << endl; + oss << rpn2 << endl; + } + + if(!result) cout << oss.str(); +#endif + return result; +} + + +//================================================================================================= +// SpyList Class definitions +//================================================================================================= + +ScomList::ScomList(const string & initfile, FILELIST & defines, ostream & stats, uint32_t i_ec) + : + iv_syntax_version(0), + iv_symbols(new Symbols(defines)), + iv_stats(stats), + iv_ec(i_ec) + +{ + yyscomlist = this; + + // What type of input? text(*.initfile) or binary(*.if) ? + size_t pos = initfile.rfind('.'); + string type; + if(pos != string::npos) + { + type = initfile.substr(pos+1); + } + + if(type.compare(0,8,"initfile") == 0) // source is text *.initfile + { + char line[100]; + string first_line; + yyin = fopen(initfile.c_str(), "r"); + if(!yyin) + { + string ers("ERROR: Could not open initfile: "); + ers.append(initfile); + throw invalid_argument(ers); + } + + // In Syntax version 1 the first or second line contains the CVS version + fgets(line,100,yyin); + first_line = line; + fgets(line,100,yyin); + first_line.append(line); + yyline = 3; + + dbg << "======================= Begin Parse ========================" << endl; + yyparse(); // Parse the initfile + dbg << "======================= End Parse ==========================" << endl; + + if(iv_syntax_version == 1) + { + // example pattern ..... $Id: galaxy.initfile,v 5.0 ...... + size_t pos = first_line.find("$Id:"); + if(pos != string::npos) + { + istringstream iss(first_line.substr(pos+4)); + string tok; + iss >> tok; // ex. galaxy.initfile,v + iss >> tok; // ex. 5.0 + iv_cvs_versions = tok; // just want the version number - eg '5.0' + } + } + + iv_stats << '*' << setw(20) << "lines:" << setw(6) << yyline-1 << endl; + iv_stats << '*' << setw(20) << "Scom statements:" << setw(6) << iv_scom_list.size() << endl; + // TODO num var/lits num lits found + } + else if(type.compare(0,2,"if") == 0) // source is binary *.if file + { +// TODO - No support for this currently +#if 0 + dbg << "======================= Begin Uncompiling ========================" << endl; + + BINSEQ bin_seq; + ifstream ifs(initfile.c_str(), ios_base::in | ios_base::binary); + if(!ifs) + { + string msg("ERROR: SpyList::Could not open "); + msg.append(initfile); + throw invalid_argument(msg); + } + while(1) + { + int ch = ifs.get(); + if (!(ifs.good())) break; + bin_seq.push_back(ch); + } + ifs.close(); + + // Turn this back into a list of spies + BINSEQ::const_iterator bli = bin_seq.begin(); + BINSEQ::const_iterator b; + + iv_syntax_version = Rpn::extract32(bli); + bli += 8; + if(iv_syntax_version == 1) + { + for(b = bli-8; (b != bli) && (*b); ++b) + { + iv_cvs_versions.push_back(*b); + } + } + else + { + // offset to CVS sub version section + b = bin_seq.begin() + Rpn::extract32(bli); + size_t size = Rpn::extract16(b); + while(size--) iv_cvs_versions.push_back(*b++); + } + + b = bin_seq.begin() + Rpn::extract32(bli); + iv_symbols->restore_var_bseq(b); + + b = bin_seq.begin() + Rpn::extract32(bli); + iv_symbols->restore_lit_bseq(b); + + size_t section_count = Rpn::extract32(bli); + if(section_count > LAST_WHEN_TYPE) + { + throw range_error("ERROR: SpyList::SpyList - Inalid # of sections"); + } + + for(size_t i = 0; i < section_count; ++i) + { + size_t spy_type = Rpn::extract32(bli); // type + size_t offset = Rpn::extract32(bli); // offset + size_t count = Rpn::extract32(bli); // Number of spies + + b = bin_seq.begin() + offset; + if(!(b < bin_seq.end())) + { + throw overflow_error("ERROR: SpyList::SpyList - iterator overflowed sequence"); + } + if(spy_type > LAST_WHEN_TYPE || spy_type == 0) + { + throw range_error("ERROR: SpyList::SpyList - when= type out of range"); + } + while(count--) + { + Scom * s = new Scom(b,iv_symbols); + insert(s); + s->set_when((SPY_WHEN)spy_type); + } + } +#endif + dbg << "======================= End Uncompiling ========================" << endl; + } + else + { + ostringstream ess; + ess << "ERROR: SpyList::SpyList Invalid file type: " << type; + ess << "\n source: " << initfile; + throw invalid_argument(ess.str()); + } +} + +//------------------------------------------------------------------------------------------------- + +ScomList::~ScomList() +{ + delete iv_symbols; +} + +//------------------------------------------------------------------------------------------------- + +void ScomList::clear() +{ + for(SCOM_LIST::iterator i = iv_scom_list.begin(); i != iv_scom_list.end(); ++i) delete i->second; + iv_scom_list.clear(); +} + +//------------------------------------------------------------------------------------------------- + +void ScomList::set_syntax_version(uint32_t v) +{ + if(v != 1 && v != 2) yyerror("Invalid Syntax Version"); + iv_syntax_version = v; +} + +//------------------------------------------------------------------------------------------------- + +void ScomList::compile(BINSEQ & bin_seq) +{ + uint32_t count_s = 0; + uint32_t section_count = 0; + size_t offset = 0; + + + BINSEQ blist_v; // vars + BINSEQ blist_i; // lits + BINSEQ blist_l; // when=L spies + BINSEQ blist_s; // when=S spies + BINSEQ blist_c; // when=C spies + BINSEQ blist_d; // when=D spies + + // Make the BINSEQs big enough to hopefully never have to resize + blist_v.reserve(0x00400); + blist_i.reserve(0x02000); + blist_l.reserve(0x30000); + blist_s.reserve(0x03000); + blist_c.reserve(0x03000); + blist_d.reserve(0x03000); + + + dbg << "======================== Begin compile ============================" << endl; + Rpn::set32(bin_seq,iv_syntax_version); // bytes[0:3] + + // bytes [4:12] + if(iv_syntax_version == 2) + { + const char * s = "SEE SUBV"; + for(; *s != 0; ++s) bin_seq.push_back(*s); + istringstream iss(iv_cvs_versions); + string vers; + while(iss >> vers) + { + stats << '*' << setw(20) << "Version:" << " " << vers << endl; + } + } + else if (iv_syntax_version == 1) + { + if(iv_cvs_versions.size()) + { + size_t len = iv_cvs_versions.size(); + if(len > 8) { iv_cvs_versions.erase(9); len = 8; } + for(string::const_iterator s = iv_cvs_versions.begin(); + s != iv_cvs_versions.end(); ++s) + { + bin_seq.push_back(*s); + } + while(len < 8) { bin_seq.push_back(0); ++len; } + stats << '*' << setw(20) << "Version:" << setw(6) << iv_cvs_versions << endl; + } + else + { + throw range_error("ERROR: No CVS version(s) specified"); + } + } + else // syntax version already validated to be 1 or 2 - so if we get here it was never set. + { + throw range_error("ERROR: No sytax version specified!"); + } + stats << '*' << setw(20) << "Syntax Version:" << setw(6) << iv_syntax_version << endl; + + + // Determine the number of scoms in each section + + for(SCOM_LIST::iterator i = iv_scom_list.begin(); i != iv_scom_list.end(); ++i) + { + // Filter out filtered spies dg003a + if(!(i->second->valid_when(dbg,iv_ec))) + { + continue; + } + + count_s += i->second->bin_listing(blist_s); + + } + if(count_s) ++section_count; + + // 28 bytes of File Header Data + offset = 28; + stats << '*' << setw(20) << "Sections:" << setw(6) << section_count << endl; + + // for verion 2 add offset to CVS versions section + if(iv_syntax_version == 2) + { + offset += 4; + Rpn::set32(bin_seq,offset); + offset += iv_cvs_versions.length() + 2; + } + // offset now points to start of Var Symbol Table + + iv_symbols->bin_vars(blist_v); // get Var table + iv_symbols->bin_lits(blist_i); // Get Lit table + + Rpn::set32(bin_seq,offset); // Offset to Variable Symbol Table + offset += blist_v.size(); // offset += var table byte size + Rpn::set32(bin_seq,offset); // Offset to Literal Symbol Table + offset += blist_i.size(); // offset += lit table byte size + + if(count_s) + { + Rpn::set32(bin_seq,offset); // SCOM Section offset + Rpn::set32(bin_seq,count_s); // Number of SCOM's + } + + if(iv_syntax_version == 2) // Add Sub-version section + { + Rpn::set16(bin_seq,(uint16_t)iv_cvs_versions.length()); // Length of Sub version + bin_seq.insert(bin_seq.end(), iv_cvs_versions.begin(), iv_cvs_versions.end()); + } + + bin_seq.insert(bin_seq.end(), blist_v.begin(), blist_v.end()); // add var table section + bin_seq.insert(bin_seq.end(), blist_i.begin(), blist_i.end()); // add lit table section + + if(count_s) + { + bin_seq.insert(bin_seq.end(), blist_s.begin(), blist_s.end()); // add SCOM section + stats << '*' << setw(20) << "S scoms:" << setw(6) << count_s << endl; + } + dbg << "======================== End compile ============================" << endl; +} + +//------------------------------------------------------------------------------------------------- + +bool Scom::valid_when(ostream & msg, uint32_t i_ec) //dg002a dg003c +{ + bool result = true; + + // unconditional state was determined earlier + if( iv_when_rpn.isTrue()) // unconditionally true - Rpn is not needed. + iv_when_rpn.clear(); + else if( iv_when_rpn.isFalse()) //unconditionally false + result = false; + else if(i_ec != 0xffffffff) + { + if(iv_when_rpn.resolve_ec(i_ec) == false) result = false; + } +#if 0 + if(result == false) + { + msg << hex; + SPY_NAMES::iterator i = iv_spy_names.begin(); + // if more than one spyname, the first is just the stem of the name - skip it + if(iv_spy_names.size() > 1) ++i; + + for(; i != iv_spy_names.end(); ++i) + { + if(i_ec != 0xffffffff) + msg << "For EC " << i_ec << ": "; + + msg << "Removing spy " << *i << endl; + } + msg << iv_when_rpn.listing("WHEN RPN","",true) << endl; + } +#endif + return result; +} + +//------------------------------------------------------------------------------------------------- + +void ScomList::listing(BINSEQ & bin_seq,ostream & olist) +{ + dbg << "======================= Begin Listing ========================" << endl; + + BINSEQ::const_iterator bli = bin_seq.begin(); + BINSEQ::const_iterator b; + uint32_t syntax_version = Rpn::extract32(bli); + + string cvs_versions; + + olist << hex << setfill('0'); + olist << "--------------- FILE HEADER ------------------------\n\n"; + olist << fmt8(syntax_version) << "[Syntax Version]\n" + << "0x"; + bli += 8; + for(b = bli-8; b != bli; ++b) olist << setw(2) << (uint32_t)(*b); + olist << " ["; + for(b = bli-8; b != bli; ++b) if((*b) != 0) olist << (char)(*b); + olist << "]\t[CVS Version]\n"; + if(syntax_version == 2) + { + size_t offset = Rpn::extract32(bli); + olist << fmt8(offset) << "[Offset to Sub-Version Section]\n"; + } + + uint32_t var_table_offset = Rpn::extract32(bli); + uint32_t lit_table_offset = Rpn::extract32(bli); + + olist << fmt8(var_table_offset) << "[Offset to Attribute Symbol Table]\n"; + olist << fmt8(lit_table_offset) << "[Offset to Literal Symbol Table]\n"; + + + b = bin_seq.begin() + var_table_offset; + iv_symbols->restore_var_bseq(b); + + b = bin_seq.begin() + lit_table_offset; + iv_symbols->restore_lit_bseq(b); + + b = bli; // save + + size_t offset = Rpn::extract32(bli); // offset + size_t count = Rpn::extract32(bli); // Number of spies + + olist << fmt8(offset) << "[Scom Section Offset]\n"; + olist << fmt8(count) << "[Number of scoms]\n"; + + olist << endl; + + if(syntax_version == 2) + { + olist << "--------------- Sub Version Section ---------------\n\n"; + uint16_t len = Rpn::extract16(bli); + olist << "0x" << setw(4) << len << "\t\t" + << "Length of Sub Version Section\n\n"; + for(uint16_t i = 0; i < len; ++i) olist << (char)(*bli++); + olist << endl; + } + + olist << iv_symbols->listing() << endl; + olist << "------------------- SCOM TABLES ------------------------\n\n" + << endl; + + bli = b; // restore + + olist << "------------ Scoms -----------\n\n"; + + b = bin_seq.begin() + offset; + if(!(b < bin_seq.end())) + { + throw overflow_error("ERROR: ScomList::listing - iterator overflowed sequence"); + } + while(count--) + { + Scom s(b,iv_symbols); + olist << s.listing() << endl; + } + + dbg << "======================= End Listing ========================" << endl; +} + +//------------------------------------------------------------------------------------------------- + +void ScomList::attr_listing(BINSEQ & bin_seq,ostream & olist) +{ + olist << iv_symbols->attr_listing(); +} + +//------------------------------------------------------------------------------------------------- + +string ScomList::fmt8(uint32_t val) +{ + ostringstream oss; + oss << setfill('0'); + oss << "0x" << hex << setw(8) << val << "\t " << '[' << dec << val << ']' << '\t'; + if(val < 1000) oss << '\t'; + return oss.str(); +} + + +//------------------------------------------------------------------------------------------------- + +void ScomList::insert(Scom * i_scom) +{ + uint64_t l_addr = i_scom->get_address(); + SCOM_LIST::iterator i = iv_scom_list.find(l_addr); + if(i == iv_scom_list.end()) + { + iv_scom_list[l_addr] = i_scom; + } + else + { + ostringstream oss; + oss << "Duplicate scom statement found on line " << i_scom->get_line() << endl; + oss << "First instance found on line " << i->second->get_line() << "Address: " << i_scom->get_address() << endl; + yyerror(oss.str().c_str()); + } +} + +//------------------------------------------------------------------------------------------------- + +bool ScomList::compare(ScomList & that) +{ + bool result = true; + dbg << "======================= Begin Compare ========================" << endl; + if(iv_scom_list.size() != that.iv_scom_list.size()) + { + cout << "E> Lists are not the same size" << endl; + result = false; + } + + // check each spy section + for(SCOM_LIST::iterator i = iv_scom_list.begin(); i != iv_scom_list.end(); ++i) + { + // The name checks spyname, arrayaddr (if array), bitrange(s) (if any) + uint64_t l_addr = i->second->get_address(); + SCOM_LIST::iterator j = that.iv_scom_list.find(l_addr); + if(j == that.iv_scom_list.end()) + { + cout << "E> " << l_addr << " not found in both lists!" << endl; + result = false; + continue; + } + if(i->second->compare(*(j->second)) == false) + { + cout << "E> Spy: " << l_addr << " does not match!" << endl; + result = false; + } + } + + // check for spies in that that are not in this + for(SCOM_LIST::iterator i = that.iv_scom_list.begin(); i != that.iv_scom_list.end(); ++i) + { + uint64_t l_addr = i->second->get_address(); + SCOM_LIST::iterator j = iv_scom_list.find(l_addr); + if(j == iv_scom_list.end()) + { + cout << "E> " << l_addr << " not found in both lists!" << endl; + result = false; + } + } + dbg << "======================= End Compare ========================" << endl; + return result; +} + +//------------------------------------------------------------------------------------------------- + +//------------------------------------------------------------------------------------------------- + +void Scom::set_scom_address(const string & i_scom_addr) +{ + + if(iv_scom_addr.size()) + { + yyerror("SCOM Address already set!"); + } + else + { + iv_scom_addr.push_back(i_scom_addr); + // cout << "I>Scom::set_scom_address: " << i_scom_addr << " is the output string!" << endl; + } +} + +//------------------------------------------------------------------------------------------------- + + +void Scom::dup_scom_address(const string & i_scom_addr) +{ + + + if(iv_scom_addr.size()) + { + iv_scom_addr.push_back(iv_scom_addr.front() + i_scom_addr); + } + else + yyerror("No base scom address to dulicate for append!"); + + // cout << "I>Scom::dup_scom_address: "<< i_scom_addr << " is the output string!" << endl; +} + +//------------------------------------------------------------------------------------------------- + +void Scom::set_scom_suffix(const string & i_scom_addr) +{ + + if(iv_scom_addr.size() == 1) iv_scom_addr[0] = iv_scom_addr[0] + i_scom_addr; + else if(iv_scom_addr.size() > 1) + { + SCOM_ADDR::iterator i = iv_scom_addr.begin(); + ++i; + for(;i != iv_scom_addr.end(); ++i) + { + *i += i_scom_addr; + } + } + else + yyerror("No base scom address to append suffix"); + + // cout << "I>Scom::set_scom_suffix: "<< i_scom_addr << " is the output string!" << endl; +} diff --git a/src/usr/hwpf/ifcompiler/initScom.H b/src/usr/hwpf/ifcompiler/initScom.H new file mode 100755 index 000000000..35938ba20 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initScom.H @@ -0,0 +1,247 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initScom.H,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +#if !defined(INITSPY_H) +#define INITSPY_H + +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ----- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dg002 SW039868 dgilbert 10/15/10 Add support to filter unneeded inits by EC +// dg003 SW047506 dgilbert 12/09/10 More filtering enhancements +// andrewg 05/24/11 Port over for VPL/PgP +// andrewg 09/19/11 Updates based on review +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initSpy.H + * @brief Declairation of the initSpy Class. Represents the information parsed from an initfile spy + * statement. + */ + +#include <stdint.h> +#include <stdlib.h> +#include <string> +#include <vector> +#include <map> +#include <set> +#include <initRpn.H> +#include <initSymbols.H> + + +using namespace std; + +namespace init +{ + typedef vector<string> SCOM_ADDR; + typedef vector<Rpn> RPN_LIST; + typedef vector<RPN_LIST> COL_LIST; + typedef vector<uint32_t> VAR_LIST; + typedef pair<uint32_t,uint32_t> RANGE; + typedef vector<RANGE> RANGE_LIST; + + enum SCOM_WHEN + { + NONE = 0x00000000, + + // WHEN= types + LONG_SCAN = 0x00000001, + SCOM = 0x00000002, + DRAMINIT = 0x00000003, + CFAMINIT = 0x00000004, + LAST_WHEN_TYPE = CFAMINIT, + WHEN_MASK = 0x000000FF, + + // WHEN= sub types + SUBTYPE_MASK = 0x0000F000, + HOT_ADD_NODE = 0x00004000, + AFTER_HOT_ADD_NODE = 0x00006000, + HOT_ADD_GX = 0x00008000, + HOT_ADD_GX0 = 0x00007000, + HOT_ADD_GX1 = 0x00005000, + AFTER_HOT_ADD_GX = 0x0000A000, + AFTER_HOT_ADD_GX0 = 0x00003000, + AFTER_HOT_ADD_GX1 = 0x00002000, + }; + + const char when_char[] = { '@','L','S','D','C' }; + + class Scom + { + public: + + enum SPY_TYPE + { + NOTYPE, + ISPY, + ESPY, + ARRAY + }; + + + Scom(Symbols * i_symbols,uint32_t i_line = 0) : + iv_symbols(i_symbols), + iv_line(i_line), + iv_scom_length(0), + iv_scom_offset(0), + iv_when(NONE) {} + + // Build from binary sequence + Scom(BINSEQ::const_iterator & bli, Symbols * i_symbols); + + bool compare(Scom & that); + uint32_t get_when(void) { return(iv_when); } + void set_when(SCOM_WHEN i_when) { iv_when |= (uint32_t)i_when; } + void set_when(const string * when_str); + bool do_when(SCOM_WHEN i_when) { return ((uint32_t)i_when == (WHEN_MASK & iv_when)); } + void set_sub_when(SCOM_WHEN i_when) { iv_when |= i_when; } + void set_when_rpn(const Rpn * i_rpn) { iv_when_rpn = *i_rpn; delete i_rpn; } + uint32_t get_line() { return iv_line; } + void add_scom_rpn(const Rpn * i_rpn) { iv_scom_rpn.push_back(*i_rpn); delete i_rpn; } + + + + /** + * Is when statement valid for this spy + * @param stats: ostream to print debug information + * @param ec restriction - true if valid for this ec, 0xffffffff means ANY ec + * @return false if Rpn for when statement resolves to false, otherwise true + */ + bool valid_when(ostream & stats, uint32_t i_ec = 0xffffffff); + + void add_col(const string & i_colname); + + /** + * Add a row rpn to the current column + * @param pointer to Rpn object + * @pre add_col() + */ + void add_row_rpn(Rpn * i_rpn); + + void add_bit_range(uint32_t start, uint32_t end); + void add_target_range(uint32_t r1, uint32_t r2); + void make_target(const char * i_symbol); + + + uint64_t get_address(void) {return(strtoul(iv_scom_addr[0].c_str(),NULL,16));} + // string name(); + string listing(); + + /** + * Append binary listing of this Spy + * @param when [init::LONG_SCAN | init::SCOM] + * @param BINSEQ binary listing to append + * @returns uint32_t number of spies added + */ + uint32_t bin_listing(BINSEQ & blist); + + void set_scom_address(const string & i_scom_addr); + void dup_scom_address(const string & i_scom_addr); + void set_scom_suffix(const string & i_scom_addr); + + private: // functions + + string list_one(RANGE range); + void bin_list_one(BINSEQ & blist,uint64_t i_addr, RANGE range); + + /** + * Optimize the row RPNs + * @note Remove any rows that resolve to unconditionally false. + */ + void row_optimize(); + + private: // data + + typedef map<string,SCOM_WHEN> WHEN_SUBTYPE_MAP; + + SCOM_ADDR iv_scom_addr; + uint64_t iv_scom_addr_hex; + uint32_t iv_scom_length; + uint32_t iv_scom_offset; + RPN_LIST iv_scom_rpn; ///< spyv - for each row + RPN_LIST iv_col_vars; ///< RPNs of column name for each column + COL_LIST iv_cols_rpn; ///< A list of row rpn segments one rpn list for each column + RPN_LIST iv_row_rpn; ///< row rpns for current column being parsed. + RANGE_LIST iv_range_list; ///< bit range list + RANGE_LIST iv_target_ranges; ///< target range for current target begin parsed. + Symbols * iv_symbols; + uint32_t iv_line; ///< line # in the initfile + uint32_t iv_when; + Rpn iv_when_rpn; + + + static WHEN_SUBTYPE_MAP cv_when_subtypes; + + }; + + + //================================================================================================= + // SpyList Class declarations + //================================================================================================= + // Container to track scoms + typedef map<uint64_t, init::Scom *> SCOM_LIST; + + class ScomList + { + public: + ScomList(const string & initfile, FILELIST & defines, ostream & stats, uint32_t i_ec = 0xFFFFFFFF); + ~ScomList(); + //size_t size() { return iv_spy_list.size(); } + //SPY_LIST::iterator begin() { return iv_spy_list.begin(); } + //SPY_LIST::iterator end() { return iv_spy_list.end(); } + void clear(); + void insert(Scom * i_scom); + + void compile(BINSEQ & bin_seq); + + void listing(BINSEQ & bin_seq, ostream & out); + void attr_listing(BINSEQ & bin_seq, ostream & out); + + /** + * Compare two spylists for equivalance + * @returns true if equal + * @note Both spylists should have been built from a binary sequence + * not directly from an initfile + */ + bool compare(ScomList & that); + + + + void set_cvs_versions(const string * s) { iv_cvs_versions = *s; } + void set_syntax_version(uint32_t v); + size_t get_syntax_version() { return iv_syntax_version; } + void clear_defines() { iv_symbols->clear_defines(); } + void add_define(const string * name, const Rpn * rpn) + { iv_symbols->add_define(name,rpn); } + + Symbols * get_symbols() { return iv_symbols; } + + private: // functions + + string fmt8(uint32_t val); + + private: + + SCOM_LIST iv_scom_list; + string iv_cvs_versions; + uint32_t iv_syntax_version; + Symbols * iv_symbols; + ostream & iv_stats; + uint32_t iv_ec; + }; +}; +#endif diff --git a/src/usr/hwpf/ifcompiler/initSymbols.C b/src/usr/hwpf/ifcompiler/initSymbols.C new file mode 100755 index 000000000..6e8b8bc38 --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initSymbols.C @@ -0,0 +1,1056 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initSymbols.C,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ---- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// dgilbert 10/22/10 Add spies_are_in() +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// andrewg 11/09/11 Multi-dimensional array and move to common fapi include +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initSymbols.C + * @brief Definition of the initSymbols class. Handles all symbols for initfiles + */ + +#include <initSymbols.H> +#include <initRpn.H> +#include <sstream> +#include <iomanip> +#include <iostream> +#include <fstream> +#include <stdexcept> +#include <stdlib.h> + +using namespace init; + +ostringstream errss; + +#define SYM_EXPR 0x10000000 + +// ------------------------------------------------------------------------------------------------ + +Symbols::Symbols(FILELIST & i_filenames) + : iv_used_var_count(1), iv_used_lit_count(1), iv_rpn_id(1) +{ + string fileline; + + for(FILELIST::iterator fn = i_filenames.begin(); fn != i_filenames.end(); ++fn) + { + printf("Parsing file %s\n",fn->c_str()); + uint32_t lineno = 0; + ifstream infs(fn->c_str()); + if(!infs) + { + errss.str(""); + errss << "ERROR - Could not open " << *fn; + throw invalid_argument(errss.str()); + } + while(getline(infs,fileline)) + { + ++lineno; + if(fileline.size() == 0) continue; + if(fileline[0] == '/') continue; + istringstream iss(fileline); + string def; + iss >> def; + //printf("def: %s\n",def.c_str()); + if(def == "enum") + { + // Make sure it's the AttributeId enum + iss >> def; + if(def == "AttributeId") + { + // We've now found the beginning of the attribute enum definition + // Read and skip the '{' on the next line + getline(infs,fileline); + getline(infs,fileline); + + // We're just parsing the enum in order so values start + // at 0 and increment by 1 after that. + uint32_t value = 0; + + while(fileline[0] != '}') + { + istringstream attr_stream(fileline); + string attr; + attr_stream >> attr; + + // Strip off the "," at the end. + size_t pos = attr.find(','); + if(pos != string::npos) + { + attr = attr.substr(0,attr.length()-1); + } + + //printf("Attribute String:%s\n",attr.c_str()); + // We now have the first attribute loaded into attr + // Get a value for the string + + iv_symbols[attr] = MAP_DATA(value,NOT_USED); + value++; + getline(infs,fileline); + } + } + else + { + // Make sure it's an attribute enum + + string attribute_enum_name; + string find_enum = "_Enum"; + + // Check for _Enum in the name + size_t pos = def.find(find_enum); + if(pos != string::npos) + { + // We've now found the beginning of the attribute enum definition + // Read and skip the '{' on the next line + getline(infs,fileline); + getline(infs,fileline); + + // We're just parsing the enum in order so values start + // at 0 and increment by 1 after that unless they are + // explicitly assigned. + uint64_t value = 0; + + while(fileline[0] != '}') + { + istringstream attr_enum_stream(fileline); + string attr_enum; + string tmp; + + // Get the attribute enum name + attr_enum_stream >> attr_enum; + + // Strip off the "," at the end. + pos = attr_enum.find(','); + if(pos != string::npos) + { + attr_enum = attr_enum.substr(0,attr_enum.length()-1); + } + else + { + // Is a value for the enum specified? + attr_enum_stream >> tmp; + + if (!attr_enum_stream.eof()) + { + //Make sure it's an '=' + if ("=" != tmp) + { + printf ("ERROR: Unknown attribute enum! %s\n",attr_enum.c_str()); + exit(1); + } + else + { + attr_enum_stream >> tmp; + value = strtoll(tmp.c_str(), NULL, 0); + } + } + } + + //printf("Attribute Enum String:%s Value %u\n",attr_enum.c_str(), value); + + // Get a value for the string + iv_attr_enum[attr_enum] = value; + value++; + getline(infs,fileline); + } + } + } + } + else if(def == "typedef") + { + string type; + string attribute_name; + string find_type = "_Type"; + string find_array = "["; + uint32_t array = 0; + iss >> type; + iss >> attribute_name; + if(attribute_name == "*") + { + // It's a pointer type so read in the next string + iss >> attribute_name; + type = type + "*"; + } + //printf("typedef: type:%s attribute_name:%s\n",type.c_str(),attribute_name.c_str()); + + // Determine how many (if any) dimensions this array has + size_t pos = attribute_name.find(find_array); + while(pos != string::npos) + { + array++; + pos = attribute_name.find(find_array,pos+1); + } + + // Now strip off the _type in the name + pos = attribute_name.find(find_type); + if(pos != string::npos) + { + attribute_name = attribute_name.substr(0,pos); + } + else + { + printf ("ERROR: Unknown attribute type! %s\n",attribute_name.c_str()); + exit(1); + } + + iv_attr_type[attribute_name] = get_attr_type(type,array); + //printf("Attribute %s Type with array dimension %u for %s is %u\n",attribute_name.c_str(),array, + // type.c_str(),get_attr_type(type,array)); + } + } + infs.close(); + } + iv_rpn_map[Rpn::SYMBOL | INIT_EXPR_VAR] = RPN_DATA("EXPR",SYM_EXPR); + iv_rpn_map[Rpn::SYMBOL | INIT_ANY_LIT] = RPN_DATA("ANY",CINI_LIT_MASK); +} + +uint32_t Symbols::get_attr_type(const string &i_type, const uint32_t i_array) +{ + uint32_t l_type = 0; + + if (i_type == "uint8_t") + { + l_type = SYM_ATTR_UINT8_TYPE; + } + else if(i_type == "uint32_t") + { + l_type = SYM_ATTR_UINT32_TYPE; + } + else if(i_type == "uint64_t") + { + l_type = SYM_ATTR_UINT64_TYPE; + } + else + { + printf("Unknown data type: %s\n",i_type.c_str()); + exit(-1); + } + + if(i_array > MAX_ATTRIBUTE_ARRAY_DIMENSION) + { + printf("Array dimension size for %s %u exceeded maximum dimension of %u\n", + i_type.c_str(),i_array,MAX_ATTRIBUTE_ARRAY_DIMENSION); + exit(-1); + } + // See enum definition on why this works + l_type += (i_array*ATTR_DIMENSION_SIZE_MULT)+i_array; + + return(l_type); +} + +// ------------------------------------------------------------------------------------------------ + +void Symbols::add_define(const string * name, const Rpn * rpn) +{ + string s(*name); + translate_spyname(s); + iv_defines[s] = DEF_DATA(*rpn,NOT_USED); +} + +// ------------------------------------------------------------------------------------------------- + +Rpn Symbols::get_define_rpn(uint32_t rpn_id) +{ + Rpn r(this); + for(DEF_MAP::iterator i = iv_defines.begin(); i != iv_defines.end(); ++i) + { + if(i->second.second == rpn_id) + { + r = i->second.first; + break; + } + } + return r; +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::use_symbol(string & i_symbol) +{ + uint32_t rpn_id = Rpn::SYMBOL | NOT_FOUND; + if(i_symbol == "ANY") rpn_id = INIT_ANY_LIT | Rpn::SYMBOL; + else if(i_symbol == "EXPR") rpn_id = INIT_EXPR_VAR | Rpn::SYMBOL; + else if(i_symbol.compare(0,3,"DEF") == 0) + { + DEF_MAP::iterator i = iv_defines.find(i_symbol); + if(i != iv_defines.end()) + { + if(i->second.second == NOT_USED) + { + rpn_id = Rpn::DEFINE | iv_rpn_id++; + i->second.second = rpn_id; + } + else + { + rpn_id = i->second.second; + } + } + else + { + rpn_id = add_undefined(i_symbol); + } + } + else + { + SYMBOL_MAP::iterator i = iv_symbols.find(i_symbol); + if(i != iv_symbols.end()) + { + if(i->second.second == NOT_USED) + { + rpn_id = Rpn::SYMBOL | iv_rpn_id++; + i->second.second = rpn_id; + iv_rpn_map[rpn_id] = RPN_DATA(i_symbol,i->second.first); + + //printf ("Symbols::use_symbol: Just added %s symbol, rpn_id:0x%8X to iv_rpn_map\n",i_symbol.c_str(),rpn_id); + + if(i->second.first & CINI_LIT_MASK) ++iv_used_lit_count; + else ++iv_used_var_count; + } + else + { + rpn_id = i->second.second; + } + } + else + { + rpn_id = add_undefined(i_symbol); + } + } + + return rpn_id; +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::add_undefined(const string & i_symbol) +{ + uint32_t rpn_id = 0; + + SYMBOL_MAP::iterator i = iv_not_found.find(i_symbol); + if(i != iv_not_found.end()) + { + rpn_id = i->second.second; + } + else + { + rpn_id = Rpn::SYMBOL | iv_rpn_id++; + iv_not_found[i_symbol] = MAP_DATA(NOT_FOUND,rpn_id); + iv_rpn_map[rpn_id] = RPN_DATA(i_symbol,CINI_ID_NOT_FOUND); + } + return rpn_id; +} + +// ------------------------------------------------------------------------------------------------ + +uint16_t Symbols::get_tag(uint32_t i_rpn_id) +{ + uint16_t tag = NOT_FOUND; + uint32_t cini_id = CINI_ID_NOT_FOUND; + + // Set up tag table if not already setup + if(iv_used_var.size() == 0) + { + iv_used_var.reserve(iv_used_var_count); // makes if faster + iv_used_lit.reserve(iv_used_lit_count); + + iv_used_var.push_back(iv_rpn_map[Rpn::SYMBOL|INIT_EXPR_VAR].second); // EXPR var always first + iv_used_lit.push_back(iv_rpn_map[Rpn::SYMBOL|INIT_ANY_LIT].second); // ANY lit always first + + for(SYMBOL_MAP::iterator i = iv_symbols.begin(); i != iv_symbols.end(); ++i) + { + if(i->second.second != NOT_USED) + { + if((i->second.first & CINI_LIT_MASK) == CINI_LIT_MASK) + { + iv_used_lit.push_back(i->second.first); + } + else //VAR + { + iv_used_var.push_back(i->second.first); + } + } + } + } + + do + { + + RPN_MAP::iterator rm = iv_rpn_map.find(i_rpn_id); + if(rm != iv_rpn_map.end()) + { + cini_id = (rm->second).second; + } + else + { + //SYMBOL_MAP::iterator sm = iv_not_found.begin(); + //for(; sm != iv_not_found.end(); ++sm) + //{ + // if((sm->second).second == i_rpn_id) + // { + // break; + // } + //} + + //if(sm == iv_not_found.end()) + //{ + ostringstream err; + err << hex; + err << "ERROR! Symbols::get_tag() bad arg rpn_id = " << i_rpn_id << endl; + throw invalid_argument(err.str()); + //} + break; + } + + uint32_t offset = 0; + for(SYMBOL_USED::iterator i = iv_used_var.begin(); i != iv_used_var.end(); ++i,++offset) + { + if(cini_id == *i) + { + tag = (uint16_t) (offset | IF_ATTR_TYPE); + break; + } + } + + } while(0); + + return tag; +} + + + + +// ------------------------------------------------------------------------------------------------ + +string Symbols::find_name(uint32_t i_rpn_id) +{ + string name; + RPN_MAP::iterator rm = iv_rpn_map.find(i_rpn_id); + if(rm != iv_rpn_map.end()) + { + name = (rm->second).first; + } + else name = "NOT FOUND"; + return name; +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::find_numeric_lit(uint64_t i_data, int32_t byte_size) +{ + uint32_t offset = 0; + LIT_LIST::iterator i = iv_lits.begin(); + for(; i != iv_lits.end(); ++i,++offset) + { + if(i_data == i->first && (uint32_t)byte_size == i->second) + break; + } + if(i == iv_lits.end()) + { + iv_lits.push_back(LIT_DATA(i_data,byte_size)); + } + //printf("Symbols::find_numeric_lit: i_data:0x%llX byte_size:%d Tag:0x%X\n", + // i_data,byte_size, offset | Rpn::NUMBER); + return offset | Rpn::NUMBER; +} + +uint32_t Symbols::find_numeric_array_lit(uint64_t i_data, int32_t byte_size) +{ + uint32_t offset = 0; + LIT_LIST::iterator i = iv_lits.begin(); + for(; i != iv_lits.end(); ++i,++offset) + { + if(i_data == i->first && (uint32_t)byte_size == i->second) + break; + } + if(i == iv_lits.end()) + { + iv_lits.push_back(LIT_DATA(i_data,byte_size)); + } + //printf("Symbols::find_numeric_lit: i_data:0x%llX byte_size:%d Tag:0x%X\n", + // i_data,byte_size, offset | Rpn::NUMBER); + return offset | Rpn::ARRAY_INDEX; +} + +// ------------------------------------------------------------------------------------------------ + +uint16_t Symbols::get_numeric_tag(uint32_t i_rpn_id) +{ + uint32_t tag = NOT_FOUND; + uint32_t offset = i_rpn_id - Rpn::NUMBER; + string any("ANY"); + if(iv_used_lit.size() == 0) get_tag(use_symbol(any)); + if(offset < iv_lits.size()) + { + // numeric lits are numbered after enum lits, but with different TYPE + tag = (iv_used_lit.size() + offset) | IF_NUM_TYPE; + } + else + { + ostringstream err; + err << hex; + err << "ERROR! - Symbols::get_numeric_tag() invalid arg rpn_id = " << i_rpn_id << endl; + throw invalid_argument(err.str()); + } + return (uint16_t)tag; +} + +// ------------------------------------------------------------------------------------------------ + +uint16_t Symbols::get_numeric_array_tag(uint32_t i_rpn_id) +{ + uint32_t tag = NOT_FOUND; + uint32_t offset = i_rpn_id - Rpn::ARRAY_INDEX; + string any("ANY"); + if(iv_used_lit.size() == 0) get_tag(use_symbol(any)); + if(offset < iv_lits.size()) + { + // numeric lits are numbered after enum lits, but with different TYPE + tag = (iv_used_lit.size() + offset) | IF_NUM_TYPE; + } + else + { + ostringstream err; + err << hex; + err << "ERROR! - Symbols::get_numeric_array_tag() invalid arg rpn_id = " << i_rpn_id << endl; + throw invalid_argument(err.str()); + } + return (uint16_t)tag; +} + +// ------------------------------------------------------------------------------------------------ + +uint64_t Symbols::get_numeric_data(uint32_t i_rpn_id, uint32_t & o_size) +{ + uint64_t data = 0; + o_size = 0; + uint32_t offset = i_rpn_id - Rpn::NUMBER; + if(offset < iv_lits.size()) + { + LIT_DATA d = iv_lits[offset]; + data = d.first; + o_size = d.second; + } + else + { + ostringstream err; + err << hex; + err << "ERROR! - Symbols::get_numeric_data() invalid arg rpn_id = " << i_rpn_id << endl; + throw invalid_argument(err.str()); + } + return data; +} + +// ------------------------------------------------------------------------------------------------ +uint64_t Symbols::get_attr_enum_val(string & i_attr_enum) +{ + return iv_attr_enum[i_attr_enum]; +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::find_text(uint32_t i_cini_id) +{ + string name = "NOT FOUND"; + if(i_cini_id == CINI_LIT_MASK) name = "ANY"; + else if(i_cini_id == SYM_EXPR) name = "EXPR"; + else + { + for(SYMBOL_MAP::const_iterator i = iv_symbols.begin(); i != iv_symbols.end(); ++i) + { + //printf("SYMBOL:%s\n",i->first.c_str()); + if((i->second).first == i_cini_id) + { + name = i->first; + break; + } + } +// for(RPN_MAP::iterator i = iv_rpn_map.begin(); i != iv_rpn_map.end(); ++i) +// { +// if((i->second).second == i_cini_id) +// { +// name = (i->second).first; +// break; +// } +// } + } + return name; +} + + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::get_spy_id(const string & spyname) +{ + uint32_t id = NOT_FOUND; + string s = spyname; + translate_spyname(s); + SPY_MAP::iterator sm = iv_spymap.find(s); + if(sm != iv_spymap.end()) + { + id = sm->second; + } + else + { + size_t pos = s.find('-'); + if(pos == string::npos) s.insert(0,"SPY_"); + else + { + s[pos] = '_'; + s.insert(pos+1,"SPY_"); + s.insert(0,"ENUM_"); + } + iv_not_found[s] = MAP_DATA(0,0); + //cerr << "ERROR! Symbols::get_spy_id() Spyname not found " << '[' << s << ']' << endl; + } + return id; +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::use_enum(const string & enumname) +{ + uint32_t rpn_id = NOT_FOUND; + string s = enumname; + translate_spyname(s); + SPY_MAP::iterator sm = iv_enums.find(s); + if(sm != iv_enums.end()) + { + rpn_id = sm->second; + } + else + { + printf("Error!\n"); + exit(0); + } + return rpn_id; +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::get_spy_enum_id(uint32_t i_rpn_id, const string & spyname) +{ + //uint32_t id = NOT_FOUND; + string enumname = get_enum_name(i_rpn_id); + enumname.append("-"); + enumname.append(spyname); + return get_spy_id(enumname); +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::get_enum_name(uint32_t i_rpn_id) +{ + string name("SPY ENUM NOT FOUND"); + for(SPY_MAP::iterator i = iv_enums.begin(); i != iv_enums.end(); ++i) + { + if(i->second == i_rpn_id) + { + name = i->first; + break; + } + } + return name; +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::full_listing() +{ + uint32_t count = 0; + ostringstream oss; + oss << hex << setfill('0'); + + for(SYMBOL_MAP::iterator i = iv_symbols.begin(); i != iv_symbols.end(); ++i) + { + if(i->second.first < CINI_LIT_MASK) //VAR + { + ++count; + oss << "0x" << setw(8) << i->second.first << '\t' + << '[' << i->first << ']' << endl; + } + } + + ostringstream title; + title << "\n--------------- Attribute Symbol Table ---------------\n\n" + << "0x" << hex << setfill('0') << setw(8) << count << '\t' + << "Number of variables\n" << oss.str(); + + oss.str(""); + count = 0; + + for(SYMBOL_MAP::iterator i = iv_symbols.begin(); i != iv_symbols.end(); ++i) + { + if((i->second.first & CINI_LIT_MASK) == CINI_LIT_MASK) //LIT + { + ++count; + oss << "0x" << setw(8) << i->second.first << '\t' + << '[' << i->first << ']' << endl; + } + } + + title << "\n--------------- Literal Symbol Table -----------------\n\n" + << setw(8) << count << '\t' << "Number of enumerated literals\n" + << oss.str(); + + oss.str(""); + title << "\n-------------------- Spies and arrays ----------------------\n\n" + << "0x" << setw(8) << iv_spymap.size() << '\t' << "Number of spies and array symbols\n"; + + for(SPY_MAP::iterator i = iv_spymap.begin(); i != iv_spymap.end(); ++i) + { + oss << "0x" << setw(8) << i->second << '\t' << '[' << i->first << ']' << endl; + } + + title << oss.str(); + + return title.str(); +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::listing() +{ + uint32_t count = 0; + ostringstream oss; + + // Set up tag table if not already setup + string any = "ANY"; + get_tag(use_symbol(any)); + + oss << hex << setfill('0'); + + oss << "\n--------------- Attribute Symbol Table ---------------\n\n" + << "0x" << setw(4) << iv_used_var.size()-1 << '\t' << "Number of variables\n"; + + for(SYMBOL_USED::iterator i = iv_used_var.begin() + 1; i != iv_used_var.end(); ++i) + { + ++count; + oss << "Type:" << setw(2) << iv_attr_type[find_text(*i)] << " Value:0x" << setw(8) << (*i) << '\t' << "ID 0X" << setw(4) << (count | IF_ATTR_TYPE) + << '\t' << '[' << find_text(*i) << ']' << endl; + + //printf("ATTRIBUTE: %s Value:0x%02X\n",(find_text(*i)).c_str(),iv_attr_type[find_text(*i)]); + } + + count = 0; + + oss << "\n--------------- Literal Symbol Table -----------------\n\n"; + + oss << "\n0x" << setw(4) << iv_lits.size() << '\t' << "Number of numeric literals\n"; + + count = 0; + for(LIT_LIST::iterator i = iv_lits.begin(); i != iv_lits.end(); ++i,++count) + { + oss << "0x" << setw(2) << i->second << endl + << "0x" << setw(2 * i->second) << i->first; + if(i->second < 6) oss << "\t\t"; + else oss<< '\t'; + oss << "ID 0x" << setw(4) << get_numeric_tag(count | Rpn::NUMBER) << endl; + } + + oss << not_found_listing(); + + return oss.str(); +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::attr_listing() +{ + ostringstream oss; + + // Set up tag table if not already setup + string any = "ANY"; + get_tag(use_symbol(any)); + + for(SYMBOL_USED::iterator i = iv_used_var.begin() + 1; i != iv_used_var.end(); ++i) + { + oss << find_text(*i) << endl; + } + + return oss.str(); +} + +// ------------------------------------------------------------------------------------------------ + +string Symbols::not_found_listing() +{ + ostringstream oss; + if(iv_not_found.size()) + { + oss << "\n------------- Symbols requested that were NOT FOUND ---------------\n\n"; + for(SYMBOL_MAP::iterator i = iv_not_found.begin(); i != iv_not_found.end(); ++i) + { + //if(i->first == "SPY_NOTFOUND" || (i->first).compare(0,13,"ENUM_NOTFOUND") == 0) continue; + oss << '[' << i->first << ']' << endl; + } + } + return oss.str(); +} + +// ------------------------------------------------------------------------------------------------ + +uint32_t Symbols::bin_vars(BINSEQ & blist) +{ + // Set up tag table if not already setup + string any = "ANY"; + get_tag(use_symbol(any)); + + uint32_t count = iv_used_var.size() - 1; // first VAR is 'EXPR' and is not stored + + Rpn::set16(blist,(uint16_t)count); + + for(SYMBOL_USED::iterator i = iv_used_var.begin() + 1; i != iv_used_var.end(); ++i) + { + // Write out the attribute type (i.e. uint8_t, uint16_t, ...) and it's index number + Rpn::set8(blist,iv_attr_type[find_text(*i)]); + Rpn::set32(blist,(*i)); + //printf("Symbols::bin_vars: Just wrote out type:%u value:%u\n",iv_attr_type[find_text(*i)],*i); + } + return count; +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Symbols::bin_lits(BINSEQ & blist) +{ + // Set up tag table if not already setup + string any = "ANY"; + get_tag(use_symbol(any)); + + uint32_t count = iv_lits.size(); + uint32_t total = count; + + Rpn::set16(blist,(uint16_t)count); + + for(LIT_LIST::iterator i = iv_lits.begin(); i != iv_lits.end(); ++i) + { + uint32_t size = i->second; + uint64_t data = i->first; + blist.push_back( (uint8_t)size ); + uint32_t shift_count = size * 8; + while(shift_count) + { + shift_count -= 8; + blist.push_back( (uint8_t)(data >> shift_count) ); + } + } + total += count; + + return total; +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Symbols::restore_var_bseq(BINSEQ::const_iterator & bli) +{ + uint32_t count = Rpn::extract16(bli); + + iv_used_var.clear(); + iv_used_var.push_back(iv_rpn_map[Rpn::SYMBOL|INIT_EXPR_VAR].second); // EXPR var always first + + for(uint32_t i = 0; i < count; ++i) + { + uint8_t type = Rpn::extract8(bli); + uint32_t attribute = Rpn::extract32(bli); + iv_attr_type[find_text(attribute)] = type; + iv_used_var.push_back(attribute); + } + return count; +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Symbols::restore_lit_bseq(BINSEQ::const_iterator & bli) +{ + iv_used_lit.clear(); + iv_used_lit.push_back(iv_rpn_map[Rpn::SYMBOL|INIT_ANY_LIT].second); // ANY lit always first + + iv_lits.clear(); + uint32_t num_count = Rpn::extract16(bli); + + for(uint32_t i = 0; i < num_count; ++i) + { + uint8_t size = *bli++; + uint64_t data = 0; + switch (size) + { + case 1: data = *bli++; break; + case 2: data = Rpn::extract16(bli); break; + case 4: data = Rpn::extract32(bli); break; + case 8: data = Rpn::extract64(bli); break; + default: + { + ostringstream errs; + errs << "ERROR! Symbols::restore_var_bseq(). Invalid literal data size [" + << size << ']' << endl; + throw invalid_argument(errs.str()); + } + break; + } + + iv_lits.push_back( LIT_DATA(data, size) ); + } + + return num_count; +} + +//------------------------------------------------------------------------------------------------- + +string Symbols::get_spyname(uint32_t spy_id) +{ + string name; + + for(SPY_MAP::const_iterator i = iv_spymap.begin(); i != iv_spymap.end(); ++i) + { + if (i->second == spy_id) + { + name = i->first; + break; + } + } + if(name.length() == 0) + { + ostringstream oss; + oss << hex << setfill('0'); + oss << "[0x" << setw(8) << spy_id << ']'; + name = oss.str(); + } + return name; +} +//------------------------------------------------------------------------------------------------- + +string Symbols::get_enumname(uint32_t spy_id) +{ + string name = get_spyname(spy_id); + size_t pos = name.find('-'); + if(pos != string::npos) + { + name = name.substr(0,pos); + } + return name; +} + +//------------------------------------------------------------------------------------------------- + +uint32_t Symbols::get_rpn_id(uint32_t bin_tag) +{ + uint32_t rpn_id = NOT_FOUND; + uint32_t type = bin_tag & IF_TYPE_MASK; + uint32_t offset = bin_tag & ~IF_TYPE_MASK; + uint32_t cini_id = 0; + switch(type) + { + case IF_ATTR_TYPE: { + cini_id = iv_used_var[offset]; + string name = find_text(cini_id); + rpn_id = use_symbol(name); + } + break; + + case IF_NUM_TYPE: { + offset -= iv_used_lit.size(); + if(offset >= iv_lits.size()) + { + ostringstream erros; + erros << hex; + erros << "ERROR! Symbols::get_rpn_id() Invalid NUM_TYPE 0x" + << bin_tag; + throw range_error(erros.str()); + } + LIT_DATA d = iv_lits[offset]; + rpn_id = find_numeric_lit(d.first,d.second); + } + break; + + default: + { + ostringstream erros; + erros << hex + << "ERROR! Symbols::get_rpn_id() Invalid bin_tag = 0x" + << bin_tag << endl; + throw range_error(erros.str()); + } + break; + } + return rpn_id; +} +//------------------------------------------------------------------------------------------------- + +string Symbols::spies_are_in(Symbols & i_full_list, const set<string> & i_ignore_spies) +{ + ostringstream result; + result << hex; + + for(SPY_MAP::iterator i = iv_spymap.begin(); i != iv_spymap.end(); ++i) + { + // enums in the reduced file will soon no longer contain the spyname as part of the enum name <enum name>-<spy name> + // At that time we will just need to check the enum part of the name <enum name> in both the ignore file and the full list + // When initfile processing AND spyhunter both use only enum names for enum spies then we can simplify all this + string spyname = i->first; + size_t pos = spyname.find('-'); // check for enum - if so just use the spy part of the name + if(pos != string::npos) + { + spyname = spyname.substr(pos+1); + } + + if(i_ignore_spies.find(spyname) != i_ignore_spies.end()) //don't check this spy or any of it's enums + { + cout << "Will not check spy: " << i->first << endl; + continue; + } + + uint32_t hash = 0; + if(pos != string::npos) // old enum style name - check by hash - only check enumname + { + // just compare enum names based on hash + string enumname1 = (i->first).substr(0,pos); + string enumname2 = i_full_list.get_enumname(i->second); + if(enumname1 != enumname2) + { + result << "ERROR! Enum not found for spy " << i->first << '\n' + << " Enum: " << enumname1 << "!=" << enumname2 << endl; + } + } + else // check spyname by name or new-style enum by name + { + hash = i_full_list.get_spy_id(i->first); + if(hash != NOT_FOUND) + { + if(hash != i->second) + { + result << "ERROR! HASH not the same for spy " + << i->first << ' ' << hash << ' ' << i->second << endl; + } + // else cout << "Found " << i->first << ' ' << i->second << endl; + } + } + } + result << i_full_list.not_found_listing(); + + + return result.str(); +} + + + + + diff --git a/src/usr/hwpf/ifcompiler/initSymbols.H b/src/usr/hwpf/ifcompiler/initSymbols.H new file mode 100755 index 000000000..efef0dcbe --- /dev/null +++ b/src/usr/hwpf/ifcompiler/initSymbols.H @@ -0,0 +1,269 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/ifcompiler/initSymbols.H,v $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2010,2010 +// +//UNDEFINED +// +// Origin: UNDEFINED +// +// IBM_PROLOG_END_TAG +#if !defined(INITSYMBOLS_H) +#define INITSYMBOLS_H + +// Change Log ************************************************************************************* +// +// Flag Track Userid Date Description +// ---- -------- -------- -------- ------------------------------------------------------------- +// D754106 dgilbert 06/14/10 Create +// andrewg 09/19/11 Updates based on review +// camvanng 11/08/11 Added support for attribute enums +// andrewg 11/09/11 Multi-dimensional array and move to common fapi include +// mjjones 11/17/11 Output attribute listing +// End Change Log ********************************************************************************* + +/** + * @file initSymbols.H + * @brief Definition of the initSymbols class. Handles all symbols for initfiles + */ + +// Definitions: +// cini_id is the 32 bit symbol tag value of a CINI initfile literal or variable as defined in ciniIfSymbols.H +// rpn_id is an internal representation used by the Rpn class for all numbers, symbols, Spy enums, etc. that is not an operator +// bin_id is the 16 bit tag used to represet number, symbols, enums, etc. in the compiled initfile. + + +#include <stdint.h> +#include <string> +#include <vector> +#include <map> +#include <set> +#include <initRpn.H> +#include <fapiHwpInitFileInclude.H> // Requires file from hwpf + +using namespace std; + + +namespace init +{ + typedef set<string> FILELIST; + + class Symbols + { + public: + + enum + { + CINI_LIT_MASK = 0xA0000000, + INIT_ANY_LIT = 0x07FFFFFE, + INIT_EXPR_VAR = 0x07FFFFFF, + }; + + + + enum + { + NOT_FOUND = 0x00000000, + NOT_USED = 0x00000000, + CINI_ID_NOT_FOUND = 0x80000000, + }; + + /** + * Build symbol map for list of files + * @param List of files to open to build Symbols + */ + Symbols(FILELIST & i_filenames); + + /** + * Add a Symbol to the "used" symbol table if not already there + * @param string Symbols name + * @returns Symbols Rpn id + * @post marks the id as 'USED' + * + */ + uint32_t use_symbol(string & i_symbol); + + /** + * Lookup the tag id from the rpn_id provided by use_symbol() + * @returns tag id + * @param rpn_id + * @pre all the symbols have been marked used (no new symbols) + * @post tag table built if not already built. + * @note tag bits 0bttxxxxxx xxxxxxxx + * tt == 0b01 -> enumerated literal + * tt == 0b10 -> Variable name + * tt == 0b11 -> Numeric constant + * xxxxxx xxxxxxxx assigned tag offset + */ + uint16_t get_tag(uint32_t i_rpn_id); + + /** + * Find the symbol name associated with an rpn_id + * @param uint32_t rpn_id + * @returns string Symbol name | "" if not found + */ + string find_name(uint32_t i_rpn_id); + + /** + * Find the tag for the numeric lit + * @param data + * @param number of significant bytes in the data [1-8] + * @returns Rpn id + */ + uint32_t find_numeric_lit(uint64_t i_data, int32_t byte_size); + + /** + * Find the tag for the numeric array lit + * @param data + * @param number of significant bytes in the data [1-8] + * @returns Rpn id + */ + uint32_t find_numeric_array_lit(uint64_t i_data, int32_t byte_size); + + /** + * Convert a numeric literal Rpn tag to an initfile tag + * @param Rpn id returned by find_numeric_lit + * @return tag + * @pre Must not be called until find_numeric_lit() has been called for all numbers + * in the initfile. + */ + uint16_t get_numeric_tag(uint32_t i_rpn_id); + + /** + * Convert a numeric array literal Rpn tag to an initfile tag + * @param Rpn id returned by find_numeric_lit + * @return tag + * @pre Must not be called until find_numeric_array_lit() has been called for all numbers + * in the initfile. + */ + uint16_t get_numeric_array_tag(uint32_t i_rpn_id); + + /** + * Get the literal data value from the Rpn id returned by find_numeric_lit() + * @param uint32_t Rpn id + * @param uint32_t for returned byte size + * @returns uint64_t data + */ + uint64_t get_numeric_data(uint32_t i_rpn_id, uint32_t & o_size); + + /** + * Get the attribute enum value for the attr enum + * @param string attribute enum name + * @returns uint64_t value + */ + uint64_t get_attr_enum_val(string & i_attr_enum); + + + /** + * Store enum name & return rpn_id + */ + uint32_t use_enum(const string & enumname); + uint32_t get_spy_enum_id(uint32_t i_rpn_id, const string & spyname); + string get_enum_name(uint32_t i_rpn_id); + + string get_enumname(uint32_t spy_id); + string get_spyname(uint32_t spy_id); + + /** + * Return spy id + */ + uint32_t get_spy_id(const string & spyname); + + void add_define(const string * name, const Rpn * rpn); + Rpn get_define_rpn(uint32_t rpn_id); + void clear_defines() { iv_defines.clear(); } + + + string listing(); ///< listing of used vars & lits + string attr_listing(); ///< listing of used HWPF attributes + uint32_t bin_vars(BINSEQ & blist); ///< binary byte output of used vars. ret # vars + uint32_t bin_lits(BINSEQ & blist); ///< binary byte sequence of used lits ret # lits + + string full_listing(); ///< listing of all vars & lits (debug) + string not_found_listing(); ///< listing of all vars searched for, but not found + + /** + * Get the rpn_id from an initfile binary tag + */ + uint32_t get_rpn_id(uint32_t bin_tag); + + + /** + * Restore used symbol lists from binary sequence + * @returns number of symbols + */ + uint32_t restore_var_bseq(BINSEQ::const_iterator & bli); + uint32_t restore_lit_bseq(BINSEQ::const_iterator & bli); + + /** + * Test that all spies in this object are a subset of the object provided + * @param Symbols object to compare against + * @return string will all error messages. Empty string indicates success. + */ + string spies_are_in(Symbols & i_full_list, const set<string> & i_ignore_spies); + + static void translate_spyname(string & s) + { + for(string::iterator i = s.begin(); i != s.end(); ++i) + if((*i) == '.' || (*i) == '#' || + (*i) == '=' || (*i) == '&' || + (*i) == '<' || (*i) == '>' || + (*i) == '!' || (*i) == '*' || + (*i) == '/' || (*i) == '%' || + (*i) == '$') *i = '_'; + else *i = toupper(*i); + } + + private: // functions + + string find_text(uint32_t i_cini_id); + uint32_t add_undefined(const string & s); + uint32_t get_attr_type(const string &i_type, const uint32_t i_array); + + private: //data + + // map | symbol name | (cini_id, usage flags) | + typedef pair<uint32_t,uint32_t> MAP_DATA; + typedef map<string,MAP_DATA > SYMBOL_MAP; + typedef map<string,uint32_t> SPY_MAP; + typedef map<string,uint32_t> SYMBOL_ATTR_TYPE; + typedef map<string,uint64_t> SYMBOL_ATTR_ENUM; + + typedef pair<Rpn,uint32_t> DEF_DATA; + typedef map<string,DEF_DATA> DEF_MAP; + + typedef pair<string,uint32_t> RPN_DATA; + typedef map<uint32_t,RPN_DATA> RPN_MAP; + + typedef vector<uint32_t> SYMBOL_USED; + + typedef pair<uint64_t,uint32_t> LIT_DATA; + typedef vector<LIT_DATA> LIT_LIST; + + SYMBOL_MAP iv_symbols; ///< From ciniIfSymbols.H all vars and enumerated lits + SYMBOL_ATTR_TYPE iv_attr_type; + SYMBOL_ATTR_ENUM iv_attr_enum; + SYMBOL_MAP iv_not_found; ///< List of symbols not found + RPN_MAP iv_rpn_map; ///< Map rpn_id to symbol name/cini_id of used Symbols + SYMBOL_USED iv_used_var; ///< List of cini_ids of used vars ordered by name + SYMBOL_USED iv_used_lit; ///< List of cini_ids of used enum lits ordered by name + + LIT_LIST iv_lits; ///< Numeric literals + + SPY_MAP iv_spymap; ///< Spies & arrays & enum spies + SPY_MAP iv_enums; ///< Spy enums + + DEF_MAP iv_defines; ///< defines + + uint32_t iv_used_var_count; + uint32_t iv_used_lit_count; + uint32_t iv_rpn_id; ///< Current rpn offset assignment + }; +}; + + +#endif diff --git a/src/usr/hwpf/makefile b/src/usr/hwpf/makefile index 7749368ec..6a031cde9 100644 --- a/src/usr/hwpf/makefile +++ b/src/usr/hwpf/makefile @@ -21,29 +21,137 @@ # # IBM_PROLOG_END ROOTPATH = ../../.. -MODULE = hwpf +SUBDIRS = fapi.d hwp.d plat.d test.d + +#------------------------------------------------------------------------------ +# This makefile controls the generation of HWPF files +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# Source XML files +#------------------------------------------------------------------------------ +HWP_ERROR_XML_FILES = hwp/fapiHwpErrorInfo.xml +HWP_ATTR_XML_FILES = hwp/fapiHwpAttributeInfo.xml + +#------------------------------------------------------------------------------ +# Initfiles +#------------------------------------------------------------------------------ +HWP_INITFILES = hwp/initfiles/sample.initfile + +#------------------------------------------------------------------------------ +# Generated files +#------------------------------------------------------------------------------ +# Initfile compiler files +IF_CMP_YACC_C_TARGET = y.tab.c +IF_CMP_YACC_H_TARGET = y.tab.h +IF_CMP_FLEX_TARGET = lex.yy.c +IF_CMP_COMPILER_TARGET = ifcompiler + +# The FAPI return code and error info files generated from Error XML files FAPI_ERROR_TARGETS = fapiHwpReturnCodes.H fapiHwpErrorInfo.H -FAPI_ATTR_TARGETS = fapiAttributeIds.H fapiAttributeService.C -FAPI_HWP_ERROR_TAGS = fapiHwpReasonCodes.H -GENFILES = ${FAPI_ERROR_TARGETS} ${FAPI_ATTR_TARGETS} ${FAPI_HWP_ERROR_TAGS} +# The PLAT error tag file generated from Error XML files +PLAT_ERROR_TAG_TARGET = fapiHwpReasonCodes.H -SUBDIRS = fapi.d hwp.d plat.d test.d +# The FAPI attribute id file generated from Attribute XML files +FAPI_ATTR_ID_TARGET = fapiAttributeIds.H + +# The binary, list and attr files generated from Initfiles +# Generation depends on ifcompiler and fapiAttributeIds.H +HWP_IF_NAMES = $(notdir ${HWP_INITFILES}) +HWP_IF_BASENAMES = $(basename ${HWP_IF_NAMES}) +HWP_IF_BIN_TARGETS = $(addsuffix .if, ${HWP_IF_BASENAMES}) +HWP_IF_LST_TARGETS = $(addsuffix .if.list, ${HWP_IF_BASENAMES}) +HWP_IF_ATT_TARGETS = $(addsuffix .if.attr, ${HWP_IF_BASENAMES}) +HWP_IF_ALL_TARGETS = ${HWP_IF_BIN_TARGETS} ${HWP_IF_LST_TARGETS} \ + ${HWP_IF_ATT_TARGETS} + +# The FAPI Initfile attribute service +# Generation depends on the Initfile <name>.if.attr files +FAPI_ATTR_IF_TARGET = fapiAttributeService.C + +GENFILES = ${IF_CMP_YACC_C_TARGET} \ + ${IF_CMP_YACC_H_TARGET} \ + ${IF_CMP_FLEX_TARGET} \ + ${IF_CMP_COMPILER_TARGET} \ + ${FAPI_ERROR_TARGETS} \ + ${PLAT_ERROR_TAG_TARGET} \ + ${FAPI_ATTR_ID_TARGET} \ + ${HWP_IF_ALL_TARGETS} \ + ${FAPI_ATTR_IF_TARGET} + +EXTRA_PARTS = ${ROOTPATH}/img/${HWP_IF_BIN_TARGETS} include ${ROOTPATH}/config.mk -# fapiParseErrorInfo.pl produces multiple output files: FAPI_ERROR_TARGETS -$(call GENTARGET, $(FAPI_ERROR_TARGETS)) : \ - fapi/fapiParseErrorInfo.pl hwp/fapiHwpErrorInfo.xml - $< $(dir $@) $(filter-out $<,$^) +#------------------------------------------------------------------------------ +# The Initfile compiler +#------------------------------------------------------------------------------ +$(call GENTARGET, ${IF_CMP_YACC_C_TARGET} ${IF_CMP_YACC_H_TARGET}) : \ + ifcompiler/initCompiler.y + yacc -d -o ${GENDIR}/${IF_CMP_YACC_C_TARGET} $^ + +$(call GENTARGET, ${IF_CMP_FLEX_TARGET}) : \ + ifcompiler/initCompiler.lex + flex -o$@ $^ + +IF_COMPILER_C_FILES = ifcompiler/initCompiler.C \ + ifcompiler/initRpn.C \ + ifcompiler/initScom.C \ + ifcompiler/initSymbols.C + +IF_COMPILER_H_FILES = ifcompiler/initCompiler.H \ + ifcompiler/initRpn.H \ + ifcompiler/initScom.H \ + ifcompiler/initSymbols.H + +$(call GENTARGET, ${IF_CMP_COMPILER_TARGET}) : \ + ${GENDIR}/${IF_CMP_YACC_C_TARGET} \ + ${GENDIR}/${IF_CMP_YACC_H_TARGET} \ + ${GENDIR}/${IF_CMP_FLEX_TARGET} \ + ${IF_COMPILER_C_FILES} \ + ${IF_COMPILER_H_FILES} + g++ ${IF_COMPILER_C_FILES} ${GENDIR}/${IF_CMP_FLEX_TARGET} \ + ${GENDIR}/${IF_CMP_YACC_C_TARGET} -I ifcompiler -I ${GENDIR} \ + -I ${ROOTPATH}/src/include/usr/hwpf/hwp -o $@ + +#------------------------------------------------------------------------------ +# The FAPI return code and error info files generated from Error XML files +#------------------------------------------------------------------------------ +$(call GENTARGET, ${FAPI_ERROR_TARGETS}) : \ + fapi/fapiParseErrorInfo.pl ${HWP_ERROR_XML_FILES} + $< $(dir $@) ${HWP_ERROR_XML_FILES} + +#------------------------------------------------------------------------------ +# The PLAT error tag file generated from Error XML files +#------------------------------------------------------------------------------ +$(call GENTARGET, ${PLAT_ERROR_TAG_TARGET}) : \ + plat/fapiCreateHwpErrorTags.pl ${HWP_ERROR_XML_FILES} + $< $(dir $@) ${HWP_ERROR_XML_FILES} + +#------------------------------------------------------------------------------ +# The FAPI attribute id file generated from Attribute XML files +#------------------------------------------------------------------------------ +$(call GENTARGET, ${FAPI_ATTR_ID_TARGET}) : \ + fapi/fapiParseAttributeInfo.pl ${HWP_ATTR_XML_FILES} + $< $(dir $@) ${HWP_ATTR_XML_FILES} + +#------------------------------------------------------------------------------ +# The binary, list and attr files generated from Initfiles +#------------------------------------------------------------------------------ +$(call GENTARGET, ${HWP_IF_ALL_TARGETS}) : \ + ${GENDIR}/${IF_CMP_COMPILER_TARGET} ${HWP_INITFILES} ${GENDIR}/${FAPI_ATTR_ID_TARGET} + $< -init ${HWP_INITFILES} -outdir $(dir $@) -attr ${GENDIR}/${FAPI_ATTR_ID_TARGET} -# fapiParseAttributeInfo.pl produces multiple output files: FAPI_ATTR_TARGETS -$(call GENTARGET, $(FAPI_ATTR_TARGETS)) : \ - fapi/fapiParseAttributeInfo.pl hwp/fapiHwpAttributeInfo.xml - $< $(dir $@) $(filter-out $<,$^) +${EXTRA_PARTS}: ${IMGDIR}/% : ${GENDIR}/% + cp -f $^ $@ -$(call GENTARGET, $(FAPI_HWP_ERROR_TAGS)) : \ - plat/fapiCreateHwpErrorTags.pl hwp/fapiHwpErrorInfo.xml - $< $(dir $@) $(filter-out $<,$^) +#------------------------------------------------------------------------------ +# The FAPI Initfile attribute service +#------------------------------------------------------------------------------ +$(call GENTARGET, ${FAPI_ATTR_IF_TARGET}) : \ + fapi/fapiCreateIfAttrService.pl ${HWP_ATTR_XML_FILES} \ + $(addprefix ${GENDIR}/, $(HWP_IF_ATT_TARGETS)) + $< $(dir $@) $(addprefix ${GENDIR}/, $(HWP_IF_ATT_TARGETS)) -a ${HWP_ATTR_XML_FILES} |