summaryrefslogtreecommitdiff
path: root/backend/exec.h
blob: f1474b8387e96434e21c914ec98f9e75cc864f53 (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
#pragma once

#include "infra/port.h"
#include "inst.h"
#include "memory/dram.h"

namespace backend {
    struct exec : public infra::sim {
        infra::port<inst> execp;
        infra::port<inst> *writebackp = nullptr;
        infra::port<memory::dram::command> *loadp = nullptr;
        infra::port<memory::dram::response> loadresultp;

        infra::port<inst> stallp;

        void clock() {
            if (stallp.can_read() && writebackp->can_write()) {
                const auto &i = stallp.peek();
                switch (i.field[OPCODE]) {
                    case OP_LOAD:
                        if (loadresultp.can_read()) {
                            auto i = stallp.read();
                            auto addr = i.field[SRC1] + i.field[SRC2];
                            auto offset = addr & memory::LINE_BYTE_OFFSET_MASK;
                            pte(i.transaction, "", fmt::format("addr={:x} offset={:x}", addr, offset));
                            auto f = loadresultp.read();
                            std::uint64_t r = 0;
                            for (unsigned int i = 0; i < sizeof(r); ++i)
                                r |= f.data[i + offset] << (8 * i);
                            i.result = r;
                            writebackp->write(std::move(i));
                        }
                        break;
                }
            } else if (execp.can_read() && writebackp->can_write() && loadp->can_write()) {
                auto i = execp.read();
                pte(i.transaction, "E", fmt::format("exec gen={} op={:x} a={:x} b={:x}", i.generation, i.field[OPCODE], i.field[SRC1], i.field[SRC2]));
                switch (i.field[OPCODE]) {
                    case OP_JUMP_ABS_IF_ZERO:
                        if (i.field[SRC2] == 0)
                            i.result = i.field[SRC1];
                        else
                            i.result = i.linear_next_pc;
                        break;
                    case OP_JUMP_ABS_IF_NONZERO:
                        if (i.field[SRC2] != 0)
                            i.result = i.field[SRC1];
                        else
                            i.result = i.linear_next_pc;
                        break;
                    case OP_EMIT:
                    case OP_ADD:
                        i.result = i.field[SRC1] + i.field[SRC2];
                        break;
                    case OP_LOAD:
                        {
                            memory::dram::command c;
                            c.transaction = i.transaction;
                            c.line_address = (i.field[SRC1] + i.field[SRC2]) >> memory::LINE_BYTES_LOG2;
                            c.write = false;
                            c.responsep = &loadresultp;
                            loadp->write(std::move(c));
                        }
                        stallp.write(std::move(i));
                        break;
                }
                if (stallp.can_write())
                    writebackp->write(std::move(i));
            }
        }
    };
}