ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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
59namespace etiss
60{
61namespace interfaces
62{
63
64template <typename T>
68struct dependent_false : std::false_type
69{
70};
71
72template <typename BOOLSIG>
76bool 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
82template <typename BOOLSIG>
86void 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
91template <typename VECTORSIG>
95uint64_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
101template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
105VECTORSIGSTORAGETYPE 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
111template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
115void 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
123template <typename SELSIG>
124uint32_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
130template <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
171template <typename BOOLSIG, typename VECTORSIG, bool instrBus, bool flipEndianess,
172 unsigned bytewidth = sizeof(VECTORSIG), typename VECTORSIGSTORAGETYPE = VECTORSIG>
178class 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 {
225 etiss::int32 exception = etiss::RETURNCODE::NOERROR;
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:
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
#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_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
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 + ...)
#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