summaryrefslogtreecommitdiff
path: root/aisa
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--aisa/aisa.h52
-rw-r--r--aisa/async.h225
-rw-r--r--aisa/eval.h65
-rw-r--r--aisa/simple-models.h95
4 files changed, 371 insertions, 66 deletions
diff --git a/aisa/aisa.h b/aisa/aisa.h
index 3c260c1..4488529 100644
--- a/aisa/aisa.h
+++ b/aisa/aisa.h
@@ -1,20 +1,67 @@
1#pragma once 1#pragma once
2 2
3#include <cstdint> 3#include <cstdint>
4#include <memory>
4#include <optional> 5#include <optional>
6#include <string>
5#include <utility> 7#include <utility>
6#include <vector> 8#include <vector>
7 9
8namespace aisa { 10namespace aisa {
9 11
12 using addr_t = std::uint64_t;
13 using byte_t = std::uint8_t;
10 using regnum_t = std::uint_fast64_t; 14 using regnum_t = std::uint_fast64_t;
11 using regval_t = std::uint64_t; 15 using regval_t = std::uint64_t;
12 16
17 struct Task;
18
19 struct ISA {
20 virtual ~ISA() { }
21
22 virtual std::pair<std::unique_ptr<const Task>, regval_t> initial_task() const = 0;
23 };
24
25 struct Step;
26
27 struct Task {
28 regnum_t environment;
29
30 virtual ~Task() { }
31
32 virtual std::string disasm() const = 0;
33
34 virtual std::optional<std::pair<std::unique_ptr<const Step>, regval_t>> step(regval_t environment_val) const { return {}; }
35 };
36
37 struct MemInfo {
38 addr_t physical_addr;
39 addr_t size;
40 };
41
42 struct Wires {
43 std::vector<regval_t> source_vals;
44 std::vector<byte_t> memory_val;
45 bool aborted = false;
46 std::vector<regval_t> destination_vals;
47 std::optional<std::pair<std::unique_ptr<const Task>, regval_t>> new_task;
48 };
49
50 enum class MOp {
51 NONE,
52 LOAD,
53 STORE,
54 };
55
13 struct Step { 56 struct Step {
14 std::optional<std::pair<regnum_t, regval_t>> predicate; 57 std::optional<std::pair<regnum_t, regval_t>> predicate;
15 std::vector<regnum_t> source_regs; 58 std::vector<regnum_t> source_regs;
16 std::vector<regnum_t> destination_regs; 59 std::vector<regnum_t> destination_regs;
17 60
61 virtual ~Step() { }
62
63 virtual std::string disasm(const Wires *w = nullptr) const = 0;
64
18 std::optional<regnum_t> predicate_reg() const 65 std::optional<regnum_t> predicate_reg() const
19 { 66 {
20 if (predicate.has_value()) 67 if (predicate.has_value())
@@ -29,7 +76,10 @@ namespace aisa {
29 return {}; 76 return {};
30 } 77 }
31 78
32 virtual std::vector<regval_t> compute_destinations(const std::vector<regval_t> &source_vals) const = 0; 79 MOp mop = MOp::NONE;
80
81 virtual MemInfo meminfo(const Wires &wires) const { return {}; }
82 virtual void evaluate(Wires &wires) const { };
33 }; 83 };
34 84
35} 85}
diff --git a/aisa/async.h b/aisa/async.h
new file mode 100644
index 0000000..42e99e7
--- /dev/null
+++ b/aisa/async.h
@@ -0,0 +1,225 @@
1#pragma once
2
3#include <coroutine>
4#include <optional>
5#include <utility>
6#include <memory>
7#include <vector>
8
9#include "aisa/aisa.h"
10#include "aisa/coroutine.h" // IWYU pragma: export
11
12namespace aisa {
13
14 template<typename CRTP> struct AsyncEval {
15 CRTP & crtp() noexcept { return static_cast<CRTP &>(*this); }
16
17 task<regval_t> async_load_reg(regnum_t rn)
18 {
19 while (true) {
20 if (auto rv = crtp().load_reg(rn); rv.has_value())
21 co_return *rv;
22 co_await std::suspend_always{};
23 }
24 }
25
26 task<void> async_store_reg(regnum_t rn, regval_t rv)
27 {
28 while (true) {
29 if (crtp().store_reg(rn, rv))
30 co_return;
31 co_await std::suspend_always{};
32 }
33 }
34
35 task<void> async_fetch_mem(byte_t *bytes, addr_t physical_addr, addr_t size)
36 {
37 while (true) {
38 if (crtp().fetch_mem(bytes, physical_addr, size))
39 co_return;
40 co_await std::suspend_always{};
41 }
42 }
43
44 task<void> async_store_mem(addr_t physical_addr, const byte_t *bytes, addr_t size)
45 {
46 while (true) {
47 if (crtp().store_mem(physical_addr, bytes, size))
48 co_return;
49 co_await std::suspend_always{};
50 }
51 }
52
53 task<bool> async_predicate(const Step &step)
54 {
55 if (step.predicate.has_value()) {
56 regval_t pval = co_await crtp().async_load_reg(step.predicate->first);
57 co_return pval == step.predicate->second;
58 }
59 co_return true;
60 }
61
62 task<void> async_load_source_registers(const Step &step, Wires &w)
63 {
64 w.source_vals.resize(step.source_regs.size());
65 for (unsigned int i = 0; i < step.source_regs.size(); ++i)
66 w.source_vals[i] = co_await crtp().async_load_reg(step.source_regs[i]);
67 }
68
69 task<void> async_load_source_memory(const Step &step, const MemInfo &mi, Wires &w)
70 {
71 w.memory_val.resize(mi.size);
72 co_await crtp().async_fetch_mem(w.memory_val.data(), mi.physical_addr, mi.size);
73 }
74
75 task<void> async_load_sources(const Step &step, Wires &w)
76 {
77 co_await crtp().async_load_source_registers(step, w);
78
79 if (step.mop == MOp::LOAD) {
80 auto mi = step.meminfo(w);
81 co_await crtp().async_load_source_memory(step, mi, w);
82 }
83 }
84
85 task<void> async_write_destination_registers(const Step &step, const Wires &w)
86 {
87 for (unsigned int i = 0; i < step.destination_regs.size(); ++i)
88 co_await crtp().async_store_reg(step.destination_regs[i], w.destination_vals[i]);
89 }
90
91 task<void> async_write_destination_memory(const Step &step, const MemInfo &mi, const Wires &w)
92 {
93 co_await crtp().async_store_mem(mi.physical_addr, w.memory_val.data(), mi.size);
94 }
95
96 task<void> async_write_destinations(const Step &step, const Wires &w)
97 {
98 if (w.aborted)
99 co_return;
100
101 co_await crtp().async_write_destination_registers(step, w);
102
103 if (step.mop == MOp::STORE) {
104 auto mi = step.meminfo(w);
105 co_await crtp().async_write_destination_memory(step, mi, w);
106 }
107 }
108
109 task<void> async_push_task(std::unique_ptr<const Task> &&task)
110 {
111 while (true) {
112 if (crtp().push_task(std::move(task)))
113 co_return;
114 co_await std::suspend_always{};
115 }
116 }
117
118 task<void> async_new_task(std::unique_ptr<const Task> &&task, regval_t environment_val)
119 {
120 auto rn = task->environment;
121 co_await crtp().async_push_task(std::move(task));
122 co_await crtp().async_store_reg(rn, environment_val);
123 }
124
125 task<Wires> async_run_step(const Step &step)
126 {
127 Wires w;
128
129 if (!co_await crtp().async_predicate(step))
130 co_return std::move(w);
131
132 co_await crtp().async_load_sources(step, w);
133
134 step.evaluate(w);
135
136 co_await crtp().async_write_destinations(step, w);
137
138 if (w.new_task.has_value())
139 co_await crtp().async_new_task(std::move(w.new_task->first), w.new_task->second);
140
141 co_return std::move(w);
142 }
143
144 task<const Task *> async_top_task()
145 {
146 while (true) {
147 if (auto rv = crtp().top_task(); rv.has_value())
148 co_return &**rv;
149 co_await std::suspend_always{};
150 }
151 }
152
153 task<void> async_pop_task()
154 {
155 while (true) {
156 if (crtp().pop_task())
157 co_return;
158 co_await std::suspend_always{};
159 }
160 }
161
162 task<std::optional<std::unique_ptr<const Step>>> async_fetch_step()
163 {
164 auto task = co_await crtp().async_top_task();
165
166 auto rn = task->environment;
167 auto rv = co_await crtp().async_load_reg(rn);
168
169 auto step = task->step(rv);
170 if (step.has_value()) {
171 co_await crtp().async_store_reg(rn, step->second);
172 co_return std::move(step->first);
173 } else {
174 co_await crtp().async_pop_task();
175 co_return {};
176 }
177 }
178
179 task<std::pair<std::unique_ptr<const Step>, Wires>> async_fetch_and_run_step()
180 {
181 while (true) {
182 if (auto step = co_await crtp().async_fetch_step(); step.has_value()) {
183 auto wires = co_await crtp().async_run_step(**step);
184 co_return {std::move(*step), std::move(wires)};
185 }
186 }
187 }
188
189 task<void> async_run_subtree()
190 {
191 while (true) {
192 if (auto step = co_await crtp().async_fetch_step(); step.has_value())
193 co_await crtp().async_run_step_and_subtree(**step);
194 else
195 break;
196 }
197 }
198
199 task<Wires> async_run_step_and_subtree(const Step &step)
200 {
201 auto w = co_await crtp().async_run_step(step);
202
203 if (w.new_task.has_value())
204 co_await crtp().async_run_subtree();
205
206 co_return std::move(w);
207 }
208
209 task<void> async_setup_initial_task(const ISA &isa)
210 {
211 auto task = isa.initial_task();
212
213 co_await crtp().async_new_task(std::move(task.first), task.second);
214 }
215
216 task<void> async_run(const ISA &isa)
217 {
218 co_await crtp().async_setup_initial_task(isa);
219
220 co_await crtp().async_run_subtree();
221 }
222
223 };
224
225}
diff --git a/aisa/eval.h b/aisa/eval.h
deleted file mode 100644
index a301e93..0000000
--- a/aisa/eval.h
+++ /dev/null
@@ -1,65 +0,0 @@
1#pragma once
2
3#include <coroutine>
4#include <memory>
5#include <optional>
6#include <utility>
7#include <vector>
8
9#include "aisa/aisa.h"
10#include "aisa/coroutine.h" // IWYU pragma: export
11
12namespace aisa {
13
14 template<typename CRTP> struct EvalState {
15 struct EvalContext {
16 task<void> coroutine;
17
18 bool resume() { return coroutine(); }
19 };
20
21 CRTP & crtp() noexcept { return static_cast<CRTP &>(*this); }
22
23 task<regval_t> async_load_reg(regnum_t rn)
24 {
25 while (true) {
26 if (auto rv = crtp().load_reg(rn); rv.has_value())
27 co_return *rv;
28 co_await std::suspend_always{};
29 }
30 }
31
32 task<void> async_store_reg(regnum_t rn, regval_t rv)
33 {
34 while (true) {
35 if (crtp().store_reg(rn, rv))
36 co_return;
37 co_await std::suspend_always{};
38 }
39 }
40
41 task<void> async_evaluate(EvalContext &contex, const Step &step)
42 {
43 if (step.predicate.has_value()) {
44 regval_t pval = co_await async_load_reg(step.predicate->first);
45 if (pval != step.predicate->second)
46 co_return;
47 }
48 std::vector<regval_t> source_vals;
49 source_vals.reserve(step.source_regs.size());
50 for (unsigned int i = 0; i < step.source_regs.size(); ++i)
51 source_vals.emplace_back(co_await async_load_reg(step.source_regs[i]));
52 auto destination_vals = step.compute_destinations(source_vals);
53 for (unsigned int i = 0; i < step.destination_regs.size(); ++i)
54 co_await async_store_reg(step.destination_regs[i], destination_vals[i]);
55 }
56
57 std::unique_ptr<EvalContext> operator()(const Step &step)
58 {
59 auto context = std::make_unique<EvalContext>();
60 context->coroutine = async_evaluate(*context, step);
61 return context;
62 }
63 };
64
65}
diff --git a/aisa/simple-models.h b/aisa/simple-models.h
new file mode 100644
index 0000000..89e8752
--- /dev/null
+++ b/aisa/simple-models.h
@@ -0,0 +1,95 @@
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstring>
6#include <deque>
7#include <map>
8#include <memory>
9#include <optional>
10#include <utility>
11#include <vector>
12
13#include "aisa/aisa.h"
14
15namespace aisa {
16
17 template<unsigned int PAGE_BITS=10> struct PagedMem {
18 using page_t = std::array<byte_t, 1 << PAGE_BITS>;
19
20 static const addr_t PAGE_SIZE = 1 << PAGE_BITS;
21 static const addr_t PAGE_MASK = PAGE_SIZE - 1;
22
23 std::map<addr_t, page_t> pages;
24
25 bool fetch_mem(byte_t *bytes, addr_t addr, addr_t size)
26 {
27 if (size == 0)
28 return true;
29 auto page_base = addr >> PAGE_BITS;
30 auto page_offset = addr & PAGE_MASK;
31 auto size_here = std::min(size, PAGE_SIZE - page_offset);
32 if (auto page = pages.find(page_base); page != pages.end())
33 std::memcpy(bytes, page->second.data() + page_offset, size_here);
34 else
35 std::memset(bytes, 0, size_here);
36 return fetch_mem(bytes + size_here, addr + size_here, size - size_here);
37 }
38
39 bool store_mem(addr_t addr, const byte_t *bytes, addr_t size)
40 {
41 if (size == 0)
42 return true;
43 auto page_base = addr >> PAGE_BITS;
44 auto page_offset = addr & PAGE_MASK;
45 auto size_here = std::min(size, PAGE_SIZE - page_offset);
46 std::memcpy(pages[page_base].data() + page_offset, bytes, size_here);
47 return store_mem(addr + size_here, bytes + size_here, size - size_here);
48 }
49 };
50
51 struct TaskStack {
52 std::deque<std::unique_ptr<const Task>> tasks;
53
54 bool pop_task()
55 {
56 if (tasks.empty())
57 return false;
58 tasks.pop_back();
59 return true;
60 }
61
62 bool push_task(std::unique_ptr<const Task> &&task)
63 {
64 tasks.emplace_back(std::move(task));
65 return true;
66 }
67
68 std::optional<const Task *> top_task()
69 {
70 if (tasks.empty())
71 return {};
72 return tasks.back().get();
73 }
74 };
75
76 struct VectorRF {
77 std::vector<std::optional<regval_t>> rf;
78
79 std::optional<regval_t> load_reg(regnum_t rn) const
80 {
81 if (rf.size() <= rn)
82 return {};
83 return rf[rn];
84 }
85
86 bool store_reg(regnum_t rn, regval_t rv)
87 {
88 if (rf.size() <= rn)
89 rf.resize(rn + 1);
90 rf[rn] = rv;
91 return true;
92 }
93 };
94
95}