Generic hardware access library
/home/cschwick/hal/generic/src/common/VME64xCrate.cc
Go to the documentation of this file.
00001 #include "hal/VME64xCrate.hh"
00002 #include <sstream>
00003 #include <iomanip>
00004 #include <list>
00005 
00006 HAL::VME64xCrate::VME64xCrate( HAL::VMEBusAdapterInterface& busAdapter,
00007                                HAL::AddressTableContainerInterface& addressTableContainer,
00008                                HAL::ModuleMapperInterface& moduleMapper) 
00009   throw( HAL::HardwareProblemException,
00010          HAL::IllegalValueException,
00011          HAL::UnsupportedException)
00012   : mapped_(false),
00013     busAdapter_ ( busAdapter ),
00014     addressTableContainer_( addressTableContainer ),
00015     moduleMapper_( moduleMapper ),
00016     vmeConfigSpaceHandler_( busAdapter_ ),
00017     slotPtrVector_(MAX_NUMBER_OF_SLOTS) {
00018   
00019   // Set default values for all pointers (this is used later in the 
00020   // function which populates the slots with plug and play modules: The 
00021   // plug and play algorithm is only tried in cases for which the pointer
00022   // to the slot Object is NULL.
00023   for ( int i=0; i<MAX_NUMBER_OF_SLOTS; i++ ) {
00024     slotPtrVector_[i] = (HAL::VMESlot*)0;
00025   }
00026   
00027   configurePlugAndPlay();
00028 }
00029 
00030 HAL::VME64xCrate::VME64xCrate( HAL::VMEBusAdapterInterface& busAdapter,
00031                                HAL::AddressTableContainerInterface& addressTableContainer,
00032                                HAL::ModuleMapperInterface& moduleMapper, 
00033                                const HAL::StaticVMEConfiguration& staticConfiguration )
00034   throw( HAL::HardwareProblemException,
00035          HAL::IllegalValueException,
00036          HAL::UnsupportedException )
00037   : mapped_(false),
00038     busAdapter_ ( busAdapter ),
00039     addressTableContainer_( addressTableContainer ),
00040     moduleMapper_( moduleMapper ),
00041     vmeConfigSpaceHandler_( busAdapter_ ),
00042     slotPtrVector_(MAX_NUMBER_OF_SLOTS) {
00043   
00044   // Set default values for all pointers (this is used later in the 
00045   // function which populates the slots with plug and play modules: The 
00046   // plug and play algorithm is only tried in cases for which no static
00047   // configuration has been given. This allows to inhibit the plug and 
00048   // play mechanism for not correctly working modules by giving a static
00049   // configuration for the module. The initialization in addition allows 
00050   // to check that there are not two items in the static configuration
00051   // for the same slot.
00052   for ( int i=0; i<MAX_NUMBER_OF_SLOTS; i++ ) {
00053     slotPtrVector_[i] = (HAL::VMESlot*)0;
00054   }
00055   
00056   // Evaluate the static Configuration and populate the slots
00057   // which contain static VME configuration items.
00058   populateWithStaticConfiguration(staticConfiguration);
00059 
00060   configurePlugAndPlay();
00061 }
00062 
00063 void HAL::VME64xCrate::configurePlugAndPlay() 
00064   throw( HAL::IllegalValueException,
00065          HAL::UnsupportedException ) {
00066   // check Amnesia address first
00067   if ( vmeConfigSpaceHandler_.containsVME64xModule( 0x1e ) ) {
00068     std::stringstream text;
00069     text << "Module at Amnesia address 0x1e found. Correct the hardware error first"
00070          << std::ends;
00071     throw( HAL::HardwareProblemException( text.str() ) );
00072   }
00073 
00074   // Populate the slots which contain plug and play modules. Afterwards there is 
00075   // a (poosible empty) HAL::VMESlot object for every possible slot.
00076   populateWithPlugAndPlay();
00077 
00078   // Build the memory Map of the crate:
00079   mapCrate();
00080 
00081   // Finally enable the VME64xModules
00082   enablePlugAndPlayModules();
00083 
00084   // sort the list of occupied address space
00085   occupiedItemList_.sort( MappedItemSorter() );
00086 }
00087 
00088 HAL::VMEDevice* HAL::VME64xCrate::getVMEDevice( uint32_t slotId ) const 
00089   throw ( HAL::IllegalOperationException,
00090           HAL::IllegalValueException,
00091           HAL::UnsupportedException,
00092           HAL::BusAdapterException,
00093           HAL::NoSuchItemException ) {
00094   if (slotPtrVector_[slotId]->getContents() != SlotContents(EMPTY) ) {
00095     return slotPtrVector_[slotId]->getVMEDevice();
00096   } 
00097   return (HAL::VMEDevice*)0;
00098 } 
00099 
00100 
00101 HAL::VMESlot* HAL::VME64xCrate::getVMESlot( uint32_t slotId ) const 
00102   throw (HAL::IllegalValueException) {
00103   if ( slotId > MAX_NUMBER_OF_SLOTS ) {
00104     std::stringstream text;
00105     text << "Illegal slot Id : " << std::dec << slotId
00106          << "  (must be less than " << MAX_NUMBER_OF_SLOTS << ")"
00107          << "\n    (HAL::VME64xCrate::getVMESlot)" << std::ends;
00108     throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00109   }
00110   return slotPtrVector_[ slotId ];
00111 }
00112 
00113 
00114 void 
00115 HAL::VME64xCrate::populateWithStaticConfiguration( const HAL::StaticVMEConfiguration& staticConfiguration ) 
00116   throw( HAL::IllegalValueException ) {
00117   HAL::VMESlot *newSlotPtr;
00118   std::list< HAL::StaticVMEItem* >::const_iterator it;
00119   for ( it = staticConfiguration.getListBegin();
00120         it != staticConfiguration.getListEnd();
00121         it++ ) {
00122     newSlotPtr = new HAL::VMESlot( *it,
00123                                    &busAdapter_,
00124                                    addressTableContainer_,
00125                                    moduleMapper_ );
00126     // put the slot in the vector
00127     uint32_t slotId = (*it)->getSlotId();
00128     if ( slotPtrVector_[ slotId ] ) {
00129       std::stringstream text;
00130       text << "Static configuration contains more than one entry for slot number"
00131            << std::dec << slotId 
00132            << "\n    (HAL::VME64xCrate::populateWithStaticConfiguration)" << std::ends;
00133       throw( HAL::IllegalValueException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00134     }
00135     slotPtrVector_[ slotId ] = newSlotPtr;
00136   }
00137 }
00138 
00139 
00140 // only populate slots for which no static configuration has been given.
00141 // This enables to give the configuration for not correctly designed modules 
00142 // by hand. This method makes sure that there is a HAL::VMESlot object for each
00143 // possible slot (it might be empty though)
00144 void HAL::VME64xCrate::populateWithPlugAndPlay()
00145   throw ( HAL::IllegalValueException,
00146           HAL::UnsupportedException ) {
00147 
00148   HAL::VMESlot *newSlotPtr;
00149 
00150   for ( int iSlot = 0; iSlot < MAX_NUMBER_OF_SLOTS; iSlot++ ) {
00151     if ( ! slotPtrVector_[ iSlot ] ) {
00152       newSlotPtr = new HAL::VMESlot( iSlot, 
00153                                 &vmeConfigSpaceHandler_, 
00154                                 addressTableContainer_,
00155                                 moduleMapper_ );
00156       slotPtrVector_[iSlot] = newSlotPtr;
00157     }
00158   }
00159 }
00160 
00161 void HAL::VME64xCrate::getAllWindows() {
00162   std::vector< HAL::VMESlot* >::const_iterator it;
00163   for ( it = slotPtrVector_.begin(); it != slotPtrVector_.end(); it++ ) {
00164     std::list< HAL::VME64xFunction* > functions = (*it)->getImplementedFunctions();
00165     std::list< HAL::VME64xFunction* >::iterator funcIt;
00166     for( funcIt = functions.begin(); funcIt != functions.end(); funcIt++ ) {
00167       std::list<HAL::VME64xMappedWindow*> funcVectors = (*funcIt)->getMappedWindowPtrList();
00168       windowList_.insert( windowList_.end(), funcVectors.begin(), funcVectors.end() );
00169     }
00170   }
00171   WindowSorter sortFunctor;
00172   windowList_.sort(sortFunctor);
00173   makeOccupiedList();
00174 }
00175 
00176 // in principle one could map the A32 A24 A16 address spaces that they 
00177 // overlap. But care should be taken since this could conflict with 
00178 // standard vme modules which could respond to various address modifiers.
00179 // So the most stupid but most save algorithm is to first detemine
00180 // where the standard vme modules are and block the taken address space for
00181 // all AMs. Then the VME64x modules can be mapped around them.
00182 // 
00183 void HAL::VME64xCrate::mapCrate() {
00184   // preparation: get a list of all windows mapped or to be mapped. 
00185   // sort this list according to the requested address-space.
00186   // then fill the occupiedItemList_ with those windows which belong
00187   // to standard VME modules. This is done in one function:
00188   getAllWindows( );
00189   // initialize constants:
00190   uint32_t A32Base = 0x00000000;
00191   uint32_t A24Base = 0x1000000;
00192   uint32_t A16Base = 0x10000;
00193   uint32_t A32Min = 0x1000000;
00194   uint32_t A24Min = 0x10000;
00195   uint32_t A16Min = 0x0;
00196   
00197   // loop over all windows starting with the ones which need most memory:
00198   // independently map the three address spaces
00199   // Static windoes are not mapped since they respond with false to all
00200   // the canAxx() requests.
00201   std::list< HAL::VME64xMappedWindow * >::reverse_iterator winIt;
00202   for ( winIt = windowList_.rbegin(); winIt != windowList_.rend(); winIt++ ) {
00203     if ( (*winIt)->canA32() ) {
00204       mapWindow( *winIt, A32Base, A32Min );
00205     } else if( (*winIt)->canA24() ) {
00206       mapWindow( *winIt, A24Base, A24Min );
00207     } else if( (*winIt)->canA16() ) {
00208       mapWindow( *winIt, A16Base, A16Min );
00209     }
00210   }
00211   mapped_ = true;
00212 }
00213 
00214 void HAL::VME64xCrate::mapWindow( HAL::VME64xMappedWindow* windowPtr, 
00215                                   uint32_t base, 
00216                                   uint32_t baseMin ) {
00217   uint32_t rank = windowPtr->getAddressRank();
00218   uint32_t space = 1 << rank;
00219   bool mapped = false;
00220 
00221   // simulate a 33rd bit in the address in order to get rid of problems in case of A32: 
00222   bool bit33 = true;
00223   while ( (!mapped) && ((base > space) || bit33)  && ((base - space) > baseMin) ) {
00224     base = base - space;
00225     if( ! isOccupied( base, space, bit33) ) {
00226       MappedItem *item = new MappedItem();
00227       item->baseAddress = base;
00228       item->startAddress = base;
00229       item->endAddress = base + space - 1;
00230       item->windowPtr = windowPtr;
00231       item->configured = true;
00232       occupiedItemList_.push_back( item );
00233       uint32_t am = windowPtr->getSortedAMCAPList().front();
00234       windowPtr->setADER( base, am);
00235       mapped = true;
00236     }
00237     bit33 = false;
00238   }
00239   if ( ! mapped ) {
00240     notMappedList_.push_back( windowPtr );
00241   }
00242 }
00243 
00248 bool HAL::VME64xCrate::isOccupied( uint32_t base, uint32_t space, bool bit33 ) {
00249   std::list< struct MappedItem * >::const_iterator it ;
00250   // as soon as an item is found which overlaps with the proposed base address 
00251   // return true.
00252   for ( it=occupiedItemList_.begin(); it != occupiedItemList_.end(); it++ ) {
00253     //    cout << hex << base << " " << space << " " << bit33 << " " << (*it)->startAddress << " " << (*it)->endAddress << endl;
00254 
00255     // check for overlap: 1) check if the start address (=base)         is in the range between the start- and endaddress of item
00256     //                    2) check if the end   address (=base + space) is in the range between the start- and endaddress of item
00257     if ( ((base <= (*it)->endAddress ) && base >= (*it)->startAddress ) ||
00258          (((base + space - 1) <= (*it)->endAddress ) && (base + space - 1) >= (*it)->startAddress ) ) {
00259       //    if ( ((base <= (*it)->endAddress || bit33) && base >= (*it)->startAddress ) ||
00260       //         (((base + space - 1) <= (*it)->endAddress || bit33) && (base + space - 1) >= (*it)->startAddress ) ) {
00261       //cout << "true" << endl;
00262       return true;
00263     }
00264   }
00265   //cout << "false" << endl;
00266   return false;
00267 }
00268 
00269 // occupied windows are removed from the windowList_. 
00270 // This is important in case that a crate is tried to be mapped
00271 // more than once. (E.g. by different applications or processes)
00272 void HAL::VME64xCrate::makeOccupiedList() {
00273   std::list< HAL::VME64xMappedWindow* > newList;
00274   std::list< HAL::VME64xMappedWindow* >::iterator it;
00275   struct MappedItem* item;
00276   for ( it = windowList_.begin(); it!= windowList_.end(); it++ ) {
00277     if ( (*it)->isConfigured() ) {
00278       item = new MappedItem();
00279       item->baseAddress = (*it)->getBaseaddress();
00280       item->startAddress = (*it)->getBaseaddress();
00281       item->endAddress = item->baseAddress + (1 << (*it)->getAddressRank()) - 1;
00282       item->windowPtr = (*it);
00283       item->configured = true;
00284       occupiedItemList_.push_back( item );
00285     } else {
00286       newList.push_back( *it );
00287     }
00288   }
00289   windowList_ = newList;
00290 }
00291 
00292 void HAL::VME64xCrate::enablePlugAndPlayModules() 
00293   throw (HAL::IllegalOperationException ) {
00294   if ( ! mapped_ ) {
00295     std::stringstream text;
00296     text << "The crate has not yet mapped the memory space and therefore the\n"
00297          << "modules cannot be enabled!\n    (HAL::VME64xCrate::enablePlugAndPlayModules)" 
00298          << std::ends;
00299     throw( HAL::IllegalOperationException( text.str(), __FILE__, __LINE__, __FUNCTION__ ) );
00300   }
00301   std::vector< HAL::VMESlot* >::iterator it;
00302   for ( it=slotPtrVector_.begin(); it != slotPtrVector_.end(); it++ ) {
00303     if ((*it)->getContents() == (SlotContents)VME64x ) {
00304       vmeConfigSpaceHandler_.enableVME64xModule( (*it)->getSlotId() );
00305     }
00306   }
00307 }
00308 
00309 void HAL::VME64xCrate::printAddressMap( std::ostream& out ) const {
00310   if ( notMappedList_.size() > 0 ) {
00311     out << "\n\nWARNING: the following items could not be mapped\n";
00312     std::list< const HAL::VME64xMappedWindow* >::const_iterator itN;
00313     for( itN = notMappedList_.begin(); itN != notMappedList_.end(); itN++ ) {
00314       out << "    slot Id     : " << (*itN)->getSlotId()
00315           << "    function Id : " << (*itN)->getFunctionId()
00316           << "    map Id      : " << (*itN)->getMappedWindowId();
00317     }
00318   }
00319 
00320   out << "\n\nList of mapped items (ordered by address space size) :\n\n";
00321   std::list< struct MappedItem * >::const_iterator itM;
00322   for ( itM = occupiedItemList_.begin(); itM!= occupiedItemList_.end(); itM++ ) {
00323     uint32_t slotId     = (*itM)->windowPtr->getSlotId();
00324     uint32_t functionId = (*itM)->windowPtr->getFunctionId();
00325     uint32_t mapId      = (*itM)->windowPtr->getMappedWindowId();
00326     uint32_t AM         = (*itM)->windowPtr->getAM();
00327     std::string serialNumber = slotPtrVector_[ slotId ]->getSerialNumber();
00328     std::string typeId = slotPtrVector_[ slotId ]->getTypeId();
00329 
00330     // This is necessary since somehow setw gets confused if there are words containing 
00331     // digits or +- signs. (It seems at least...)
00332     std::string text;
00333     text = "         |             type : " + typeId + "      serial : " + serialNumber;
00334     uint32_t size = text.length();
00335     int diff = 78-size;
00336     for ( ; diff > 0; diff-- ) text += " ";
00337     text += "|";
00338     
00339     out << std::hex << std::setw(8) << std::setfill('0') << (*itM)->endAddress;
00340     out <<" ---------------------------------------------------------------------\n"
00341         <<"         |                                                                    |\n"
00342         << text << "\n"
00343         <<"         |                                                                    |\n"
00344         <<"         |                      slot ID : " << std::setw(2) << slotId << "                                  |\n"
00345         <<"         |                     function : " << std::setw(2) << functionId << "                                  |\n"
00346         <<"         |                       map ID : " << std::setw(2) << mapId << "                                  |\n"
00347         <<"         |                           AM : " << std::setw(2) << std::setfill('0') << AM << "                                  |\n"
00348         <<"         |                                                                    |\n"
00349         << std::hex << std::setw(8) << std::setfill('0') << (*itM)->startAddress
00350         <<" ---------------------------------------------------------------------\n";
00351   }
00352   out << "\n\n" << std::endl;
00353 }