forked from sysprog21/rv32emu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathio.c
144 lines (129 loc) · 3.56 KB
/
io.c
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "io.h"
static const uint32_t mask_lo = 0xffff;
static const uint32_t mask_hi = ~(0xffff);
memory_t *memory_new()
{
memory_t *m = malloc(sizeof(memory_t));
memset(m->chunks, 0, sizeof(m->chunks));
return m;
}
void memory_delete(memory_t *m)
{
if (!m)
return;
for (uint32_t i = 0; i < (sizeof(m->chunks) / sizeof(chunk_t *)); i++) {
chunk_t *c = m->chunks[i];
if (c)
free(c);
}
free(m);
}
void memory_read(memory_t *m, uint8_t *dst, uint32_t addr, uint32_t size)
{
/* test if this read is entirely within one chunk */
if ((addr & mask_hi) == ((addr + size) & mask_hi)) {
chunk_t *c;
if ((c = m->chunks[addr >> 16])) {
/* get the subchunk pointer */
const uint32_t p = (addr & mask_lo);
/* copy over the data */
memcpy(dst, c->data + p, size);
} else {
memset(dst, 0, size);
}
} else {
/* naive copy */
for (uint32_t i = 0; i < size; ++i) {
uint32_t p = addr + i;
chunk_t *c = m->chunks[p >> 16];
dst[i] = c ? c->data[p & 0xffff] : 0;
}
}
}
uint32_t memory_read_str(memory_t *m, uint8_t *dst, uint32_t addr, uint32_t max)
{
uint32_t len = 0;
const uint8_t *end = dst + max;
for (;; ++len, ++dst) {
uint8_t ch = 0;
memory_read(m, &ch, addr + len, 1);
if (dst < end)
*dst = ch;
if (!ch)
break;
}
return len + 1;
}
uint32_t memory_read_ifetch(memory_t *m, uint32_t addr)
{
const uint32_t addr_lo = addr & mask_lo;
assert((addr_lo & 1) == 0);
chunk_t *c = m->chunks[addr >> 16];
assert(c);
return *(const uint32_t *) (c->data + addr_lo);
}
uint32_t memory_read_w(memory_t *m, uint32_t addr)
{
const uint32_t addr_lo = addr & mask_lo;
if (addr_lo <= 0xfffc) { /* test if this is within one chunk */
chunk_t *c;
if ((c = m->chunks[addr >> 16]))
return *(const uint32_t *) (c->data + addr_lo);
return 0u;
}
uint32_t dst = 0;
memory_read(m, (uint8_t *) &dst, addr, 4);
return dst;
}
uint16_t memory_read_s(memory_t *m, uint32_t addr)
{
const uint32_t addr_lo = addr & mask_lo;
if (addr_lo <= 0xfffe) { /* test if this is within one chunk */
chunk_t *c;
if ((c = m->chunks[addr >> 16]))
return *(const uint16_t *) (c->data + addr_lo);
return 0u;
}
uint16_t dst = 0;
memory_read(m, (uint8_t *) &dst, addr, 2);
return dst;
}
uint8_t memory_read_b(memory_t *m, uint32_t addr)
{
chunk_t *c;
if ((c = m->chunks[addr >> 16]))
return *(c->data + (addr & 0xffff));
return 0u;
}
void memory_write(memory_t *m, uint32_t addr, const uint8_t *src, uint32_t size)
{
for (uint32_t i = 0; i < size; ++i) {
uint32_t p = addr + i;
uint32_t x = p >> 16;
chunk_t *c = m->chunks[x];
if (!c) {
c = malloc(sizeof(chunk_t));
memset(c->data, 0, sizeof(c->data));
m->chunks[x] = c;
}
c->data[p & 0xffff] = src[i];
}
}
void memory_fill(memory_t *m, uint32_t addr, uint32_t size, uint8_t val)
{
for (uint32_t i = 0; i < size; ++i) {
uint32_t p = addr + i;
uint32_t x = p >> 16;
chunk_t *c = m->chunks[x];
if (!c) {
c = malloc(sizeof(chunk_t));
memset(c->data, 0, sizeof(c->data));
m->chunks[x] = c;
}
c->data[p & 0xffff] = val;
}
}