From c72951a36d6cb9775dc1ecd9bc26bc13e796f10c Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 2 Jul 2022 13:45:09 -0700 Subject: Dropping the async interface, and adding some real uarch. --- uarch/fetch.cpp | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 uarch/fetch.cpp (limited to 'uarch/fetch.cpp') 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 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "sim/sim.h" +#include "sim/queue.h" +#include "uarch/fetch.h" +#include "uarch/types.h" +#include "util/assert.h" + +namespace uarch { + + FetchStage::FetchStage(sim::Scheduler &scheduler, const aisa::ISA &isa, sim::Queue &fillreqq, sim::Queue &fillq, sim::Queue &uopq) + : sim::Schedulable(scheduler) + , fillreqq(fillreqq) + , fillq(fillq) + , uopq(uopq) + { + fillreqq.add_writer(this); + fillq.add_reader(this); + uopq.add_writer(this); + + auto [task, env] = isa.initial_task(); + store_reg(task->environment, env); + push_task(std::move(task)); + } + + void FetchStage::clock() + { + bool sent_uop = false; + while (!sent_uop) { + while (!step) { + const auto &task = *top_task().value(); + auto s = task.step(load_reg(task.environment).value()); + if (s.has_value()) { + step = std::move(s->first); + std::cout << "fetch step " << step->disasm() << "\n"; + wires = {}; + outstanding_fill = false; + fill_complete = false; + ASSERT(store_reg(task.environment, s->second), "Could not write next environment value"); + } else { + pop_task(); + } + } + + if (step->predicate.has_value()) { + auto x = load_reg(step->predicate->first); + if (x.has_value()) { + if (*x != step->predicate->second) + goto nextstep; + } else { + std::cout << "fetch stalls on predicate register"; + break; + } + } + + wires.source_vals.reserve(step->source_regs.size()); + for (unsigned int i = wires.source_vals.size(); i < step->source_regs.size(); ++i) { + auto x = load_reg(step->source_regs[i]); + if (!x.has_value()) { + std::cout << "fetch stalls on source register"; + break; + } + wires.source_vals.emplace_back(*x); + } + + if (step->mop == aisa::MOp::LOAD && !fill_complete) { + auto mi = step->meminfo(wires); + if (outstanding_fill) { + for (unsigned int i = 0; i < fillq.available(); ++i) { + auto &fill = fillq.peek(i); + if (fill.physical_addr == mi.physical_addr) { + std::cout << "fetch fills\n"; + wires.memory_val = std::move(fill.bytes); + outstanding_fill = false; + fill_complete = true; + } + } + if (!fill_complete) + break; + } else { + std::cout << "fetch sends fill request\n"; + FillReq req; + req.fillq = &fillq; + req.physical_addr = mi.physical_addr; + req.size = mi.size; + fillreqq.write(std::move(req)); + outstanding_fill = true; + fill_complete = false; + break; + } + } + + step->evaluate(wires); + + for (unsigned int i = 0; i < step->destination_regs.size(); ++i) + ASSERT(store_reg(step->destination_regs[i], wires.destination_vals[i]), "Could not write destination register"); + + ASSERT(step->mop != aisa::MOp::STORE, "No stores allowed in fetch"); + + if (wires.new_task.has_value()) { + std::cout << "fetch sends subtask " << wires.new_task->first->disasm() << " downstream\n"; + Uop uop; + static_cast(uop) = *this; + ASSERT(uop.store_reg(wires.new_task->first->environment, wires.new_task->second), "Could not write initial environment to uop"); + ASSERT(uop.push_task(std::move(wires.new_task->first)), "Could not push subtask to uop"); + uopq.write(std::move(uop)); + sent_uop = true; + } + +nextstep: + step = nullptr; + wires = {}; + outstanding_fill = false; + fill_complete = false; + } + + while (fillq.available()) { + std::cout << "fetch consumes fill\n"; + fillq.read(); + } + } + +} -- cgit v1.2.3