/******************************************************************************* * Pupe.cc Pupe process * T.Barnaby, BEAM Ltd, 2007-02-13 ******************************************************************************* */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <math.h> #include <syslog.h> #include <Pupe.h> #include <SigGen.h> #include <Control.h> #include <TmsD.h> #include <Debug.h> #include <signal.h> #include <sys/time.h> #include <sys/ioctl.h> #include <sys/fcntl.h> #include <errno.h> #include <main.h> #include <TmsLib.h> #include <BFile.h> /* Build Options */ #define USE_DMA 1 #define LOAD_USE_DMA 1 /* Debug options */ #define SYSCLK_INTERNAL 0 #define DEBUG_CTRL 0 #define DEBUG_DATA 0 #define DEBUG_DATA_ERROR 1 #define DEBUG_DATA_TIME 0 #define DEBUG_CONTROL_TIME 0 // 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_STRB_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 uint32_t SDRAM_DATA_SIZE = (256*1024*1024); // The SDRAM bank size const uint32_t SDRAM_DATA_MASK = ((SDRAM_DATA_SIZE/8)-1); // The SDRAM bank bit mask 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) // ADC register bits const int ADC_LED_YELLOW = (1 << 10); ///< The Yellow LED const int ADC_LED_RED = (1 << 11); ///< The Red LED // FPGA Control Space Registers const int SYSMON_CTL = (0x00400 >> 2); const int SYSMON_BUF = (0x00500 >> 2); const int SYSMON_SMB_ERROR = (0x10000000); const int minTimingDiff = 500; // The minimum time difference in the timing table const int diagnosticsNumSamples = 4096; // The number of diagnostics samples const int diagnosticsTimeout = 1000; // The diagnostics timeout in 10ms steps const uint32_t maxNumValues = (SDRAM_DATA_SIZE / 2 / 8); // Maximum number of samples to return /// 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 slot, int board) : ocontrol(control), ointerruptThread(*this){ osimulate = 0; oinitialised = 0; omaster = 0; oboard = board; oslot = slot; 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; opllRefErrors = 0; opllLocked = 0; memset(&opupeConfig, 0, sizeof(opupeConfig)); ostatus.set(ErrorFpga, "Not initialised"); ocycleCount = 0; } Pupe::~Pupe(){ if(!osimulate){ fpgaClose(); } } BString Pupe::getName(){ return BString("Pupe: ") + (oslot + 1) + ": "; } BError Pupe::init(){ BError err; BUInt32 simulateTiming; BString s; ostatus.set(ErrorFpga, "Not initialised"); if(config.findValue("SimulateFpga:").retInt() == 1) osimulate = 1; olock.lock(); memset(&opupeConfig, 0, sizeof(opupeConfig)); s = config.findValue("SimulateTiming:"); if(s != "") simulateTiming = s.retInt(); else simulateTiming = 0; opupeConfig.internalTimingMask = simulateTiming; // Initialise NumBunches array onumBunches[0].assign(9, 0); onumBunches[1].assign(9, 0); onumBunches[2].assign(9, 0); if(!osimulate){ if(oinitialised){ fpgaClose(); oinitialised = 0; } if(oboard >= 0){ if(!(err = fpgaInit())){ // Set up Pll Synthesisor opllSynth.init(ofpga); // opllSynth.displayRegisters(); // Clear CycleInfo table ofpga[MEM_REG] = SDRAM_BLOCKRAM; memset(ocycleInfoTable, 0, sizeof(ocycleInfoTable)); ofpga[IMEM_REG] = PU0_BRAM_BASE + BRAM_CYCLE_INFO; fpgaWriteData64(ocycleInfoTable, 0, sizeof(ocycleInfoTable)); ofpga[IMEM_REG] = PU1_BRAM_BASE + BRAM_CYCLE_INFO; fpgaWriteData64(ocycleInfoTable, 0, sizeof(ocycleInfoTable)); ofpga[IMEM_REG] = PU2_BRAM_BASE + BRAM_CYCLE_INFO; fpgaWriteData64(ocycleInfoTable, 0, sizeof(ocycleInfoTable)); oinitialised = 1; } } else { err.set(ErrorFpga, getName() + "Not present"); } } else { oinitialised = 1; } ostatus = err; olock.unlock(); return err; } int Pupe::getSlot(){ return oslot; } BError Pupe::status(){ BError err; olock.lock(); err = ostatus.copy(); olock.unlock(); return err; } BError Pupe::setMaster(int on){ BError err; if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } 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; dprintf(DBG_SETNEXTCYCLE, "Pupe::setNextCycle: %u\n", cycleNumber); // 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 %s\n", puChannel.moduleNum, puChannel.pupeNum, puChannel.pupeChan, params.cycleType.retStr()); 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, getName() + "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]; UInt8 phaseTables[14][512]; #if DEBUG_CONTROL_TIME double t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0; t1 = getTime(); #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, getName() + "Incorrect puChannel"); } #ifdef ZAP if(puChannel.pupeChan == 1) dumpState(); #endif puChannel.moduleNum = ocontrol.moduleNum(); puChannel.pupeNum = (oslot + 1); 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; #if DEBUG_CONTROL_TIME t2 = getTime(); #endif // 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)); #if DEBUG_CONTROL_TIME t3 = getTime(); #endif ofpga[IMEM_REG] = brBase + BRAM_PHASE_TABLE; #ifdef ZAP for(n = 0; (n < 14) && (n < params.stateTable.size()); n++){ fpgaWriteData64(params.stateTable[n].phaseTable.data(), n * 512, 512); } #else for(n = 0; (n < 14) && (n < params.stateTable.size()); n++){ memcpy(phaseTables[n], params.stateTable[n].phaseTable.data(), 512); } // memcpy((void*)&ofpga[FPGA_MEM], phaseTables, 512 * params.stateTable.size()); fpgaWriteData64(phaseTables, 0, 512 * params.stateTable.size()); #endif #if DEBUG_CONTROL_TIME t4 = getTime(); #endif 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 #if DEBUG_CONTROL_TIME t5 = getTime(); printf("SetControlInfoPickUp: Times: %f, %f, %f, %f, %f Total: %f\n", t2 - t1, t3 - t2, t4 - t3, t5 - t4, t5 - t4, t5 - t1); #endif dprintf(DBG_FPGA, "Pupe::setControlInfoPickUp: End\n"); return err; } BError Pupe::getStatusList(PuChannel puChannel, BList<NameValue>& statusList){ BError err; BString baseName = BString("Module") + ocontrol.moduleNum() + "_Pupe" + (oslot + 1); BList<NameValue> il; BIter i; err = status(); olock.lock(); statusList.append(NameValue(baseName + "_SerialNumber", ocardInfo.SerialNum)); if(!err) statusList.append(NameValue(baseName + "_Running", "1")); else statusList.append(NameValue(baseName + "_Running", "0")); statusList.append(NameValue(baseName + "_Error", err.getString())); statusList.append(NameValue(baseName + "_AdcPllLock", opllLocked)); statusList.append(NameValue(baseName + "_AdcPllLockErrors", opllRefErrors)); 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 < -3) return err.set(ErrorDataGone, getName() + "Cycle's data has already been overwritten: Current: " + ocycleCompletedNumber + " Requested: " + cycleNumber); if(osimulate){ if(diff > 1) return err.set(ErrorDataFuture, getName() + "Cycle data required is to far in the future: Current: " + ocycleCompletedNumber + " Requested: " + cycleNumber); } else { if(diff > 0) return err.set(ErrorDataFuture, getName() + "Cycle data required is to far in the future: Current: " + ocycleCompletedNumber + " Requested: " + cycleNumber); } return err; } BError Pupe::getEventList(BUInt32 pupeCycleNumber, BList<PupeEvent>& events){ BError err; int i; PupeEvent event; PupeEvent eventPrev = { 0, 0, 0, 0 }; int hasInjection = 0; events.clear(); pupeCycleNumber &= 0x03; // Gather events from Cycle Information table for(i = 0; i < 16; i++){ event.event = ocycleInfoTable[(pupeCycleNumber << 4) + i] >> 24; event.timingAddress = ocycleInfoTable[(pupeCycleNumber << 4) + i] & FpgaCycleTimingTableMask; event.time = ocycleTimingTable[event.timingAddress] & 0xFFFFFFFF; event.dataAddress = ocycleTimingTable[event.timingAddress] >> 32; // Special case for CYCLE_STOP event as no data is written to timing table after event if(event.event & 0x02){ event.timingAddress = (ocycleInfoTable[(pupeCycleNumber << 4) + i] - 1) & FpgaCycleTimingTableMask; event.time = ocycleTimingTable[event.timingAddress] & 0xFFFFFFFF; event.dataAddress = ocycleTimingTable[event.timingAddress] >> 32; } // Check validity of events if((i == 0) && (event.event != 0x01)){ return err.set(ErrorFpga, getName() + "CYCLE_START event not first in cycle"); } if(event.event & 0x10){ if(hasInjection) return err.set(ErrorFpga, getName() + "Multiple injection events"); hasInjection = 1; } if(eventPrev.event && (event.time <= eventPrev.time)){ #if DEBUG_DATA_ERROR printf("Event timing backwards in CycleInfoTable Entry: %d Event: %x Times: %d <= %d\n", pupeCycleNumber, event.event, event.time, eventPrev.time); hd32(ocycleInfoTable, 4 * 16); #endif return err.set(ErrorFpga, getName() + "Multiple events at the same time or later events have time before previous events"); } events.append(event); eventPrev = event; if(event.event & 0x02) break; } return err; } void Pupe::printEventList(BList<PupeEvent>& events){ BIter i; int n; for(events.start(i), n = 0; !events.isEnd(i); events.next(i), n++){ printf("Event: %d Type: %x TimingAddress: %x Time: %d DataAddress: %x\n", n, events[i].event, events[i].timingAddress, events[i].time, events[i].dataAddress); } } BError Pupe::getCycleInformation(UInt32 cycleNumber, CycleInformation& cycleInformation){ BError err; int timeOut; uint32_t pupeCycleNumber; int32_t diff; BList<PupeEvent> events; BIter i; BIter n; int h; CycleInformationPeriod period; dprintf(DBG_FPGA, "Pupe::getCycleInformation: Cycle: %u\n", cycleNumber); olock.lock(); // Return an error if already gone or to far in the future if(err = checkData(cycleNumber)){ olock.unlock(); return err; } cycleInformation.cycleNumber = cycleNumber; cycleInformation.cycleType = "Unknown"; ofpga[MEM_REG] = SDRAM_BLOCKRAM; // Need to test if the cycle number has changed while we read the following two data tables timeOut = 2; do { pupeCycleNumber = ofpga[PU0_REG_BASE + CYCLE]; ofpga[IMEM_REG] = PU0_BRAM_BASE + BRAM_CYCLE_INFO; fpgaReadData64(0, ocycleInfoTable, sizeof(ocycleInfoTable)); ofpga[IMEM_REG] = PU0_BRAM_BASE + 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, getName() + "Timed out while getting Cycle Information tables"); } // Return an error if already gone or to far in the future if(err = checkData(cycleNumber)){ olock.unlock(); return err; } // Calculate actual Pupe Cycle number required diff = ocycleNumber - cycleNumber; pupeCycleNumber = (opuCycleNumbers[0] - diff) & 0x03; #if DEBUG_DATA printf("CycleInfoTable Entry: %d\n", pupeCycleNumber); hd32(ocycleInfoTable, 4 * 16); #endif if(err = getEventList(pupeCycleNumber, events)){ olock.unlock(); return err; } // Find CyclePeriods in Cycle Information table for(events.start(i), h = 0; !events.isEnd(i); events.next(i)){ n = i; events.next(n); period.cyclePeriod = 0; period.startTime = events[i].time; period.endTime = 0; period.numBunches = 0; period.numValues = 0; if(events[i].event & 0x01){ period.cyclePeriod = CyclePeriodAll; cycleInformation.periods.append(period); } else if(events[i].event & 0x04){ period.cyclePeriod = CyclePeriodCalibration; period.numBunches = onumBunches[0][period.cyclePeriod]; if(!events.isEnd(n)){ period.endTime = events[n].time; period.numValues = (events[n].dataAddress - events[i].dataAddress) & SDRAM_DATA_MASK; } cycleInformation.periods.append(period); } else if(events[i].event & 0x10){ period.cyclePeriod = CyclePeriodHarmonic0; period.numBunches = onumBunches[0][period.cyclePeriod]; if(!events.isEnd(n)){ period.endTime = events[n].time; period.numValues = (events[n].dataAddress - events[i].dataAddress) & SDRAM_DATA_MASK; } cycleInformation.periods.append(period); h++; } else if(events[i].event & 0x20){ period.cyclePeriod = CyclePeriodHarmonic0 + h; period.numBunches = onumBunches[0][period.cyclePeriod]; if(!events.isEnd(n)){ period.endTime = events[n].time; period.numValues = (events[n].dataAddress - events[i].dataAddress) & SDRAM_DATA_MASK; } cycleInformation.periods.append(period); h++; } else if(events[i].event & 0x02){ events.start(n); cycleInformation.periods[0].endTime = events[i].time; cycleInformation.periods[0].numValues = (events[i].dataAddress - events[n].dataAddress) & SDRAM_DATA_MASK; break; } } if(!err){ // Need to check the FPGA has not overwritten the data while we were reading it. #ifdef ZAP printf("CheckTime: cycleTimingAddressStart: %u TIME_TBLADDR: %u\n", events.front().timingAddress, ofpga[PU0_REG_BASE + TIME_TBLADDR]); #endif diff = (events.front().timingAddress - ofpga[PU0_REG_BASE + TIME_TBLADDR]) & FpgaCycleTimingTableMask; if(diff < minTimingDiff) err.set(ErrorDataGone, getName() + "Data has already gone"); } olock.unlock(); return err; } void Pupe::dataAverage(Data& data){ BUInt32 n; DataValueMean* v; int s; for(n = 0; n < data.dataValues.size(); n++){ v = (DataValueMean*)&data.dataValues[n]; if(v->numSamples < 256) s = 256; else if(v->numSamples < 512) s = 512; else if(v->numSamples < 1024) s = 1024; else if(v->numSamples < 2048) s = 2048; else s = 4096; v->sigma = (int(v->sigma) * s) / v->numSamples; v->deltaX = (int(v->deltaX) * s) / v->numSamples; v->deltaY = (int(v->deltaY) * s) / v->numSamples; } } BError Pupe::getData(PuChannel puChannel, DataInfo dataInfo, Data& data){ BError err; int regBase; int brBase; BList<PupeEvent> events; BIter i; BIter n; PupeEvent eventStart = { 0, 0, 0, 0 }; PupeEvent eventEnd = { 0, 0, 0, 0 }; PupeEvent eventStop = { 0, 0, 0, 0 }; uint32_t p; int32_t diff; uint32_t timingAddress = 0; uint32_t dataAddress = 0; int h; int found = 0; int nbunchesPerOrbit = 0; uint32_t pupeCycleNumber; int timeOut; uint32_t numValues; #if DEBUG_DATA_TIME double t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0; t1 = getTime(); #endif dprintf(DBG_FPGA, "Pupe::getData: PuChannel: %d.%d RequiredCycleNumber: %u CurrentCycleNumber: %u LastCompletedCycle: %u\n", puChannel.pupeNum, puChannel.pupeChan, dataInfo.cycleNumber, ocycleNumber, ocycleCompletedNumber); // printf("Pupe::getData: PuChannel: %d.%d RequiredCycleNumber: %u CurrentCycleNumber: %u LastCompletedCycle: %u\n", puChannel.pupeNum, puChannel.pupeChan, dataInfo.cycleNumber, ocycleNumber, ocycleCompletedNumber); if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } // Basic parameter validation if(dataInfo.startTime > 1200){ return err.set(ErrorParam, getName() + "Start time beyond 1200ms"); } if(dataInfo.orbitNumber > 500000){ return err.set(ErrorParam, getName() + "Orbit number beyond 500000"); } 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, getName() + "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 { #if DEBUG_DATA_TIME t2 = getTime(); #endif // 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 = 2; 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, getName() + "Timed out while getting Cycle Information tables"); } #if DEBUG_DATA_TIME t3 = getTime(); #endif // Return an error if already gone or to far in the future if(err = checkData(dataInfo.cycleNumber)){ olock.unlock(); return err; } nbunchesPerOrbit = onumBunches[puChannel.pupeChan-1][dataInfo.cyclePeriod]; // Calculate actual Pupe Cycle number required diff = ocycleNumber - dataInfo.cycleNumber; pupeCycleNumber = opuCycleNumbers[puChannel.pupeChan - 1] - diff; #if DEBUG_DATA printf("GetData: 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(err = getEventList(pupeCycleNumber, events)){ olock.unlock(); return err; } // Find required CyclePeriod in Events list for(events.start(i), h = 0, p = CyclePeriodAll, found = 0; !events.isEnd(i); events.next(i)){ n = i; events.next(n); if(events[i].event == 0x01){ p = CyclePeriodAll; } else if(events[i].event == 0x04){ p = CyclePeriodCalibration; } else if(events[i].event == 0x10){ p = CyclePeriodHarmonic0; h = 1; } else if(events[i].event == 0x20){ p = CyclePeriodHarmonic0 + h; h++; } else if(events[i].event == 0x02){ eventStop = events[i]; break; } if(events.isEnd(n)) break; if(p == dataInfo.cyclePeriod){ eventStart = events[i]; eventEnd = events[n]; found = 1; } } if(!found){ err.set(ErrorDataNotAvailable, getName() + "The CyclePeriod required could not be found"); olock.unlock(); return err; } // Default is to limit data to this Cycle if(!dataInfo.limitData || (dataInfo.cyclePeriod == CyclePeriodAll)){ eventEnd = eventStop; } #if DEBUG_DATA printf("\n"); printf("CycleInfoTable Entry: %d\n", pupeCycleNumber & 0x03); hd32(ocycleInfoTable, 4 * 16); printf("\n"); printf("EventStart: %x Time: %d TimingAddress: %x DataAddress: %x\n", eventStart.event, eventStart.time, eventStart.timingAddress, eventStart.dataAddress); printf("EventEnd: %x Time: %d TimingAddress: %x DataAddress: %x\n", eventEnd.event, eventEnd.time, eventEnd.timingAddress, eventEnd.dataAddress); printf("EventStop: %x Time: %d TimingAddress: %x DataAddress: %x\n", eventStop.event, eventStop.time, eventStop.timingAddress, eventStop.dataAddress); #endif // Offset by Start time timingAddress = (eventStart.timingAddress + dataInfo.startTime) & FpgaCycleTimingTableMask; dataAddress = ocycleTimingTable[timingAddress] >> 32; // Offset by orbit number dataAddress = (dataAddress + (nbunchesPerOrbit * dataInfo.orbitNumber)) & SDRAM_DATA_MASK; // Make sure data is within cycle period numValues = (eventEnd.dataAddress - dataAddress) & SDRAM_DATA_MASK; if(numValues > maxNumValues){ err.set(ErrorDataNotAvailable, getName() + "CycleTable Error: The amount of data for a period exceeds a maximum cycle period"); olock.unlock(); return err; } // Perform data access functions depending on type if(dataInfo.function == DataFunctionRaw){ if(dataInfo.bunchNumber){ numValues /= nbunchesPerOrbit; } // Set up return data size if(numValues < dataInfo.numValues){ dataInfo.numValues = numValues; } data.dataValues.resize(dataInfo.numValues); data.numValues = dataInfo.numValues; if(dataInfo.bunchNumber) data.numBunches = 1; else data.numBunches = nbunchesPerOrbit; data.numChannels = 1; #if DEBUG_DATA printf("Data: TimingAddress: %d Orbits: %d DataStart: %d DataEnd: %d NumValues: %d\n", timingAddress, dataInfo.orbitNumber, dataAddress, eventEnd.dataAddress, numValues); printf("BunchNumber: %d NumBunches: %d\n", dataInfo.bunchNumber, nbunchesPerOrbit); printf("CycleTimingAddress: %u(%x) CycleTime: %u CycleDataAddress: %u(%x)\n", timingAddress, timingAddress, uint32_t(ocycleTimingTable[timingAddress] & 0xFFFFFFFF), dataAddress, dataAddress); printf("CycleTimingTable:\n"); hd64(&ocycleTimingTable[timingAddress], 16); #endif #if DEBUG_DATA_TIME t4 = getTime(); #endif if(dataInfo.bunchNumber && nbunchesPerOrbit){ ofpga[MEM_RAO] = (dataAddress % nbunchesPerOrbit) + dataInfo.bunchNumber - 1; ofpga[MEM_RAS] = nbunchesPerOrbit; dataAddress = dataAddress / nbunchesPerOrbit; } else { ofpga[MEM_RAO] = 0; ofpga[MEM_RAS] = 1; } // Read the Data err = fpgaCopyData(puChannel.pupeChan, dataAddress * 8, dataInfo.numValues, data); } else if(dataInfo.function == DataFunctionMean0){ if(dataInfo.bunchNumber != 0){ err.set(ErrorNotImplemented, getName() + "Can only return average for all bunches"); } if(dataInfo.orbitNumber != 0){ err.set(ErrorNotImplemented, getName() + "Cannot offset by orbit"); } numValues = (eventEnd.timingAddress - timingAddress) & FpgaCycleTimingTableMask; // Set up return data size if(numValues < dataInfo.numValues){ dataInfo.numValues = numValues; } data.dataValues.resize(dataInfo.numValues); data.numValues = dataInfo.numValues; data.numBunches = 1; data.numChannels = 1; ofpga[IMEM_REG] = brBase + BRAM_BUNCH_MEAN0; fpgaReadData64(timingAddress * sizeof(uint64_t), data.dataValues.data(), dataInfo.numValues * sizeof(uint64_t)); dataAverage(data); } else if(dataInfo.function == DataFunctionMean1){ #ifdef ZAP if(dataInfo.bunchNumber != 1){ err.set(ErrorNotImplemented, getName() + "Can only return average for bunch 1"); } #endif if(dataInfo.orbitNumber != 0){ err.set(ErrorNotImplemented, getName() + "Cannot offset by orbit"); } numValues = (eventEnd.timingAddress - timingAddress) & FpgaCycleTimingTableMask; // Set up return data size if(numValues < dataInfo.numValues){ dataInfo.numValues = numValues; } data.dataValues.resize(dataInfo.numValues); data.numValues = dataInfo.numValues; data.numBunches = 1; data.numChannels = 1; ofpga[IMEM_REG] = brBase + BRAM_BUNCH_MEAN1; fpgaReadData64(timingAddress * sizeof(uint64_t), data.dataValues.data(), dataInfo.numValues * sizeof(uint64_t)); dataAverage(data); } else { err.set(ErrorNotImplemented, getName() + "Data function: " + dataInfo.function + " has not been implemented"); } #if DEBUG_DATA_TIME t5 = getTime(); #endif #if DEBUG_DATA printf("CycleDataTable: %x %d\n", dataAddress, data.dataValues.size()); if(data.dataValues.size() >= 16) hd64(data.dataValues.data(), 16); #endif if(!err){ // Need to check the FPGA has not overwritten the data while we were reading it. diff = (timingAddress - ofpga[regBase + TIME_TBLADDR]) & FpgaCycleTimingTableMask; if(diff < minTimingDiff){ err.set(ErrorDataGone, getName() + "Data has already gone: Difference: " + diff + " StartTimingAddress: " + timingAddress + " PupeWriteTimingAddress: " + ofpga[regBase + TIME_TBLADDR]); #if DEBUG_DATA_ERROR printf("Data has already gone: Difference: %d StartTimingAddress: %x PupeWriteTimingAddress: %x\n", diff, timingAddress, ofpga[regBase + TIME_TBLADDR]); printf("PupeCycle: %d PupeTime: %d PupeTimingAddress: %x\n", ofpga[regBase + CYCLE], ofpga[regBase + TIME], ofpga[regBase + TIME_TBLADDR]); printf("GetData: CycleWanted: %u CurrentCycle: %u Diff: %d PupeCycle: %u CurrentPupeCycle: %u Period: %d\n", dataInfo.cycleNumber, ocycleNumber, diff,pupeCycleNumber, ofpga[regBase + CYCLE], dataInfo.cyclePeriod); printEventList(events); printf("CycleInfoTable Entry: %d\n", pupeCycleNumber & 0x03); hd32(ocycleInfoTable, 4 * 16); #endif } } } olock.unlock(); #if DEBUG_DATA_TIME printf("GetData: Times: %f, %f, %f, %f, %f Total: %f\n", t2 - t1, t3 - t2, t4 - t3, t5 - t4, t5 - t4, t5 - t1); #endif return err; } BError Pupe::getSimData(DataInfo dataInfo, Data& data){ BError err; SigGenBeam sigBeam; UInt32 i; Sample* samples; static Data dataCache; double t; double tend; struct timespec treq; t = getTime(); tend = t + (dataInfo.numValues * sizeof(DataValue)) / 100e6; 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.numBunches = 4; dataCache.numChannels = 1; 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; #ifndef ZAP // Delay to get data rate while((t = getTime()) < tend){ if((tend - t) > 0.01){ treq.tv_sec = 0; treq.tv_nsec = long((tend - t) * 1e9); nanosleep(&treq, 0); } } #endif return err; } BError Pupe::setTestMode(PuChannel puChannel, UInt32 testOutput, UInt32 timingDisableMask){ BError err; int regBase = 0; int brBase = 0; if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } if(osimulate){ err.set(ErrorNotImplemented, getName() + "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, getName() + "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(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } if(osimulate){ err.set(ErrorNotImplemented, getName() + "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<UInt64>& data){ BError err; int regBase = 0; int brBase = 0; UInt32 v = 0; int num = diagnosticsNumSamples; int timeOut; dprintf(DBG_FPGA, "Pupe::captureTestData\n"); if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } // Check Parameters if(captureInfo.startTime && captureInfo.postTriggerDelay) return err.set(ErrorParam, getName() + "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, getName() + "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, getName() + "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<UInt32> data){ BError err; int regBase = 0; int brBase = 0; BArray<UInt32> rdata; uint32_t i; dprintf(DBG_FPGA, "Pupe::setTestData: Len: %d\n", data.size()); if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } 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, getName() + "Incorrect puChannel"); } if(data.size() > (opageSize / sizeof(UInt32))){ return err.set(ErrorParam, getName() + "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, getName() + "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(10000); // Write to test data SDRAM fpgaWriteData64(data.data(), 0x0, data.size() * sizeof(UInt32)); // 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)); 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, getName() + "Error setting test data"); } } ofpga[MEM_REG] = SDRAM_BLOCKRAM; ofpga[TESTLEN] = data.size() / 2; ofpga[TESTCTRL] = (1 << 25); switch(puChannel.pupeChan){ case 1: ofpga[ADC] &= ~0x007; break; case 2: ofpga[ADC] &= ~0x038; break; case 3: ofpga[ADC] &= ~0x1C0; break; } ofpga[regBase + TEST] = ofpga[regBase + TEST] | 0x8000; } else { ofpga[regBase + TEST] = ofpga[regBase + TEST] & ~0x8000; switch(puChannel.pupeChan){ case 1: ofpga[ADC] |= 0x007; break; case 2: ofpga[ADC] |= 0x038; break; case 3: ofpga[ADC] |= 0x1C0; break; } #ifdef ZAP ofpga[TESTCTRL] = 0; #endif } 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,%d\n", pupeConfig.adcSysclkSync, pupeConfig.internalTimingMask, pupeConfig.disableBlr); if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } 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, getName() + "Incorrect puChannel"); } if(!osimulate){ // Enable timing bus simulation if(pupeConfig.internalTimingMask){ ofpga[TIMING_IO] = (ofpga[TIMING_IO] & ~0x00FF00) | (pupeConfig.internalTimingMask << 8); } else { ofpga[TIMING_IO] = ofpga[TIMING_IO] & ~0x00FF00; } if(pupeConfig.disableBlr){ ofpga[regBase + CONTROL] |= CONTROL_BLR_DISABLE; } else { ofpga[regBase + CONTROL] &= ~CONTROL_BLR_DISABLE; } // This sets up the ADC Clock if(pupeConfig.adcSysclkSync != opupeConfig.adcSysclkSync){ if(pupeConfig.adcSysclkSync){ opllSynth.setMode(PllSynth::VCXO_REF); } else { opllSynth.setMode(PllSynth::VCXO); } // opllSynth.displayRegisters(); // Reset memory DCM's ofpga[LOCKED] = 0x01; } } opupeConfig = pupeConfig; return err; } BError Pupe::getPupeConfig(PuChannel puChannel, PupeConfig& pupeConfig){ BError err; int regBase = 0; int brBase = 0; dprintf(DBG_FPGA, "Pupe::getPupeConfig: %d.%d.%d\n", puChannel.moduleNum, puChannel.pupeNum, puChannel.pupeChan); if(!oinitialised){ return err.set(ErrorFpga, getName() + "Not present"); } 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, getName() + "Incorrect puChannel"); } pupeConfig = opupeConfig; return err; } int Pupe::adcPllLockCheck(){ int v; if(oinitialised && opupeConfig.adcSysclkSync){ v = opllSynth.lockStatus(); dprintf(DBG_FPGA, "LockStatus: %d Count: %d\n", v, opllRefErrors); if(!v){ opllRefErrors++; opllSynth.lockReset(); } opllLocked = opllSynth.lockStatus(); } else { opllLocked = 0; } return opllLocked; } 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]; } ofpga[ADC] |= ADC_LED_YELLOW; 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); ofpga[ADC] &= ~ADC_LED_YELLOW; 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_OpenCardByIndex(oboard, &ofpgaCard)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_GetCardInfo(ofpgaCard, &ocardInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_SetClockRate(ofpgaCard, 0, lclk, NULL)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + ADMXRC2_GetStatusString(status)); return err; } if((status = ADMXRC2_SetClockRate(ofpgaCard, 1, mclk, NULL)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + 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 LOAD_USE_DMA if((status = ADMXRC2_ConfigureFromFileDMA(ofpgaCard, fileName, ADMXRC2_DMACHAN_ANY, 0)) != ADMXRC2_SUCCESS){ #else if((status = ADMXRC2_ConfigureFromFile(ofpgaCard, fileName)) != ADMXRC2_SUCCESS){ #endif return err.set(Tms::ErrorFpga, getName() + "Fpga Error: " + "Configuring FPGA from File: " + ADMXRC2_GetStatusString(status)); } #ifdef ZAP else { usleep(500000); } #endif } else { return err.set(Tms::ErrorFpga, getName() + "Fpga Error: " + "File: " + fileName + " not found"); } if((status = ADMXRC2_GetSpaceInfo(ofpgaCard, 0, &spInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + "Fpga Error: " + ADMXRC2_GetStatusString(status)); return err; } ofpga = (volatile uint32_t*)spInfo.VirtualBase; if((status = ADMXRC2_GetSpaceInfo(ofpgaCard, 1, &spInfo)) != ADMXRC2_SUCCESS){ err.set(Tms::ErrorFpga, getName() + "Fpga Error: " + ADMXRC2_GetStatusString(status)); return err; } ofpgaControl = (volatile uint32_t*)spInfo.VirtualBase; v = ofpga[FIRMWARE]; if(((v >> 24) & 0xFF) != 'C'){ err.set(ErrorFpga, getName() + "FPGA Firmware type incorrect"); } else { nprintf("Pupe: FpgaVersion: %d.%d.%d\n", ((v >> 16) & 0xFF), ((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); pthread_testcancel(); 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, getName() + "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(opupeConfig.disableBlr){ 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; } // Setup Interrupt handler ointerruptThread.start(); ofpga[IER] = INT_PU0_CYCLE_START | INT_PU0_CYCLE_STOP | INT_PU0_ERROR | INT_PU1_ERROR | INT_PU2_ERROR; // 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<UInt32> 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<NameValue> 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, getName() + "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, getName() + "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, getName() + "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)){ ofpga[MEM_REG] = SDRAM_BLOCKRAM; 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); } ofpga[MEM_REG] = SDRAM_BLOCKRAM; 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(); ADMXRC2_CancelWaitForInterrupt(ofpgaCard); 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<NameValue>& 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){ 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, getName() + "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; }