/******************************************************************************* * Pupe.cc Pupe process * T.Barnaby, BEAM Ltd, 2007-02-13 ******************************************************************************* */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Build Options */ #define USE_DMA 1 #define ALL_CHANNELS 1 /* Debug options */ #define TEST_TESTDATA 1 #define DISABLE_BLR 0 #define SYSCLK_INTERNAL 0 #define DEBUG_CTRL 0 #define DEBUG_DATA 0 const int diagnosticsTimeout = 1000; // The diagnostics timeout in 10ms steps // FPGA Control Registers const int IMEM_REG = 0x0000 >> 2; // Block RAM Index const int LOCKED = 0x0008 >> 2; // DCM Locked Status const int ADDR_REG = 0x0010 >> 2; // PAGE Register for SDRAM access const int MEM_REG = 0x0018 >> 2; // SDRAM Bank Select Register and BlockRam enable const int IER = 0x0020 >> 2; // Interrupt Enable Register const int ISR = 0x0028 >> 2; // Interrupt Status Register const int MEM_RAS = 0x0030 >> 2; // SDRAM Read Address Scaling const int MEM_RAO = 0x0038 >> 2; // SDRAM Read Address Offset const int SYNTH_CNTRL_REG = 0x0080 >> 2; // ADC PLL Registers const int SYNTH_WSTB_REG = 0x0088 >> 2; // ADC PLL Registers const int SYNTH_RESET = 0x0090 >> 2; // ADC PLL Registers const int MEM_GNT0 = 0x0400 >> 2; // Memory Grant Registers const int MEM_GNT1 = 0x0408 >> 2; // Memory Grant Registers const int MEM_GNT2 = 0x0410 >> 2; // Memory Grant Registers const int MEM_GNT3 = 0x0408 >> 2; // Memory Grant Registers const int FIRMWARE = 0x0800 >> 2; // Firmware ID code "CN" + version numbers const int ADC = 0x0808 >> 2; // ADC Control Register const int TIMING_IO = 0x0810 >> 2; // Timing I/O Register const int TESTCTRL = 0x0818 >> 2; // Test Data Control Register const int TESTLEN = 0x0820 >> 2; // Test Data Pattern Length // Per Pick-Up registers const int PU0_REG_BASE = 0x0880 >> 2; // PickUp 0 Register Base const int PU1_REG_BASE = 0x0900 >> 2; // PickUp 1 Register Base const int PU2_REG_BASE = 0x0980 >> 2; // PickUp 2 Register Base const int CONTROL = 0x0000 >> 2; // PU General Control and Status register const int CYCLE = 0x0008 >> 2; // Cycle number const int TIME = 0x0010 >> 2; // Time in ms from start of cycle const int TIME_TBLADDR = 0x0018 >> 2; // Last write address in timing table const int PLL_FREQUENCY = 0x0020 >> 2; // PLL Reference orbit frequency const int PLL_FREQDELAY = 0x0028 >> 2; // PLL frequency load delay const int PLL_PHASEDELAY = 0x0030 >> 2; // PLL phase delay const int PLL_GAIN = 0x0038 >> 2; // PLL gain const int DDS_FREQ_MIN = 0x0040 >> 2; // PLL DDS minimum frequency const int DDS_FREQ_MAX = 0x0048 >> 2; // PLL DDS maximum frequency const int DIAG_CTRL = 0x0050 >> 2; // Diagnostics Control/Status const int DIAG_TRIGGER = 0x0058 >> 2; // Diagnostics Trigger const int TEST = 0x0060 >> 2; // Timing Test // Memory access window const int FPGA_DATA_ADDRESS = 0x200000; // The FPGA memory const int FPGA_MEM = 0x200000 >> 2; // The FPGA memory // SDRAM Data Banks const int SDRAM_DATA_PU0 = 0x08; // PickUp 0 data const int SDRAM_DATA_PU1 = 0x09; // PickUp 1 data const int SDRAM_DATA_PU2 = 0x0A; // PickUp 2 data const int SDRAM_DATA_TEST = 0x0B; // Test input data const int SDRAM_BLOCKRAM = 0x00; // FPGA Memory const int PU0_BRAM_BASE = 0; // PickUp 0 Block Ram ID base const int PU1_BRAM_BASE = 8; // PickUp 0 Block Ram ID base const int PU2_BRAM_BASE = 16; // PickUp 0 Block Ram ID base const int BRAM_CYCLE_TIMING = 0; // Cycle Timing Table const int BRAM_CYCLE_INFO = 1; // Cycle Information Table const int BRAM_PHASE_TABLE = 2; // Timing Phase Table const int BRAM_SWITCH_TABLE = 3; // Timing Switch Table const int BRAM_DIAG_TABLE = 4; // Diagnostics table const int BRAM_BUNCH_MEAN0 = 5; // Bunch Mean Table #0 const int BRAM_BUNCH_MEAN1 = 6; // Bunch Mean Table #1 // Control register bits const int CONTROL_INIT = 0x01; // Reset's PLL and State/Phase tables const int CONTROL_LOOP_CONTROL = 0x02; // Disables PLL feedback const int CONTROL_DDS_FREQUENCY_LIMIT_ENABLE = 0x04; // Enables PLL frequency limits const int CONTROL_BLR_DISABLE = 0x08; // Disables the BLR algorithm // Interrupt bits const int INT_PU0_CYCLE_START = (1<<0); // 0 PU #0 CYCLE_START const int INT_PU0_CYCLE_STOP = (1<<1); // 1 PU #0 CYCLE_STOP const int INT_PU0_ERROR = (1<<2); // 2 PU #0 ERROR const int INT_PU0_DIAG = (1<<3); // 3 PU #0 DIAGNOSTIC INFO CAPTURED const int INT_PU0_WRITE_FIFO = (1<<4); // 4 PU #0 SDRAM Write FIFO Half Full const int INT_PU0_USER0 = (1<<5); // 5 PU #0 User Interrupts (Switch Table bits 5) const int INT_PU0_USER1 = (1<<6); // 6 PU #0 User Interrupts (Switch Table bits 6) const int INT_PU0_USER2 = (1<<7); // 7 PU #0 User Interrupts (Switch Table bits 7) const int INT_PU1_CYCLE_START = (1<<8); // 8 PU #1 CYCLE_START const int INT_PU1_CYCLE_STOP = (1<<9); // 9 PU #1 CYCLE_STOP const int INT_PU1_ERROR = (1<<10); // 10 PU #1 ERROR const int INT_PU1_DIAG = (1<<11); // 11 PU #1 DIAGNOSTIC INFO CAPTURED const int INT_PU1_WRITE_FIFO = (1<<12); // 12 PU #1 SDRAM Write FIFO Half Full const int INT_PU1_USER0 = (1<<13); // 13 PU #1 User Interrupts (Switch Table bits 5) const int INT_PU1_USER1 = (1<<14); // 14 PU #1 User Interrupts (Switch Table bits 6) const int INT_PU1_USER2 = (1<<15); // 15 PU #1 User Interrupts (Switch Table bits 7) const int INT_PU2_CYCLE_START = (1<<16); // 16 PU #2 CYCLE_START const int INT_PU2_CYCLE_STOP = (1<<17); // 17 PU #2 CYCLE_STOP const int INT_PU2_ERROR = (1<<18); // 18 PU #2 ERROR const int INT_PU2_DIAG = (1<<19); // 19 PU #2 DIAGNOSTIC INFO CAPTURED const int INT_PU2_WRITE_FIFO = (1<<20); // 20 PU #2 SDRAM Write FIFO Half Full const int INT_PU2_USER0 = (1<<21); // 21 PU #2 User Interrupts (Switch Table bits 5) const int INT_PU2_USER1 = (1<<22); // 22 PU #2 User Interrupts (Switch Table bits 6) const int INT_PU2_USER2 = (1<<23); // 23 PU #2 User Interrupts (Switch Table bits 7) // FPGA Control Space Registers const int SYSMON_CTL = (0x00400 >> 2); const int SYSMON_BUF = (0x00500 >> 2); const int SYSMON_SMB_ERROR = (0x10000000); /// 64bit memory copy function for PUPE board 64bit data access static inline int memcpy_64(void* to, const void* from, size_t len){ size_t i; // Check alignment and size if(((unsigned int)to & 0x07) || ((unsigned int)from & 0x07) || (len & 0x07)){ fprintf(stderr, "memcpy_mmx: Memory pointers and length need to be aligned to 64bit boundary\n"); return 1; } i = len / 8; while(i--){ __asm__ __volatile__ ( "movq (%0), %%mm0\n" "movq %%mm0, (%1)\n" :: "r" (from), "r" (to) : "memory"); from = ((const unsigned char *)from) + 8; to = ((unsigned char *)to) + 8; } __asm__ __volatile__ ("emms":::"memory"); return 0; } PupeInterruptThread::PupeInterruptThread(Pupe& pupe) : opupe(pupe){ } void* PupeInterruptThread::function(){ dprintf(DBG_THREADS, "InterruptThread Thread: %d\n", gettid()); opupe.fpgaInterruptLoop(); return 0; } Pupe::Pupe(Control& control, int board) : ocontrol(control), ointerruptThread(*this){ osimulate = 0; omaster = 0; oboard = board; ofpgaCard = 0; ofpga = 0; ofpgaControl = 0; ocycleNumberNext = 0; ocycleNumber = 0; ocycleCompletedNumber = 0; opuCycleNumbers[0] = 0; opuCycleNumbers[1] = 0; opuCycleNumbers[2] = 0; opageSize = 2*1024*1024; odmaBufferSize = opageSize; odmaBuffer = new UInt64 [odmaBufferSize/sizeof(UInt64)]; odmabuf = 0; memset(&opupeConfig, 0, sizeof(opupeConfig)); opupeConfig.internalTimingMask = ocontrol.osimulateTiming; ostatus.set(ErrorFpga, "Not initialised"); ocycleCount = 0; } Pupe::~Pupe(){ if(!osimulate){ fpgaClose(); } } BError Pupe::init(){ BError err; if(config.findValue("SimulateFpga:").retInt() == 1) osimulate = 1; olock.lock(); if(!osimulate){ if(oinitialised){ fpgaClose(); oinitialised = 0; } if( ! (err = fpgaInit())){ oinitialised = 1; } } ostatus = err; olock.unlock(); return err; } BError Pupe::status(){ BError err; olock.lock(); err = ostatus.copy(); olock.unlock(); return err; } BError Pupe::setMaster(int on){ BError err; if(!osimulate){ if(on) ofpga[TIMING_IO] = ofpga[TIMING_IO] | (1 << 29); else ofpga[TIMING_IO] = ofpga[TIMING_IO] & ~0xFF000000; } omaster = on; return err; } BError Pupe::setNextCycle(UInt32 cycleNumber, BString cycleType){ BError err; olock.lock(); ocycleNumberNext = cycleNumber; olock.unlock(); return err; } BError Pupe::setControlInfo(PuChannel puChannel, CycleParam params){ BError err; int n; dprintf(DBG_PUPE, "Pupe::setControlInfo: %u.%u.%u\n", puChannel.moduleNum, puChannel.pupeNum, puChannel.pupeChan); if(ofpgaCard){ olock.lock(); if(puChannel.pupeChan == 0){ for(n = 1; (n < numChan + 1) && !err; n++){ puChannel.pupeChan = n; err = setControlInfoPickUp(puChannel, params); } } else if((puChannel.pupeChan > 0) && (puChannel.pupeChan < numChan + 1)){ err = setControlInfoPickUp(puChannel, params); } else { olock.unlock(); return err.set(ErrorParam, "Incorrect puChannel"); } olock.unlock(); } return err; } void Pupe::setNumBunches(PuChannel puChannel, CycleParam params){ UInt32 s; UInt32 h; UInt32 p = puChannel.pupeChan - 1; TmsState state; onumBunches[p].assign(9, 0); onumBunches[p][0] = params.stateTable[0].numBunches; for(s = 0, h = 0; s < params.stateTable.size(); s++){ state.value = params.stateTable[s].state; if(state.calStart < 14){ onumBunches[p][1] = params.stateTable[state.calStart].numBunches; } else if(state.injection < 14){ onumBunches[p][2] = params.stateTable[state.injection].numBunches; h++; } else if(state.hchange < 14){ onumBunches[p][2 + h] = params.stateTable[state.hchange].numBunches; h++; } } #ifdef ZAP for(s = 0; s < onumBunches[p].size(); s++){ printf("NumBunches: %d: %d\n", s, onumBunches[p][s]); } #endif } BError Pupe::setControlInfoPickUp(PuChannel puChannel, CycleParam params){ BError err; UInt32 regBase = 0; UInt32 brBase = 0; UInt32 n; UInt32 logicalPuChannel = 1; UInt32 stateTable[14]; #if !ALL_CHANNELS if(puChannel.pupeChan != 1) return err; #endif dprintf(DBG_FPGA, "Pupe::setControlInfoPickUp: PupeChan: %d Type: %s\n", puChannel.pupeChan, params.cycleType.retStr()); switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } #ifdef ZAP if(puChannel.pupeChan == 1) dumpState(); #endif puChannel.moduleNum = ocontrol.moduleNum(); if(ocontrol.getPuChannel(puChannel, logicalPuChannel)) logicalPuChannel = 1; #if DEBUG_CTRL //params.pllGain = 10; //params.frefPhaseDelay[logicalPuChannel - 1] = 128; printf("pllInitialFrequencyDelay: %d\n", params.pllInitialFrequencyDelay); printf("pllFrefGain: %d\n", params.pllFrefGain); printf("pllGain: %d\n", params.pllGain); printf("frefPhaseDelay: %d\n", params.frefPhaseDelay[logicalPuChannel - 1]); printf("FrefMsbSource: %d\n", params.stateTable[0].state & 0x10); #endif if(!osimulate){ ofpga[regBase + PLL_PHASEDELAY] = 128 + params.frefPhaseDelay[logicalPuChannel - 1]; ofpga[regBase + PLL_FREQUENCY] = params.pllInitialFrequency; ofpga[regBase + PLL_FREQDELAY] = params.pllInitialFrequencyDelay; ofpga[regBase + PLL_GAIN] = (params.pllGain << 16) | (params.pllFrefGain & 0xFFFF); ofpga[regBase + DDS_FREQ_MIN] = params.pllDdsMinimum; ofpga[regBase + DDS_FREQ_MAX] = params.pllDdsMaximum; // Write State and Phase Tables ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = brBase + BRAM_SWITCH_TABLE; for(n = 0; n < 14; n++){ if(n < params.stateTable.size()) stateTable[n] = params.stateTable[n].state; else stateTable[n] = 0x0eeeee00; } fpgaWriteData64(stateTable, 0, sizeof(stateTable)); ofpga[IMEM_REG] = brBase + BRAM_PHASE_TABLE; for(n = 0; (n < 14) && (n < params.stateTable.size()); n++){ fpgaWriteData64(params.stateTable[n].phaseTable.data(), n * 512, 512); } if(params.pllDdsMinimum || params.pllDdsMaximum){ if(! (ofpga[regBase + CONTROL] & CONTROL_DDS_FREQUENCY_LIMIT_ENABLE)) ofpga[regBase + CONTROL] |= CONTROL_DDS_FREQUENCY_LIMIT_ENABLE; } else { if(ofpga[regBase + CONTROL] & CONTROL_DDS_FREQUENCY_LIMIT_ENABLE) ofpga[regBase + CONTROL] &= ~CONTROL_DDS_FREQUENCY_LIMIT_ENABLE; } } ocycleParam[puChannel.pupeChan - 1] = params; setNumBunches(puChannel, params); #ifdef ZAP if(puChannel.pupeChan == 1) dumpState(); #endif dprintf(DBG_FPGA, "Pupe::setControlInfoPickUp: End\n"); return err; } BError Pupe::getStatusList(PuChannel puChannel, BList& statusList){ BError err; BString baseName = BString("TmsPuServer") + ocontrol.moduleNum() + "_Pupe" + oboard; BList il; BIter i; err = status(); olock.lock(); if(!err) statusList.append(NameValue(baseName + "_Running", "1")); else statusList.append(NameValue(baseName + "_Running", "0")); statusList.append(NameValue(baseName + "_Error", err.getString())); fpgaGetInfo(il); for(il.start(i); !il.isEnd(i); il.next(i)){ statusList.append(NameValue(baseName + "_" + il[i].name, il[i].value)); } olock.unlock(); return err; } BError Pupe::getStatus(PuChannel puChannel, PuStatus& puStatus){ BError err; err = status(); olock.lock(); if(!err) puStatus.running = 1; else puStatus.running = 0; puStatus.error = err; olock.unlock(); return err; } BError Pupe::checkData(UInt32 cycleNumber){ BError err; Int32 diff; // In the initial state we need to check if we have actually captured the cycle // We also need to check here when the cycle number wraps. // First check if we are within the possible cycle range diff = cycleNumber - ocycleCompletedNumber; if(diff < -4) return err.set(ErrorDataGone, "Cycle's data has already been overwritten"); if(diff > 0) return err.set(ErrorDataFuture, "Cycle data required is to far in the future"); return err; } BError Pupe::getData(PuChannel puChannel, DataInfo dataInfo, Data& data){ BError err; int regBase; int brBase; uint32_t cycleTimingAddress = 0; int32_t diff; uint64_t cycleTimingEntry; uint32_t cycleDataAddress; int i; int e; int ph = 0; int h; int found = 0; int nbunchesPerOrbit = 0; uint32_t pupeCycleNumber; int timeOut; dprintf(DBG_FPGA, "Pupe::getData: RequiredCycleNumber: %u CurrentCycleNumber: %u LastCompletedCycle: %u\n", dataInfo.cycleNumber, ocycleNumber, ocycleCompletedNumber); switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorParam, "Incorrect puChan"); } olock.lock(); // Return an error if already gone or to far in the future if(err = checkData(dataInfo.cycleNumber)){ olock.unlock(); return err; } if(osimulate){ err = getSimData(dataInfo, data); } else { data.dataValues.resize(dataInfo.numValues); data.numValues = dataInfo.numValues; // Get Cycle information ofpga[MEM_REG] = SDRAM_BLOCKRAM; // Need to test if the cycle number has changed while we read the following two data tables timeOut = 1; do { pupeCycleNumber = ofpga[PU0_REG_BASE + CYCLE]; ofpga[IMEM_REG] = brBase + BRAM_CYCLE_INFO; fpgaReadData64(0, ocycleInfoTable, sizeof(ocycleInfoTable)); ofpga[IMEM_REG] = brBase + BRAM_CYCLE_TIMING; fpgaReadData64(0, ocycleTimingTable, sizeof(ocycleTimingTable)); } while(timeOut-- && (pupeCycleNumber != ofpga[PU0_REG_BASE + CYCLE])); if(timeOut < 0){ olock.unlock(); return err.set(ErrorFpga, "Timed out while getting Cycle Information tables"); } // Return an error if already gone or to far in the future if(err = checkData(dataInfo.cycleNumber)){ olock.unlock(); return err; } // Calculate actual Pupe Cycle number required diff = ocycleNumber - dataInfo.cycleNumber; pupeCycleNumber = opuCycleNumbers[puChannel.pupeChan - 1] - diff; #if DEBUG_DATA printf("CycleWanted: %u CurrentCycle: %u Diff: %d PupeCycle: %u CurrentPupeCycle: %u Period: %d\n", dataInfo.cycleNumber, ocycleNumber, diff,pupeCycleNumber, ofpga[PU0_REG_BASE + CYCLE], dataInfo.cyclePeriod); #endif if(dataInfo.cyclePeriod == CyclePeriodStart){ } else if(dataInfo.cyclePeriod == CyclePeriodCalibration){ } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic0){ ph = 0; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic1){ ph = 1; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic2){ ph = 2; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic3){ ph = 3; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic4){ ph = 4; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic5){ ph = 5; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic6){ ph = 6; } else if(dataInfo.cyclePeriod == CyclePeriodHarmonic7){ ph = 7; } else { err.set(ErrorParam, "Incorrect cycle period"); olock.unlock(); return err; } nbunchesPerOrbit = onumBunches[puChannel.pupeChan-1][dataInfo.cyclePeriod]; #if DEBUG_DATA printf("Number of bunches: %d\n", nbunchesPerOrbit); printf("CycleInfoTable:\n"); hd32(ocycleInfoTable, 4 * 16); #endif if(dataInfo.cyclePeriod == CyclePeriodStart){ // Get address of Cycle Start cycleTimingAddress = ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + 0] & 0x00FFFFFF; if((ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + 0] >> 24) != 0x01){ eprintf("CycleInformationTable Error\n"); hd32(ocycleInfoTable, 4 * 16); } // Offset by start time and orbit number cycleTimingAddress += dataInfo.startTime; cycleTimingAddress += (nbunchesPerOrbit * dataInfo.orbitNumber); } else { // Find CyclePeriod Entry in Cycle Information table for(i = 0, h = 0, found = 0; i < 16; i++){ e = ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + i] >> 24; if((dataInfo.cyclePeriod == CyclePeriodCalibration) && (e & 0x04)){ cycleTimingAddress = ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + i] & 0x00FFFFFF; found = 1; break; } else if((dataInfo.cyclePeriod == CyclePeriodHarmonic0) && (e & 0x10) && (h == ph)){ cycleTimingAddress = ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + i] & 0x00FFFFFF; found = 1; break; } else if((dataInfo.cyclePeriod > CyclePeriodHarmonic0) && (e & 0x20) && (h == ph)){ cycleTimingAddress = ocycleInfoTable[((pupeCycleNumber & 0x03) << 4) + i] & 0x00FFFFFF; found = 1; break; } if((e & 0x10) || (e & 0x20)) h++; } if(!found){ err.set(ErrorDataNotAvailable, "The data required could not be found"); #if DEBUG_DATA printf("CycleInfoTable: Period: %d\n", dataInfo.cyclePeriod); hd32(ocycleInfoTable, 4 * 16); #endif olock.unlock(); return err; } // Offset by start time and orbit number cycleTimingAddress += dataInfo.startTime; cycleTimingAddress += (nbunchesPerOrbit * dataInfo.orbitNumber); } // Get Cycle Data Table Address cycleTimingAddress &= FpgaCycleTimingTableMask; cycleTimingEntry = ocycleTimingTable[cycleTimingAddress]; cycleDataAddress = cycleTimingEntry >> 32; #if DEBUG_DATA printf("CycleTimingAddress: %u(%x) CycleTime: %u CycleDataAddress: %u(%x)\n", cycleTimingAddress, cycleTimingAddress, uint32_t(cycleTimingEntry & 0xFFFFFFFF), cycleDataAddress, cycleDataAddress); printf("CycleTimingTable:\n"); hd64(&ocycleTimingTable[cycleTimingAddress], 16); #endif #ifdef ZAP ofpga[MEM_RAO] = 0; ofpga[MEM_RAS] = 1; // Read the Data printf("RawData: %x\n", cycleDataAddress); err = fpgaCopyData(puChannel.pupeChan, cycleDataAddress * 8, dataInfo.numValues, data); hd64(data.dataValues.data(), 16); #endif if(dataInfo.function == DataFunctionRaw){ if(dataInfo.bunchNumber && nbunchesPerOrbit){ ofpga[MEM_RAO] = (cycleDataAddress % nbunchesPerOrbit) + dataInfo.bunchNumber - 1; ofpga[MEM_RAS] = nbunchesPerOrbit; cycleDataAddress = cycleDataAddress / nbunchesPerOrbit; } else { ofpga[MEM_RAO] = 0; ofpga[MEM_RAS] = 1; } // Read the Data err = fpgaCopyData(puChannel.pupeChan, cycleDataAddress * 8, dataInfo.numValues, data); } else if(dataInfo.function == DataFunctionMean0){ ofpga[IMEM_REG] = brBase + BRAM_BUNCH_MEAN0; fpgaReadData64(cycleTimingAddress * sizeof(uint64_t), data.dataValues.data(), dataInfo.numValues * sizeof(uint64_t)); } else if(dataInfo.function == DataFunctionMean1){ ofpga[IMEM_REG] = brBase + BRAM_BUNCH_MEAN1; fpgaReadData64(cycleTimingAddress * sizeof(uint64_t), data.dataValues.data(), dataInfo.numValues * sizeof(uint64_t)); } else { err.set(ErrorNotImplemented, BString("Data function: ") + dataInfo.function + " has not been implemented"); } #if DEBUG_DATA printf("CycleDataTable: %x %d\n", cycleDataAddress, data.dataValues.size()); hd64(data.dataValues.data(), 16); #endif if(!err){ // Need to check the FPGA has not overwritten the data while we were reading it. #ifdef ZAP printf("CheckTime: cycleTimingEntry: %u TIME_TBLADDR: %u\n", (UInt32)(cycleTimingEntry >> 32), ofpga[regBase + TIME_TBLADDR]); #endif diff = cycleDataAddress - ofpga[regBase + TIME_TBLADDR]; if(diff <= 0) err.set(ErrorDataGone, "Data has already gone"); } } olock.unlock(); return err; } BError Pupe::getSimData(DataInfo dataInfo, Data& data){ BError err; SigGenBeam sigBeam; UInt32 i; Sample* samples; static Data dataCache; if(dataCache.dataValues.size() != dataInfo.numValues){ samples = new Sample[dataInfo.numValues]; sigBeam.config(125000000, 437000, 8, 0x3C, 0.0, 0, 1.0); sigBeam.generateIntegrated(samples, dataInfo.numValues); dataCache.numValues = dataInfo.numValues; dataCache.dataType = 0; dataCache.dataValues.resize(dataInfo.numValues); for(i = 0; i < dataInfo.numValues; i++){ dataCache.dataValues[i].sigma = Int16(32767.0 * samples[i]); dataCache.dataValues[i].deltaX = Int16(0.2 * 32767.0 * samples[i]); dataCache.dataValues[i].deltaY = Int16(-0.1 * 32767.0 * samples[i]); } delete [] samples; } data = dataCache; return err; } BError Pupe::setTestMode(PuChannel puChannel, UInt32 testOutput, UInt32 timingDisableMask){ BError err; int regBase = 0; int brBase = 0; if(osimulate){ err.set(ErrorNotImplemented, "Not Implemented"); } else { switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } olock.lock(); ofpga[TIMING_IO] = (ofpga[TIMING_IO] & ~0xFF00) | ((timingDisableMask & 0xFF) << 8); olock.unlock(); } return err; } BError Pupe::setTimingSignals(PuChannel puChannel, UInt32 timingSignals){ BError err; if(osimulate){ err.set(ErrorNotImplemented, "Not Implemented"); } else { olock.lock(); ofpga[TIMING_IO] = (ofpga[TIMING_IO] & ~0xFF) | (timingSignals & 0xFF); olock.unlock(); } return err; } BError Pupe::captureTestData(PuChannel puChannel, TestCaptureInfo captureInfo, BArray& data){ BError err; int regBase = 0; int brBase = 0; UInt32 v = 0; int num = 1024; int timeOut; dprintf(DBG_FPGA, "Pupe::captureTestData\n"); // Check Parameters if(captureInfo.startTime && captureInfo.postTriggerDelay) return err.set(ErrorParam, "Parameter error: Can only have startTime or postTriggerDelay not both"); if(osimulate){ data.resize(num); } else { switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } #if DEBUG_CTRL printf("TIMING_IO: %x\n", ofpga[TIMING_IO]); printf("TEST: %x\n", ofpga[regBase + TEST]); printf("ADC: %x\n", ofpga[ADC]); #endif odiagLock.lock(); v |= ((captureInfo.source & 0x03) << 2); v |= ((captureInfo.triggerStore & 0x01) << 4); v |= ((captureInfo.triggerAnd & 0x1) << 5); v |= ((captureInfo.triggerSourceData & 0x1) << 6); v |= ((captureInfo.clock & 0x1F) << 8); if(captureInfo.startTime){ v |= ((captureInfo.startTime & 0xFFFF) << 16); v |= ((0x1) << 7); } else { v |= ((captureInfo.postTriggerDelay & 0xFFFF) << 16); } #ifdef ZAP ofpga[regBase + DIAG_TRIGGER] = captureInfo.triggerMask; ofpga[regBase + DIAG_CTRL] = v; usleep(1000); // Trigger the data capture v |= ((0x1) << 0); ofpga[regBase + DIAG_CTRL] = v; #else // Trigger the data capture v |= ((0x1) << 0); ofpga[regBase + DIAG_TRIGGER] = captureInfo.triggerMask; ofpga[regBase + DIAG_CTRL] = v; #endif timeOut = diagnosticsTimeout; while((ofpga[regBase + DIAG_CTRL] & 0x01) && timeOut--){ usleep(10000); } if(timeOut <= 0){ odiagLock.unlock(); return err.set(ErrorTimeout, "Diagnostics capture timed out"); } olock.lock(); ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = brBase + BRAM_DIAG_TABLE; data.resize(num); // Fetch data fpgaReadData64(0, data.data(), data.size() * sizeof(UInt64)); olock.unlock(); odiagLock.unlock(); } return err; } BError Pupe::setTestData(PuChannel puChannel, Int32 on, BArray data){ BError err; int regBase = 0; int brBase = 0; BArray rdata; uint32_t i; dprintf(DBG_FPGA, "Pupe::setTestData: Len: %d\n", data.size()); switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } if(data.size() > (opageSize / sizeof(UInt32))){ return err.set(ErrorParam, "Data length is to long"); } if(data.size() % 1){ // Round down to a multiple of 64bits data.resize(data.size() - 1); } if(osimulate){ err.set(ErrorNotImplemented, "Not Implemented"); } else { olock.lock(); if(on){ ofpga[TESTCTRL] = 0; ofpga[MEM_RAO] = 0; ofpga[MEM_RAS] = 1; ofpga[MEM_REG] = SDRAM_DATA_TEST; ofpga[ADDR_REG] = 0; // Delay needed so that TEST DATA engine has released access to SDRAM usleep(1000); // Write to test data SDRAM fpgaWriteData64(data.data(), 0x0, data.size() * sizeof(UInt32)); ofpga[MEM_REG] = 0; #if TEST_TESTDATA // Check data read ofpga[MEM_REG] = SDRAM_DATA_TEST; ofpga[ADDR_REG] = 0; rdata.resize(data.size()); fpgaReadData64(0x0, rdata.data(), rdata.size() * sizeof(UInt32)); printf("\n\n####### TEST DATA TEST ############\n"); for(i = 0; i < data.size(); i++){ if(data[i] != rdata[i]){ printf("ERROR TestData ERROR: %d %x %x\n", i, data[i], rdata[i]); olock.unlock(); return err.set(ErrorFpga, "Error setting test data"); } } #endif ofpga[TESTLEN] = data.size() / 2; ofpga[TESTCTRL] = (1 << 25); switch(puChannel.pupeChan){ case 1: ofpga[ADC] &= ~0x07; break; case 2: ofpga[ADC] &= ~0x38; break; case 3: ofpga[ADC] &= ~0x1C; break; } ofpga[regBase + TEST] = ofpga[regBase + TEST] | 0x8000; } else { ofpga[regBase + TEST] = ofpga[regBase + TEST] & ~0x8000; switch(puChannel.pupeChan){ case 1: ofpga[ADC] |= 0x07; break; case 2: ofpga[ADC] |= 0x38; break; case 3: ofpga[ADC] |= 0x1C; break; } ofpga[TESTCTRL] = 0; } olock.unlock(); } return err; } BError Pupe::setPupeConfig(PuChannel puChannel, PupeConfig pupeConfig){ BError err; int regBase = 0; int brBase = 0; dprintf(DBG_FPGA, "Pupe::setPupeConfig: %d,%d\n", pupeConfig.internalAdcClockRef, pupeConfig.internalTimingMask); switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } opupeConfig = pupeConfig; if(!osimulate){ // Enable timing bus simulation if(opupeConfig.internalTimingMask){ ofpga[TIMING_IO] = (ofpga[TIMING_IO] & ~0x00FF00) | (opupeConfig.internalTimingMask << 8); } else { ofpga[TIMING_IO] = ofpga[TIMING_IO] & ~0x00FF00; } // Should setup ADC Clock } return err; } BError Pupe::getPupeConfig(PuChannel puChannel, PupeConfig& pupeConfig){ BError err; int regBase = 0; int brBase = 0; dprintf(DBG_FPGA, "Pupe::getPupeConfig\n"); switch(puChannel.pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } pupeConfig = opupeConfig; return err; } void Pupe::cycleStart(){ if(osimulate){ dprintf(DBG_FPGA, "Pupe::cycleStart\n"); } else { dprintf(DBG_FPGA, "Pupe::cycleStart: PupeCycle: %u Ctime: %u\n", ofpga[PU0_REG_BASE + CYCLE], ofpga[PU0_REG_BASE + TIME]); } olock.lock(); ocycleNumber = ocycleNumberNext; if(osimulate){ opuCycleNumbers[0]++; opuCycleNumbers[1]++; opuCycleNumbers[2]++; } else { opuCycleNumbers[0] = ofpga[PU0_REG_BASE + CYCLE]; opuCycleNumbers[1] = ofpga[PU1_REG_BASE + CYCLE]; opuCycleNumbers[2] = ofpga[PU2_REG_BASE + CYCLE]; } olock.unlock(); // Only master should send this if(omaster) ocontrol.cycleStart(ocycleNumber); } void Pupe::cycleStop(){ UInt32 currentCycle; olock.lock(); currentCycle = ocycleNumber; ocycleCompletedNumber = ocycleNumber; olock.unlock(); if(osimulate){ dprintf(DBG_FPGA, "Pupe::cycleStop\n"); } else { dprintf(DBG_FPGA, "Pupe::cycleStop: PupeCycle: %u Ctime: %u\n", ofpga[PU0_REG_BASE + CYCLE], ofpga[PU0_REG_BASE + TIME]); } // Only master should send this if(omaster) ocontrol.cycleStop(currentCycle); dprintf(DBG_FPGA, "Pupe::cycleStop: %d %d %d %d\n", ocycleNumber, opuCycleNumbers[0], opuCycleNumbers[1], opuCycleNumbers[2]); } void Pupe::cycleError(int puChan){ dprintf(DBG_FPGA, "Pupe::cycleError: %d\n", puChan); olock.lock(); // Clear the error ocontrol.cycleError(ocycleNumber, BError(ErrorStateTable, "FPGA State table transition error")); #ifdef ZAP exit(1); #endif olock.unlock(); } /******************************************************************************* * FPGA access functions ******************************************************************************* */ void Pupe::dumpState(){ int regBase = 0; int brBase = 0; UInt32 switchTable[14]; UInt8 phaseTables[16][512]; int s; int n; int pupeChan = 1; switch(pupeChan){ case 1: regBase = PU0_REG_BASE; brBase = PU0_BRAM_BASE; break; case 2: regBase = PU1_REG_BASE; brBase = PU1_BRAM_BASE; break; case 3: regBase = PU2_REG_BASE; brBase = PU2_BRAM_BASE; break; } printf("CycleNumber: %u\n", ocycleNumber); printf("CycleCompletedNumber: %u\n", ocycleCompletedNumber); printf("CycleType: %u\n", ocycleNumber); if(!osimulate){ ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = brBase + BRAM_SWITCH_TABLE; fpgaReadData64(0, switchTable, sizeof(switchTable)); ofpga[IMEM_REG] = brBase + BRAM_PHASE_TABLE; fpgaReadData64(0, phaseTables, sizeof(phaseTables)); printf("CONTROL: %x\n", ofpga[regBase + CONTROL]); printf("PLL_PHASEDELAY: %d\n", ofpga[regBase + PLL_PHASEDELAY]); printf("PLL_FREQUENCY: %d\n", ofpga[regBase + PLL_FREQUENCY]); printf("PLL_FREQDELAY: %d\n", ofpga[regBase + PLL_FREQDELAY]); printf("PLL_GAIN: %d\n", ofpga[regBase + PLL_GAIN]); printf("DDS_FREQ_MIN: %d\n", ofpga[regBase + DDS_FREQ_MIN]); printf("DDS_FREQ_MAX: %d\n", ofpga[regBase + DDS_FREQ_MAX]); printf("SwitchTable:\n"); for(n = 0; n < 14; n++){ printf("%4.4x, ", switchTable[n]); } printf("\n"); printf("PhaseTables:\n"); for(s = 0; s < 14; s++){ for(n = 0; n < 16; n++){ printf("%2.2x,", phaseTables[s][n]); } printf("\n"); } } } BError Pupe::fpgaInit(){ BError err; ADMXRC2_STATUS status; BString s; double lclk = 50.0e6; double mclk = 125.0e6; dprintf(DBG_FPGA, "Pupe::fpgaInit\n"); s = config.findValue("FpgaLclk:"); if(s != "") lclk = atof(s) * 1e6; s = config.findValue("FpgaMclk:"); if(s != "") mclk = atof(s) * 1e6; nprintf("Pupe: Setting LClk: %f Mhz, MClk: %f MHz\n", lclk/1e6, mclk/1e6); // Open FPGA Card if((status = ADMXRC2_OpenCard(oboard, &ofpgaCard)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_GetCardInfo(ofpgaCard, &ocardInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_SetClockRate(ofpgaCard, 0, lclk, NULL)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_SetClockRate(ofpgaCard, 1, mclk, NULL)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } if(err = fpgaLoad()) return err; return fpgaConfig(); } BError Pupe::fpgaLoad(){ BError err; ADMXRC2_STATUS status; ADMXRC2_SPACE_INFO spInfo; BString fileName = "/usr/tms/fpga/tms-fpga.bit"; BString s; uint32_t v; dprintf(DBG_FPGA, "Pupe::fpgaLoad\n"); s = config.findValue("FpgaFirmwareFile:"); if(s != "") fileName = s; // Load FPGA if(!access(fileName, R_OK)){ // Try to load file. if((status = ADMXRC2_ConfigureFromFile(ofpgaCard, fileName)) != ADMXRC2_SUCCESS){ return err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); } else { usleep(500000); } } else { return err.set(Tms::ErrorFpga, BString("FpgaError: File: ") + fileName + " not found"); } if((status = ADMXRC2_GetSpaceInfo(ofpgaCard, 0, &spInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } ofpga = (volatile uint32_t*)spInfo.VirtualBase; if((status = ADMXRC2_GetSpaceInfo(ofpgaCard, 1, &spInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, BString("FpgaError: ") + ADMXRC2_GetStatusString(status)); return err; } ofpgaControl = (volatile uint32_t*)spInfo.VirtualBase; v = ofpga[FIRMWARE]; if((((v >> 24) & 0xFF) != 'C') || (((v >> 16) & 0xFF) != 'N')){ err.set(ErrorFpga, "FPGA Firmware version incorrect"); } else { nprintf("Pupe: FpgaVersion: %d.%d\n", ((v >> 8) & 0xFF), (v & 0xFF)); } return err; } BError Pupe::fpgaInterruptLoop(){ BError err; uint i; while(1){ dprintf(DBG_INTERRUPT, "Pupe::fpgaInterruptLoop\n"); ADMXRC2_WaitForInterrupt(ofpgaCard, 0, 0, 0); dprintf(DBG_INTERRUPT, "Interrupt: %x !!\n", ofpga[ISR]); // Check for interrupts i = ofpga[ISR]; if(i & INT_PU0_ERROR) cycleError(0); if(i & INT_PU1_ERROR) cycleError(1); if(i & INT_PU2_ERROR) cycleError(2); if(i & INT_PU0_CYCLE_STOP) cycleStop(); if(i & INT_PU0_CYCLE_START) cycleStart(); if(i & ~(INT_PU0_CYCLE_START|INT_PU0_CYCLE_STOP|INT_PU0_ERROR|INT_PU1_ERROR|INT_PU2_ERROR)){ nprintf("Unknown interrupt: %x\n", i); } // Clear all interrupts ofpga[ISR] = 0xFFFFFFFF; ofpga[ISR] = 0x0; } return err; } void Pupe::fpgaTriggerTimingInputs(TimingSig input){ dprintf(DBG_FPGA, "Pupe::fpgaTriggerTimingInput: %d\n", input); if(ofpga){ dprintf(DBG_FPGA_TIMING, "Pupe::Trigger: %x PupeCycle: %u Ctime: %u\n", input, ofpga[PU0_REG_BASE + CYCLE], ofpga[PU0_REG_BASE + TIME]); ofpga[TIMING_IO] = ofpga[TIMING_IO] | (input & 0xFF); usleep(100); ofpga[TIMING_IO] = (ofpga[TIMING_IO] & ~0xFF); } #ifdef ZAP // Warning this code is not thread safe if(input & 0x04){ uint32_t add; uint32_t cycle; uint32_t dataAdd; uint64_t data[64]; ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = PU0_BRAM_BASE + BRAM_CYCLE_INFO; fpgaReadData64(0, ocycleInfoTable, sizeof(ocycleInfoTable)); printf("TriggerCycleStop: CycleInfoTable:\n"); hd32(ocycleInfoTable, 4 * 16); ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = PU0_BRAM_BASE + BRAM_CYCLE_TIMING; fpgaReadData64(0, ocycleTimingTable, sizeof(ocycleTimingTable)); cycle = ofpga[PU0_REG_BASE + CYCLE] - 1; add = ocycleInfoTable[(cycle << 4) + 1] & 0x00FFFFFF; printf("CycleTimingTable Cycle: %u Starting at: %x:\n", cycle, add); hd32(&ocycleTimingTable[add], 8 * 16); dataAdd = ocycleTimingTable[add] >> 32; printf("CycleDataTable Starting at: %x (%x Bytes)\n", dataAdd, dataAdd * 8); ofpga[MEM_RAS] = 1; ofpga[MEM_RAO] = 0; ofpga[MEM_REG] = SDRAM_DATA_PU0; ofpga[ADDR_REG] = 0; fpgaReadData64(dataAdd * 8, data, sizeof(data)); hd32(data, 128); ofpga[MEM_REG] = SDRAM_DATA_PU1; ofpga[ADDR_REG] = 0; fpgaReadData64(dataAdd * 8, data, sizeof(data)); hd32(data, 128); ofpga[MEM_REG] = SDRAM_DATA_PU2; ofpga[ADDR_REG] = 0; fpgaReadData64(dataAdd * 8, data, sizeof(data)); hd32(data, 128); } #endif if(input & 0x04) ocycleCount++; } BError Pupe::fpgaConfig(){ BError err; ADMXRC2_STATUS status; UInt32 n; UInt32 stateTable[14]; dprintf(DBG_FPGA, "Pupe::fpgaConfig:\n"); status = ADMXRC2_SetupDMA(ofpgaCard, odmaBuffer, odmaBufferSize, 0, &odmabuf); if(status != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, "Failed to set up DMA buffer"); return err; } #ifdef ZAP // Reset ADC PLL clock source ofpga[ADC] = 0x200 | 0x1FF; usleep(1000); ofpga[ADC] = 0x000 | 0x1FF; usleep(10000); #endif #ifdef ZAP { int data; printf("Resetting Card\n"); data = 1; ADMXRC2_Write(ofpgaCard, ADMXRC2_IOWIDTH_32, ADMXRC2_IOADAPTER, 0x28, &data, 4); usleep(10000); data = 0; ADMXRC2_Write(ofpgaCard, ADMXRC2_IOWIDTH_32, ADMXRC2_IOADAPTER, 0x28, &data, 4); sleep(1); } #endif ofpga[ADC] = 0x1FF; // Set State tables so that all paths lead to cycle stop for(n = 0; n < 14; n++){ stateTable[n] = 0x0fffff00; } ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[IMEM_REG] = PU0_REG_BASE + BRAM_SWITCH_TABLE; fpgaWriteData64(stateTable, 0, sizeof(stateTable)); ofpga[IMEM_REG] = PU1_REG_BASE + BRAM_SWITCH_TABLE; fpgaWriteData64(stateTable, 0, sizeof(stateTable)); ofpga[IMEM_REG] = PU2_REG_BASE + BRAM_SWITCH_TABLE; fpgaWriteData64(stateTable, 0, sizeof(stateTable)); // Reset PLL's ofpga[PU0_REG_BASE + CONTROL] = CONTROL_INIT; ofpga[PU1_REG_BASE + CONTROL] = CONTROL_INIT; ofpga[PU2_REG_BASE + CONTROL] = CONTROL_INIT; usleep(1000); ofpga[PU0_REG_BASE + CONTROL] = 0; ofpga[PU1_REG_BASE + CONTROL] = 0; ofpga[PU2_REG_BASE + CONTROL] = 0; #if DISABLE_BLR wprintf("BLR is disabled\n"); ofpga[PU0_REG_BASE + CONTROL] = CONTROL_BLR_DISABLE; ofpga[PU1_REG_BASE + CONTROL] = CONTROL_BLR_DISABLE; ofpga[PU2_REG_BASE + CONTROL] = CONTROL_BLR_DISABLE; #endif // Setup Interrupt handler ointerruptThread.start(); #if ALL_CHANNELS ofpga[IER] = INT_PU0_CYCLE_START | INT_PU0_CYCLE_STOP | INT_PU0_ERROR | INT_PU1_ERROR | INT_PU2_ERROR; #else ofpga[IER] = INT_PU0_CYCLE_START | INT_PU0_CYCLE_STOP | INT_PU0_ERROR; #endif // Enable timing bus simulation if(opupeConfig.internalTimingMask){ ofpga[TIMING_IO] = (opupeConfig.internalTimingMask << 8); } else { ofpga[TIMING_IO] = 0x0000; } #if SYSCLK_INTERNAL ofpga[TIMING_IO] |= 0x0100; // Force internal SysClock printf("TIMING_IO: %x\n", ofpga[TIMING_IO]); printf("TEST: %x\n", ofpga[PU0_REG_BASE + TEST]); #endif dprintf(DBG_FPGA, "TIMING_IO: %x\n", ofpga[TIMING_IO]); ofpga[PU0_REG_BASE + CYCLE] = 0; ofpga[PU1_REG_BASE + CYCLE] = 0; ofpga[PU2_REG_BASE + CYCLE] = 0; #ifdef ZAP { uint8_t data[2*1024*1024]; uint32_t p = 0; printf("Clear memory\n"); memset(data, 0x55, sizeof(data)); ofpga[MEM_REG] = SDRAM_DATA_PU0; for(p = 0; p < 1; p++){ ofpga[ADDR_REG] = p << 19; fpgaWriteData64(data, 0, sizeof(data)); } ofpga[MEM_REG] = SDRAM_DATA_PU1; for(p = 0; p < 1; p++){ ofpga[ADDR_REG] = p << 19; fpgaWriteData64(data, 0, sizeof(data)); } ofpga[MEM_REG] = SDRAM_DATA_PU2; for(p = 0; p < 1; p++){ ofpga[ADDR_REG] = p << 19; fpgaWriteData64(data, 0, sizeof(data)); } printf("Clear memory: Done\n"); } #endif #ifdef ZAP { BArray data; BFile file; BString fileName = "../datasrc/beam3-437000-8.psd"; int nb; printf("Load Test Data\n"); if(err = file.open(fileName, "r")){ printf("Error: Opening file:\n"); } data.resize(1024); if((nb = file.read(&data[0], 1024 * sizeof(UInt32))) <= 0){ printf("Error: Reading file:\n"); } data.resize(nb / sizeof(UInt32)); olock.unlock(); setTestData(PuChannel(1,1,1), 1, data); olock.lock(); printf("Load Test Data: Done\n"); } #endif #ifdef ZAP dprintf(DBG_FPGA, "Pupe::fpgaConfig: DumpState\n"); dumpState(); #endif #ifdef ZAP BIter i; BList infoList; fpgaGetInfo(infoList); for(infoList.start(i); !infoList.isEnd(i); infoList.next(i)){ printf("%s: %s\n", infoList[i].name.retStr(), infoList[i].value.retStr()); } #endif dprintf(DBG_FPGA, "Pupe::fpgaConfig: End\n"); return err; } BError Pupe::fpgaReadData64(uint32_t fpgaOffset, void* toAddress, int nbytes){ BError err; ADMXRC2_STATUS status; uint32_t dmaMode; dprintf(DBG_FPGA, "Pupe::fpgaReadData64\n"); dmaMode = ADMXRC2_BuildDMAModeWord(ocardInfo.BoardType, ADMXRC2_IOWIDTH_64, 0, ADMXRC2_DMAMODE_USEREADY | ADMXRC2_DMAMODE_USEBTERM | ADMXRC2_DMAMODE_BURSTENABLE); status = ADMXRC2_DoDMA(ofpgaCard, odmabuf, 0, nbytes, FPGA_DATA_ADDRESS + fpgaOffset, ADMXRC2_LOCALTOPCI, 0, dmaMode, 0, 0, 0); memcpy(toAddress, odmaBuffer, nbytes); if(status){ err.set(ErrorFpga, "Fpga: DMA Error"); } return err; } BError Pupe::fpgaReadData32(uint32_t fpgaOffset, void* toAddress, int nbytes){ BError err; ADMXRC2_STATUS status; uint32_t dmaMode; dprintf(DBG_FPGA, "Pupe::fpgaReadData32\n"); dmaMode = ADMXRC2_BuildDMAModeWord(ocardInfo.BoardType, ADMXRC2_IOWIDTH_32, 0, ADMXRC2_DMAMODE_USEREADY | ADMXRC2_DMAMODE_USEBTERM | ADMXRC2_DMAMODE_BURSTENABLE); status = ADMXRC2_DoDMA(ofpgaCard, odmabuf, 0, nbytes, FPGA_DATA_ADDRESS + fpgaOffset, ADMXRC2_LOCALTOPCI, 0, dmaMode, 0, 0, 0); memcpy(toAddress, odmaBuffer, nbytes); if(status){ err.set(ErrorFpga, "Fpga: DMA Error"); } return err; } BError Pupe::fpgaWriteData64(void* fromAddress, uint32_t fpgaOffset, int nbytes){ BError err; ADMXRC2_STATUS status; uint32_t dmaMode; dprintf(DBG_FPGA, "Pupe::fpgaWriteData64\n"); dmaMode = ADMXRC2_BuildDMAModeWord(ocardInfo.BoardType, ADMXRC2_IOWIDTH_64, 0, ADMXRC2_DMAMODE_USEREADY | ADMXRC2_DMAMODE_USEBTERM | ADMXRC2_DMAMODE_BURSTENABLE); memcpy(odmaBuffer, fromAddress, nbytes); status = ADMXRC2_DoDMA(ofpgaCard, odmabuf, 0, nbytes, FPGA_DATA_ADDRESS + fpgaOffset, ADMXRC2_PCITOLOCAL, 0, dmaMode, 0, 0, 0); if(status){ err.set(ErrorFpga, "Fpga: DMA Error"); } return err; } BError Pupe::fpgaCopyData(int pupeChan, uint32_t address, uint32_t nsamples, Data& data){ BError err; uint32_t pageSize = 2*1024*1024; uint32_t dataTablePage; uint32_t dataTableOffset; uint32_t ncopy; uint32_t addressOut = 0; dprintf(DBG_FPGA, "Pupe::fpgaCopyData: %d\n", pupeChan); switch(pupeChan){ case 1: ofpga[MEM_REG] = SDRAM_DATA_PU0; break; case 2: ofpga[MEM_REG] = SDRAM_DATA_PU1; break; case 3: ofpga[MEM_REG] = SDRAM_DATA_PU2; break; default: return err.set(ErrorFpga, "Incorrect puChannel"); } while(nsamples){ dataTablePage = address >> 21; // 2MByte Region dataTableOffset = address & 0x001FFFFF; // Offset ncopy = nsamples * 8; if(ncopy > (pageSize - dataTableOffset)){ ncopy = pageSize - dataTableOffset; } ofpga[ADDR_REG] = dataTablePage << 19; #if DEBUG_DATA printf("MEM_RAO: %d MEM_RAS: %d\n", ofpga[MEM_RAO], ofpga[MEM_RAS]); printf("ReadData: Chan: %d Address: %x Page: %x Offset: %x NBytes: %d\n", pupeChan, address, dataTablePage, dataTableOffset, ncopy); #endif #if USE_DMA if(err = fpgaReadData64(dataTableOffset, &data.dataValues[addressOut], ncopy)) return err; #else uint64_t* dataTable = (uint64_t*)&ofpga[FPGA_MEM]; memcpy_64(&data.dataValues[addressOut], &dataTable[dataTableOffset/8], ncopy); #endif dataTableOffset = 0; address += ncopy; addressOut += (ncopy / 8); nsamples -= (ncopy / 8); } dprintf(DBG_FPGA, "Pupe::fpgaCopyData: End\n"); return err; } void Pupe::fpgaClose(){ dprintf(DBG_FPGA, "Pupe::fpgaClose\n"); if(ofpgaCard){ // Stop interrupt thread ointerruptThread.cancel(); ointerruptThread.waitForCompletion(); // Disable interrupts ofpga[IER] = 0; // Release DMA if(odmabuf){ ADMXRC2_UnsetupDMA(ofpgaCard, odmabuf); odmabuf = 0; } ofpga = 0; // Close card ADMXRC2_CloseCard(ofpgaCard); } } BError Pupe::fpgaGetInfo(BList& infoList){ BError err; uint8_t* p; float sysFactors[10] = { 0.0130, 0.0141, 0.0172, 0.0260, 0.0625, 0.0141, 1.0000, 1.0000, 0.0098, 0.0098 }; if(ofpgaControl){ #if 1 /* * Removed. Bridge now sets up the LM87 Automatically */ ofpgaControl[SYSMON_CTL] = 0x132D4080; usleep(1000); if (ofpgaControl[SYSMON_CTL] & SYSMON_SMB_ERROR) { printf("\nSMB Serial Bus Error - LM87 Reset Failed\n"); printf("Ctl = %8.8x\n", ofpgaControl[SYSMON_CTL]); return err.set(ErrorFpga, "SMB Serial Bus Error - LM87 Reset Failed"); } ofpgaControl[SYSMON_CTL] = 0x032D1603; usleep(1000); ofpgaControl[SYSMON_CTL] = 0x032D4001; usleep(1000); #endif ofpgaControl[SYSMON_CTL] = 0x042D0000; usleep(1000); if(ofpgaControl[SYSMON_CTL] & SYSMON_SMB_ERROR){ printf("\nSMB Serial Bus Error - Shadow Read Failed\n"); return err.set(ErrorFpga, "SMB Serial Bus Error - Shadow Read Failed"); } p = (uint8_t*)&ofpgaControl[SYSMON_BUF] + 0x20; infoList.append(NameValue("+1V2", p[8] * sysFactors[8])); infoList.append(NameValue("+1V5", p[1] * sysFactors[1])); infoList.append(NameValue("+1V8", p[9] * sysFactors[9])); infoList.append(NameValue("+2V5", p[0] * sysFactors[0])); infoList.append(NameValue("+3V3", p[2] * sysFactors[2])); infoList.append(NameValue("+5V", p[3] * sysFactors[3])); infoList.append(NameValue("Vio", p[4] * sysFactors[4])); infoList.append(NameValue("FPIO", p[5] * sysFactors[5])); infoList.append(NameValue("TempInternal", p[7] * sysFactors[7])); infoList.append(NameValue("TempFpga", p[6] * sysFactors[6])); } return err; }