Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
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 }