Files
EMBS/Practicals/hlsdev/include-stub/ap_int.h

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