summaryrefslogtreecommitdiff
path: root/uarch
diff options
context:
space:
mode:
Diffstat (limited to 'uarch')
-rw-r--r--uarch/exec.cpp138
-rw-r--r--uarch/exec.h29
-rw-r--r--uarch/fetch.cpp129
-rw-r--r--uarch/fetch.h28
-rw-r--r--uarch/memory.cpp46
-rw-r--r--uarch/memory.h21
-rw-r--r--uarch/types.h30
-rw-r--r--uarch/uarch.d2
8 files changed, 423 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}
diff --git a/uarch/exec.h b/uarch/exec.h
new file mode 100644
index 0000000..1cfc525
--- /dev/null
+++ b/uarch/exec.h
@@ -0,0 +1,29 @@
1#pragma once
2
3#include <memory>
4
5#include "aisa/aisa.h"
6#include "aisa/simple-models.h"
7#include "sim/sim.h"
8#include "sim/queue.h"
9#include "uarch/types.h"
10
11namespace uarch {
12
13 struct ExecStage : public sim::Schedulable, aisa::TaskStack, aisa::VectorRF {
14 sim::Queue<Uop> &execq;
15 sim::Queue<FillReq> &fillreqq;
16 sim::Queue<Fill> &fillq;
17 sim::Queue<Store> &storeq;
18
19 std::unique_ptr<const aisa::Step> step;
20 aisa::Wires wires;
21 bool outstanding_fill = false;
22 bool fill_complete = false;
23
24 ExecStage(sim::Scheduler &scheduler, sim::Queue<Uop> &execq, sim::Queue<FillReq> &fillreqq, sim::Queue<Fill> &fillq, sim::Queue<Store> &storeq);
25
26 void clock() override;
27 };
28
29}
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}
diff --git a/uarch/fetch.h b/uarch/fetch.h
new file mode 100644
index 0000000..452b207
--- /dev/null
+++ b/uarch/fetch.h
@@ -0,0 +1,28 @@
1#pragma once
2
3#include <memory>
4
5#include "aisa/aisa.h"
6#include "aisa/simple-models.h"
7#include "sim/sim.h"
8#include "sim/queue.h"
9#include "uarch/types.h"
10
11namespace uarch {
12
13 struct FetchStage : public sim::Schedulable, aisa::TaskStack, aisa::VectorRF {
14 sim::Queue<FillReq> &fillreqq;
15 sim::Queue<Fill> &fillq;
16 sim::Queue<Uop> &uopq;
17
18 std::unique_ptr<const aisa::Step> step;
19 aisa::Wires wires;
20 bool outstanding_fill = false;
21 bool fill_complete = false;
22
23 FetchStage(sim::Scheduler &scheduler, const aisa::ISA &isa, sim::Queue<FillReq> &fillreqq, sim::Queue<Fill> &fillq, sim::Queue<Uop> &uopq);
24
25 void clock() override;
26 };
27
28}
diff --git a/uarch/memory.cpp b/uarch/memory.cpp
new file mode 100644
index 0000000..5cf9920
--- /dev/null
+++ b/uarch/memory.cpp
@@ -0,0 +1,46 @@
1#include <algorithm>
2#include <cstdint>
3#include <initializer_list>
4#include <iostream>
5#include <set>
6#include <utility>
7#include <vector>
8
9#include "aisa/aisa.h"
10#include "uarch/memory.h"
11#include "util/assert.h"
12
13namespace uarch {
14
15 MemStage::MemStage(sim::Scheduler &scheduler, sim::Queue<FillReq> &fillreqq, const std::initializer_list<sim::Queue<Fill> *> &fillqs, sim::Queue<Store> &storeq)
16 : sim::Schedulable(scheduler)
17 , fillreqq(fillreqq)
18 , storeq(storeq)
19 {
20 fillreqq.add_reader(this);
21 for (const auto &q : fillqs)
22 q->add_writer(this);
23 storeq.add_reader(this);
24 }
25
26 void MemStage::clock()
27 {
28 if (storeq.available()) {
29 auto s = storeq.read();
30 std::uint64_t x = 0;
31 for (unsigned int i = 0; i < s.bytes.size(); ++i)
32 x |= static_cast<std::uint64_t>(s.bytes[i]) << 8 * i;
33 std::cout << "mem stores " << s.bytes.size() << " bytes to " << s.physical_addr << " <- " << x << "\n";
34 ASSERT(store_mem(s.physical_addr, s.bytes.data(), s.bytes.size()), "Could not complete store");
35 } else if (fillreqq.available()) {
36 auto r = fillreqq.read();
37 std::cout << "mem fills " << r.size << " bytes from " << r.physical_addr << "\n";
38 Fill f;
39 f.physical_addr = r.physical_addr;
40 f.bytes.resize(r.size);
41 ASSERT(fetch_mem(f.bytes.data(), r.physical_addr, r.size), "Could not complete fill");
42 r.fillq->write(std::move(f));
43 }
44 }
45
46}
diff --git a/uarch/memory.h b/uarch/memory.h
new file mode 100644
index 0000000..f36e375
--- /dev/null
+++ b/uarch/memory.h
@@ -0,0 +1,21 @@
1#pragma once
2
3#include <initializer_list>
4
5#include "aisa/simple-models.h"
6#include "sim/sim.h"
7#include "sim/queue.h"
8#include "uarch/types.h"
9
10namespace uarch {
11
12 struct MemStage : public sim::Schedulable, aisa::PagedMem<> {
13 sim::Queue<FillReq> &fillreqq;
14 sim::Queue<Store> &storeq;
15
16 MemStage(sim::Scheduler &scheduler, sim::Queue<FillReq> &fillreqq, const std::initializer_list<sim::Queue<Fill> *> &fillqs, sim::Queue<Store> &storeq);
17
18 void clock() override;
19 };
20
21}
diff --git a/uarch/types.h b/uarch/types.h
new file mode 100644
index 0000000..481b8fe
--- /dev/null
+++ b/uarch/types.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include <vector>
4
5#include "aisa/aisa.h"
6#include "aisa/simple-models.h"
7#include "sim/queue.h"
8
9namespace uarch {
10
11 struct Fill {
12 aisa::addr_t physical_addr;
13 std::vector<aisa::byte_t> bytes;
14 };
15
16 struct FillReq {
17 sim::Queue<Fill> *fillq;
18 aisa::addr_t physical_addr;
19 aisa::addr_t size;
20 };
21
22 struct Store {
23 aisa::addr_t physical_addr;
24 std::vector<aisa::byte_t> bytes;
25 };
26
27 struct Uop : public aisa::TaskStack, aisa::VectorRF {
28 };
29
30}
diff --git a/uarch/uarch.d b/uarch/uarch.d
new file mode 100644
index 0000000..e99bf71
--- /dev/null
+++ b/uarch/uarch.d
@@ -0,0 +1,2 @@
1uarch_SODEPS += build/libaisa.so
2uarch_SODEPS += build/libsim.so