summaryrefslogtreecommitdiff
path: root/backend/regfile.h
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/regfile.h
downloadprocmodel-eb3fd68203fee7c63245c702914c2acd3332d65a.tar.xz
Initial commit.
Diffstat (limited to 'backend/regfile.h')
-rw-r--r--backend/regfile.h132
1 files changed, 132 insertions, 0 deletions
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}