mrfioc2  2.3.0
evgMrm.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven Science Associates, as Operator of
3 * Brookhaven National Laboratory.
4 * Copyright (c) 2015 Paul Scherrer Institute (PSI), Villigen, Switzerland
5 * mrfioc2 is distributed subject to a Software License Agreement found
6 * in file LICENSE that is included with this distribution.
7 \*************************************************************************/
8 #include "evgMrm.h"
9 
10 #include <iostream>
11 #include <sstream>
12 #include <stdexcept>
13 #include <math.h>
14 
15 #include <errlog.h>
16 
17 #include <dbAccess.h>
18 #include <devSup.h>
19 #include <recSup.h>
20 #include <recGbl.h>
21 #include <epicsInterrupt.h>
22 #include <epicsTime.h>
23 #include <generalTimeSup.h>
24 #include <epicsStdio.h>
25 
26 #include <longoutRecord.h>
27 
28 #include "mrmpci.h"
29 #include "fct.h"
30 
31 #include "mrf/version.h"
32 #include <mrfCommonIO.h>
33 #include <mrfCommon.h>
34 
35 #ifdef __rtems__
36 #include <rtems/bspIo.h>
37 #endif //__rtems__
38 
39 #include "evgRegMap.h"
40 
41 #include <epicsExport.h>
42 
43 static
44 EVRMRM::Config evm_evru_conf = {
45  "mTCA-EVM-300 (EVRU)",
46  16, // pulse generators
47  3, // prescalers
48  8, // FP outputs
49  0, // FPUV outputs
50  0, // RB outputs
51  0, // Backplane outputs
52  0, // FP Delay outputs
53  0, // CML/GTX outputs
55  8, // FP inputs
56 };
57 
58 static
59 EVRMRM::Config evm_evrd_conf = {
60  "mTCA-EVM-300 (EVRD)",
61  16, // pulse generators
62  3, // prescalers
63  8, // FP outputs
64  0, // FPUV outputs
65  0, // RB outputs
66  0, // Backplane outputs
67  0, // FP Delay outputs
68  0, // CML/GTX outputs
70  8, // FP inputs
71 };
72 
73 evgMrm::evgMrm(const std::string& id,
74  const Config *conf,
75  bus_configuration& busConfig,
76  volatile epicsUInt8* const pReg,
77  const epicsPCIDevice *pciDevice):
78  mrf::ObjectInst<evgMrm>(id),
79  TimeStampSource(1.0),
80  MRMSPI(pReg+U32_SPIDData),
81  irqExtInp_queued(0),
82  m_buftx(id+":BUFTX",pReg+U32_DataBufferControl, pReg+U8_DataBuffer_base),
83  m_pciDevice(pciDevice),
84  m_id(id),
85  m_pReg(pReg),
86  busConfiguration(busConfig),
87  m_RFref(0),
88  m_fracSynFreq(0),
89  m_RFDiv(1u),
90  m_ClkSrc(ClkSrcInternal),
91  m_seq(this, pReg),
92  m_acTrig(id+":AcTrig", pReg),
93  shadowIrqEnable(READ32(m_pReg, IrqEnable))
94 {
95  epicsUInt32 v, isevr;
96 
97  v = READ32(m_pReg, FPGAVersion);
98  isevr=v&FPGAVersion_TYPE_MASK;
99  isevr>>=FPGAVersion_TYPE_SHIFT;
100 
101  if(isevr!=0x2)
102  throw std::runtime_error("Address does not correspond to an EVG");
103 
104  for(int i = 0; i < evgNumEvtTrig; i++) {
105  std::ostringstream name;
106  name<<id<<":TrigEvt"<<i;
107  m_trigEvt.push_back(new evgTrigEvt(name.str(), i, pReg));
108  }
109 
110  for(int i = 0; i < evgNumMxc; i++) {
111  std::ostringstream name;
112  name<<id<<":Mxc"<<i;
113  m_muxCounter.push_back(new evgMxc(name.str(), i, this));
114  }
115 
116  for(int i = 0; i < evgNumDbusBit; i++) {
117  std::ostringstream name;
118  name<<id<<":Dbus"<<i;
119  m_dbus.push_back(new evgDbus(name.str(), i, pReg));
120  }
121 
122  for(unsigned i = 0; i < conf->numFrontInp; i++) {
123  std::ostringstream name;
124  name<<id<<":FrontInp"<<i;
125  m_input[ std::pair<epicsUInt32, InputType>(i, FrontInp) ] =
126  new evgInput(name.str(), i, FrontInp, pReg + U32_FrontInMap(i));
127  }
128 
129  for(unsigned i = 0; i < conf->numUnivInp; i++) {
130  std::ostringstream name;
131  name<<id<<":UnivInp"<<i;
132  m_input[ std::pair<epicsUInt32, InputType>(i, UnivInp) ] =
133  new evgInput(name.str(), i, UnivInp, pReg + U32_UnivInMap(i));
134  }
135 
136  for(unsigned i = 0; i < conf->numRearInp; i++) {
137  std::ostringstream name;
138  name<<id<<":RearInp"<<i;
139  m_input[ std::pair<epicsUInt32, InputType>(i, RearInp) ] =
140  new evgInput(name.str(), i, RearInp, pReg + U32_RearInMap(i));
141  }
142 
143  for(int i = 0; i < evgNumFrontOut; i++) {
144  std::ostringstream name;
145  name<<id<<":FrontOut"<<i;
146  m_output[std::pair<epicsUInt32, evgOutputType>(i, FrontOut)] =
147  new evgOutput(name.str(), i, FrontOut, pReg + U16_FrontOutMap(i));
148  }
149 
150  for(int i = 0; i < evgNumUnivOut; i++) {
151  std::ostringstream name;
152  name<<id<<":UnivOut"<<i;
153  m_output[std::pair<epicsUInt32, evgOutputType>(i, UnivOut)] =
154  new evgOutput(name.str(), i, UnivOut, pReg + U16_UnivOutMap(i));
155  }
156 
157  init_cb(&irqExtInp_cb, priorityHigh, &evgMrm::process_inp_cb, this);
158 
159  scanIoInit(&ioScanTimestamp);
160 
161  if(busConfig.busType==busType_pci)
162  mrf::SPIDevice::registerDev(id+":FLASH", mrf::SPIDevice(this, 1));
163 
164  if(pciDevice->id.sub_device==PCI_DEVICE_ID_MRF_MTCA_EVM_300) {
165  printf("EVM automatically creating '%s:FCT', '%s:EVRD', and '%s:EVRU'\n", id.c_str(), id.c_str(), id.c_str());
166  fct.reset(new FCT(this, id+":FCT", pReg+0x10000));
167  evrd.reset(new EVRMRM(id+":EVRD", busConfig, &evm_evrd_conf, pReg+0x20000, 0x10000));
168  evru.reset(new EVRMRM(id+":EVRU", busConfig, &evm_evru_conf, pReg+0x30000, 0x10000));
169  }
170 }
171 
175 
176  for(size_t i = 0; i < m_trigEvt.size(); i++)
177  delete m_trigEvt[i];
178 
179  for(size_t i = 0; i < m_muxCounter.size(); i++)
180  delete m_muxCounter[i];
181 
182  for(size_t i = 0; i < m_dbus.size(); i++)
183  delete m_dbus[i];
184 
185  while(!m_input.empty())
186  m_input.erase(m_input.begin());
187 
188  while(!m_output.empty())
189  m_output.erase(m_output.begin());
190 }
191 
193 {
194  shadowIrqEnable |= EVG_IRQ_PCIIE | //PCIe interrupt enable,
197  EVG_IRQ_STOP_RAM(0) |
198  EVG_IRQ_STOP_RAM(1) |
199  EVG_IRQ_START_RAM(0) |
201 
202  WRITE32(m_pReg, IrqEnable, shadowIrqEnable);
203 }
204 
205 void
206 evgMrm::init_cb(CALLBACK *ptr, int priority, void(*fn)(CALLBACK*), void* valptr) {
207  callbackSetPriority(priority, ptr);
208  callbackSetCallback(fn, ptr);
209  callbackSetUser(valptr, ptr);
210  (ptr)->timer=NULL;
211 }
212 
213 const std::string
214 evgMrm::getId() const {
215  return m_id;
216 }
217 
218 volatile epicsUInt8*
220  return m_pReg;
221 }
222 
223 MRFVersion evgMrm::version() const
224 {
225  return MRFVersion(READ32(m_pReg, FPGAVersion));
226 }
227 
228 std::string evgMrm::getFwVersionStr() const
229 {
230  return version().str();
231 }
232 
233 std::string
235  return MRF_VERSION;
236 }
237 
238 epicsUInt32
240  return READ32(m_pReg, Status)>>16;
241 }
242 
243 void
244 evgMrm::enable(epicsUInt16 mode) {
245  if(mode>2)
246  throw std::runtime_error("Unsupported mode");
247 
248  SCOPED_LOCK(m_lock);
249  epicsUInt32 ctrl = NAT_READ32(m_pReg, Control);
250  if(mode!=0)
251  ctrl |= EVG_MASTER_ENA;
252  else
253  ctrl &= ~EVG_MASTER_ENA;
254  if(mode==2)
255  ctrl |= EVG_BCGEN|EVG_DCMST;
256  else
257  ctrl &= ~(EVG_BCGEN|EVG_DCMST);
258 
260 
261  NAT_WRITE32(m_pReg, Control, ctrl);
262 }
263 
264 epicsUInt16 evgMrm::enabled() const {
265  epicsUInt32 ctrl = NAT_READ32(m_pReg, Control);
266  if(!(ctrl&EVG_MASTER_ENA)) return 0;
267  else if(!(ctrl&EVG_BCGEN)) return 1;
268  else return 2;
269 }
270 
271 void
272 evgMrm::resetMxc(bool reset) {
273  if(reset) {
274  SCOPED_LOCK(m_lock);
275  BITSET32(m_pReg, Control, EVG_MXC_RESET);
276  }
277 }
278 
279 void
280 evgMrm::isr_pci(void* arg) {
281  evgMrm *evg = static_cast<evgMrm*>(arg);
282 
283  // Call to the generic implementation
284  evg->isr(evg, true);
285 
286 #if defined(__linux__) || defined(_WIN32)
287 
291  if(devPCIEnableInterrupt(evg->m_pciDevice)) {
292  printf("PCI: Failed to enable interrupt\n");
293  return;
294  }
295 #endif
296 }
297 
298 void
299 evgMrm::isr_vme(void* arg) {
300  evgMrm *evg = static_cast<evgMrm*>(arg);
301 
302  // Call to the generic implementation
303  evg->isr(evg, false);
304 }
305 
306 void
307 evgMrm::isr_poll(void* arg) {
308  evgMrm *evg = static_cast<evgMrm*>(arg);
309 
310  // Call to the generic implementation
311  evg->isr(evg, true);
312 }
313 
314 void
315 evgMrm::isr(evgMrm *evg, bool pci) {
316 try{
317  epicsUInt32 flags = READ32(evg->m_pReg, IrqFlag);
318  epicsUInt32 active = flags & evg->shadowIrqEnable;
319 
320 #if defined(vxWorks) || defined(__rtems__)
321  if(!active) {
322 # ifdef __rtems__
323  if(!pci)
324  printk("evgMrm::isr with no active VME IRQ 0x%08x 0x%08x\n", flags, evg->shadowIrqEnable);
325 #else
326  (void)pci;
327 # endif
328  // this is a shared interrupt
329  return;
330  }
331  // Note that VME devices do not normally shared interrupts
332 #else
333  // for Linux, shared interrupts are detected by the kernel module
334  // so any notifications to userspace are real interrupts by this device
335  (void)pci;
336 #endif
337 
338  if(active & EVG_IRQ_START_RAM(0)) {
339  evg->m_seq.doStartOfSequence(0);
340  }
341 
342  if(active & EVG_IRQ_START_RAM(1)) {
343  evg->m_seq.doStartOfSequence(1);
344  }
345 
346  if(active & EVG_IRQ_STOP_RAM(0)) {
347  evg->m_seq.doEndOfSequence(0);
348  }
349 
350  if(active & EVG_IRQ_STOP_RAM(1)) {
351  evg->m_seq.doEndOfSequence(1);
352  }
353 
354  if(active & EVG_IRQ_EXT_INP) {
355  if(evg->irqExtInp_queued==0) {
356  callbackRequest(&evg->irqExtInp_cb);
357  evg->irqExtInp_queued=1;
358  } else if(evg->irqExtInp_queued==1) {
359  evg->shadowIrqEnable &= ~EVG_IRQ_EXT_INP;
360  evg->irqExtInp_queued=2;
361  }
362  }
363 
364  WRITE32(evg->getRegAddr(), IrqEnable, evg->shadowIrqEnable);
365  WRITE32(evg->m_pReg, IrqFlag, flags); // Clear the interrupt causes
366  READ32(evg->m_pReg, IrqFlag); // Make sure the clear completes before returning
367 
368 }catch(...){
369  epicsInterruptContextMessage("c++ Exception in ISR!!!\n");
370 }
371 }
372 
373 void
374 evgMrm::process_inp_cb(CALLBACK *pCallback) {
375  void* pVoid;
376  callbackGetUser(pVoid, pCallback);
377  evgMrm* evg = static_cast<evgMrm*>(pVoid);
378 
379  {
380  interruptLock ig;
381  if(evg->irqExtInp_queued==2) {
382  evg->shadowIrqEnable |= EVG_IRQ_EXT_INP;
383  WRITE32(evg->getRegAddr(), IrqEnable, evg->shadowIrqEnable);
384  }
385  evg->irqExtInp_queued=0;
386  }
387 
388  evg->tickSecond();
389  scanIoRequest(evg->ioScanTimestamp);
390 }
391 
392 void
394 {
395  tickSecond();
396  scanIoRequest(ioScanTimestamp);
397 }
398 
399 void
400 evgMrm::setEvtCode(epicsUInt32 evtCode) {
401  if(evtCode > 255)
402  throw std::runtime_error("Event Code out of range. Valid range: 0 - 255.");
403 
404  SCOPED_LOCK(m_lock);
405 
406  while(READ32(m_pReg, SwEvent) & SwEvent_Pend) {}
407 
408  WRITE32(m_pReg, SwEvent,
409  (evtCode<<SwEvent_Code_SHIFT)
410  |SwEvent_Ena);
411 }
412 
415 evgInput*
416 evgMrm::getInput(epicsUInt32 inpNum, InputType type) {
417  evgInput* inp = m_input[ std::pair<epicsUInt32, InputType>(inpNum, type) ];
418  if(!inp)
419  throw std::runtime_error("Input not initialized");
420 
421  return inp;
422 }
423 
424 epicsEvent*
426  return &m_timerEvent;
427 }
428 
430 {
431  return &busConfiguration;
432 }
433 
434 void evgMrm::show(int lvl)
435 {
436 }
epicsEvent * getTimerEvent()
Definition: evgMrm.cpp:425
std::string getFwVersionStr() const
Definition: evgMrm.cpp:228
enum busType busType
#define EVG_IRQ_EXT_INP
Definition: evgRegMap.h:57
#define BITSET32(base, offset, mask)
Definition: mrfCommonIO.h:124
#define PCI_DEVICE_ID_MRF_MTCA_EVM_300
Definition: uio_mrf.c:67
static void isr_vme(void *)
Definition: evgMrm.cpp:299
#define U16_FrontOutMap(n)
Definition: evgRegMap.h:194
#define EVG_DIS_EVT_REC
Definition: evgRegMap.h:267
#define U32_FrontInMap(n)
Definition: evgRegMap.h:206
#define EVG_IRQ_STOP_RAM(N)
Definition: evgRegMap.h:54
std::string getSwVersion() const
Definition: evgMrm.cpp:234
epicsMutex m_lock
Definition: evgMrm.h:79
#define READ32(base, offset)
Definition: mrfCommonIO.h:114
void show(int lvl)
Definition: evgMrm.cpp:434
static void registerDev(const std::string &name, const SPIDevice &)
Definition: spi.cpp:86
#define U16_UnivOutMap(n)
Definition: evgRegMap.h:200
#define EVG_IRQ_PCIIE
Definition: evgRegMap.h:52
void setEvtCode(epicsUInt32)
Definition: evgMrm.cpp:400
#define EVG_DCMST
Definition: evgRegMap.h:271
#define EVG_IRQ_START_RAM(N)
Definition: evgRegMap.h:56
~evgMrm()
Definition: evgMrm.cpp:172
#define evgNumMxc
Definition: evgRegMap.h:282
#define SwEvent_Code_SHIFT
Definition: evgRegMap.h:91
#define EVG_REV_PWD_DOWN
Definition: evgRegMap.h:268
#define SwEvent_Ena
Definition: evgRegMap.h:88
unsigned numUnivInp
Definition: evgMrm.h:63
void doStartOfSequence(unsigned i)
Call from ISR.
Definition: mrmSeq.cpp:723
Modular Register Map Event Receivers.
Definition: drvem.h:86
static void process_inp_cb(CALLBACK *)
Definition: evgMrm.cpp:374
void enable(epicsUInt16)
Definition: evgMrm.cpp:244
volatile epicsUInt8 * getRegAddr() const
Definition: evgMrm.cpp:219
Definition: fct.h:19
void resetMxc(bool reset)
Definition: evgMrm.cpp:272
#define evgNumUnivOut
Definition: evgRegMap.h:286
CALLBACK irqExtInp_cb
Definition: evgMrm.h:145
#define U8_DataBuffer_base
Definition: evgRegMap.h:224
void doEndOfSequence(unsigned i)
Call from ISR.
Definition: mrmSeq.cpp:739
IOSCANPVT ioScanTimestamp
Definition: evgMrm.h:149
void tickSecond()
Call just after the start of each second.
Definition: mrmtimesrc.cpp:160
#define FPGAVersion
Definition: mrf.h:133
Definition: mrmspi.h:20
static void isr_poll(void *)
Definition: evgMrm.cpp:307
epicsUInt32 getDbusStatus() const
Definition: evgMrm.cpp:239
virtual void postSoftSecondsSrc()
Definition: evgMrm.cpp:393
unsigned char irqExtInp_queued
Definition: evgMrm.h:147
#define NAT_READ32(base, offset)
Definition: mrfCommonIO.h:145
const bus_configuration * getBusConfiguration()
Definition: evgMrm.cpp:429
#define EVG_BCGEN
Definition: evgRegMap.h:270
evgInput * getInput(epicsUInt32, InputType)
Definition: evgMrm.cpp:416
#define SwEvent_Pend
Definition: evgRegMap.h:89
#define U32_DataBufferControl
Definition: evgRegMap.h:96
void enableIRQ()
Definition: evgMrm.cpp:192
const epicsPCIDevice * m_pciDevice
Definition: evgMrm.h:155
Definition: evgDbus.h:7
#define U32_UnivInMap(n)
Definition: evgRegMap.h:212
#define EVG_IRQ_ENABLE
Definition: evgRegMap.h:51
#define EVG_MASTER_ENA
Definition: evgRegMap.h:266
#define evgNumFrontOut
Definition: evgRegMap.h:285
static void unregisterDev(const std::string &name)
Definition: spi.cpp:93
const std::string & name() const
Definition: object.h:393
#define FPGAVersion_TYPE_SHIFT
Definition: evgRegMap.h:107
static void init_cb(CALLBACK *, int, void(*)(CALLBACK *), void *)
Definition: evgMrm.cpp:206
InputType
Definition: evgInput.h:11
static void isr(evgMrm *evg, bool pci)
Definition: evgMrm.cpp:315
#define evgNumDbusBit
Definition: evgRegMap.h:284
#define NAT_WRITE32(base, offset, value)
Definition: mrfCommonIO.h:148
#define evgNumEvtTrig
Definition: evgRegMap.h:283
const std::string getId() const
Definition: evgMrm.cpp:214
epicsUInt16 enabled() const
Definition: evgMrm.cpp:264
static void isr_pci(void *)
Definition: evgMrm.cpp:280
Definition: flash.cpp:23
evgMrm(const std::string &id, const Config *conf, bus_configuration &busConfig, volatile epicsUInt8 *const base, const epicsPCIDevice *pciDevice)
Definition: evgMrm.cpp:73
unsigned numFrontInp
Definition: evgMrm.h:63
#define WRITE32(base, offset, value)
Definition: mrfCommonIO.h:119
#define U32_SPIDData
Definition: mrmspi.cpp:23
#define U32_RearInMap(n)
Definition: evgRegMap.h:219
#define EVG_MXC_RESET
Definition: evgRegMap.h:269
Definition: evgMrm.h:56
#define FPGAVersion_TYPE_MASK
Definition: evgRegMap.h:104
MRFVersion version() const
Definition: evgMrm.cpp:223
unsigned numRearInp
Definition: evgMrm.h:63
Definition: evgMxc.h:9