// Header for Chisel emulator module // defines the mod_t class as well as bit operation functions #ifndef __IS_EMULATOR_MOD__ #define __IS_EMULATOR_MOD__ #pragma GCC diagnostic push #ifdef __clang__ #pragma GCC diagnostic ignored "-Wunknown-pragmas" #else #pragma GCC diagnostic ignored "-Wpragmas" #endif // __clang__ #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wparentheses" #pragma GCC diagnostic ignored "-Wreturn-type" #pragma GCC diagnostic ignored "-Wchar-subscripts" #pragma GCC diagnostic ignored "-Wtype-limits" #pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wreorder" #pragma GCC diagnostic ignored "-Wsometimes-uninitialized" #pragma GCC diagnostic ignored "-pedantic" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef uint64_t val_t; typedef int64_t sval_t; typedef uint32_t half_val_t; #if defined(__GNUC__) && defined(__SIZEOF_INT128__) #define __HAVE_DUB_VAL_T__ typedef unsigned __int128 dub_val_t; #endif union flo2int_t { float f; val_t i; }; inline float toFloat (val_t x) { flo2int_t f2i; f2i.i = x; return f2i.f; } inline val_t fromFloat (float x) { flo2int_t f2i; f2i.f = x; return f2i.i; } union dbl2int_t { double f; val_t i; }; inline double toDouble (val_t x) { dbl2int_t f2i; f2i.i = x; return f2i.f; } inline val_t fromDouble (double x) { dbl2int_t f2i; f2i.f = x; return f2i.i; } #define TERNARY(c, t, f) ((f) ^ (((f) ^ (t)) & -(c))) #if defined(__GNUC__) && defined(__x86_64__) #define TERNARY_1(c, t, f) ({ \ val_t __res; \ if (!__builtin_constant_p(c)) { \ __res = (f); \ val_t __t = (t); \ uint8_t __c = (c); \ asm ("testb $1, %1; cmovne %2, %0" : "+r"(__res) : "rm"(__c), "rm"(__t) : "cc"); \ } else __res = TERNARY(c, t, f); \ __res; }) #else #define TERNARY_1(c, t, f) TERNARY(c, t, f) #endif #define MASK(v, c) ((v) & -(val_t)(c)) #ifndef MIN #define MIN(a, b) TERNARY((a) < (b), (a), (b)) #endif #ifndef MAX #define MAX(a, b) TERNARY((a) > (b), (a), (b)) #endif #define CLAMP(a, min, max) MAX(MIN(a, max), min) template struct CeilLog { static uint32_t const v = CeilLog<(x >> 1), shifted + 1, sticky | (x & 1)>::v; }; template struct CeilLog<0, shifted, sticky> { static uint32_t const v = -1; }; template struct CeilLog<1, shifted, sticky> { static uint32_t const v = sticky ? shifted + 1 : shifted; }; #define val_n_bits() (sizeof(val_t)*8) #define val_n_half_bits() (val_n_bits()/2) #define val_all_ones() val_all_ones_or_zeroes(1) #define val_all_ones_or_zeroes(bit) (val_t(0) - val_t(bit)) #define val_n_words(n_bits) (1+((n_bits)-1)/val_n_bits()) #define val_n_half_words(n_bits) (1+((n_bits)-1)/val_n_half_bits()) #define val_top_bit(v) (val_t(v) >> (val_n_bits()-1)) #define val_n_full_words(n_bits) ((n_bits)/val_n_bits()) #define val_n_word_bits(n_bits) ((n_bits) % val_n_bits()) inline val_t val_n_nibs( void ) { return val_n_bits()>>2; } inline val_t val_half_mask( void ) { return (((val_t)1)<<(val_n_half_bits()))-1; } inline val_t val_lo_half( val_t n_bits ) { return n_bits & val_half_mask(); } inline val_t val_hi_half( val_t n_bits ) { return n_bits >> val_n_half_bits(); } inline val_t val_n_rem_word_bits( val_t n_bits ) { return val_n_bits() - val_n_word_bits(n_bits); } //inline val_t dub_val_lo_half( dub_val_t bits ) { return (val_t)bits; } //inline val_t dub_val_hi_half( dub_val_t bits ) { return (val_t)(bits >> val_n_bits()); } inline void val_to_half_vals ( val_t *fvals, half_val_t *hvals, int nf ) { for (int i = 0; i < nf; i++) { hvals[i*2] = val_lo_half(fvals[i]); hvals[i*2+1] = val_hi_half(fvals[i]); } } inline void half_val_to_vals ( half_val_t *hvals, val_t *vals, int nf ) { for (int i = 0; i < nf; i++) vals[i] = ((val_t)hvals[i*2+1] << val_n_half_bits()) | hvals[i*2]; } template class dat_t; template class datz_t; template int datz_eq(dat_t d1, datz_t d2); template inline dat_t DAT(val_t value) { dat_t res(value); return res; } template inline dat_t DAT(val_t val1, val_t val0) { dat_t res; res.values[0] = val0; res.values[1] = val1; return res; } const static char hex_digs[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; static void add_n (val_t d[], val_t s0[], val_t s1[], int nw, int nb) { val_t carry = 0; for (int i = 0; i < nw; i++) { d[i] = s0[i] + s1[i] + carry; carry = ((s0[i] + s1[i]) < s0[i]) || (d[i] < carry); } } static void neg_n (val_t d[], val_t s0[], int nw, int nb) { val_t borrow = 0; for (int i = 0; i < nw; i++) { d[i] = -s0[i] - borrow; borrow = s0[i] || d[i]; } } static void sub_n (val_t d[], val_t s0[], val_t s1[], int nw, int nb) { val_t borrow = 0; for (int i = 0; i < nw; i++) { d[i] = s0[i] - s1[i] - borrow; borrow = (s0[i] < (s0[i] - s1[i])) || (s0[i] - s1[i]) < d[i]; } } static void mul_n (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) { // Adapted from Hacker's Delight, from Knuth #if BYTE_ORDER != LITTLE_ENDIAN # error mul_n assumes a little-endian architecture #endif int nbd = nb0 + nb1; for (int i = 0; i < val_n_words(nbd); i++) d[i] = 0; half_val_t* w = reinterpret_cast(d); half_val_t* u = reinterpret_cast(s0); half_val_t* v = reinterpret_cast(s1); int m = val_n_half_words(nb0), n = val_n_half_words(nb1), p = val_n_half_words(nbd); for (int j = 0; j < n; j++) { val_t k = 0; for (int i = 0; i < MIN(m, p-j); i++) { val_t t = (val_t)u[i]*v[j] + w[i+j] + k; w[i+j] = t; k = t >> val_n_half_bits(); } if (j+m < p) w[j+m] = k; } } static void rsha_n (val_t d[], val_t s0[], int amount, int nw, int w) { int n_shift_bits = amount % val_n_bits(); int n_shift_words = amount / val_n_bits(); int n_rev_shift_bits = val_n_bits() - n_shift_bits; int is_zero_carry = n_shift_bits == 0; int msb = s0[nw-1] >> (w - nw*val_n_bits() - 1); val_t carry = 0; if (msb == 0) for (int i = 0; i < n_shift_words; i++) { d[nw-i-1] = 0; } for (int i = nw-1; i >= n_shift_words; i--) { val_t val = s0[i]; d[i-n_shift_words] = val >> n_shift_bits | carry; carry = is_zero_carry ? 0 : val << n_rev_shift_bits; } if (msb == 0) { return; } int boundary = (w - amount); for (int i = nw-1; i >= 0; i--) { int idx = i*val_n_bits(); if (idx > boundary) { d[i] = val_all_ones(); } else { d[i] = d[i] | (val_all_ones() << (boundary - idx)); d[nw-1] = d[nw-1] & (val_all_ones() >> ((nw-1)*val_n_bits() - w)); return; } } } static void rsh_n (val_t d[], val_t s0[], int amount, int nw) { val_t carry = 0; int n_shift_bits = amount % val_n_bits(); int n_shift_words = amount / val_n_bits(); int n_rev_shift_bits = val_n_bits() - n_shift_bits; int is_zero_carry = n_shift_bits == 0; for (int i = 0; i < n_shift_words; i++) d[nw-i-1] = 0; for (int i = nw-1; i >= n_shift_words; i--) { val_t val = s0[i]; d[i-n_shift_words] = val >> n_shift_bits | carry; carry = is_zero_carry ? 0 : val << n_rev_shift_bits; } } static void lsh_n (val_t d[], val_t s0[], int amount, int nwd, int nws) { val_t carry = 0; int n_shift_bits = amount % val_n_bits(); int n_shift_words = amount / val_n_bits(); int n_rev_shift_bits = val_n_bits() - n_shift_bits; int is_zero_carry = n_shift_bits == 0; for (int i = 0; i < nwd; i++) d[i] = 0; for (int i = 0; i < (nws-n_shift_words); i++) { val_t val = s0[i]; d[i+n_shift_words] = val << n_shift_bits | carry; carry = is_zero_carry ? 0 : val >> n_rev_shift_bits; } } static inline val_t mask_val(int n) { val_t res = val_all_ones() >> (val_n_bits()-n); return res; } static inline void mask_n (val_t d[], int nw, int nb) { int n_full_words = val_n_full_words(nb); int n_word_bits = val_n_word_bits(nb); for (int i = 0; i < n_full_words; i++) d[i] = val_all_ones(); for (int i = n_full_words; i < nw; i++) d[i] = 0; if (n_word_bits > 0) d[n_full_words] = mask_val(n_word_bits); } static inline val_t log2_1 (val_t v) { #ifdef __GNUC__ return TERNARY(v != 0, val_n_bits() - 1 - __builtin_clzll(v), 0); #else val_t r; val_t shift; r = (v > 0xFFFFFFFF) << 5; v >>= r; shift = (v > 0xFFFF ) << 4; v >>= shift; r |= shift; shift = (v > 0xFF ) << 3; v >>= shift; r |= shift; shift = (v > 0xF ) << 2; v >>= shift; r |= shift; shift = (v > 0x3 ) << 1; v >>= shift; r |= shift; r |= (v >> 1); return r; #endif } static inline val_t reverse_1 (val_t v) { v = ((v >> 1) & 0x5555555555555555) | ((v & 0x5555555555555555) << 1); v = ((v >> 2) & 0x3333333333333333) | ((v & 0x3333333333333333) << 2); v = ((v >> 4) & 0x0F0F0F0F0F0F0F0F) | ((v & 0x0F0F0F0F0F0F0F0F) << 4); v = ((v >> 8) & 0x00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF) << 8); v = ((v >> 16) & 0x0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF) << 16); v = ( v >> 32 ) | ( v << 32); return v; } static inline val_t priority_encode_1 (val_t v) { #ifdef __GNUC__ return TERNARY(v != 0, __builtin_ctzll(v), 0); #else if (v == 0) return 0; val_t r; val_t shift; r = !(v & 0xFFFFFFFF) << 5; v >>= r; shift = !(v & 0xFFFF ) << 4; v >>= shift; r |= shift; shift = !(v & 0xFF ) << 3; v >>= shift; r |= shift; shift = !(v & 0xF ) << 2; v >>= shift; r |= shift; shift = !(v & 0x3 ) << 1; v >>= shift; r |= shift; shift = !(v & 0x1 ) << 0; v >>= shift; r |= shift; return r; #endif } #define ispow2(x) (((x) & ((x)-1)) == 0) static inline val_t nextpow2_1(val_t x) { x--; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; x |= x >> 32; x++; return x; } /* #define __FLOAT_WORD_ORDER LITTLE_ENDIAN static inline uint32_t log2_1_32 (uint32_t v) { union { uint32_t u[2]; double d; } t; // temp t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] = 0x43300000; t.u[__FLOAT_WORD_ORDER!=LITTLE_ENDIAN] = v; t.d -= 4503599627370496.0; return (t.u[__FLOAT_WORD_ORDER==LITTLE_ENDIAN] >> 20) - 0x3FF; } static inline val_t log2_1 (val_t v) { uint32_t r_lo = (uint32_t)v; uint32_t r_hi = (uint32_t)(v >> 32); return (((val_t)log2_1_32(r_hi)) << 32)|((val_t)log2_1_32(r_lo)); } */ /* static inline val_t log2_1 (val_t v) { v |= (v >> 1); v |= (v >> 2); v |= (v >> 4); v |= (v >> 8); v |= (v >> 16); v |= (v >> 32); return ones64(v) - 1; } */ /* static inline val_t log2_1 (val_t v) { val_t res = 0; while (v >>= 1) res++; return res; } */ static inline val_t log2_n (val_t s0[], int nw) { val_t off = (nw-1)*val_n_bits(); for (int i = nw-1; i >= 0; i--) { val_t s0i = s0[i]; if (s0i > 0) { val_t res = log2_1(s0i); return res + off; } off -= val_n_bits(); } return 0; } template struct bit_word_funs { static void fill (val_t d[], val_t s0) { for (int i = 0; i < nw; i++) d[i] = s0; } static void fill_nb (val_t d[], val_t s0, int nb) { mask_n(d, nw, nb); for (int i = 0; i < nw; i++) d[i] = d[i] & s0; // printf("FILL-NB N\n"); } static void copy (val_t d[], val_t s0[], int sww) { if (sww > nw) { for (int i = 0; i < nw; i++) { // printf("A I %d\n", i); fflush(stdout); d[i] = s0[i]; } } else { for (int i = 0; i < sww; i++) { // printf("B I %d\n", i); fflush(stdout); d[i] = s0[i]; } for (int i = sww; i < nw; i++) { // printf("C I %d\n", i); fflush(stdout); d[i] = 0; } } } static void mask (val_t d[], int nb) { mask_n(d, nw, nb); } static void add (val_t d[], val_t s0[], val_t s1[], int nb) { add_n(d, s0, s1, nw, nb); } static void neg (val_t d[], val_t s0[], int nb) { neg_n(d, s0, nw, nb); } static void sub (val_t d[], val_t s0[], val_t s1[], int nb) { sub_n(d, s0, s1, nw, nb); } static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) { mul_n(d, s0, s1, nb0, nb1); } static void bit_xor (val_t d[], val_t s0[], val_t s1[]) { for (int i = 0; i < nw; i++) d[i] = s0[i] ^ s1[i]; } static void bit_and (val_t d[], val_t s0[], val_t s1[]) { for (int i = 0; i < nw; i++) d[i] = s0[i] & s1[i]; } static void bit_or (val_t d[], val_t s0[], val_t s1[]) { for (int i = 0; i < nw; i++) d[i] = s0[i] | s1[i]; } static void bit_neg (val_t d[], val_t s0[], int nb) { val_t msk[nw]; mask_n(msk, nw, nb); for (int i = 0; i < nw; i++) d[i] = ~s0[i] & msk[i]; } static bool ltu (val_t s0[], val_t s1[]) { val_t diff[nw]; sub(diff, s0, s1, nw*val_n_bits()); return val_top_bit(diff[nw-1]); } static bool lt (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1; if (msb_0 != msb_1) { return msb_0; } else { val_t diff[nw]; sub(diff, s0, s1, nw*val_n_bits()); return val_top_bit(diff[nw-1]); } } static bool lteu (val_t s0[], val_t s1[]) { val_t diff[nw]; sub(diff, s1, s0, nw*val_n_bits()); return !val_top_bit(diff[nw-1]); } static bool lte (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - (nw-1)*val_n_bits() - 1)) & 0x1; if (msb_0 != msb_1) { return msb_0; } else { val_t diff[nw]; sub(diff, s1, s0, nw*val_n_bits()); return !val_top_bit(diff[nw-1]); } } static bool eq (val_t s0[], val_t s1[]) { for (int i = 0; i < nw; i++) if (s0[i] != s1[i]) return false; return true; } static bool neq (val_t s0[], val_t s1[]) { return !eq(s0, s1); } static void rsha (val_t d[], val_t s0[], int amount, int w) { rsha_n(d, s0, amount, nw, w); } static void rsh (val_t d[], val_t s0[], int amount) { rsh_n(d, s0, amount, nw); } static void lsh (val_t d[], val_t s0[], int amount) { lsh_n(d, s0, amount, nw, nw); } static void extract (val_t d[], val_t s0[], int e, int s, int nb) { // TODO: FINISH THIS const int bw = e-s+1; val_t msk[nw]; mask_n(msk, nw, nb); if (s == 0) { // printf("EXT E %d S %d NW %d NB %d: ", e, s, nw, nb); for (int i = 0; i < nw; i++) { d[i] = s0[i] & msk[i]; // printf("%d:%llx ", i, d[i]); } } else { rsh_n(d, s0, s, nw); // printf("EXT E %d S %d NW %d NB %d: ", e, s, nw, nb); for (int i = 0; i < nw; i++) { // printf("I%d:R%llx:M%llx:", i, d[i], msk[i]); d[i] = d[i] & msk[i]; // printf("D%llx ", d[i]); } } // printf("\n"); } static void inject (val_t d[], val_t s0[], int e, int s) { // Opposite of extract: Assign s0 to a subfield of d. const int bw = e-s+1; val_t msk[nw]; val_t msk_lsh[nw]; val_t s0_lsh[nw]; mask_n(msk, nw, bw); lsh_n(msk_lsh, msk, s, nw, nw); lsh_n(s0_lsh, s0, s, nw, nw); for (int i = 0; i < nw; i++) { d[i] = (d[i] & ~msk_lsh[i]) | (s0_lsh[i] & msk_lsh[i]); } } static void set (val_t d[], val_t s0[]) { for (int i = 0; i < nw; i++) d[i] = s0[i]; } static void log2 (val_t d[], val_t s0[]) { d[0] = log2_n(s0, nw); } }; template <> struct bit_word_funs<1> { static void fill (val_t d[], val_t s0) { d[0] = s0; } static void fill_nb (val_t d[], val_t s0, int nb) { d[0] = mask_val(nb) & s0; } static void copy (val_t d[], val_t s0[], int sww) { d[0] = s0[0]; } static void mask (val_t d[], int nb) { d[0] = mask_val(nb); } static void add (val_t d[], val_t s0[], val_t s1[], int nb) { d[0] = (s0[0] + s1[0]) & mask_val(nb); } static void sub (val_t d[], val_t s0[], val_t s1[], int nb) { d[0] = (s0[0] - s1[0]) & mask_val(nb); } static void neg (val_t d[], val_t s0[], int nb) { d[0] = (- s0[0]) & mask_val(nb); } static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) { d[0] = s0[0] * s1[0]; } static bool ltu (val_t s0[], val_t s1[]) { return (s0[0] < s1[0]); } static bool lt (val_t s0[], val_t s1[], int w) { sval_t a = s0[0] << (val_n_bits() - w); sval_t b = s1[0] << (val_n_bits() - w); return (a < b); } static bool lteu (val_t s0[], val_t s1[]) { return (s0[0] <= s1[0]); } static bool lte (val_t s0[], val_t s1[], int w) { sval_t a = s0[0] << (val_n_bits() - w); sval_t b = s1[0] << (val_n_bits() - w); return (a <= b); } static void bit_neg (val_t d[], val_t s0[], int nb) { d[0] = ~s0[0] & mask_val(nb); } static void bit_xor (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] ^ s1[0]); } static void bit_and (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] & s1[0]); } static void bit_or (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] | s1[0]); } static bool eq (val_t s0[], val_t s1[]) { return s0[0] == s1[0]; } static bool neq (val_t s0[], val_t s1[]) { return s0[0] != s1[0]; } static void lsh (val_t d[], val_t s0[], int amount) { d[0] = (s0[0] << amount); } static void rsh (val_t d[], val_t s0[], int amount) { d[0] = (s0[0] >> amount); } static void rsha (val_t d[], val_t s0[], int amount, int w) { d[0] = s0[0] << (val_n_bits() - w); d[0] = (sval_t(d[0]) >> (val_n_bits() - w + amount)) & mask_val(w); } static void extract (val_t d[], val_t s0[], int e, int s, int nb) { const int bw = e-s+1; d[0] = (s0[0] >> s) & mask_val(bw); } static void inject (val_t d[], val_t s0[], int e, int s) { // Opposite of extract: Assign s0 to a subfield of d. const int bw = e-s+1; val_t msk = mask_val(bw); d[0] = ((s0[0] & msk) << s) | (d[0] & ~(msk << s)); } static void set (val_t d[], val_t s0[]) { d[0] = s0[0]; } static void log2 (val_t d[], val_t s0[]) { d[0] = log2_1(s0[0]); } }; template <> struct bit_word_funs<2> { static void fill (val_t d[], val_t s0) { d[0] = s0; d[1] = s0; } static void fill_nb (val_t d[], val_t s0, int nb) { d[0] = s0; d[1] = mask_val(nb - val_n_bits()) & s0; } static void copy (val_t d[], val_t s0[], int sww) { d[0] = s0[0]; d[1] = sww > 1 ? s0[1] : 0; } static void mask (val_t d[], int nb) { d[0] = val_all_ones(); d[1] = mask_val(nb - val_n_bits()); } static void add (val_t d[], val_t x[], val_t y[], int nb) { val_t x0 = x[0]; val_t sum0 = x0 + y[0]; val_t carry0 = (sum0 < x0); d[0] = sum0; val_t sum1 = x[1] + y[1] + carry0; d[1] = sum1; } static void sub (val_t d[], val_t s0[], val_t s1[], int nb) { val_t d0 = s0[0] - s1[0]; d[1] = s0[1] - s1[1] - (s0[0] < d0); d[0] = d0; } static void neg (val_t d[], val_t s0[], int nb) { val_t d0 = -s0[0]; d[1] = -s0[1] - (s0[0] != 0); d[0] = d0; } static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) { #ifdef __HAVE_DUB_VAL_T__ dub_val_t a = s0[0], b = s1[0]; if (nb0 > val_n_bits()) a |= dub_val_t(s0[1]) << val_n_bits(); if (nb1 > val_n_bits()) b |= dub_val_t(s1[1]) << val_n_bits(); dub_val_t res = a * b; d[0] = res; d[1] = res >> val_n_bits(); #else mul_n(d, s0, s1, nb0, nb1); #endif } static bool ltu (val_t s0[], val_t s1[]) { return ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] < s1[0])); } static bool lt (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - val_n_bits() - 1)) & 0x1; int cond = msb_0 ^ msb_1; return (cond && msb_0) || (!cond && ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] < s1[0]))); } static bool lteu (val_t s0[], val_t s1[]) { return ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] <= s1[0])); } static bool lte (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - val_n_bits() - 1)) & 0x1; int cond = msb_0 ^ msb_1; return (cond && msb_0) || (!cond && ((s0[1] < s1[1]) | (s0[1] == s1[1] & s0[0] <= s1[0]))); } static void bit_xor (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] ^ s1[0]); d[1] = (s0[1] ^ s1[1]); } static void bit_and (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] & s1[0]); d[1] = (s0[1] & s1[1]); } static void bit_or (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] | s1[0]); d[1] = (s0[1] | s1[1]); } static void bit_neg (val_t d[], val_t s0[], int nb) { d[0] = ~s0[0]; d[1] = ~s0[1] & mask_val(nb - val_n_bits()); } static bool eq (val_t s0[], val_t s1[]) { return (s0[0] == s1[0]) & (s0[1] == s1[1]); } static bool neq (val_t s0[], val_t s1[]) { return (s0[0] != s1[0]) | (s0[1] != s1[1]); } static void extract (val_t d[], val_t s0[], int e, int s, int nb) { val_t msk[2]; const int bw = e-s+1; mask_n(msk, 2, bw); if (s == 0) { d[0] = s0[0] & msk[0]; d[1] = s0[1] & msk[1]; } else { rsh(d, s0, s); d[0] = d[0] & msk[0]; d[1] = d[1] & msk[1]; } } static void inject (val_t d[], val_t s0[], int e, int s) { // Opposite of extract: Assign s0 to a subfield of d. const int bw = e-s+1; val_t msk[2]; val_t msk_lsh[2]; val_t s0_lsh[2]; mask_n(msk, 2, bw); lsh_n(msk_lsh, msk, s, 2, 2); lsh_n(s0_lsh, s0, s, 2, 2); d[0] = (d[0] & ~msk_lsh[0]) | (s0_lsh[0] & msk_lsh[0]); d[1] = (d[1] & ~msk_lsh[1]) | (s0_lsh[1] & msk_lsh[1]); } static void rsha (val_t d[], val_t s0[], int amount, int w) { sval_t hi = s0[1] << (2*val_n_bits() - w); if (amount >= val_n_bits()) { d[0] = hi >> (amount - w + val_n_bits()); d[1] = hi >> (val_n_bits() - 1); d[1] = d[1] >> (2*val_n_bits() - w); } else if (amount == 0) { d[0] = s0[0]; d[1] = s0[1]; } else { int s = 2*val_n_bits() - w + amount; d[0] = s0[0] >> amount; d[0] = d[0] | ((hi >> (2*val_n_bits() - w)) << (val_n_bits() - amount)); d[1] = hi >> (s >= val_n_bits() ? val_n_bits()-1 : s); d[1] = d[1] & mask_val(w - val_n_bits()); } } static void rsh (val_t d[], val_t s0[], int amount) { if (amount >= val_n_bits()) { d[1] = 0; d[0] = s0[1] >> (amount - val_n_bits()); } else if (amount == 0) { d[0] = s0[0]; d[1] = s0[1]; } else { d[1] = s0[1] >> amount; d[0] = (s0[1] << (val_n_bits() - amount)) | (s0[0] >> amount); } } static void lsh (val_t d[], val_t s0[], int amount) { if (amount == 0) { d[1] = s0[1]; d[0] = s0[0]; } else if (amount >= val_n_bits()) { d[1] = s0[0] << (amount - val_n_bits()); d[0] = 0; } else { d[1] = (s0[1] << amount) | (s0[0] >> (val_n_bits() - amount)); d[0] = (s0[0] << amount); } } static void set (val_t d[], val_t s0[]) { d[0] = s0[0]; d[1] = s0[1]; } static void log2 (val_t d[], val_t s0[]) { val_t s01 = s0[1]; if (s01 > 0) d[0] = log2_1(s01) + val_n_bits(); else d[0] = log2_1(s0[0]); // d[0] = log2_n(s0, 2); } }; template <> struct bit_word_funs<3> { static void fill (val_t d[], val_t s0) { d[0] = s0; d[1] = s0; d[2] = s0; } static void fill_nb (val_t d[], val_t s0, int nb) { d[0] = s0; d[1] = s0; d[2] = mask_val(nb - 2*val_n_bits()) & s0; } static void copy (val_t d[], val_t s0[], int sww) { d[0] = s0[0]; d[1] = sww > 1 ? s0[1] : 0; d[2] = sww > 2 ? s0[2] : 0; } static void mask (val_t d[], int nb) { d[0] = val_all_ones(); d[1] = val_all_ones(); d[2] = mask_val(nb - 2*val_n_bits()); } static void add (val_t d[], val_t s0[], val_t s1[], int nb) { add_n(d, s0, s1, 3, nb); } static void sub (val_t d[], val_t s0[], val_t s1[], int nb) { sub_n(d, s0, s1, 3, nb); } static void neg (val_t d[], val_t s0[], int nb) { neg_n(d, s0, 3, nb); } static void mul (val_t d[], val_t s0[], val_t s1[], int nb0, int nb1) { mul_n(d, s0, s1, nb0, nb1); } static bool ltu (val_t s0[], val_t s1[]) { return ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] < s1[0]))))); } static bool lt (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - 2*val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - 2*val_n_bits() - 1)) & 0x1; int cond = msb_0 ^ msb_1; return (cond && msb_0) || (!cond && (((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] < s1[0]))))))); } static bool lteu (val_t s0[], val_t s1[]) { return ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] <= s1[0]))))); } static bool lte (val_t s0[], val_t s1[], int w) { int msb_0 = (s0[1] >> (w - 2*val_n_bits() - 1)) & 0x1; int msb_1 = (s1[1] >> (w - 2*val_n_bits() - 1)) & 0x1; int cond = msb_0 ^ msb_1; return (cond && msb_0) || (!cond && ((s0[2] < s1[2]) | ((s0[2] == s1[2]) & ((s0[1] < s1[1]) | ((s0[1] == s1[1]) & (s0[0] <= s1[0])))))); } static void bit_xor (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] ^ s1[0]); d[1] = (s0[1] ^ s1[1]); d[2] = (s0[2] ^ s1[2]); } static void bit_and (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] & s1[0]); d[1] = (s0[1] & s1[1]); d[2] = (s0[2] & s1[2]); } static void bit_or (val_t d[], val_t s0[], val_t s1[]) { d[0] = (s0[0] | s1[0]); d[1] = (s0[1] | s1[1]); d[2] = (s0[2] | s1[2]); } static void bit_neg (val_t d[], val_t s0[], int nb) { d[0] = ~s0[0]; d[1] = ~s0[1]; d[2] = ~s0[2] & mask_val(nb - 2*val_n_bits()); } static bool eq (val_t s0[], val_t s1[]) { return (s0[0] == s1[0]) & (s0[1] == s1[1]) & (s0[2] == s1[2]); } static bool neq (val_t s0[], val_t s1[]) { return (s0[0] != s1[0]) | (s0[1] != s1[1]) | (s0[2] != s1[2]); } static void extract (val_t d[], val_t s0[], int e, int s, int nb) { val_t msk[3]; const int bw = e-s+1; mask_n(msk, 3, bw); if (s == 0) { d[0] = s0[0] & msk[0]; d[1] = s0[1] & msk[1]; d[2] = s0[2] & msk[2]; } else { rsh(d, s0, s); d[0] = d[0] & msk[0]; d[1] = d[1] & msk[1]; d[2] = d[2] & msk[2]; } } static void inject (val_t d[], val_t s0[], int e, int s) { const int bw = e-s+1; val_t msk[3]; val_t msk_lsh[3]; val_t s0_lsh[3]; mask_n(msk, 3, bw); lsh_n(msk_lsh, msk, s, 3, 3); lsh_n(s0_lsh, s0, s, 3, 3); d[0] = (d[0] & ~msk_lsh[0]) | (s0_lsh[0] & msk_lsh[0]); d[1] = (d[1] & ~msk_lsh[1]) | (s0_lsh[1] & msk_lsh[1]); d[2] = (d[2] & ~msk_lsh[2]) | (s0_lsh[2] & msk_lsh[2]); } static void rsha (val_t d[], val_t s0[], int amount, int w) { rsha_n(d, s0, amount, 3, w); } static void rsh (val_t d[], val_t s0[], int amount) { rsh_n(d, s0, amount, 3); } static void lsh (val_t d[], val_t s0[], int amount) { lsh_n(d, s0, amount, 3, 3); } static void log2 (val_t d[], val_t s0[]) { d[0] = log2_n(s0, 3); } static void set (val_t d[], val_t s0[]) { d[0] = s0[0]; d[1] = s0[1]; d[2] = s0[2]; } }; static val_t __rand_val(val_t* seed) { val_t x = *seed; *seed = (x << 1) ^ (-(sval_t(x) < 0) & 0x1B); return x; } template class dat_t { public: const static int n_words = ((w - 1) / 64) + 1; // const static int n_words = (w >> CeilLog::v) + 1; val_t values[n_words]; inline int width ( void ) { return w; } inline int n_words_of ( void ) { return n_words; } inline bool to_bool ( void ) { return lo_word() != 0; } inline val_t lo_word ( void ) { return values[0]; } inline unsigned long to_ulong ( void ) { return (unsigned long)lo_word(); } std::string to_str () { std::string rres, res; int nn = (int)ceilf(w / 4.0); for (int i = 0; i < n_words; i++) { int n_nibs = nn < val_n_nibs() ? nn : val_n_nibs(); for (int j = 0; j < n_nibs; j++) { uint8_t nib = (values[i] >> (j*4))&0xf; rres.push_back(hex_digs[nib]); } nn -= val_n_bits()/4; } res.push_back('0'); res.push_back('x'); for (int i = 0; i < rres.size(); i++) res.push_back(rres[rres.size()-i-1]); return res; } void randomize(val_t* seed) { for (int i = 0; i < n_words; i++) values[i] = __rand_val(seed); if (val_n_word_bits(w)) values[n_words-1] &= mask_val(val_n_word_bits(w)); } inline dat_t () { } template inline dat_t (const dat_t& src) { bit_word_funs::copy(values, (val_t*)src.values, src.n_words); if (sw != w && val_n_word_bits(w)) values[n_words-1] &= mask_val(val_n_word_bits(w)); } inline dat_t (const dat_t& src) { bit_word_funs::set(values, (val_t*)src.values); } static inline dat_t from_vals(val_t val[n_words]) { dat_t res; for (int i = 0; i < n_words; i++) res.values[i] = val[i]; return res; } inline dat_t (val_t val) { values[0] = val; for (int i = 1; i < n_words; i++) values[i] = 0; } template dat_t mask(dat_t fill, int n) { dat_t res; bit_word_funs::mask(res.values, n); return res; } template dat_t mask(int n) { dat_t res; return res.mask(*this, n); } template inline dat_t mask(void) { dat_t res = mask(n); return res; } val_t operator [] (size_t i) { return values[i]; } dat_t operator + ( dat_t o ) { dat_t res; bit_word_funs::add(res.values, values, o.values, w); return res; } dat_t operator - ( dat_t o ) { dat_t res; bit_word_funs::sub(res.values, values, o.values, w); return res; } dat_t operator - ( ) { return ~(*this) + DAT(1); } template dat_t operator * ( dat_t o ) { dat_t res; bit_word_funs::mul(res.values, values, o.values, w, w2); return res; } template dat_t fix_times_fix( dat_t o ) { if (w+w2 <= val_n_bits()) { sval_t a = sval_t(values[0] << (val_n_bits()-w)) >> (val_n_bits()-w); sval_t b = sval_t(o.values[0] << (val_n_bits()-w2)) >> (val_n_bits()-w2); return dat_t((a * b) & mask_val(w+w2)); } else { val_t sgn_a = msb(); dat_t abs_a = sgn_a ? -(*this) : (*this); val_t sgn_b = o.msb(); dat_t abs_b = sgn_b ? -o : o; dat_t res = abs_a * abs_b; return (sgn_a ^ sgn_b) ? -res : res; } } dat_t operator / ( dat_t o ) { dat_t res(0); if (o == 0) { res.fill_bit(1); } else if (n_words == 1) { res.values[0] = values[0] / o.values[0]; } else { dat_t<2*w> p = *this, d = o; d = d << w; for (int i = w-1; i >= 0; i--) { p = p << 1; if (p >= d) { p = p - d; res.values[i / val_n_bits()] |= val_t(1) << (i % val_n_bits()); } } } return res; } dat_t operator % ( dat_t o ) { return *this - *this / o * o; } dat_t ufix_times_fix( dat_t o ) { return o.fix_times_ufix(*this); } template dat_t fix_times_ufix( dat_t o ) { if (w+w2 <= val_n_bits()) { sval_t a = sval_t(values[0] << (val_n_bits()-w)) >> (val_n_bits()-w); return dat_t((a * o.values[0]) & mask_val(w+w2)); } else { val_t sgn_a = msb(); dat_t abs_a = sgn_a ? -(*this) : (*this); dat_t res = abs_a * o; return sgn_a ? -res : res; } } inline bool operator < ( dat_t o ) { return bit_word_funs::ltu(values, o.values); } inline bool operator <= ( dat_t o ) { return bit_word_funs::lteu(values, o.values); } inline bool operator > ( dat_t o ) { return o < *this; } inline bool operator >= ( dat_t o ) { return o <= *this; } inline bool lt ( dat_t o ) { return bit_word_funs::lt(values, o.values, w); } inline bool lte ( dat_t o ) { return bit_word_funs::lte(values, o.values, w); } inline bool gt ( dat_t o ) { return o.lt(*this); } inline bool gte ( dat_t o ) { return o.lte(*this); } dat_t operator ^ ( dat_t o ) { dat_t res; bit_word_funs::bit_xor(res.values, values, o.values); return res; } dat_t operator & ( dat_t o ) { dat_t res; bit_word_funs::bit_and(res.values, values, o.values); return res; } dat_t operator | ( dat_t o ) { dat_t res; bit_word_funs::bit_or(res.values, values, o.values); return res; } dat_t operator ~ ( void ) { dat_t res; bit_word_funs::bit_neg(res.values, values, w); return res; } inline dat_t<1> operator ! ( void ) { return DAT<1>(!lo_word()); } dat_t<1> operator && ( dat_t<1> o ) { return DAT<1>(lo_word() & o.lo_word()); } dat_t<1> operator || ( dat_t<1> o ) { return DAT<1>(lo_word() | o.lo_word()); } bool operator == ( dat_t o ) { return bit_word_funs::eq(values, o.values); } bool operator == ( datz_t o ) { return o == *this; } bool operator != ( dat_t o ) { return bit_word_funs::neq(values, o.values); } dat_t operator << ( int amount ) { dat_t res; bit_word_funs::lsh(res.values, values, amount); if (val_n_word_bits(w)) res.values[n_words-1] &= mask_val(val_n_word_bits(w)); return res; } inline dat_t operator << ( dat_t o ) { return *this << o.lo_word(); } dat_t operator >> ( int amount ) { dat_t res; bit_word_funs::rsh(res.values, values, amount); return res; } inline dat_t operator >> ( dat_t o ) { return *this >> o.lo_word(); } dat_t rsha ( dat_t o) { dat_t res; int amount = o.lo_word(); bit_word_funs::rsha(res.values, values, amount, w); return res; } dat_t& operator = ( dat_t o ) { bit_word_funs::set(values, o.values); return *this; } dat_t fill_bit( val_t bit ) { dat_t res; val_t word = 0L - bit; bit_word_funs::fill_nb(res.values, word, w); return res; } // TODO: SPEED THIS UP dat_t fill_byte( val_t byte, int nb, int n ) { dat_t res; bit_word_funs::fill(res.values, 0L); for (size_t i = 0; i < n; i++) res = (res << nb) | byte; return res; } template dat_t fill( void ) { // TODO: GET RID OF IF'S dat_t res; if (w == 1) { return res.fill_bit(lo_word()); } else { return res.fill_byte(lo_word(), w, n); } } template dat_t fill( dat_t n ) { // TODO: GET RID OF IF'S dat_t res; if (w == 1) { return res.fill_bit(lo_word()&1); } else { return res.fill_byte(lo_word(), w, n); } } template dat_t extract() { dat_t res; int i; for (i = 0; i < val_n_full_words(dw); i++) res.values[i] = values[i]; if (val_n_word_bits(dw)) res.values[i] = values[i] & mask_val(val_n_word_bits(dw)); return res; } template dat_t extract(val_t e, val_t s) { dat_t x = (*this >> s); return x.extract(); } template inline dat_t extract(dat_t e, dat_t s) { return extract(e.lo_word(), s.lo_word()); } template dat_t inject(dat_t src, val_t e, val_t s) { // Modify this.values in place. dat_t inject_src(src); // Enlarged if needed to match inject_dst bit_word_funs::inject(values, inject_src.values, e, s); return *this; } template inline dat_t inject(dat_t src, dat_t e, dat_t s) { return inject(src, e.lo_word(), s.lo_word()); } template inline dat_t log2() { dat_t res; bit_word_funs::log2(res.values, values); return res; } inline val_t bit(val_t b) { return (values[val_n_full_words(b)] >> val_n_word_bits(b)) & 1; } inline val_t msb() { return values[n_words-1] >> val_n_word_bits(w-1); } template inline dat_t<1> bit(dat_t b) { return bit(b.lo_word()); } }; template std::string dat_to_str(const dat_t& x) { char s[w]; s[dat_to_str(s, x)] = 0; return s; } static __inline__ int n_digits(int w, int base) { return (int)ceil(log(2)/log(base)*w); } template int dat_to_str(char* s, dat_t x, int base = 16, char pad = '0') { int n_digs = n_digits(w, base); int j = n_digs-1, digit; do { if (ispow2(base)) { digit = x.lo_word() & (base-1); x = x >> log2_1(base); } else { digit = (x % base).lo_word(); x = x / base; } s[j] = (digit >= 10 ? 'a'-10 : '0') + digit; } while (--j >= 0 && x != 0); for ( ; j >= 0; j--) s[j] = pad; return n_digs; } static __inline__ int dat_to_str(char* s, val_t x, int base = 16, char pad = '0') { return dat_to_str(s, dat_t(x), base, pad); } template int fix_to_str(char* s, dat_t x, int base = 16, char pad = '0') { bool neg = x.msb(); s[0] = neg; int len = dat_to_str(s+1, neg ? -x : x, base, pad); return len+1; } static __inline__ int flo_digits(int m, int e) { return 2 + n_digits(m, 10) + 2 + n_digits(e, 10); } template int flo_to_str(char* s, dat_t x, char pad = ' ') { char buf[1000]; int n_digs = (w == 32) ? flo_digits(32, 8) : flo_digits(52, 11); double val = (w == 32) ? toFloat(x.values[0]) : toDouble(x.values[0]); // sprintf(buf, "%d %d%*e", w, n_digs, n_digs, val); sprintf(buf, "%*e", n_digs, val); assert(strlen(buf) <= n_digs); for (int i = 0; i < n_digs; i++) s[i] = (i < strlen(buf)) ? buf[i] : pad; s[n_digs] = 0; // printf("N-DIGS = %d BUF %lu PAD %lu\n", n_digs, strlen(buf), n_digs-strlen(buf)); // return strlen(buf); return n_digs; } template int dat_as_str(char* s, const dat_t& x) { int i, j; for (i = 0, j = (w/8-1)*8; i < w/8; i++, j -= 8) { char ch = x.values[j/val_n_bits()] >> (j % val_n_bits()); if (ch == 0) break; s[i] = ch; } for ( ; i < w/8; i++) s[i] = ' '; return w/8; } static __inline__ int dat_as_str(char* s, val_t x) { return dat_as_str(s, dat_t(x)); } #if __cplusplus >= 201103L static void __attribute__((unused)) dat_format(char* s, const char* fmt) { for (char c; (c = *fmt); fmt++) { if (c == '%' && *++fmt != '%') abort(); *s++ = c; } } template static void dat_format(char* s, const char* fmt, T value, Args... args) { while (*fmt) { if (*fmt == '%') { switch(fmt[1]) { case 'e': s += flo_to_str(s, value, ' '); break; case 'h': s += dat_to_str(s, value, 16, '0'); break; case 'b': s += dat_to_str(s, value, 2, '0'); break; case 'd': s += dat_to_str(s, value, 10, ' '); break; case 's': s += dat_as_str(s, value); break; case '%': *s++ = '%'; break; default: abort(); } return dat_format(s, fmt + 2, args...); } else { *s++ = *fmt++; } } abort(); } template static dat_t dat_format(const char* fmt, Args... args) { #if BYTE_ORDER != LITTLE_ENDIAN # error dat_format assumes a little-endian architecture #endif char str[w/8+1]; dat_format(str, fmt, args...); dat_t res; res.values[res.n_words-1] = 0; for (int i = 0; i < w/8; i++) ((char*)res.values)[w/8-1-i] = str[i]; return res; } template static ssize_t dat_fprintf(FILE *f, const char* fmt, Args... args) { char str[w/8+1]; dat_format(str, fmt, args...); return fwrite(str, 1, w/8, f); } template static ssize_t dat_prints(std::ostream& s, const char* fmt, Args... args) { char str[w/8+1]; dat_format(str, fmt, args...); s.write(str, w/8); ssize_t ret = s.good() ? w/8 : -1; return ret; } #endif /* C++11 */ template inline dat_t DAT(dat_t dat) { dat_t res(dat); return res; } template inline dat_t LIT(val_t value) { return DAT(value); } template inline dat_t mux ( dat_t<1> t, dat_t c, dat_t a ) { dat_t mask; bit_word_funs::fill(mask.values, -t.lo_word()); return a ^ ((a ^ c) & mask); } template class datz_t : public dat_t { public: dat_t mask; inline bool operator == ( dat_t o ) { dat_t masked = (o & mask); return (o & mask) == (dat_t)*this; } }; template datz_t inline LITZ(val_t value, val_t mask) { datz_t res; res.mask.values[0] = mask; res.values[0] = value; return res; } template < int w, int w1, int w2 > inline dat_t cat(dat_t d1, dat_t d2) { if (w <= val_n_bits() && w1 + w2 == w) return DAT(d1.values[0] << (w2 & (val_n_bits()-1)) | d2.values[0]); return DAT((DAT(d1) << w2) | DAT(d2)); } template < int w1 > inline dat_t<1> reduction_and(dat_t d) { return DAT<1>(d == ~DAT(0)); } template < int w1 > inline dat_t<1> reduction_or(dat_t d) { return DAT<1>(d != DAT(0)); } // I am O(n) where n is number of bits in val_t. Future optimization would be log(n). template < int w1 > inline dat_t<1> reduction_xor(dat_t d) { dat_t<1> res = DAT<1>(0); val_t word = d.values[0]; for (int i = 1; i < d.n_words_of(); i++) word ^= d.values[i]; for (int i = 0; i < sizeof(val_t)*8; i++) { res = res ^ DAT<1>(word & 1); word = word >> 1; } return res; } template class mem_t { public: dat_t contents[d]; val_t dummy_seed; val_t* seedp; int width() { return w; } int length() { return d; } template dat_t get (dat_t idx) { return get(idx.lo_word() & (nextpow2_1(d)-1)); } dat_t get (val_t idx) { if (!ispow2(d) && idx >= d) { dat_t res; res.randomize(seedp); return res; } return contents[idx]; } val_t get (val_t idx, int word) { if (!ispow2(d) && idx >= d) return __rand_val(seedp) & (word == val_n_words(w) && val_n_word_bits(w) ? mask_val(w) : -1L); return contents[idx].values[word]; } template void put (dat_t idx, dat_t val) { put(idx.lo_word(), val); } void put (val_t idx, dat_t val) { if (ispow2(d) || idx < d) contents[idx] = val; } val_t put (val_t idx, int word, val_t val) { if (ispow2(d) || idx < d) contents[idx].values[word] = val; } void print ( void ) { for (int j = 0; j < d/4; j++) { for (int i = 0; i < 4; i++) { int idx = j*4+i; printf("|%2d: %16llx| ", idx, contents[idx].lo_word()); } printf("\n"); } } mem_t () { dummy_seed = 1; seedp = &dummy_seed; for (int i = 0; i < d; i++) contents[i] = DAT(0); } void randomize(val_t* seed) { seedp = seed; for (int i = 0; i < d; i++) contents[i].randomize(seed); } size_t read_hex(const char *hexFileName) { ifstream ifp(hexFileName); if (ifp.fail()) { printf("[error] Unable to open hex data file %s\n", hexFileName); return -1; } std::string hex_line; dat_t hex_dat; for (int addr = 0; addr < d && !ifp.eof();) { getline(ifp, hex_line); if (dat_from_hex(hex_line, hex_dat) > 0) { contents[addr++] = hex_dat; } } ifp.close(); return 0; } }; static __attribute__((unused)) char hex_to_char[] = "0123456789abcdef"; static int char_to_hex[] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; // dat_from_hex: Read a hex value from a std::string into a given dat_t variable. // Author: B. Richards, for parsing data formatted for Verilog $readmemh // Arguments: // hex_line A string containing hex numbers with embedded x, _ characters // res A dat_t object to fill in with a return value // offset Starting index in hex_line // Return value: // Success: returns next character offset // Fail: 0 template size_t dat_from_hex(std::string hex_line, dat_t& res, size_t offset = 0) { size_t first_digit, last_digit, comment; // Scan for the hex data bounds. comment = hex_line.find_first_of("/", offset); first_digit = hex_line.find_first_of("0123456789abcdefABCDEF", offset); if (first_digit == std::string::npos) return 0; if (comment != std::string::npos && comment < first_digit) return 0; last_digit = hex_line.find_first_not_of("0123456789abcdefABCDEF_xX", first_digit); if (last_digit == std::string::npos) { last_digit = hex_line.length() - 1; } else { last_digit--; } // Convert the hex data to a dat_t, from right to left. int digit_val; val_t word_accum = 0; int digit, w_index, bit; for (digit = last_digit, w_index = 0, bit = 0; digit >= (int)first_digit && w_index < res.n_words; digit--) { digit_val = char_to_hex[hex_line[digit]]; if (digit_val >= 0) { word_accum |= ((val_t)digit_val) << bit; bit += 4; if (bit == 64) { res.values[w_index] = word_accum; word_accum = 0L; bit = 0; w_index++; } } } if (bit != 0) { res.values[w_index] = word_accum; } // Return a pointer to the character after the converted value. return last_digit + 1; } #pragma GCC push_options #pragma GCC optimize ("no-stack-protector") template void dat_dump (FILE* f, const dat_t& val, val_t name) { size_t pos = 0; char str[1 + w + 1 + s + 1]; str[pos++] = 'b'; for (int i = 0; i < w; i++) str[pos + w-i-1] = '0' + ((val.values[i/val_n_bits()] >> (i%val_n_bits())) & 1); pos += w; str[pos++] = ' '; for (int i = 0; i < s; i++) { str[pos++] = name; name >>= 8; } str[pos++] = '\n'; fwrite(str, 1, sizeof(str), f); } #pragma GCC pop_options inline std::string read_tok(FILE* f) { std::string res; bool is_skipping = true; for (;;) { char c = fgetc(f); if (feof(f)) return res; if (is_skipping) { if (char_to_hex[c] != -1) { res.push_back(c); is_skipping = false; } } else { if (char_to_hex[c] == -1) { ungetc(c, f); return res; } res.push_back(c); } } } template void dat_dump(FILE* file, const mem_t& val, val_t name) { } template mem_t MEM( void ); class mod_t { public: mod_t(): dumpfile(NULL), is_stale(false), printStream() {} std::vector< mod_t* > children; virtual void init ( val_t rand_init=false ) { }; virtual void clock_lo ( dat_t<1> reset ) { }; virtual void clock_hi ( dat_t<1> reset ) { }; virtual int clock ( dat_t<1> reset ) { }; virtual void setClocks ( std::vector< int >& periods ) { }; // Returns a clone of this object's circuit state (both registers and wires). // Currently, it is undefined what happens to other state (like dumpfile and // timestep), so use with care. virtual mod_t* clone() = 0; // Sets this module's circuit state (registers and wires) from the src mod_t. // For mod_t subclasses, src must be the same class. // Returns true on success, and false on failure. Currently, no guarantees // are made about state consistency on failure, virtual bool set_circuit_from(mod_t* src) = 0; virtual void print ( FILE* f ) { }; virtual void print ( std::ostream& s ) { }; virtual void dump ( FILE* f, int t ) { }; void set_dumpfile(FILE* f) { dumpfile = f; } int timestep; void dump () { if (dumpfile != NULL) dump(dumpfile, timestep); timestep += 1; } int step (bool is_reset, int n) { int delta = 0; dat_t<1> reset = LIT<1>(is_reset); for (int i = 0; i < n; i++) { if (is_reset) { clock_lo(reset); } // Collect any print output. print(printStream); dump(); delta += clock(reset); } return delta; } void mark_stale (void) { is_stale = true; } void propagate_changes (void) { if (is_stale) clock_lo(LIT<1>(false)); is_stale = false; } int has_output(void) { return printStream.tellp(); } std::string drain_output(void) { return printStream.str(); } // Since we have an element with a deleted copy constructor - printStream, // we need to provide our own explicit copy constructor. mod_t(const mod_t& src) { children = src.children; timestep = src.timestep; is_stale = src.is_stale; dumpfile = src.dumpfile; } protected: bool is_stale; FILE* dumpfile; std::basic_ostringstream< char > printStream; }; #define ASSERT(cond, msg) { \ if (!(cond)) \ throw std::runtime_error("Assertion failed: " msg); \ } #pragma GCC diagnostic pop #endif