summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorJulian Blake Kongslie2022-09-22 11:29:07 -0700
committerJulian Blake Kongslie2022-09-22 11:29:07 -0700
commiteb3fd68203fee7c63245c702914c2acd3332d65a (patch)
tree7796707c0372e7fbe4a8bac70aad95f619e8ba29 /backend
downloadprocmodel-eb3fd68203fee7c63245c702914c2acd3332d65a.tar.xz
Initial commit.
Diffstat (limited to 'backend')
-rw-r--r--backend/exec.h72
-rw-r--r--backend/regfile.h132
2 files changed, 204 insertions, 0 deletions
diff --git a/backend/exec.h b/backend/exec.h
new file mode 100644
index 0000000..f1474b8
--- /dev/null
+++ b/backend/exec.h
@@ -0,0 +1,72 @@
1#pragma once
2
3#include "infra/port.h"
4#include "inst.h"
5#include "memory/dram.h"
6
7namespace backend {
8 struct exec : public infra::sim {
9 infra::port<inst> execp;
10 infra::port<inst> *writebackp = nullptr;
11 infra::port<memory::dram::command> *loadp = nullptr;
12 infra::port<memory::dram::response> loadresultp;
13
14 infra::port<inst> stallp;
15
16 void clock() {
17 if (stallp.can_read() && writebackp->can_write()) {
18 const auto &i = stallp.peek();
19 switch (i.field[OPCODE]) {
20 case OP_LOAD:
21 if (loadresultp.can_read()) {
22 auto i = stallp.read();
23 auto addr = i.field[SRC1] + i.field[SRC2];
24 auto offset = addr & memory::LINE_BYTE_OFFSET_MASK;
25 pte(i.transaction, "", fmt::format("addr={:x} offset={:x}", addr, offset));
26 auto f = loadresultp.read();
27 std::uint64_t r = 0;
28 for (unsigned int i = 0; i < sizeof(r); ++i)
29 r |= f.data[i + offset] << (8 * i);
30 i.result = r;
31 writebackp->write(std::move(i));
32 }
33 break;
34 }
35 } else if (execp.can_read() && writebackp->can_write() && loadp->can_write()) {
36 auto i = execp.read();
37 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]));
38 switch (i.field[OPCODE]) {
39 case OP_JUMP_ABS_IF_ZERO:
40 if (i.field[SRC2] == 0)
41 i.result = i.field[SRC1];
42 else
43 i.result = i.linear_next_pc;
44 break;
45 case OP_JUMP_ABS_IF_NONZERO:
46 if (i.field[SRC2] != 0)
47 i.result = i.field[SRC1];
48 else
49 i.result = i.linear_next_pc;
50 break;
51 case OP_EMIT:
52 case OP_ADD:
53 i.result = i.field[SRC1] + i.field[SRC2];
54 break;
55 case OP_LOAD:
56 {
57 memory::dram::command c;
58 c.transaction = i.transaction;
59 c.line_address = (i.field[SRC1] + i.field[SRC2]) >> memory::LINE_BYTES_LOG2;
60 c.write = false;
61 c.responsep = &loadresultp;
62 loadp->write(std::move(c));
63 }
64 stallp.write(std::move(i));
65 break;
66 }
67 if (stallp.can_write())
68 writebackp->write(std::move(i));
69 }
70 }
71 };
72}
diff --git a/backend/regfile.h b/backend/regfile.h
new file mode 100644
index 0000000..276504c
--- /dev/null
+++ b/backend/regfile.h
@@ -0,0 +1,132 @@
1#pragma once
2
3#include <array>
4
5#include "frontend/decode.h"
6#include "infra/port.h"
7#include "inst.h"
8#include "memory/dram.h"
9
10namespace backend {
11 struct regfile : public infra::sim {
12 infra::port<frontend::decode::restart> *decode_restartp = nullptr;
13
14 infra::port<inst> instp;
15 infra::port<inst> *execp = nullptr;
16 infra::port<inst> writebackp;
17 infra::port<memory::dram::command> *storep = nullptr;
18
19 unsigned int generation_up = 0;
20 unsigned int generation_down = 0;
21
22 std::array<std::uint64_t, 16> regs;
23 std::array<bool, 16> hazards;
24 std::uint64_t pc = 0;
25
26 regfile() {
27 regs.fill(0);
28 hazards.fill(false);
29 }
30
31 void clock() {
32 if (writebackp.can_read() && storep->can_write()) {
33 auto i = writebackp.read();
34 if (i.generation == generation_down) {
35 pte(i.transaction, "W", fmt::format("writeback gen={} pc={:x}", generation_down, pc));
36 auto old_pc = pc;
37 pc = i.linear_next_pc;
38 switch (i.field[OPCODE]) {
39 case OP_JUMP_ABS_IF_ZERO:
40 case OP_JUMP_ABS_IF_NONZERO:
41 pte(i.transaction, "", fmt::format("jump to {:x}", i.result.value()));
42 pc = i.result.value();
43 break;
44 case OP_EMIT:
45 pte(i.transaction, "*", fmt::format("emit {}", i.result.value()));
46 break;
47 case OP_STORE:
48 {
49 memory::dram::command c;
50 c.transaction = i.transaction;
51 c.line_address = i.field[SRC1] >> memory::LINE_BYTES_LOG2;
52 c.write = true;
53 c.mask.fill(false);
54 auto offset = i.field[SRC1] & memory::LINE_BYTE_OFFSET_MASK;
55 pte(i.transaction, "", fmt::format("store [{:x}]={:x} offset={:x}", i.field[SRC1], i.field[SRC2], offset));
56 for (unsigned int j = 0; j < sizeof(i.field[SRC2]); ++j) {
57 c.mask[offset + j] = true;
58 c.data[offset + j] = (i.field[SRC2] >> (8 * j)) & 0xff;
59 }
60 storep->write(std::move(c));
61 }
62 break;
63 default:
64 pte(i.transaction, "", fmt::format("wb r{}={:x}", i.field[FLAGS_DST] % regs.size(), i.result.value()));
65 regs[i.field[FLAGS_DST] % regs.size()] = i.result.value();
66 hazards[i.field[FLAGS_DST] % regs.size()] = false;
67 break;
68 }
69 if (!i.predicted_next_pc.has_value() || pc != i.predicted_next_pc.value()) {
70 pte(i.transaction, "", "restart due to pc misprediction");
71 frontend::decode::restart dr;
72 dr.new_generation = ++generation_up;
73 dr.new_pc = pc;
74 dr.from_pc = old_pc;
75 decode_restartp->write(std::move(dr));
76 hazards.fill(false);
77 ++generation_down;
78 }
79 }
80 }
81
82 if (instp.can_read() && execp->can_write() && !writebackp.can_read()) {
83 auto i = instp.peek();
84 if (i.generation == generation_up) {
85 bool hazard = false;
86 if (!(i.field[FLAGS_DST] & FLAG_IMM1))
87 hazard |= hazards[i.field[SRC1] % regs.size()];
88 if (!(i.field[FLAGS_DST] & FLAG_IMM2))
89 hazard |= hazards[i.field[SRC2] % regs.size()];
90 switch (i.field[OPCODE]) {
91 case OP_JUMP_ABS_IF_ZERO:
92 case OP_JUMP_ABS_IF_NONZERO:
93 case OP_EMIT:
94 case OP_STORE:
95 break;
96 default:
97 hazard |= hazards[i.field[FLAGS_DST] % regs.size()];
98 break;
99 }
100 if (!hazard) {
101 auto i = instp.read();
102 if (!(i.field[FLAGS_DST] & FLAG_IMM1)) {
103 auto x = regs[i.field[SRC1] % regs.size()];
104 pte(i.transaction, "", fmt::format("rf1[{}]={:x}", i.field[SRC1] % regs.size(), x));
105 i.field[SRC1] = x;
106 }
107 if (!(i.field[FLAGS_DST] & FLAG_IMM2)) {
108 auto x = regs[i.field[SRC2] % regs.size()];
109 pte(i.transaction, "", fmt::format("rf2[{}]={:x}", i.field[SRC2] % regs.size(), x));
110 i.field[SRC2] = x;
111 }
112 pte(i.transaction, "R", fmt::format("read gen={}", generation_up));
113 i.generation = generation_down;
114 switch (i.field[OPCODE]) {
115 case OP_JUMP_ABS_IF_ZERO:
116 case OP_JUMP_ABS_IF_NONZERO:
117 case OP_EMIT:
118 case OP_STORE:
119 break;
120 default:
121 hazards[i.field[FLAGS_DST] % regs.size()] = true;
122 break;
123 }
124 execp->write(std::move(i));
125 }
126 } else {
127 instp.discard();
128 }
129 }
130 }
131 };
132}