28#ifndef __DEV_REG_BANK_HH__
29#define __DEV_REG_BANK_HH__
37#include <initializer_list>
331template <ByteOrder BankByteOrder>
336 template <
typename Data>
337 static constexpr Data
340 return value & bitmask;
343 template <
typename Data>
344 static constexpr Data
364 virtual const std::string &
name()
const {
return _name; }
370 virtual void read(
void *buf) = 0;
371 virtual void read(
void *buf, off_t
offset,
size_t bytes) = 0;
374 virtual void write(
const void *buf) = 0;
375 virtual void write(
const void *buf, off_t
offset,
size_t bytes) = 0;
390 const std::string &new_name,
size_t new_size) :
394 virtual void fill(
void *buf, off_t
offset,
size_t bytes) = 0;
398 void write(
const void *buf)
override {}
399 void write(
const void *buf, off_t
offset,
size_t bytes)
override {}
439 memset(buf, 0xff, bytes);
455 RegisterBuf(
const std::string &new_name,
void *ptr,
size_t bytes) :
493 assert(
_ptr ==
nullptr);
494 assert(buf !=
nullptr);
500 template <
int BufBytes>
517 for (
int i = 1;
i < BufBytes;
i++) {
527 std::istringstream
is(
s);
531 tokens.push_back(
token);
533 if (tokens.size() != BufBytes) {
534 warn(
"Size mismatch unserialing %s, expected %d, got %d",
535 this->
name(), BufBytes, tokens.size());
539 for (
int i = 0;
i < BufBytes;
i++) {
547 void reset()
override {
buffer = std::array<uint8_t, BufBytes>{}; }
550 template <
typename Data, ByteOrder RegByteOrder=BankByteOrder>
559 Data (
This &
reg,
int first,
int last)>;
562 void (
This &
reg,
const Data &value,
int first,
int last)>;
594 reg._writer(
reg, writeWithMask<Data>(
reg._reader(
reg), value,
601 reg.get() =
reg.initialValue();
607 switch (RegByteOrder) {
610 case ByteOrder::little:
613 panic(
"Unrecognized byte order %d.", (
unsigned)RegByteOrder);
620 switch (RegByteOrder) {
623 case ByteOrder::little:
626 panic(
"Unrecognized byte order %d.", (
unsigned)RegByteOrder);
642 constexpr Register(
const std::string &new_name,
const Data &new_data) :
647 const Data &&new_data) :
672 template <
class Parent,
class... Args>
674 reader(Parent *parent, Data (Parent::*nr)(Args... args))
676 auto wrapper = [parent, nr](Args&&... args) -> Data {
677 return (parent->*nr)(std::forward<Args>(args)...);
687 template <
class Parent,
class... Args>
689 writer(Parent *parent,
void (Parent::*
nw)(Args... args))
691 auto wrapper = [parent,
nw](Args&&... args) {
692 (parent->*
nw)(std::forward<Args>(args)...);
713 template <
class Parent,
class... Args>
717 auto wrapper = [parent, nr](Args&&... args) -> Data {
718 return (parent->*nr)(std::forward<Args>(args)...);
728 template <
class Parent,
class... Args>
732 auto wrapper = [parent,
nw](Args&&... args) {
733 return (parent->*
nw)(std::forward<Args>(args)...);
748 template <
class Parent,
class... Args>
750 resetter(Parent *parent,
void (Parent::*nr)(Args... args))
752 auto wrapper = [parent, nr](Args&&... args) {
753 return (parent->*nr)(std::forward<Args>(args)...);
779 update(
const Data &new_data,
const Data &bitmask)
801 memcpy(buf, (uint8_t *)&
data,
sizeof(
data));
809 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
812 const int first = (host_off + bytes) * 8 - 1;
813 const int last = host_off * 8;
816 memcpy(buf, (uint8_t *)&
data +
offset, bytes);
824 memcpy((uint8_t *)&
data, buf,
sizeof(
data));
833 memcpy((uint8_t *)&
data +
offset, buf, bytes);
839 const off_t host_off = (RegByteOrder != ByteOrder::little) ?
842 const int first = (host_off + bytes) * 8 - 1;
843 const int last = host_off * 8;
865 std::map<Addr, std::reference_wrapper<RegisterBase>>
_offsetMap;
897 std::optional<RegisterBase *>
reg;
916 "Adding an empty list of registers to %s?",
name());
917 for (
auto &adder: adders) {
921 auto *
reg = adder.reg.value();
922 if (adder.offset && adder.offset.value() !=
offset) {
924 "Expected offset of register %s.%s to be %#x, is %#x.",
929 }
else if (adder.offset) {
930 if (adder.offset.value() !=
offset) {
931 panic(
"Expected current offset of %s to be %#x, is %#x.",
947 uint8_t *ptr = (uint8_t *)buf;
952 "Out of bounds read in register bank %s, address %#x, size %d.",
959 if (it->first <
addr) {
964 const off_t reg_off =
addr - it->first;
965 const size_t reg_bytes = std::min(
reg.size() - reg_off,
969 reg.read(ptr, reg_off, reg_bytes);
981 const size_t reg_size =
reg.size();
982 const size_t remaining = bytes - done;
984 if (remaining == reg_size) {
986 reg.read(ptr + done);
988 }
else if (remaining > reg_size) {
990 reg.read(ptr + done);
995 reg.read(ptr + done, 0, remaining);
1004 const uint8_t *ptr = (
const uint8_t *)buf;
1009 "Out of bounds write in register bank %s, address %#x, size %d.",
1016 if (it->first <
addr) {
1021 const off_t reg_off =
addr - it->first;
1022 const size_t reg_bytes = std::min(
reg.size() - reg_off,
1026 reg.write(ptr, reg_off, reg_bytes);
1038 const size_t reg_size =
reg.size();
1039 const size_t remaining = bytes - done;
1041 if (remaining == reg_size) {
1043 reg.write(ptr + done);
1045 }
else if (remaining > reg_size) {
1047 reg.write(ptr + done);
1052 reg.write(ptr + done, 0, remaining);
1063 it.second.get().reset();
1073 typename RegisterBankBase::RegisterBaseBase, T>>>
1078 return value.unserialize(
s);
1084 typename RegisterBankBase::RegisterBaseBase, T>>>
1089 value.serialize(
os);
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
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)
std::function< Data(This ®, int first, int last)> PartialReadFunc
bool unserialize(const std::string &s) override
static void defaultWriter(This ®, const Data &value)
constexpr Register(const std::string &new_name)
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)
std::function< void(This ®, const Data &value, int first, int last)> PartialWriteFunc
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)
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)
void addRegister(RegisterAdder reg)
void addRegisters(std::initializer_list< RegisterAdder > adders)
constexpr RegisterBank(const std::string &new_name, Addr new_base)
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)
virtual void write(Addr addr, const void *buf, Addr bytes)
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...
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
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)