40#ifndef __DEV_REG_BANK_HH__
41#define __DEV_REG_BANK_HH__
49#include <initializer_list>
355template <ByteOrder BankByteOrder>
360 template <
typename Data>
361 static constexpr Data
364 return value & bitmask;
367 template <
typename Data>
368 static constexpr Data
388 virtual const std::string &
name()
const {
return _name; }
394 virtual void read(
void *buf) = 0;
395 virtual void read(
void *buf, off_t
offset,
size_t bytes) = 0;
398 virtual void write(
const void *buf) = 0;
399 virtual void write(
const void *buf, off_t
offset,
size_t bytes) = 0;
414 const std::string &new_name,
size_t new_size) :
418 virtual void fill(
void *buf, off_t
offset,
size_t bytes) = 0;
422 void write(
const void *buf)
override {}
423 void write(
const void *buf, off_t
offset,
size_t bytes)
override {}
463 memset(buf, 0xff, bytes);
479 RegisterBuf(
const std::string &new_name,
void *ptr,
size_t bytes) :
517 assert(
_ptr ==
nullptr);
518 assert(buf !=
nullptr);
524 template <
int BufBytes>
541 for (
int i = 1;
i < BufBytes;
i++) {
551 std::istringstream
is(
s);
555 tokens.push_back(
token);
557 if (tokens.size() != BufBytes) {
558 warn(
"Size mismatch unserialing %s, expected %d, got %d",
559 this->
name(), BufBytes, tokens.size());
563 for (
int i = 0;
i < BufBytes;
i++) {
571 void reset()
override {
buffer = std::array<uint8_t, BufBytes>{}; }
574 template <
typename Data, ByteOrder RegByteOrder=BankByteOrder>
583 Data (
This &
reg,
int first,
int last)>;
586 void (
This &
reg,
const Data &value,
int first,
int last)>;
625 reg.get() =
reg.initialValue();
631 switch (RegByteOrder) {
634 case ByteOrder::little:
637 panic(
"Unrecognized byte order %d.", (
unsigned)RegByteOrder);
644 switch (RegByteOrder) {
647 case ByteOrder::little:
650 panic(
"Unrecognized byte order %d.", (
unsigned)RegByteOrder);
666 constexpr Register(
const std::string &new_name,
const Data &new_data) :
671 const Data &&new_data) :
696 template <
class Parent,
class... Args>
698 reader(Parent *parent, Data (Parent::*nr)(Args... args))
700 auto wrapper = [parent, nr](Args&&... args) -> Data {
701 return (parent->*nr)(std::forward<Args>(args)...);
711 template <
class Parent,
class... Args>
713 writer(Parent *parent,
void (Parent::*
nw)(Args... args))
715 auto wrapper = [parent,
nw](Args&&... args) {
716 (parent->*
nw)(std::forward<Args>(args)...);
737 template <
class Parent,
class... Args>
741 auto wrapper = [parent, nr](Args&&... args) -> Data {
742 return (parent->*nr)(std::forward<Args>(args)...);
752 template <
class Parent,
class... Args>
756 auto wrapper = [parent,
nw](Args&&... args) {
757 return (parent->*
nw)(std::forward<Args>(args)...);
772 template <
class Parent,
class... Args>
774 resetter(Parent *parent,
void (Parent::*nr)(Args... args))
776 auto wrapper = [parent, nr](Args&&... args) {
777 return (parent->*nr)(std::forward<Args>(args)...);
803 update(
const Data &new_data,
const Data &bitmask)
825 memcpy(buf, (uint8_t *)&
data,
sizeof(
data));
833 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
836 const int first = (host_off + bytes) * 8 - 1;
837 const int last = host_off * 8;
840 memcpy(buf, (uint8_t *)&
data +
offset, bytes);
848 memcpy((uint8_t *)&
data, buf,
sizeof(
data));
857 memcpy((uint8_t *)&
data +
offset, buf, bytes);
863 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
866 const int first = (host_off + bytes) * 8 - 1;
867 const int last = host_off * 8;
906 std::map<Addr, std::reference_wrapper<RegisterBase>>
_offsetMap;
940 std::optional<RegisterBase *>
reg;
959 "Adding an empty list of registers to %s?",
name());
960 for (
auto &adder: adders) {
964 auto *
reg = adder.reg.value();
965 if (adder.offset && adder.offset.value() !=
offset) {
967 "Expected offset of register %s.%s to be %#x, is %#x.",
972 }
else if (adder.offset) {
973 if (adder.offset.value() !=
offset) {
974 panic(
"Expected current offset of %s to be %#x, is %#x.",
981 template <
class FillerReg>
986 "Adding an empty list of registers to %s?",
name());
989 std::sort(
vec.begin(),
vec.end(),
990 [] (
const auto& first,
const auto& second) {
991 return first.offset.value() < second.offset.value();
995 for (
auto &adder:
vec) {
996 assert(adder.offset && adder.reg);
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());
1010 owned.push_back(std::make_unique<FillerReg>(hole_range.
to_string(), gap));
1016 auto *
reg = adder.reg.value();
1031 uint8_t *ptr = (uint8_t *)buf;
1036 "Out of bounds read in register bank %s, address %#x, size %d.",
1043 std::ostringstream
ss;
1044 while (done != bytes) {
1046 const Addr reg_off =
addr - it->first;
1048 const Addr reg_bytes = std::min(reg_size, bytes - done);
1050 if (reg_bytes !=
reg.size()) {
1052 ccprintf(
ss,
"Read register %s, byte offset %d, size %d\n",
1053 reg.name(), reg_off, reg_bytes);
1055 reg.read(ptr + done, reg_off, reg_bytes);
1060 reg.read(ptr + done);
1077 const uint8_t *ptr = (
const uint8_t *)buf;
1082 "Out of bounds write in register bank %s, address %#x, size %d.",
1089 std::ostringstream
ss;
1090 while (done != bytes) {
1092 const Addr reg_off =
addr - it->first;
1094 const Addr reg_bytes = std::min(reg_size, bytes - done);
1096 if (reg_bytes !=
reg.size()) {
1098 ccprintf(
ss,
"Write register %s, byte offset %d, size %d\n",
1099 reg.name(), reg_off, reg_size);
1101 reg.write(ptr + done, reg_off, reg_bytes);
1106 reg.write(ptr + done);
1125 it.second.get().reset();
1135 typename RegisterBankBase::RegisterBaseBase, T>>>
1140 return value.unserialize(
s);
1146 typename RegisterBankBase::RegisterBaseBase, T>>>
1151 value.serialize(
os);
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
RegisterAdder(Addr new_offset)
std::optional< Addr > offset
RegisterAdder(RegisterBase &new_reg)
std::optional< RegisterBase * > reg
RegisterAdder(Addr new_offset, RegisterBase &new_reg)
virtual void write(const void *buf)=0
virtual void read(void *buf)=0
constexpr RegisterBase(const std::string &new_name, size_t new_size)
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
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
RegisterBuf(const std::string &new_name, void *ptr, size_t bytes)
bool unserialize(const std::string &s) override
void serialize(std::ostream &os) const override
void write(const void *buf) override
void read(void *buf) override
void read(void *buf, off_t offset, size_t bytes) override
void setBuffer(void *buf)
This method exists so that derived classes that need to initialize their buffers before they can be s...
void serialize(std::ostream &os) const override
bool unserialize(const std::string &s) override
std::array< uint8_t, BufBytes > buffer
RegisterLBuf(const std::string &new_name)
RegisterRao(const std::string &new_name, size_t new_size)
void fill(void *buf, off_t offset, size_t bytes) override
RegisterRaz(const std::string &new_name, size_t new_size)
void fill(void *buf, off_t offset, size_t bytes) override
void read(void *buf, off_t offset, size_t bytes) override
virtual void fill(void *buf, off_t offset, size_t bytes)=0
constexpr RegisterRoFill(const std::string &new_name, size_t new_size)
void write(const void *buf, off_t offset, size_t bytes) override
bool unserialize(const std::string &s) override
void serialize(std::ostream &os) const override
void write(const void *buf) override
void read(void *buf) override
constexpr This & resetter(const ResetFunc &new_resetter)
bool unserialize(const std::string &s) override
static void defaultWriter(This ®, const Data &value)
constexpr Register(const std::string &new_name)
std::function< Data(This ®, int first, int last)> PartialReadFunc
void write(const void *buf) override
std::function< void(This ®, const Data &value)> WriteFunc
constexpr This & writer(Parent *parent, void(Parent::*nw)(Args... args))
PartialReadFunc _partialReader
constexpr This & partialWriter(const PartialWriteFunc &new_writer)
PartialWriteFunc _partialWriter
constexpr This & reader(Parent *parent, Data(Parent::*nr)(Args... args))
constexpr This & readonly()
static Data defaultReader(This ®)
constexpr This & writer(const WriteFunc &new_writer)
void update(const Data &new_data, const Data &bitmask)
constexpr This & reader(const ReadFunc &new_reader)
void read(void *buf, off_t offset, size_t bytes) override
static void defaultPartialWriter(This ®, const Data &value, int first, int last)
void write(const void *buf, off_t offset, size_t bytes) override
void serialize(std::ostream &os) const override
constexpr Data regtoh(Data data)
const Data & writeable() const
constexpr Data htoreg(Data data)
const Data & initialValue() const
constexpr Register(const std::string &new_name, const Data &&new_data)
constexpr This & partialWriter(Parent *parent, void(Parent::*nw)(Args... args))
constexpr Register(const std::string &new_name, const Data &new_data)
constexpr This & partialReader(const PartialReadFunc &new_reader)
std::function< void(This ®, const Data &value, int first, int last)> PartialWriteFunc
constexpr This & partialReader(Parent *parent, Data(Parent::*nr)(Args... args))
static Data defaultPartialReader(This ®, int first, int last)
std::function< void(This ®)> ResetFunc
void read(void *buf) override
constexpr This & writeable(const Data &new_mask)
void update(const Data &new_data)
constexpr This & resetter(Parent *parent, void(Parent::*nr)(Args... args))
Register< Data, RegByteOrder > This
std::function< Data(This ®)> ReadFunc
static void defaultResetter(This ®)
const std::string & name() const
static constexpr Data readWithMask(const Data &value, const Data &bitmask)
const ::gem5::debug::SimpleFlag * _debug_flag
void addRegister(RegisterAdder reg)
std::vector< std::unique_ptr< RegisterBase > > owned
void addRegisters(std::initializer_list< RegisterAdder > adders)
constexpr RegisterBank(const std::string &new_name, Addr new_base)
void setDebugFlag(const ::gem5::debug::SimpleFlag &flag)
std::map< Addr, std::reference_wrapper< RegisterBase > > _offsetMap
virtual void read(Addr addr, void *buf, Addr bytes)
static constexpr Data writeWithMask(const Data &old, const Data &value, const Data &bitmask)
void addRegistersAt(std::initializer_list< RegisterAdder > adders)
virtual void write(Addr addr, const void *buf, Addr bytes)
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.
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.
#define panic(...)
This implements a cprintf based panic() function.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Logger * getDebugLogger()
Get the current global debug logger.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Tick curTick()
The universal simulation clock.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
void ccprintf(cp::Print &print)
Overload hash function for BasicBlockRange type.
static bool parse(const std::string &s, T &value)
static void show(std::ostream &os, const T &value)
static void show(std::ostream &os, const T &value)