gem5  v22.1.0.0
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 <sstream>
41 #include <utility>
42 
43 #include "base/bitfield.hh"
44 #include "base/logging.hh"
45 #include "base/types.hh"
46 #include "sim/byteswap.hh"
48 
49 /*
50  * Device models often have contiguous banks of registers which can each
51  * have unique and arbitrary behavior when they are completely or partially
52  * read or written. Historically it's been up to each model to map an access
53  * which covers an arbitrary portion of that register bank down to individual
54  * registers. It must handle cases where registers are only partially accessed,
55  * or where multiple registers are accessed at the same time, or a combination
56  * of both.
57  *
58  *
59  * == RegisterBank ==
60  *
61  * The RegisterBank class(es), defined below, handle that mapping, and let the
62  * device model focus on defining what each of the registers actually do when
63  * read or written. Once it's set up, it has two primary interfaces which
64  * access the registers it contains:
65  *
66  * void read(Addr addr, void *buf, Addr bytes);
67  * void write(Addr addr, const void *buf, Addr bytes);
68  *
69  * These two methods will handle a read or write contained within the register
70  * bank starting at address "addr". The data that will be written or has been
71  * read is pointed to by "buf", and is "bytes" bytes long.
72  *
73  * These methods are virtual, so if you need to implement extra rules, like
74  * for instance that registers can only be accessed one at a time, that
75  * accesses have to be aligned, have to access complete registers, etc, that
76  * can be added in a subclass.
77  *
78  * Additionally, each RegisterBank has a name and a base address which is
79  * passed into the constructor. The meaning of the "base" value can be whatever
80  * makes sense for your device, and is considered the lowest address contained
81  * in the bank. The value could be the offset of this bank of registers within
82  * the device itself, with the device's own offset subtracted out before read
83  * or write are called. It could alternatively be the base address of the
84  * entire device, with the address from accesses passed into read or write
85  * unmodified.
86  *
87  * To add actual registers to the RegisterBank (discussed below), you can use
88  * either the addRegister method which adds a single register, or addRegisters
89  * which adds an initializer list of them all at once. The register will be
90  * appended to the end of the bank as they're added, contiguous to the
91  * existing registers. The size of the bank is automatically accumulated as
92  * registers are added.
93  *
94  * The base(), size() and name() methods can be used to access each of those
95  * read only properties of the RegisterBank instance.
96  *
97  * While the RegisterBank itself doesn't have any data in it directly and so
98  * has no endianness, it's very likely all the registers within it will have
99  * the same endinanness. The bank itself therefore has a default endianness
100  * which, unless specified otherwise, will be passed on to the register types
101  * within it. The RegisterBank class is templated on its endianness. There are
102  * RegisterBankLE and RegisterBankBE aliases to make it a little easier to
103  * refer to one or the other version.
104  *
105  *
106  * == Register interface ==
107  *
108  * Every register in a RegisterBank needs to inherit, directly or indirectly,
109  * from the RegisterBase class. Each register must have a name (for debugging),
110  * and a well defined size. The following methods define the interface the
111  * register bank uses to access the register, and where the register can
112  * implement its special behaviors:
113  *
114  * void read(void *buf);
115  * void read(void *buf, off_t offset, size_t bytes);
116  *
117  * void write(const void *buf);
118  * void write(const void *buf, off_t offset, size_t bytes);
119  *
120  * The single argument versions of these methods completely overwrite the
121  * register's contents with whatever is pointed to by buf.
122  *
123  * The version which also takes "offset" and "bytes" arguments reads or writes
124  * only a portion of the register, starting "offset" bytes from the start of
125  * the register, and writing or reading the next "bytes" bytes.
126  *
127  * Each register also needs to implement serialize or unserialize methods
128  * which make it accessible to the checkpointing mechanism. If a register
129  * doesn't need to be serialized (for instance if it has a fixed value) then
130  * it still has to implement these methods, but they don't have to actually do
131  * anything.
132  *
133  *
134  * == Basic Register types ==
135  *
136  * Some simple register types have been defined which handle basic, common
137  * behaviors found in many devices:
138  *
139  * = RegisterRaz and RegisterRao =
140  *
141  * RegisterRaz (read as zero) and RegisterRao (read as one) will ignore writes,
142  * and will return all zeroes or ones, respectively, when read. These can have
143  * arbitrary alignment and size, and can be used for, for instance,
144  * unimplemented registers that still need to take up a certain amount of
145  * space, or for gaps between registers which still need to handle accesses
146  * even though they don't do anything or hold any data.
147  *
148  * For instance, a device might have several regions of registers which are
149  * aligned on different boundaries, but which might not take up all of the
150  * space in each region. The extra space can be filled with a RegisterRaz or
151  * RegisterRao, making it possible to implement all the registers as a single
152  * bank.
153  *
154  * If you need a register with a different fill pattern, you can subclass the
155  * RegisterRoFill type and implement its "fill" method. This should behave
156  * like the three argument form of the read() method, described above.
157  *
158  * = RegisterBuf and RegisterLBuf =
159  *
160  * These two types act like inert blobs of storage. They don't have any
161  * special behavior and can have any arbitrary size like the RegisterRao and
162  * RegisterRaz types above, but these registers actually store what's written
163  * to them.
164  *
165  * The RegisterBuf type acts as an interface to a buffer stored elsewhere. That
166  * makes it possible to, for instance, alias the same buffer to different parts
167  * of the register space, or to expose some other object which needs to exist
168  * outside of the register bank for some reason.
169  *
170  * The RegisterLBuf does the same thing, except it uses a local buffer it
171  * manages. That makes it a little easier to work with if you don't need the
172  * flexibility of the RegisterBuf type.
173  *
174  *
175  * == Typed Registers ==
176  *
177  * The Register template class is for more complex registers with side effects,
178  * and/or which hold structured data. The template arguments define what type
179  * the register should hold, and also its endianness.
180  *
181  * = Access handlers =
182  *
183  * Instead of subclassing the Register<Data> type and redefining its read/write
184  * methods, reads and writes are implemented using replaceable handlers with
185  * these signatures:
186  *
187  * Data read(Register<Data> &reg);
188  * Data partialRead(Register<Data> &reg, int first, int last);
189  * void write(Register<Data> &reg, const Data &value);
190  * void partialWrite(Register<Data> &reg, const Data &value,
191  * int first, int last);
192  *
193  * The "partial" version of these handlers take "first" and "last" arguments
194  * which specify what bits of the register to modify. They should be
195  * interpreted like the same arguments in base/bitfield.hh. The endianness
196  * of the register will have already been dealt with by the time the handler
197  * is called.
198  *
199  * The read and partialRead handlers should generate whatever value reading the
200  * register should return, based on (or not based on) the state of "reg". The
201  * partial handler should keep the bits it returns in place. For example, if
202  * bits 15-8 are read from a 16 bit register with the value 0x1234, it should
203  * return 0x1200, not 0x0012.
204  *
205  * The write and partialWrite handlers work the same way, except in they write
206  * instead of read. They are responsible for updating the value in reg in
207  * whatever way and to whatever value is appropriate, based on
208  * (or not based on) the value of "value" and the state of "reg".
209  *
210  * The default implementations of the read and write handlers simply return or
211  * update the value stored in reg. The default partial read calls the read
212  * handler (which may not be the default), and trims down the data as required.
213  * The default partial write handler calls the read handler (which may not be
214  * the default), updates the value as requested, and then calls the write
215  * handler (which may not be the default).
216  *
217  * Overriding the partial read or write methods might be necessary if reads or
218  * writes have side effects which should affect only the part of the register
219  * read or written. For instance, there might be some status bits which will
220  * be cleared when accessed. Only the bits which were actually accessed should
221  * be affected, even if they're grouped together logically with the other bits
222  * in a single register.
223  *
224  * To set your own handlers, you can use the "reader", "writer",
225  * "partialReader", and "partialWriter" methods. Each of these takes a single
226  * callable argument (lambda, functor, function pointer, etc.) which will
227  * replace the current corresponding handler.
228  *
229  * These methods all return a reference to the current Register so that they
230  * can be strung together without having to respecify what object you're
231  * modifying over and over again.
232  *
233  * There are also versions of these which will set up methods on some object as
234  * the handlers. These take a pointer to whatever object will handle the call,
235  * and a member function pointer to the method that will actually implement
236  * the handler. This can be used if, for instance, the registers are all
237  * members of a RegisterBank subclass, and need to call methods on their
238  * parent class to actually implement the behavior. These methods must have
239  * the same signature as above, with the exception that they are methods and
240  * not bare functions.
241  *
242  * When updating the register's value in custom write or partialWrite handlers,
243  * be sure to use the "update" method which will honor read only bits. There
244  * is an alternative form of update which also takes a custom bitmask, if you
245  * need to update bits other than the normally writeable ones.
246  *
247  * = Read only bits =
248  *
249  * Often registers have bits which are fixed and not affected by writes. To
250  * specify which bits are writeable, use the "writeable" method which takes a
251  * single argument the same type as the type of the register. It should hold a
252  * bitmask where a 1 bit can be written, and a 0 cannot. Calling writeable with
253  * no arguments will return the current bitmask.
254  *
255  * A shorthand "readonly" method marks all bits as read only.
256  *
257  * Both methods return a reference to the current Register so they can be
258  * strung together into a sequence when configuring it.
259  *
260  * = Underlying data and serialization =
261  *
262  * The "get" method returns a reference to the underlying storage inside the
263  * register. That can be used to manually update the entire register, even bits
264  * which are normally read only, or for structured data, to access members of
265  * the underlying data type.
266  *
267  * For instance, if the register holds a BitUnion, you could use the get()
268  * method to access the bitfields within it:
269  *
270  * reg.get().bitfieldA = reg.get().bitfieldB;
271  *
272  * The serialize and unserialize methods for these types will pass through the
273  * underlying data within the register. For instance, when serializing a
274  * Register<Foo>, the value in the checkpoint will be the same as if you had
275  * serialized a Foo directly, with the value stored in the register.
276  *
277  * = Aliases =
278  *
279  * Some convenient aliases have been defined for frequently used versions of
280  * the Register class. These are
281  *
282  * Register(8|16|32|64)(LE|BE|)
283  *
284  * Where the underlying type of the register is a uint8_t, uint16_t, etc, and
285  * the endianness is little endian, big endian, or whatever the default is for
286  * the RegisterBank.
287  */
288 
289 namespace gem5
290 {
291 
292 // Common bases to make it easier to identify both endiannesses at once.
294 {
295  public:
297 };
298 
299 template <ByteOrder BankByteOrder>
301 {
302  public:
303  // Static helper methods for implementing register types.
304  template <typename Data>
305  static constexpr Data
306  readWithMask(const Data &value, const Data &bitmask)
307  {
308  return value & bitmask;
309  }
310 
311  template <typename Data>
312  static constexpr Data
313  writeWithMask(const Data &old, const Data &value, const Data &bitmask)
314  {
315  return readWithMask(
316  old, (Data)~bitmask) | readWithMask(value, bitmask);
317  }
318 
320  {
321  protected:
322  const std::string _name;
323  size_t _size = 0;
324 
325  public:
326  constexpr RegisterBase(const std::string &new_name, size_t new_size) :
327  _name(new_name), _size(new_size)
328  {}
329  virtual ~RegisterBase() {}
330 
331  // Read the register's name.
332  virtual const std::string &name() const { return _name; }
333 
334  // Read the register's size in bytes.
335  size_t size() const { return _size; }
336 
337  // Perform a read on the register.
338  virtual void read(void *buf) = 0;
339  virtual void read(void *buf, off_t offset, size_t bytes) = 0;
340 
341  // Perform a write on the register.
342  virtual void write(const void *buf) = 0;
343  virtual void write(const void *buf, off_t offset, size_t bytes) = 0;
344 
345  // Methods for implementing serialization for checkpoints.
346  virtual void serialize(std::ostream &os) const = 0;
347  virtual bool unserialize(const std::string &s) = 0;
348  };
349 
350  // Filler registers which return a fixed pattern.
352  {
353  protected:
354  constexpr RegisterRoFill(
355  const std::string &new_name, size_t new_size) :
356  RegisterBase(new_name, new_size)
357  {}
358 
359  virtual void fill(void *buf, off_t offset, size_t bytes) = 0;
360 
361  public:
362  // Ignore writes.
363  void write(const void *buf) override {}
364  void write(const void *buf, off_t offset, size_t bytes) override {}
365 
366  // Use fill() to handle reads.
367  void read(void *buf) override { fill(buf, 0, this->size()); }
368  void
369  read(void *buf, off_t offset, size_t bytes) override
370  {
371  fill(buf, offset, bytes);
372  }
373 
374  void serialize(std::ostream &os) const override {}
375  bool unserialize(const std::string &s) override { return true; }
376  };
377 
378  // Register which reads as all zeroes.
380  {
381  protected:
382  void
383  fill(void *buf, off_t offset, size_t bytes) override
384  {
385  bzero(buf, bytes);
386  }
387 
388  public:
389  RegisterRaz(const std::string &new_name, size_t new_size) :
390  RegisterRoFill(new_name, new_size)
391  {}
392  };
393 
394  // Register which reads as all ones.
396  {
397  protected:
398  void
399  fill(void *buf, off_t offset, size_t bytes) override
400  {
401  memset(buf, 0xff, bytes);
402  }
403 
404  public:
405  RegisterRao(const std::string &new_name, size_t new_size) :
406  RegisterRoFill(new_name, new_size)
407  {}
408  };
409 
410  // Register which acts as a simple buffer.
411  class RegisterBuf : public RegisterBase
412  {
413  private:
414  void *_ptr = nullptr;
415 
416  public:
417  RegisterBuf(const std::string &new_name, void *ptr, size_t bytes) :
418  RegisterBase(new_name, bytes), _ptr(ptr)
419  {}
420 
421  void write(const void *buf) override { write(buf, 0, this->size()); }
422  void
423  write(const void *buf, off_t offset, size_t bytes) override
424  {
425  assert(offset + bytes <= this->size());
426  memcpy((uint8_t *)_ptr + offset, buf, bytes);
427  }
428 
429  void read(void *buf) override { read(buf, 0, this->size()); }
430  void
431  read(void *buf, off_t offset, size_t bytes) override
432  {
433  assert(offset + bytes <= this->size());
434  memcpy(buf, (uint8_t *)_ptr + offset, bytes);
435  }
436 
437  // The buffer's owner is responsible for serializing it.
438  void serialize(std::ostream &os) const override {}
439  bool unserialize(const std::string &s) override { return true; }
440 
441  protected:
448  void
449  setBuffer(void *buf)
450  {
451  assert(_ptr == nullptr);
452  assert(buf != nullptr);
453  _ptr = buf;
454  }
455  };
456 
457  // Same as above, but which keeps its storage locally.
458  template <int BufBytes>
459  class RegisterLBuf : public RegisterBuf
460  {
461  public:
462  std::array<uint8_t, BufBytes> buffer;
463 
464  RegisterLBuf(const std::string &new_name) :
465  RegisterBuf(new_name, nullptr, BufBytes)
466  {
467  this->setBuffer(buffer.data());
468  }
469 
470  void
471  serialize(std::ostream &os) const override
472  {
473  if (BufBytes)
475  for (int i = 1; i < BufBytes; i++) {
476  os << " ";
478  }
479  }
480 
481  bool
482  unserialize(const std::string &s) override
483  {
485  std::istringstream is(s);
486 
487  std::string token;
488  while (is >> token)
489  tokens.push_back(token);
490 
491  if (tokens.size() != BufBytes) {
492  warn("Size mismatch unserialing %s, expected %d, got %d",
493  this->name(), BufBytes, tokens.size());
494  return false;
495  }
496 
497  for (int i = 0; i < BufBytes; i++) {
498  if (!ParseParam<uint8_t>::parse(tokens[i], buffer[i]))
499  return false;
500  }
501 
502  return true;
503  }
504  };
505 
506  template <typename Data, ByteOrder RegByteOrder=BankByteOrder>
507  class Register : public RegisterBase
508  {
509  protected:
511 
512  public:
513  using ReadFunc = std::function<Data (This &reg)>;
514  using PartialReadFunc = std::function<
515  Data (This &reg, int first, int last)>;
516  using WriteFunc = std::function<void (This &reg, const Data &value)>;
517  using PartialWriteFunc = std::function<
518  void (This &reg, const Data &value, int first, int last)>;
519 
520  private:
521  Data _data = {};
522  Data _writeMask = mask(sizeof(Data) * 8);
523 
528 
529  protected:
530  static Data defaultReader(This &reg) { return reg.get(); }
531 
532  static Data
533  defaultPartialReader(This &reg, int first, int last)
534  {
535  return mbits(reg._reader(reg), first, last);
536  }
537 
538  static void
539  defaultWriter(This &reg, const Data &value)
540  {
541  reg.update(value);
542  }
543 
544  static void
545  defaultPartialWriter(This &reg, const Data &value, int first, int last)
546  {
547  reg._writer(reg, writeWithMask<Data>(reg._reader(reg), value,
548  mask(first, last)));
549  }
550 
551  constexpr Data
552  htoreg(Data data)
553  {
554  switch (RegByteOrder) {
555  case ByteOrder::big:
556  return htobe(data);
557  case ByteOrder::little:
558  return htole(data);
559  default:
560  panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
561  }
562  }
563 
564  constexpr Data
565  regtoh(Data data)
566  {
567  switch (RegByteOrder) {
568  case ByteOrder::big:
569  return betoh(data);
570  case ByteOrder::little:
571  return letoh(data);
572  default:
573  panic("Unrecognized byte order %d.", (unsigned)RegByteOrder);
574  }
575  }
576 
577  public:
578 
579  /*
580  * Interface for setting up the register.
581  */
582 
583  // Constructor which lets data default initialize itself.
584  constexpr Register(const std::string &new_name) :
585  RegisterBase(new_name, sizeof(Data))
586  {}
587 
588  // Constructor and move constructor with an initial data value.
589  constexpr Register(const std::string &new_name, const Data &new_data) :
590  RegisterBase(new_name, sizeof(Data)), _data(new_data)
591  {}
592  constexpr Register(const std::string &new_name,
593  const Data &&new_data) :
594  RegisterBase(new_name, sizeof(Data)), _data(new_data)
595  {}
596 
597  // Set which bits of the register are writeable.
598  constexpr This &
599  writeable(const Data &new_mask)
600  {
601  _writeMask = new_mask;
602  return *this;
603  }
604 
605  // Set the register as read only.
606  constexpr This &readonly() { return writeable(0); }
607 
608  // Set the callables which handles reads or writes.
609  // The default reader just returns the register value.
610  // The default writer uses the write mask to update the register value.
611  constexpr This &
612  reader(const ReadFunc &new_reader)
613  {
614  _reader = new_reader;
615  return *this;
616  }
617  template <class Parent, class... Args>
618  constexpr This &
619  reader(Parent *parent, Data (Parent::*nr)(Args... args))
620  {
621  auto wrapper = [parent, nr](Args&&... args) -> Data {
622  return (parent->*nr)(std::forward<Args>(args)...);
623  };
624  return reader(wrapper);
625  }
626  constexpr This &
627  writer(const WriteFunc &new_writer)
628  {
629  _writer = new_writer;
630  return *this;
631  }
632  template <class Parent, class... Args>
633  constexpr This &
634  writer(Parent *parent, void (Parent::*nw)(Args... args))
635  {
636  auto wrapper = [parent, nw](Args&&... args) {
637  (parent->*nw)(std::forward<Args>(args)...);
638  };
639  return writer(wrapper);
640  }
641 
642  // Set the callables which handle reads or writes. These may need to
643  // be handled specially if, for instance, accessing bits outside of
644  // the enables would have side effects that shouldn't happen.
645  //
646  // The default partial reader just uses the byte enables to mask off
647  // bits that are not being read.
648  //
649  // The default partial writer reads the current value of the register,
650  // uses the byte enables to update only the bytes that are changing,
651  // and then writes the result back to the register.
652  constexpr This &
653  partialReader(const PartialReadFunc &new_reader)
654  {
655  _partialReader = new_reader;
656  return *this;
657  }
658  template <class Parent, class... Args>
659  constexpr This &
660  partialReader(Parent *parent, Data (Parent::*nr)(Args... args))
661  {
662  auto wrapper = [parent, nr](Args&&... args) -> Data {
663  return (parent->*nr)(std::forward<Args>(args)...);
664  };
665  return partialReader(wrapper);
666  }
667  constexpr This &
668  partialWriter(const PartialWriteFunc &new_writer)
669  {
670  _partialWriter = new_writer;
671  return *this;
672  }
673  template <class Parent, class... Args>
674  constexpr This &
675  partialWriter(Parent *parent, void (Parent::*nw)(Args... args))
676  {
677  auto wrapper = [parent, nw](Args&&... args) {
678  return (parent->*nw)(std::forward<Args>(args)...);
679  };
680  return partialWriter(wrapper);
681  }
682 
683 
684  /*
685  * Interface for accessing the register's state, for use by the
686  * register's helper functions and the register bank.
687  */
688 
689  const Data &writeable() const { return _writeMask; }
690 
691  // Directly access the underlying data value.
692  const Data &get() const { return _data; }
693  Data &get() { return _data; }
694 
695  // Update data while applying a mask.
696  void
697  update(const Data &new_data, const Data &bitmask)
698  {
699  _data = writeWithMask(_data, new_data, bitmask);
700  }
701  // This version uses the default write mask.
702  void
703  update(const Data &new_data)
704  {
705  _data = writeWithMask(_data, new_data, _writeMask);
706  }
707 
708 
709  /*
710  * Interface for reading/writing the register, for use by the
711  * register bank.
712  */
713 
714  // Perform a read on the register.
715  void
716  read(void *buf) override
717  {
718  Data data = htoreg(_reader(*this));
719  memcpy(buf, (uint8_t *)&data, sizeof(data));
720  }
721 
722  void
723  read(void *buf, off_t offset, size_t bytes) override
724  {
725  // Move the region we're reading to be little endian, since that's
726  // what gem5 uses internally in BitUnions, masks, etc.
727  const off_t host_off = (RegByteOrder != ByteOrder::little) ?
728  sizeof(Data) - (offset + bytes) : offset;
729 
730  const int first = (host_off + bytes) * 8 - 1;
731  const int last = host_off * 8;
732  Data data = htoreg(_partialReader(*this, first, last));
733 
734  memcpy(buf, (uint8_t *)&data + offset, bytes);
735  }
736 
737  // Perform a write on the register.
738  void
739  write(const void *buf) override
740  {
741  Data data;
742  memcpy((uint8_t *)&data, buf, sizeof(data));
743  data = regtoh(data);
744  _writer(*this, data);
745  }
746 
747  void
748  write(const void *buf, off_t offset, size_t bytes) override
749  {
750  Data data = {};
751  memcpy((uint8_t *)&data + offset, buf, bytes);
752 
753  data = regtoh(data);
754 
755  // Move the region we're reading to be little endian, since that's
756  // what gem5 uses internally in BitUnions, masks, etc.
757  const off_t host_off = (RegByteOrder != ByteOrder::little) ?
758  sizeof(Data) - (offset + bytes) : offset;
759 
760  const int first = (host_off + bytes) * 8 - 1;
761  const int last = host_off * 8;
762  _partialWriter(*this, data, first, last);
763  }
764 
765  // Serialize our data using existing mechanisms.
766  void
767  serialize(std::ostream &os) const override
768  {
770  }
771 
772  bool
773  unserialize(const std::string &s) override
774  {
775  return ParseParam<Data>::parse(s, get());
776  }
777  };
778 
779  private:
780  std::map<Addr, std::reference_wrapper<RegisterBase>> _offsetMap;
781 
782  Addr _base = 0;
783  Addr _size = 0;
784  const std::string _name;
785 
786  public:
787 
800 
801 
802  constexpr RegisterBank(const std::string &new_name, Addr new_base) :
803  _base(new_base), _name(new_name)
804  {}
805 
806  virtual ~RegisterBank() {}
807 
808  void
810  std::initializer_list<std::reference_wrapper<RegisterBase>> regs)
811  {
812  panic_if(regs.size() == 0, "Adding an empty list of registers to %s?",
813  name());
814  for (auto &reg: regs) {
815  _offsetMap.emplace(_base + _size, reg);
816  _size += reg.get().size();
817  }
818  }
819 
821 
822  Addr base() const { return _base; }
823  Addr size() const { return _size; }
824  const std::string &name() const { return _name; }
825 
826  virtual void
827  read(Addr addr, void *buf, Addr bytes)
828  {
829  uint8_t *ptr = (uint8_t *)buf;
830  // Number of bytes we've transferred.
831  Addr done = 0;
832 
833  panic_if(addr - base() + bytes > size(),
834  "Out of bounds read in register bank %s, address %#x, size %d.",
835  name(), addr, bytes);
836 
837  auto it = _offsetMap.lower_bound(addr);
838  if (it == _offsetMap.end() || it->first > addr)
839  it--;
840 
841  if (it->first < addr) {
842  RegisterBase &reg = it->second.get();
843  // Skip at least the beginning of the first register.
844 
845  // Figure out what parts of it we're accessing.
846  const off_t reg_off = addr - it->first;
847  const size_t reg_bytes = std::min(reg.size() - reg_off,
848  bytes - done);
849 
850  // Actually do the access.
851  reg.read(ptr, reg_off, reg_bytes);
852  done += reg_bytes;
853  it++;
854 
855  // Was that everything?
856  if (done == bytes)
857  return;
858  }
859 
860  while (true) {
861  RegisterBase &reg = it->second.get();
862 
863  const size_t reg_size = reg.size();
864  const size_t remaining = bytes - done;
865 
866  if (remaining == reg_size) {
867  // A complete register read, and then we're done.
868  reg.read(ptr + done);
869  return;
870  } else if (remaining > reg_size) {
871  // A complete register read, with more to go.
872  reg.read(ptr + done);
873  done += reg_size;
874  it++;
875  } else {
876  // Skip the end of the register, and then we're done.
877  reg.read(ptr + done, 0, remaining);
878  return;
879  }
880  }
881  }
882 
883  virtual void
884  write(Addr addr, const void *buf, Addr bytes)
885  {
886  const uint8_t *ptr = (const uint8_t *)buf;
887  // Number of bytes we've transferred.
888  Addr done = 0;
889 
890  panic_if(addr - base() + bytes > size(),
891  "Out of bounds write in register bank %s, address %#x, size %d.",
892  name(), addr, bytes);
893 
894  auto it = _offsetMap.lower_bound(addr);
895  if (it == _offsetMap.end() || it->first > addr)
896  it--;
897 
898  if (it->first < addr) {
899  RegisterBase &reg = it->second.get();
900  // Skip at least the beginning of the first register.
901 
902  // Figure out what parts of it we're accessing.
903  const off_t reg_off = addr - it->first;
904  const size_t reg_bytes = std::min(reg.size() - reg_off,
905  bytes - done);
906 
907  // Actually do the access.
908  reg.write(ptr, reg_off, reg_bytes);
909  done += reg_bytes;
910  it++;
911 
912  // Was that everything?
913  if (done == bytes)
914  return;
915  }
916 
917  while (true) {
918  RegisterBase &reg = it->second.get();
919 
920  const size_t reg_size = reg.size();
921  const size_t remaining = bytes - done;
922 
923  if (remaining == reg_size) {
924  // A complete register write, and then we're done.
925  reg.write(ptr + done);
926  return;
927  } else if (remaining > reg_size) {
928  // A complete register write, with more to go.
929  reg.write(ptr + done);
930  done += reg_size;
931  it++;
932  } else {
933  // Skip the end of the register, and then we're done.
934  reg.write(ptr + done, 0, remaining);
935  return;
936  }
937  }
938  }
939 };
940 
943 
944 // Delegate serialization to the individual RegisterBase subclasses.
945 template <class T>
946 struct ParseParam<T, std::enable_if_t<std::is_base_of_v<
947  typename RegisterBankBase::RegisterBaseBase, T>>>
948 {
949  static bool
950  parse(const std::string &s, T &value)
951  {
952  return value.unserialize(s);
953  }
954 };
955 
956 template <class T>
957 struct ShowParam<T, std::enable_if_t<std::is_base_of_v<
958  typename RegisterBankBase::RegisterBaseBase, T>>>
959 {
960  static void
961  show(std::ostream &os, const T &value)
962  {
963  value.serialize(os);
964  }
965 };
966 
967 } // namespace gem5
968 
969 #endif // __DEV_REG_BANK_HH__
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
const char data[]
virtual const std::string & name() const
Definition: reg_bank.hh:332
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:326
virtual void read(void *buf, off_t offset, size_t bytes)=0
virtual bool unserialize(const std::string &s)=0
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:423
RegisterBuf(const std::string &new_name, void *ptr, size_t bytes)
Definition: reg_bank.hh:417
bool unserialize(const std::string &s) override
Definition: reg_bank.hh:439
void serialize(std::ostream &os) const override
Definition: reg_bank.hh:438
void write(const void *buf) override
Definition: reg_bank.hh:421
void read(void *buf) override
Definition: reg_bank.hh:429
void read(void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:431
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:449
void serialize(std::ostream &os) const override
Definition: reg_bank.hh:471
bool unserialize(const std::string &s) override
Definition: reg_bank.hh:482
std::array< uint8_t, BufBytes > buffer
Definition: reg_bank.hh:462
RegisterLBuf(const std::string &new_name)
Definition: reg_bank.hh:464
RegisterRao(const std::string &new_name, size_t new_size)
Definition: reg_bank.hh:405
void fill(void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:399
RegisterRaz(const std::string &new_name, size_t new_size)
Definition: reg_bank.hh:389
void fill(void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:383
void read(void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:369
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:354
void write(const void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:364
bool unserialize(const std::string &s) override
Definition: reg_bank.hh:375
void serialize(std::ostream &os) const override
Definition: reg_bank.hh:374
void write(const void *buf) override
Definition: reg_bank.hh:363
void read(void *buf) override
Definition: reg_bank.hh:367
std::function< Data(This &reg, int first, int last)> PartialReadFunc
Definition: reg_bank.hh:515
bool unserialize(const std::string &s) override
Definition: reg_bank.hh:773
static void defaultWriter(This &reg, const Data &value)
Definition: reg_bank.hh:539
constexpr Register(const std::string &new_name)
Definition: reg_bank.hh:584
void write(const void *buf) override
Definition: reg_bank.hh:739
constexpr This & writeable(const Data &new_mask)
Definition: reg_bank.hh:599
constexpr This & reader(Parent *parent, Data(Parent::*nr)(Args... args))
Definition: reg_bank.hh:619
std::function< void(This &reg, const Data &value)> WriteFunc
Definition: reg_bank.hh:516
const Data & get() const
Definition: reg_bank.hh:692
PartialReadFunc _partialReader
Definition: reg_bank.hh:527
constexpr This & partialWriter(const PartialWriteFunc &new_writer)
Definition: reg_bank.hh:668
PartialWriteFunc _partialWriter
Definition: reg_bank.hh:526
constexpr This & partialWriter(Parent *parent, void(Parent::*nw)(Args... args))
Definition: reg_bank.hh:675
const Data & writeable() const
Definition: reg_bank.hh:689
constexpr This & partialReader(const PartialReadFunc &new_reader)
Definition: reg_bank.hh:653
static Data defaultReader(This &reg)
Definition: reg_bank.hh:530
constexpr This & reader(const ReadFunc &new_reader)
Definition: reg_bank.hh:612
void update(const Data &new_data, const Data &bitmask)
Definition: reg_bank.hh:697
std::function< void(This &reg, const Data &value, int first, int last)> PartialWriteFunc
Definition: reg_bank.hh:518
constexpr This & partialReader(Parent *parent, Data(Parent::*nr)(Args... args))
Definition: reg_bank.hh:660
void read(void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:723
static void defaultPartialWriter(This &reg, const Data &value, int first, int last)
Definition: reg_bank.hh:545
void write(const void *buf, off_t offset, size_t bytes) override
Definition: reg_bank.hh:748
void serialize(std::ostream &os) const override
Definition: reg_bank.hh:767
constexpr Data regtoh(Data data)
Definition: reg_bank.hh:565
constexpr Data htoreg(Data data)
Definition: reg_bank.hh:552
constexpr Register(const std::string &new_name, const Data &&new_data)
Definition: reg_bank.hh:592
constexpr Register(const std::string &new_name, const Data &new_data)
Definition: reg_bank.hh:589
constexpr This & writer(const WriteFunc &new_writer)
Definition: reg_bank.hh:627
constexpr This & writer(Parent *parent, void(Parent::*nw)(Args... args))
Definition: reg_bank.hh:634
static Data defaultPartialReader(This &reg, int first, int last)
Definition: reg_bank.hh:533
void read(void *buf) override
Definition: reg_bank.hh:716
void update(const Data &new_data)
Definition: reg_bank.hh:703
Register< Data, RegByteOrder > This
Definition: reg_bank.hh:510
std::function< Data(This &reg)> ReadFunc
Definition: reg_bank.hh:513
constexpr This & readonly()
Definition: reg_bank.hh:606
void addRegisters(std::initializer_list< std::reference_wrapper< RegisterBase >> regs)
Definition: reg_bank.hh:809
static constexpr Data readWithMask(const Data &value, const Data &bitmask)
Definition: reg_bank.hh:306
Addr size() const
Definition: reg_bank.hh:823
constexpr RegisterBank(const std::string &new_name, Addr new_base)
Definition: reg_bank.hh:802
const std::string _name
Definition: reg_bank.hh:784
void addRegister(RegisterBase &reg)
Definition: reg_bank.hh:820
std::map< Addr, std::reference_wrapper< RegisterBase > > _offsetMap
Definition: reg_bank.hh:780
virtual ~RegisterBank()
Definition: reg_bank.hh:806
const std::string & name() const
Definition: reg_bank.hh:824
virtual void read(Addr addr, void *buf, Addr bytes)
Definition: reg_bank.hh:827
Addr base() const
Definition: reg_bank.hh:822
static constexpr Data writeWithMask(const Data &old, const Data &value, const Data &bitmask)
Definition: reg_bank.hh:313
virtual void write(Addr addr, const void *buf, Addr bytes)
Definition: reg_bank.hh:884
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
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define warn(...)
Definition: logging.hh:246
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 24, 22 > is
Bitfield< 1 > s
Definition: pagetable.hh:64
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:2826
static void show(std::ostream &os, const T &value)

Generated on Wed Dec 21 2022 10:22:34 for gem5 by doxygen 1.9.1