Files
Jungfraujoch/fpga/include/hls_burst_maxi.h

123 lines
3.5 KiB
C++

// 67d7842dbbe25473c3c32b93c0da8047785f30d78e8a024de1b57352245f9689
// Modified by Filip Leonarski (Paul Scherrer Institute
// to allow for multiple parallel bursts to the same pointer
// (via independent HBM channels)
#ifndef X_HLS_BURST_MAXI_SIM_H
#define X_HLS_BURST_MAXI_SIM_H
/*
* This file contains a C++ simulation model of hls::burst_maxi
*/
#ifndef __cplusplus
#error C++ is required to include this header file
#else
#include <list>
#include <map>
#include <iostream>
#include <assert.h>
#include "ap_int.h"
namespace hls {
struct MAXIAccessRecord {
unsigned read_disp;
unsigned write_disp;
std::list<std::pair<size_t, unsigned>> ReadQ;
std::list<std::pair<size_t, unsigned>> WriteQ;
std::list<std::pair<size_t, unsigned>> WriteRespQ;
};
template<typename T>
class burst_maxi {
public:
burst_maxi(T *p) : Ptr(p) {
unsigned bitwidth = sizeof(T) * 8;
assert(bitwidth != 0 && !(bitwidth & (bitwidth - 1)) &&
"Error: bit width of hls::burst_maxi is not poower-of-2.");
// Reset the MAXI access record to this pointer
R.read_disp = 0;
R.write_disp = 0;
R.ReadQ.clear();
R.WriteQ.clear();
R.WriteRespQ.clear();
}
void read_request(size_t offset, unsigned len) {
assert(len > 0);
R.ReadQ.push_back(std::make_pair(offset, len));
std::list<std::pair<size_t, unsigned>> CurrentWriteQ = R.WriteQ;
CurrentWriteQ.insert(CurrentWriteQ.end(),
R.WriteRespQ.begin(), R.WriteRespQ.end());
for (auto Pair : CurrentWriteQ) {
if (overlap(offset, len, Pair.first, Pair.second)) {
std::cerr << "Error: MAXI read request(offset = " << offset << ", len = " << len << ") overlaps with previous write request(offset = " << Pair.first << ", len = " << Pair.second << ")." << std::endl;
abort();
}
}
}
T read() {
assert(!R.ReadQ.empty() && "Error: MAXI read without request.");
auto Pair = R.ReadQ.front();
T V = Ptr[Pair.first + (R.read_disp++)];
if (R.read_disp == Pair.second) {
R.read_disp = 0;
R.ReadQ.pop_front();
}
return V;
}
void write_request(size_t offset, unsigned len) {
assert(len > 0);
for (auto Pair : R.ReadQ) {
if (overlap(offset, len, Pair.first, Pair.second)) {
std::cerr << "Error: MAXI write request(offset = " << offset << ", len = " << len << ") overlaps with previous read request(offset = " << Pair.first << ", len = " << Pair.second << ")." << std::endl;
abort();
}
}
R.WriteQ.push_back(std::make_pair(offset, len));
}
void write(const T &val, ap_int<sizeof(T)> byte_enable_mask = -1) {
assert(!R.WriteQ.empty() && "Error: MAXI write without request.");
auto Pair = R.WriteQ.front();
T *DstP = &Ptr[Pair.first + R.write_disp++];
T Src = val;
for (unsigned i = 0; i < sizeof(T); i++) {
if (byte_enable_mask[i])
reinterpret_cast<char *>(DstP)[i] = reinterpret_cast<char *>(&Src)[i];
}
if (R.write_disp == Pair.second) {
R.write_disp = 0;
R.WriteRespQ.push_back(Pair);
R.WriteQ.pop_front();
}
}
void write_response() {
assert(!R.WriteRespQ.empty() && "Error: bad MAXI write response. Possible: 1) no corresponding write request; 2) some data still not written.");
R.WriteRespQ.pop_front();
}
private:
T *Ptr;
MAXIAccessRecord R;
bool overlap(size_t a, unsigned a_len, size_t b, unsigned b_len) {
return a <= b ? a + a_len > b : b + b_len > a;
}
};
} // namespace hls
#endif // __cplusplus
#endif // X_HLS_STREAM_SIM_H