2 * Copyright 2020 Google, Inc.
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.
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.
28 #ifndef __DEV_REG_BANK_HH__
29 #define __DEV_REG_BANK_HH__
35 #include <initializer_list>
41 #include "base/bitfield.hh"
42 #include "base/logging.hh"
43 #include "base/types.hh"
44 #include "sim/byteswap.hh"
45 #include "sim/serialize_handlers.hh"
48 * Device models often have contiguous banks of registers which can each
49 * have unique and arbitrary behavior when they are completely or partially
50 * read or written. Historically it's been up to each model to map an access
51 * which covers an arbitrary portion of that register bank down to individual
52 * registers. It must handle cases where registers are only partially accessed,
53 * or where multiple registers are accessed at the same time, or a combination
59 * The RegisterBank class(es), defined below, handle that mapping, and let the
60 * device model focus on defining what each of the registers actually do when
61 * read or written. Once it's set up, it has two primary interfaces which
62 * access the registers it contains:
64 * void read(Addr addr, void *buf, Addr bytes);
65 * void write(Addr addr, const void *buf, Addr bytes);
67 * These two methods will handle a read or write contained within the register
68 * bank starting at address "addr". The data that will be written or has been
69 * read is pointed to by "buf", and is "bytes" bytes long.
71 * These methods are virtual, so if you need to implement extra rules, like
72 * for instance that registers can only be accessed one at a time, that
73 * accesses have to be aligned, have to access complete registers, etc, that
74 * can be added in a subclass.
76 * Additionally, each RegisterBank has a name and a base address which is
77 * passed into the constructor. The meaning of the "base" value can be whatever
78 * makes sense for your device, and is considered the lowest address contained
79 * in the bank. The value could be the offset of this bank of registers within
80 * the device itself, with the device's own offset subtracted out before read
81 * or write are called. It could alternatively be the base address of the
82 * entire device, with the address from accesses passed into read or write
85 * To add actual registers to the RegisterBank (discussed below), you can use
86 * either the addRegister method which adds a single register, or addRegisters
87 * which adds an initializer list of them all at once. The register will be
88 * appended to the end of the bank as they're added, contiguous to the
89 * existing registers. The size of the bank is automatically accumulated as
90 * registers are added.
92 * The base(), size() and name() methods can be used to access each of those
93 * read only properties of the RegisterBank instance.
95 * While the RegisterBank itself doesn't have any data in it directly and so
96 * has no endianness, it's very likely all the registers within it will have
97 * the same endinanness. The bank itself therefore has a default endianness
98 * which, unless specified otherwise, will be passed on to the register types
99 * within it. The RegisterBank class is templated on its endianness. There are
100 * RegisterBankLE and RegisterBankBE aliases to make it a little easier to
101 * refer to one or the other version.
104 * == Register interface ==
106 * Every register in a RegisterBank needs to inherit, directly or indirectly,
107 * from the RegisterBase class. Each register must have a name (for debugging),
108 * and a well defined size. The following methods define the interface the
109 * register bank uses to access the register, and where the register can
110 * implement its special behaviors:
112 * void read(void *buf);
113 * void read(void *buf, off_t offset, size_t bytes);
115 * void write(const void *buf);
116 * void write(const void *buf, off_t offset, size_t bytes);
118 * The single argument versions of these methods completely overwrite the
119 * register's contents with whatever is pointed to by buf.
121 * The version which also takes "offset" and "bytes" arguments reads or writes
122 * only a portion of the register, starting "offset" bytes from the start of
123 * the register, and writing or reading the next "bytes" bytes.
125 * Each register also needs to implement serialize or unserialize methods
126 * which make it accessible to the checkpointing mechanism. If a register
127 * doesn't need to be serialized (for instance if it has a fixed value) then
128 * it still has to implement these methods, but they don't have to actually do
132 * == Basic Register types ==
134 * Some simple register types have been defined which handle basic, common
135 * behaviors found in many devices:
137 * = RegisterRaz and RegisterRao =
139 * RegisterRaz (read as zero) and RegisterRao (read as one) will ignore writes,
140 * and will return all zeroes or ones, respectively, when read. These can have
141 * arbitrary alignment and size, and can be used for, for instance,
142 * unimplemented registers that still need to take up a certain amount of
143 * space, or for gaps between registers which still need to handle accesses
144 * even though they don't do anything or hold any data.
146 * For instance, a device might have several regions of registers which are
147 * aligned on different boundaries, but which might not take up all of the
148 * space in each region. The extra space can be filled with a RegisterRaz or
149 * RegisterRao, making it possible to implement all the registers as a single
152 * If you need a register with a different fill pattern, you can subclass the
153 * RegisterRoFill type and implement its "fill" method. This should behave
154 * like the three argument form of the read() method, described above.
156 * = RegisterBuf and RegisterLBuf =
158 * These two types act like inert blobs of storage. They don't have any
159 * special behavior and can have any arbitrary size like the RegisterRao and
160 * RegisterRaz types above, but these registers actually store what's written
163 * The RegisterBuf type acts as an interface to a buffer stored elsewhere. That
164 * makes it possible to, for instance, alias the same buffer to different parts
165 * of the register space, or to expose some other object which needs to exist
166 * outside of the register bank for some reason.
168 * The RegisterLBuf does the same thing, except it uses a local buffer it
169 * manages. That makes it a little easier to work with if you don't need the
170 * flexibility of the RegisterBuf type.
173 * == Typed Registers ==
175 * The Register template class is for more complex registers with side effects,
176 * and/or which hold structured data. The template arguments define what type
177 * the register should hold, and also its endianness.
179 * = Access handlers =
181 * Instead of subclassing the Register<Data> type and redefining its read/write
182 * methods, reads and writes are implemented using replaceable handlers with
185 * Data read(Register<Data> ®);
186 * Data partialRead(Register<Data> ®, int first, int last);
187 * void write(Register<Data> ®, const Data &value);
188 * void partialWrite(Register<Data> ®, const Data &value,
189 * int first, int last);
191 * The "partial" version of these handlers take "first" and "last" arguments
192 * which specify what bits of the register to modify. They should be
193 * interpreted like the same arguments in base/bitfield.hh. The endianness
194 * of the register will have already been dealt with by the time the handler
197 * The read and partialRead handlers should generate whatever value reading the
198 * register should return, based on (or not based on) the state of "reg". The
199 * partial handler should keep the bits it returns in place. For example, if
200 * bits 15-8 are read from a 16 bit register with the value 0x1234, it should
201 * return 0x1200, not 0x0012.
203 * The write and partialWrite handlers work the same way, except in they write
204 * instead of read. They are responsible for updating the value in reg in
205 * whatever way and to whatever value is appropriate, based on
206 * (or not based on) the value of "value" and the state of "reg".
208 * The default implementations of the read and write handlers simply return or
209 * update the value stored in reg. The default partial read calls the read
210 * handler (which may not be the default), and trims down the data as required.
211 * The default partial write handler calls the read handler (which may not be
212 * the default), updates the value as requested, and then calls the write
213 * handler (which may not be the default).
215 * Overriding the partial read or write methods might be necessary if reads or
216 * writes have side effects which should affect only the part of the register
217 * read or written. For instance, there might be some status bits which will
218 * be cleared when accessed. Only the bits which were actually accessed should
219 * be affected, even if they're grouped together logically with the other bits
220 * in a single register.
222 * To set your own handlers, you can use the "reader", "writer",
223 * "partialReader", and "partialWriter" methods. Each of these takes a single
224 * callable argument (lambda, functor, function pointer, etc.) which will
225 * replace the current corresponding handler.
227 * These methods all return a reference to the current Register so that they
228 * can be strung together without having to respecify what object you're
229 * modifying over and over again.
231 * There are also versions of these which will set up methods on some object as
232 * the handlers. These take a pointer to whatever object will handle the call,
233 * and a member function pointer to the method that will actually implement
234 * the handler. This can be used if, for instance, the registers are all
235 * members of a RegisterBank subclass, and need to call methods on their
236 * parent class to actually implement the behavior. These methods must have
237 * the same signature as above, with the exception that they are methods and
238 * not bare functions.
240 * When updating the register's value in custom write or partialWrite handlers,
241 * be sure to use the "update" method which will honor read only bits. There
242 * is an alternative form of update which also takes a custom bitmask, if you
243 * need to update bits other than the normally writeable ones.
247 * Often registers have bits which are fixed and not affected by writes. To
248 * specify which bits are writeable, use the "writeable" method which takes a
249 * single argument the same type as the type of the register. It should hold a
250 * bitmask where a 1 bit can be written, and a 0 cannot. Calling writeable with
251 * no arguments will return the current bitmask.
253 * A shorthand "readonly" method marks all bits as read only.
255 * Both methods return a reference to the current Register so they can be
256 * strung together into a sequence when configuring it.
258 * = Underlying data and serialization =
260 * The "get" method returns a reference to the underlying storage inside the
261 * register. That can be used to manually update the entire register, even bits
262 * which are normally read only, or for structured data, to access members of
263 * the underlying data type.
265 * For instance, if the register holds a BitUnion, you could use the get()
266 * method to access the bitfields within it:
268 * reg.get().bitfieldA = reg.get().bitfieldB;
270 * The serialize and unserialize methods for these types will pass through the
271 * underlying data within the register. For instance, when serializing a
272 * Register<Foo>, the value in the checkpoint will be the same as if you had
273 * serialized a Foo directly, with the value stored in the register.
277 * Some convenient aliases have been defined for frequently used versions of
278 * the Register class. These are
280 * Register(8|16|32|64)(LE|BE|)
282 * Where the underlying type of the register is a uint8_t, uint16_t, etc, and
283 * the endianness is little endian, big endian, or whatever the default is for
287 // Common bases to make it easier to identify both endiannesses at once.
288 class RegisterBankBase
291 class RegisterBaseBase {};
294 template <ByteOrder BankByteOrder>
295 class RegisterBank : public RegisterBankBase
298 // Static helper methods for implementing register types.
299 template <typename Data>
300 static constexpr Data
301 readWithMask(const Data &value, const Data &bitmask)
303 return value & bitmask;
306 template <typename Data>
307 static constexpr Data
308 writeWithMask(const Data &old, const Data &value, const Data &bitmask)
311 old, (Data)~bitmask) | readWithMask(value, bitmask);
314 class RegisterBase : public RegisterBankBase::RegisterBaseBase
317 const std::string _name;
321 constexpr RegisterBase(const std::string &new_name, size_t new_size) :
322 _name(new_name), _size(new_size)
324 virtual ~RegisterBase() {}
326 // Read the register's name.
327 virtual const std::string &name() const { return _name; }
329 // Read the register's size in bytes.
330 size_t size() const { return _size; }
332 // Perform a read on the register.
333 virtual void read(void *buf) = 0;
334 virtual void read(void *buf, off_t offset, size_t bytes) = 0;
336 // Perform a write on the register.
337 virtual void write(const void *buf) = 0;
338 virtual void write(const void *buf, off_t offset, size_t bytes) = 0;
340 // Methods for implementing serialization for checkpoints.
341 virtual void serialize(std::ostream &os) const = 0;
342 virtual bool unserialize(const std::string &s) = 0;
345 // Filler registers which return a fixed pattern.
346 class RegisterRoFill : public RegisterBase
349 constexpr RegisterRoFill(
350 const std::string &new_name, size_t new_size) :
351 RegisterBase(new_name, new_size)
354 virtual void fill(void *buf, off_t offset, size_t bytes) = 0;
358 void write(const void *buf) override {}
359 void write(const void *buf, off_t offset, size_t bytes) override {}
361 // Use fill() to handle reads.
362 void read(void *buf) override { fill(buf, 0, this->size()); }
364 read(void *buf, off_t offset, size_t bytes) override
366 fill(buf, offset, bytes);
369 void serialize(std::ostream &os) const override {}
370 bool unserialize(const std::string &s) override { return true; }
373 // Register which reads as all zeroes.
374 class RegisterRaz : public RegisterRoFill
378 fill(void *buf, off_t offset, size_t bytes) override
384 RegisterRaz(const std::string &new_name, size_t new_size) :
385 RegisterRoFill(new_name, new_size)
389 // Register which reads as all ones.
390 class RegisterRao : public RegisterRoFill
394 fill(void *buf, off_t offset, size_t bytes) override
396 memset(buf, 0xff, bytes);
400 RegisterRao(const std::string &new_name, size_t new_size) :
401 RegisterRoFill(new_name, new_size)
405 // Register which acts as a simple buffer.
406 class RegisterBuf : public RegisterBase
409 void *_ptr = nullptr;
412 RegisterBuf(const std::string &new_name, void *ptr, size_t bytes) :
413 RegisterBase(new_name, bytes), _ptr(ptr)
416 void write(const void *buf) override { write(buf, 0, this->size()); }
418 write(const void *buf, off_t offset, size_t bytes) override
420 assert(offset + bytes <= this->size());
421 memcpy((uint8_t *)_ptr + offset, buf, bytes);
424 void read(void *buf) override { read(buf, 0, this->size()); }
426 read(void *buf, off_t offset, size_t bytes) override
428 assert(offset + bytes <= this->size());
429 memcpy(buf, (uint8_t *)_ptr + offset, bytes);
432 // The buffer's owner is responsible for serializing it.
433 void serialize(std::ostream &os) const override {}
434 bool unserialize(const std::string &s) override { return true; }
437 // Same as above, but which keeps its storage locally.
438 template <int BufBytes>
439 class RegisterLBuf : public RegisterBuf
442 std::array<uint8_t, BufBytes> buffer;
444 RegisterLBuf(const std::string &new_name) :
445 RegisterBuf(new_name, buffer.data(), BufBytes)
449 serialize(std::ostream &os) const override
452 ShowParam<uint8_t>::show(os, buffer[0]);
453 for (int i = 1; i < BufBytes; i++) {
455 ShowParam<uint8_t>::show(os, buffer[i]);
460 unserialize(const std::string &s) override
462 std::vector<std::string> tokens;
463 std::istringstream is(s);
467 tokens.push_back(token);
469 if (tokens.size() != BufBytes) {
470 warn("Size mismatch unserialing %s, expected %d, got %d",
471 this->name(), BufBytes, tokens.size());
475 for (int i = 0; i < BufBytes; i++) {
476 if (!ParseParam<uint8_t>::parse(tokens[i], buffer[i]))
484 template <typename Data, ByteOrder RegByteOrder=BankByteOrder>
485 class Register : public RegisterBase
488 using This = Register<Data, RegByteOrder>;
491 using ReadFunc = std::function<Data (This ®)>;
492 using PartialReadFunc = std::function<
493 Data (This ®, int first, int last)>;
494 using WriteFunc = std::function<void (This ®, const Data &value)>;
495 using PartialWriteFunc = std::function<
496 void (This ®, const Data &value, int first, int last)>;
500 Data _writeMask = mask(sizeof(Data) * 8);
502 ReadFunc _reader = defaultReader;
503 WriteFunc _writer = defaultWriter;
504 PartialWriteFunc _partialWriter = defaultPartialWriter;
505 PartialReadFunc _partialReader = defaultPartialReader;
508 static Data defaultReader(This ®) { return reg.get(); }
511 defaultPartialReader(This ®, int first, int last)
513 return mbits(reg._reader(reg), first, last);
517 defaultWriter(This ®, const Data &value)
523 defaultPartialWriter(This ®, const Data &value, int first, int last)
525 reg._writer(reg, writeWithMask<Data>(reg._reader(reg), value,
532 switch (RegByteOrder) {
535 case ByteOrder::little:
538 panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
545 switch (RegByteOrder) {
548 case ByteOrder::little:
551 panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
558 * Interface for setting up the register.
561 // Constructor which lets data default initialize itself.
562 constexpr Register(const std::string &new_name) :
563 RegisterBase(new_name, sizeof(Data))
566 // Constructor and move constructor with an initial data value.
567 constexpr Register(const std::string &new_name, const Data &new_data) :
568 RegisterBase(new_name, sizeof(Data)), _data(new_data)
570 constexpr Register(const std::string &new_name,
571 const Data &&new_data) :
572 RegisterBase(new_name, sizeof(Data)), _data(new_data)
575 // Set which bits of the register are writeable.
577 writeable(const Data &new_mask)
579 _writeMask = new_mask;
583 // Set the register as read only.
584 constexpr This &readonly() { return writeable(0); }
586 // Set the callables which handles reads or writes.
587 // The default reader just returns the register value.
588 // The default writer uses the write mask to update the register value.
590 reader(const ReadFunc &new_reader)
592 _reader = new_reader;
595 template <class Parent, class... Args>
597 reader(Parent *parent, Data (Parent::*nr)(Args... args))
599 auto wrapper = [parent, nr](Args&&... args) -> Data {
600 return (parent->*nr)(std::forward<Args>(args)...);
602 return reader(wrapper);
605 writer(const WriteFunc &new_writer)
607 _writer = new_writer;
610 template <class Parent, class... Args>
612 writer(Parent *parent, void (Parent::*nw)(Args... args))
614 auto wrapper = [parent, nw](Args&&... args) {
615 (parent->*nw)(std::forward<Args>(args)...);
617 return writer(wrapper);
620 // Set the callables which handle reads or writes. These may need to
621 // be handled specially if, for instance, accessing bits outside of
622 // the enables would have side effects that shouldn't happen.
624 // The default partial reader just uses the byte enables to mask off
625 // bits that are not being read.
627 // The default partial writer reads the current value of the register,
628 // uses the byte enables to update only the bytes that are changing,
629 // and then writes the result back to the register.
631 partialReader(const PartialReadFunc &new_reader)
633 _partialReader = new_reader;
636 template <class Parent, class... Args>
638 partialReader(Parent *parent, Data (Parent::*nr)(Args... args))
640 auto wrapper = [parent, nr](Args&&... args) -> Data {
641 return (parent->*nr)(std::forward<Args>(args)...);
643 return partialReader(wrapper);
646 partialWriter(const PartialWriteFunc &new_writer)
648 _partialWriter = new_writer;
651 template <class Parent, class... Args>
653 partialWriter(Parent *parent, void (Parent::*nw)(Args... args))
655 auto wrapper = [parent, nw](Args&&... args) {
656 return (parent->*nw)(std::forward<Args>(args)...);
658 return partialWriter(wrapper);
663 * Interface for accessing the register's state, for use by the
664 * register's helper functions and the register bank.
667 const Data &writeable() const { return _writeMask; }
669 // Directly access the underlying data value.
670 const Data &get() const { return _data; }
671 Data &get() { return _data; }
673 // Update data while applying a mask.
675 update(const Data &new_data, const Data &bitmask)
677 _data = writeWithMask(_data, new_data, bitmask);
679 // This version uses the default write mask.
681 update(const Data &new_data)
683 _data = writeWithMask(_data, new_data, _writeMask);
688 * Interface for reading/writing the register, for use by the
692 // Perform a read on the register.
694 read(void *buf) override
696 Data data = htoreg(_reader(*this));
697 memcpy(buf, (uint8_t *)&data, sizeof(data));
701 read(void *buf, off_t offset, size_t bytes) override
703 // Move the region we're reading to be little endian, since that's
704 // what gem5 uses internally in BitUnions, masks, etc.
705 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
706 sizeof(Data) - (offset + bytes) : offset;
708 const int first = (host_off + bytes) * 8 - 1;
709 const int last = host_off * 8;
710 Data data = htoreg(_partialReader(*this, first, last));
712 memcpy(buf, (uint8_t *)&data + offset, bytes);
715 // Perform a write on the register.
717 write(const void *buf) override
720 memcpy((uint8_t *)&data, buf, sizeof(data));
722 _writer(*this, data);
726 write(const void *buf, off_t offset, size_t bytes) override
729 memcpy((uint8_t *)&data + offset, buf, bytes);
733 // Move the region we're reading to be little endian, since that's
734 // what gem5 uses internally in BitUnions, masks, etc.
735 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
736 sizeof(Data) - (offset + bytes) : offset;
738 const int first = (host_off + bytes) * 8 - 1;
739 const int last = host_off * 8;
740 _partialWriter(*this, data, first, last);
743 // Serialize our data using existing mechanisms.
745 serialize(std::ostream &os) const override
747 ShowParam<Data>::show(os, get());
751 unserialize(const std::string &s) override
753 return ParseParam<Data>::parse(s, get());
758 std::map<Addr, std::reference_wrapper<RegisterBase>> _offsetMap;
762 const std::string _name;
766 using Register8 = Register<uint8_t>;
767 using Register8LE = Register<uint8_t, ByteOrder::little>;
768 using Register8BE = Register<uint8_t, ByteOrder::big>;
769 using Register16 = Register<uint16_t>;
770 using Register16LE = Register<uint16_t, ByteOrder::little>;
771 using Register16BE = Register<uint16_t, ByteOrder::big>;
772 using Register32 = Register<uint32_t>;
773 using Register32LE = Register<uint32_t, ByteOrder::little>;
774 using Register32BE = Register<uint32_t, ByteOrder::big>;
775 using Register64 = Register<uint64_t>;
776 using Register64LE = Register<uint64_t, ByteOrder::little>;
777 using Register64BE = Register<uint64_t, ByteOrder::big>;
780 constexpr RegisterBank(const std::string &new_name, Addr new_base) :
781 _base(new_base), _name(new_name)
784 virtual ~RegisterBank() {}
788 std::initializer_list<std::reference_wrapper<RegisterBase>> regs)
790 panic_if(regs.size() == 0, "Adding an empty list of registers to %s?",
792 for (auto ®: regs) {
793 _offsetMap.emplace(_base + _size, reg);
794 _size += reg.get().size();
798 void addRegister(RegisterBase ®) { addRegisters({reg}); }
800 Addr base() const { return _base; }
801 Addr size() const { return _size; }
802 const std::string &name() const { return _name; }
805 read(Addr addr, void *buf, Addr bytes)
807 uint8_t *ptr = (uint8_t *)buf;
808 // Number of bytes we've transferred.
811 panic_if(addr - base() + bytes > size(),
812 "Out of bounds read in register bank %s, address %#x, size %d.",
813 name(), addr, bytes);
815 auto it = _offsetMap.lower_bound(addr);
816 if (it == _offsetMap.end() || it->first > addr)
819 if (it->first < addr) {
820 RegisterBase ® = it->second.get();
821 // Skip at least the beginning of the first register.
823 // Figure out what parts of it we're accessing.
824 const off_t reg_off = addr - it->first;
825 const size_t reg_bytes = std::min(reg.size() - reg_off,
828 // Actually do the access.
829 reg.read(ptr, reg_off, reg_bytes);
833 // Was that everything?
839 RegisterBase ® = it->second.get();
841 const size_t reg_size = reg.size();
842 const size_t remaining = bytes - done;
844 if (remaining == reg_size) {
845 // A complete register read, and then we're done.
846 reg.read(ptr + done);
848 } else if (remaining > reg_size) {
849 // A complete register read, with more to go.
850 reg.read(ptr + done);
854 // Skip the end of the register, and then we're done.
855 reg.read(ptr + done, 0, remaining);
862 write(Addr addr, const void *buf, Addr bytes)
864 const uint8_t *ptr = (const uint8_t *)buf;
865 // Number of bytes we've transferred.
868 panic_if(addr - base() + bytes > size(),
869 "Out of bounds write in register bank %s, address %#x, size %d.",
870 name(), addr, bytes);
872 auto it = _offsetMap.lower_bound(addr);
873 if (it == _offsetMap.end() || it->first > addr)
876 if (it->first < addr) {
877 RegisterBase ® = it->second.get();
878 // Skip at least the beginning of the first register.
880 // Figure out what parts of it we're accessing.
881 const off_t reg_off = addr - it->first;
882 const size_t reg_bytes = std::min(reg.size() - reg_off,
885 // Actually do the access.
886 reg.write(ptr, reg_off, reg_bytes);
890 // Was that everything?
896 RegisterBase ® = it->second.get();
898 const size_t reg_size = reg.size();
899 const size_t remaining = bytes - done;
901 if (remaining == reg_size) {
902 // A complete register write, and then we're done.
903 reg.write(ptr + done);
905 } else if (remaining > reg_size) {
906 // A complete register write, with more to go.
907 reg.write(ptr + done);
911 // Skip the end of the register, and then we're done.
912 reg.write(ptr + done, 0, remaining);
919 using RegisterBankLE = RegisterBank<ByteOrder::little>;
920 using RegisterBankBE = RegisterBank<ByteOrder::big>;
922 // Delegate serialization to the individual RegisterBase subclasses.
924 struct ParseParam<T, std::enable_if_t<std::is_base_of<
925 typename RegisterBankBase::RegisterBaseBase, T>::value>>
928 parse(const std::string &s, T &value)
930 return value.unserialize(s);
935 struct ShowParam<T, std::enable_if_t<std::is_base_of<
936 typename RegisterBankBase::RegisterBaseBase, T>::value>>
939 show(std::ostream &os, const T &value)
945 #endif // __DEV_REG_BANK_HH__