diff options
Diffstat (limited to 'src/core/bops.h')
| -rw-r--r-- | src/core/bops.h | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/src/core/bops.h b/src/core/bops.h new file mode 100644 index 0000000..a7ef0d9 --- /dev/null +++ b/src/core/bops.h @@ -0,0 +1,87 @@ +/* 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 <stdint.h> + +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 |
