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

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0