lab5: add assembler and dynamic pipeline system emulator

This commit is contained in:
2026-11-07 20:44:35 +02:00
parent 79a96aea77
commit 36b4596bd4
12 changed files with 401 additions and 7 deletions
+99
View File
@@ -0,0 +1,99 @@
#include "assembler.hpp"
namespace Assembler {
// operand source
enum OpSrc
{
PRELOAD, // static memory
DYNAMIC // dynamic memory
};
struct Command
{
DynamicPipeline::CommandType opcode;
OpSrc left_src;
int left_index;
OpSrc right_src;
int right_index;
Command(DynamicPipeline::CommandType opcode, OpSrc left_src, OpSrc right_src, int left_index, int right_index)
: opcode(opcode), left_src(left_src), left_index(left_index), right_src(right_src), right_index(right_index)
{
}
};
int descend_var(const Expression::TreeNode& node, int& preload_mem)
{
(void) node;
preload_mem++;
return preload_mem - 1; // this index in preload memory
}
int descend_operator(const Expression::TreeNode& node, int& preload_mem, std::vector<Command>& commands)
{
int left, right;
OpSrc lo, ro;
if (node.l->o.t == Expression::Token::OPERATOR)
{
left = descend_operator(*node.l, preload_mem, commands);
lo = DYNAMIC;
}
else
{
left = descend_var(*node.l, preload_mem);
lo = PRELOAD;
}
if (node.r->o.t == Expression::Token::OPERATOR)
{
right = descend_operator(*node.r, preload_mem, commands);
ro = DYNAMIC;
}
else
{
right = descend_var(*node.r, preload_mem);
ro = PRELOAD;
}
commands.emplace_back((DynamicPipeline::CommandType) (node.o.t - 2), lo, ro, left, right);
return commands.size() - 1; // this index in dynamic memory
}
void assemble(
const Expression::TreeNode& root,
std::vector<DynamicPipeline::Command>& program,
std::array<double, DYN_PIPELINE_MEM_SIZE>& memory,
int& mem_used)
{
(void) memory;
int preload_mem = 0;
std::vector<Command> commands;
if (root.o.t == Expression::Token::OPERATOR)
{
(void) descend_operator(root, preload_mem, commands);
}
else
{
(void) descend_var(root, preload_mem);
}
mem_used = preload_mem;
program.reserve(commands.size());
for (int i = 0, l = commands.size(); i < l; i++)
{
Command &cmd = commands[i];
program.emplace_back(cmd.opcode, cmd.left_src * preload_mem + cmd.left_index, cmd.right_src * preload_mem + cmd.right_index, preload_mem + i);
}
}
}
View File
+161
View File
@@ -0,0 +1,161 @@
#include "dyn-pipeline.hpp"
#include "print.h"
namespace DynamicPipeline {
void System::init(const std::vector<Command> * 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<Command> *>(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;
}
pc = 0;
system_time = 0;
}
void System::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] << " | ");
}
else
{
pri_info("IDL | ");
}
}
if (layer_cmd[DYN_PIPELINE_LAYERS - 1] != -1)
{
pri_info(std::setw(3) << layer_cmd[DYN_PIPELINE_LAYERS - 1] << "\n");
}
else
{
pri_info("IDL\n");
}
}
bool System::pipeline_empty(void) const
{
for (int i = 0; i < DYN_PIPELINE_LAYERS; i++)
{
if (layer_cmd[i] != -1)
{
return false;
}
}
return true;
}
bool System::next_instruction(void) const
{
return pc < program_memory->size();
}
bool System::instruction_ready(void) const
{
if (!next_instruction())
{
return false;
}
Command &cmd = (*program_memory)[pc];
if (!data_memory[cmd.op1].ready)
{
return false;
}
if (!data_memory[cmd.op2].ready)
{
return false;
}
return true;
}
void System::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 = delays[(*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)
{
Command &cmd = (*program_memory)[prg_mem_addr];
pr_info("Instruction " << prg_mem_addr << " 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 (instruction_ready())
{
Command &cmd = (*program_memory)[pc];
pr_info("Instruction " << pc << " reads " << cmd.op1 << " and " << cmd.op2 << " and enters the pipeline");
layer_cmd[0] = pc;
pc++;
}
pr_info("Pipeline step took " << time_taken << " ticks");
}
void System::run(void)
{
while (next_instruction() || !pipeline_empty())
{
print_pipeline();
pri_info("\n");
step();
pri_info("\n");
}
pr_info("System finished in " << system_time << " ticks");
}
}
+13
View File
@@ -1,5 +1,9 @@
#include "config.h"
#include "parser.hpp"
#include "syntaxer.hpp"
#include "assembler.hpp"
#include "dyn-pipeline.hpp"
int main(int argc, char **argv)
{
@@ -18,4 +22,13 @@ int main(int argc, char **argv)
std::vector<Expression::Operation> ov = Syntax::build_op_vector(tv);
Expression::TreeNode root = Syntax::ov_to_tree(tv, ov);
std::vector<DynamicPipeline::Command> program;
std::array<double, DYN_PIPELINE_MEM_SIZE> memory;
int mem_used;
Assembler::assemble(root, program, memory, mem_used);
DynamicPipeline::System machine;
machine.init(&program, memory, mem_used);
machine.run();
}
+3 -1
View File
@@ -1388,7 +1388,7 @@ finish:
return ov;
}
Expression::TreeNode ov_to_tree(const std::vector<Expression::Token> tv, const std::vector<Expression::Operation>& ov)
Expression::TreeNode ov_to_tree(const std::vector<Expression::Token>& tv, const std::vector<Expression::Operation>& ov)
{
Expression::TreeNode root;
std::queue<std::pair<Expression::TreeNode *, int>> queued_ops;
@@ -1434,6 +1434,8 @@ Expression::TreeNode ov_to_tree(const std::vector<Expression::Token> tv, const s
void print_op_tree(const Expression::TreeNode& root)
{
(void) root;
std::vector<std::pair<Expression::TreeNode *, int>> items_to_display;
}