aboutsummaryrefslogtreecommitdiff
path: root/src/core/bops.h
blob: a7ef0d92a4ebcab7460d98e3dec6c8868b44bc50 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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