Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
si_gen.cxx
Go to the documentation of this file.
00001 /*
00002 
00003   Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.
00004 
00005   This program is free software; you can redistribute it and/or modify it
00006   under the terms of version 2 of the GNU General Public License as
00007   published by the Free Software Foundation.
00008 
00009   This program is distributed in the hope that it would be useful, but
00010   WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00012 
00013   Further, this software is distributed without any warranty that it is
00014   free of the rightful claim of any third person regarding infringement 
00015   or the like.  Any license provided herein, whether implied or 
00016   otherwise, applies only to this software file.  Patent licenses, if 
00017   any, provided herein do not apply to combinations of this program with 
00018   other software, or any other product whatsoever.  
00019 
00020   You should have received a copy of the GNU General Public License along
00021   with this program; if not, write the Free Software Foundation, Inc., 59
00022   Temple Place - Suite 330, Boston MA 02111-1307, USA.
00023 
00024   Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
00025   Mountain View, CA 94043, or:
00026 
00027   http://www.sgi.com
00028 
00029   For further information regarding this notice, see:
00030 
00031   http://oss.sgi.com/projects/GenInfo/NoticeExplan
00032 
00033 */
00034 
00035 
00036 //   si_gen
00038 //
00039 //  Description:
00040 //
00041 //      Digest the description of a particular hardware implementation's
00042 //      scheduling information and generate a c file that describes the
00043 //      features.  The interface is extensively described in si_gen.h.
00044 //
00046 
00047 
00048 
00049 #include <cassert>
00050 #include <cstdio>
00051 #include <unistd.h>
00052 #include <climits>
00053 #include <cstdarg>
00054 #include <cstring>
00055 #include <cstdlib>
00056 
00057 #include <vector>
00058 #include <list>
00059 #include <map>
00060 
00061 using namespace std;
00062 
00063 #include "topcode.h"
00064 #include "targ_isa_properties.h"
00065 #include "targ_isa_subset.h"
00066 #include "targ_isa_operands.h"
00067 
00068 #include "si_gen.h"
00069 
00070 static ISA_SUBSET machine_isa;
00071 
00072 // Parameters:
00073 const int bits_per_long = 32;
00074 const int bits_per_long_long = 64;
00075 const bool use_long_longs = true;       // For now always
00076 const int max_operands = ISA_OPERAND_max_operands;
00077 const int max_results = ISA_OPERAND_max_results;
00078 
00080 int Mod( int i, int j )
00082 //  Mathematically correct integer modulus function.  Unlike C's
00083 //  builtin remainder function, this correctly handles the case where
00084 //  one of the two arguments is negative.
00086 {
00087   int rem;
00088 
00089   if ( j == 0 )
00090     return i;
00091 
00092   rem = i % j;
00093 
00094   if ( rem == 0 )
00095     return 0;
00096 
00097   if ( (i < 0) != (j < 0) )
00098     return j + rem;
00099   else
00100     return rem;
00101 }
00102 
00104 static void Maybe_Print_Comma(FILE* fd, bool& is_first)
00106 // Print a "," to <fd> if <is_first> is false.  Update <is_first> to false.
00107 // Great for printing C initializers.
00109 {
00110   if ( is_first )
00111     is_first = false;
00112   else
00113     fprintf(fd,",");
00114 }
00115 
00118 
00120 class GNAME {
00122 // A generated name for a variable in the generated file.  This supports a
00123 // unified method for naming and getting the names of the objects we generate.
00125 public:
00126   GNAME();
00127   // Generate a unique name.  Don't care about prefix.
00128   GNAME(char* prefix);
00129   // Generate a unique name.  Force a particular prefix.
00130   GNAME(GNAME& other);
00131   // Generate a name that is a copy of <other>.  The name will not be unique.
00132   // Really only useful when <other> is about to be destructed, but we still
00133   // need to refer to it.
00134   char* Gname();
00135   // Return the name.  This is the name under which the object is defined.
00136   char* Addr_Of_Gname();
00137   // Return a pointer to the named object.
00138   void Stub_Out();
00139   // We've decided not to define the object after all but we may still want a
00140   // pointer to it.  After this call, Addr_Of_Gname will return 0.
00141 
00142 private:
00143   char gname[16];       // Where to keep the name.  (This could be more
00144                         //   hi-tech, but why?
00145   bool stubbed;         // Stubbed-out?
00146   static int count;     // For generating the unique names.
00147 };
00148 
00149 int GNAME::count = 0;
00150 
00151 GNAME::GNAME() : stubbed(false) {
00152   sprintf(gname,"&gname%d",count++);
00153 }
00154 
00155 GNAME::GNAME(char* prefix) : stubbed(false) {
00156   assert(strlen(prefix) <= 8);
00157   sprintf(gname,"&%s%d",prefix,count++);
00158 }
00159 
00160 GNAME::GNAME(GNAME& other) : stubbed(false) {
00161   sprintf(gname,"%s",other.gname);
00162 }
00163 
00164 char* GNAME::Gname() {
00165   if (stubbed)
00166     return "0";
00167   else
00168     return gname + 1;
00169 }
00170 
00171 char* GNAME::Addr_Of_Gname() {
00172   if (stubbed)
00173     return "0";
00174   else
00175     return gname;
00176 }
00177 
00178 void GNAME::Stub_Out() {
00179   stubbed = true;
00180 }
00181 
00184 
00186 class RES_WORD {
00188 // A machine word in the resource reservation table.  We use an encoding of
00189 // resources that allows very effecient checking for resources with more than
00190 // a single instance.  Shifted arithmetic is used to check for resource
00191 // availability and to reserve resources.  Each resource has a reserved field
00192 // in the RES_WORD.  The field for a given resource r is log2(count(r)) + 1
00193 // bits wide.  This field is wide enough to hold the count of members of r and
00194 // one extra bit to the left of the count.  This bit is called the "overuse
00195 // bit".  The field is initialized to be 2**field_width - (count + 1).  This
00196 // means that we can add count elements to the field without effecting the
00197 // overuse bit, but adding more elements to the field will set the overuse
00198 // bit.  So we can can check for resource availability of all the resources
00199 // reqpresented in a word with an an add (of the counts required) and a mask
00200 // of the overuse bits.  If the result is non-zero, there is a resource
00201 // overuse (conflict).
00202 //
00203 // In theory this could be any natural sized integer supported on the host
00204 // architecture, but for now we will always use long longs so we don't have to
00205 // worry about generating/checking more than one word/cycle.  This could be
00206 // extended, but it would mean moving the actual resource checking to the
00207 // generated side of the compile time interface (since it would need to know
00208 // the format of the resource reservation table which could change...
00209 
00210 public:
00211   static void Find_Word_Allocate_Field(int width, int count,
00212                                        int &word, int &bit);
00213   // Allocate the first available resource field with <widtn> bits to hold
00214   // <count> resources.  A new resource word is allocated if required.  On
00215   // return, <word> and <bit> hold the word index and bit index of the
00216   // allocated word.
00217 
00218   static void Output_All(FILE* fd);
00219   // Write resource word descriptions to output.
00220 
00221 private:
00222   int bit_inx;                          // Index of first next free bit
00223   const int word_inx;                   // My index in table
00224   long long initializer;                // Value when no resources used
00225   long long overuse_mask;               // Bits to check
00226                                         //   for overuse after adding new
00227                                         //   resources
00228   static list<RES_WORD*> res_words;     // Of all res_words in order
00229   static int count;                     // Of all resource words
00230   static bool has_long_long_word;       // Will we need to use long longs for
00231                                         //   resource words?
00232 
00233   RES_WORD()
00234     : bit_inx(0),
00235       word_inx(count++),
00236       initializer(0),
00237       overuse_mask(0)
00238   {
00239     res_words.push_back(this);
00240   }
00241   bool Allocate_Field(int width, int count, int &word, int &bit);
00242 };
00243 
00244 list<RES_WORD*> RES_WORD::res_words;
00245 int RES_WORD::count = 0;
00246 bool RES_WORD::has_long_long_word = false;
00247 
00249 bool RES_WORD::Allocate_Field(int width, int count, int &word, int &bit)
00251 // Allocate a field <width> bits wide to hold <count> elements.  Return true
00252 // to indicate success with <word> set to my word_inx and <bit> set to the
00253 // the bit index of the start of the field.
00255 {
00256   int new_inx = bit_inx + width;
00257 
00258   if (    use_long_longs && new_inx >= bits_per_long_long
00259        || !use_long_longs && new_inx >= bits_per_long
00260   ) {
00261     return false;
00262   }
00263 
00264   if ( new_inx >= bits_per_long )
00265     has_long_long_word = true;
00266 
00267   word = word_inx;
00268   bit = bit_inx;
00269   initializer |= ((1ll << (width - 1)) - (count + 1)) << bit_inx;
00270   overuse_mask |= (1ll << (width - 1)) << bit_inx;
00271   bit_inx += width;
00272   return true;
00273 }
00274 
00275 void RES_WORD::Find_Word_Allocate_Field(int width, int count,
00276                                         int &word, int &bit)
00277 {
00278   list<RES_WORD*>::iterator rwi;
00279   for ( rwi = res_words.begin(); rwi != res_words.end(); ++rwi ) {
00280     if ( (*rwi)->Allocate_Field(width,count,word,bit) )
00281       return;
00282   }
00283 
00284   RES_WORD* new_res_word = new RES_WORD();
00285 
00286   if ( ! new_res_word->Allocate_Field(width,count,word,bit) ) {
00287     fprintf(stderr,"### Cannot allocate field for %d resources\n",count);
00288     exit(EXIT_FAILURE);
00289   }
00290 }
00291 
00292 void RES_WORD::Output_All(FILE* fd)
00293 {
00294   if ( count == 0 )
00295     fprintf(stderr,"ERROR: no resource words allocated.\n");
00296   else if ( count > 1 ) {
00297     fprintf(stderr,"ERROR: cannot handle %d > 1 long long worth of "
00298                    "resource info.\n",
00299                    count);
00300   }
00301   else {
00302     // Important special case.  We don't need a vector of resource words at all
00303     // and can just use a scalar.
00304     fprintf(fd,"const SI_RRW SI_RRW_initializer = 0x%llx;\n",
00305                res_words.front()->initializer);
00306     fprintf(fd,"const SI_RRW SI_RRW_overuse_mask = 0x%llx;\n",
00307                res_words.front()->overuse_mask);
00308   }
00309 }
00310 
00313 
00315 class RES {
00317 // A machine level resource.
00319 
00320 public:
00321   RES(char *name,int count);
00322   // <name> is used for documentation and debugging.  <count> is the number of
00323   // elements in the class.
00324 
00325   static RES* Get(int id);
00326   // Find and return the resource with the given <id>.
00327 
00328   char* Name() const { return name; }
00329   // Return debugging name.
00330 
00331   char* Addr_Of_Gname() { return gname.Addr_Of_Gname(); }
00332   // Return name of pointer to this resource object (in generated code).
00333 
00334   unsigned int Count() const { return count; }
00335   // How may members?
00336 
00337   int Word() const { return word; }
00338   // Index of word in resource reservation table.  (We have sort of allowed
00339   // there to be more than one, but this is probably not fully working.)
00340 
00341   int Id() const { return id; }
00342   // Unique ID of resource.  Index into table of pointers to resources in the
00343   // generated file.
00344 
00345   unsigned int Shift_Count() const { return shift_count; }
00346   // Bit index of the field in the resource reservation word.
00347 
00348   static void Output_All( FILE* fd );
00349   // Write out all the resource info to <fd>.
00350 
00351 private:
00352   const int count;          // Available per cycle
00353   char* const name;         // For documentation and debugging
00354   GNAME gname;              // Generated symbolic name
00355   int word;                 // Which word in the table?
00356   int field_width;          // How wide the field?
00357   int shift_count;          // How much to shift (starting pos of the low
00358                             //   order bit
00359   const int id;             // Unique numerical identifier
00360   static int total;         // Total number of different RESs (not the the
00361                             //   total of their counts, 1 for each RES)
00362   static map <int,RES*> resources;
00363                             // Map of all resources, ordered by their Id's
00364   void Calculate_Field_Width();
00365   void Calculate_Field_Pos();
00366 
00367   static void Calculate_Fields();
00368   // Calculate fields for all resources.  This can only be done at the very
00369   // end becaue we may not know for sure that there are no multiple resources
00370   // until then.
00371 
00372   void Output( FILE* fd );
00373 };
00374 
00375 int  RES::total = 0;
00376 map <int,RES*> RES::resources;
00377 
00378 RES::RES(char *name, int count)
00379 // constructor maintains list of all resources.
00380   : count(count), name(name), id(total++), gname("resource")
00381 {
00382   resources[id] = this;
00383 }
00384 
00385 RES* RES::Get(int i)
00386 {
00387   assert(total > 0 && i >= 0 && i < total);
00388   return resources[i];
00389 }
00390 
00391 void RES::Output_All( FILE* fd )
00392 {
00393   int i;
00394 
00395   Calculate_Fields();
00396 
00397   for ( i = 0; i < total; ++i )
00398     resources[i]->Output(fd);
00399 
00400   fprintf(fd,"const int SI_resource_count = %d;\n",total);
00401   fprintf(fd,"SI_RESOURCE * const SI_resources[] = {");
00402 
00403   bool is_first = true;
00404   for ( i = 0; i < total; ++i ) {
00405     Maybe_Print_Comma(fd,is_first);
00406     fprintf(fd,"\n  %s",resources[i]->gname.Addr_Of_Gname());
00407   }
00408 
00409   fprintf(fd,"\n};\n");
00410 }
00411 
00413 void RES::Calculate_Field_Width()
00415 //  Calculate the number of bits for my field and set <field_width>
00416 //  accordingly.
00418 {
00419   int i;
00420 
00421   assert(count > 0);
00422 
00423   for ( i = 31 ; i >= 0 ; --i ) {
00424     if ((( (int) 1) << i) & count) {
00425       field_width = i + 2;
00426       break;
00427     }
00428   }
00429 }
00430 
00431 void RES::Calculate_Field_Pos()
00432 {
00433   Calculate_Field_Width();
00434   RES_WORD::Find_Word_Allocate_Field(field_width,count,word,shift_count);
00435 }
00436 
00438 void RES::Calculate_Fields()
00440 //  See interface description.
00441 //  Description
00443 {
00444   for ( int i = 0; i < total; ++i )
00445     resources[i]->Calculate_Field_Pos();
00446 }
00447 
00449 void RES::Output( FILE* fd )
00451 // Allocate my field in the resource reservation table.
00453 {
00454   fprintf(fd,"SI_RESOURCE %s = {\"%s\",%d,%d,%d,%d};\n",
00455              gname.Gname(),
00456              name,
00457              id,
00458              count,
00459              word,
00460              shift_count);
00461 }
00462 
00465 
00467 class RES_REQ {
00469 // A resource requirement.  Represents all the resources needed to perform an
00470 // instruction.
00472 
00473 public:
00474   RES_REQ();
00475 
00476   bool Add_Resource(const RES* res, int cycle);
00477   // Require an additional resource <res> at the given <cycle> relative to
00478   // my start.  Return indication of success.  If adding the resource would
00479   // create an overuse, don't add it and return false.
00480 
00481   void Output(FILE* fd);
00482   // Output my definition and initialization.
00483 
00484   char* Addr_Of_Gname() { return gname.Addr_Of_Gname(); }
00485   // Return name of pointer to me (in generated code).
00486 
00487   char* Gname() { return gname.Gname(); }
00488   // Return my name (in generated code).
00489 
00490   bool Compute_Maybe_Output_II_RES_REQ(int ii, FILE* fd,
00491                                        GNAME*& res_req_gname,
00492                                        GNAME*& resource_id_set_gname );
00493   // When software pipelining, we want to check all the resources for a given
00494   // cycle of the schedule at once.  Because the resource requirement may be
00495   // longer than the II into which we are trying to schedule it, we statically
00496   // combine the resource requirements for each II shorter than the number of
00497   // cycles in the request.  This function does the combining and returns a
00498   // bool to indicate whether the resource requirement can be scheduled in the
00499   // given <ii>.  If it can, the combined a definition and initialization of
00500   // resource requirement is output to <fd> under the GNAME <res_req_gname>.
00501   // A cycle indexed set of resource id's used is also output under the GNAME
00502   // <resource_id_set_gname>.
00503 
00504   int Max_Res_Cycle() { return max_res_cycle; }
00505   // Return the cycle (relative to my start) of the latest resource I
00506   // require.  (Used to know how many II relative resource requirements need
00507   // to be computed/output.)
00508 
00509   void Compute_Output_Resource_Count_Vec(FILE* fd);
00510   // Count up all the resources of each kind that I require (in all my cycles)
00511   // and output a definition and initialization.
00512 
00513   char* Res_Count_Vec_Gname() { return res_count_vec_gname.Gname(); }
00514   // Return name of pointer to start of my resource count vector.
00515 
00516   int Res_Count_Vec_Size() const { return res_count_vec_size; }
00517   // Return length of my resource count vector.
00518 
00519   char* Res_Id_Set_Gname() { return res_id_set_gname.Gname(); }
00520   // Return name of pointer to start of vector of resource id sets, one per
00521   // cycle.
00522 
00523 private:
00524 
00526   class CYCLE_RES {
00528   // A cycle and resource (id) combined into a single object.  Used as a key
00529   // into a map so we can find out how may of the given resources are required
00530   // in the given cycle.
00532 
00533   public:
00534     CYCLE_RES(int cycle, const RES* res) : cycle(cycle), res_id(res->Id()) {}
00535     // Construct the <cycle,res> combination.
00536 
00537     int Cycle() const { return cycle; }
00538     // Return cycle component.
00539 
00540     RES* Res() const { return RES::Get(res_id); }
00541     // Return resource component.
00542 
00543     friend bool operator < (const CYCLE_RES a, const CYCLE_RES b)
00544     // Ordering for map.
00545     {  // I didn't want to put this inline, but mongoose C++ forced me to.
00546       return    a.cycle< b.cycle
00547              || a.cycle == b.cycle && a.res_id < b.res_id;
00548     }
00549 
00550     CYCLE_RES()
00551     // Horrible useless required constructor required by STL map.
00552      : cycle(0), res_id(0)
00553     {  // Also forced inline by mongoose C++.
00554       fprintf(stderr,"### Default initializer for CYCLE_RES"
00555               " shouldn't happen.\n");
00556     }
00557 
00558   private:
00559     const short cycle;
00560     const short res_id;
00561   };
00562 
00563   typedef map < CYCLE_RES,int,less <CYCLE_RES> > CYCLE_RES_COUNT_MAP;
00564   // For keeping track of the number of resources of a given type in a given
00565   // cycle.  <cycle,res> => count
00566 
00567   int max_res_cycle;
00568   // Latest cycle with a resource requirement
00569 
00570   CYCLE_RES_COUNT_MAP cycle_res_count;
00571   // <cycle,res> -> count required
00572 
00573   GNAME gname;
00574   // My symbolic name.
00575 
00576   GNAME res_count_vec_gname;
00577   // Symbolic name of my resource count vector.
00578 
00579   GNAME res_id_set_gname;
00580   // Symbolic name of vector of resource id sets
00581 
00582   int res_count_vec_size;
00583   // How big it is.
00584 
00585   bool Compute_II_RES_REQ(int ii, RES_REQ& ii_res_req);
00586 };
00587 
00588 RES_REQ::RES_REQ()
00589   : max_res_cycle(-1),
00590     gname("res_req")
00591 {}
00592 
00593 bool RES_REQ::Add_Resource(const RES* res, int cycle)
00594 {
00595   assert(cycle >= 0);
00596   if ( cycle > max_res_cycle ) max_res_cycle = cycle;
00597 
00598   CYCLE_RES cr = CYCLE_RES(cycle,res);
00599   int count = cycle_res_count[cr];
00600 
00601   if ( count >= res->Count() )
00602     return false;
00603 
00604   cycle_res_count[cr] = ++count;
00605   return true;
00606 }
00607 
00609 bool RES_REQ::Compute_II_RES_REQ(int ii, RES_REQ& ii_res_req)
00611 //  Compute my <ii> relative resourse requirement info <ii_res_req> and return
00612 //  a bool to indicate whether it is possible to issue me in a loop with <ii>
00613 //  cycles.
00615 {
00616   CYCLE_RES_COUNT_MAP::iterator mi;
00617   for (mi = cycle_res_count.begin(); mi != cycle_res_count.end(); ++mi) {
00618     int cycle = (*mi).first.Cycle();
00619     RES* res = (*mi).first.Res();
00620     int count = (*mi).second;
00621 
00622     for (int i = 0; i < count; ++i) {
00623       if ( ! ii_res_req.Add_Resource(res,Mod(cycle,ii)) )
00624         return false;
00625     }
00626   }
00627 
00628   return true;
00629 }
00630 
00631 bool RES_REQ::Compute_Maybe_Output_II_RES_REQ(int ii, FILE* fd,
00632                                               GNAME*& res_req_gname,
00633                                               GNAME*& res_id_set_gname_ref )
00634 {
00635   RES_REQ ii_res_req;
00636 
00637   if ( ! Compute_II_RES_REQ(ii,ii_res_req) )
00638     return false;
00639 
00640   ii_res_req.Output(fd);
00641   res_req_gname = new GNAME(ii_res_req.gname);
00642   res_id_set_gname_ref = new GNAME(ii_res_req.res_id_set_gname);
00643   return true;
00644 }
00645 
00646 void RES_REQ::Compute_Output_Resource_Count_Vec(FILE* fd)
00647 {
00648   CYCLE_RES_COUNT_MAP::iterator mi;
00649   map<int,int,less<int> > res_inx_count;  // res_id => count
00650 
00651   // Sum up the number of each required
00652   for (mi = cycle_res_count.begin(); mi != cycle_res_count.end(); ++mi) {
00653     RES* res = (*mi).first.Res();
00654     int count = (*mi).second;
00655 
00656     res_inx_count[res->Id()] += count;
00657   }
00658 
00659   res_count_vec_size = res_inx_count.size();
00660 
00661   if ( res_count_vec_size == 0 ) {
00662     res_count_vec_gname.Stub_Out();
00663     return;
00664   }
00665 
00666   // Print it out
00667   fprintf(fd,"static SI_RESOURCE_TOTAL %s[] = {",
00668              res_count_vec_gname.Gname());
00669 
00670   bool is_first = true;
00671   map<int,int,less<int> >::iterator mj;
00672   for (mj = res_inx_count.begin(); mj != res_inx_count.end(); ++mj) {
00673     RES* res = RES::Get((*mj).first);  // You'd think STL would allow
00674     int count = (*mj).second;          // something less ugly!  But no.
00675 
00676     Maybe_Print_Comma(fd,is_first);
00677     fprintf(fd,"\n  {%s,%d} /* %s */",
00678                RES::Get(res->Id())->Addr_Of_Gname(),count,res->Name());
00679   }
00680   fprintf(fd,"\n};\n");
00681 }
00682 
00683 void RES_REQ::Output(FILE* fd)
00684 {
00685   int i;
00686   CYCLE_RES_COUNT_MAP::iterator mi;
00687   vector<unsigned long long> res_vec((size_t) max_res_cycle + 1,0);
00688   vector<unsigned long long> res_used_set((size_t) max_res_cycle + 1,0);
00689 
00690   for (mi = cycle_res_count.begin(); mi != cycle_res_count.end(); ++mi) {
00691     int cycle = (*mi).first.Cycle();  // You'd think this could be abstracted,
00692     RES* res = (*mi).first.Res();     // but I couldn't even explain the
00693     long long  count = (*mi).second;  // the concept to Alex S.
00694 
00695     res_vec[cycle] += count << res->Shift_Count();
00696     res_used_set[cycle] |= 1ll << res->Id();
00697   }
00698 
00699   fprintf(fd,"static const SI_RRW %s[] = {\n  %d",
00700              gname.Gname(),
00701              max_res_cycle + 1);
00702 
00703   for ( i = 0; i <= max_res_cycle; ++i )
00704     fprintf(fd,",\n  0x%llx",res_vec[i]);
00705 
00706   fprintf(fd,"\n};\n");
00707 
00708   if ( max_res_cycle < 0 ) {
00709     res_id_set_gname.Stub_Out();
00710     return;
00711   }
00712 
00713   fprintf(fd,"static const SI_RESOURCE_ID_SET %s[] = {",
00714              res_id_set_gname.Gname());
00715 
00716   bool is_first = true;
00717   for ( i = 0; i <= max_res_cycle; ++i ) {
00718     Maybe_Print_Comma(fd,is_first);
00719     fprintf(fd,"\n  0x%llx",res_used_set[i]);
00720   }
00721 
00722   fprintf(fd,"\n};\n");
00723 }
00724 
00727 
00729 class ISLOT {
00731 // An issue slot.  This is for modeling the horrible beast skewed pipe and we
00732 // hope that it will be useful enough to support experimentation with related
00733 // ideas.
00735 
00736 public:
00737   ISLOT(char* name, int skew, int avail_count);
00738   // <name> is for documentation and debugging.  <skew> gives a latency skew
00739   // instructions issued in me.
00740 
00741   char* Addr_Of_Gname() { return gname.Addr_Of_Gname(); }
00742   // Return pointer to my name in generated.
00743 
00744   static int Count() { return count; }
00745   // How may instructions can issue in me.
00746 
00747   static void Output_All(FILE* fd);
00748   // Output all the issue slots and a vector of pointers to them all.
00749 
00750 private:
00751   char* const name;             // User supplied for documentation & debugging
00752   const int skew;               // Latency skew
00753   const int avail_count;        // How many instructions can happen in it
00754   GNAME gname;                  // Symbolic name in generated
00755   static list <ISLOT*> islots;  // All the created islot
00756   static int count;             // How many issue slots total?
00757 };
00758 
00759 list<ISLOT*> ISLOT::islots;
00760 int ISLOT::count = 0;
00761 
00762 ISLOT::ISLOT(char* name, int skew, int avail_count)
00763   : name(name),
00764     skew(skew),
00765     avail_count(avail_count)
00766 {
00767   islots.push_back(this);
00768   ++count;
00769 }
00770 
00771 void ISLOT::Output_All(FILE* fd)
00772 {
00773   list<ISLOT*>::iterator isi;
00774 
00775   fprintf(fd,"const int SI_issue_slot_count = %d;\n",count);
00776 
00777   for ( isi = islots.begin(); isi != islots.end(); ++isi ) {
00778     ISLOT* islot = *isi;
00779     fprintf(fd,"static SI_ISSUE_SLOT %s = { \"%s\",%d,%d};\n",
00780             islot->gname.Gname(),
00781             islot->name,
00782             islot->skew,
00783             islot->avail_count);
00784   }
00785 
00786   if ( count == 0 )
00787     fprintf(fd,"SI_ISSUE_SLOT * const SI_issue_slots[1] = {0};\n");
00788   else {
00789     fprintf(fd,"SI_ISSUE_SLOT * const SI_issue_slots[%d] = {",count);
00790 
00791     bool is_first = true;
00792     for ( isi = islots.begin(); isi != islots.end(); ++isi ) {
00793       ISLOT* islot = *isi;
00794       Maybe_Print_Comma(fd,is_first);
00795       fprintf(fd,"\n  %s",islot->Addr_Of_Gname());
00796     }
00797 
00798     fprintf(fd,"\n};\n");
00799   }
00800 }
00801 
00804 
00806 class LATENCY_INFO {
00808 // Describes latency information for an instruction group's operands or
00809 // results.
00811 
00812 public:
00813   LATENCY_INFO(int max_elements);
00814   // <max_elements> is the maximum number either of operands or results.
00815 
00816   void Set_Any_Time(int time);
00817   // Any (all) of the operands or results have <time> as access or available
00818   // time.
00819 
00820   void Set_Time(int index, int time);
00821   // <index>'th operand or result has <time> as access or available time.
00822 
00823   void Output(FILE* fd);
00824   // Output latency vector to <fd>.
00825 
00826   char* Gname() { return gname.Gname(); }
00827   // Return name of pointer to me in generated file.
00828 
00829 private:
00830   GNAME gname;                  // Name in generated
00831   const int max_elements;       // Maximum number of operands or results
00832   bool any_time_defined;        // Overriding time defined
00833   int any_time;                 // And here it is
00834   vector<bool> times_defined;   // Times for each operands defined?
00835   vector<int> times;            // And here they are
00836 };
00837 
00838 LATENCY_INFO::LATENCY_INFO(int max_elements)
00839   : gname("latency"),
00840     max_elements(max_elements),
00841     any_time_defined(false),
00842     times_defined(max_elements,false),
00843     times(max_elements)
00844 {}
00845 
00846 void LATENCY_INFO::Set_Any_Time(int time)
00847 {
00848   if ( any_time_defined ) {
00849     fprintf(stderr,"### Warning any_time redefined for %s.  "
00850                    "Was %d.  Is %d\n",
00851                    gname.Gname(),
00852                    any_time,
00853                    time);
00854   }
00855 
00856   any_time_defined = true;
00857   any_time = time;
00858 }
00859 
00860 void LATENCY_INFO::Set_Time(int index, int time)
00861 {
00862   if ( any_time_defined ) {
00863     fprintf(stderr,"### WARNING: %s setting specific time after any time.  "
00864                    "Any %d.  Specific %d\n",
00865                    gname.Gname(),
00866                    any_time,
00867                    time);
00868   }
00869 
00870   assert(index < max_elements);
00871 
00872   if ( times_defined[index] ) {
00873     fprintf(stderr,"### WARNING: Resetting %s time.  "
00874                    "Was %d. Now is %d\n",
00875                    gname.Gname(),
00876                    time,
00877                    times[index]);
00878   }
00879 
00880   times_defined[index] = true;
00881   times[index] = time;
00882 }
00883 
00884 void LATENCY_INFO::Output(FILE* fd)
00885 {
00886   fprintf(fd,"static const mUINT8 %s[] = {",gname.Gname());
00887 
00888     bool is_first = true;
00889     vector<int>::iterator i;
00890     for ( i = times.begin(); i < times.end(); ++i ) {
00891       Maybe_Print_Comma(fd,is_first);
00892       fprintf(fd,"%d",any_time_defined ? any_time : *i);
00893     }
00894 
00895     fprintf(fd,"};\n");
00896 }
00897 
00900 
00902 class INSTRUCTION_GROUP {
00904 // Represents one of the instruction groups, a common piece of scheduling
00905 // information for a set of instructions.
00907 
00908 public:
00909   // These functions correspond exactly with the defined C client interface.
00910   INSTRUCTION_GROUP(char* name);
00911   void Set_Any_Operand_Access_Time(int time);
00912   void Set_Operand_Access_Time(int operand_index, int time);
00913   void Set_Any_Result_Available_Time(int time);
00914   void Set_Result_Available_Time(int result_index, int time);
00915   void Set_Load_Access_Time( int time );
00916   void Set_Last_Issue_Cycle( int time );
00917   void Set_Store_Available_Time( int time );
00918   void Add_Resource_Requirement(const RES* res, int cycle);
00919   void Add_Valid_ISLOT(ISLOT* islot);
00920   void Set_Write_Write_Interlock();
00921 
00922   static void Output_All(FILE* fd);
00923   // Write them all out
00924 
00925   char* Addr_Of_Gname() { return gname.Addr_Of_Gname(); }
00926   // Name of pointer to me in generated file.
00927 
00928 private:
00929   int id;                               // Index in vector of same
00930   GNAME gname;                          // Variable name in generated    
00931   char* const name;                     // User supplied name for documentation
00932   RES_REQ res_requirement;              // Required to issue
00933 
00934   list<ISLOT*> valid_islots;            // If there are any issue slots at all
00935   GNAME islot_vec_gname;                // Variable name of above in generated
00936 
00937   LATENCY_INFO operand_latency_info;    // When operands latch
00938   LATENCY_INFO result_latency_info;     // When results available
00939 
00940   int load_access_time;                 // When loads access memory
00941   int last_issue_cycle;                 // Last issue cycle in simulated insts
00942   int store_available_time;             // When stores make value available in
00943                                         //   memory 
00944 
00945   bool write_write_interlock;           // For simulator
00946 
00947   GNAME ii_res_req_gname;
00948   // Generated name of vector of resource requirements for each II less than
00949   // the total number of cycles in res_requirement (one based).
00950 
00951   GNAME ii_res_id_set_gname;
00952   // Generate name of vector of resource id sets for each II less than
00953   // the total number of cycles in res_requirement (one based).
00954 
00955   unsigned long long bad_iis[2];
00956   // Tells whether it is possible to schedule at all at a given II.  This
00957   // could be a more flexible data structure.  As it is, it is limited to 128
00958   // bad IIs, but I think this will be enough.
00959 
00960   static list<INSTRUCTION_GROUP*> instruction_groups;
00961   // All the defined instruction groups.
00962 
00963   static int count;
00964   // Of all instruction groups.  Used to generate ids.
00965 
00966   int II_Info_Size() { return res_requirement.Max_Res_Cycle(); }
00967   // Latest cycle in which I need a resource
00968 
00969   void Output_II_Info(FILE* fd);
00970   void Output_Latency_Info(FILE* fd);
00971   void Output_Issue_Slot_Info(FILE* fd);
00972   void Output(FILE* fd);
00973 };
00974 
00975 
00976 list<INSTRUCTION_GROUP*> INSTRUCTION_GROUP::instruction_groups;
00977 int INSTRUCTION_GROUP::count = 0;
00978 
00979 INSTRUCTION_GROUP::INSTRUCTION_GROUP(char* name)
00980     : id(count++),
00981       name(name),
00982       operand_latency_info(max_operands),
00983       result_latency_info(max_results),
00984       load_access_time(0),
00985       last_issue_cycle(0),
00986       store_available_time(0),
00987       write_write_interlock(false),
00988       ii_res_req_gname("ii_rr")
00989 {
00990   bad_iis[0] = 0;
00991   bad_iis[1] = 0;
00992   instruction_groups.push_back(this);
00993 }
00994 
00995 void INSTRUCTION_GROUP::Set_Any_Operand_Access_Time(int time)
00996 {
00997   operand_latency_info.Set_Any_Time(time);
00998 }
00999 
01000 void INSTRUCTION_GROUP::Set_Operand_Access_Time(int operand_index, int time)
01001 {
01002   operand_latency_info.Set_Time(operand_index,time);
01003 }
01004 
01005 void INSTRUCTION_GROUP::Set_Any_Result_Available_Time(int time)
01006 {
01007   result_latency_info.Set_Any_Time(time);
01008 }
01009 
01010 void INSTRUCTION_GROUP::Set_Result_Available_Time(int result_index, int time)
01011 {
01012   result_latency_info.Set_Time(result_index,time);
01013 }
01014 
01015 void INSTRUCTION_GROUP::Set_Load_Access_Time( int time )
01016 {
01017   load_access_time = time;
01018 }
01019 
01020 void INSTRUCTION_GROUP::Set_Last_Issue_Cycle( int time )
01021 {
01022   last_issue_cycle = time;
01023 }
01024 
01025 void INSTRUCTION_GROUP::Set_Store_Available_Time( int time )
01026 {
01027   store_available_time = time;
01028 }
01029 
01030 void INSTRUCTION_GROUP::Add_Resource_Requirement(const RES* res, int cycle)
01031 {
01032   if (! res_requirement.Add_Resource(res,cycle)) {
01033     fprintf(stderr,"### ERROR: Impossible resource request for "
01034                     "instruction group %s.\n",
01035                     name);
01036     fprintf(stderr,"###    %s at cycle %d.\n",res->Name(),cycle);
01037   }
01038 }
01039 
01040 void INSTRUCTION_GROUP::Add_Valid_ISLOT(ISLOT* islot)
01041 {
01042   valid_islots.push_back(islot);
01043 }
01044 
01045 void INSTRUCTION_GROUP::Set_Write_Write_Interlock()
01046 {
01047   write_write_interlock = true;
01048 }
01049 
01050 void INSTRUCTION_GROUP::Output_II_Info(FILE* fd)
01051 {
01052   int i;
01053   bool is_first;
01054   const int ii_vec_size = II_Info_Size();
01055   const int max_num_bad_iis = sizeof(bad_iis) * 8;
01056   // We need ii relative information for ii's in the range
01057   // 1..cycle_with_final_res_requirement.  An ii of 0 makes no sense and an II
01058   // enough cycles that the request doesn't need to wrap are the outside bounds.
01059 
01060   if ( ii_vec_size <= 0 ) {
01061     ii_res_req_gname.Stub_Out();
01062     ii_res_id_set_gname.Stub_Out();
01063     return;
01064   }
01065 
01066   vector<GNAME*> ii_res_req_gname_vector(ii_vec_size);
01067   vector<GNAME*> ii_resources_used_gname_vector(ii_vec_size);
01068   vector<bool> ii_can_do_vector(ii_vec_size);
01069 
01070   int greatest_bad_ii = 0;
01071 
01072   for ( i = 0; i < res_requirement.Max_Res_Cycle(); ++i ) {
01073     if ( res_requirement.Compute_Maybe_Output_II_RES_REQ(
01074            i+1,fd,
01075            ii_res_req_gname_vector[i],
01076            ii_resources_used_gname_vector[i])
01077     ) {
01078       ii_can_do_vector[i] = true;
01079     }
01080     else {
01081       ii_can_do_vector[i] = false;
01082       greatest_bad_ii = i;
01083       if ( i > max_num_bad_iis ) {
01084         fprintf(stderr,"### Error: bad II %d > %d.  "
01085                 "Need a more flexible representation.\n",
01086                 i, max_num_bad_iis);
01087       }
01088     }
01089   }
01090 
01091   for ( i = 0; i < sizeof(bad_iis) / sizeof(bad_iis[0]); ++i ) {
01092     bad_iis[i] = 0ULL;
01093   }
01094 
01095   for ( i = 0; i <= greatest_bad_ii; ++i ) {
01096     if ( ! ii_can_do_vector[i] ) {
01097       bad_iis[i / bits_per_long_long] |= (1ULL << (i % bits_per_long_long));
01098     }
01099   }
01100   
01101   // Print vector of pointers to the II relative resource requirements
01102 
01103   fprintf(fd,"static const SI_RR %s[] = {",
01104           ii_res_req_gname.Gname());
01105 
01106   is_first = true;
01107   for ( i = 0; i < ii_vec_size; ++i ) {
01108     Maybe_Print_Comma(fd,is_first);
01109     if ( ii_can_do_vector[i] )
01110       fprintf(fd,"\n  %s",ii_res_req_gname_vector[i]->Gname());
01111     else
01112       fprintf(fd,"\n  0");
01113   }
01114 
01115   fprintf(fd,"\n};\n");
01116 
01117   // Print vector of pointers to the II relative resoruce id sets
01118 
01119   fprintf(fd,"static const SI_RESOURCE_ID_SET * const %s[] = {",
01120           ii_res_id_set_gname.Gname());
01121 
01122   is_first = true;
01123   for ( i = 0; i < ii_vec_size; ++i ) {
01124     Maybe_Print_Comma(fd,is_first);
01125     if ( ii_can_do_vector[i] ) {
01126       fprintf(fd,"\n  %s",
01127               ii_resources_used_gname_vector[i]->Gname());
01128     }
01129     else
01130       fprintf(fd,"\n  0");
01131   }
01132 
01133   fprintf(fd,"\n};\n");
01134 
01135 }
01136 
01137 void INSTRUCTION_GROUP::Output_Latency_Info(FILE* fd)
01138 {
01139   operand_latency_info.Output(fd);
01140   result_latency_info.Output(fd);
01141 }
01142 
01143 void INSTRUCTION_GROUP::Output_Issue_Slot_Info(FILE* fd)
01144 {
01145   if ( valid_islots.size() == 0 ) {
01146 
01147 /* Comment out the warning until the beast skewed support is implemented;
01148  * it's currently a post 7.2 affair.
01149  *
01150  *  if ( ISLOT::Count() > 0 )
01151  *    fprintf(stderr,"### Issue slots defined but none defined for %s\n",name);
01152 */
01153     islot_vec_gname.Stub_Out();
01154     return;
01155   }
01156 
01157   fprintf(fd,"static SI_ISSUE_SLOT * const %s[] = {",islot_vec_gname.Gname());
01158 
01159   bool is_first = true;
01160   list<ISLOT*>::iterator i;
01161   for (i = valid_islots.begin(); i != valid_islots.end(); ++i) {
01162     ISLOT* islot = *i;
01163 
01164     Maybe_Print_Comma(fd,is_first);
01165     fprintf(fd,"\n  %s",islot->Addr_Of_Gname());
01166   }
01167 
01168   fprintf(fd,"\n};\n");
01169 }
01170 
01171 void INSTRUCTION_GROUP::Output(FILE* fd)
01172 {
01173   int i;
01174 
01175   fprintf(fd,"\n/* Instruction group %s */\n",name);
01176   res_requirement.Output(fd);
01177   res_requirement.Compute_Output_Resource_Count_Vec(fd);
01178   Output_II_Info(fd);
01179   Output_Latency_Info(fd);
01180   Output_Issue_Slot_Info(fd);
01181 
01182 
01183   fprintf(fd,"static SI %s = {\n",gname.Gname());
01184   fprintf(fd,"  \"%s\",\n",name);
01185   fprintf(fd,"  %-15d, /* id */\n",id);
01186   fprintf(fd,"  %-15s, /* operand latency */\n",
01187              operand_latency_info.Gname());
01188   fprintf(fd,"  %-15s, /* result latency */\n",
01189              result_latency_info.Gname());
01190   fprintf(fd,"  %-15d, /* load access time */\n",
01191              load_access_time);
01192   fprintf(fd,"  %-15d, /* last issue cycle */\n",
01193              last_issue_cycle);
01194   fprintf(fd,"  %-15d, /* store available time */\n",
01195              store_available_time);
01196   fprintf(fd,"  %-15s, /* resource requirement */\n",
01197              res_requirement.Gname());
01198   fprintf(fd,"  %-15s, /* res id used set vec */\n",
01199              res_requirement.Res_Id_Set_Gname());
01200   fprintf(fd,"  %-15d, /* II info size */\n",
01201              II_Info_Size() >= 0 ? II_Info_Size() : 0);
01202   fprintf(fd,"  %-15s, /* II resource requirement vec */\n",
01203              ii_res_req_gname.Gname());
01204   fprintf(fd,"  %-15s, /* II res id used set vec */\n",
01205              ii_res_id_set_gname.Gname());
01206   fprintf(fd,"  {{");
01207   for ( i = 0; i < sizeof(bad_iis) / sizeof(bad_iis[0]); ++i ) {
01208     fprintf(fd, "0x%llx", bad_iis[i]);
01209     if ( i < sizeof(bad_iis) / sizeof(bad_iis[0]) - 1 ) fprintf(fd, ",");
01210   }
01211   fprintf(fd, "}}    , /* Bad IIs */\n");
01212   fprintf(fd,"  %-15d, /* valid issue slots vec size */\n",
01213              valid_islots.size());
01214   fprintf(fd,"  %-15s, /* valid issue slots vec */\n",
01215              islot_vec_gname.Gname());
01216   fprintf(fd,"  %-15d, /* resource count vec size */\n",
01217              res_requirement.Res_Count_Vec_Size());
01218   fprintf(fd,"  %-15s, /* resource count vec */\n",
01219              res_requirement.Res_Count_Vec_Gname());
01220   fprintf(fd,"  %-15s  /* write-write interlock */\n",
01221              write_write_interlock ? "1" : "0");
01222   fprintf(fd,"};\n");
01223 }
01224 
01225 void INSTRUCTION_GROUP::Output_All(FILE* fd)
01226 {
01227   list<INSTRUCTION_GROUP*>::iterator iig;
01228 
01229   for (iig = instruction_groups.begin();
01230        iig != instruction_groups.end();
01231        ++iig
01232   ) {
01233     (*iig)->Output(fd);
01234   }
01235 
01236   fprintf(fd,"SI * const SI_ID_si[] = {");
01237 
01238   bool is_first = true;
01239   for (iig = instruction_groups.begin();
01240        iig != instruction_groups.end();
01241        ++iig
01242   ) {
01243     Maybe_Print_Comma(fd,is_first);
01244     fprintf(fd,"\n  %s",(*iig)->Addr_Of_Gname());
01245   }
01246 
01247   fprintf(fd,"\n};\n");
01248 
01249   fprintf(fd,"const int SI_ID_count = %d;\n",count);
01250 
01251   fprintf(fd,"\n"); // One extra new line to separate from what follows.
01252 
01253 }
01254 
01257 
01259 class TOP_SCHED_INFO_MAP {
01261 // Keeps track of which TOPs need are in which INSTRUCTION_GROUPs (and thus
01262 // map to which TOP_SCHED_INFOs.
01264 
01265 public:
01266   static void Add_Entry( TOP top, INSTRUCTION_GROUP* ig );
01267   // Add entry to the map.  <top> uses <ig>'s scheduling information.
01268 
01269   static void Output( FILE* fd );
01270   // Write out the map.
01271 
01272   static void Create_Dummies( void );
01273   // Create schedling info for the "dummy" instructions.
01274 
01275 private:
01276   static vector<char*> top_sched_info_ptr_map;  // The map itself.
01277   static vector<bool> top_sched_info_defined;   // Which elements defined
01278 };
01279 
01280 vector<char*> TOP_SCHED_INFO_MAP::top_sched_info_ptr_map(TOP_count,"0");
01281 vector<bool> TOP_SCHED_INFO_MAP::top_sched_info_defined(TOP_count,false);
01282 
01283 void TOP_SCHED_INFO_MAP::Create_Dummies( void )
01284 {
01285   INSTRUCTION_GROUP *dummies = NULL;
01286 
01287   for ( int i = 0; i < TOP_count; ++i ) {
01288     if ( TOP_is_dummy((TOP)i) ) {
01289       if ( !dummies ) {
01290         dummies = new INSTRUCTION_GROUP("Dummy instructions");
01291         dummies->Set_Any_Operand_Access_Time(0);
01292         dummies->Set_Any_Result_Available_Time(0);
01293       }
01294       top_sched_info_ptr_map[i] = dummies->Addr_Of_Gname();
01295     }
01296   }
01297 }
01298 
01299 void TOP_SCHED_INFO_MAP::Add_Entry( TOP top, INSTRUCTION_GROUP* ig )
01300 {
01301   if ( top_sched_info_defined[(int) top] ) {
01302     fprintf(stderr,"### Warning: scheduling information for %s redefined.\n",
01303             TOP_Name(top));
01304   }
01305 
01306   top_sched_info_ptr_map[(int) top] = ig->Addr_Of_Gname();
01307   top_sched_info_defined[(int) top] = true;
01308 }
01309 
01310 void TOP_SCHED_INFO_MAP::Output( FILE* fd )
01311 {
01312   int i;
01313 
01314   fprintf(fd,"SI * const SI_top_si[%d] = {",TOP_count);
01315 
01316   bool err = false;
01317   bool is_first = true;
01318   for ( i = 0; i < TOP_count; ++i ) {
01319     bool isa_member = ISA_SUBSET_Member(machine_isa, (TOP)i);
01320     bool is_dummy = TOP_is_dummy((TOP)i);
01321 
01322     Maybe_Print_Comma(fd,is_first);
01323 
01324     fprintf(fd,"\n  %-10s  /* %s */",top_sched_info_ptr_map[i],
01325                                      TOP_Name((TOP)i));
01326 
01327     if ( top_sched_info_defined[i] ) {
01328       if ( ! isa_member ) {
01329         fprintf(stderr,"### Warning: scheduling info for non-%s ISA opcode %s\n",
01330                        ISA_SUBSET_Name(machine_isa), TOP_Name((TOP)i));
01331       } else if ( is_dummy ) {
01332         fprintf(stderr,"### Warning: scheduling info for dummy opcode %s\n",
01333                        TOP_Name((TOP)i));
01334       }
01335     } else {
01336       if ( isa_member && ! is_dummy ) {  
01337         fprintf(stderr,"### Error: no scheduling info for opcode %s\n",
01338                        TOP_Name((TOP)i));
01339         err = true;
01340       }
01341     }
01342   }
01343   fprintf(fd,"\n};\n");
01344   if (err) exit(EXIT_FAILURE);
01345 }
01346 
01349 
01350 // The client interface functions
01351 
01352 static INSTRUCTION_GROUP* current_instruction_group;
01353 
01354 /*ARGSUSED*/
01355 void Machine(char* name, ISA_SUBSET isa, int argc, char** argv)
01356 {
01357   machine_isa = isa;
01358 
01359   TOP_SCHED_INFO_MAP::Create_Dummies();
01360 }
01361 
01362 RESOURCE RESOURCE_Create(char* name, int count)
01363 {
01364   return new RES(name,count);
01365 }
01366 
01367 ISSUE_SLOT ISSUE_SLOT_Create(char* name, int skew, int count)
01368 {
01369   return new ISLOT(name,skew,count);
01370 }
01371 
01372 void Instruction_Group(char* name,...)
01373 {
01374   va_list ap;
01375   TOP opcode;
01376 
01377   current_instruction_group = new INSTRUCTION_GROUP(name);
01378 
01379   va_start(ap,name);
01380 
01381   while ( (opcode = static_cast<TOP>(va_arg(ap,int))) != TOP_UNDEFINED )
01382     TOP_SCHED_INFO_MAP::Add_Entry(opcode,current_instruction_group);
01383 
01384   va_end(ap);
01385 }
01386 
01387 void Any_Operand_Access_Time( int time )
01388 {
01389   current_instruction_group->Set_Any_Operand_Access_Time(time);
01390 }
01391 
01392 void Operand_Access_Time( int operand_index, int time )
01393 {
01394   current_instruction_group->Set_Operand_Access_Time(operand_index,time);
01395 }
01396 
01397 void Any_Result_Available_Time( int time )
01398 {
01399   current_instruction_group->Set_Any_Result_Available_Time(time);
01400 }
01401 
01402 void Result_Available_Time( int result_index, int time )
01403 {
01404   current_instruction_group->Set_Result_Available_Time(result_index,time);
01405 }
01406 
01407 void Load_Access_Time( int time )
01408 {
01409   current_instruction_group->Set_Load_Access_Time(time);
01410 }
01411 
01412 void Last_Issue_Cycle( int time )
01413 {
01414   current_instruction_group->Set_Last_Issue_Cycle(time);
01415 }
01416 
01417 void Store_Available_Time( int time )
01418 {
01419   current_instruction_group->Set_Store_Available_Time(time);
01420 }
01421 
01422 void Resource_Requirement( RESOURCE resource, int time )
01423 {
01424   current_instruction_group->Add_Resource_Requirement(resource,time);
01425 }
01426 
01427 void Valid_Issue_Slot( ISSUE_SLOT slot )
01428 {
01429   current_instruction_group->Add_Valid_ISLOT(slot);
01430 }
01431 
01432 void Write_Write_Interlock()
01433 {
01434   current_instruction_group->Set_Write_Write_Interlock();
01435 }
01436 
01437 void Machine_Done( char* filename )
01438 {
01439   FILE* fd = fopen(filename,"w");
01440 
01441   if ( fd == NULL ) {
01442     fprintf(stderr,"### Error: couldn't write %s\n",filename);
01443     return;
01444   }
01445 
01446   fprintf(fd,"#include \"ti_si.h\"\n");
01447   RES::Output_All(fd);
01448   RES_WORD::Output_All(fd);
01449   ISLOT::Output_All(fd);
01450   INSTRUCTION_GROUP::Output_All(fd);
01451   TOP_SCHED_INFO_MAP::Output(fd);
01452 
01453   //  Print_End_Boiler_Plate(fd);
01454 
01455   fclose(fd);
01456 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines