gem5 v23.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
reg_bank.hh
Go to the documentation of this file.
1/*
2 * Copyright 2020 Google, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef __DEV_REG_BANK_HH__
29#define __DEV_REG_BANK_HH__
30
31#include <algorithm>
32#include <bitset>
33#include <cassert>
34#include <cstdint>
35#include <cstring>
36#include <functional>
37#include <initializer_list>
38#include <iostream>
39#include <map>
40#include <optional>
41#include <sstream>
42#include <utility>
43
44#include "base/bitfield.hh"
45#include "base/logging.hh"
46#include "base/types.hh"
47#include "sim/byteswap.hh"
49
50/*
51 * Device models often have contiguous banks of registers which can each
52 * have unique and arbitrary behavior when they are completely or partially
53 * read or written. Historically it's been up to each model to map an access
54 * which covers an arbitrary portion of that register bank down to individual
55 * registers. It must handle cases where registers are only partially accessed,
56 * or where multiple registers are accessed at the same time, or a combination
57 * of both.
58 *
59 *
60 * == RegisterBank ==
61 *
62 * The RegisterBank class(es), defined below, handle that mapping, and let the
63 * device model focus on defining what each of the registers actually do when
64 * read or written. Once it's set up, it has two primary interfaces which
65 * access the registers it contains:
66 *
67 * void read(Addr addr, void *buf, Addr bytes);
68 * void write(Addr addr, const void *buf, Addr bytes);
69 *
70 * These two methods will handle a read or write contained within the register
71 * bank starting at address "addr". The data that will be written or has been
72 * read is pointed to by "buf", and is "bytes" bytes long.
73 *
74 * These methods are virtual, so if you need to implement extra rules, like
75 * for instance that registers can only be accessed one at a time, that
76 * accesses have to be aligned, have to access complete registers, etc, that
77 * can be added in a subclass.
78 *
79 * Additionally, each RegisterBank has a name and a base address which is
80 * passed into the constructor. The meaning of the "base" value can be whatever
81 * makes sense for your device, and is considered the lowest address contained
82 * in the bank. The value could be the offset of this bank of registers within
83 * the device itself, with the device's own offset subtracted out before read
84 * or write are called. It could alternatively be the base address of the
85 * entire device, with the address from accesses passed into read or write
86 * unmodified.
87 *
88 * The base(), size() and name() methods can be used to access each of those
89 * read only properties of the RegisterBank instance.
90 *
91 * To add actual registers to the RegisterBank (discussed below), you can use
92 * either the addRegister method which adds a single register, or addRegisters
93 * which adds an initializer list of them all at once. The register will be
94 * appended to the end of the bank as they're added, contiguous to the
95 * existing registers. The size of the bank is automatically accumulated as
96 * registers are added.
97 *
98 * When adding a lot of registers, you might accidentally add an extra,
99 * or accidentally skip one in a long list. Because the offset is handled
100 * automatically, some of your registers might end up shifted higher or lower
101 * than you expect. To help mitigate this, you can set what offset you expect
102 * a register to have by specifying it as an offset, register pair.
103 *
104 * addRegisters({{0x1000, reg0}, reg1, reg2});
105 *
106 * If the register would end up at a different offset, gem5 will panic. You
107 * can also leave off the register if you want to just check the offset, for
108 * instance between groups of registers.
109 *
110 * addRegisters({reg0, reg1, reg2, 0x100c})
111 *
112 * While the RegisterBank itself doesn't have any data in it directly and so
113 * has no endianness, it's very likely all the registers within it will have
114 * the same endinanness. The bank itself therefore has a default endianness
115 * which, unless specified otherwise, will be passed on to the register types
116 * within it. The RegisterBank class is templated on its endianness. There are
117 * RegisterBankLE and RegisterBankBE aliases to make it a little easier to
118 * refer to one or the other version.
119 *
120 * A RegisterBank also has a reset() method which will (by default) call the
121 * reset() method on each register within it. This method is virtual, and so
122 * can be overridden if something additional or different needs to be done to
123 * reset the hardware model.
124 *
125 *
126 * == Register interface ==
127 *
128 * Every register in a RegisterBank needs to inherit, directly or indirectly,
129 * from the RegisterBase class. Each register must have a name (for debugging),
130 * and a well defined size. The following methods define the interface the
131 * register bank uses to access the register, and where the register can
132 * implement its special behaviors:
133 *
134 * void read(void *buf);
135 * void read(void *buf, off_t offset, size_t bytes);
136 *
137 * void write(const void *buf);
138 * void write(const void *buf, off_t offset, size_t bytes);
139 *
140 * The single argument versions of these methods completely overwrite the
141 * register's contents with whatever is pointed to by buf.
142 *
143 * The version which also takes "offset" and "bytes" arguments reads or writes
144 * only a portion of the register, starting "offset" bytes from the start of
145 * the register, and writing or reading the next "bytes" bytes.
146 *
147 * Each register also needs to implement serialize or unserialize methods
148 * which make it accessible to the checkpointing mechanism. If a register
149 * doesn't need to be serialized (for instance if it has a fixed value) then
150 * it still has to implement these methods, but they don't have to actually do
151 * anything.
152 *
153 * Each register also has a "reset" method, which will reset the register as
154 * if its containing device is being reset. By default, this will just restore
155 * the initial value of the register, but can be overridden to implement
156 * additional behavior like resetting other aspects of the device which are
157 * controlled by the value of the register.
158 *
159 *
160 * == Basic Register types ==
161 *
162 * Some simple register types have been defined which handle basic, common
163 * behaviors found in many devices:
164 *
165 * = RegisterRaz and RegisterRao =
166 *
167 * RegisterRaz (read as zero) and RegisterRao (read as one) will ignore writes,
168 * and will return all zeroes or ones, respectively, when read. These can have
169 * arbitrary alignment and size, and can be used for, for instance,
170 * unimplemented registers that still need to take up a certain amount of
171 * space, or for gaps between registers which still need to handle accesses
172 * even though they don't do anything or hold any data.
173 *
174 * For instance, a device might have several regions of registers which are
175 * aligned on different boundaries, but which might not take up all of the
176 * space in each region. The extra space can be filled with a RegisterRaz or
177 * RegisterRao, making it possible to implement all the registers as a single
178 * bank.
179 *
180 * If you need a register with a different fill pattern, you can subclass the
181 * RegisterRoFill type and implement its "fill" method. This should behave
182 * like the three argument form of the read() method, described above.
183 *
184 * = RegisterBuf and RegisterLBuf =
185 *
186 * These two types act like inert blobs of storage. They don't have any
187 * special behavior and can have any arbitrary size like the RegisterRao and
188 * RegisterRaz types above, but these registers actually store what's written
189 * to them.
190 *
191 * The RegisterBuf type acts as an interface to a buffer stored elsewhere. That
192 * makes it possible to, for instance, alias the same buffer to different parts
193 * of the register space, or to expose some other object which needs to exist
194 * outside of the register bank for some reason.
195 *
196 * The RegisterLBuf does the same thing, except it uses a local buffer it
197 * manages. That makes it a little easier to work with if you don't need the
198 * flexibility of the RegisterBuf type.
199 *
200 *
201 * == Typed Registers ==
202 *
203 * The Register template class is for more complex registers with side effects,
204 * and/or which hold structured data. The template arguments define what type
205 * the register should hold, and also its endianness.
206 *
207 * = Access handlers =
208 *
209 * Instead of subclassing the Register<Data> type and redefining its read/write
210 * methods, reads and writes are implemented using replaceable handlers with
211 * these signatures:
212 *
213 * Data read(Register<Data> &reg);
214 * Data partialRead(Register<Data> &reg, int first, int last);
215 * void write(Register<Data> &reg, const Data &value);
216 * void partialWrite(Register<Data> &reg, const Data &value,
217 * int first, int last);
218 *
219 * The "partial" version of these handlers take "first" and "last" arguments
220 * which specify what bits of the register to modify. They should be
221 * interpreted like the same arguments in base/bitfield.hh. The endianness
222 * of the register will have already been dealt with by the time the handler
223 * is called.
224 *
225 * The read and partialRead handlers should generate whatever value reading the
226 * register should return, based on (or not based on) the state of "reg". The
227 * partial handler should keep the bits it returns in place. For example, if
228 * bits 15-8 are read from a 16 bit register with the value 0x1234, it should
229 * return 0x1200, not 0x0012.
230 *
231 * The write and partialWrite handlers work the same way, except in they write
232 * instead of read. They are responsible for updating the value in reg in
233 * whatever way and to whatever value is appropriate, based on
234 * (or not based on) the value of "value" and the state of "reg".
235 *
236 * The default implementations of the read and write handlers simply return or
237 * update the value stored in reg. The default partial read calls the read
238 * handler (which may not be the default), and trims down the data as required.
239 * The default partial write handler calls the read handler (which may not be
240 * the default), updates the value as requested, and then calls the write
241 * handler (which may not be the default).
242 *
243 * Overriding the partial read or write methods might be necessary if reads or
244 * writes have side effects which should affect only the part of the register
245 * read or written. For instance, there might be some status bits which will
246 * be cleared when accessed. Only the bits which were actually accessed should
247 * be affected, even if they're grouped together logically with the other bits
248 * in a single register.
249 *
250 * To set your own handlers, you can use the "reader", "writer",
251 * "partialReader", and "partialWriter" methods. Each of these takes a single
252 * callable argument (lambda, functor, function pointer, etc.) which will
253 * replace the current corresponding handler.
254 *
255 * These methods all return a reference to the current Register so that they
256 * can be strung together without having to respecify what object you're
257 * modifying over and over again.
258 *
259 * There are also versions of these which will set up methods on some object as
260 * the handlers. These take a pointer to whatever object will handle the call,
261 * and a member function pointer to the method that will actually implement
262 * the handler. This can be used if, for instance, the registers are all
263 * members of a RegisterBank subclass, and need to call methods on their
264 * parent class to actually implement the behavior. These methods must have
265 * the same signature as above, with the exception that they are methods and
266 * not bare functions.
267 *
268 * When updating the register's value in custom write or partialWrite handlers,
269 * be sure to use the "update" method which will honor read only bits. There
270 * is an alternative form of update which also takes a custom bitmask, if you
271 * need to update bits other than the normally writeable ones.
272 *
273 * Similarly, you can set a "resetter" handler which is responsible for
274 * resetting the register. It takes a reference to the current Register, and
275 * no other parameters. The "initialValue" accessor can retrieve the value the
276 * register was constructed with. The register is simply set to this value
277 * in the default resetter implementation.
278 *
279 * = Read only bits =
280 *
281 * Often registers have bits which are fixed and not affected by writes. To
282 * specify which bits are writeable, use the "writeable" method which takes a
283 * single argument the same type as the type of the register. It should hold a
284 * bitmask where a 1 bit can be written, and a 0 cannot. Calling writeable with
285 * no arguments will return the current bitmask.
286 *
287 * A shorthand "readonly" method marks all bits as read only.
288 *
289 * Both methods return a reference to the current Register so they can be
290 * strung together into a sequence when configuring it.
291 *
292 * = Underlying data and serialization =
293 *
294 * The "get" method returns a reference to the underlying storage inside the
295 * register. That can be used to manually update the entire register, even bits
296 * which are normally read only, or for structured data, to access members of
297 * the underlying data type.
298 *
299 * For instance, if the register holds a BitUnion, you could use the get()
300 * method to access the bitfields within it:
301 *
302 * reg.get().bitfieldA = reg.get().bitfieldB;
303 *
304 * The serialize and unserialize methods for these types will pass through the
305 * underlying data within the register. For instance, when serializing a
306 * Register<Foo>, the value in the checkpoint will be the same as if you had
307 * serialized a Foo directly, with the value stored in the register.
308 *
309 * = Aliases =
310 *
311 * Some convenient aliases have been defined for frequently used versions of
312 * the Register class. These are
313 *
314 * Register(8|16|32|64)(LE|BE|)
315 *
316 * Where the underlying type of the register is a uint8_t, uint16_t, etc, and
317 * the endianness is little endian, big endian, or whatever the default is for
318 * the RegisterBank.
319 */
320
321namespace gem5
322{
323
324// Common bases to make it easier to identify both endiannesses at once.
326{
327 public:
329};
330
331template <ByteOrder BankByteOrder>
333{
334 public:
335 // Static helper methods for implementing register types.
336 template <typename Data>
337 static constexpr Data
338 readWithMask(const Data &value, const Data &bitmask)
339 {
340 return value & bitmask;
341 }
342
343 template <typename Data>
344 static constexpr Data
345 writeWithMask(const Data &old, const Data &value, const Data &bitmask)
346 {
347 return readWithMask(
348 old, (Data)~bitmask) | readWithMask(value, bitmask);
349 }
350
352 {
353 protected:
354 const std::string _name;
355 size_t _size = 0;
356
357 public:
358 constexpr RegisterBase(const std::string &new_name, size_t new_size) :
359 _name(new_name), _size(new_size)
360 {}
361 virtual ~RegisterBase() {}
362
363 // Read the register's name.
364 virtual const std::string &name() const { return _name; }
365
366 // Read the register's size in bytes.
367 size_t size() const { return _size; }
368
369 // Perform a read on the register.
370 virtual void read(void *buf) = 0;
371 virtual void read(void *buf, off_t offset, size_t bytes) = 0;
372
373 // Perform a write on the register.
374 virtual void write(const void *buf) = 0;
375 virtual void write(const void *buf, off_t offset, size_t bytes) = 0;
376
377 // Methods for implementing serialization for checkpoints.
378 virtual void serialize(std::ostream &os) const = 0;
379 virtual bool unserialize(const std::string &s) = 0;
380
381 // Reset the register.
382 virtual void reset() = 0;
383 };
384
385 // Filler registers which return a fixed pattern.
387 {
388 protected:
389 constexpr RegisterRoFill(
390 const std::string &new_name, size_t new_size) :
391 RegisterBase(new_name, new_size)
392 {}
393
394 virtual void fill(void *buf, off_t offset, size_t bytes) = 0;
395
396 public:
397 // Ignore writes.
398 void write(const void *buf) override {}
399 void write(const void *buf, off_t offset, size_t bytes) override {}
400
401 // Use fill() to handle reads.
402 void read(void *buf) override { fill(buf, 0, this->size()); }
403 void
404 read(void *buf, off_t offset, size_t bytes) override
405 {
406 fill(buf, offset, bytes);
407 }
408
409 void serialize(std::ostream &os) const override {}
410 bool unserialize(const std::string &s) override { return true; }
411
412 // Resetting a read only register doesn't need to do anything.
413 void reset() override {}
414 };
415
416 // Register which reads as all zeroes.
418 {
419 protected:
420 void
421 fill(void *buf, off_t offset, size_t bytes) override
422 {
423 bzero(buf, bytes);
424 }
425
426 public:
427 RegisterRaz(const std::string &new_name, size_t new_size) :
428 RegisterRoFill(new_name, new_size)
429 {}
430 };
431
432 // Register which reads as all ones.
434 {
435 protected:
436 void
437 fill(void *buf, off_t offset, size_t bytes) override
438 {
439 memset(buf, 0xff, bytes);
440 }
441
442 public:
443 RegisterRao(const std::string &new_name, size_t new_size) :
444 RegisterRoFill(new_name, new_size)
445 {}
446 };
447
448 // Register which acts as a simple buffer.
450 {
451 private:
452 void *_ptr = nullptr;
453
454 public:
455 RegisterBuf(const std::string &new_name, void *ptr, size_t bytes) :
456 RegisterBase(new_name, bytes), _ptr(ptr)
457 {}
458
459 void write(const void *buf) override { write(buf, 0, this->size()); }
460 void
461 write(const void *buf, off_t offset, size_t bytes) override
462 {
463 assert(offset + bytes <= this->size());
464 memcpy((uint8_t *)_ptr + offset, buf, bytes);
465 }
466
467 void read(void *buf) override { read(buf, 0, this->size()); }
468 void
469 read(void *buf, off_t offset, size_t bytes) override
470 {
471 assert(offset + bytes <= this->size());
472 memcpy(buf, (uint8_t *)_ptr + offset, bytes);
473 }
474
475 // The buffer's owner is responsible for serializing it.
476 void serialize(std::ostream &os) const override {}
477 bool unserialize(const std::string &s) override { return true; }
478
479 // Assume since the buffer is managed externally, it will be reset
480 // externally.
481 void reset() override {}
482
483 protected:
490 void
491 setBuffer(void *buf)
492 {
493 assert(_ptr == nullptr);
494 assert(buf != nullptr);
495 _ptr = buf;
496 }
497 };
498
499 // Same as above, but which keeps its storage locally.
500 template <int BufBytes>
502 {
503 public:
504 std::array<uint8_t, BufBytes> buffer;
505
506 RegisterLBuf(const std::string &new_name) :
507 RegisterBuf(new_name, nullptr, BufBytes)
508 {
509 this->setBuffer(buffer.data());
510 }
511
512 void
513 serialize(std::ostream &os) const override
514 {
515 if (BufBytes)
517 for (int i = 1; i < BufBytes; i++) {
518 os << " ";
520 }
521 }
522
523 bool
524 unserialize(const std::string &s) override
525 {
527 std::istringstream is(s);
528
529 std::string token;
530 while (is >> token)
531 tokens.push_back(token);
532
533 if (tokens.size() != BufBytes) {
534 warn("Size mismatch unserialing %s, expected %d, got %d",
535 this->name(), BufBytes, tokens.size());
536 return false;
537 }
538
539 for (int i = 0; i < BufBytes; i++) {
540 if (!ParseParam<uint8_t>::parse(tokens[i], buffer[i]))
541 return false;
542 }
543
544 return true;
545 }
546
547 void reset() override { buffer = std::array<uint8_t, BufBytes>{}; }
548 };
549
550 template <typename Data, ByteOrder RegByteOrder=BankByteOrder>
551 class Register : public RegisterBase
552 {
553 protected:
555
556 public:
557 using ReadFunc = std::function<Data (This &reg)>;
558 using PartialReadFunc = std::function<
559 Data (This &reg, int first, int last)>;
560 using WriteFunc = std::function<void (This &reg, const Data &value)>;
561 using PartialWriteFunc = std::function<
562 void (This &reg, const Data &value, int first, int last)>;
563 using ResetFunc = std::function<void (This &reg)>;
564
565 private:
566 Data _data = {};
567 Data _resetData = {};
568 Data _writeMask = mask(sizeof(Data) * 8);
569
575
576 protected:
577 static Data defaultReader(This &reg) { return reg.get(); }
578
579 static Data
580 defaultPartialReader(This &reg, int first, int last)
581 {
582 return mbits(reg._reader(reg), first, last);
583 }
584
585 static void
586 defaultWriter(This &reg, const Data &value)
587 {
588 reg.update(value);
589 }
590
591 static void
592 defaultPartialWriter(This &reg, const Data &value, int first, int last)
593 {
594 reg._writer(reg, writeWithMask<Data>(reg._reader(reg), value,
595 mask(first, last)));
596 }
597
598 static void
600 {
601 reg.get() = reg.initialValue();
602 }
603
604 constexpr Data
606 {
607 switch (RegByteOrder) {
608 case ByteOrder::big:
609 return htobe(data);
610 case ByteOrder::little:
611 return htole(data);
612 default:
613 panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
614 }
615 }
616
617 constexpr Data
619 {
620 switch (RegByteOrder) {
621 case ByteOrder::big:
622 return betoh(data);
623 case ByteOrder::little:
624 return letoh(data);
625 default:
626 panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
627 }
628 }
629
630 public:
631
632 /*
633 * Interface for setting up the register.
634 */
635
636 // Constructor which lets data default initialize itself.
637 constexpr Register(const std::string &new_name) :
638 RegisterBase(new_name, sizeof(Data))
639 {}
640
641 // Constructor and move constructor with an initial data value.
642 constexpr Register(const std::string &new_name, const Data &new_data) :
643 RegisterBase(new_name, sizeof(Data)), _data(new_data),
644 _resetData(new_data)
645 {}
646 constexpr Register(const std::string &new_name,
647 const Data &&new_data) :
648 RegisterBase(new_name, sizeof(Data)), _data(new_data),
649 _resetData(new_data)
650 {}
651
652 // Set which bits of the register are writeable.
653 constexpr This &
654 writeable(const Data &new_mask)
655 {
656 _writeMask = new_mask;
657 return *this;
658 }
659
660 // Set the register as read only.
661 constexpr This &readonly() { return writeable(0); }
662
663 // Set the callables which handles reads or writes.
664 // The default reader just returns the register value.
665 // The default writer uses the write mask to update the register value.
666 constexpr This &
667 reader(const ReadFunc &new_reader)
668 {
669 _reader = new_reader;
670 return *this;
671 }
672 template <class Parent, class... Args>
673 constexpr This &
674 reader(Parent *parent, Data (Parent::*nr)(Args... args))
675 {
676 auto wrapper = [parent, nr](Args&&... args) -> Data {
677 return (parent->*nr)(std::forward<Args>(args)...);
678 };
679 return reader(wrapper);
680 }
681 constexpr This &
682 writer(const WriteFunc &new_writer)
683 {
684 _writer = new_writer;
685 return *this;
686 }
687 template <class Parent, class... Args>
688 constexpr This &
689 writer(Parent *parent, void (Parent::*nw)(Args... args))
690 {
691 auto wrapper = [parent, nw](Args&&... args) {
692 (parent->*nw)(std::forward<Args>(args)...);
693 };
694 return writer(wrapper);
695 }
696
697 // Set the callables which handle reads or writes. These may need to
698 // be handled specially if, for instance, accessing bits outside of
699 // the enables would have side effects that shouldn't happen.
700 //
701 // The default partial reader just uses the byte enables to mask off
702 // bits that are not being read.
703 //
704 // The default partial writer reads the current value of the register,
705 // uses the byte enables to update only the bytes that are changing,
706 // and then writes the result back to the register.
707 constexpr This &
709 {
710 _partialReader = new_reader;
711 return *this;
712 }
713 template <class Parent, class... Args>
714 constexpr This &
715 partialReader(Parent *parent, Data (Parent::*nr)(Args... args))
716 {
717 auto wrapper = [parent, nr](Args&&... args) -> Data {
718 return (parent->*nr)(std::forward<Args>(args)...);
719 };
720 return partialReader(wrapper);
721 }
722 constexpr This &
724 {
725 _partialWriter = new_writer;
726 return *this;
727 }
728 template <class Parent, class... Args>
729 constexpr This &
730 partialWriter(Parent *parent, void (Parent::*nw)(Args... args))
731 {
732 auto wrapper = [parent, nw](Args&&... args) {
733 return (parent->*nw)(std::forward<Args>(args)...);
734 };
735 return partialWriter(wrapper);
736 }
737
738 // Set the callables which handle resetting.
739 //
740 // The default resetter restores the initial value used in the
741 // constructor.
742 constexpr This &
743 resetter(const ResetFunc &new_resetter)
744 {
745 _resetter = new_resetter;
746 return *this;
747 }
748 template <class Parent, class... Args>
749 constexpr This &
750 resetter(Parent *parent, void (Parent::*nr)(Args... args))
751 {
752 auto wrapper = [parent, nr](Args&&... args) {
753 return (parent->*nr)(std::forward<Args>(args)...);
754 };
755 return resetter(wrapper);
756 }
757
758 // An accessor which returns the initial value as set in the
759 // constructor. This is intended to be used in a resetter function.
760 const Data &initialValue() const { return _resetData; }
761
762 // Reset the initial value, which is normally set in the constructor,
763 // to the register's current value.
765
766 /*
767 * Interface for accessing the register's state, for use by the
768 * register's helper functions and the register bank.
769 */
770
771 const Data &writeable() const { return _writeMask; }
772
773 // Directly access the underlying data value.
774 const Data &get() const { return _data; }
775 Data &get() { return _data; }
776
777 // Update data while applying a mask.
778 void
779 update(const Data &new_data, const Data &bitmask)
780 {
781 _data = writeWithMask(_data, new_data, bitmask);
782 }
783 // This version uses the default write mask.
784 void
785 update(const Data &new_data)
786 {
787 _data = writeWithMask(_data, new_data, _writeMask);
788 }
789
790
791 /*
792 * Interface for reading/writing the register, for use by the
793 * register bank.
794 */
795
796 // Perform a read on the register.
797 void
798 read(void *buf) override
799 {
800 Data data = htoreg(_reader(*this));
801 memcpy(buf, (uint8_t *)&data, sizeof(data));
802 }
803
804 void
805 read(void *buf, off_t offset, size_t bytes) override
806 {
807 // Move the region we're reading to be little endian, since that's
808 // what gem5 uses internally in BitUnions, masks, etc.
809 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
810 sizeof(Data) - (offset + bytes) : offset;
811
812 const int first = (host_off + bytes) * 8 - 1;
813 const int last = host_off * 8;
814 Data data = htoreg(_partialReader(*this, first, last));
815
816 memcpy(buf, (uint8_t *)&data + offset, bytes);
817 }
818
819 // Perform a write on the register.
820 void
821 write(const void *buf) override
822 {
823 Data data;
824 memcpy((uint8_t *)&data, buf, sizeof(data));
825 data = regtoh(data);
826 _writer(*this, data);
827 }
828
829 void
830 write(const void *buf, off_t offset, size_t bytes) override
831 {
832 Data data = {};
833 memcpy((uint8_t *)&data + offset, buf, bytes);
834
835 data = regtoh(data);
836
837 // Move the region we're reading to be little endian, since that's
838 // what gem5 uses internally in BitUnions, masks, etc.
839 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
840 sizeof(Data) - (offset + bytes) : offset;
841
842 const int first = (host_off + bytes) * 8 - 1;
843 const int last = host_off * 8;
844 _partialWriter(*this, data, first, last);
845 }
846
847 // Serialize our data using existing mechanisms.
848 void
849 serialize(std::ostream &os) const override
850 {
852 }
853
854 bool
855 unserialize(const std::string &s) override
856 {
857 return ParseParam<Data>::parse(s, get());
858 }
859
860 // Reset our data to its initial value.
861 void reset() override { _resetter(*this); }
862 };
863
864 private:
865 std::map<Addr, std::reference_wrapper<RegisterBase>> _offsetMap;
866
869 const std::string _name;
870
871 public:
872
885
886
887 constexpr RegisterBank(const std::string &new_name, Addr new_base) :
888 _base(new_base), _name(new_name)
889 {}
890
891 virtual ~RegisterBank() {}
892
894 {
895 private:
896 std::optional<Addr> offset;
897 std::optional<RegisterBase *> reg;
898
899 public:
900 // Nothing special to do for this register.
901 RegisterAdder(RegisterBase &new_reg) : reg(&new_reg) {}
902 // Ensure that this register is added at a particular offset.
903 RegisterAdder(Addr new_offset, RegisterBase &new_reg) :
904 offset(new_offset), reg(&new_reg)
905 {}
906 // No register, just check that the offset is what we expect.
907 RegisterAdder(Addr new_offset) : offset(new_offset) {}
908
909 friend class RegisterBank;
910 };
911
912 void
913 addRegisters(std::initializer_list<RegisterAdder> adders)
914 {
915 panic_if(std::empty(adders),
916 "Adding an empty list of registers to %s?", name());
917 for (auto &adder: adders) {
918 const Addr offset = _base + _size;
919
920 if (adder.reg) {
921 auto *reg = adder.reg.value();
922 if (adder.offset && adder.offset.value() != offset) {
923 panic(
924 "Expected offset of register %s.%s to be %#x, is %#x.",
925 name(), reg->name(), adder.offset.value(), offset);
926 }
927 _offsetMap.emplace(offset, *reg);
928 _size += reg->size();
929 } else if (adder.offset) {
930 if (adder.offset.value() != offset) {
931 panic("Expected current offset of %s to be %#x, is %#x.",
932 name(), adder.offset.value(), offset);
933 }
934 }
935 }
936 }
937
939
940 Addr base() const { return _base; }
941 Addr size() const { return _size; }
942 const std::string &name() const { return _name; }
943
944 virtual void
945 read(Addr addr, void *buf, Addr bytes)
946 {
947 uint8_t *ptr = (uint8_t *)buf;
948 // Number of bytes we've transferred.
949 Addr done = 0;
950
951 panic_if(addr - base() + bytes > size(),
952 "Out of bounds read in register bank %s, address %#x, size %d.",
953 name(), addr, bytes);
954
955 auto it = _offsetMap.lower_bound(addr);
956 if (it == _offsetMap.end() || it->first > addr)
957 it--;
958
959 if (it->first < addr) {
960 RegisterBase &reg = it->second.get();
961 // Skip at least the beginning of the first register.
962
963 // Figure out what parts of it we're accessing.
964 const off_t reg_off = addr - it->first;
965 const size_t reg_bytes = std::min(reg.size() - reg_off,
966 bytes - done);
967
968 // Actually do the access.
969 reg.read(ptr, reg_off, reg_bytes);
970 done += reg_bytes;
971 it++;
972
973 // Was that everything?
974 if (done == bytes)
975 return;
976 }
977
978 while (true) {
979 RegisterBase &reg = it->second.get();
980
981 const size_t reg_size = reg.size();
982 const size_t remaining = bytes - done;
983
984 if (remaining == reg_size) {
985 // A complete register read, and then we're done.
986 reg.read(ptr + done);
987 return;
988 } else if (remaining > reg_size) {
989 // A complete register read, with more to go.
990 reg.read(ptr + done);
991 done += reg_size;
992 it++;
993 } else {
994 // Skip the end of the register, and then we're done.
995 reg.read(ptr + done, 0, remaining);
996 return;
997 }
998 }
999 }
1000
1001 virtual void
1002 write(Addr addr, const void *buf, Addr bytes)
1003 {
1004 const uint8_t *ptr = (const uint8_t *)buf;
1005 // Number of bytes we've transferred.
1006 Addr done = 0;
1007
1008 panic_if(addr - base() + bytes > size(),
1009 "Out of bounds write in register bank %s, address %#x, size %d.",
1010 name(), addr, bytes);
1011
1012 auto it = _offsetMap.lower_bound(addr);
1013 if (it == _offsetMap.end() || it->first > addr)
1014 it--;
1015
1016 if (it->first < addr) {
1017 RegisterBase &reg = it->second.get();
1018 // Skip at least the beginning of the first register.
1019
1020 // Figure out what parts of it we're accessing.
1021 const off_t reg_off = addr - it->first;
1022 const size_t reg_bytes = std::min(reg.size() - reg_off,
1023 bytes - done);
1024
1025 // Actually do the access.
1026 reg.write(ptr, reg_off, reg_bytes);
1027 done += reg_bytes;
1028 it++;
1029
1030 // Was that everything?
1031 if (done == bytes)
1032 return;
1033 }
1034
1035 while (true) {
1036 RegisterBase &reg = it->second.get();
1037
1038 const size_t reg_size = reg.size();
1039 const size_t remaining = bytes - done;
1040
1041 if (remaining == reg_size) {
1042 // A complete register write, and then we're done.
1043 reg.write(ptr + done);
1044 return;
1045 } else if (remaining > reg_size) {
1046 // A complete register write, with more to go.
1047 reg.write(ptr + done);
1048 done += reg_size;
1049 it++;
1050 } else {
1051 // Skip the end of the register, and then we're done.
1052 reg.write(ptr + done, 0, remaining);
1053 return;
1054 }
1055 }
1056 }
1057
1058 // By default, reset all the registers in the bank.
1059 virtual void
1061 {
1062 for (auto &it: _offsetMap)
1063 it.second.get().reset();
1064 }
1065};
1066
1069
1070// Delegate serialization to the individual RegisterBase subclasses.
1071template <class T>
1072struct ParseParam<T, std::enable_if_t<std::is_base_of_v<
1073 typename RegisterBankBase::RegisterBaseBase, T>>>
1074{
1075 static bool
1076 parse(const std::string &s, T &value)
1077 {
1078 return value.unserialize(s);
1079 }
1080};
1081
1082template <class T>
1083struct ShowParam<T, std::enable_if_t<std::is_base_of_v<
1084 typename RegisterBankBase::RegisterBaseBase, T>>>
1085{
1086 static void
1087 show(std::ostream &os, const T &value)
1088 {
1089 value.serialize(os);
1090 }
1091};
1092
1093} // namespace gem5
1094
1095#endif // __DEV_REG_BANK_HH__
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
const char data[]
std::optional< Addr > offset
Definition reg_bank.hh:896
RegisterAdder(RegisterBase &new_reg)
Definition reg_bank.hh:901
std::optional< RegisterBase * > reg
Definition reg_bank.hh:897
RegisterAdder(Addr new_offset, RegisterBase &new_reg)
Definition reg_bank.hh:903
virtual void write(const void *buf)=0
virtual void read(void *buf)=0
constexpr RegisterBase(const std::string &new_name, size_t new_size)
Definition reg_bank.hh:358
virtual void read(void *buf, off_t offset, size_t bytes)=0
virtual bool unserialize(const std::string &s)=0
virtual const std::string & name() const
Definition reg_bank.hh:364
virtual void write(const void *buf, off_t offset, size_t bytes)=0
virtual void serialize(std::ostream &os) const =0
void write(const void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:461
RegisterBuf(const std::string &new_name, void *ptr, size_t bytes)
Definition reg_bank.hh:455
bool unserialize(const std::string &s) override
Definition reg_bank.hh:477
void serialize(std::ostream &os) const override
Definition reg_bank.hh:476
void write(const void *buf) override
Definition reg_bank.hh:459
void read(void *buf) override
Definition reg_bank.hh:467
void read(void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:469
void setBuffer(void *buf)
This method exists so that derived classes that need to initialize their buffers before they can be s...
Definition reg_bank.hh:491
void serialize(std::ostream &os) const override
Definition reg_bank.hh:513
bool unserialize(const std::string &s) override
Definition reg_bank.hh:524
std::array< uint8_t, BufBytes > buffer
Definition reg_bank.hh:504
RegisterLBuf(const std::string &new_name)
Definition reg_bank.hh:506
RegisterRao(const std::string &new_name, size_t new_size)
Definition reg_bank.hh:443
void fill(void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:437
RegisterRaz(const std::string &new_name, size_t new_size)
Definition reg_bank.hh:427
void fill(void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:421
void read(void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:404
virtual void fill(void *buf, off_t offset, size_t bytes)=0
constexpr RegisterRoFill(const std::string &new_name, size_t new_size)
Definition reg_bank.hh:389
void write(const void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:399
bool unserialize(const std::string &s) override
Definition reg_bank.hh:410
void serialize(std::ostream &os) const override
Definition reg_bank.hh:409
void write(const void *buf) override
Definition reg_bank.hh:398
void read(void *buf) override
Definition reg_bank.hh:402
constexpr This & resetter(const ResetFunc &new_resetter)
Definition reg_bank.hh:743
std::function< Data(This &reg, int first, int last)> PartialReadFunc
Definition reg_bank.hh:559
bool unserialize(const std::string &s) override
Definition reg_bank.hh:855
static void defaultWriter(This &reg, const Data &value)
Definition reg_bank.hh:586
constexpr Register(const std::string &new_name)
Definition reg_bank.hh:637
void write(const void *buf) override
Definition reg_bank.hh:821
std::function< void(This &reg, const Data &value)> WriteFunc
Definition reg_bank.hh:560
constexpr This & writer(Parent *parent, void(Parent::*nw)(Args... args))
Definition reg_bank.hh:689
PartialReadFunc _partialReader
Definition reg_bank.hh:573
constexpr This & partialWriter(const PartialWriteFunc &new_writer)
Definition reg_bank.hh:723
PartialWriteFunc _partialWriter
Definition reg_bank.hh:572
constexpr This & reader(Parent *parent, Data(Parent::*nr)(Args... args))
Definition reg_bank.hh:674
constexpr This & readonly()
Definition reg_bank.hh:661
static Data defaultReader(This &reg)
Definition reg_bank.hh:577
constexpr This & writer(const WriteFunc &new_writer)
Definition reg_bank.hh:682
void update(const Data &new_data, const Data &bitmask)
Definition reg_bank.hh:779
constexpr This & reader(const ReadFunc &new_reader)
Definition reg_bank.hh:667
std::function< void(This &reg, const Data &value, int first, int last)> PartialWriteFunc
Definition reg_bank.hh:562
void read(void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:805
static void defaultPartialWriter(This &reg, const Data &value, int first, int last)
Definition reg_bank.hh:592
void write(const void *buf, off_t offset, size_t bytes) override
Definition reg_bank.hh:830
void serialize(std::ostream &os) const override
Definition reg_bank.hh:849
constexpr Data regtoh(Data data)
Definition reg_bank.hh:618
const Data & writeable() const
Definition reg_bank.hh:771
constexpr Data htoreg(Data data)
Definition reg_bank.hh:605
const Data & initialValue() const
Definition reg_bank.hh:760
constexpr Register(const std::string &new_name, const Data &&new_data)
Definition reg_bank.hh:646
constexpr This & partialWriter(Parent *parent, void(Parent::*nw)(Args... args))
Definition reg_bank.hh:730
const Data & get() const
Definition reg_bank.hh:774
constexpr Register(const std::string &new_name, const Data &new_data)
Definition reg_bank.hh:642
constexpr This & partialReader(const PartialReadFunc &new_reader)
Definition reg_bank.hh:708
constexpr This & partialReader(Parent *parent, Data(Parent::*nr)(Args... args))
Definition reg_bank.hh:715
static Data defaultPartialReader(This &reg, int first, int last)
Definition reg_bank.hh:580
std::function< void(This &reg)> ResetFunc
Definition reg_bank.hh:563
void read(void *buf) override
Definition reg_bank.hh:798
constexpr This & writeable(const Data &new_mask)
Definition reg_bank.hh:654
void update(const Data &new_data)
Definition reg_bank.hh:785
constexpr This & resetter(Parent *parent, void(Parent::*nr)(Args... args))
Definition reg_bank.hh:750
Register< Data, RegByteOrder > This
Definition reg_bank.hh:554
std::function< Data(This &reg)> ReadFunc
Definition reg_bank.hh:557
static void defaultResetter(This &reg)
Definition reg_bank.hh:599
const std::string & name() const
Definition reg_bank.hh:942
virtual void reset()
Definition reg_bank.hh:1060
static constexpr Data readWithMask(const Data &value, const Data &bitmask)
Definition reg_bank.hh:338
void addRegister(RegisterAdder reg)
Definition reg_bank.hh:938
void addRegisters(std::initializer_list< RegisterAdder > adders)
Definition reg_bank.hh:913
Addr size() const
Definition reg_bank.hh:941
constexpr RegisterBank(const std::string &new_name, Addr new_base)
Definition reg_bank.hh:887
const std::string _name
Definition reg_bank.hh:869
std::map< Addr, std::reference_wrapper< RegisterBase > > _offsetMap
Definition reg_bank.hh:865
virtual ~RegisterBank()
Definition reg_bank.hh:891
virtual void read(Addr addr, void *buf, Addr bytes)
Definition reg_bank.hh:945
Addr base() const
Definition reg_bank.hh:940
static constexpr Data writeWithMask(const Data &old, const Data &value, const Data &bitmask)
Definition reg_bank.hh:345
virtual void write(Addr addr, const void *buf, Addr bytes)
Definition reg_bank.hh:1002
STL vector class.
Definition stl.hh:37
Definition test.h:49
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
Definition bitfield.hh:103
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define warn(...)
Definition logging.hh:256
Bitfield< 3, 0 > mask
Definition pcstate.hh:63
Bitfield< 4 > s
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 24, 22 > is
Bitfield< 5, 3 > reg
Definition types.hh:92
Bitfield< 17 > os
Definition misc.hh:810
Bitfield< 3 > addr
Definition types.hh:84
Bitfield< 29 > nw
Definition misc.hh:601
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
T letoh(T value)
Definition byteswap.hh:173
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
T betoh(T value)
Definition byteswap.hh:175
T htole(T value)
Definition byteswap.hh:172
T htobe(T value)
Definition byteswap.hh:174
Overload hash function for BasicBlockRange type.
Definition misc.hh:2910
static void show(std::ostream &os, const T &value)

Generated on Mon Jul 10 2023 14:24:31 for gem5 by doxygen 1.9.7