summaryrefslogtreecommitdiff
path: root/uarch/core.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--uarch/core.cpp348
1 files changed, 275 insertions, 73 deletions
diff --git a/uarch/core.cpp b/uarch/core.cpp
index 8b2db9b..12f8b5b 100644
--- a/uarch/core.cpp
+++ b/uarch/core.cpp
@@ -10,23 +10,30 @@ fetch_stage::fetch_stage(core &c)
10 10
11decode_stage::decode_stage(core &c) 11decode_stage::decode_stage(core &c)
12 : c(c) 12 : c(c)
13 , pc(c.checker.pc)
14 , icount(c.checker.icount)
15{ }
16
17indir_stage::indir_stage(core &c)
18 : c(c)
19{ }
20
21exec_stage::exec_stage(core &c)
22 : c(c)
13 , acc(c.checker.acc) 23 , acc(c.checker.acc)
14 , link(c.checker.link) 24 , link(c.checker.link)
15 , mq(c.checker.mq) 25 , mq(c.checker.mq)
16 , pc(c.checker.pc) 26 , pc(c.checker.pc)
17 , ctlregs(c.checker.ctlregs) 27 , ctlregs(c.checker.ctlregs)
18 , icount(c.checker.icount)
19{ } 28{ }
20 29
21void fetch_stage::clock() { 30void fetch_stage::clock() {
22 if (c.fetch_restarto.has_value()) { 31 if (c.restarto.has_value()) {
23 auto &r = *c.fetch_restarto; 32 auto &r = *c.restarto;
24 pte(r.tr, "!"); 33 pte(r.tr, "!", fmt::format("newpc={:05o}", r.new_pc));
25 gen = r.new_gen;
26 pc = r.new_pc; 34 pc = r.new_pc;
27 didrestart = true; 35 didrestart = true;
28 outstandingfill = false; 36 outstandingfill = false;
29 c.fetch_restarto.reset();
30 } 37 }
31 38
32 if (c.fetch_mem_responsep.can_read()) { 39 if (c.fetch_mem_responsep.can_read()) {
@@ -38,11 +45,11 @@ void fetch_stage::clock() {
38 fetch_bundle b; 45 fetch_bundle b;
39 if (auto t = cache.fetchline(b.data, pc); t.has_value()) { 46 if (auto t = cache.fetchline(b.data, pc); t.has_value()) {
40 b.tr = infra::pt::toplevel(); 47 b.tr = infra::pt::toplevel();
41 b.gen = gen; 48 b.gen = c.gen;
42 b.pc = pc; 49 b.pc = pc;
43 if (didrestart) 50 if (didrestart)
44 infra::pt::event(b.tr, ">", now-1, ""); 51 infra::pt::event(b.tr, ">", now-1, "");
45 pte(b.tr, "F", fmt::format("pc={:05o}", b.pc)); 52 pte(b.tr, "F");
46 c.fetch_bundlep.write(std::move(b)); 53 c.fetch_bundlep.write(std::move(b));
47 pc = (pc & 070000) | (((pc & ~memory::LINE_BYTE_OFFSET_MASK) + memory::LINE_BYTES) & 007777); 54 pc = (pc & 070000) | (((pc & ~memory::LINE_BYTE_OFFSET_MASK) + memory::LINE_BYTES) & 007777);
48 didrestart = false; 55 didrestart = false;
@@ -50,114 +57,309 @@ void fetch_stage::clock() {
50 } 57 }
51 } 58 }
52 59
53 if (!outstandingfill && c./*fetch_*/mem_commandp.can_write() && !cache.probe(pc)) { 60 if (!outstandingfill && c.fetch_mem_commandp.can_write() && !cache.probe(pc)) {
54 memory::dram::command fr; 61 memory::dram::command fr;
55 fr.transaction = infra::pt::toplevel(); 62 fr.transaction = infra::pt::toplevel();
63 pte(fr.transaction, "p", fmt::format("fpc={:05o}", pc));
56 fr.line_address = pc >> memory::LINE_BYTES_LOG2; 64 fr.line_address = pc >> memory::LINE_BYTES_LOG2;
57 fr.responsep = &c.fetch_mem_responsep; 65 fr.responsep = &c.fetch_mem_responsep;
58 c./*fetch_*/mem_commandp.write(std::move(fr)); 66 c.fetch_mem_commandp.write(std::move(fr));
59 outstandingfill = true; 67 outstandingfill = true;
60 } 68 }
61} 69}
62 70
63void decode_stage::clock() { 71void decode_stage::clock() {
64 bool progress = ctlregs[HALTED]; 72 if (c.restarto.has_value()) {
73 auto &r = *c.restarto;
74 pc = r.new_pc;
75 interrupt |= r.interrupt;
76 icount = c.icount;
77 }
65 78
66 if (!ctlregs[HALTED] && c.fetch_bundlep.can_read()) { 79 if (c.fetch_bundlep.can_read() && c.decode_mem_commandp.can_write() && c.indir_instp.can_write() && c.decode_to_exec_instp.can_write()) {
67 auto b = c.fetch_bundlep.peek(); 80 auto b = c.fetch_bundlep.peek();
68 81
69 if (b.gen != gen) 82 if (b.gen != c.gen) {
70 goto bail_out; 83 pte(b.tr, "~");
84 c.fetch_bundlep.discard();
85 return;
86 }
71 87
72 if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) { 88 if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) {
89 if (!c.restarto.has_value()) {
90 restart r;
91 r.tr = b.tr;
92 r.new_pc = pc;
93 r.interrupt = false;
94 ++c.gen;
95 c.restarto = std::move(r);
96 }
73 pte(b.tr, "~"); 97 pte(b.tr, "~");
74 fetch_restart r;
75 r.tr = b.tr;
76 r.new_gen = ++gen;
77 r.new_pc = pc;
78 c.fetch_restarto = std::move(r);
79 c.fetch_bundlep.discard(); 98 c.fetch_bundlep.discard();
80 goto bail_out; 99 return;
81 } 100 }
82 101
83 progress = true; 102 inst_bundle i;
84 103
85 auto tr = infra::pt::child(b.tr); 104 i.tr = infra::pt::child(b.tr);
105 i.gen = c.gen;
106 i.pc = pc;
107 i.icount = icount++;
86 108
87 pte(tr, "E"); 109 pte(i.tr, "D");
88 110
89 inst = decode(ctlregs[FLAGS], 111 i.inst = decode(c.exec.ctlregs[FLAGS],
90 pc, 112 pc,
91 b.data[pc & memory::LINE_BYTE_OFFSET_MASK], 113 b.data[pc & memory::LINE_BYTE_OFFSET_MASK],
92 interrupt); 114 interrupt);
93 auto next_pc = inst.next_pc; 115 interrupt = false;
116
117 pte(i.tr, "", fmt::format("{:05o}: {}", pc, i.inst.disasm()));
118
119 pc = i.inst.next_pc;
120
121 if (i.inst.need_indirect_load) {
122 memory::dram::command fr;
123 fr.transaction = i.tr;
124 fr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2;
125 fr.responsep = &c.indir_mem_responsep;
126 pte(i.tr, "", fmt::format("iload={:05o}", *i.inst.init_address));
127 c.decode_mem_commandp.write(std::move(fr));
128 c.indir_instp.write(std::move(i));
129 } else {
130 if (i.inst.need_exec_load) {
131 memory::dram::command fr;
132 fr.transaction = i.tr;
133 fr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2;
134 fr.responsep = &c.exec_mem_responsep;
135 pte(i.tr, "", fmt::format("load={:05o}", *i.inst.final_address));
136 c.decode_mem_commandp.write(std::move(fr));
137 }
138 c.decode_to_exec_instp.write(std::move(i));
139 }
140
141 if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) {
142 pte(b.tr, "~");
143 c.fetch_bundlep.discard();
144 }
145 }
146}
147
148void indir_stage::clock() {
149 if (c.restarto.has_value()) {
150 gen = c.gen;
151 }
152
153 if (c.indir_instp.can_read() && c.indir_mem_load_commandp.can_write() && c.indir_mem_store_commandp.can_write() && c.indir_to_exec_instp.can_write()) {
154 auto &i = c.indir_instp.peek();
155
156 if (i.gen != gen && i.gen != c.gen) {
157 pte(i.tr, "~");
158 c.indir_instp.discard();
159 return;
160 } else if (i.gen != gen) {
161 gen = c.gen;
162 assert(i.gen == gen);
163 }
94 164
95 if (inst.need_indirect_load) { 165 if (i.inst.need_indirect_load && !c.indir_mem_responsep.can_read())
96 auto addr = c.mem.fetch(inst.init_address.value()); 166 return;
97 if (inst.need_autoinc_store) { 167
168 if (i.inst.need_indirect_load) {
169 auto l = c.indir_mem_responsep.read();
170 if (l.line_address != i.inst.init_address.value() >> memory::LINE_BYTES_LOG2)
171 return;
172 auto addr = l.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK];
173 if (i.inst.need_autoinc_store) {
98 addr = (addr + 1) & 07777; 174 addr = (addr + 1) & 07777;
99 c.mem.store(*inst.init_address, addr); 175 pte(i.tr, "+", fmt::format("istore={:05o} istoredata={:04o}", *i.inst.init_address, addr));
176 memory::dram::command sr;
177 sr.transaction = i.tr;
178 sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2;
179 sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr;
180 sr.mask.fill(false);
181 sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true;
182 sr.write = true;
183 c.indir_mem_store_commandp.write(std::move(sr));
184 } else {
185 pte(i.tr, "I");
100 } 186 }
101 auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT; 187 auto df = (c.exec.ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT;
102 inst.final_address = (df << 12) | addr; 188 i.inst.final_address = (unsigned int)((df << 12) | addr);
103 } else {
104 assert(!inst.need_autoinc_store);
105 } 189 }
106 190
107 pte(tr, "", inst.disasm()); 191 if (i.inst.need_exec_load) {
192 memory::dram::command fr;
193 fr.transaction = i.tr;
194 fr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2;
195 fr.responsep = &c.exec_mem_responsep;
196 pte(i.tr, "", fmt::format("load={:05o}", *i.inst.final_address));
197 c.indir_mem_load_commandp.write(std::move(fr));
198 }
108 199
109 if (inst.need_exec_load) 200 c.indir_to_exec_instp.write(std::move(i));
110 inst.data = c.mem.fetch(inst.final_address.value());
111 201
112 if (inst.need_read_acc) 202 c.indir_instp.discard();
113 inst.acc = acc; 203 }
114 if (inst.need_read_link) 204}
115 inst.link = link; 205
116 if (inst.need_read_mq) 206void exec_stage::clock() {
117 inst.mq = mq; 207 c.restarto.reset();
118 if (inst.read_ctlreg.has_value()) 208
119 inst.ctlval = ctlregs[*inst.read_ctlreg]; 209 std::optional<infra::transaction> restarttr;
210
211 bool progress = ctlregs[HALTED];
120 212
121 inst.execute(); 213 if (!ctlregs[HALTED] && (c.decode_to_exec_instp.can_read() || c.indir_to_exec_instp.can_read()) && c.exec_mem_commandp.can_write()) {
214 infra::port<inst_bundle> *instp = nullptr;
215 if (c.decode_to_exec_instp.can_read()) {
216 auto &i = c.decode_to_exec_instp.peek();
217 if (i.gen != gen && i.gen != c.gen) {
218 pte(i.tr, "~");
219 if (i.inst.need_autoinc_store) {
220 auto addr = (*i.inst.final_address - 1) & 07777;
221 pte(i.tr, "", fmt::format("unstore={:05o}, unstoredata={:04o}", *i.inst.init_address, addr));
222 memory::dram::command sr;
223 sr.transaction = i.tr;
224 sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2;
225 sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr;
226 sr.mask.fill(false);
227 sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true;
228 sr.write = true;
229 c.exec_mem_commandp.write(std::move(sr));
230 }
231 c.decode_to_exec_instp.discard();
232 } else if (i.icount == c.icount) {
233 instp = &c.decode_to_exec_instp;
234 }
235 }
236 if (c.indir_to_exec_instp.can_read()) {
237 auto &i = c.indir_to_exec_instp.peek();
238 if (i.gen != gen && i.gen != c.gen) {
239 pte(i.tr, "~");
240 if (i.inst.need_autoinc_store) {
241 auto addr = (*i.inst.final_address - 1) & 07777;
242 pte(i.tr, "", fmt::format("unstore={:05o}, unstoredata={:04o}", *i.inst.init_address, addr));
243 memory::dram::command sr;
244 sr.transaction = i.tr;
245 sr.line_address = *i.inst.init_address >> memory::LINE_BYTES_LOG2;
246 sr.data[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = addr;
247 sr.mask.fill(false);
248 sr.mask[*i.inst.init_address & memory::LINE_BYTE_OFFSET_MASK] = true;
249 sr.write = true;
250 c.exec_mem_commandp.write(std::move(sr));
251 }
252 c.indir_to_exec_instp.discard();
253 } else if (i.icount == c.icount) {
254 instp = &c.indir_to_exec_instp;
255 }
256 }
257 if (!instp)
258 goto bail_out;
259 if (!c.exec_mem_commandp.can_write())
260 goto bail_out;
261 auto &i = instp->peek();
122 262
123 if (inst.need_write_acc) 263 assert(i.gen == gen || i.gen == c.gen);
124 acc = inst.acc.value(); 264 if (i.gen != gen) {
125 if (inst.need_write_link) 265 gen = c.gen;
126 link = inst.link.value(); 266 assert(i.gen == gen);
127 if (inst.need_write_mq) 267 }
128 mq = inst.mq.value();
129 if (inst.write_ctlreg.has_value())
130 ctlregs[*inst.write_ctlreg] = inst.ctlval.value();
131 268
132 if (inst.need_exec_store) 269 if (i.inst.need_exec_load && !c.exec_mem_responsep.can_read())
133 c.mem.store(inst.final_address.value(), inst.data.value()); 270 return;
134 271
135 assert(inst.next_pc == next_pc || inst.possibly_redirects); 272 if (i.inst.need_exec_load) {
136 pc = inst.next_pc; 273 auto l = c.exec_mem_responsep.read();
274 if (l.line_address != i.inst.final_address.value() >> memory::LINE_BYTES_LOG2)
275 return;
276 i.inst.data = l.data[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK];
277 pte(i.tr, "", fmt::format("loaddata={:04o}", *i.inst.data));
278 }
137 279
138 if ((b.pc >> memory::LINE_BYTES_LOG2) != (pc >> memory::LINE_BYTES_LOG2)) 280 pte(i.tr, "E");
139 c.fetch_bundlep.discard(); 281 progress = true;
282
283 assert(i.pc == pc);
284
285 auto next_pc = i.inst.next_pc;
286
287 if (i.inst.need_read_acc)
288 i.inst.acc = acc;
289 if (i.inst.need_read_link)
290 i.inst.link = link;
291 if (i.inst.need_read_mq)
292 i.inst.mq = mq;
293 if (i.inst.read_ctlreg.has_value())
294 i.inst.ctlval = ctlregs[*i.inst.read_ctlreg];
295
296 i.inst.execute();
297
298 if (i.inst.need_write_acc)
299 acc = i.inst.acc.value();
300 if (i.inst.need_write_link)
301 link = i.inst.link.value();
302 if (i.inst.need_write_mq)
303 mq = i.inst.mq.value();
304 if (i.inst.write_ctlreg.has_value()) {
305 ctlregs[*i.inst.write_ctlreg] = i.inst.ctlval.value();
306 restarttr = i.tr;
307 }
308
309 if (i.inst.need_exec_store) {
310 pte(i.tr, "", fmt::format("store={:05o} storedata={:04o}", *i.inst.final_address, *i.inst.data));
311 memory::dram::command sr;
312 sr.transaction = i.tr;
313 sr.line_address = *i.inst.final_address >> memory::LINE_BYTES_LOG2;
314 sr.data[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK] = *i.inst.data;
315 sr.mask.fill(false);
316 sr.mask[*i.inst.final_address & memory::LINE_BYTE_OFFSET_MASK] = true;
317 sr.write = true;
318 c.exec_mem_commandp.write(std::move(sr));
319 }
320
321 assert(i.inst.next_pc == next_pc || i.inst.possibly_redirects);
322 pc = i.inst.next_pc;
323
324 if (pc != next_pc) {
325 pte(i.tr, "", fmt::format("jump={:05o}", pc));
326 restarttr = i.tr;
327 }
328
329 instp->discard();
140 } 330 }
331
141bail_out: 332bail_out:
333 bool interrupt = false;
142 334
143 if (progress) 335 if (progress) {
144 interrupt = c.system.interact(icount++, ctlregs); 336 auto oldctlregs = ctlregs;
337 interrupt = c.system.interact(c.icount++, ctlregs);
338 if (interrupt || oldctlregs != ctlregs)
339 if (!restarttr.has_value())
340 restarttr = infra::pt::toplevel();
341 }
342
343 if (restarttr.has_value()) {
344 restart r;
345 r.tr = *restarttr;
346 r.new_pc = pc;
347 r.interrupt = interrupt;
348 gen = ++c.gen;
349 c.restarto = std::move(r);
350 }
145 351
146 if (c.checker.icount != icount) { 352 if (c.checker.icount != c.icount) {
147 assert(c.checker.icount + 1 == icount); 353 assert(c.checker.icount + 1 == c.icount);
148 354
149 c.checker.execute(); 355 c.checker.execute();
150 assert(c.checker.icount == icount); 356 assert(c.checker.icount == c.icount);
151// std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", icount, pc, c.checker.pc); 357// std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", c.icount, pc, c.checker.pc);
152 assert(pc == c.checker.pc); 358 assert(pc == c.checker.pc);
153 assert(acc == c.checker.acc); 359 assert(acc == c.checker.acc);
154 assert(link == c.checker.link); 360 assert(link == c.checker.link);
155 assert(mq == c.checker.mq); 361 assert(mq == c.checker.mq);
156 assert(ctlregs == c.checker.ctlregs); 362 assert(ctlregs == c.checker.ctlregs);
157 if (inst.init_address.has_value())
158 assert(c.mem.fetch(*inst.init_address) == c.checker.mem.fetch(*inst.init_address));
159 if (inst.final_address.has_value())
160 assert(c.mem.fetch(*inst.final_address) == c.checker.mem.fetch(*inst.final_address));
161 assert(c.mem.fetch(pc) == c.checker.mem.fetch(pc));
162 } 363 }
364
163} 365}