From ce9e806b4abbebd311db610c3a8e89ab35bfbf9d Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Sun, 8 Nov 2026 18:25:35 +0200 Subject: [PATCH] implement hardware out-of-order execution --- CMakeLists.txt | 1 + config.h | 1 + inc/assembler.hpp | 3 + inc/dyn-pipeline.hpp | 35 ++++++ src/assembler.cpp | 13 +++ src/dyn-pipeline-ooe.cpp | 224 +++++++++++++++++++++++++++++++++++++++ src/dyn-pipeline.cpp | 2 + src/main.cpp | 8 ++ 8 files changed, 287 insertions(+) create mode 100644 src/dyn-pipeline-ooe.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 824034b..575c1d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ target_include_directories(syntaxer PRIVATE add_library(dyn-pipeline STATIC) target_sources(dyn-pipeline PRIVATE src/dyn-pipeline.cpp + src/dyn-pipeline-ooe.cpp ) target_include_directories(dyn-pipeline PRIVATE ${GLOBAL_INC} diff --git a/config.h b/config.h index 93d4440..5acd71e 100644 --- a/config.h +++ b/config.h @@ -11,3 +11,4 @@ #define DYN_PIPELINE_MEM_SIZE 512 #define DYN_PIPELINE_LAYERS 3 +#define DYN_PIPELINE_OUT_OF_ORDER_EXECUTION 1 diff --git a/inc/assembler.hpp b/inc/assembler.hpp index 7f60ebd..7d690a0 100644 --- a/inc/assembler.hpp +++ b/inc/assembler.hpp @@ -12,5 +12,8 @@ void assemble( std::vector& program, std::array& memory, int& mem_used); +void to_ooe( + std::vector& p_ooe, + std::vector& p); } diff --git a/inc/dyn-pipeline.hpp b/inc/dyn-pipeline.hpp index 42a3cf9..ca1bf9c 100644 --- a/inc/dyn-pipeline.hpp +++ b/inc/dyn-pipeline.hpp @@ -32,6 +32,21 @@ struct Command } }; +struct CommandOOE +{ + enum CommandType t; + uint16_t op1; + uint16_t op2; + uint16_t res; + uint16_t exe; + + CommandOOE(enum CommandType t, uint16_t op1, uint16_t op2, uint16_t res) + : t(t), op1(op1), op2(op2), res(res), exe(0) + { + + } +}; + struct MemCell { double v; @@ -59,4 +74,24 @@ public: void run(void); }; +class SystemOOE +{ +private: + std::vector *program_memory; + std::array data_memory; + std::array layer_cmd {-1}; + unsigned int system_time; + + void print_program_memory(void) const; + void print_pipeline(void) const; + bool pipeline_empty(void) const; + bool next_instruction(void) const; + int get_instruction(void) const; + void step(void); + +public: + void init(const std::vector * const prg, const std::array& mem, const int init_mem_size); + void run(void); +}; + } diff --git a/src/assembler.cpp b/src/assembler.cpp index 6fa4fb8..956a475 100644 --- a/src/assembler.cpp +++ b/src/assembler.cpp @@ -131,4 +131,17 @@ void assemble( } } +void to_ooe( + std::vector& p_ooe, + std::vector& p) +{ + p_ooe.reserve(p.size()); + + for (int i = 0, l = p.size(); i < l; i++) + { + const DynamicPipeline::Command &c = p[i]; + p_ooe.emplace_back(c.t, c.op1, c.op2, c.res); + } +} + } diff --git a/src/dyn-pipeline-ooe.cpp b/src/dyn-pipeline-ooe.cpp new file mode 100644 index 0000000..224023e --- /dev/null +++ b/src/dyn-pipeline-ooe.cpp @@ -0,0 +1,224 @@ +#include "dyn-pipeline.hpp" +#include "print.h" +#include "expression.hpp" + +#include "config.h" + +namespace DynamicPipeline { + +static int weight_op(DynamicPipeline::CommandType o) +{ + return Expression::Token::weight_op(static_cast(o + 2)); +} + +static const char *op_to_str(DynamicPipeline::CommandType o) +{ + switch (o) + { + case ADD: + return "ADD"; + case SUB: + return "SUB"; + case MUL: + return "MUL"; + case DIV: + return "DIV"; + case POW: + return "POW"; + default: + pr_warn("Impossible token - this is a bug!"); + return "Impossible token"; + } +} + +void SystemOOE::print_program_memory(void) const +{ + pr_info("Program memory dump: " << program_memory->size() * sizeof(struct CommandOOE) << " bytes"); + pr_info("### cmd op1 op2 res exe"); + + for (int i = 0, l = program_memory->size(); i < l; i++) + { + const struct CommandOOE &cmd = (*program_memory)[i]; + pr_info(std::setw(3) << i << ". " << op_to_str(cmd.t) << ", " + << std::setw(3) << cmd.op1 << ", " + << std::setw(3) << cmd.op2 << ", " + << std::setw(3) << cmd.res << ", " + << std::setw(3) << cmd.exe); + } +} + +void SystemOOE::init(const std::vector * const prg, const std::array& mem, const int init_mem_size) +{ + pr_info("Dynamic Pipeline System initialized with:\n" + << prg->size() << " commands in program memory\n" + << init_mem_size << " values in data memory"); + + program_memory = const_cast *>(prg); + + for (int i = 0; i < init_mem_size; i++) + { + data_memory[i].v = mem[i]; + data_memory[i].ready = 1; + } + + for (int i = 0; i < DYN_PIPELINE_LAYERS; i++) + { + layer_cmd[i] = -1; + } + + system_time = 0; + + print_program_memory(); + pri_info("\n"); +} + +void SystemOOE::print_pipeline(void) const +{ + prs_info(" "); + + for (int i = 0; i < DYN_PIPELINE_LAYERS - 1; i++) + { + if (layer_cmd[i] != -1) + { + pri_info(std::setw(3) << layer_cmd[i] << " (" << op_to_str((*program_memory)[layer_cmd[i]].t) << ") " + << std::setw(3) << (*program_memory)[layer_cmd[i]].res << " | "); + } + else + { + pri_info("--- (---) --- | "); + } + } + + if (layer_cmd[DYN_PIPELINE_LAYERS - 1] != -1) + { + int addr = layer_cmd[DYN_PIPELINE_LAYERS - 1]; + pri_info(std::setw(3) << addr << " (" << op_to_str((*program_memory)[addr].t) << ") " + << std::setw(3) << (*program_memory)[addr].res << "\n"); + } + else + { + pri_info("--- (---) ---\n"); + } +} + +bool SystemOOE::pipeline_empty(void) const +{ + for (int i = 0; i < DYN_PIPELINE_LAYERS; i++) + { + if (layer_cmd[i] != -1) + { + return false; + } + } + + return true; +} + +bool SystemOOE::next_instruction(void) const +{ + for (unsigned int i = 0; i < program_memory->size(); i++) + { + if ((*program_memory)[i].exe == 0) + { + return true; + } + } + + return false; +} + +int SystemOOE::get_instruction(void) const +{ + for (unsigned int i = 0; i < program_memory->size(); i++) + { + if ((*program_memory)[i].exe == 1) + { + continue; + } + + const CommandOOE &cmd = (*program_memory)[i]; + + if (!data_memory[cmd.op1].ready) + { + continue; + } + + if (!data_memory[cmd.op2].ready) + { + continue; + } + + return i; + } + + + return -1; +} + +void SystemOOE::step(void) +{ + pr_info("Step start time: " << system_time << " ticks"); + + // count time + int time_taken = 1; + for (int i = 0; i < DYN_PIPELINE_LAYERS; i++) + { + if (layer_cmd[i] == -1) + { + continue; + } + + if (const int d = weight_op((*program_memory)[layer_cmd[i]].t); d > time_taken) + { + time_taken = d; + } + } + + system_time += time_taken; + + // handle output + if (int prg_mem_addr = layer_cmd[DYN_PIPELINE_LAYERS - 1]; prg_mem_addr != -1) + { + const CommandOOE &cmd = (*program_memory)[prg_mem_addr]; + pr_info("Instruction " << prg_mem_addr << " (" << op_to_str(cmd.t) << ") completes, writes output to " << cmd.res); + + data_memory[cmd.res].ready = 1; + } + + // progress pipeline + for (int i = DYN_PIPELINE_LAYERS - 2; i >= 0; i--) + { + layer_cmd[i+1] = layer_cmd[i]; + } + + layer_cmd[0] = -1; + + // load new operation if ready + if (int cmd_idx = get_instruction(); cmd_idx != -1) + { + const CommandOOE &cmd = (*program_memory)[cmd_idx]; + pr_info("Instruction " << cmd_idx << " (" << op_to_str(cmd.t) << ") reads " << cmd.op1 << " and " << cmd.op2 << " and enters the pipeline"); + + layer_cmd[0] = cmd_idx; + + (*program_memory)[cmd_idx].exe = 1; + } + + pr_info("Step took " << time_taken << " ticks"); +} + +void SystemOOE::run(void) +{ + while (next_instruction() || !pipeline_empty()) + { + print_pipeline(); + pri_info("\n"); + + step(); + pri_info("\n"); + } + + pr_info("System finished in " << system_time << " ticks"); +} + +} diff --git a/src/dyn-pipeline.cpp b/src/dyn-pipeline.cpp index 78afea0..7a226a2 100644 --- a/src/dyn-pipeline.cpp +++ b/src/dyn-pipeline.cpp @@ -2,6 +2,8 @@ #include "print.h" #include "expression.hpp" +#include "config.h" + namespace DynamicPipeline { static int weight_op(DynamicPipeline::CommandType o) diff --git a/src/main.cpp b/src/main.cpp index 64d23cf..9f027c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,15 @@ int main(int argc, char **argv) int mem_used; Assembler::assemble(root, program, memory, mem_used); +#if DYN_PIPELINE_OUT_OF_ORDER_EXECUTION == 1 + std::vector program_ooe; + Assembler::to_ooe(program_ooe, program); + + DynamicPipeline::SystemOOE machine; + machine.init(&program_ooe, memory, mem_used); +#else DynamicPipeline::System machine; machine.init(&program, memory, mem_used); +#endif machine.run(); }