summaryrefslogtreecommitdiff
path: root/uarch/exec.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--uarch/exec.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/uarch/exec.cpp b/uarch/exec.cpp
new file mode 100644
index 0000000..e40813b
--- /dev/null
+++ b/uarch/exec.cpp
@@ -0,0 +1,138 @@
1#include <algorithm>
2#include <deque>
3#include <iostream>
4#include <optional>
5#include <set>
6#include <string>
7#include <type_traits>
8#include <utility>
9#include <vector>
10
11#include "uarch/exec.h"
12#include "util/assert.h"
13
14namespace uarch {
15
16 ExecStage::ExecStage(sim::Scheduler &scheduler, sim::Queue<Uop> &execq, sim::Queue<FillReq> &fillreqq, sim::Queue<Fill> &fillq, sim::Queue<Store> &storeq)
17 : sim::Schedulable(scheduler)
18 , execq(execq)
19 , fillreqq(fillreqq)
20 , fillq(fillq)
21 , storeq(storeq)
22 {
23 execq.add_reader(this);
24 fillreqq.add_writer(this);
25 fillq.add_reader(this);
26 storeq.add_writer(this);
27 }
28
29 void ExecStage::clock()
30 {
31 if (tasks.empty() && !step && execq.available()) {
32 auto uop = execq.read();
33 std::cout << "exec accepts uop " << uop.top_task().value()->disasm() << "\n";
34 aisa::TaskStack::operator=(std::move(uop));
35 aisa::VectorRF::operator=(std::move(uop));
36 }
37
38 bool sent_store = false;
39 while (!sent_store) {
40 while (!step) {
41 auto t = top_task();
42 if (!t)
43 goto no_work;
44 const auto &task = **t;
45 auto s = task.step(load_reg(task.environment).value());
46 if (s.has_value()) {
47 step = std::move(s->first);
48 std::cout << "exec step " << step->disasm() << "\n";
49 wires = {};
50 outstanding_fill = false;
51 fill_complete = false;
52 ASSERT(store_reg(task.environment, s->second), "Could not write next environment value");
53 } else {
54 pop_task();
55 if (tasks.empty())
56 std::cout << "exec completes uop\n";
57 }
58 }
59
60 if (step->predicate.has_value()) {
61 auto x = load_reg(step->predicate->first);
62 if (x.has_value()) {
63 if (*x != step->predicate->second)
64 goto nextstep;
65 } else {
66 std::cout << "exec stalls on predicate register";
67 break;
68 }
69 }
70
71 wires.source_vals.reserve(step->source_regs.size());
72 for (unsigned int i = wires.source_vals.size(); i < step->source_regs.size(); ++i) {
73 auto x = load_reg(step->source_regs[i]);
74 if (!x.has_value()) {
75 std::cout << "exec stalls on source register";
76 break;
77 }
78 wires.source_vals.emplace_back(*x);
79 }
80
81 if (step->mop == aisa::MOp::LOAD && !fill_complete) {
82 auto mi = step->meminfo(wires);
83 if (outstanding_fill) {
84 for (unsigned int i = 0; i < fillq.available(); ++i) {
85 auto &fill = fillq.peek(i);
86 if (fill.physical_addr == mi.physical_addr) {
87 std::cout << "exec fills\n";
88 wires.memory_val = std::move(fill.bytes);
89 outstanding_fill = false;
90 fill_complete = true;
91 }
92 }
93 if (!fill_complete)
94 break;
95 } else {
96 std::cout << "exec sends fill request\n";
97 FillReq req;
98 req.fillq = &fillq;
99 req.physical_addr = mi.physical_addr;
100 req.size = mi.size;
101 fillreqq.write(std::move(req));
102 outstanding_fill = true;
103 fill_complete = false;
104 break;
105 }
106 }
107
108 step->evaluate(wires);
109
110 for (unsigned int i = 0; i < step->destination_regs.size(); ++i)
111 ASSERT(store_reg(step->destination_regs[i], wires.destination_vals[i]), "Could not write destination register");
112
113 if (step->mop == aisa::MOp::STORE) {
114 std::cout << "exec sends store\n";
115 auto mi = step->meminfo(wires);
116 Store store;
117 store.physical_addr = mi.physical_addr;
118 store.bytes = std::move(wires.memory_val);
119 storeq.write(std::move(store));
120 //sent_store = true;
121 }
122
123nextstep:
124 step = nullptr;
125 wires = {};
126 outstanding_fill = false;
127 fill_complete = false;
128 }
129
130no_work:
131
132 while (fillq.available()) {
133 std::cout << "exec consumes fill\n";
134 fillq.read();
135 }
136 }
137
138}