From eb3fd68203fee7c63245c702914c2acd3332d65a Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Thu, 22 Sep 2022 11:29:07 -0700 Subject: Initial commit. --- backend/exec.h | 72 +++++++++++++++++++++++++++++ backend/regfile.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 backend/exec.h create mode 100644 backend/regfile.h (limited to 'backend') 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 @@ +#pragma once + +#include "infra/port.h" +#include "inst.h" +#include "memory/dram.h" + +namespace backend { + struct exec : public infra::sim { + infra::port execp; + infra::port *writebackp = nullptr; + infra::port *loadp = nullptr; + infra::port loadresultp; + + infra::port 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)); + } + } + }; +} 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 @@ +#pragma once + +#include + +#include "frontend/decode.h" +#include "infra/port.h" +#include "inst.h" +#include "memory/dram.h" + +namespace backend { + struct regfile : public infra::sim { + infra::port *decode_restartp = nullptr; + + infra::port instp; + infra::port *execp = nullptr; + infra::port writebackp; + infra::port *storep = nullptr; + + unsigned int generation_up = 0; + unsigned int generation_down = 0; + + std::array regs; + std::array hazards; + std::uint64_t pc = 0; + + regfile() { + regs.fill(0); + hazards.fill(false); + } + + void clock() { + if (writebackp.can_read() && storep->can_write()) { + auto i = writebackp.read(); + if (i.generation == generation_down) { + pte(i.transaction, "W", fmt::format("writeback gen={} pc={:x}", generation_down, pc)); + auto old_pc = pc; + pc = i.linear_next_pc; + switch (i.field[OPCODE]) { + case OP_JUMP_ABS_IF_ZERO: + case OP_JUMP_ABS_IF_NONZERO: + pte(i.transaction, "", fmt::format("jump to {:x}", i.result.value())); + pc = i.result.value(); + break; + case OP_EMIT: + pte(i.transaction, "*", fmt::format("emit {}", i.result.value())); + break; + case OP_STORE: + { + memory::dram::command c; + c.transaction = i.transaction; + c.line_address = i.field[SRC1] >> memory::LINE_BYTES_LOG2; + c.write = true; + c.mask.fill(false); + auto offset = i.field[SRC1] & memory::LINE_BYTE_OFFSET_MASK; + pte(i.transaction, "", fmt::format("store [{:x}]={:x} offset={:x}", i.field[SRC1], i.field[SRC2], offset)); + for (unsigned int j = 0; j < sizeof(i.field[SRC2]); ++j) { + c.mask[offset + j] = true; + c.data[offset + j] = (i.field[SRC2] >> (8 * j)) & 0xff; + } + storep->write(std::move(c)); + } + break; + default: + pte(i.transaction, "", fmt::format("wb r{}={:x}", i.field[FLAGS_DST] % regs.size(), i.result.value())); + regs[i.field[FLAGS_DST] % regs.size()] = i.result.value(); + hazards[i.field[FLAGS_DST] % regs.size()] = false; + break; + } + if (!i.predicted_next_pc.has_value() || pc != i.predicted_next_pc.value()) { + pte(i.transaction, "", "restart due to pc misprediction"); + frontend::decode::restart dr; + dr.new_generation = ++generation_up; + dr.new_pc = pc; + dr.from_pc = old_pc; + decode_restartp->write(std::move(dr)); + hazards.fill(false); + ++generation_down; + } + } + } + + if (instp.can_read() && execp->can_write() && !writebackp.can_read()) { + auto i = instp.peek(); + if (i.generation == generation_up) { + bool hazard = false; + if (!(i.field[FLAGS_DST] & FLAG_IMM1)) + hazard |= hazards[i.field[SRC1] % regs.size()]; + if (!(i.field[FLAGS_DST] & FLAG_IMM2)) + hazard |= hazards[i.field[SRC2] % regs.size()]; + switch (i.field[OPCODE]) { + case OP_JUMP_ABS_IF_ZERO: + case OP_JUMP_ABS_IF_NONZERO: + case OP_EMIT: + case OP_STORE: + break; + default: + hazard |= hazards[i.field[FLAGS_DST] % regs.size()]; + break; + } + if (!hazard) { + auto i = instp.read(); + if (!(i.field[FLAGS_DST] & FLAG_IMM1)) { + auto x = regs[i.field[SRC1] % regs.size()]; + pte(i.transaction, "", fmt::format("rf1[{}]={:x}", i.field[SRC1] % regs.size(), x)); + i.field[SRC1] = x; + } + if (!(i.field[FLAGS_DST] & FLAG_IMM2)) { + auto x = regs[i.field[SRC2] % regs.size()]; + pte(i.transaction, "", fmt::format("rf2[{}]={:x}", i.field[SRC2] % regs.size(), x)); + i.field[SRC2] = x; + } + pte(i.transaction, "R", fmt::format("read gen={}", generation_up)); + i.generation = generation_down; + switch (i.field[OPCODE]) { + case OP_JUMP_ABS_IF_ZERO: + case OP_JUMP_ABS_IF_NONZERO: + case OP_EMIT: + case OP_STORE: + break; + default: + hazards[i.field[FLAGS_DST] % regs.size()] = true; + break; + } + execp->write(std::move(i)); + } + } else { + instp.discard(); + } + } + } + }; +} -- cgit v1.2.3