// 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 #include #include #include #include "ap_int.h" namespace hls { struct MAXIAccessRecord { unsigned read_disp; unsigned write_disp; std::list> ReadQ; std::list> WriteQ; std::list> WriteRespQ; }; template 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> 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 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(DstP)[i] = reinterpret_cast(&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