/************************************************************************************* * masterPrimFuncts.c * * synopsis: Contains the primitive functions which are used only by the master DSP. * * in this file: rwSlaveMemory, tranSerialData, startSlaveExecuting, configSlave, * rwRegField, pollRegField, rwFifo, sendSlaveList, startSlaveList, * slaveListOp, buildStream, sendStream, dspReset, setRodMode, * rwBocData, bocHistogram. * * related files: * masterPrimFuncts_pxl.c, masterPrimFuncts_sct.c: Detector-specific MDSP primitives * listManager.c: Routines which manage the execution of a primitive list and * writing the reply data. * primFuncts.h: Declares the structure tag which communicates necessary information * to primitive functions. * primParams.h: Defines primitive ids which are used to index the array of pointers * to primitive functions, structure tags for primitive data and reply * data, and prototypes of primitive functions. * primFuncts.c: Contains primitive execution functions and the function which ini- * tializes the array of pointers to the primitive execution functions. * serialStreams.c: Contains routines which send and build serial streams to send to * the detector electronics. * * Damon Fasching, UW Madison fasching@wisconsin.cern.ch * Douglas Ferguson, UW Madison (510) 486-5230 dpferguson@lbl.gov * Richard Jared, Lawrence Berkeley Lab rcjared@lbl.gov * Tom Meyer, Iowa State University meyer@iastate.edu * Roy McKay, Iowa State University mckay@iastate.edu * John Richardson, Lawrence Berkeley Lab john.richardson@cern.ch * Joseph Virzi, UC Berkeley jsvirzi@lbl.gov ************************************************************************************/ #include #include #include #include #include #include #include #include #include #include "resources.h" #include "registerIndices.h" #include "accessSlave.h" #include "serialStreams.h" #include "comRegDfns.h" extern char genStr[]; extern TIMER_Handle timer1; /* general purpose timer, started in main() */ extern far Module moduleConfigSet[N_MODULE_CONFIG_SETS][N_TOTMODULES]; extern far CmdBuff cmdBuffer[]; extern far BOCConfig bocConfig; #pragma CODE_SECTION(rwSlaveMemory, "xcode"); #pragma CODE_SECTION(transSerialData, "xcode"); #pragma CODE_SECTION(startSlaveExecuting, "xcode"); #pragma CODE_SECTION(configSlave, "xcode"); #pragma CODE_SECTION(rwRegField, "xcode"); #pragma CODE_SECTION(pollRegField, "xcode"); #pragma CODE_SECTION(rwFifo, "xcode"); #pragma CODE_SECTION(sendSlaveList, "xcode"); #pragma CODE_SECTION(startSlaveList, "xcode"); #pragma CODE_SECTION(slaveListOp, "xcode"); #pragma CODE_SECTION(buildStream, "xcode"); #pragma CODE_SECTION(sendStream, "xcode"); #pragma CODE_SECTION(dspReset, "xcode"); #pragma CODE_SECTION(setRodMode, "xcode"); #pragma CODE_SECTION(rwBocData, "xcode"); #pragma CODE_SECTION(bocHistogram, "xcode"); #pragma CODE_SECTION(writeFlash, "xcode"); /************************************************************************************ * rwSlaveMemory (previously loadSlaveMemory) * * synopsis: Loads slave memory from the contents of a primitive from the host to * the master. * * arguments: * * IN: * sdsp: ID of the SDSP to be accessed * fRead = FALSE for writing to SDSPs, or TRUE for reading. * *slaveAddress: slave reads: source address of the data * slave writes: destination address of the data * *masterAddress: slave reads: destination address of the data; the special value * DEFAULT puts the data in the body of the reply msg * just after the RW_SLAVE_MEMORY_OUT structure * slave writes: source address of the data; the special value * DEFAULT gets the data from the body of the primitive * just after the RW_SLAVE_MEMORY_IN structure * numWords: number of 32 bit words to read or write * * author: Tom Meyer * * modifications/bug fixes * - Data was written FROM *destAddress rather than from the desired source * address!! Added the input structure element *sourceAddress which is now * the from address. dpf * - Added the required line, "primtData->repBodyLength = SIZEOF(...);" * Primitives which have reply data must have this or the reply data * will be ignored. dpf * - Added the #define TI_EVM block for debugging on the evm. dpf * - Added the special value of sourceAddress, 'DEFAULT'. This indicates * the source of the data is the body of this primitive just after the * last element of the LOAD_SLAVE_MEMORY_IN structure. dpf * - Changed it from loading bytes to loading 32b words. This meshes * better with 32b access over the slave HPI. dpf * - return value of numWords is assigned to input numWords rather than * final value of wordIdx; rather not use wordIdx outside of the loop. dpf * - added check on sdsp: slaveStat = slaveIsOn(sdsp) 4-17-01 dpf * - added read option and renamed (loadSlaveMemory => rwSlaveMemory) 4-25-01 dpf * - added argument descriptions and READING and WRITING macros 4-25-01 dpf * - got rid of output data structure 4-25-01 dpf * - modified routine to use read/writeSlvBlock 10.08.03 dpsf ************************************************************************************/ INT32 rwSlaveMemory(PrimData *primData) { INT32 returnCode= SUCCESS; UINT32 slaveNumber; UINT32 fRead; UINT32 *slaveAddress, *masterAddress; UINT32 numWords; INT32 slaveStat; UINT32 wordIdx; #define READING (fRead) #define WRITING (!READING) RwSlaveMemory *rwSlaveMemoryIn = (RwSlaveMemory *) primData->priBodyPtr; slaveNumber = rwSlaveMemoryIn->slaveNumber; slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "rwSlaveMemory", "Attempt to access memory of a nonexistent slave DSP.\n", __FILE__, __LINE__); return returnCode; } fRead= rwSlaveMemoryIn->readNotWrite; numWords= rwSlaveMemoryIn->numWords; slaveAddress= rwSlaveMemoryIn->slaveAddress; if (rwSlaveMemoryIn->masterAddress == (UINT32 *)(DEFAULT)) { if (WRITING) { masterAddress= (UINT32 *)rwSlaveMemoryIn +SIZEOF(RwSlaveMemory); } else { masterAddress= (UINT32 *)primData->repBodyPtr; } } else { masterAddress= rwSlaveMemoryIn->masterAddress; } if (WRITING) writeSlvBlock(slaveNumber, slaveAddress, masterAddress, numWords); else readSlvBlock(slaveNumber, slaveAddress, masterAddress, numWords); if (READING && (rwSlaveMemoryIn->masterAddress == (UINT32 *)(DEFAULT))) { primData->repBodyLength = numWords; } return returnCode; } /****************************************************************************************** * in masterPrimFuncts.c * * tranSerialData ROUTINE MUST BE IN IPRAM! (TIME CRITICAL) * * Synopsis: * The input data is defined as integer captureSerOn * (flage to turn on data capture), integer numSets (number of * data sets) and sets of serial data to transmit. The number of data sets * is limited to 2000 (bit streams of 2000words x 32 bits = 64,000 bits). * Each data set contains 2 words. One 32b word for each serial port. * The data sets are written two the serial ports with programmed IO * in a tight loop. Writing of the serial data set must be done * within 32 clk 40 ticks. * The result is a set of serial data that is clocked at 40 MHz with * no padded zeroes. * The last data set must be all zeros so that the handler * is in the initial state of transmitting the data of all zero over and * over again. * When a primitive sends data to the serial port the following steps are followed. * 1. The captureSerOn is tested for TRUE. If true the input memory FIFOs will be * stared to capture the serial data from the module return data. * Of the 4096 samples at 40 MHz only about 3900 will contain data * due to latencies. This data is read by the primitive rwFifo() after * this primitive is complete. In the special case where there is more * than 3900 data bits only the first bits in the stream will be recorded in the in memory. * 2. To transmit serial data (40 MHz bit stream)the function must first test * the flag that determins if the data in the serial output * register has been sent. * 3. When data has been sent it writes a new word to the transmitter data * register that will be sent out as serial data. * 4. Steps 2 and 3 are repeated for each word. * Note 1: the last work sent is zero so that the port will be in the state for a low * output level (ready for the next series of data words). * Note 2: The writing of successive data words must be within 32 40 MHz periods * or unwanted repeating of the current word will occure. * * TBD Note: Operations of FPGA Controller needs are defined here. A working * definition is detailed below. * Serial Port 0 is the input data stream to the normal data path mask bit * register (48 bits) (streams can be sent to any/all or subset of the control * links) that supply bit streams to the front end modules. * Serial Port 1 is the input data stream to the secondary data path mask bit * register (48 bits) (streams can be sent to any/all or subset of the control * links) that supply bit streams to the front end modules. * The resultant streams of data for each front end link (links)are ORed together * on a module control link by link basis. * The Controler FPGA modes are define by 2 bits in the control Register. * State (code 0x0) Normal Running The serial bit streams are ignored * State (code 0x1) Normal Running with Port 1 active for configuration. * This state allows configuation of front end modules via stream 1 * during normal data taking. The mask bit resiters must not point at * the same module bit streams (programmer beware). * State (code 0x02) Port 1 and 2 acitve for module configuration. * Two front end modules can be configured at the same time. The * normal running and secondary mask register should not point * at the same modules (programmer beware). For the pixel 5 MHz data * streams the bit stream will be in the same value for 8 clock * 40 ticks. * State (code 0x3) Ports 1 and 2 are active for trigger and other fast * commands. * The controller FPGA contains contains 2 sets of register ( * event type and event ID )and 2 sets of * beam crossover and L1 trigger counters. * Event ID register (2 ea.) static contains the event type * set by a primitive. One for each serial link. * Event type Register (2 ea.) static contains the event ID * set by a primitive. One for each serial link. * BCO counter (one of each serial link) is reset when a reset fast * command is sent by the corresponding serial link. The counters are * incremented at 40 MHz. * LI trigger (one for each link) is reset when a reset fast command * is sent by the corresponding serial link. Counter is incremented * when a trigger is sent by the corresponding serial link. * This mode is intended for study of two trigger streams to * the front end modules for diagnostic of cross talk and other * effects. The conbined triggers must be at least 6 clock 40 ticks * apart. Bit stream 1 has a latency of 3 to 4 clock 40 ticks compared * to bit stream 0.There are no other special restrictions (programmer beware). * The normal running and secondary mask register should not point * at the same modules (programmer beware) but is can be done if the * programmer is very carefull to not have simulatious command bits (note * latency above). * * Input: * extern serPort0Handle Defined and initalized in initSerPort.c * extern serPort1Handle Defined and initalized in initSerPort.c * * TransData { defined in primParms.h * UINT32 port0Data; 32b serial data port 0 * UINT32 port1Data; 32b serial data port 1 * }; * struct TRANS_SERIAL { defined in primParms.h * UINT32 captureSerOn; Capture module return data in input FIFOs * UINT32 numSets; number of data sets to transmit * struct TRANS_DATA_IN dataIn[n]; array of data * }; * Output: none * * error: return error mesage if the last data set is not =0 or to many data sets. * No serial data is transmitted. * * Richard Jared * * modifications/bugs * - Added bracketing calls to HWI and SWI disabling/re-enabling routines * around the critical code which does the transfer. 18.02.02 dpsf * * - Added code which adjusts the latency of the two serial streams to 0, * using inline assembly language statements. Proper adjustment requires * that the compilation flags for this routine be set to o1, overriding * the project optimizations. The serial data is referred to through * pointers instead of dummy arrays, and there is no longer any need to * have the data streamed out of IDRAM. SDRAM is fast enough. 28.05.02 LT * * - The code which sends the serial stream is now in a separate function, * serialStreamOut.c 26.06.02 dpsf * - Removed the stream interleaving in serialStreamOut (needed by other * functions). Streams now completely independent. 05.03.02 dpsf ******************************************************************************************/ INT32 transSerialData( PrimData *primData ) { INT32 returnCode= SUCCESS; /* set structure pointer to primitive data */ TransSerialDataIn *transSerialDataIn= (TransSerialDataIn *) primData->priBodyPtr; UINT32 captureSerOn, *stream[2], streamLen[2], nSets, *ptr; /* TransData *dataIn= (TransData*) &transSerialDataIn->dataIn; const UINT32 numSets= transSerialDataIn -> numSets; */ captureSerOn= transSerialDataIn->captureSerOn; streamLen[0]= transSerialDataIn->streamLen[0]; streamLen[1]= transSerialDataIn->streamLen[1]; stream[0]= (UINT32 *) &transSerialDataIn->streams; stream[1]= ((UINT32 *) &transSerialDataIn->streams) +streamLen[0]; interleave(streamLen, stream, &ptr, &nSets); serialStreamOut(captureSerOn, (TransData *) ptr, nSets); /* serialStreamOut(captureSerOn, stream, streamLen); */ return returnCode; } /************************************************************************************ * startSlaveExecuting * * synopsis: Sets DSPINT to put slave into execution then waits for the RUNNING bit * to be set in the slave's status register. When this happens, it reads * the text buffer addresses from the slave's reply buffer and sends them * back to the host in a reply message. * * arguments: * IN * slaveNumber: ID of slave to be started * commOnOff: Indicates whether the master DSP is going to attend * to this slave or not. (Sets a configuration bit in * the master DSP rodConfig structure.) added 1-01-01 dpf * slaveType: Sets the type member for this slave in the master * DSP rodConfig structure.) added 1-01-01 dpf * * author: Tom Meyer * * bug fixes/modifications: * - Added call to new function, setSlaveConfig. 1-01-01 dpf * - Added assignment statement for repBodyLength. 1-01-01 dpf * - Fixed error returns. 1-09-01 dpf * - Added call to new access routine, getRunningBit() 4-05-01 dpf * - Removed clear of DSPINT bit; it is autocleared on boot. 4-10-01 dpf * - Added code to set the NOHOLD bit in the slave EMIF. This code can be * removed if the production ROD does not leave the NOHOLD input pin * floating. 4-13-01 dpf * - added check on slaveNumber: slaveStat = slaveIsOn(slaveNumber) 4-17-01 dpf * - released timer channel with TIMER_STOP(timerChan) 4-17-01 dpf * - replaced hardwired timerLimit = 41750000 with new input parameter, * timeoutInUsec. The timer units are 1/4 of the CPU clock. 5-15-01 dpf * - Added call to setSlvID after the slave is running. (So that their * messages while running are unambiguously identified). 06.05.01 dpsf * - Replaced call to startUserTimer with a measurement of the time at * init-- the user timer is now started in main() with the maximal period * and left running. Successive calls to TIMER_getCount will subtract * correctly. 09.01.03 dpsf ************************************************************************************/ INT32 startSlaveExecuting(PrimData *primData) { UINT32 timeoutInTmrUnits, timeOut, initTime; UINT32 slaveNumber, commOnOff, slaveType, timeoutInUsec; INT32 slaveStat; UINT32 hpic; INT32 errorKeep, returnCode = SUCCESS; StartSlaveExecutingIn *startSlaveExecutingIn= (StartSlaveExecutingIn *)primData->priBodyPtr; StartSlaveExecutingOut *startSlaveExecutingOut= (StartSlaveExecutingOut *)primData->repBodyPtr; slaveNumber = startSlaveExecutingIn->slaveNumber; commOnOff = startSlaveExecutingIn->commOnOff; slaveType = startSlaveExecutingIn->slaveType; timeoutInUsec = startSlaveExecutingIn->timeoutInUsec; timeoutInTmrUnits = timeoutInUsec * (DSPClockInMHz()/4); slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "startSlaveExecuting", "Attempt to boot a nonexistent slave DSP.\0", __FILE__, __LINE__); return returnCode; } else { initTime= TIMER_getCount(timer1); if (GET_RBIT(DIAGNOSTIC_REG, DR_SPEED_220)) setSlvClk(slaveNumber, 11); /* Now start the CPU by setting DSPINT bit of HPIC; DSPINT is autoreset. * Must keep HWOB bit set as well. */ hpic= (1 << _HPI_HPIC_HWOB_SHIFT) | (1 << _HPI_HPIC_DSPINT_SHIFT); hpic|= (hpic < timeoutInTmrUnits) { newError(&errorKeep, TIMEOUT_ERR, FATAL_ERR, "startSlaveExecuting", "Timer timed out.", __FILE__, __LINE__); timeOut= TRUE; } } while ( ! (getSlvRunning(slaveNumber) || timeOut)); setSlvID(slaveNumber); /* Give the slave an ID. */ /* Set up the master DSP for a newly activated slave DSP. */ if (!timeOut) { setSlaveConfig(slaveNumber, commOnOff, slaveType); readSlvTxtBuffAddr(slaveNumber); startSlaveExecutingOut->slaveNumber = slaveNumber; } else { startSlaveExecutingOut->slaveNumber = 0xFFFFFFFF; } primData->repBodyLength = SIZEOF(StartSlaveExecutingOut); } return SUCCESS; } /************************************************************************************ * configSlave * * synopsis: Fills the save DSP configuration struct. * * arguments * IN: * slaveNumber: number of slave DSP to configure * commOnOff: turn the slave on or off * slaveType: type of slave DSP, e.g. error correction, monitoring hists... * * author: Damon Fasching ************************************************************************************/ INT32 configSlave(PrimData *primData) { INT32 returnCode = SUCCESS; INT32 slaveStat; UINT32 slaveNumber, commOnOff, slaveType; ConfigSlaveIn *configSlaveIn= (ConfigSlaveIn *)primData->priBodyPtr; slaveNumber = configSlaveIn->slaveNumber; commOnOff = configSlaveIn->commOnOff; slaveType = configSlaveIn->slaveType; slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "configSlave", "Attempt to configure a nonexistent slave DSP.\0", __FILE__, __LINE__); return returnCode; } else { setSlaveConfig(slaveNumber, commOnOff, slaveType); } return returnCode; } /************************************************************************************ * rwRegField * * synopsis: Reads or writes a field of a register in the master DSP memory map. * Should NOT be used to read or write the memories, i.e. inmem, debugmem * and eventmem. * * arguments * IN: * registerID: mnemonic symbols to be used are defined in registerIndices.h * fRead: 1 for read, 0 for write * offset: lsb of bit field to be read or written * width: width of bit field to be read or written * dataIn: value to be written to field * OUT: * dataOut: value read from field * * author: Damon Fasching * * bug fixes/modifications * - added BOC specific code 3-20-02 rcj * ************************************************************************************/ INT32 rwRegField(PrimData *primData) { INT32 error, returnCode = SUCCESS; RwRegFieldIn *rwRegFieldIn= (RwRegFieldIn *) primData->priBodyPtr; RwRegFieldOut *rwRegFieldOut= (RwRegFieldOut *) primData->repBodyPtr; UINT32 fRead, registerID, offset, width, dataIn, dataOut; UINT8 bocReg, link, data; registerID= rwRegFieldIn->registerID; offset= rwRegFieldIn->offset; width= rwRegFieldIn->width; fRead= rwRegFieldIn->readNotWrite; dataIn= rwRegFieldIn->dataIn; if ( (registerID >= FIRST_BOC_REG) && (registerID <= LAST_BOC_REG) ) { /* 1st translate from the register ID to the BOC register & link #. */ bocRegDecode(registerID, &bocReg, &link); if (fRead) {error= getBocVariable(link, bocReg, &data); dataOut= data; } else {error= setBocVariable(link, bocReg, (UINT8) dataIn); } if (error < 0) { if (fRead) { addError(&returnCode, error, "rwRegField", "getBocVariable", __FILE__, __LINE__); } else { addError(&returnCode, error, "rwRegField", "setBocVariable", __FILE__, __LINE__); } } if ((fRead) && (!(FATAL(error))) ) { rwRegFieldOut->dataOut = dataOut; primData->repBodyLength = SIZEOF(RwRegFieldOut); } } else { if (fRead) { error = readRegister( registerID, width, offset, &dataOut); if (!(FATAL(error))) { rwRegFieldOut->dataOut = dataOut; primData->repBodyLength = SIZEOF(RwRegFieldOut); } } else { error = writeRegister(registerID, width, offset, dataIn); } if (error < 0) { if (fRead) { addError(&returnCode, error, "rwRegField", "readRegister", __FILE__, __LINE__); } else { addError(&returnCode, error, "rwRegField", "writeRegister", __FILE__, __LINE__); } } } /* register not in BOC range */ return returnCode; } /************************************************************************************ * pollRegField * * synopsis: Polls a field of a register for a value. A timeout is available. * * arguments * IN: * registerID: ID of the register being polled * offset: number of lsb in the field, starting with 0 * width: width of the field * desiredValue: value of the defined field to poll for * timeoutInUsec: timeout period in microseconds * OUT: * found: indicates whether 'desiredValue' was found within 'timeoutInUsec' * * author: Damon Fasching * * bug fixes/modifications: * - Replaced call to startUserTimer with a measurement of the time at * init-- the user timer is now started in main() with the maximal period * and left running. Successive calls to TIMER_getCount will subtract * correctly. 09.01.03 dpsf ************************************************************************************/ INT32 pollRegField(PrimData *primData) { INT32 returnCode = SUCCESS, error; static UINT32 polling = 0, found, timedOut, initTime; static UINT32 registerID, offset, width; static UINT32 desiredValue, timeoutInTmrUnits; UINT32 timeoutInUsec; UINT32 currentValue; PollRegFieldIn *pollRegFieldIn= (PollRegFieldIn *)primData->priBodyPtr; PollRegFieldOut *pollRegFieldOut= (PollRegFieldOut *)primData->repBodyPtr; /* 1st time entering function, initialize static variables and start timer */ if (!polling) { initTime= TIMER_getCount(timer1); registerID = pollRegFieldIn->registerID; offset= pollRegFieldIn->offset; width= pollRegFieldIn->width; desiredValue= pollRegFieldIn->desiredValue; timeoutInUsec= pollRegFieldIn->timeoutInUsec; timeoutInTmrUnits= timeoutInUsec * (DSPClockInMHz()/4); found= FALSE; timedOut= FALSE; polling= TRUE; } /* read register, check current time if value not ok */ error = readRegister(registerID, width, offset, ¤tValue); if (error < 0) { addError(&returnCode, error, "pollRegField", "readRegister", __FILE__, __LINE__); } if (currentValue == desiredValue) found= TRUE; else if ((TIMER_getCount(timer1) -initTime) > timeoutInTmrUnits) timedOut= TRUE; /* If found or timed out, build reply structure, reset polling, return SUCCESS; * NOTE: The return value of a routine indicates whether or not it had an * execution error. A time out while polling for the register is not an * error in the execution of the routine, so SUCCESS is still returned. The * timeout is indicated by found = 0 in the reply data structure. It may be * useful to make an exception here and return a fatal error code in case of * a time out so that the remainder of the primitive list is aborted. dpf */ if (found || timedOut || FATAL(returnCode)) { pollRegFieldOut->found = found; primData->repBodyLength = SIZEOF(PollRegFieldOut); polling = 0; if (!FATAL(returnCode)) { returnCode = SUCCESS; } } else { returnCode = REPEAT_PRIMITIVE; } return returnCode; } /************************************************************************************ * rwFifo * * synopsis: Reads/writes some number of elements from/to a FIFO on the ROD. * * arguments * IN: * fifoID: mnemonic symbols to be used are defined in primParams.h * bank: mnemonic symbols to be used are defined in primParams.h * fRead: 1 = read, 0 = write * numElements: number of data elements to read or write * *data: for fRead = 0 source address of data for the FIFO * = 1 destination address for data from the FIFO * if *data = DEFAULT (defined in primParams.h) * fRead = 0: data is supplied with the RW_FIFO primitive after *data * fRead = 1: data is written to the reply msg body after bytesXfrd * There is also a scratch space in SDRAM at SCRATCH_BASE (memoryPartitions.h) * OUT: * bytesXfrd: The number of individual read or write operations performed. * (a more complete description is in primParams.h or accessFifo.c) * * author: Damon Fasching ************************************************************************************/ INT32 rwFifo(PrimData *primData) { INT32 error = SUCCESS, returnCode = SUCCESS; UINT32 bank, fifoId, fRead, numElements, *dataBaseAdr, bytesXfrd; RwFifoIn *rwFifoIn= (RwFifoIn *) primData->priBodyPtr; RwFifoOut *rwFifoOut= (RwFifoOut *) primData->repBodyPtr; fifoId= rwFifoIn->fifoId; bank= rwFifoIn->bank; fRead= rwFifoIn->readNotWrite; numElements = rwFifoIn->numElements; if (rwFifoIn->dataBaseAdr == (UINT32 *)(DEFAULT)) { if (fRead) { dataBaseAdr = (UINT32 *)rwFifoOut + SIZEOF(RwFifoOut); } else { dataBaseAdr = (UINT32 *)rwFifoIn + SIZEOF(RwFifoIn); } } else { dataBaseAdr = rwFifoIn->dataBaseAdr; } bytesXfrd = 0; error = accessFifo(fifoId, bank, fRead, numElements, dataBaseAdr, &bytesXfrd); /* set the reply parameters */ rwFifoOut->bytesXfrd = bytesXfrd; primData->repBodyLength = SIZEOF(RwFifoOut); /* if reading to the reply buffer, update the reply body length */ if (fRead) { if (rwFifoIn->dataBaseAdr == (UINT32 *)(DEFAULT)) { primData->repBodyLength = primData->repBodyLength + (bytesXfrd/4); if ((bytesXfrd % 4) != 0) { primData->repBodyLength = primData->repBodyLength + 1; } } } if (error < 0) { addError(&returnCode, error, "rwFifo", "accessFifo", __FILE__, __LINE__); if (FATAL(returnCode)) { return returnCode; } } return returnCode; } /************************************************************************************ * sendSlaveList * * synopsis: Sends a primitive list to a slave DSP. * * arguments * IN: * slaveNumber - ID of targeted slave DSP * listLength - length in 32 bit words of primitive list * *slavePrimList - Address of the slave primitive list source * - *slavePrimList = DEFAULT indicates that the slave primitive list is stored * in the body of this SEND_SLAVE_LIST primtive starting just after the last * SEND_SLAVE_LIST_IN structure element. * *slaveRepData - Address where master should put slave reply data if the * START_SLAVE_LIST primitive is executed with getSlaveReply != 0. * - *slaveRepData = DEFAULT indicates that the slave reply list should be * stored in the body of a reply message of the next START_SLAVE_LIST * for this slave primtive. * * author: Damon Fasching * * modifications/bugs: * - The slave was receiving listLength copies of the 1st word of the * primitive list, 'listLength'. SEND_SLAVE_LIST_IN structure element * *slavePrimList was being used incorrectly. That has been fixed. It * is now really interpreted as a pointer to the source list. In addition * the special value, 'DEFAULT', has been added which indicates the * body of this primitive is the source of the slave primitive list. 4/10/01 dpf * - Made new routine, loadSlaveList() in listManager.c. Moved the code which * does the actual list transfer to that routine. memoryPartitions.h * removed from the include list above. 4/11/01 dpf * - Moved *slaveRepData parameter from startSlaveList to here and added * call to a new routine, storeReplyParams. This was needed because * the slave reply should be associated with this primitive, not the * startSlaveExecuting primitive. 4/13/01 dpf ************************************************************************************/ INT32 sendSlaveList(PrimData *primData) { INT32 returnCode = SUCCESS; INT32 slaveStat; UINT32 slaveNumber; UINT32 listLength; UINT32 *slavePrimList; UINT32 *slaveRepData; SendSlaveListIn *sendSlaveListIn= (SendSlaveListIn *)primData->priBodyPtr; slaveNumber = sendSlaveListIn->slaveNumber; slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "sendSlaveList", "Attempt to send host primitive list to a nonexistent slave DSP.\0", __FILE__, __LINE__); return returnCode; } else if (SDSP_NOT_CONFIGURED(slaveStat)) { newError(&returnCode, SLAVE_DSP_OFF, FATAL_ERR, "sendSlaveList", "Attempt to send host primitive list to a disabled slave DSP.\0", __FILE__, __LINE__); return returnCode; } else if (SDSP_HOST_LIST_BUSY(slaveNumber)) { /****** ****** ****** add a timeout or max reps here ****** ****** ******/ return REPEAT_PRIMITIVE; } else { /* get length and address of list, copy it to primitive list buffer on slave */ listLength = sendSlaveListIn->listLength; if (sendSlaveListIn->slavePrimList == (UINT32 *)(DEFAULT)) { slavePrimList= (UINT32 *)sendSlaveListIn + SIZEOF(SendSlaveListIn); } else { slavePrimList= sendSlaveListIn->slavePrimList; } loadSlaveList(slaveNumber, listLength, slavePrimList); slaveRepData= sendSlaveListIn->slaveRepData; storeReplyParams(slaveNumber, slaveRepData); } return returnCode; } /************************************************************************************ * startSlaveList * * synopsis: Initiates the execution of a primitive list by slave DSP. If the * targeted slave is already executing a primitive list, will wait for * that list to finish (by repeating this primitive until the slave is * finished or until a timeout). * * arguments * IN: * slaveNumber: ID of targeted slave DSP * pauseMasterList != 0 if master DSP list pauses while slave list executes * getSlaveReply != 0 if the master should read the slave reply data * * author: Damon Fasching * * bugs/modifications: * - Added getSlaveReply parameter to indicate whether the master DSP * should retrieve reply data from the slave when the slave is done * executing. 4/13/01 dpf ************************************************************************************/ INT32 startSlaveList(PrimData *primData) { INT32 returnCode = SUCCESS; INT32 slaveStat; UINT32 slaveNumber; UINT32 pauseMasterList; UINT32 getSlaveReply; StartSlaveListIn *startSlaveListIn= (StartSlaveListIn *)primData->priBodyPtr; slaveNumber = startSlaveListIn->slaveNumber; slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "startSlaveList", "Attempt to start primitive list on nonexistent slave DSP.\0", __FILE__, __LINE__); return returnCode; } else if (SDSP_NOT_CONFIGURED(slaveStat)) { newError(&returnCode, SLAVE_DSP_OFF, FATAL_ERR, "startSlaveList", "Attempt to start primitive list on disabled slave DSP.\0", __FILE__, __LINE__); return returnCode; } else if (SDSP_HOST_LIST_BUSY(slaveNumber)) { /****** ****** ****** add a timeout or max reps here ****** ****** ******/ return REPEAT_PRIMITIVE; } else { pauseMasterList = startSlaveListIn->pauseMasterList; getSlaveReply = startSlaveListIn->getSlaveReply; initiateSlvList(slaveNumber, pauseMasterList, getSlaveReply); } return returnCode; } /************************************************************************************ * slaveListOp * * synopsis: Pauses, resumes or aborts list execution on a slave DSP. * * arguments * IN: * UINT32 slaveNumber - ID of targeted slave DSP * UINT32 listOp - pause, resume or abort * * author: Damon Fasching ************************************************************************************/ INT32 slaveListOp(PrimData *primData) { INT32 returnCode = SUCCESS; INT32 slaveStat; UINT32 slaveNumber, listOp; SlaveListOpIn *slaveListOpIn= (SlaveListOpIn *)primData->priBodyPtr; slaveNumber = slaveListOpIn->slaveNumber; listOp = slaveListOpIn->listOp; slaveStat = slaveIsOn(slaveNumber); if (SDSP_DOES_NOT_EXIST(slaveStat)) { newError(&returnCode, SLAVE_DSP_DNE, FATAL_ERR, "slaveListOp", "Attempt to perform list operation on a nonexistent slave DSP.\0", __FILE__, __LINE__); return returnCode; } else if (SDSP_NOT_CONFIGURED(slaveStat)) { newError(&returnCode, SLAVE_DSP_OFF, FATAL_ERR, "slaveListOp", "Attempt to perform list operation on a disabled slave DSP.\0", __FILE__, __LINE__); return returnCode; } else { if (LIST_PAUSE == listOp) {initiateSlvPause(slaveNumber); } else if (LIST_RESUME == listOp) {initiateSlvResume(slaveNumber); } else if (LIST_ABORT == listOp) {initiateSlvAbort(slaveNumber); } } return SUCCESS; } #define BUILDSTREAM_CMD_ID 0xab /************************************************************************************ * buildStream * * synopsis: Appends a series of input commands to one or both of the serial port * buffers. * * arguments * IN: * struct CmdList cmdList Structure which contains the input commands. * UINT32 port The serial port; can be SP0 (0), SP1 or SP_BOTH (2) * UINT32 reset If set, will clear the buffer before building the stream; * if not set, will append to the end of a pre-existing stream. * UINT32 chip The chip number the commands apply to (for addressed * commands); can be ALL_CHIPS. * * SCT: UINT32 fibre The fibre to address. * or Pixel: UINT32 feFlavour The front-end flavour (FE-I1 or FE-I2) * * UINT32 dataLen Length of any extra data, in bits. * UINT32 *data; Start of the data for a command with large amounts of * data (masks & some pixel commands). * * author: Douglas Ferguson ************************************************************************************/ INT32 buildStream(PrimData *primData) { INT32 returnCode= SUCCESS, errorCode; BuildStreamIn *buildStreamIn= (BuildStreamIn *) primData->priBodyPtr; struct CmdList cmdList, *cmdListPtr[2]; UINT8 port, reset, chip, fibre; UINT32 dataLen, *data; UINT32 *ptr, nSets; cmdList= buildStreamIn->cmdList; port= buildStreamIn->port; reset= buildStreamIn->reset; chip= buildStreamIn->chip; fibre= buildStreamIn->fibre; dataLen= buildStreamIn->dataLen; data= buildStreamIn->data; if (port > SP_BOTH) { sprintf(genStr,"%s%d%s%s","Serial port buffer (", port,") ", "is out of range! \n"); newError(&returnCode, INVALID_CMD_STREAM_BUF, FATAL_ERR, "buildStream", genStr, __FILE__, __LINE__); return returnCode; } cmdListPtr[0]= cmdListPtr[1]= NULL; if ((port == SP0) || (port == SP_BOTH)) cmdListPtr[0]= &cmdList; if ((port == SP1) || (port == SP_BOTH)) cmdListPtr[1]= &cmdList; errorCode= makeStreamSet(cmdListPtr[0], cmdListPtr[1], reset, chip, fibre, (dataLen*32), data, &ptr, &nSets, FALSE /*doInterleave*/); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "buildStream", "makeStreamSet", __FILE__, __LINE__); return returnCode; } return returnCode; } /************************************************************************************ * sendStream * * synopsis: Sends a serial stream out of one or both of the MDSP's serial ports. * * arguments * IN: * UINT32 port The serial port; can be SP0 (0), SP1 or SP_BOTH (2) * UINT32 captureSerOn Obsolete -- use set ROD mode if serial capture is * desired. * * author: Douglas Ferguson ************************************************************************************/ INT32 sendStream(PrimData *primData) { INT32 returnCode= SUCCESS; SendStreamIn *sendStreamIn= (SendStreamIn *) primData->priBodyPtr; UINT32 *stream[2]= {NULL, NULL}, streamLen[2]= {0, 0}, *ptr, nSets; UINT8 port, captureSerOn; port= sendStreamIn->port; captureSerOn= sendStreamIn->captureSerOn; /* check that it's a good buffer # and then send the stream, regardless of how it was built */ if (port > SP_BOTH) { sprintf(genStr,"%s%d%s%s","Command stream buffer (", port,") ", "is out of range! \n"); newError(&returnCode, INVALID_CMD_STREAM_BUF, FATAL_ERR, "sendStream", genStr, __FILE__, __LINE__); return returnCode; } if (port == SP_BOTH) { stream[0]= cmdBuffer[0].data; stream[1]= cmdBuffer[1].data; streamLen[0]= cmdBuffer[0].bufferSizeWords; streamLen[1]= cmdBuffer[1].bufferSizeWords; } else { stream[port]= cmdBuffer[port].data; stream[port^1]= NULL; streamLen[port]= cmdBuffer[port].bufferSizeWords; streamLen[port^1]= 0; } interleave(streamLen, stream, &ptr, &nSets); serialStreamOut(captureSerOn, (TransData *) ptr, nSets); return returnCode; } /************************************************************************************ * dspReset * * synopsis: Resets slave DSPs at run-time. After reset, re-loads the slave's * DMA registers. * * arguments * IN: slvBits: Bitfield indicating which slaves should be reset. * * forceSync: If set, the master DSP will check the slave clock's * synchronization after reset, and force it to be in sync. * DSP 0, 1 & 2 all have a global clock and should nearly always be * in sync; if not the router must be re-configured. DSP 3 shares a * global clock with DSP 0. When the ROD is powered on or the slave * is reset, it can come on with the clock either in phase, or 180 * degrees out of phase. Setting forceSync for this DSP will cause * the master to repeatedly attempt to put the slave in phase. * * nAttempts: If forceSync is set, the total # of reset attempts to make * before giving up. Note that at least one reset is always * performed. * * timeOut: A time-out in micro-seconds for the response pulse from * the Program Reset Manager. After the master DSP sends its * information to the PRM (a series of pulses from a receiver bit in * serial port 1, configured for general purpose I/O), the PRM responds * by sending an acknowledgement signal over SP0's receiver; the ack. * lasts until the reset is done. The time-out should be set to reflect * the length of the acknowledgement signal (for slave DSPs this should * be approximately. * * author: Douglas Ferguson ************************************************************************************/ INT32 dspReset(PrimData *primData) { INT32 returnCode= SUCCESS, errorCode; DspResetIn *dspResetIn= (DspResetIn *) primData->priBodyPtr; UINT8 slv, slvBits; slvBits= dspResetIn->slvBits; for (slv=0; slvforceSync, dspResetIn->nAttempts, dspResetIn->timeOut, TRUE /*info*/); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "dspReset", "resetSlaveSync", __FILE__, __LINE__); return returnCode; } } return returnCode; } /************************************************************************************ * setRodMode * * synopsis: Sets parameters associated with the ROD's current running mode. * * arguments * IN: mode: The new ROD mode. Some modes are additive; e.g. the mode could * be CALIBRATION_MODE +INMEM_EVT_CAPTURE_MODE. The ROD will return * an error for those modes which are incompatible. Defined modes are * listed in rodConfiguration.h * * flag: Indicates what actions the routine will take. Can be SET_MODE in * which the routine will simply set the ROD to the indicated mode, * STORE, in which it will set a new mode but 1st store the current state * of the ROD for later RESTORE, or MODIFY, in which case the current ROD * mode will simply be modified to add or remove a mode modifier (such as * EVT_CAPTURE). * * fifoSetup: Indicates that the MDSP should reset & then enable all the * relevant FIFOs on the ROD for the input mode. * * nBits: For data capture into the input memories, indicates the length * of the capture in bits (25 ns/bit). If set to 0, the routine will * use the entire FIFO (default value). * * delay: The number of clock cycles to delay before activating the capture. * There must be at least a 1 cycle delay. If this is set to 0, the * routine will use the default value of 1 cycle. * * evtsPerL1A: Only used by Pixel detectors: sets up the formatters to detect * and process the number of expected returns per L1A coming from * the modules. * * message: If set, the routine will give a text message indicating the new * mode. * * author: Douglas Ferguson ************************************************************************************/ INT32 setRodMode(PrimData *primData) { INT32 returnCode= SUCCESS, errorCode; struct SET_ROD_MODE_IN *setRodModeIn= (struct SET_ROD_MODE_IN *) primData->priBodyPtr; UINT8 evtsPerL1A; #if (defined(SCT_ROD)) evtsPerL1A= 1; #elif (defined(PIXEL_ROD)) evtsPerL1A= setRodModeIn->evtsPerL1A; #endif errorCode= rodMode(setRodModeIn->mode, setRodModeIn->flag, setRodModeIn->fifoSetup, setRodModeIn->nBits, setRodModeIn->delay, evtsPerL1A, setRodModeIn->message); if (errorCode != SUCCESS) { addError(&returnCode, errorCode, "setRodMode", "rodMode", __FILE__, __LINE__); return returnCode; } return returnCode; } /************************************************************************************ * rwBocData * * synopsis: Changes or retrieves register settings inside the BOC. * * arguments * IN: read: If set, indicates that the variable is to be read from the * structure & returned via the reply list. * dpsf etc. * struct RW_BOC_DATA_IN { UINT32 read, sendToBoc, dataLen, *data; }; struct RW_BOC_DATA_OUT { BOCConfig bocCfgData; }; * * author: Douglas Ferguson ************************************************************************************/ INT32 rwBocData(PrimData *primData) { INT32 returnCode= SUCCESS; RwBocDataIn *rwBocDataIn= (RwBocDataIn *) primData->priBodyPtr; RwBocDataOut *rwBocDataOut= (RwBocDataOut *) primData->repBodyPtr; UINT8 fRead, sendToBoc; UINT32 dataLen; BOCConfig *configData; fRead= rwBocDataIn->read; sendToBoc= rwBocDataIn->sendToBoc; dataLen= rwBocDataIn->dataLen; configData= (BOCConfig *) &rwBocDataIn->data; if (fRead) { primData->repBodyLength= SIZEOF(RwBocDataOut); copyMem((UINT32 *) &bocConfig, (UINT32 *) rwBocDataOut, SIZEOF(BOCConfig)); } else { primData->repBodyLength= 0; if (dataLen != SIZEOF(BOCConfig)) { newError(&returnCode, PRIM_PARAMETER_ERROR, FATAL_ERR, "rwBocData", "Bad BOC input data length!\n", __FILE__, __LINE__); return returnCode; } copyMem((UINT32 *) configData, (UINT32 *) &bocConfig, SIZEOF(BOCConfig)); //If requensted, transfer the data to the BOC. if (sendToBoc) { //errorCode= configureBoc(); dpsf complete, bocConfig gets same //# of sets as module sets, and a new configBoc primitive configures //it using one of the sets. boc struct gets a present member which is //tested for validity before configuring. } } return returnCode; } /************************************************************************************ * bocHistogram * * synopsis: . * * arguments * IN: * * OUT: * * * author: Lukas Tomasek ************************************************************************************/ INT32 bocHistogram(PrimData *primData) { INT32 error = SUCCESS, returnCode = SUCCESS; BocHistogramIn *BOChistoIn= (BocHistogramIn *) primData->priBodyPtr; BocHistogramOut *BOChistoOut= (BocHistogramOut *) primData->repBodyPtr; #define SCRATCH_BUFF 0x02f00000 #ifdef REV_E //scratch buffers - temporary!!!! #define MAX_SAMPLES 0x8000 #define MAX_FIFO_SIZE 0x30000 // in bytes #else // rev B&C #define MAX_SAMPLES 0x1000 #define MAX_FIFO_SIZE 0x6000 // in bytes #endif UINT8 *dataA=(UINT8*)SCRATCH_BUFF; // scratch buffer UINT8 *dataB=(UINT8*)(SCRATCH_BUFF+MAX_FIFO_SIZE); UINT32 tempHisto[96][2]; UINT32 bytesXfrd; unsigned char byteA, byteB; int bin; int link; int loop; int i, bit; primData->repBodyLength= 0; #if 0 ------------------------------------- /* reset INMEM FIFO */ error = writeRegister(RRIF_CMND_0, 1, INP_MEM_RST_O, 0x1); if (error < 0) { addError(&returnCode, error, "BOChistogram", "writeRegister",__FILE__, __LINE__); } error = writeRegister(RRIF_CMND_0, 1, INP_MEM_RST_O, 0x0); if (error < 0) { addError(&returnCode, error, "BOChistogram", "writeRegister",__FILE__, __LINE__); } //set mask etc. ------------------------------- #endif /* clear output array */ memset (BOChistoOut->histo, 0, 768); for(loop=0; loopnumLoops; loop++){ memset (tempHisto, 0, 768); // clear array /* read inp fifos */ error = accessFifo(INPUT_MEM, BANK_A, 1, BOChistoIn->numSamples, (UINT32*)dataA, &bytesXfrd); if (error < 0) { addError(&returnCode, error, "BOChistogram", "accessFifo", __FILE__, __LINE__); if (FATAL(returnCode)) { return returnCode; } } error = accessFifo(INPUT_MEM, BANK_B, 1, BOChistoIn->numSamples, (UINT32*)dataB, &bytesXfrd); if (error < 0) { addError(&returnCode, error, "BOChistogram", "accessFifo", __FILE__, __LINE__); if (FATAL(returnCode)) { return returnCode; } } /* get temp histo */ for(bit=0, i=0; bitnumSamples; bit++){ if(bit&1) bin=1; else bin=0; for(link=0; link<48; link++){ if((link%8)==0){ byteA=dataA[i]; byteB=dataB[i]; i++; } tempHisto[link][bin]+=(byteA&1); tempHisto[link+48][bin]+=(byteB&1); byteA=(byteA>>1); byteB=(byteB>>1); } } /* add to final histogram */ for(link=0; link<96; link++){ if(tempHisto[link][0] > tempHisto[link][1]){ BOChistoOut->histo[link][0]+=tempHisto[link][0]; BOChistoOut->histo[link][1]+=tempHisto[link][1]; }else{ BOChistoOut->histo[link][0]+=tempHisto[link][1]; BOChistoOut->histo[link][1]+=tempHisto[link][0]; } } } primData->repBodyLength= SIZEOF(BocHistogramOut); return returnCode; } /************************************************************************************ * writeFlash * * synopsis: Writes the input data into the MDSP's EEPROM. * * arguments * IN: MDSP Binary; follows the primitive header directly. * ************************************************************************************/ INT32 writeFlash(PrimData *primData) { INT32 status; UINT32 size; WriteFlashIn *writeFlashIn; void *ptr; writeFlashIn = (WriteFlashIn *)primData->priBodyPtr; size = writeFlashIn->length; ptr = writeFlashIn->buffPtr; if(ptr == (void *) DEFAULT) { ptr = ++writeFlashIn; /* data follows immediately thereafter */ } redLed_on; yellowLed_on; status= programFlash(size, ptr); redLed_off; yellowLed_off; return SUCCESS; }