/////////////////////////////////////////////////////////////////////////// // File : soclib_segment_table.h // Date : 08/07/2004 // authors : François Pécheux & Alain Greiner // // Copyright : UPMC - LIP6 // This program is released under the GNU public license // // This object is used to describe the memory mapping and address // decoding scheme. It supports a two level hierarchical interconnect : // All VCI initiators and VCI targets share the same address space. // - Several sub-systems can be interconnected thanks to a VCI ADVANCED // global interconnect that can be either a micro-network, or a global system bus. // - Each sub-system can contain as many targets as the LSB size allows. // They are connected by a VCI ADVANCED local interconnect, that can be // a local bus, or a VCI to VCI bridge such as the TARGET_DEMUX // and INITIATOR_MUX components of the SoCLib library. // // The VCI ADDRESS is structured as follows (three fields): | MSB | LSB | OFFSET | // The MSB bits of the VCI ADDRESS are decoded by the global interconnect // to route a VCI CMD/RSP packet to a given sub-system. // In each sub-system, the LSB bits of the VCI ADDRESS are decoded by the // local interconnect to route the a VCI CMD/RSP packet to the selected target/initiator. // // If the number of bits of the LSB field is zero, a global "flat" interconnect // is used, and both the VCI target index and the VCI initiator index are coded // on 8 bits. // // The segment table is an associative table that is organized as a // list of segments. This table must be built in the system top cell. // // Each segment descriptor contains the following fields: // // - const char *name : segment name // - unsigned int base : base address // - unsigned int size : segment size (in bytes) // - unsigned int globalindex : VCI subsystem index // - unsigned int localindex : VCI target index in the subsystem // - bool uncached : uncached when true // // The constraints on the memory mapping are the following : // // 1/ The system designer must define the number of bits for the address // MSB and LSB fields. Both numbers can be zero. (For example the number // of LSB bits will be zero, in case of a "flat" VCI interconnect). // // 2/ The (MSB | LSB) bits are indexing a "page" in the address space. // Several pages can be mapped to the same VCI target. // // 3/ A segment is allocated to a VCI target, and must be contained in // a single page or in several contiguous pages. // // 4/ Several segments can be mapped to the same VCI target // (thanks to the SOCLIB_VCI_MULTIRAM component) // // 5/ A given page cannot contain two segments that are not // mapped to the same VCI target. // // The segment table is used by most SoCLib components : // // - The constructors of the VCI interconnect components can use it to build // the ROMs implementing the routing tables // - The constructors of all VCI targets use it to implement the segmentation // violation detection mechanism, and allocate the buffers representing // the memory in case of an embedded memory component. // - The constructors of several processors (MIPS, SPARC) use it to build // the ROM implementing the uncached table. /////////////////////////////////////////////////////////////////////////// #ifndef SEGMENT_TABLE_H #define SEGMENT_TABLE_H #include using namespace std; ////////////////////////////////////////////// // SEGMENT_TABLE_ENTRY definition ////////////////////////////////////////////// struct SEGMENT_TABLE_ENTRY { private: const char *name; unsigned int base; unsigned int size; unsigned int globalTarget; unsigned int localTarget; bool uncached ; //-----[ SIM2OS - begin ]----------------------------------------- void * addr_alloc; //-----[ SIM2OS - end ]----------------------------------------- public: // constructor SEGMENT_TABLE_ENTRY(const char *nm , unsigned int ba , unsigned int sz , unsigned int glt, unsigned int lct, bool unc ) { name=nm; base=ba; size=sz; globalTarget=glt; localTarget=lct; uncached=unc; //-----[ SIM2OS - begin ]----------------------------------------- addr_alloc = (void *) 0; //-----[ SIM2OS - end ]----------------------------------------- }; // end constructor // basic methods void print() { printf("segment : %s , base = %.8x , size = %.8x , Global target = %d , Local Target = %d , unc = %d, addr_alloc : %.8x\n", name, base, size, globalTarget, localTarget, uncached, (unsigned int) addr_alloc); }; const char *getName() { return name; }; unsigned int getBase() { return base; }; unsigned int getSize() { return size; }; unsigned int getGlobalTarget() { return globalTarget; }; unsigned int getLocalTarget() { return localTarget; }; bool getUncached() { return uncached; }; //-----[ SIM2OS - begin ]----------------------------------------- void * getAddrAlloc() { return addr_alloc; } void setAddrAlloc (void * addr) { addr_alloc = addr; } //-----[ SIM2OS - end ]----------------------------------------- };// end struct SEGMENT_TABLE_ENTRY ////////////////////////////////////////////////////////// // SegmentTable definition ////////////////////////////////////////////////////////// using namespace std; struct SOCLIB_SEGMENT_TABLE { private : std::list segList; int MSBNumber; int LSBNumber; unsigned int defaultTargetGlobalIndex; unsigned int defaultTargetLocalIndex; bool MSBNumberCalled; bool defaultTargetCalled; bool LSBNumberCalled; public : // CONSTRUCTOR SOCLIB_SEGMENT_TABLE() { MSBNumberCalled=false; LSBNumberCalled=false; defaultTargetCalled=false; }; // end constructor // BASIC METHODS void setMSBNumber (int number) { if ((number<0)||(number>16)) { cerr << "ERROR in the Segment Table :" << endl ; cerr << "MSB number must be in the [0..16] range !" << endl ; //sc_stop(); } MSBNumberCalled=true; MSBNumber=number; }; void setLSBNumber (int number) { if ((number<0)||(number>16)) { cerr << "ERROR in the Segment Table :" << endl ; cerr << "LSB number must be in the [0..16] range !" << endl ; //sc_stop(); } LSBNumberCalled=true; LSBNumber=number; }; int getMSBNumber() { return MSBNumber; }; int getLSBNumber() { return LSBNumber; }; void setDefaultTarget (int _defTargetGlobalIndex , int _defTargetLocalIndex) { defaultTargetCalled=true; defaultTargetGlobalIndex=_defTargetGlobalIndex; defaultTargetLocalIndex=_defTargetLocalIndex; }; int getdefaultTargetGlobalIndex() { return defaultTargetGlobalIndex; }; int getdefaultTargetLocalIndex() { return defaultTargetLocalIndex; }; void addSegment(const char *nm, unsigned int ba, unsigned int sz, unsigned int glt, unsigned int lct, bool unc) { SEGMENT_TABLE_ENTRY *seg=new SEGMENT_TABLE_ENTRY(nm,ba,sz,glt,lct,unc); segList.push_back(*seg); delete seg; }; //-----[ SIM2OS - begin ]----------------------------------------- void setAddrAlloc(unsigned int ba , void * addr) { std::list::iterator segIterator; // Scan of all list for (segIterator = segList.begin() ; segIterator != segList.end() ; ++segIterator) { // Find a entry match with number of base // NOTE : The memory is shared, also we can't have 2 segment with the same base if (ba == (*segIterator).getBase ()) { (*segIterator).setAddrAlloc(addr); } } }; void * getAddrAlloc(unsigned int addr) { std::list::iterator segIterator; // Scan of all list for (segIterator = segList.begin() ; segIterator != segList.end() ; ++segIterator) { unsigned int addr_min = (*segIterator).getBase (); unsigned int addr_max = addr_min + (*segIterator).getSize (); if ((addr >= addr_min) && (addr <= addr_max)) { unsigned int offset = (addr-addr_min); return (void*)((unsigned int)(*segIterator).getAddrAlloc() + offset); } } return NULL; } //-----[ SIM2OS - end ]----------------------------------------- void print() { cout << "\n SEGMENT_TABLE\n\n" ; std::list::iterator iter; for (iter = segList.begin() ; iter != segList.end() ; ++iter) { (*iter).print(); } cout << "\n" ; } void printMSBRoutingTable() { cout << "\n MSB ROUTING_TABLE\n\n" ; int size = 1 << MSBNumber+LSBNumber; unsigned int *tab = new unsigned int[size]; initRoutingTable(tab); for(int index = 0 ; index < size ; index++) { if (tab[index]!=0xFFFFFFFF){ printf("TAB[%x] = %d\n", index, tab[index]); } } cout << "\n" ; }; void printLSBRoutingTable(int glt) { printf( "\n LSB_ROUTING_TABLE OF GLOBAL TARGET :%d \n\n", glt ); int size = 1 << MSBNumber+LSBNumber; unsigned int *tab = new unsigned int[size]; initLocalRoutingTable(tab,glt); for(int index = 0 ; index < size ; index++) { if (tab[index]!=0xFFFFFFFF){ printf("TAB[%d] = %d\n", index, tab[index]); } } cout << "\n" ; }; void initRoutingTable(unsigned int* tab) { if (MSBNumberCalled==false) { cerr << "ERROR in initMSBRoutingTable:" << endl ; cerr << "MSB number has not been defined !" << endl ; //sc_stop(); } if (LSBNumberCalled==false) { cout << "WARNING in initMSBRoutingTable:" << endl ; cout << "LSB number has not been defined !" << endl ; cout << "it is set to 0" << endl ; LSBNumberCalled=true; LSBNumber=0; } if (defaultTargetCalled==false) { cerr << "ERROR in initMSBRoutingTable:" << endl ; cerr << "Default Target has not been defined!" << endl ; //sc_stop(); } int RoutingTableSize = 1 << MSBNumber+LSBNumber; int PageSize = 1 << (32 - MSBNumber - LSBNumber); // The 0xFFFFFFFF value means "not allocated" for (int i=0 ; i < RoutingTableSize ; i++) { tab[i] = 0xFFFFFFFF; } // printf ( " tableau rempli de 0xFFFFFFFF \n"); // loop on the segment list std::list::iterator seg; for (seg = segList.begin() ; seg != segList.end() ; ++seg) { const char *name = (*seg).getName(); unsigned int base = (*seg).getBase(); unsigned int size = (*seg).getSize(); unsigned int globalTarget = (*seg).getGlobalTarget(); unsigned int page = base >> (32-MSBNumber - LSBNumber) ; for (int x = (int) size ; x > 0 ; x = x - PageSize) { if(tab[page] != 0xFFFFFFFF) { // printf("\n page n° %x can not be added to cluster %x because it is already allocated to %x\n",page,globalTarget,tab[page]); cerr << "Error in initMSBRoutingTable:" << endl ; cerr << "Segment " << name << " allocated to VCI target " << globalTarget << endl; cerr << "overlap another segment... or is in the same page" << endl; cerr << "as another segment allocated to another VCI target" << endl; //sc_stop(); } else { tab[page]=globalTarget; // printf("\n page n° %x allocated to cluster °%x i.e %s \n",page,tab[page],name); } page = page + 1; } // end for x } // end for seg // Default target for (int i=0 ; i < RoutingTableSize ; i++) { if(tab[i] == 0xFFFFFFFF) tab[i] = defaultTargetGlobalIndex; } }; // end initRoutingTable() //////////////////////////////////////////////////////////////// // initGlobalRoutingTable() // This method can be used by any global VCI interconnect. // It initializes the routing table that implements // the VCI address MSB bits decoding ROM. // - The argument is a pointer to the int table that // has been allocated by the constructor of the // VCI interconnect component. // - Each entry contains a VCI target global index. // The VCI local Target index is not used here //////////////////////////////////////////////////////////////// void initGlobalRoutingTable(unsigned int* tab) { if (MSBNumberCalled==false) { cerr << "ERROR in initMSBRoutingTable:" << endl ; cerr << "MSB number has not been defined !" << endl ; //sc_stop(); } if (defaultTargetCalled==false) { cerr << "ERROR in initMSBRoutingTable:" << endl ; cerr << "Default Target has not been defined!" << endl ; //sc_stop(); } int RoutingTableSize = 1 << MSBNumber; int PageSize = 1 << (32 - MSBNumber); // The 0xFFFFFFFF value means "not allocated" for (int i=0 ; i < RoutingTableSize ; i++) { tab[i] = 0xFFFFFFFF; } // printf ( " tableau rempli de 0xFFFFFFFF \n"); // loop on the segment list std::list::iterator seg; for (seg = segList.begin() ; seg != segList.end() ; ++seg) { const char *name = (*seg).getName(); unsigned int base = (*seg).getBase(); unsigned int size = (*seg).getSize(); unsigned int globalTarget = (*seg).getGlobalTarget(); unsigned int page = base >> (32-MSBNumber) ; for (int x = (int) size ; x > 0 ; x = x - PageSize) { if(tab[page] != 0xFFFFFFFF) { // printf("\n page n° %x can not be added to cluster %x because it is already allocated to %x\n",page,globalTarget,tab[page]); cerr << "Error in initGlobalRoutingTable:" << endl ; cerr << "Segment " << name << " allocated to VCI target " << globalTarget << endl; cerr << "overlap another segment... or is in the same page" << endl; cerr << "as another segment allocated to another VCI target" << endl; //sc_stop(); } else { tab[page]=globalTarget; // printf("\n page n° %x allocated to cluster °%x i.e %s \n",page,tab[page],name); } page = page + 1; } // end for x } // end for seg // Default target for (int i=0 ; i < RoutingTableSize ; i++) { if(tab[i] == 0xFFFFFFFF) tab[i] = defaultTargetGlobalIndex; } }; // end initGlobalRoutingTable() //////////////////////////////////////////////////////////////// // initLocalRoutingTable() // This method can be used by the local VCI interconnect. // It initializes the routing table that implements // the VCI address LSB bits decoding ROM. // - The argument is a pointer to the char table that // has been allocated by the constructor of the local // VCI interconnect component. // - Each entry contains a VCI target local index as well as a global index . // - This method needs a parameter : the global index of the subsystem , // because it only fills the pages corresponding to a segment in this subsystem // other pages are adressed to the Default Target //////////////////////////////////////////////////////////////// void initLocalRoutingTable(unsigned int* tab, unsigned int cluster) { if (MSBNumberCalled==false) { cerr << "ERROR in initLocalRoutingTable:" << endl ; cerr << "MSB number has not been defined !" << endl ; //sc_stop(); } if (defaultTargetCalled==false) { cerr << "ERROR in initLocalRoutingTable:" << endl ; cerr << "Default Target has not been defined!" << endl ; //sc_stop(); } int RoutingTableSize = 1 << MSBNumber+LSBNumber; int PageSize = 1 << (32 - MSBNumber - LSBNumber ); // The 0xFF value means "not allocated" for (int i=0 ; i < RoutingTableSize ; i++) { tab[i] = 0xFF; } // printf ( " Local routing table cluster %x: tableau rempli de 0xFF \n",cluster); // loop on the segment list std::list::iterator seg; for (seg = segList.begin() ; seg != segList.end() ; ++seg) { const char *name = (*seg).getName(); unsigned int base = (*seg).getBase(); unsigned int size = (*seg).getSize(); unsigned int localTarget = (*seg).getLocalTarget(); unsigned int globalTarget = (*seg).getGlobalTarget(); unsigned int page = base >> (32 - MSBNumber - LSBNumber) ; for (int x = (int) size ; x > 0 ; x = x - PageSize) { if(tab[page] != 0xFF) { // printf("\n page n° %x ne peut etre adressée à target n°%x car elle est allouée à %x \n",page,localTarget,tab[page]); cerr << "Error in initLocalRoutingTable:" << endl ; cerr << "Segment " << name << " allocated to VCI target " << localTarget << endl; cerr << "overlap another segment... or is in the same page" << endl; cerr << "as another segment allocated to another VCI target" << endl; //sc_stop(); } else { if (globalTarget==cluster){ tab[page] = localTarget; // printf(" page n° %x adressée à target n°%x dans cluster %x i.e %s \n",page,tab[page],cluster,name); } page = page + 1; } } } // end loop segment list for (int i=0 ; i < RoutingTableSize ; i++) { if ((tab[i]==0xFF) && (defaultTargetGlobalIndex==cluster)) tab[i]=defaultTargetLocalIndex; } }; // end initLocalRoutingTable() ////////////////////////////////////////////////////////////// // getSegmentList() // returns the list of all segments // allocated to a given VCI target. // This method tests both the local and global VCI target index ////////////////////////////////////////////////////////////// std::list getSegmentList(unsigned int globalIndex,unsigned int localIndex){ std::list targetlist; std::list::iterator segIterator; unsigned int localTarget; unsigned int globalTarget; for (segIterator = segList.begin() ; segIterator != segList.end() ; ++segIterator) { localTarget=(*segIterator).getLocalTarget(); globalTarget=(*segIterator).getGlobalTarget(); if ((localTarget==localIndex)&&(globalTarget==globalIndex)){ targetlist.push_back(*segIterator); } } return(targetlist); }; // end getSegmentList() //////////////////////////////////////////////////// // function getTotalsegmentList // used to get the whole segmentlist /////////////////////////////////////////////////// std::list getTotalSegmentList() { return(segList); }; // end getSegmentList() //////////////////////////////////////////////////////////////// // initUncachedTable() // This method can be used by any SoCLib processor. // It initializes an "Uncached Table" that implements // the address MSB bits decoding ROM. // - The argument is a pointer to the bool table that // has been allocated by the constructor of the processor. // - Each ROM entry contains a boolean that is true when // the adress Ris to an uncached segment. ///////////////////////////////////////////////////////////////: void initUncachedTable(bool* tab) { if ((MSBNumberCalled==false)||(LSBNumberCalled==false)) { cerr << "ERROR in initUncachedTable:" << endl ; cerr << "MSB or LSB number has not been defined !" << endl ; //sc_stop(); } int UncachedTableSize = 1 << (MSBNumber+LSBNumber); int PageSize = 1 << (32 - (MSBNumber + LSBNumber)); for (int i=0 ; i < UncachedTableSize ; i++) { tab[i] = true; } std::list::iterator iter; for ( iter = segList.begin() ; iter != segList.end() ; ++iter) { unsigned int base = (*iter).getBase(); unsigned int size = (*iter).getSize(); bool uncached = (*iter).getUncached(); unsigned int page_index = base >> (32-((MSBNumber + LSBNumber))) ; for (int x = (int) size ; x > 0 ; x = x - PageSize) { tab[page_index] = uncached; page_index = page_index + 1; } } // end for segment list }; // end initUncachedTable() }; // end struct SOCLIB_SEGMENT_TABLE #endif