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
|