summaryrefslogtreecommitdiff
path: root/frontend/fetch.h
blob: a5c2e32ebce40289e3e4de69b6fd901521cf8440 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#pragma once

#include <cassert>
#include <cstdint>
#include <cstring>
#include <map>
#include <optional>
#include <utility>

#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<restart> restartp;

        infra::port<memory::dram::command> *commandp = nullptr;
        infra::port<memory::dram::response> responsep;

        infra::port<bundle> *bundlep = nullptr;

        unsigned int generation = 0;
        std::uint64_t next_line_address = 0;

        // FIXME make prediction table finite
        std::map<std::uint64_t, std::uint64_t> 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;
                return;
            }
            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();
        }
    };
}