ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
Wishbone.h
Go to the documentation of this file.
1 
52 #ifndef ETISS_INTERFACES_WISHBONE_H
53 #define ETISS_INTERFACES_WISHBONE_H
54 
56 
57 #include <utility>
58 
59 namespace etiss
60 {
61 namespace interfaces
62 {
63 
64 template <typename T>
68 struct dependent_false : std::false_type
69 {
70 };
71 
72 template <typename BOOLSIG>
76 bool getBool(etiss::CPUCore &core, BOOLSIG &sig)
77 {
78  static_assert(dependent_false<BOOLSIG>::value, "etiss::interfaces::getBool needs to be specialized");
79  return false; // never remove static_assert above!
80 }
81 
82 template <typename BOOLSIG>
86 void setBool(etiss::CPUCore &core, BOOLSIG &sig, bool val)
87 {
88  static_assert(dependent_false<BOOLSIG>::value, "etiss::interfaces::setBool needs to be specialized");
89 }
90 
91 template <typename VECTORSIG>
95 uint64_t getAddr(etiss::CPUCore &core, VECTORSIG &sig, bool instrBus)
96 {
97  static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::getAddr needs to be specialized");
98  return 0; // never remove static_assert above!
99 }
100 
101 template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
105 VECTORSIGSTORAGETYPE getData(etiss::CPUCore &core, VECTORSIG &sig)
106 {
107  static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::getData needs to be specialized");
108  return 0; // never remove static_assert above!
109 }
110 
111 template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
115 void setData(etiss::CPUCore &core, VECTORSIG &sig, VECTORSIGSTORAGETYPE val)
116 {
117  static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::setData needs to be specialized");
118 }
119 
123 template <typename SELSIG>
124 uint32_t getSel(etiss::CPUCore &core, SELSIG &sel_i)
125 {
126  static_assert(dependent_false<SELSIG>::value, "etiss::interfaces::getSelData needs to be specialized");
127  return 0;
128 }
129 
130 template <typename BOOLSIG, typename VECTORSIG>
132 {
133  public:
134  // Signals
135  BOOLSIG &clk_i;
136  BOOLSIG &ack_o;
137  BOOLSIG &err_o;
138  BOOLSIG &rty_o;
139  BOOLSIG &cyc_i;
140  BOOLSIG &stb_i;
141  BOOLSIG &we_i;
142  BOOLSIG &sel_i;
143  BOOLSIG &bte_i;
144  BOOLSIG &cti_i;
145  VECTORSIG &dat_o;
146  VECTORSIG &adr_i;
147  VECTORSIG &dat_i;
148 
149  public:
150  // Constructor
151  WishboneSignalMap(BOOLSIG &clk_o, BOOLSIG &ack_i, BOOLSIG &err_i, BOOLSIG &rty_i, BOOLSIG &cyc_o, BOOLSIG &stb_o,
152  BOOLSIG &we_o, BOOLSIG &sel_o, BOOLSIG &bte_o, BOOLSIG &cti_o, VECTORSIG &dat_i, VECTORSIG &adr_o,
153  VECTORSIG &dat_o)
154  : clk_i(clk_o)
155  , ack_o(ack_i)
156  , err_o(err_i)
157  , rty_o(rty_i)
158  , cyc_i(cyc_o)
159  , stb_i(stb_o)
160  , we_i(we_o)
161  , sel_i(sel_o)
162  , bte_i(bte_o)
163  , cti_i(cti_o)
164  , dat_o(dat_i)
165  , adr_i(adr_o)
166  , dat_i(dat_o)
167  {
168  }
169 };
170 
171 template <typename BOOLSIG, typename VECTORSIG, bool instrBus, bool flipEndianess,
172  unsigned bytewidth = sizeof(VECTORSIG), typename VECTORSIGSTORAGETYPE = VECTORSIG>
178 class WishboneBus : public Delegate
179 {
180  static_assert(bytewidth == sizeof(VECTORSIGSTORAGETYPE), "bytewidth != sizeof(VECTORSIGSTORAGETYPE)");
181 
182  public:
190  : Delegate(system, cpu)
191  , core_(core)
192  , lastutime(0)
193  , etime(0)
194  , lastclock(false)
195  , useposclkedge(true)
196  , dat_o(0)
197  , po_err(false)
198  , pending(0)
199  , sigs(sigs)
200  {
201  }
202 
204  void init()
205  {
206  sigs.ack_o = false;
207  sigs.err_o = false;
208  sigs.rty_o = false;
209  sigs.dat_o = 0;
210  pending = 0;
211  }
212 
223  etiss_int32 update(uint64_t time, bool premain, bool reset, bool posSimTime = true)
224  {
226 
227  if (time != 0) // check if time has been elapsed
228  {
229  if (posSimTime) // safeguard
230  {
231  if (time <= lastutime)
232  {
233  std::cout << "Wishbone::update() no time elapsed or time is negative!" << std::endl;
234  return exception;
235  }
236  }
237  else
238  {
239  if (time + 2 < lastutime) // ignore differences from rounding errors (casts from double etc.)
240  {
241  std::cout << "Wishbone::update() time is negative! time: " << time / 1000
242  << " ns, lastutime: " << lastutime / 1000 << " ns"
243  << " premain: " << premain << " reset: " << reset << std::endl;
244  return exception;
245  }
246  }
247  }
248 
249  bool clkedge = (((bool)lastclock) != (getBool(core_, sigs.clk_i))) &&
250  ((getBool(core_, sigs.clk_i)) == ((bool)useposclkedge)); // detect clock edge
251 
252  if (!premain) // store last update time clock edge
253  {
254  lastutime = time;
255  lastclock = getBool(core_, sigs.clk_i);
256  }
257 
258  if (reset) // reset
259  {
260  init();
261  }
262  else
263  {
264  if (premain) // apply pending signal changes
265  {
266  if (pending != 0) // signal changes to apply?
267  {
268  if (time >= etime)
269  { // event ready?
270  switch (pending)
271  {
272  case 1: // read
273  setBool(core_, sigs.ack_o, !po_err);
274  setBool(core_, sigs.err_o, po_err);
275  setBool(core_, sigs.rty_o, false);
276  if (!po_err)
277  setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, dat_o);
278  break;
279  case 2: // write
280  sigs.ack_o = !po_err;
281  sigs.err_o = po_err;
282  break;
283  default:
284  etiss_log(FATALERROR, "variable \"pending\" has an invalid value");
285  }
286  if (clkedge)
287  pending = 0; // clear event
288  }
289  }
290  else if (clkedge)
291  {
292  setBool(core_, sigs.ack_o, false);
293  setBool(core_, sigs.err_o, false);
294  setBool(core_, sigs.rty_o, false);
295  setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, 0);
296  }
297  }
298  else // reevaluate signals
299  {
300  if (clkedge && (pending == 0))
301  {
302  // immediate reset of signals
303  {
304  setBool(core_, sigs.ack_o, false);
305  setBool(core_, sigs.err_o, false);
306  setBool(core_, sigs.rty_o, false);
307  setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, 0);
308  }
309  if (getBool(core_, sigs.cyc_i) && getBool(core_, sigs.stb_i)) // Bus access
310  {
311  uint64_t addr = getAddr(core_, sigs.adr_i, instrBus);
312  unsigned addressOffet = addr & (bytewidth - 1); // offset (only needed for validation)
313  addr &= (~uint64_t(bytewidth - 1)); // Ignore unaligned address bits
314  VECTORSIGSTORAGETYPE dataBuf = 0;
315  uint64_t localTime = time; // time on read/write call
316  unsigned dataLength; // length of read/write access
317 
318  if (getBool(core_, sigs.we_i)) // write
319  {
320  if (!sel2Length(getSel(core_, sigs.sel_i), dataLength, addressOffet))
322  std::string("invalid sel_i: ") + std::to_string(getSel(core_, sigs.sel_i)));
323  dataBuf = getData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_i);
324  flipEndianness((uint8_t *)&dataBuf);
325  exception = write(instrBus, localTime, addr + addressOffet,
326  ((uint8_t *)&dataBuf) + addressOffet, dataLength);
327  pending = 2;
328 
329  /*std::cout << "Wishbone " << (instrBus?"ibus":"dbus")
330  << " - write: 0x" << std::hex << dataBuf
331  << " at address 0x" << addr+addressOffet
332  << " len: " << dataLength
333  << std::dec << std::endl;*/
334  }
335  else // read
336  {
337  if (!sel2Length(getSel(core_, sigs.sel_i), dataLength, addressOffet))
339  std::string("invalid sel_i: ") + std::to_string(getSel(core_, sigs.sel_i)));
340  exception = read(instrBus, localTime, addr + addressOffet,
341  ((uint8_t *)&dataBuf) + addressOffet, dataLength);
342  flipEndianness((uint8_t *)&dataBuf);
343  dat_o = dataBuf; // store but don't provide result
344  pending = 1;
345 
346  /*std::cout << "Wishbone " << (instrBus?"ibus":"dbus")
347  << " - read: 0x" << std::hex << dataBuf
348  << " at address 0x" << addr+addressOffet
349  << " len: " << dataLength
350  << std::dec << std::endl;*/
351  }
352 
353  po_err = (exception == etiss::RETURNCODE::DBUS_READ_ERROR ||
354  exception == etiss::RETURNCODE::DBUS_WRITE_ERROR ||
355  exception == etiss::RETURNCODE::IBUS_READ_ERROR ||
356  exception == etiss::RETURNCODE::IBUS_WRITE_ERROR);
357  if (po_err)
358  exception = etiss::RETURNCODE::NOERROR;
359 
360  etime = localTime; // store event time
361  }
362  }
363  }
364  }
365  return exception;
366  }
367 
368  private:
370  inline void flipEndianness(uint8_t *buf)
371  {
372  if (flipEndianess)
373  {
374  for (unsigned i = 0; i < (bytewidth / 2); ++i)
375  {
376  std::swap(buf[i], buf[bytewidth - 1 - i]);
377  }
378  }
379  }
380 
388  bool sel2Length(uint32_t sel, unsigned &length, unsigned &addressOffset)
389  {
390  length = 0;
391  unsigned selectOffset = 0;
392 
393  // nothing to transmit on bus (len = 0)
394  if (sel == 0)
395  return 0;
396 
397  /* only one steam of '1's is allowed like 0011 or 1100 (correlates to halfword)
398  * so we first remove all leading '0's and so get the address offset
399  * (unusual cases like 0110 are not covered with this check!)
400  */
401  while ((sel & 1) == 0)
402  {
403  selectOffset++;
404  sel >>= 1;
405  }
406  /* thereafter we check the length with the following '1's
407  * if the sel signal thereafter is NOT empty it wasn't valid
408  */
409  while ((sel & 1) == 1)
410  {
411  length++;
412  sel >>= 1;
413  }
414 
415  /* Endianess is always swapped on the whole bus width eg. 32bit or 64bit.
416  * The offset is than be seen from the other side of the stream:
417  * 0010 0010
418  * ^ -> ^^
419  */
420  if (flipEndianess)
421  selectOffset = bytewidth - length - selectOffset;
422 
423  // Check if calculated offset is valid with given bus offset. (Normally not given in wishbone bus)
424  static bool output_addressOffset_warning = false;
425  if ((selectOffset != addressOffset) && !output_addressOffset_warning)
426  {
428  std::string("Wishbone bus offset not valid! (0x") + std::to_string((int)addressOffset) + ")");
429  output_addressOffset_warning = true;
430  }
431 
432  return sel == 0;
433  }
434 
435  //--------------------------------------- Attributes ---------------------------------------
436  public:
438 
439  private:
443  bool lastclock;
445  VECTORSIGSTORAGETYPE dat_o;
446  bool po_err;
447  unsigned pending;
448 };
449 
450 } // namespace interfaces
451 } // namespace etiss
452 
453 #endif // ETISS_INTERFACES_WISHBONE_H
etiss_int32 int32
Definition: 386-GCC.h:81
#define static_assert(x, y)
Definition: Fault.cpp:60
#define etiss_log(LEVEL, MSG)
Definition: Misc.h:83
static __inline__ uint32_t
Definition: arm_cde.h:25
static __inline__ uint64_t
Definition: arm_cde.h:31
static __inline__ uint8_t
Definition: arm_mve.h:323
int32_t etiss_int32
Definition: types.h:92
CPUCore is responsible for the simulation of a CPU core in ETISS.
Definition: CPUCore.h:113
connects a wishbone bus interface implemented with the variables of WishboneSignalMap to a ETISS_Syst...
Definition: Wishbone.h:179
bool useposclkedge
use positive or negative clock edge
Definition: Wishbone.h:444
VECTORSIGSTORAGETYPE dat_o
buffer for data out to CPU
Definition: Wishbone.h:445
void init()
Initiate all bus output signals and set pending status to "nothing pending".
Definition: Wishbone.h:204
unsigned pending
0: nothing pending; 1: Read pending; 2: Write pending
Definition: Wishbone.h:447
WishboneBus(WishboneSignalMap< BOOLSIG, VECTORSIG > &sigs, ETISS_System &system, ETISS_CPU &cpu, etiss::CPUCore &core)
Constructor.
Definition: Wishbone.h:189
void flipEndianness(uint8_t *buf)
Flips endianess of a VECTORSIG.
Definition: Wishbone.h:370
bool po_err
bus error arised
Definition: Wishbone.h:446
bool lastclock
used for determining clock edge
Definition: Wishbone.h:443
WishboneSignalMap< BOOLSIG, VECTORSIG > & sigs
Signals between bus and CPU.
Definition: Wishbone.h:437
bool sel2Length(uint32_t sel, unsigned &length, unsigned &addressOffset)
Calculates length and offset out of signal sel.
Definition: Wishbone.h:388
etiss::CPUCore & core_
Definition: Wishbone.h:440
etiss_int32 update(uint64_t time, bool premain, bool reset, bool posSimTime=true)
Update signals to CPU or read/write from/to bus.
Definition: Wishbone.h:223
uint64_t lastutime
time of last signal evaluation phase
Definition: Wishbone.h:441
WishboneSignalMap(BOOLSIG &clk_o, BOOLSIG &ack_i, BOOLSIG &err_i, BOOLSIG &rty_i, BOOLSIG &cyc_o, BOOLSIG &stb_o, BOOLSIG &we_o, BOOLSIG &sel_o, BOOLSIG &bte_o, BOOLSIG &cti_o, VECTORSIG &dat_i, VECTORSIG &adr_o, VECTORSIG &dat_o)
Definition: Wishbone.h:151
void setData(etiss::CPUCore &core, VECTORSIG &sig, VECTORSIGSTORAGETYPE val)
general helper function to set a signal; needs to be implemented as needed
Definition: Wishbone.h:115
VECTORSIGSTORAGETYPE getData(etiss::CPUCore &core, VECTORSIG &sig)
general helper function to read a signal; needs to be implemented as needed
Definition: Wishbone.h:105
uint64_t getAddr(etiss::CPUCore &core, VECTORSIG &sig, bool instrBus)
general helper function to read an address; needs to be implemented as needed
Definition: Wishbone.h:95
bool getBool(etiss::CPUCore &core, BOOLSIG &sig)
general helper function to read a signal; needs to be implemented as needed
Definition: Wishbone.h:76
void setBool(etiss::CPUCore &core, BOOLSIG &sig, bool val)
general helper function to set a signal; needs to be implemented as needed
Definition: Wishbone.h:86
uint32_t getSel(etiss::CPUCore &core, SELSIG &sel_i)
general helper function to read a vector signal; needs to be implemented as needed
Definition: Wishbone.h:124
MM_EXPORT const int32_t NOERROR
void init()
Page Table Entry (PTE) defines the composition of Page Frame Number (PFN) and relavant flags.
Definition: Benchmark.h:53
@ WARNING
Definition: Misc.h:128
@ ERROR
Definition: Misc.h:127
@ FATALERROR
Definition: Misc.h:126
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition: Misc.cpp:125
float __ovld __cnfn length(float p)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:6324
#define true
Definition: stdbool.h:16
#define false
Definition: stdbool.h:17
#define bool
Definition: stdbool.h:15
basic cpu state structure needed for execution of any cpu architecture.
Definition: CPU.h:89
memory access and time synchronization functions.
Definition: System.h:78
simple helper struct to trigger static_assert only if the template is instantiated
Definition: Wishbone.h:69