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