aboutsummaryrefslogtreecommitdiff
path: root/src/core/bops.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/bops.h')
-rw-r--r--src/core/bops.h87
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