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
|
#include <fmt/format.h>
#include <iostream>
#include "uarch/core.h"
fetch_stage::fetch_stage(core &c)
: c(c)
, pc(c.checker.pc)
{ }
decode_stage::decode_stage(core &c)
: c(c)
, acc(c.checker.acc)
, link(c.checker.link)
, mq(c.checker.mq)
, pc(c.checker.pc)
, ctlregs(c.checker.ctlregs)
, icount(c.checker.icount)
{ }
void fetch_stage::clock() {
if (c.fetch_restarto.has_value()) {
auto &r = *c.fetch_restarto;
pte(r.tr, "!");
gen = r.new_gen;
pc = r.new_pc;
didrestart = true;
c.fetch_restarto.reset();
}
if (c.fetch_bundlep.can_write()) {
fetch_bundle b;
b.tr = infra::pt::toplevel();
b.gen = gen;
b.pc = pc;
b.word = c.mem.fetch(pc);
if (didrestart)
infra::pt::event(b.tr, ">", now-1, "");
pte(b.tr, "F");
c.fetch_bundlep.write(std::move(b));
pc = (pc & 070000) | ((pc + 1) & 007777);
didrestart = false;
}
}
void decode_stage::clock() {
bool progress = ctlregs[HALTED];
if (!ctlregs[HALTED] && c.fetch_bundlep.can_read()) {
auto b = c.fetch_bundlep.read();
if (b.gen != gen)
goto bail_out;
if (b.pc != pc) {
pte(b.tr, "~");
fetch_restart r;
r.tr = b.tr;
r.new_gen = ++gen;
r.new_pc = pc;
c.fetch_restarto = std::move(r);
goto bail_out;
}
progress = true;
pte(b.tr, "E");
inst = decode(ctlregs[FLAGS],
pc,
c.mem.fetch(pc),
interrupt);
auto next_pc = inst.next_pc;
if (inst.need_indirect_load) {
auto addr = c.mem.fetch(inst.init_address.value());
if (inst.need_autoinc_store) {
addr = (addr + 1) & 07777;
c.mem.store(*inst.init_address, addr);
}
auto df = (ctlregs[FLAGS] & FLAG_DF) >> FLAG_DF_SHIFT;
inst.final_address = (df << 12) | addr;
} else {
assert(!inst.need_autoinc_store);
}
pte(b.tr, "", inst.disasm());
if (inst.need_exec_load)
inst.data = c.mem.fetch(inst.final_address.value());
if (inst.need_read_acc)
inst.acc = acc;
if (inst.need_read_link)
inst.link = link;
if (inst.need_read_mq)
inst.mq = mq;
if (inst.read_ctlreg.has_value())
inst.ctlval = ctlregs[*inst.read_ctlreg];
inst.execute();
if (inst.need_write_acc)
acc = inst.acc.value();
if (inst.need_write_link)
link = inst.link.value();
if (inst.need_write_mq)
mq = inst.mq.value();
if (inst.write_ctlreg.has_value())
ctlregs[*inst.write_ctlreg] = inst.ctlval.value();
if (inst.need_exec_store)
c.mem.store(inst.final_address.value(), inst.data.value());
assert(inst.next_pc == next_pc || inst.possibly_redirects);
pc = inst.next_pc;
}
bail_out:
if (progress)
interrupt = c.system.interact(icount++, ctlregs);
if (c.checker.icount != icount) {
assert(c.checker.icount + 1 == icount);
c.checker.execute();
assert(c.checker.icount == icount);
std::cerr << fmt::format("icount={:} pc={:05o} checkerpc={:05o}\n", icount, pc, c.checker.pc);
assert(pc == c.checker.pc);
assert(acc == c.checker.acc);
assert(link == c.checker.link);
assert(mq == c.checker.mq);
assert(ctlregs == c.checker.ctlregs);
if (inst.init_address.has_value())
assert(c.mem.fetch(*inst.init_address) == c.checker.mem.fetch(*inst.init_address));
if (inst.final_address.has_value())
assert(c.mem.fetch(*inst.final_address) == c.checker.mem.fetch(*inst.final_address));
assert(c.mem.fetch(pc) == c.checker.mem.fetch(pc));
}
}
|