76 lines
2.9 KiB
C++
76 lines
2.9 KiB
C++
#ifndef HLSDEV_AP_INT_STUB_H
|
|
#define HLSDEV_AP_INT_STUB_H
|
|
|
|
// ===========================================================================
|
|
// EDITOR-ONLY STAND-IN for Xilinx's <ap_int.h>
|
|
// ---------------------------------------------------------------------------
|
|
// This is NOT the real header. It exists so clangd can resolve ap_uint<N>
|
|
// (and so a simple C-simulation can be built) on a machine with no Xilinx
|
|
// tools installed.
|
|
//
|
|
// It implements only what the EMBS practicals use: unsigned fixed-width
|
|
// values, bit indexing, += / -=, and conversion to/from integers.
|
|
// It supports widths 1..64 only, and has none of the real header's
|
|
// arbitrary-precision, signed, overflow or simulation semantics.
|
|
//
|
|
// Run ./fetch-headers.sh to download the REAL headers from csteach0.
|
|
// They take precedence over this file when present.
|
|
// ===========================================================================
|
|
|
|
#include <cstdint>
|
|
|
|
template <int W>
|
|
class ap_uint {
|
|
static_assert(W > 0 && W <= 64, "hlsdev stub ap_uint supports widths 1..64");
|
|
|
|
public:
|
|
unsigned long long v;
|
|
|
|
static constexpr unsigned long long width_mask() {
|
|
return W >= 64 ? ~0ULL : ((1ULL << W) - 1ULL);
|
|
}
|
|
|
|
ap_uint() : v(0) {}
|
|
ap_uint(int x) : v((unsigned long long)x & width_mask()) {}
|
|
ap_uint(unsigned int x) : v((unsigned long long)x & width_mask()) {}
|
|
ap_uint(unsigned long long x) : v(x & width_mask()) {}
|
|
|
|
// Cross-width conversion, so e.g. ap_uint<4> += ap_uint<1> works.
|
|
// The implicit copy constructor is still preferred for the same width.
|
|
template <int W2>
|
|
ap_uint(const ap_uint<W2>& o) : v((unsigned long long)o & width_mask()) {}
|
|
|
|
operator unsigned long long() const { return v & width_mask(); }
|
|
|
|
ap_uint& operator=(unsigned long long x) { v = x & width_mask(); return *this; }
|
|
|
|
ap_uint& operator+=(const ap_uint& o) { v = (v + o.v) & width_mask(); return *this; }
|
|
ap_uint& operator-=(const ap_uint& o) { v = (v - o.v) & width_mask(); return *this; }
|
|
|
|
// Writing a single bit needs a proxy object, just like the real ap_uint.
|
|
class bit_ref {
|
|
ap_uint& parent;
|
|
int bit;
|
|
|
|
public:
|
|
bit_ref(ap_uint& p, int b) : parent(p), bit(b) {}
|
|
|
|
bit_ref& operator=(bool x) {
|
|
if (x) parent.v |= (1ULL << bit);
|
|
else parent.v &= ~(1ULL << bit);
|
|
return *this;
|
|
}
|
|
operator bool() const { return ((parent.v >> bit) & 1ULL) != 0; }
|
|
|
|
// Convert straight to any ap_uint<N> in a single user-defined
|
|
// conversion, so things like acc += grid[r][c]; resolve cleanly.
|
|
template <int W2>
|
|
operator ap_uint<W2>() const { return ap_uint<W2>((parent.v >> bit) & 1ULL); }
|
|
};
|
|
|
|
bit_ref operator[](int b) { return bit_ref(*this, b); }
|
|
bool operator[](int b) const { return ((v >> b) & 1ULL) != 0; }
|
|
};
|
|
|
|
#endif // HLSDEV_AP_INT_STUB_H
|