Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Namespace Members | Data Fields | Related Pages

RodModule.cxx

00001 //File: RodModule.cxx
00002 // $Header: /afs/cern.ch/user/s/sctpixel/private/cvsroot/RodDaq/RodCrate/RodModule.cxx,v 1.61.2.1 2004/10/13 16:06:25 jchill Exp $
00003 
00004 #include "RodModule.h"
00005 #include "BocCard.h"
00006 
00008 namespace SctPixelRod {
00009 
00010 // Flag to force endian-ness swap before calls to HPI registers.  This should be
00011 // a temporary patch.
00012 
00013 static long endianSwap = 0;
00014 static const long rodInitTimeout = 10;
00015 
00016 //******************************Class NoImageFile**************************
00017 //
00018 // Description:
00019 //  This class is thrown if If we try to load a binary image for a master or 
00020 //  slave DSP and the file is not found
00021 //   
00022 //  Author(s):
00023 //    Tom Meyer (meyer@iastate.edu) - originator
00024 
00025 //  Constructors. Use defaults for destructor, copy, and assignment.
00026 
00027 NoImageFile::NoImageFile(std::string descriptor, std::string fileName) : BaseException(descriptor) {
00028   m_fileName = fileName;
00029   setType(NOIMAGEFILE);
00030   }
00031   
00032 void NoImageFile::what(std::ostream& os) {
00033   os << "NoImageFile Exception. Descriptor, File name: " << getDescriptor() << ";" << m_fileName << std::endl;
00034 }
00035   
00036 //******************************Class HpiException**************************
00037 //
00038 // Description:
00039 //  This class is thrown if an error in an HPI read/write operation is detected.
00040 //   
00041 //  Author(s):
00042 //    Tom Meyer (meyer@iastate.edu) - originator
00043 
00044 //  Constructors. Use defaults for destructor, copy, and assignment.
00045 
00046 HpiException::HpiException( std::string descriptor, unsigned long calcAddr,
00047                             unsigned long readAddr) : BaseException(descriptor) {
00048   m_calcAddr = calcAddr;
00049   m_readAddr = readAddr;
00050   setType(HPI);
00051   }
00052 
00053 void HpiException::what(std::ostream& os) {
00054     os << "HpiException: " << getDescriptor() << std::endl;
00055     os << "Calculated Address:" << std::hex << getCalcAddr() << std::endl;
00056     os << "Read Address:" << std::hex << getReadAddr() << std::endl;
00057 }  
00058 //***************************Class RodException**************************
00059 //
00060 // Description:
00061 //  This class is thrown if an error in a ROD operation is detected.
00062 //   
00063 //  Author(s):
00064 //    Tom Meyer (meyer@iastate.edu) - originator
00065 
00066 //  Constructors. Use defaults for destructor, copy, and assignment.
00067 
00068 RodException::RodException( std::string descriptor) : BaseException(descriptor) {
00069   m_numData = 0;
00070   m_data1 = m_data2 = 0;
00071   setType(ROD);
00072   }
00073 RodException::RodException( std::string descriptor, unsigned long data1) :
00074                             BaseException(descriptor) {
00075   m_numData = 1;
00076   m_data1 = data1;
00077   m_data2 = 0;
00078   setType(ROD);
00079   }
00080 RodException::RodException( std::string descriptor, unsigned long data1,
00081                             unsigned long data2) : BaseException(descriptor) {
00082   m_numData = 2;
00083   m_data1 = data1;
00084   m_data2 = data2;
00085   setType(ROD);
00086   }
00087 
00088 void RodException::what(std::ostream& os) {
00089   unsigned long numData;
00090   numData = getNumData();
00091   os << "RodException: " << getDescriptor() << std::endl;
00092   if (0 == numData) return;
00093   os << "Data1:" << getData1() << std::endl;
00094   if (1 == numData) return;
00095   os << "Data2:" << getData2() << std::endl;
00096 }  
00097 //********************************Class RodModule***************************
00098 //
00099 // Description:
00100 //  This is a derived class providing the software interface for VME ROD modules.
00101 //   
00102 //  Author(s):
00103 //    Tom Meyer (meyer@iastate.edu) - originator
00104 
00105 //---------------------------------Constructor------------------------------                                    
00106 /*
00107 This is the only constructor to use.
00108 */
00109 
00110 RodModule::RodModule( unsigned long baseAddr, unsigned long mapSize, 
00111      VmeInterface & ourInterface, long numSlaves) throw (RodException&,
00112      VmeException&) :
00113      VmeModule(baseAddr, mapSize, ourInterface) {
00114   m_slot = baseAddr>>24;
00115   m_serialNumber = 0xFFFFFFFF;  // Will be overwritten during init
00116   m_revision = 0;               // Will be overwritten during init
00117   m_numSlaves = numSlaves; 
00118   m_finBufferSize = 4096; 
00119   m_masterImageName = std::string("");
00120   m_myOutList = 0;
00121 
00122   try {
00123     m_myVmePort = new VmePort(m_baseAddress, m_mapSize, VmeInterface::A32, 
00124                   m_ourInterface); 
00125   }
00126   catch (std::bad_alloc & ba) {
00127     throw RodException("Failed to get VME Port.");
00128   }
00129   for (long i=0; i<4; i++) {
00130     m_slaveIpramName[i]= std::string("");
00131     m_slaveIdramName[i]= std::string("");
00132     m_slaveExtName[i]= std::string("");
00133   }
00134 
00135   for(int i=0; i<2; i++) {
00136     m_vmeCommandReg[i] = 0;
00137   }
00138   for(int i=0; i<3; i++) {
00139     m_rodStatusReg[i] = 0;
00140   }
00141 
00142   m_myOutList = 0;
00143 
00144   for (long i=0; i<N_TXT_BUFFS; i++) {
00145     m_textBuff[i] = 0;
00146   };
00147   m_myTextState = TEXT_IDLE;
00148   m_myPrimState = PRIM_IDLE;
00149   m_textType = TEXT_UNDEF;
00150 
00151   // Make the vme library generate exceptions on bus errors
00152   getVmePort()->setExceptionTrapping(true);
00153 
00154   m_myBoc = new BocCard(*this);
00155 }
00156 
00157 //---------------------------------Destructor------------------------------                                    
00158 /*
00159 Be sure to delete all VME Ports.
00160 */
00161 
00162 RodModule::~RodModule() {
00163   delete(m_myVmePort);
00164   delete m_myBoc;
00165   m_myVmePort = 0;
00166   return;
00167 }
00168 
00169 //  Member methods
00170 
00171 // Some data accessor methods placed here instead of in RodModule.h to avoid
00172 // potential problems with forward declaration of BocCard.
00173 
00174   void RodModule::setBoc(BocCard* myBoc) {m_myBoc=myBoc; return;};
00175   BocCard* RodModule::getBocCard() {return m_myBoc; }
00176 
00177 //--------------------------------initialize---------------------------------                                 
00178 
00179 /* This method performs all actions necessary to place a properly loaded ROD 
00180 in its initialized state, except for initializing the slave DSPs. This must be done
00181 separately using initSlaveDsp().
00182 
00183 Activities:
00184     Reset the ROD
00185     Read ROD serial number
00186     Load 0x000l000l into Master DSP HPIC register. (Says low order 16-bit word
00187                                                     comes first)
00188     Read back HPIC to verify
00189     Retrieve pointers to text buffer structs
00190     Initialize PrimList and TextBuff state variables
00191 */
00192 void RodModule::initialize() {initialize(false); return;};
00193 
00194 void RodModule::initialize(bool resetFlag) throw (RodException &, VmeException &) {
00195 
00196   unsigned long hpicReadback;   // for debugging
00197   const unsigned long fpgaResetValue = 0x00000020;
00198   const unsigned long rodResetValue = 0x00000040;
00199   unsigned long rodReset, fpgaReset;
00200   unsigned long rodRegValue;
00201   clock_t startTime;
00202   
00203 // If reset flag is set reset the ROD so it starts in a known state
00204   if (resetFlag) {
00205     if (endianSwap) {
00206       rodReset = endianReverse32(rodResetValue);
00207       fpgaReset = endianReverse32(fpgaResetValue);
00208     }
00209     else {
00210       fpgaReset = fpgaResetValue;
00211       rodReset = rodResetValue;
00212     }
00213 
00214 // Reconfigure the FPGAs
00215     m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[0], fpgaReset);  //FPGA config
00216 
00217 // Test that FPGA has finished its reset
00218     rodRegValue = 0;
00219     startTime = time(NULL);
00220     bool change = false;
00221     do {
00222       rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[0]);
00223       if ((time(NULL)-startTime) > DSP_RESET_TIMEOUT) {
00224         throw RodException("FPGA reset timeout in initialize(), DSP_RESET_TIMEOUT=30", rodRegValue);
00225       }
00226       // Check for configuration active
00227       if ((rodRegValue&0x20) == 0x20) change = true;
00228     } while (((rodRegValue&0x3f) != 0x1f) || change==false);
00229 
00230 // Wait a bit in between reconfigure and MDSP reset
00231     sleep(500);
00232 
00233     rodRegValue = readRodStatusReg(0);
00234     m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[2], rodReset);   // MDSP reset
00235 
00236 // Test that MDSP has finished its reset
00237     rodRegValue = 0;
00238     startTime = clock();
00239     do {
00240       rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
00241       if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
00242         throw RodException("DSP reset timeout in initialize(), DSP_RESET_TIMEOUT=",
00243         (long)DSP_RESET_TIMEOUT);
00244       }
00245     }
00246     while ((rodRegValue&0x3e) != 0x3e);
00247     rodRegValue = readRodStatusReg(0);
00248 
00249     // Wait an extra half a second
00250     sleep(500);
00251   }
00252 
00253 // Read ROD serial number 
00254   m_serialNumber = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[6]);
00255   if (endianSwap) m_serialNumber = endianReverse32(m_serialNumber); // Temporary (I hope)
00256   m_revision = (m_serialNumber&0x00ff0000)>>16;
00257   m_serialNumber = m_serialNumber & 0x3ff;   // Mask to get 10 least significant bits
00258    
00259 //  Initialize Master HPIC register to set half-word order
00260 
00261   unsigned long hpicValue = 0x00010001;
00262 
00263   hpiLoad(HPIC, hpicValue);
00264   hpicReadback = hpiFetch(HPIC);         // for debugging
00265   sleep(100);
00266 
00267 // Wait for MasterDSP init
00268   for (long i=0; ; ++i) {
00269     if (readRodStatusBit(0, SR_RUNNING)) {
00270       break;
00271     }
00272     if (i>rodInitTimeout*10) throw RodException("Master DSP init timed out. Tries, Limit:", i,
00273         rodInitTimeout);
00274     sleep(100);
00275   }
00276 
00277   for (int i=0; i< N_TXT_BUFFS; i++) {
00278     m_textBuff[i] = (unsigned long *)mdspSingleRead(REPLY_BUFF_BASE + 4*i);
00279   }
00280 
00281 //  Reinitialize state variables
00282   m_myTextState = TEXT_IDLE;
00283   m_myPrimState = PRIM_IDLE;
00284 
00285 return;
00286 }
00287 
00288 //---------------------------------reset------------------------------------                                
00289 
00290 /* This method resets the ROD.
00291 */
00292 
00293 void RodModule::reset() throw (RodException&, VmeException &) {
00294   // Reset all FPGAs and DSPs (bit 7 = 0x80)
00295   const unsigned long rodResetValue = 0x00000040;
00296   unsigned long rodReset;
00297   unsigned long rodRegValue;
00298   clock_t startTime;
00299   
00300   if (endianSwap) {
00301     rodReset = endianReverse32(rodResetValue);
00302   }
00303   else {
00304     rodReset = rodResetValue;
00305   }
00306   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[2], rodReset);
00307   sleep(10000);
00308   rodRegValue = 0;
00309   startTime = clock();
00310   do {
00311     rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
00312     if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
00313       throw RodException("DSP reset timeout in reset() (first call), DSP_RESET_TIMEOUT=",
00314       (long)DSP_RESET_TIMEOUT);
00315     }
00316   }
00317   while (rodRegValue != 0x3e);
00318    
00319   // Clear IDRAM
00320   unsigned long * buff;
00321   try {
00322     // Allocate a buffer of zeros
00323     buff = new unsigned long[IDRAM_SZ/sizeof(long)];
00324 
00325     for(unsigned int i=0; i<IDRAM_SZ/sizeof(long); i++) {
00326       buff[i] = 0;
00327     }
00328   }
00329   catch (std::bad_alloc & ba) {
00330     throw RodException("Reset() failed to allocate buffer. Size=",
00331                                   IDRAM_SZ/sizeof(long));
00332   }
00333   mdspBlockWrite(IDRAM_BASE, buff, IDRAM_SZ/sizeof(long));
00334   delete [] buff;
00335   
00336   // Reset all DSPs
00337   resetMasterDsp();
00338   sleep(50);
00339   for (long i=0; i<m_numSlaves; i++) {
00340     resetSlaveDsp(i);
00341     sleep(50);
00342     rodRegValue = 0;
00343     startTime = clock();
00344     do {
00345       rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
00346       if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
00347         throw RodException("DSP reset timeout in reset() (second call), DSP_RESET_TIMEOUT=",
00348         (long)DSP_RESET_TIMEOUT);
00349       }
00350     }
00351   while (rodRegValue != 0x3e);
00352   };
00353   
00354   //  Reinitialize state variables
00355   m_myTextState = TEXT_IDLE;
00356   m_myPrimState = PRIM_IDLE;
00357   
00358 return;
00359 }
00360 
00361 //----------------------------------verify----------------------------------                                
00362 
00363 /* This method checks the value of the h.o. byte of the 
00364 */
00365 
00366 bool RodModule::verify() throw() {
00367   unsigned long regVal;
00368   
00369 // Read status register 6 
00370   regVal = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[6]);
00371   if (endianSwap) regVal = endianReverse32(regVal); 
00372   regVal = regVal & 0xff000000;            // Mask to get most significant byte
00373   if (regVal!=0xad000000) return false;
00374   return true;
00375 }
00376 
00377 //---------------------------------status-----------------------------------                                
00378 
00379 /* This method reports the status of the ROD.
00380 For now, it simply prints to standard output.
00381 */
00382 void RodModule::status() throw() {
00383     std::cout << "Slot: " << m_slot;
00384     std::cout << "Serial Number:" << m_serialNumber;
00385     std::cout << "Number of slave DSPs: " << m_numSlaves;
00386     std::cout << std::endl;
00387     std::hex(std::cout);
00388     std::cout << "Status registers[0-2]: ";
00389     try {
00390       for (int i=0; i<3; i++) {
00391         std::cout << readRodStatusReg(i) << " " ;
00392       }
00393     }
00394     catch (VmeException &) {
00395       std::cout << "status() can't read ROD status registers." << std::flush;
00396     }
00397     std::cout << std::endl;
00398     
00399     std::cout << "Command registers[0-1]: ";
00400     try {
00401       for (int i=0; i<2; i++) {
00402         std::cout << readRodCommandReg(i) << " " ;
00403       }
00404     }
00405     catch (VmeException &) {
00406       std::cout << "status() can't read ROD command registers.\n" << std::flush;
00407     }
00408 
00409     std::dec(std::cout);
00410     std::cout << "Primitive state: " << getPrimState() << " Text State: " << 
00411           getTextState();
00412     std::cout << std::endl;
00413     return;
00414 }
00415 
00416 //--------------------------------initSlaveDsp-------------------------------                       
00417 void RodModule::initSlaveDsp(const std::string & ipramFile,
00418      const std::string & idramFile,const std::string & extFile,
00419      const long slaveNumber, char opt) throw (RodException&, NoImageFile&, VmeException &) {
00420 
00421   unsigned long readBack;
00422   unsigned long hpicValue = 0x00010001;
00423   unsigned long rodRegValue;
00424   clock_t startTime;
00425  
00426   if ((slaveNumber < 0) || (slaveNumber >= m_numSlaves)) throw RodException(
00427        "Slave Number out of Range. slaveNumber, m_numSlaves:", slaveNumber, 
00428        m_numSlaves);
00429 
00430 // Set HPIC registers to make first halfword the most significant
00431   slvHpiLoad(SLAVE_HPIC_BASE, hpicValue, slaveNumber);
00432   readBack = slvHpiFetch(SLAVE_HPIC_BASE, slaveNumber);
00433   
00434 // Load the memory images and remember the file names
00435   loadSlaveImage(ipramFile, SLAVE_IPRAM_ADDR, slaveNumber, opt);
00436   m_slaveIpramName[slaveNumber] = ipramFile;
00437   loadSlaveImage(idramFile, SLAVE_IDRAM_ADDR, slaveNumber, opt);
00438   m_slaveIdramName[slaveNumber] = idramFile;
00439   loadSlaveImage(extFile, SLAVE_CE2_ADDR, slaveNumber, opt);
00440   m_slaveExtName[slaveNumber] = extFile;
00441   
00442 // Send the START_SLAVE_EXECUTING primitive. Do the primList dialog synchronously
00443   startSlave(slaveNumber);
00444 
00445 // Check that slave has finished its reset
00446   rodRegValue = 0;
00447   startTime = clock();
00448   do {
00449     rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
00450     if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
00451       throw RodException("DSP reset timeout in initSlaveDsp(), DSP_RESET_TIMEOUT=",
00452       (long)DSP_RESET_TIMEOUT);
00453     }
00454   }
00455   while (rodRegValue != 0x3e);
00456   return;
00457 }
00458 
00459 
00460 //--------------------------------loadSlaveImage-------------------------------                       
00461 // This version writes to cout. This needs to be changed.
00462 void RodModule::loadSlaveImage(const std::string & fileName, const unsigned long address,
00463      const long slaveNum, char opt) throw (NoImageFile&, RodException&, 
00464                                                VmeException &) {
00465   
00466   long numWords;
00467   unsigned long readBack;   
00468   int fileSize;
00469   const unsigned long DSP_BUSY_MASK=0x00000002;
00470   std::ifstream fin;
00471 // Cannot load image if slave is running.  Check it and throw a rodException if it is
00472   readBack = slvHpiFetch(SLAVE_HPIC_BASE, slaveNum);
00473   if (readBack & DSP_BUSY_MASK) throw RodException(
00474      "loadSlaveImage tried to load to a running SDSP. slavenum = ", slaveNum);
00475      
00476   fin.open(fileName.c_str(),std::ios::binary);
00477   if (fin.is_open()) {
00478 
00479 // Get size of file
00480     fin.seekg(0, std::ios::end);  // go to end of file
00481     fileSize = fin.tellg();  // file size is current location
00482     fin.seekg(0, std::ios::beg);  // go back to beginning of file
00483 
00484 // Create buffer and fill it with file contents
00485     char * buffer; 
00486     try {
00487       buffer = new char[fileSize];
00488     }
00489     catch (std::bad_alloc & ba) {
00490       throw RodException(
00491                   "loadSlaveImage buffer failed to allocate. buffer, fileSize:",
00492                   (unsigned long)buffer, (unsigned long)fileSize);
00493     }
00494     fin.read(buffer, fileSize);
00495 
00496 // Use slvBlockWrite to transfer buffer into memory
00497     numWords = (fileSize+3)/4;
00498     slvBlockWrite(address, (unsigned long*) buffer, numWords, slaveNum);
00499     
00500 // Read back buffer for verification if 'v' option was given
00501     if (opt=='v') {
00502       char* buffer2;
00503       try {
00504         buffer2 = new char[fileSize];
00505       }
00506       catch (std::bad_alloc & ba) {
00507         throw RodException(
00508                   "loadSlaveImage buffer2 failed to allocate. buffer, fileSize:",
00509                   (unsigned long)buffer, (unsigned long)fileSize);
00510       }
00511       slvBlockRead(address, (unsigned long*)buffer2, numWords, slaveNum);
00512    
00513       for (int i=0; i<fileSize; i++) {
00514         if (buffer[i] != buffer2[i]) {
00515           delete [] buffer;
00516           delete [] buffer2;
00517           fin.close();
00518           char message[] = "loadSlaveImage buffer readback invalid for file, slavenum, char index: ";
00519           throw RodException( message+fileName, slaveNum, i);
00520         }
00521       } 
00522       delete [] buffer2;
00523       std::cout << "Image verification check complete\n";
00524     }
00525     
00526 // Close the file and delete the buffer    
00527     fin.close();
00528     delete [] buffer;
00529   }
00530   else {
00531     throw NoImageFile("NoImageFile thrown from loadSlaveImage", fileName);
00532   }
00533   return;
00534 }
00535 
00536 //--------------------------------startSlave-------------------------------                       
00537 // Starts slave executing
00538 // The default way is to have the master DSP run the START_SLAVE_EXECUTING
00539 // primitive. This is what should normally be used.
00540 // A quick "back door" way is to set the slave's DSPINT bit directly.
00541 
00542 void RodModule::startSlave(const long slaveNumber, char mode) 
00543                                             throw(RodException&, VmeException &) {
00544   const unsigned long dspint = 0x2;
00545 
00546   if (mode == 'q') {             // The quick way: just set DSPINT directly
00547     slvHpiLoad(SLAVE_HPIC_BASE, dspint, slaveNumber);
00548   }
00549 
00550   else {                         // The slow way, a master primitive (default)
00551   long primData[4]={slaveNumber, 1, 2, 0x200000};
00552   RodPrimitive * startSlaveExec;
00553   try {
00554     startSlaveExec = new RodPrimitive(8, 1, START_SLAVE_EXECUTING, 
00555        R_START_SLAVE_EXECUTING, primData);
00556   }
00557   catch (std::bad_alloc & ba) {
00558     throw RodException(
00559       "startSlave unable to allocate startSlaveExec. slaveNumber:", slaveNumber); 
00560   }
00561   synchSendPrim(*startSlaveExec); 
00562   delete startSlaveExec;
00563   }
00564   
00565   return;
00566 }
00567 
00568 /*---------------------------------synchSendPrim------------------------------                           
00569 This version writes to cout. This needs to be changed.
00570 */
00571 void RodModule::synchSendPrim(RodPrimitive & prim) throw (RodException&, 
00572                                                          VmeException &) {
00573   RodPrimList primList(1);  // Private primList (local to this routine)
00574   long myTextLength;                            // Actual length of text message
00575   TEXT_BUFFER_TYPE myTextType;                  // Buffer type for latest message
00576   PrimState returnPState;
00577   TextBuffState returnTState;
00578 
00579 // Create a text buffer in case of error message
00580     char * myTextBuffer;
00581     try {
00582       myTextBuffer = new char[TEXT_BUFF_SIZE];
00583     }
00584     catch (std::bad_alloc & ba) {
00585       throw RodException(
00586           "synchSendPrim failed to allocate text. Size=", TEXT_BUFF_SIZE);
00587     }
00588     primList.insert(primList.begin(), prim);
00589     try {
00590       primList.bufferBuild();
00591     }
00592     catch (PrimListException &p) {
00593 //      throw (RodException(p.getDescriptor,p.getData1(), p.getData2());
00594       std::cout << p.getDescriptor() << " ";
00595       std::cout << p.getData1() << ", " << p.getData2() << "\n";
00596     };
00597     try {
00598       this->sendPrimList(&primList);
00599     }
00600     catch (BaseException &h) {
00601       std::cout << h;
00602     };
00603 
00604 // Wait for ROD to begin executing and then wait for it to finish executing
00605 // Check for error messages in text buffer and read them out if they exist.
00606 // Note: this is the synchronous way to do it. In general, it is better to do it
00607 // asynchronously.
00608     do {
00609       returnPState = this->primHandler();
00610       returnTState = this->textHandler();
00611 
00612       // Use while to print out multiple buffers
00613       while (returnTState == TEXT_RQ_SET) {
00614         do {
00615           returnTState = this->textHandler();
00616         } while (returnTState != TEXT_READOUT);
00617         this->getTextBuffer(myTextBuffer, myTextLength, myTextType);
00618         this->clearTextBuffer();
00619         for (int i=0; i<myTextLength; i++) {
00620           std::cout << myTextBuffer[i];
00621           if (0==(i+1)%64) std::cout << std::endl;
00622         }
00623         std::cout << std::endl; 
00624         returnTState = this->textHandler();
00625       }
00626     } while (returnPState != PRIM_EXECUTING); 
00627     do {
00628        try {
00629          returnPState = this->primHandler();
00630        }
00631        catch (RodException &r) {
00632        std::cout << r.getDescriptor() <<", " << r.getData1() << ", " << r.getData2()
00633                << '\n';
00634        }
00635     } while (returnPState != PRIM_WAITING && returnPState != PRIM_IDLE); 
00636     delete [] myTextBuffer;    // Found by valgrind
00637 
00638   return;
00639 }
00640 
00641 //---------------------------------sendPrimList-------------------------------                           
00642 
00643 void RodModule::sendPrimList(RodPrimList *l) throw(PrimListException &, VmeException &) {
00644 
00645   unsigned long * buffAddr;
00646   long buffCount;
00647 
00648   if (!l->getBuffer()) {
00649     l->bufferBuild();
00650   };
00651 
00652   buffCount = l->getBufferLength();
00653 
00654   if(abs(buffCount) > PRIM_BUFF_SIZE) {
00655     throw PrimListException("PrimList is bigger than DSP buffer", buffCount, PRIM_BUFF_SIZE);
00656   }
00657 
00658   buffAddr = l->getBuffer();
00659   mdspBlockWrite(PRIM_BUFF_BASE, buffAddr, buffCount);
00660   m_myPrimState = PRIM_LOADED;
00661 
00662   return;  
00663 }  
00664 
00665 //---------------------------------primHandler-------------------------------                           
00666 
00667 PrimState RodModule::primHandler() throw(RodException &, VmeException &) {
00668 long wordCount;
00669 unsigned long status;
00670 unsigned long* buffptr;
00671 unsigned long replyBuffer;
00672   switch (m_myPrimState) {
00673     case PRIM_LOADED: {
00674       if (0==getDspAck()) {
00675         setInListReady();
00676         m_myPrimState = PRIM_EXECUTING;
00677       };
00678     break;
00679     };
00680     case PRIM_EXECUTING: {
00681       status = readRodStatusReg(0);
00682       if (1==getDspAck()) {
00683         if (status >> TEXT_BUFF_NOT_EMPTY[0]) {
00684 //        throw RodException ("Error buffer not empty in primHandler(PRIM_EXECUTING)");
00685         }
00686         if (1==readRodStatusBit(0,OUTLIST_READY)) {
00687           // read buffer size
00688           hpiLoad(HPIA, REPLY_BUFF_BASE);
00689           wordCount = hpiFetch(HPID_NOAUTO);
00690 
00691       // create new OutList object.  Note that this object persists until it is deleted
00692       // in deleteOutList.  The pointer in outList dies when this routine exists but
00693       // the object itself persists in memory until deleted.  By copying the pointer
00694       // value in the address "outList" to m_myOutList, we keep knowledge of where the
00695       // object is an may continue to use it until it is deleted.
00696       
00697           RodOutList* outList;
00698           try {
00699             outList = new RodOutList(wordCount);
00700           }
00701           catch (std::bad_alloc & ba) {
00702             throw RodException("Outlist creation failed. WordCount=", 
00703                                               wordCount);
00704           }
00705           if (0==outList->getBody()) throw RodException(
00706                  "Outlist failed to allocate body array.WordCount=", wordCount);
00707          
00708       // This is where the value of m_myOutList gets set to the value of outList.
00709           this->setOutList(outList);
00710       
00711       // fill OutList object
00712           buffptr = m_myOutList->getBody();
00713           replyBuffer = REPLY_BUFF_BASE;
00714       mdspBlockRead(replyBuffer, buffptr, wordCount);
00715           m_myPrimState = PRIM_WAITING;
00716         }
00717         else m_myPrimState = PRIM_IDLE;
00718         clearVmeCommandRegBit(INLISTRDY);
00719       }
00720     break;
00721     };
00722     default: {
00723     break;
00724     };
00725   };
00726   return m_myPrimState;
00727 };
00728 
00729 //--------------------------------deleteOutList--------------------------------
00730 
00731   void RodModule::deleteOutList() throw() {
00732   delete m_myOutList;
00733   m_myOutList = 0;
00734   return;
00735   };
00736 
00737 //---------------------------------textHandler-------------------------------                           
00738 
00739 TextBuffState RodModule::textHandler() throw(VmeException &) {
00740   unsigned long regValue;
00741   unsigned long dataPtr;
00742   long txtLength, txtLength1, txtLength2, txtWords;
00743   switch (m_myTextState) {
00744     case TEXT_IDLE: {
00745       regValue = readRodStatusReg(0) & SR_TEXT_MASK;
00746       if (0==regValue) return m_myTextState;         // Quick return if no text
00747       for (long i=0; i<4; i++) {
00748         if (regValue & SR_TEXT_BIT_MASK[i]) {
00749           m_textType = (TEXT_BUFFER_TYPE)i;
00750           setVmeCommandRegBit(TEXT_BUFF_READ_REQ[m_textType]);
00751           sleep(10);
00752           m_myTextState = TEXT_RQ_SET;
00753           return m_myTextState;
00754         };
00755       }
00756       break;
00757     };
00758     case TEXT_RQ_SET: {
00759       if (readRodStatusReg(0) & SR_TEXT_BIT_MASK[m_textType]) {
00760         return m_myTextState;
00761       };
00762       hpiLoad( HPIA, (unsigned long)m_textBuff[m_textType]);
00763       m_txtBuffer.dataEnd = hpiFetch(HPID_AUTO);
00764       m_txtBuffer.readIndx = hpiFetch(HPID_AUTO);
00765       m_txtBuffer.writeIndx = hpiFetch(HPID_AUTO);
00766       m_txtBuffer.mode = hpiFetch(HPID_AUTO);
00767       m_txtBuffer.overwrite = hpiFetch(HPID_AUTO);
00768       m_txtBuffer.overflow = hpiFetch(HPID_AUTO);
00769       m_txtBuffer.wrap = hpiFetch(HPID_AUTO);
00770       m_txtBuffer.state = hpiFetch(HPID_AUTO);
00771       m_txtBuffer.id = hpiFetch(HPID_AUTO);
00772       m_txtBuffer.data = (char *)hpiFetch(HPID_AUTO);
00773       dataPtr = (unsigned long)m_txtBuffer.data;
00774 
00775 // If there was a wrap-around we need to read two blocks, otherwise only one
00776       if (m_txtBuffer.readIndx < m_txtBuffer.writeIndx) {           // No wrap
00777         txtLength = m_txtBuffer.writeIndx - m_txtBuffer.readIndx;
00778         txtWords = (txtLength+3)/4;     // Convert char count to words
00779     mdspBlockRead(dataPtr, (unsigned long*)m_textData, txtWords);
00780       }
00781       else {                                                         // Wrap
00782         txtLength1 = TEXT_BUFF_SIZE - m_txtBuffer.readIndx;
00783         txtWords = (txtLength1+3)/4;
00784     mdspBlockRead(dataPtr+4*m_txtBuffer.readIndx, (unsigned long*)m_textData, txtWords);
00785         txtLength2 = m_txtBuffer.writeIndx;
00786         txtWords = (txtLength2+3)/4;
00787     mdspBlockRead(dataPtr, (unsigned long*)(m_textData+4*txtLength1), txtWords);
00788         txtLength = txtLength1 + txtLength2;
00789       };
00790       clearVmeCommandRegBit(TEXT_BUFF_READ_REQ[m_textType]);
00791       sleep(10);
00792       m_myTextState = TEXT_READOUT;
00793       m_txtBuffer.state = txtLength;
00794       return m_myTextState;
00795       break;
00796     };
00797     default: {
00798       return m_myTextState;
00799       break;
00800     };
00801   };
00802 
00803   return m_myTextState;
00804 };
00805 
00806 
00807 //-----------------------------getTextBuffer-------------------------------                                
00808 
00809   void RodModule::getTextBuffer(char * buffer, long & length, 
00810          TEXT_BUFFER_TYPE & type) throw() {
00811     length = m_txtBuffer.state;
00812     type = (TEXT_BUFFER_TYPE)m_textType;
00813     for (int i=0; i<m_txtBuffer.state; i++) {
00814       buffer[i] = m_textData[i];
00815     };
00816     return;
00817   };
00818   
00819 //--------------------------------clearTextBuffer------------------------------
00820 
00821 void RodModule::clearTextBuffer() throw() {
00822   m_textType = TEXT_UNDEF;
00823   m_txtBuffer.state = 0;
00824   m_myTextState = TEXT_IDLE;
00825   return;
00826 };
00827 
00828 //----------------------------------hpiLoad------------------------------------                                
00829 
00830 void RodModule::hpiLoad(unsigned long hpiReg, unsigned long hpiValue) 
00831      throw(VmeException &) {
00832 
00833   if (endianSwap) hpiValue = endianReverse32(hpiValue); 
00834   m_myVmePort->write32(hpiReg, hpiValue);
00835 };
00836 
00837 //--------------------------------hpiFetch-------------------------------------                                
00838 
00839 unsigned long RodModule::hpiFetch(unsigned long hpiReg) 
00840               throw(VmeException &){
00841 
00842 unsigned long hpiValue;
00843 
00844   hpiValue=m_myVmePort->read32(hpiReg);
00845   if (endianSwap) hpiValue = endianReverse32(hpiValue);
00846   
00847   return hpiValue;
00848 };
00849 
00850 //-----------------------------mdspSingleRead---------------------------------                                
00851 
00852 unsigned long RodModule::mdspSingleRead(const unsigned long dspAddr) 
00853               throw(VmeException &) {
00854   unsigned long value; 
00855 
00856 //  Load the DSP address into the HPIA register 
00857   hpiLoad(HPIA, dspAddr);
00858 
00859 //  Do the read 
00860   value = m_myVmePort->read32(HPID_NOAUTO);
00861   if (endianSwap) {
00862     value = endianReverse32(value);
00863   }
00864   return value;
00865 };
00866 
00867 //------------------------------mdspSingleWrite------------------------------------                                   
00868 
00869 void RodModule::mdspSingleWrite(unsigned long dspAddr, unsigned long buffer) 
00870      throw(VmeException &) { 
00871 
00872 //  Load the HPID address into the HPIA register 
00873   hpiLoad(HPIA, dspAddr);
00874 
00875 //  Do the write 
00876   if (endianSwap) {
00877       buffer = endianReverse32(buffer);
00878   }
00879 
00880   m_myVmePort->write32(HPID_NOAUTO, buffer);
00881 
00882   return;
00883 };
00884 
00885 //-----------------------------mdspBlockRead---------------------------------                                
00886 
00887 
00888 void RodModule::mdspBlockRead(const unsigned long dspAddr, unsigned long buffer[],
00889        const long wordCount, HpidMode mode) throw (HpiException &, 
00890        VmeException &) {
00891   unsigned long hpidAddr; 
00892   long myCount, localCount, blockWordCount, wordIncr;
00893 
00894 // Determine the HPI mode to use.
00895   switch (mode) {
00896     case AUTO:
00897       hpidAddr= HPID_AUTO;
00898       break;
00899     case NO_AUTO:
00900       hpidAddr = HPID_NOAUTO; 
00901       break;
00902     case DYNAMIC:
00903     default:
00904       if (wordCount == 1){
00905         hpidAddr = HPID_NOAUTO;
00906       } 
00907       else { 
00908         hpidAddr = HPID_AUTO;
00909       };
00910       break;
00911   };
00912 
00913 //  Load the DSP address into the HPIA register 
00914   hpiLoad(HPIA, dspAddr);  
00915   
00916 // Check if wordcount is odd and, if so, first do a single word read.
00917 
00918   localCount = wordCount;
00919   wordIncr = 0;
00920   if (wordCount%2 !=0) {
00921     buffer[0] = m_myVmePort->read32(hpidAddr);
00922     wordIncr = 1;
00923     localCount -= 1;
00924   }
00925 
00926 // Check to see that we don't access too large a block. 
00927 // MAX_HPID_WORD_ELEMENTS is defined in RodVmeAddresses.h
00928 
00929    blockWordCount = std::min(localCount, MAX_HPID_WORD_ELEMENTS);
00930    
00931 //  Set up the transfer as a series of block transfers 
00932   for (myCount=localCount; myCount>0;
00933                     myCount-=blockWordCount, wordIncr+=blockWordCount) {
00934 
00935 //  Recheck each block 
00936     blockWordCount = std::min(myCount, MAX_HPID_WORD_ELEMENTS);
00937     
00938 //  Do the transfer for this block 
00939 // Block reads are being done in hardware as from 10 June 03.
00940 
00941     m_myVmePort->blockRead32(hpidAddr, buffer+wordIncr, blockWordCount*4);
00942 
00943 // Use this code if you have problems with the hardware block transfers    
00944 /*    for (int i=0; i<blockWordCount; i++) {
00945       buffer[wordIncr+i] = m_myVmePort->read32(hpidAddr);
00946     }
00947 
00948     if (endianSwap) {
00949       for (int i=0; i<blockWordCount; i++) {
00950         buffer[wordIncr+i] = endianReverse32(buffer[wordIncr+i]);
00951       }
00952     }
00953 */
00954   }
00955   return;
00956 };
00957 
00958 //------------------------------mdspBlockWrite-----------------------------------  
00959 
00960 void RodModule::mdspBlockWrite(unsigned long dspAddr, unsigned long buffer[], 
00961        long wordCount, HpidMode mode) throw (HpiException &, 
00962        VmeException &) { 
00963 
00964   unsigned long hpidAddr;
00965   long myCount, localCount, blockWordCount, wordIncr;
00966 
00967 //  Load the initial dsp address into the HPIA register 
00968   hpiLoad(HPIA, dspAddr);
00969 
00970 // Determine the HPI mode to use.
00971   switch (mode) {
00972     case AUTO:
00973       hpidAddr= HPID_AUTO;
00974       break;
00975     case NO_AUTO:
00976       hpidAddr = HPID_NOAUTO; 
00977       break;
00978     case DYNAMIC:
00979     default:
00980       if (wordCount == 1){
00981         hpidAddr = HPID_NOAUTO;
00982       } 
00983       else { 
00984         hpidAddr = HPID_AUTO;
00985       };
00986       break;
00987   };
00988 
00989 // Check if wordcount is odd and, if so, first do a single word write.
00990 
00991   localCount = wordCount;
00992   wordIncr = 0;
00993   if (wordCount%2 !=0) {
00994     m_myVmePort->write32(hpidAddr, buffer[0]);
00995     wordIncr = 1;
00996     localCount -= 1;
00997   }
00998 
00999 // Check to see that we don't access too large a block.
01000 // MAX_HPID_WORD_ELEMENTS is defined in vmeAddressMap.h
01001 
01002   blockWordCount = std::min(wordCount, MAX_HPID_WORD_ELEMENTS);
01003 
01004 //  Set up the transfer as a series of block transfers 
01005   for (myCount=localCount; myCount>0;
01006                     myCount-=blockWordCount, wordIncr+=blockWordCount) {
01007 
01008 //  Recheck each block 
01009     blockWordCount = std::min(myCount, MAX_HPID_WORD_ELEMENTS);
01010   
01011 //  Do the transfer for this block 
01012   if (endianSwap) {
01013     for (int i=0; i<blockWordCount; i++) {
01014       buffer[wordIncr+i] = endianReverse32(buffer[wordIncr+i]);
01015     }
01016   }
01017 
01018 // Block writes are being done in hardware as from 10 June 03.
01019 
01020     m_myVmePort->blockWrite32(hpidAddr, &buffer[wordIncr], blockWordCount*4);
01021     
01022 // Use this code if harfdware block transfers are a problem.
01023 /*
01024     for (int i=0; i<blockWordCount; i++) {
01025       m_myVmePort->write32(hpidAddr, buffer[wordIncr+i]);
01026     }
01027 */
01028   }
01029   return;
01030 };
01031 
01032 //-----------------------------mdspBlockDump--------------------------------                                
01033 
01034 void RodModule::mdspBlockDump(const unsigned long firstAddress, 
01035        const unsigned long lastAddress,
01036        const std::string & fileName) throw(RodException &, VmeException &) {
01037        
01038   long numBytes;
01039   std::ofstream fout;
01040   numBytes = lastAddress - firstAddress + 1;
01041   fout.open(fileName.c_str(), std::ios::binary);
01042   if (fout.is_open()) {
01043     unsigned long * buffer;
01044     try {
01045       buffer = new unsigned long[numBytes];
01046     }
01047     catch (std::bad_alloc & ba) {
01048       throw RodException(
01049        "mdspBlockDump failed to allocate buffer; buffer size in bytes=", numBytes);
01050     }   
01051     mdspBlockRead(firstAddress, buffer, numBytes/4);
01052     fout.write((char*)buffer, numBytes);
01053     fout.close();
01054     delete [] buffer;
01055   }
01056   else {
01057     throw RodException("mdspBlockDump failed to open file");
01058   }
01059   return;                    
01060 }
01061 
01062 //--------------------------------slvHpiLoad-----------------------------------                                
01063 
01064 void RodModule::slvHpiLoad(unsigned long hpiReg, unsigned long hpiValue,
01065                            long slaveNum) throw(VmeException &) {
01066 
01067   unsigned long address;
01068   address = hpiReg + slaveNum*SLAVE_HPI_OFFSET;
01069   
01070   mdspSingleWrite(address, hpiValue);
01071 };
01072 
01073 //------------------------------slvHpiFetch------------------------------------
01074 
01075 unsigned long RodModule::slvHpiFetch(unsigned long hpiReg, long slaveNum) 
01076               throw(VmeException &) {
01077 
01078   unsigned long hpiValue;
01079   unsigned long address;
01080   address = hpiReg + slaveNum*SLAVE_HPI_OFFSET;
01081   
01082     hpiValue=mdspSingleRead(address);
01083 
01084   return hpiValue;
01085 };
01086 
01087 //-------------------------------slvSingleRead---------------------------------
01088 unsigned long RodModule::slvSingleRead(unsigned long dspAddr, long slaveNum ) 
01089               throw(VmeException &) {
01090 
01091   unsigned long slvHpia, slvHpid;
01092   unsigned long value;
01093   slvHpia = SLAVE_HPIA_BASE + slaveNum*SLAVE_HPI_OFFSET;
01094   slvHpid = SLAVE_HPID_NOAUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01095 
01096 //  Load the DSP address into the HPIA register 
01097   mdspSingleWrite(slvHpia, dspAddr);
01098 
01099 //  Do the read 
01100   value = mdspSingleRead(slvHpid);
01101 
01102   return value;
01103 };
01104 
01105 //------------------------------slvSingleWrite------------------------------------                                   
01106 
01107 void RodModule::slvSingleWrite(unsigned long dspAddr, unsigned long buffer, 
01108                  long slaveNum) throw(VmeException &) { 
01109 
01110   unsigned long slvHpia, slvHpid;
01111   slvHpia = SLAVE_HPIA_BASE + slaveNum*SLAVE_HPI_OFFSET;
01112   slvHpid = SLAVE_HPID_NOAUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01113 
01114   mdspSingleWrite(slvHpia, dspAddr);
01115 
01116 //  Do the write 
01117   mdspSingleWrite(slvHpid, buffer);
01118 
01119   return;
01120 };
01121 
01122 //-----------------------------slvBlockRead---------------------------------                                
01123 
01124 void RodModule::slvBlockRead(const unsigned long dspAddr, unsigned long buffer[],
01125                 const long wordCount, long slaveNum, HpidMode mode) 
01126                 throw (HpiException &, VmeException &) {
01127                 
01128   unsigned long hpidAddr, dspAddrLocal, hpiaAfterFetch, hpiaAfterCalc; 
01129   long myCount, blockWordCount, wordIncr;
01130   unsigned long slvHpia, slvHpidAuto, slvHpidNoAuto;
01131   slvHpia = SLAVE_HPIA_BASE + slaveNum*SLAVE_HPI_OFFSET;
01132   slvHpidAuto = SLAVE_HPID_AUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01133   slvHpidNoAuto = SLAVE_HPID_NOAUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01134 
01135 
01136 // Determine the HPI mode to use.
01137   switch (mode) {
01138     case AUTO:
01139       hpidAddr= slvHpidAuto;
01140       break;
01141     case NO_AUTO:
01142       hpidAddr = slvHpidNoAuto; 
01143       break;
01144     case DYNAMIC:
01145     default:
01146       if (wordCount == 1){
01147         hpidAddr = slvHpidNoAuto;
01148       } 
01149       else { 
01150         hpidAddr = slvHpidAuto;
01151       };
01152       break;
01153   };
01154 
01155 //  Load the DSP address into the HPIA register 
01156   mdspSingleWrite(slvHpia, dspAddr);
01157 
01158 // Check to see that we don't access too large a block. HPID has 20 bits of 
01159 // address space available. MAX_HPID_WORD_ELEMENTS is defined in RodVmeAddresses.h
01160 
01161   blockWordCount = std::min(wordCount, MAX_HPID_WORD_ELEMENTS);
01162 
01163 //  Set up the transfer as a series of block transfers 
01164   for (myCount=wordCount, wordIncr=0; myCount>0;
01165                     myCount-=blockWordCount, wordIncr+=blockWordCount) {
01166 
01167 //  Recheck each block 
01168     blockWordCount = std::min(myCount, MAX_HPID_WORD_ELEMENTS);
01169 
01170 //  Do the transfer for this block 
01171     dspAddrLocal = dspAddr+ (4*wordIncr);
01172     mdspBlockRead(hpidAddr, &buffer[wordIncr], blockWordCount, NO_AUTO);
01173   }
01174 
01175 //  Check HPID after transfer 
01176   hpiaAfterFetch = mdspSingleRead(slvHpia);
01177   if (wordCount == 1) {
01178     hpiaAfterCalc = dspAddr;
01179   } else  {
01180     hpiaAfterCalc = dspAddr+wordCount*4;
01181   }
01182 /*  if (hpiaAfterFetch != hpiaAfterCalc) {
01183     throw HpiException("mslvBlockRead address check failed", hpiaAfterCalc, 
01184                        hpiaAfterFetch);
01185   }
01186 */
01187   return;
01188 };
01189 
01190 //------------------------------slvBlockWrite-----------------------------------  
01191 
01192 void RodModule::slvBlockWrite(unsigned long dspAddr, unsigned long buffer[], 
01193          long wordCount, long slaveNum, HpidMode mode) 
01194          throw (HpiException &, VmeException &) { 
01195 
01196   unsigned long hpidAddr, dspAddrLocal, hpiaAfterFetch, hpiaAfterCalc;
01197   long myCount, blockWordCount, wordIncr;
01198   unsigned long slvHpia, slvHpidAuto, slvHpidNoAuto;
01199   slvHpia = SLAVE_HPIA_BASE + slaveNum*SLAVE_HPI_OFFSET;
01200   slvHpidAuto = SLAVE_HPID_AUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01201   slvHpidNoAuto = SLAVE_HPID_NOAUTO_BASE + slaveNum*SLAVE_HPI_OFFSET;
01202 
01203 //  Load the initial dsp address into the HPIA register 
01204   mdspSingleWrite(slvHpia, dspAddr);
01205 
01206 // Determine the HPI mode to use.
01207   switch (mode) {
01208     case AUTO:
01209       hpidAddr= slvHpidAuto;
01210       break;
01211     case NO_AUTO:
01212       hpidAddr = slvHpidNoAuto; 
01213       break;
01214     case DYNAMIC:
01215     default:
01216       if (wordCount == 1){
01217         hpidAddr = slvHpidNoAuto;
01218       } 
01219       else { 
01220         hpidAddr = slvHpidAuto;
01221       };
01222       break;
01223   };
01224 
01225 // Check to see that we don't access too large a block. HPID has 20 bits of 
01226 // address space available. MAX_HPID_WORD_ELEMENTS is defined in vmeAddressMap.h
01227 
01228   blockWordCount = std::min(wordCount, MAX_HPID_WORD_ELEMENTS);
01229 
01230 //  Set up the transfer as a series of block transfers 
01231   for (myCount=wordCount, wordIncr=0; myCount>0;
01232                     myCount-=blockWordCount, wordIncr+=blockWordCount) {
01233 
01234 //  Recheck each block 
01235     blockWordCount = std::min(myCount, MAX_HPID_WORD_ELEMENTS);
01236   
01237 //  Do the transfer for this block 
01238   dspAddrLocal = dspAddr+ (4*wordIncr);
01239     mdspBlockWrite(hpidAddr, &buffer[wordIncr], blockWordCount, NO_AUTO);
01240   }
01241   
01242 //  Check HPID after transfer 
01243   hpiaAfterFetch = mdspSingleRead(slvHpia);
01244     
01245   if (wordCount == 1) {
01246     hpiaAfterCalc = dspAddr;
01247   } 
01248   else  {
01249     hpiaAfterCalc = dspAddr+wordCount*4-4;
01250   }
01251   
01252 /*  if (hpiaAfterFetch != hpiaAfterCalc) {
01253     throw HpiException("mdspBlockWrite address check failed", hpiaAfterCalc, 
01254                         hpiaAfterFetch);
01255   }
01256 */  
01257   return;
01258 };
01259 
01260 //------------------------------resetMasterDsp--------------------------------                                
01261 
01262 void RodModule::resetMasterDsp() throw(RodException&, VmeException &) {
01263   unsigned long value=0;
01264   unsigned long rodRegValue;
01265   clock_t startTime;
01266   
01267   rodRegValue = readRodStatusReg(0);
01268   setBit(&value, 1);
01269   if (endianSwap) {
01270     value = endianReverse32(value);
01271   }
01272   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[2], value);
01273   sleep(4000);
01274   rodRegValue = 0;
01275   startTime = clock();
01276   do {
01277     rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
01278     if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
01279       throw RodException("DSP reset timeout in resetMasterDsp(), DSP_RESET_TIMEOUT=",
01280       (long)DSP_RESET_TIMEOUT);
01281     }
01282   }
01283   while (rodRegValue != 0x3e);
01284   rodRegValue = readRodStatusReg(0);
01285   
01286   return;
01287 };
01288 
01289 //------------------------------resetSlaveDsp--------------------------------                                
01290 
01291 void RodModule::resetSlaveDsp(long slaveNumber) throw(RodException&, VmeException &) {
01292   unsigned long value=0;
01293   unsigned long rodRegValue;
01294   clock_t startTime;
01295   
01296   setBit(&value, 2+slaveNumber);
01297   if (endianSwap) {
01298     value = endianReverse32(value);
01299   }
01300   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[2], value);
01301   sleep(4000);
01302   rodRegValue = 0;
01303   startTime = clock();
01304   do {
01305     rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
01306     if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
01307       throw RodException("DSP reset timeout in resetSlaveDsp(), DSP_RESET_TIMEOUT=",
01308       (long)DSP_RESET_TIMEOUT);
01309     }
01310   }
01311   while (rodRegValue != 0x3e);
01312   
01313   return;
01314 };
01315 
01316 
01317 //------------------------------resetAllDsps--------------------------------                                
01318 
01319 void RodModule::resetAllDsps() throw(RodException &, VmeException &) {
01320   unsigned long value=0;
01321   unsigned long rodRegValue;
01322   clock_t startTime;
01323   
01324   setBit(&value, 6);
01325   if (endianSwap) {
01326     value = endianReverse32(value);
01327   }
01328   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[2], value);
01329   sleep(4000);
01330   rodRegValue = 0;
01331   startTime = clock();
01332   do {
01333     rodRegValue = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[2]);
01334     if ((clock()-startTime)/CLOCKS_PER_SEC > DSP_RESET_TIMEOUT) {
01335       throw RodException("DSP reset timeout in resetAllDsps(), DSP_RESET_TIMEOUT=",
01336       (long)DSP_RESET_TIMEOUT);
01337     }
01338   }
01339   while (rodRegValue != 0x3e);
01340   
01341   return;
01342 };
01343 
01344 //-------------------------------chipEraseHpi---------------------------------
01345 
01346 void RodModule::chipEraseHpi() throw(VmeException &) {
01347   unsigned long value = 0x10;
01348   
01349 // Commands 1 to 5
01350   commonEraseCommandsHpi(MDSP_FLASH_BOTTOM);
01351   
01352 // Command 6
01353   mdspSingleWrite(MDSP_FLASH_BOTTOM+(0x5555<<2), value);
01354   
01355 // Wait for operation to complete
01356   sleep(CHIP_ERASE_TIME_MS);
01357   return;
01358 };
01359   
01360 //--------------------------------sectorErase---------------------------------
01361 
01362 void RodModule::sectorErase(unsigned long sectorBaseAddress) 
01363                             throw(RodException &, VmeException &) {
01364   unsigned long flashBaseAddress, valueD32;
01365   bool busyBit;
01366 
01367 // Get flash base address
01368   switch (m_revision) {
01369     case 0x0f:
01370     case 0x0e: 
01371       flashBaseAddress = FPGA_FLASH_REL_ADDR_REVE;
01372       break;
01373     case 0x0b:
01374     case 0x0c:
01375     default: 
01376       if ((sectorBaseAddress<FPGA_FLASH_0_BOTTOM)||
01377             (sectorBaseAddress>FPGA_FLASH_2_BOTTOM+FLASH_MEMORY_SIZE)) {
01378         throw RodException("Flash sector base addr out of range, sectorBaseAddress=",
01379              sectorBaseAddress);
01380       }
01381       if (sectorBaseAddress<FPGA_FLASH_1_BOTTOM) {
01382         flashBaseAddress = FPGA_FLASH_0_BOTTOM;
01383       }
01384       else if (sectorBaseAddress<FPGA_FLASH_2_BOTTOM) {
01385         flashBaseAddress = FPGA_FLASH_1_BOTTOM;
01386       }
01387       else flashBaseAddress = FPGA_FLASH_2_BOTTOM;
01388       break;
01389   }
01390 // Commands 1 to 5
01391   commonEraseCommands(flashBaseAddress);
01392   
01393 // Set write bit
01394   vmeWriteElementFlash(0x30, sectorBaseAddress, WRITE_COMMAND_HANDSHAKE_BIT);
01395   
01396 // Wait for operation to complete
01397   switch (m_revision ) {
01398     case 0x0f:
01399     case 0x0e:
01400       do {                           /* Poll busy */ 
01401         valueD32 = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[4]); 
01402         busyBit = readBit(valueD32, 3);                
01403       } while (busyBit);
01404       break;
01405     case 0x0b:
01406     case 0x0c: 
01407     default:
01408       sleep(SECTOR_ERASE_TIME_MS);
01409       break;
01410   }
01411 
01412   return;
01413 };
01414   
01415 //---------------_-------------writeByteToFlash-------------------------------
01416 
01417 void RodModule::writeByteToFlash(unsigned long address, UINT8 data) 
01418                             throw (RodException &, VmeException &) {
01419   UINT8 readData;
01420   clock_t startTime;   // start time for DQ7 data polling, in seconds
01421   long updateAddress;
01422   
01423   if (data!=0xFF) {   // if erased, don't rewrite. 0xFF is default after erasing
01424 // write data
01425     vmeWriteElementFlash(data, address, WRITE_DATA_HANDSHAKE_BIT);
01426     updateAddress = 0;
01427   }
01428   else {
01429     updateAddress = 1;
01430   }
01431   
01432 // Wait for operation to complete - data polling
01433   startTime = clock();
01434   while(1) {
01435     readData = readByteFromFlash(address, updateAddress);
01436     if (readData == data) return;
01437     else if((clock()-startTime)/CLOCKS_PER_SEC > FLASH_TIMEOUT) {
01438       throw RodException("Flash timeout in writeByteToFlash, FLASH_TIMEOUT=",
01439       (long)FLASH_TIMEOUT);
01440     }
01441   }
01442   return;
01443 };
01444 
01445 //----------------------------writeBlockToFlash-------------------------------
01446 
01447 void RodModule::writeBlockToFlash(unsigned long address, UINT8 *data, 
01448                                unsigned long numBytes) throw(RodException &, VmeException &) {
01449   unsigned long index, sectorSize;
01450   switch (m_revision) {
01451     case 0x0f:
01452     case 0x0e:
01453       sectorSize = FLASH_SECTOR_SIZE_REVE;
01454       break;
01455     case 0x0b:
01456     case 0x0c:
01457     default:
01458       sectorSize = FLASH_SECTOR_SIZE;
01459       break;
01460   }
01461   for (index=0; index<numBytes; ++index) {
01462     if ((index%sectorSize)==0) {
01463       sectorErase(address+index);
01464     }
01465     writeByteToFlash(address+index, *(data+index));
01466   } 
01467   return;
01468 };
01469   
01470 //---------------------------writeBlockToFlashHpi-----------------------------
01471 
01472 void RodModule::writeBlockToFlashHpi(unsigned long address, UINT8 *data, 
01473      unsigned long numBytes) throw (RodException &, VmeException &) {
01474   unsigned long index, sectorAddr;
01475   const unsigned long eraseData=0x30;
01476   const unsigned long data1=0xAA;
01477   const unsigned long data2=0x55;
01478   const unsigned long data3=0xA0;
01479   const unsigned long addr1=MDSP_FLASH_BOTTOM+(0x5555<<2);
01480   const unsigned long addr2=MDSP_FLASH_BOTTOM+(0x2AAA<<2);
01481   unsigned long byteRelAddr;
01482   long words;
01483   UINT8 dataVal, verifyVal;
01484   unsigned long longVal, busyVal;
01485   
01486   for (index=0; index<numBytes; ++index) {
01487     byteRelAddr = address+index-MDSP_FLASH_BOTTOM;
01488     if ((index%FLASH_SECTOR_SIZE)==0) {
01489 // implement sectorEraseHpi(address+index) inline.
01490 //    commands 1 to 5
01491       commonEraseCommandsHpi(MDSP_FLASH_BOTTOM);
01492 // 6th command
01493       sectorAddr = MDSP_FLASH_BOTTOM+
01494                   (byteRelAddr<<2);
01495       mdspSingleWrite(sectorAddr, eraseData);
01496 // Wait for operation to complete
01497       sleep(SECTOR_ERASE_TIME_MS);
01498     };
01499  
01500 // implement writeByteToFlashHpi(address+index, *(data+index)) inline.
01501     dataVal = *(data+index);
01502     longVal = dataVal&0x000000FF;
01503     if (dataVal != 0xFF) {
01504       mdspSingleWrite(addr1, data1);                      // 1st command
01505       mdspSingleWrite(addr2, data2);                      // 2nd command
01506       mdspSingleWrite(addr1, data3);                      // 3rd command
01507       mdspSingleWrite(MDSP_FLASH_BOTTOM+(byteRelAddr<<2), longVal);
01508 // Verify data by reading it back before continuing. Flash memory may need up to
01509 // 20 microseconds to complete the write sequence.
01510       for (int i=0; i<4000; i++) {
01511         busyVal = mdspSingleRead(MDSP_FLASH_BOTTOM+byteRelAddr);
01512         switch (byteRelAddr%4) {
01513           case 1: busyVal = busyVal >> 8;
01514                   break;
01515           case 2: busyVal = busyVal >> 16;
01516                   break;
01517           case 3: busyVal = busyVal >> 24;
01518                   break;
01519           default: break;
01520         }
01521         busyVal = busyVal & 0x000000FF;
01522         if (busyVal == longVal) break;
01523       }
01524     };
01525   };
01526     
01527 // Verification
01528   words = (numBytes+3)/4;       // round up
01529   UINT8 *buffer;
01530   try {
01531     buffer = new UINT8[words*4];
01532   }
01533   catch (std::bad_alloc & ba) {
01534     throw RodException("writeBlockToFlashHpi unable to get buffer.");
01535   }
01536   mdspBlockRead(address, (unsigned long*)buffer, words);
01537   for (index=0; index<numBytes; ++index) {
01538     dataVal = *(data+index);
01539     verifyVal = *(buffer+index);
01540     if (dataVal != verifyVal) {
01541       delete [] buffer;
01542       throw RodException("writeBlockToFlashHpi verify failed. index, data:", index,
01543                  dataVal);
01544     };
01545   }
01546   delete [] buffer;
01547   return;
01548 };
01549   
01550 //-----------------------------readByteFromFlash------------------------------
01551 
01552 UINT8 RodModule::readByteFromFlash(unsigned long address, long updateAddress) 
01553                  throw (RodException &, VmeException &){
01554   UINT8 dataByte;
01555   unsigned long commandReg;
01556   clock_t startTime;
01557   unsigned long handshakeBitValue = 0;
01558   unsigned long valueD32;
01559   
01560   if (updateAddress) {
01561     m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[4], address);
01562   }
01563 // Set rd bit
01564     setBit(&handshakeBitValue, READ_HANDSHAKE_BIT);
01565     m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[3], handshakeBitValue);
01566     
01567 // Wait for valid data
01568     startTime = clock();
01569     while (1) {
01570       commandReg = m_myVmePort->read32(FPGA_CONTROL_REG_REL_ADDR[3]);
01571       if (0==readBit(commandReg, READ_HANDSHAKE_BIT)) break;
01572       if ((clock()-startTime)>FLASH_TIMEOUT) throw RodException(
01573                           "Timeout in readByteFromFlash. Address=", address);
01574     }
01575     
01576 // Read valid data
01577   valueD32 = m_myVmePort->read32(FPGA_STATUS_REG_REL_ADDR[7]); 
01578   dataByte = (UINT8)(valueD32&0xFF);
01579   return dataByte;
01580 };
01581   
01582 //---------------------------vmeWriteElementFlash------------------------------
01583 
01584 void RodModule::vmeWriteElementFlash(UINT8 value, unsigned long address, 
01585            long handshakeBit) throw (RodException &, VmeException &) {
01586   unsigned long ctrlReg4Val;  // address(23:0) + data(31:24)
01587   unsigned long commandReg;
01588   clock_t startTime;
01589   unsigned long handshakeBitValue=0;
01590   
01591   ctrlReg4Val = (value<<24)| address;
01592   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[4], ctrlReg4Val);
01593 
01594 // Set wr bit
01595   setBit(&handshakeBitValue, handshakeBit);
01596   m_myVmePort->write32(FPGA_CONTROL_REG_REL_ADDR[3], handshakeBitValue);
01597 
01598 // Wait for ack
01599   startTime = clock();
01600   while(1) {
01601       commandReg = m_myVmePort->read32(FPGA_CONTROL_REG_REL_ADDR[3]);
01602       if (0==readBit(commandReg, handshakeBit)) break;
01603       if ((clock()-startTime)>FLASH_TIMEOUT) throw RodException(
01604                    "Timeout in vmeWriteElementFlash. Address, value=", 
01605                    address, (unsigned long)value);
01606   }
01607   return;   
01608 };
01609 
01610 //-----------------------------readBlockFromFlash------------------------------
01611 
01612 void RodModule::readBlockFromFlash(unsigned long address, UINT8 *buffer, 
01613                                    unsigned long numBytes) throw(RodException &, VmeException &) {
01614   unsigned long index;
01615   for (index=0; index<numBytes; ++index) {
01616     buffer[index] = readByteFromFlash(address+index, 1);
01617   }
01618   return;
01619 };
01620   
01621 //-----------------------------commonEraseCommands----------------------------
01622 
01623 void RodModule::commonEraseCommands(unsigned long flashBaseAddr) 
01624                                            throw(RodException &, VmeException &) {
01625 
01626   const unsigned long addr1 = flashBaseAddr+0x5555;
01627   const unsigned long addr2 = flashBaseAddr+0x2AAA;
01628   
01629 // 1st command
01630   vmeWriteElementFlash(0xAA, addr1, WRITE_COMMAND_HANDSHAKE_BIT);
01631   
01632 // 2nd command
01633   vmeWriteElementFlash(0x55, addr2, WRITE_COMMAND_HANDSHAKE_BIT);
01634 
01635 // 3rd command
01636   vmeWriteElementFlash(0x80, addr1, WRITE_COMMAND_HANDSHAKE_BIT);
01637   
01638 // 4th command
01639   vmeWriteElementFlash(0xAA, addr1, WRITE_COMMAND_HANDSHAKE_BIT);
01640 
01641 // 5th command
01642   vmeWriteElementFlash(0x55, addr2, WRITE_COMMAND_HANDSHAKE_BIT);
01643 
01644   return;
01645 };
01646 
01647 //----------------------------commonEraseCommandsHpi--------------------------
01648 
01649 void RodModule::commonEraseCommandsHpi(unsigned long flashBaseAddr) 
01650                                               throw(VmeException &) {
01651 
01652   unsigned long buffer;
01653   const unsigned long addr1 = flashBaseAddr+(0x5555<<2);
01654   const unsigned long addr2 = flashBaseAddr+(0x2AAA<<2);
01655   
01656 // 1st command
01657   buffer = 0xAA;
01658   mdspSingleWrite(addr1, buffer);
01659   
01660 // 2nd command
01661   buffer = 0x55;
01662   mdspSingleWrite(addr2, buffer);
01663 
01664 // 3rd command
01665   buffer = 0x80;
01666   mdspSingleWrite(addr1, buffer);
01667   
01668 // 4th command
01669   buffer = 0xAA;
01670   mdspSingleWrite(addr1, buffer);
01671 
01672 // 5th command
01673   buffer = 0x55;
01674   mdspSingleWrite(addr2, buffer);
01675 
01676   return;
01677 };
01678 
01679 //---------------------------getFlashSectorSize---------------------------                                
01680 
01681   unsigned long RodModule::getFlashSectorSize() {
01682   unsigned long sectorSize;
01683   switch (m_revision) {
01684     case 0x0f:
01685     case 0x0e:
01686       sectorSize = FLASH_SECTOR_SIZE_REVE;
01687       break;
01688     case 0x0b:
01689     case 0x0c:
01690     default:
01691       sectorSize = FLASH_SECTOR_SIZE;
01692       break;
01693   }
01694   return sectorSize;
01695 };
01696 
01697 //----------------------------------sleep-------------------------------------                                
01698 
01699 void RodModule::sleep(const double milliSecs) {
01700   clock_t start, delay;
01701   delay = CLOCKS_PER_SEC;
01702   delay = clock_t(milliSecs * CLOCKS_PER_SEC / 1000 ); //need explicit type cast
01703                                                        //to avoid warning.
01704   start = clock();
01705   while (clock()-start< delay)   // wait until time elapses
01706      ;
01707   return;
01708 };
01709   
01710 //--------------------------------checkSum------------------------------------                                
01711 
01712 unsigned long RodModule::checkSum(const unsigned long *sourceArray, const long wordCount) {
01713   unsigned long result=0;
01714   long i;
01715   
01716   for (i=0; i<wordCount; ++i) {
01717     result ^= sourceArray[i];
01718   }
01719   return result;
01720 };
01721  
01722 //-----------------------------endianReverse32----------------------------------                                
01723 
01724 unsigned long RodModule::endianReverse32(const unsigned long inVal) {
01725   unsigned long outVal;
01726   outVal  = (inVal & 0x000000ff) << 24;
01727   outVal |= (inVal & 0x0000ff00) << 8;
01728   outVal |= (inVal & 0x00ff0000) >> 8;
01729   outVal |= (inVal & 0xff000000) >> 24;
01730   return outVal;
01731 };
01732   
01733 } //  End namespace SctPixelRod
01734 
01735 //------------------------- Overload insertion operators "<<" -------------------------
01736 /* This overloaded operator lets us use cout to print the status of the ROD
01737 */
01738   std::ostream& operator<<(std::ostream& os, SctPixelRod::RodModule& rod) {
01739     os << "Slot: " << rod.getSlot() << std::endl;
01740     os << "Serial Number:" << rod.getSerialNumber() << std::endl;
01741     os << "Number of slave DSPs: " << rod.getNumSlaves() << std::endl;
01742     os << "Status registers[0-2]: ";
01743     try {
01744       for (int i=0; i<3; i++) {
01745         os << std::hex << rod.readRodStatusReg(i) << " ";
01746       }
01747       os << std::endl;
01748     }
01749     catch (SctPixelRod::VmeException &) {
01750       os << "VmeException while reading ROD status registers. " << std::endl;
01751     }
01752     
01753     os << "Command registers[0-1]: ";
01754     try {
01755       for (int i=0; i<2; i++) {
01756         os << std::hex << rod.readRodCommandReg(i) << " ";
01757       }
01758       os << std::endl;
01759     }
01760     catch (SctPixelRod::VmeException &) {
01761       os << "VmeException while reading ROD command registers. " << std::endl;
01762     }
01763 
01764     os << "Primitive state: " << rod.getPrimState() << " Text State: " << 
01765           rod.getTextState() << std::dec << std::endl;
01766     return os;
01767   }
01768 
01769 /* This overloaded operator lets us use cout to print the RodException information. We use the virtual
01770  * what() method to get the information from the derived class instead of BaseException.
01771 */
01772 /*  std::ostream& operator<<(std::ostream& os, SctPixelRod::RodException& rodEx) {
01773     return rodEx.what(os, rodEx);
01774   }
01775 */
01776 /* This overloaded operator lets us use cout to print the HpiException information
01777 */
01778 /*  std::ostream& operator<<(std::ostream& os, SctPixelRod::HpiException& hpiEx) {
01779     return hpiEx.what(os,hpiEx);
01780   }
01781 */
01782 /* This overloaded operator lets us use cout to print the NoImagerFile exception information
01783 */
01784 /*  std::ostream& operator<<(std::ostream& os, SctPixelRod::NoImageFile& imaEx) {
01785     return imaEx.what(os, imaEx);
01786   }
01787 */
01788 

Generated on Fri Sep 16 18:01:55 2005 for SCT DAQ/DCS Software - C++ by doxygen 1.3.5