implement hardware out-of-order execution
This commit is contained in:
@@ -29,6 +29,7 @@ target_include_directories(syntaxer PRIVATE
|
|||||||
add_library(dyn-pipeline STATIC)
|
add_library(dyn-pipeline STATIC)
|
||||||
target_sources(dyn-pipeline PRIVATE
|
target_sources(dyn-pipeline PRIVATE
|
||||||
src/dyn-pipeline.cpp
|
src/dyn-pipeline.cpp
|
||||||
|
src/dyn-pipeline-ooe.cpp
|
||||||
)
|
)
|
||||||
target_include_directories(dyn-pipeline PRIVATE
|
target_include_directories(dyn-pipeline PRIVATE
|
||||||
${GLOBAL_INC}
|
${GLOBAL_INC}
|
||||||
|
|||||||
@@ -11,3 +11,4 @@
|
|||||||
|
|
||||||
#define DYN_PIPELINE_MEM_SIZE 512
|
#define DYN_PIPELINE_MEM_SIZE 512
|
||||||
#define DYN_PIPELINE_LAYERS 3
|
#define DYN_PIPELINE_LAYERS 3
|
||||||
|
#define DYN_PIPELINE_OUT_OF_ORDER_EXECUTION 1
|
||||||
|
|||||||
@@ -12,5 +12,8 @@ void assemble(
|
|||||||
std::vector<DynamicPipeline::Command>& program,
|
std::vector<DynamicPipeline::Command>& program,
|
||||||
std::array<double, DYN_PIPELINE_MEM_SIZE>& memory,
|
std::array<double, DYN_PIPELINE_MEM_SIZE>& memory,
|
||||||
int& mem_used);
|
int& mem_used);
|
||||||
|
void to_ooe(
|
||||||
|
std::vector<DynamicPipeline::CommandOOE>& p_ooe,
|
||||||
|
std::vector<DynamicPipeline::Command>& p);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
struct MemCell
|
||||||
{
|
{
|
||||||
double v;
|
double v;
|
||||||
@@ -59,4 +74,24 @@ public:
|
|||||||
void run(void);
|
void run(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SystemOOE
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::vector<CommandOOE> *program_memory;
|
||||||
|
std::array<MemCell, DYN_PIPELINE_MEM_SIZE> data_memory;
|
||||||
|
std::array<int, DYN_PIPELINE_LAYERS> 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<CommandOOE> * const prg, const std::array<double, DYN_PIPELINE_MEM_SIZE>& mem, const int init_mem_size);
|
||||||
|
void run(void);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,4 +131,17 @@ void assemble(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void to_ooe(
|
||||||
|
std::vector<DynamicPipeline::CommandOOE>& p_ooe,
|
||||||
|
std::vector<DynamicPipeline::Command>& 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Expression::Token::Operator>(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<CommandOOE> * const prg, const std::array<double, DYN_PIPELINE_MEM_SIZE>& 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<std::vector<CommandOOE> *>(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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "expression.hpp"
|
#include "expression.hpp"
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
namespace DynamicPipeline {
|
namespace DynamicPipeline {
|
||||||
|
|
||||||
static int weight_op(DynamicPipeline::CommandType o)
|
static int weight_op(DynamicPipeline::CommandType o)
|
||||||
|
|||||||
@@ -29,7 +29,15 @@ int main(int argc, char **argv)
|
|||||||
int mem_used;
|
int mem_used;
|
||||||
Assembler::assemble(root, program, memory, mem_used);
|
Assembler::assemble(root, program, memory, mem_used);
|
||||||
|
|
||||||
|
#if DYN_PIPELINE_OUT_OF_ORDER_EXECUTION == 1
|
||||||
|
std::vector<DynamicPipeline::CommandOOE> program_ooe;
|
||||||
|
Assembler::to_ooe(program_ooe, program);
|
||||||
|
|
||||||
|
DynamicPipeline::SystemOOE machine;
|
||||||
|
machine.init(&program_ooe, memory, mem_used);
|
||||||
|
#else
|
||||||
DynamicPipeline::System machine;
|
DynamicPipeline::System machine;
|
||||||
machine.init(&program, memory, mem_used);
|
machine.init(&program, memory, mem_used);
|
||||||
|
#endif
|
||||||
machine.run();
|
machine.run();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user