This repository has been archived by the owner on Jul 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmemory.c
210 lines (202 loc) · 6.35 KB
/
memory.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <assert.h>
#include <endian.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "memory.h"
#include "bus.h"
#include "common-data-bus.h"
#include "clk.h"
#include "lib/closure.h"
#include "lib/log.h"
#include "queue.h"
#include "reg.h"
#include "rv32i.h"
#include "rvmath.h"
#if BYTE_ORDER != LITTLE_ENDIAN
#error This program runs only on little endian architectures
#endif
word_t _mem_get_sz (memory_t *mem, addr_t addr,
ls_size_t size) {
void *base = &mem->data[addr];
switch (size) {
case LS_BYTE: return sign_extend(*(__uint8_t *) base, 8);
case LS_BYTEU: return *(__uint8_t *) base;
case LS_HWORD: return sign_extend(*(__uint16_t *) base, 16);
case LS_HWORDU: return *(__uint16_t *) base;
case LS_WORD: return *(__uint32_t *) base;
default:
debug_log("invalid size %d", size);
assert(0);
}
}
void _mem_set_sz (memory_t *mem, addr_t addr,
word_t value, ls_size_t size) {
void *base = &mem->data[addr];
switch (size) {
case LS_BYTE: *(__uint8_t *) base = value; break;
case LS_HWORD: *(__uint16_t *) base = value; break;
case LS_WORD: *(__uint32_t *) base = value; break;
default:
debug_log("invalid size %d", size);
assert(0);
}
}
void _mem_tick (void *state, va_list args) {
memory_t *mem = (memory_t *) state;
if (*rm_read(mem->clear, bool)) {
for (int i = 0; i < MEM_TICKS; ++i) {
bool busy = *rr_read(mem->store_requests_busy[i], bool);
reg_reduce_write(mem->store_requests_busy[i], &busy);
}
return;
}
bool load_requests_busy[MEM_TICKS];
bool store_requests_busy[MEM_TICKS];
for (int i = 0; i < MEM_TICKS; ++i) {
load_requests_busy[i] =
*rr_read(mem->load_requests_busy[i], bool);
store_requests_busy[i] =
*rr_read(mem->store_requests_busy[i], bool);
}
bool cdb_sent = false;
// load
for (int i = 0; i < MEM_TICKS; ++i) {
if (!load_requests_busy[i]) continue;
const struct mem_load_request_t *req =
rm_read(mem->load_requests[i],
struct mem_load_request_t);
struct mem_load_request_t *req_next =
&rm_write(mem->load_requests[i],
struct mem_load_request_t);
int ticks_remaining = --req_next->ticks_remaining;
if (!cdb_sent && ticks_remaining <= 0) {
// the common data bus cannot handle two msgs at once.
cdb_sent = true;
reg_mut_t *reg = bh_acquire(mem->cdb_helper);
if (!reg) continue;
cdb_message_t msg = req->base_msg;
msg.result = _mem_get_sz(mem, req->addr, req->size);
debug_log("mem writing to ROB #%02d addr %08x value %08x",
msg.rob, req->addr, msg.result);
rm_write(reg, cdb_message_t) = msg;
load_requests_busy[i] = false;
continue;
}
}
// store
for (int i = 0; i < MEM_TICKS; ++i) {
if (!store_requests_busy[i]) continue;
const struct mem_store_request_t *req =
rm_read(mem->store_requests[i],
struct mem_store_request_t);
struct mem_store_request_t *req_next =
&rm_write(mem->store_requests[i],
struct mem_store_request_t);
req_next->ticks_remaining = req->ticks_remaining - 1;
if (req_next->ticks_remaining == 0) {
_mem_set_sz(mem, req->addr, req->value, req->size);
debug_log("store addr %08x complete!", req->addr);
store_requests_busy[i] = false;
rm_write(req->callback, bool) = true;
}
}
for (int i = 0; i < MEM_TICKS; ++i) {
reg_reduce_write(mem->load_requests_busy[i],
&load_requests_busy[i]);
reg_reduce_write(mem->store_requests_busy[i],
&store_requests_busy[i]);
}
}
memory_t *mem_create (bus_t *cdb, clk_t *clk) {
memory_t *mem = (memory_t *) malloc(sizeof(memory_t));
memset(mem->data, 0, sizeof(mem->data));
for (int i = 0; i < MEM_TICKS; ++i) {
mem->load_requests[i] =
reg_mut_create(sizeof(struct mem_load_request_t), clk);
mem->store_requests[i] =
reg_mut_create(sizeof(struct mem_store_request_t), clk);
mem->load_requests_busy[i] = reg_or_create(clk);
mem->store_requests_busy[i] = reg_or_create(clk);
}
mem->cdb = cdb;
mem->cdb_helper = bh_create(cdb);
mem->clear = reg_mut_create(sizeof(bool), clk);
mem->clear->clear = true;
clk_add_callback(clk, closure_create(_mem_tick, mem));
return mem;
}
void mem_free (memory_t *mem) {
for (int i = 0; i < MEM_TICKS; ++i) {
reg_mut_free(mem->load_requests[i]);
reg_mut_free(mem->store_requests[i]);
reg_reduce_free(mem->load_requests_busy[i]);
reg_reduce_free(mem->store_requests_busy[i]);
}
bh_free(mem->cdb_helper);
free(mem);
}
void mem_set (memory_t *mem, addr_t addr, byte_t value) {
mem->data[addr] = value;
}
byte_t mem_get (memory_t *mem, addr_t addr) {
if (addr >= MEM_SIZE) {
debug_log("bad mem access addr %08x", addr);
return 0;
}
return mem->data[addr];
}
word_t mem_get_inst (memory_t *mem, addr_t addr) {
return _mem_get_sz(mem, addr, LS_WORD);
}
int _mem_acquire_load_req (memory_t *mem) {
for (int i = 0; i < MEM_SIZE; ++i) {
if (!*rr_read(mem->load_requests_busy[i], bool)) {
bool t = true;
reg_reduce_write(mem->load_requests_busy[i], &t);
return i;
}
}
return -1;
}
int _mem_acquire_store_req (memory_t *mem) {
for (int i = 0; i < MEM_SIZE; ++i) {
if (!*rr_read(mem->store_requests_busy[i], bool)) {
bool t = true;
reg_reduce_write(mem->store_requests_busy[i], &t);
return i;
}
}
return -1;
}
status_t mem_request_load (memory_t *mem, addr_t addr,
ls_size_t size, cdb_message_t base_msg) {
int id = _mem_acquire_load_req(mem);
if (id < 0) return STATUS_FAIL;
struct mem_load_request_t *req =
&rm_write(mem->load_requests[id],
struct mem_load_request_t);
req->addr = addr;
req->size = size;
req->ticks_remaining = MEM_TICKS - 1;
req->base_msg = base_msg;
return STATUS_SUCCESS;
}
status_t mem_request_store (memory_t *mem, addr_t addr,
word_t value, ls_size_t size, reg_mut_t *callback) {
int id = _mem_acquire_store_req(mem);
if (id < 0) return STATUS_FAIL;
struct mem_store_request_t *req =
&rm_write(mem->store_requests[id],
struct mem_store_request_t);
req->addr = addr;
req->value = value;
req->callback = callback;
req->size = size;
req->ticks_remaining = MEM_TICKS - 1;
return STATUS_SUCCESS;
}
void mem_clear (memory_t *mem) {
rm_write(mem->clear, bool) = true;
}