ETISS 0.11.2
ExtendableTranslatingInstructionSetSimulator(version0.11.2)
Loading...
Searching...
No Matches
Wishbone.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2//
3// This file is part of ETISS. It is licensed under the BSD 3-Clause License; you may not use this file except in
4// compliance with the License. You should have received a copy of the license along with this project. If not, see the
5// LICENSE file.
14#ifndef ETISS_INTERFACES_WISHBONE_H
15#define ETISS_INTERFACES_WISHBONE_H
16
18
19#include <utility>
20
21namespace etiss
22{
23namespace interfaces
24{
25
26template <typename T>
30struct dependent_false : std::false_type
31{
32};
33
34template <typename BOOLSIG>
38bool getBool(etiss::CPUCore &core, BOOLSIG &sig)
39{
40 static_assert(dependent_false<BOOLSIG>::value, "etiss::interfaces::getBool needs to be specialized");
41 return false; // never remove static_assert above!
42}
43
44template <typename BOOLSIG>
48void setBool(etiss::CPUCore &core, BOOLSIG &sig, bool val)
49{
50 static_assert(dependent_false<BOOLSIG>::value, "etiss::interfaces::setBool needs to be specialized");
51}
52
53template <typename VECTORSIG>
57uint64_t getAddr(etiss::CPUCore &core, VECTORSIG &sig, bool instrBus)
58{
59 static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::getAddr needs to be specialized");
60 return 0; // never remove static_assert above!
61}
62
63template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
67VECTORSIGSTORAGETYPE getData(etiss::CPUCore &core, VECTORSIG &sig)
68{
69 static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::getData needs to be specialized");
70 return 0; // never remove static_assert above!
71}
72
73template <typename VECTORSIGSTORAGETYPE, typename VECTORSIG>
77void setData(etiss::CPUCore &core, VECTORSIG &sig, VECTORSIGSTORAGETYPE val)
78{
79 static_assert(dependent_false<VECTORSIG>::value, "etiss::interfaces::setData needs to be specialized");
80}
81
85template <typename SELSIG>
86uint32_t getSel(etiss::CPUCore &core, SELSIG &sel_i)
87{
88 static_assert(dependent_false<SELSIG>::value, "etiss::interfaces::getSelData needs to be specialized");
89 return 0;
90}
91
92template <typename BOOLSIG, typename VECTORSIG>
94{
95 public:
96 // Signals
97 BOOLSIG &clk_i;
98 BOOLSIG &ack_o;
99 BOOLSIG &err_o;
100 BOOLSIG &rty_o;
101 BOOLSIG &cyc_i;
102 BOOLSIG &stb_i;
103 BOOLSIG &we_i;
104 BOOLSIG &sel_i;
105 BOOLSIG &bte_i;
106 BOOLSIG &cti_i;
107 VECTORSIG &dat_o;
108 VECTORSIG &adr_i;
109 VECTORSIG &dat_i;
110
111 public:
112 // Constructor
113 WishboneSignalMap(BOOLSIG &clk_o, BOOLSIG &ack_i, BOOLSIG &err_i, BOOLSIG &rty_i, BOOLSIG &cyc_o, BOOLSIG &stb_o,
114 BOOLSIG &we_o, BOOLSIG &sel_o, BOOLSIG &bte_o, BOOLSIG &cti_o, VECTORSIG &dat_i, VECTORSIG &adr_o,
115 VECTORSIG &dat_o)
116 : clk_i(clk_o)
117 , ack_o(ack_i)
118 , err_o(err_i)
119 , rty_o(rty_i)
120 , cyc_i(cyc_o)
121 , stb_i(stb_o)
122 , we_i(we_o)
123 , sel_i(sel_o)
124 , bte_i(bte_o)
125 , cti_i(cti_o)
126 , dat_o(dat_i)
127 , adr_i(adr_o)
128 , dat_i(dat_o)
129 {
130 }
131};
132
133template <typename BOOLSIG, typename VECTORSIG, bool instrBus, bool flipEndianess,
134 unsigned bytewidth = sizeof(VECTORSIG), typename VECTORSIGSTORAGETYPE = VECTORSIG>
140class WishboneBus : public Delegate
141{
142 static_assert(bytewidth == sizeof(VECTORSIGSTORAGETYPE), "bytewidth != sizeof(VECTORSIGSTORAGETYPE)");
143
144 public:
152 : Delegate(system, cpu)
153 , core_(core)
154 , lastutime(0)
155 , etime(0)
156 , lastclock(false)
157 , useposclkedge(true)
158 , dat_o(0)
159 , po_err(false)
160 , pending(0)
161 , sigs(sigs)
162 {
163 }
164
166 void init()
167 {
168 sigs.ack_o = false;
169 sigs.err_o = false;
170 sigs.rty_o = false;
171 sigs.dat_o = 0;
172 pending = 0;
173 }
174
185 etiss_int32 update(uint64_t time, bool premain, bool reset, bool posSimTime = true)
186 {
187 etiss::int32 exception = etiss::RETURNCODE::NOERROR;
188
189 if (time != 0) // check if time has been elapsed
190 {
191 if (posSimTime) // safeguard
192 {
193 if (time <= lastutime)
194 {
195 std::cout << "Wishbone::update() no time elapsed or time is negative!" << std::endl;
196 return exception;
197 }
198 }
199 else
200 {
201 if (time + 2 < lastutime) // ignore differences from rounding errors (casts from double etc.)
202 {
203 std::cout << "Wishbone::update() time is negative! time: " << time / 1000
204 << " ns, lastutime: " << lastutime / 1000 << " ns"
205 << " premain: " << premain << " reset: " << reset << std::endl;
206 return exception;
207 }
208 }
209 }
210
211 bool clkedge = (((bool)lastclock) != (getBool(core_, sigs.clk_i))) &&
212 ((getBool(core_, sigs.clk_i)) == ((bool)useposclkedge)); // detect clock edge
213
214 if (!premain) // store last update time clock edge
215 {
216 lastutime = time;
217 lastclock = getBool(core_, sigs.clk_i);
218 }
219
220 if (reset) // reset
221 {
222 init();
223 }
224 else
225 {
226 if (premain) // apply pending signal changes
227 {
228 if (pending != 0) // signal changes to apply?
229 {
230 if (time >= etime)
231 { // event ready?
232 switch (pending)
233 {
234 case 1: // read
235 setBool(core_, sigs.ack_o, !po_err);
236 setBool(core_, sigs.err_o, po_err);
237 setBool(core_, sigs.rty_o, false);
238 if (!po_err)
239 setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, dat_o);
240 break;
241 case 2: // write
242 sigs.ack_o = !po_err;
243 sigs.err_o = po_err;
244 break;
245 default:
246 etiss_log(FATALERROR, "variable \"pending\" has an invalid value");
247 }
248 if (clkedge)
249 pending = 0; // clear event
250 }
251 }
252 else if (clkedge)
253 {
254 setBool(core_, sigs.ack_o, false);
255 setBool(core_, sigs.err_o, false);
256 setBool(core_, sigs.rty_o, false);
257 setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, 0);
258 }
259 }
260 else // reevaluate signals
261 {
262 if (clkedge && (pending == 0))
263 {
264 // immediate reset of signals
265 {
266 setBool(core_, sigs.ack_o, false);
267 setBool(core_, sigs.err_o, false);
268 setBool(core_, sigs.rty_o, false);
269 setData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_o, 0);
270 }
271 if (getBool(core_, sigs.cyc_i) && getBool(core_, sigs.stb_i)) // Bus access
272 {
273 uint64_t addr = getAddr(core_, sigs.adr_i, instrBus);
274 unsigned addressOffet = addr & (bytewidth - 1); // offset (only needed for validation)
275 addr &= (~uint64_t(bytewidth - 1)); // Ignore unaligned address bits
276 VECTORSIGSTORAGETYPE dataBuf = 0;
277 uint64_t localTime = time; // time on read/write call
278 unsigned dataLength; // length of read/write access
279
280 if (getBool(core_, sigs.we_i)) // write
281 {
282 if (!sel2Length(getSel(core_, sigs.sel_i), dataLength, addressOffet))
284 std::string("invalid sel_i: ") + std::to_string(getSel(core_, sigs.sel_i)));
285 dataBuf = getData<VECTORSIGSTORAGETYPE, VECTORSIG>(core_, sigs.dat_i);
286 flipEndianness((uint8_t *)&dataBuf);
287 exception = write(instrBus, localTime, addr + addressOffet,
288 ((uint8_t *)&dataBuf) + addressOffet, dataLength);
289 pending = 2;
290
291 /*std::cout << "Wishbone " << (instrBus?"ibus":"dbus")
292 << " - write: 0x" << std::hex << dataBuf
293 << " at address 0x" << addr+addressOffet
294 << " len: " << dataLength
295 << std::dec << std::endl;*/
296 }
297 else // read
298 {
299 if (!sel2Length(getSel(core_, sigs.sel_i), dataLength, addressOffet))
301 std::string("invalid sel_i: ") + std::to_string(getSel(core_, sigs.sel_i)));
302 exception = read(instrBus, localTime, addr + addressOffet,
303 ((uint8_t *)&dataBuf) + addressOffet, dataLength);
304 flipEndianness((uint8_t *)&dataBuf);
305 dat_o = dataBuf; // store but don't provide result
306 pending = 1;
307
308 /*std::cout << "Wishbone " << (instrBus?"ibus":"dbus")
309 << " - read: 0x" << std::hex << dataBuf
310 << " at address 0x" << addr+addressOffet
311 << " len: " << dataLength
312 << std::dec << std::endl;*/
313 }
314
315 po_err = (exception == etiss::RETURNCODE::DBUS_READ_ERROR ||
316 exception == etiss::RETURNCODE::DBUS_WRITE_ERROR ||
317 exception == etiss::RETURNCODE::IBUS_READ_ERROR ||
318 exception == etiss::RETURNCODE::IBUS_WRITE_ERROR);
319 if (po_err)
320 exception = etiss::RETURNCODE::NOERROR;
321
322 etime = localTime; // store event time
323 }
324 }
325 }
326 }
327 return exception;
328 }
329
330 private:
332 inline void flipEndianness(uint8_t *buf)
333 {
334 if (flipEndianess)
335 {
336 for (unsigned i = 0; i < (bytewidth / 2); ++i)
337 {
338 std::swap(buf[i], buf[bytewidth - 1 - i]);
339 }
340 }
341 }
342
350 bool sel2Length(uint32_t sel, unsigned &length, unsigned &addressOffset)
351 {
352 length = 0;
353 unsigned selectOffset = 0;
354
355 // nothing to transmit on bus (len = 0)
356 if (sel == 0)
357 return 0;
358
359 /* only one steam of '1's is allowed like 0011 or 1100 (correlates to halfword)
360 * so we first remove all leading '0's and so get the address offset
361 * (unusual cases like 0110 are not covered with this check!)
362 */
363 while ((sel & 1) == 0)
364 {
365 selectOffset++;
366 sel >>= 1;
367 }
368 /* thereafter we check the length with the following '1's
369 * if the sel signal thereafter is NOT empty it wasn't valid
370 */
371 while ((sel & 1) == 1)
372 {
373 length++;
374 sel >>= 1;
375 }
376
377 /* Endianess is always swapped on the whole bus width eg. 32bit or 64bit.
378 * The offset is than be seen from the other side of the stream:
379 * 0010 0010
380 * ^ -> ^^
381 */
382 if (flipEndianess)
383 selectOffset = bytewidth - length - selectOffset;
384
385 // Check if calculated offset is valid with given bus offset. (Normally not given in wishbone bus)
386 static bool output_addressOffset_warning = false;
387 if ((selectOffset != addressOffset) && !output_addressOffset_warning)
388 {
390 std::string("Wishbone bus offset not valid! (0x") + std::to_string((int)addressOffset) + ")");
391 output_addressOffset_warning = true;
392 }
393
394 return sel == 0;
395 }
396
397 //--------------------------------------- Attributes ---------------------------------------
398 public:
400
401 private:
407 VECTORSIGSTORAGETYPE dat_o;
408 bool po_err;
409 unsigned pending;
410};
411
412} // namespace interfaces
413} // namespace etiss
414
415#endif // ETISS_INTERFACES_WISHBONE_H
#define etiss_log(LEVEL, MSG)
Definition Misc.h:41
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:54
CPUCore is responsible for the simulation of a CPU core in ETISS.
Definition CPUCore.h:64
connects a wishbone bus interface implemented with the variables of WishboneSignalMap to a ETISS_Syst...
Definition Wishbone.h:141
bool useposclkedge
use positive or negative clock edge
Definition Wishbone.h:406
VECTORSIGSTORAGETYPE dat_o
buffer for data out to CPU
Definition Wishbone.h:407
void init()
Initiate all bus output signals and set pending status to "nothing pending".
Definition Wishbone.h:166
unsigned pending
0: nothing pending; 1: Read pending; 2: Write pending
Definition Wishbone.h:409
WishboneBus(WishboneSignalMap< BOOLSIG, VECTORSIG > &sigs, ETISS_System &system, ETISS_CPU &cpu, etiss::CPUCore &core)
Constructor.
Definition Wishbone.h:151
void flipEndianness(uint8_t *buf)
Flips endianess of a VECTORSIG.
Definition Wishbone.h:332
bool po_err
bus error arised
Definition Wishbone.h:408
bool lastclock
used for determining clock edge
Definition Wishbone.h:405
WishboneSignalMap< BOOLSIG, VECTORSIG > & sigs
Signals between bus and CPU.
Definition Wishbone.h:399
bool sel2Length(uint32_t sel, unsigned &length, unsigned &addressOffset)
Calculates length and offset out of signal sel.
Definition Wishbone.h:350
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:185
uint64_t lastutime
time of last signal evaluation phase
Definition Wishbone.h:403
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:113
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:77
VECTORSIGSTORAGETYPE getData(etiss::CPUCore &core, VECTORSIG &sig)
general helper function to read a signal; needs to be implemented as needed
Definition Wishbone.h:67
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:57
bool getBool(etiss::CPUCore &core, BOOLSIG &sig)
general helper function to read a signal; needs to be implemented as needed
Definition Wishbone.h:38
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:48
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:86
forwards: include/jit/*
Definition Benchmark.h:17
@ WARNING
Definition Misc.h:86
@ ERROR
Definition Misc.h:85
@ FATALERROR
Definition Misc.h:84
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition Misc.cpp:94
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:51
memory access and time synchronization functions.
Definition System.h:40
simple helper struct to trigger static_assert only if the template is instantiated
Definition Wishbone.h:31