/* little-endian bytes of a word-addressed cell array. byte address b names bits [8b, 8b+8) of the flat image: word b>>3, low byte first. a byte address is an ordinary integer. the odd/even tag is only for code words, and ownership tags stay on word pointers. wider loads and stores are little-endian and may cross a word. an access that does not lie entirely inside the image is refused. */ #ifndef BOPS_H #define BOPS_H #include static int bop_ok(int64_t addr, int n, int64_t nwords) { uint64_t bytes, a, k; if (n <= 0 || n > 8 || addr < 0 || nwords < 1) return 0; bytes = (uint64_t)nwords << 3; a = (uint64_t)addr; k = (uint64_t)n; if (a >= bytes || k > bytes - a) return 0; return 1; } static int64_t bop_load(const int64_t *mem, int64_t addr, int n) { int64_t v = 0; int i; for (i = 0; i < n; i++) { int64_t a = addr + i; int sh = (int)((a & 7) << 3); v |= (int64_t)(((uint64_t)mem[a >> 3] >> sh) & 255) << (i * 8); } return v; } /* fold n bytes of val into the words they touch. *w0 is the first word. returns how many words changed (1 or 2). does not write mem. */ static int bop_merge(const int64_t *mem, int64_t addr, int64_t val, int n, int64_t *out, int64_t *w0) { int i, nw; int64_t base = addr >> 3; nw = (int)(((addr + n - 1) >> 3) - base) + 1; *w0 = base; out[0] = mem[base]; if (nw > 1) out[1] = mem[base + 1]; for (i = 0; i < n; i++) { int64_t a = addr + i; int wi = (int)((a >> 3) - base); int sh = (int)((a & 7) << 3); uint64_t mask = (uint64_t)255 << sh; uint64_t byte = ((uint64_t)val >> (i * 8)) & 255; out[wi] = (int64_t)(((uint64_t)out[wi] & ~mask) | (byte << sh)); } return nw; } static void bop_put1(int64_t *mem, int64_t addr, int byte) { int64_t out[2], w0; int n, i; n = bop_merge(mem, addr, byte & 255, 1, out, &w0); for (i = 0; i < n; i++) mem[w0 + i] = out[i]; } /* copy a NUL-terminated byte string into dst. returns the length, or -1 when the address is outside the image. */ static int bop_cstr(const int64_t *mem, int64_t addr, char *dst, int max, int64_t nwords) { int i = 0, c; if (max < 1) return -1; if (!bop_ok(addr, 1, nwords)) { dst[0] = 0; return -1; } while (i < max - 1 && bop_ok(addr + i, 1, nwords)) { c = (int)bop_load(mem, addr + i, 1); if (!c) break; dst[i++] = (char)c; } dst[i] = 0; return i; } /* how many of the next n bytes, starting at addr, lie inside the image */ static int bop_span(int64_t addr, int n, int64_t nwords) { int i; if (n <= 0) return 0; for (i = 0; i < n; i++) if (!bop_ok(addr + i, 1, nwords)) return i; return n; } #endif