Skip to content

File banked_memory.h

File List > mem > banked_memory.h

Go to the documentation of this file

#pragma once
#include <simtix/mem.h>

#include <deque>
#include <string>
#include <vector>

namespace simtix {

namespace mem {

// Class: mem::BankedMemory::Impl
//   The implementation class for BankedMemory.
class BankedMemory::Impl {
 public:
  explicit Impl(const std::string &name, const Param &param = kDefaultParam)
      : stat_(name),
        kBanks(param.kBanks),
        kInterleaveGranularity(param.kInterleaveGranularity),
        kLatencyCycles(param.kLatencyCycles),
        name_(name),
        bank_occupied_(param.kBanks, false) {
    SimpleMemory::Param bank_param = {
        .kSizeBytes = param.kSizeBytes / param.kBanks,
        .kLatencyCycles = param.kLatencyCycles,
        .kOutputFifoDepth = param.kOutputFifoDepth,
    };
    for (size_t i = 0; i < param.kBanks; i++) {
      banks_.emplace_back(fmt::format("{}.bank[{}]", name, i), bank_param);
    }
  }
  ~Impl() = default;

 protected:
  struct Stat : stat::Group {
    explicit Stat(const std::string &s)
        : Group(s),
          STAT(bank_conflict, "Number of bank conflicts", "N/A"),
          STAT(bank_available, "Number of available banks when request is sent",
               "N/A"),
          STAT(total_write_requests,
               "Total number of write requests send to banked memory", "N/A"),
          STAT(total_read_requests,
               "Total number of read requests send to banked memory", "N/A"),
          STAT(forwarded_requests, "Number of forwarded requests", "N/A"),
          STAT(total_requests, "Total number of requests send to banked memory",
               "N/A"),
          STAT(bank_utilization, "Bank utilization of banked memory", "N/A") {
      total_requests = total_write_requests + total_read_requests;
      bank_utilization = forwarded_requests / bank_available;
    }
    stat::Integer bank_conflict;
    stat::Integer bank_available;
    stat::Integer total_write_requests;
    stat::Integer total_read_requests;
    stat::Integer forwarded_requests;

    stat::Formula<stat::Integer> total_requests;
    stat::Formula<stat::Real> bank_utilization;
  } stat_;

  inline uint32_t ToBankIndex(uint64_t addr) const {
    return (addr / kInterleaveGranularity) % kBanks;
  }

  inline uint64_t ToBankedAddrOffset(uint64_t addr) const {
    return addr % kInterleaveGranularity;
  }

  inline uint64_t ToBankedAddr(uint64_t addr) const {
    return addr / kBanks / kInterleaveGranularity * kInterleaveGranularity +
           ToBankedAddrOffset(addr);
  }

  // Function: mem::BankedMemory::Impl::ForwardRequest
  //   Forward a memory request to a bank. Return false if the bank is occupied.
  bool ForwardRequest(const Payload &payload, OnResp on_resp, bool is_write);

  const size_t kBanks;
  const uint32_t kInterleaveGranularity;
  const uint32_t kLatencyCycles;

  std::string name_;
  std::deque<SimpleMemory> banks_;
  std::vector<bool> bank_occupied_;

  friend class BankedMemory;
};

}  // namespace mem

}  // namespace simtix