#pragma once #include #include #include #include #include #include #include "frontend/bundle.h" #include "infra/pipetrace.h" #include "infra/sim.h" #include "memory/dram.h" namespace frontend { struct fetch : public infra::sim { struct restart { unsigned int new_generation; std::uint64_t previous_line_address; std::uint64_t new_next_line_address; }; infra::port restartp; infra::port *commandp = nullptr; infra::port responsep; infra::port *bundlep = nullptr; unsigned int generation = 0; std::uint64_t next_line_address = 0; // FIXME make prediction table finite std::map predictor; bool fill_request_sent = false; void clock() { if (restartp.can_read()) { auto r = restartp.read(); generation = r.new_generation; next_line_address = r.new_next_line_address; fill_request_sent = false; if (r.new_next_line_address == r.previous_line_address || r.new_next_line_address == r.previous_line_address + 1) predictor.erase(r.previous_line_address); else predictor[r.previous_line_address] = r.new_next_line_address; } if (fill_request_sent && responsep.can_read() && bundlep->can_write()) { auto r = responsep.read(); if (r.line_address == next_line_address) { bundle b; b.transaction = r.transaction; b.generation = generation; b.line_address = next_line_address; if (auto p = predictor.find(next_line_address); p != predictor.end()) b.next_line_address = p->second; else b.next_line_address = next_line_address + 1; next_line_address = b.next_line_address; pte(b.transaction, "", fmt::format("next fetch line {:x}", next_line_address)); b.data = std::move(r.data); bundlep->write(std::move(b)); fill_request_sent = false; } } if (!fill_request_sent && commandp->can_write()) { memory::dram::command c; c.transaction = infra::pt::toplevel(); pte(c.transaction, "F", fmt::format("fetch gen={}", generation)); c.line_address = next_line_address; c.responsep = &responsep; commandp->write(std::move(c)); fill_request_sent = true; } if (!fill_request_sent) responsep.discard(); } }; }