6#include <unordered_map>
8#include "sparta/functional/Register.hpp"
29template <
typename RegisterT>
37 static constexpr typename RegisterT::bank_idx_type WARN_MAX_BANK_IDX = 64;
44 static constexpr typename RegisterT::bank_idx_type ERROR_MAX_BANK_IDX = 256;
52 typedef std::unordered_map<Register::group_idx_type, RegisterT *>
RegisterMap;
53 typedef std::vector<RegisterT *> RegisterVector;
77 static_assert(RegisterT::BANK_IDX_DEFAULT==0,
"BANK_IDX_DEFAULT must be 0");
115 typename RegisterT::bank_idx_type bank_num)
117 if(group_num == RegisterT::GROUP_NUM_NONE){
120 if(bank_num >= banks_.size()){
122 << bank_num <<
" group " << group_num <<
" because there are only "
123 << banks_.size() <<
" banks in bank table " << stringize();
125 if(group_num >= banks_[bank_num].size()){
131 return banks_[bank_num][group_num].size();
134 GroupVector& operator[](
typename RegisterT::bank_idx_type bank_idx)
136 return banks_[bank_idx];
139 GroupVector& at(
typename RegisterT::bank_idx_type bank_idx)
141 return banks_.at(bank_idx);
193 const auto &rdef = r->getDefinition();
195 if(rdef.group_num == RegisterT::GROUP_NUM_NONE){
196 if(rdef.bank_membership.size() != 0){
197 throw SpartaException(
"A register has no group number so it cannot be looked up "
198 "through a bank, but but does have bank membership information. This is "
199 "probably a mistake in one of these two fields. Error while adding unbanked "
204 if(rdef.group_num > num_groups_ && rdef.group_num >= 300){
206 std::cerr <<
"WARNING: Register " << r->getLocation()
207 <<
" Group num is very large: " << rdef.group_num
208 <<
". This requires a vector to be allocated of this size and "
209 "probably wastes memory";
212 if(r->isBanked() ==
false){
216 sparta_assert(banks_.size() > 0,
"1 or more banks expected before any addRegister calls");
220 for(
size_t bank_idx = 0; bank_idx < banks_.size(); ++bank_idx){
221 if(canLookupRegister(rdef.group_num, rdef.group_idx, bank_idx)){
222 throw SpartaException(
"A regsiter already exists in bank ") << bank_idx
223 <<
" with group num " << rdef.group_num <<
" and group idx "
224 << rdef.group_idx <<
". Error while adding unbanked register: " << *r;
229 unbanked_regs_.push_back(r);
238 typename RegisterT::bank_idx_type max_bank_idx = 0;
239 for(
typename RegisterT::bank_idx_type bank_idx : rdef.bank_membership){
240 max_bank_idx = std::max(max_bank_idx, bank_idx);
241 if(bank_idx < banks_.size()){
243 if(canLookupRegister(rdef.group_num, rdef.group_idx, bank_idx)){
244 throw SpartaException(
"A regsiter already exists in bank ") << bank_idx
245 <<
" with group num " << rdef.group_num <<
" and group idx "
246 << rdef.group_idx <<
". Error while adding banked register: " << *r;
251 if(max_bank_idx >= WARN_MAX_BANK_IDX){
253 std::cerr <<
"WARNING: Register " << r->getLocation()
254 <<
" bank membership number contains a large value: " << max_bank_idx
255 <<
". This requires a vector to be allocated of this size and "
256 "probably wastes memory";
258 if(max_bank_idx >= ERROR_MAX_BANK_IDX){
261 <<
" bank membership number contains a very large value: " << max_bank_idx
262 <<
". This requires a vector to be allocated of this size and is likely a "
263 "mistake. If not, increase RegisterBankTable::ERROR_MAX_BANK_IDX";
267 for(
auto ubr : unbanked_regs_){
268 if(ubr->getGroupNum() == r->getGroupNum()
269 && ubr->getGroupIdx() == r->getGroupIdx()){
270 throw SpartaException(
"An unbanked regsiter already exists in this set with ")
271 <<
"group num " << r->getGroupNum() <<
" and group idx "
272 << r->getGroupIdx() <<
". Error while adding banked register: " << *r;
281 for(
auto bank_idx : rdef.bank_membership){
287 num_groups_ = std::max(num_groups_, rdef.group_num+1);
292 bool canLookupRegister(
typename RegisterT::group_num_type group_num,
293 typename RegisterT::group_idx_type group_idx,
294 typename RegisterT::bank_idx_type bank_idx)
const noexcept
296 return banks_.size() > bank_idx
297 && banks_[bank_idx].size() > group_num
298 && banks_[bank_idx][group_num].count(group_idx) != 0;
301 RegisterT *lookupRegister(
typename RegisterT::group_num_type group_num,
302 typename RegisterT::group_idx_type group_idx,
303 typename RegisterT::bank_idx_type bank_idx)
305 const auto &rm = banks_[bank_idx][group_num];
306 const auto idx_count = rm.count(group_idx);
310 return (idx_count==1 ? rm.at(group_idx) : nullptr);
313 const RegisterT *lookupRegister(
typename RegisterT::group_num_type group_num,
314 typename RegisterT::group_idx_type group_idx,
315 typename RegisterT::bank_idx_type bank_idx)
const
317 const auto &rm = banks_[bank_idx][group_num];
318 const auto idx_count = rm.count(group_idx);
322 return (idx_count==1 ? rm.at(group_idx) : nullptr);
337 RegisterT *
getRegister(
typename RegisterT::group_num_type group_num,
338 typename RegisterT::group_idx_type group_idx,
339 typename RegisterT::bank_idx_type bank_idx) {
340 if(__builtin_expect(banks_.size() <= bank_idx, 0)){
342 << stringize() <<
" has no bank_idx " << bank_idx;
345 if(__builtin_expect(gv.size() <= group_num, 0)){
347 << stringize() <<
" has no group " << group_num
348 <<
" in bank " << bank_idx;
351 if(__builtin_expect(rm.size() == 0, 0)){
354 << stringize() <<
" has no group " << group_num;
357 if(__builtin_expect(rm.count(group_idx) == 0, 0)){
360 << stringize() <<
" has no register with idx " << group_idx
361 <<
" in group " << group_num;
365 return rm[group_idx];
369 virtual std::string stringize(
bool pretty=
false)
const {
371 std::stringstream ss;
373 ss <<
"<RegisterSet bank table: " << banks_.size() <<
" banks, "
374 << num_regs_ <<
" phy regs>";
382 void dump(std::ostream& out,
bool detailed=
false)
const {
385 const uint32_t GROUP_NAME_WIDTH = 5;
386 const uint32_t GROUP_NUM_WIDTH = 4;
387 const uint32_t GROUP_IDX_WIDTH = 4;
388 const uint32_t COL_WIDTH = 8;
390 typename RegisterT::group_num_type group_num_max = 0;
394 for(
size_t bank_idx = 0; bank_idx != banks_.size(); ++bank_idx){
395 out << std::setw(COL_WIDTH) << bank_idx <<
"|";
398 decltype(group_num_max) num_groups = banks_[bank_idx].size();
399 if(num_groups > group_num_max){
400 group_num_max = num_groups - 1;
407 out <<
" group |index|";
408 for(
size_t bank_idx = 0; bank_idx != banks_.size(); ++bank_idx){
415 for(
typename RegisterT::group_num_type group_num = 0; group_num <= group_num_max; ++group_num) {
418 typename RegisterT::group_idx_type group_idx_max = 0;
419 for(
size_t bank_idx = 0; bank_idx != banks_.size(); ++bank_idx){
420 if(banks_[bank_idx].size() > group_num){
422 const auto & bank = banks_[bank_idx];
423 for (
auto &it : bank[group_num]) {
424 group_idx_max = std::max(group_idx_max, it.first);
430 bool wrote_group =
false;
431 for(
typename RegisterT::group_idx_type group_idx = 0; group_idx <= group_idx_max; ++group_idx) {
434 bool has_reg =
false;
435 std::string group_name;
436 std::vector<std::string> names;
437 for(
size_t bank_idx = 0; bank_idx != banks_.size(); ++bank_idx){
438 if(canLookupRegister(group_num, group_idx, bank_idx)){
439 if(has_reg ==
false){
440 group_name = lookupRegister(group_num, group_idx, bank_idx)->getGroupName();
443 const auto r = lookupRegister(group_num, group_idx, bank_idx);
444 names.push_back(r->getName());
453 writeNChars(out, GROUP_NAME_WIDTH + 1 + GROUP_NUM_WIDTH);
456 out << std::setw(GROUP_NAME_WIDTH) << group_name <<
' '
457 << std::setw(GROUP_NUM_WIDTH) << group_num;
459 out <<
" |" << std::setw(GROUP_IDX_WIDTH) << group_idx <<
" |";
462 for(
const std::string& val : names){
463 out << std::setw(COL_WIDTH) << val <<
"|";
486 while(num_banks > banks_.size()){
487 banks_.push_back({});
489 for(
auto r : unbanked_regs_){
508 const auto rdef = r->getDefinition();
509 while(rdef.group_num >= bank.size()){
514 rm.insert(std::make_pair(rdef.group_idx, r));
536 std::vector<RegisterT *> unbanked_regs_;
542 typename RegisterT::group_num_type num_groups_;
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
Container of register banks as a helper for RegisterSet. Instances of this class will be owned by a s...
RegisterBankTable()
Constructor.
std::unordered_map< Register::group_idx_type, RegisterT * > RegisterMap
Vector of registers owned externally. Available for lookup within a group by Register::Definition::gr...
std::vector< RegisterMap > GroupVector
Vector of RegisterMap's used for lookup by numeric group number of type Register::Definition::group_n...
void addRegister(RegisterT *r)
Adds a register to this table unless it is not a member of a group (See Register::getGroupNum.
void insertRegisterInBank_(RegisterT *r, GroupVector &bank)
Insert a register in a specific bank.
void dump(std::ostream &out, bool detailed=false) const
Dump this register bank table to an out stream. Banks will be columns and group num/id will be rows.
void setMinimumBankIndex(Register::bank_idx_type min_idx)
Sets the minimum bank index for this register set, overriding the default of BANK_IDX_DEFAULT.
RegisterT::group_idx_type getNumGroups() const
Gets the number of register groups added to this table regardless of banks.
uint32_t getGroupSize(typename RegisterT::group_num_type group_num, typename RegisterT::bank_idx_type bank_num)
Gets the number of registers in a group by its group num and bank.
virtual ~RegisterBankTable()=default
Destructor.
std::vector< GroupVector > BankVector
Vector of GroupVectors used for lookup by numeric bank index of type Register::Definition::bank_idx_t...
void extendBanks_(typename RegisterT::bank_idx_type num_banks)
Extends the banks_ vector to contain num_banks entries.
RegisterT * getRegister(typename RegisterT::group_num_type group_num, typename RegisterT::group_idx_type group_idx, typename RegisterT::bank_idx_type bank_idx)
Gets a Register by group number and group index and throws an exception if it cannot be found.
RegisterT::bank_idx_type getNumBanks() const
Gets the total number of banks instantiated (even if they contain have no actual registers accessible...
uint32_t getNumRegisters() const
Returns number of registers in this table. This excludes any registers added having no group number.
uint32_t bank_idx_type
Numeric bank identifier for bank lookup.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Macros for handling exponential backoff.
void writeNChars(std::ostream &out, uint32_t num, char chr=' ')
Insert a number of some character into an ostream.