diff --git a/CMakeLists.txt b/CMakeLists.txt index ba3a455..824034b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,23 @@ target_include_directories(syntaxer PRIVATE ${GLOBAL_INC} ) +add_library(dyn-pipeline STATIC) +target_sources(dyn-pipeline PRIVATE + src/dyn-pipeline.cpp +) +target_include_directories(dyn-pipeline PRIVATE + ${GLOBAL_INC} +) + +add_library(assembler STATIC) +target_sources(assembler PRIVATE + src/assembler.cpp +) +target_include_directories(assembler PRIVATE + ${GLOBAL_INC} +) + + add_executable(tester) target_sources(tester PRIVATE src/test.cpp @@ -51,4 +68,6 @@ target_include_directories(main PRIVATE target_link_libraries(main PRIVATE parser syntaxer + assembler + dyn-pipeline ) diff --git a/config.h b/config.h index 8747f64..93d4440 100644 --- a/config.h +++ b/config.h @@ -1,9 +1,13 @@ #pragma once -#define DEBUG 1 +#define PRINT_DEBUG 1 +#define PRINT_INFO 1 #define PRINT_DISABLE_PREFIXES 1 #define MAX_TOKEN_STRING_LEN 256 #define LAB2_EXCLUDE_COMPTIME_OP_WRITES 1 #define LAB2_PREVENT_NON_FOLDED_DIV_BY_ZERO 1 + +#define DYN_PIPELINE_MEM_SIZE 512 +#define DYN_PIPELINE_LAYERS 3 diff --git a/inc/assembler.hpp b/inc/assembler.hpp new file mode 100644 index 0000000..7f60ebd --- /dev/null +++ b/inc/assembler.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "expression.hpp" +#include "dyn-pipeline.hpp" + +namespace Assembler { + +void assemble( + const Expression::TreeNode& root, + std::vector& program, + std::array& memory, + int& mem_used); + +} diff --git a/inc/dyn-pipeline.hpp b/inc/dyn-pipeline.hpp new file mode 100644 index 0000000..7076baa --- /dev/null +++ b/inc/dyn-pipeline.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include + +#include "config.h" + +namespace DynamicPipeline { + +enum CommandType : char +{ + ADD, + SUB, + MUL, + DIV, + POW, + CMD_COUNT +}; + +struct Command +{ + enum CommandType t; + uint16_t op1; + uint16_t op2; + uint16_t res; + + Command(enum CommandType t, uint16_t op1, uint16_t op2, uint16_t res) + : t(t), op1(op1), op2(op2), res(res) + { + + } +}; + +struct MemCell +{ + double v; + int ready; +}; + +class System +{ +private: + std::vector *program_memory; + std::array data_memory; + std::array delays {2, 2, 5, 5, 9}; + std::array layer_cmd {-1}; + unsigned int pc {0}; + unsigned int system_time; + + void print_pipeline(void) const; + bool pipeline_empty(void) const; + bool next_instruction(void) const; + bool instruction_ready(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/inc/expression.hpp b/inc/expression.hpp index b423261..0ca3afe 100644 --- a/inc/expression.hpp +++ b/inc/expression.hpp @@ -24,7 +24,8 @@ public: SUB, MUL, DIV, - POW + POW, + NOP // not an operator }; union TokenValue { @@ -358,7 +359,7 @@ public: // if value, left and right hands should be null explicit TreeNode(void) - : l(nullptr), r(nullptr), o() + : l(nullptr), r(nullptr), o(Token::NOP) { } diff --git a/inc/print.h b/inc/print.h index 11ecc85..72389af 100644 --- a/inc/print.h +++ b/inc/print.h @@ -1,9 +1,10 @@ #pragma once #include +#include #include "config.h" -#if DEBUG == 1 +#if PRINT_DEBUG == 1 #if PRINT_DISABLE_PREFIXES == 1 #define pr_debug(...) std::cout << "debug: " << __VA_ARGS__ << "\n" #define pri_debug(...) std::cout << __VA_ARGS__ @@ -19,6 +20,22 @@ #define prs_debug(...) do {} while (0) #endif +#if PRINT_INFO == 1 + #if PRINT_DISABLE_PREFIXES == 1 + #define pr_info(...) std::cout << "info: " << __VA_ARGS__ << "\n" + #define pri_info(...) std::cout << __VA_ARGS__ + #define prs_info(...) std::cout << "info: " << __VA_ARGS__ + #else + #define pr_info(...) std::cout << "[" << __FILE__ << ":" << __LINE__ << " " << __func__ << "] info: " << __VA_ARGS__ << "\n" + #define pri_info(...) std::cout << __VA_ARGS__ + #define prs_info(...) std::cout << "[" << __FILE__ << ":" << __LINE__ << " " << __func__ << "] info: " << __VA_ARGS__ + #endif +#else +#define pr_info(...) do {} while (0) +#define pri_info(...) do {} while (0) +#define prs_info(...) do {} while (0) +#endif + #if PRINT_DISABLE_PREFIXES == 1 #define pr_warn(...) std::cout << "warning: " << __VA_ARGS__ << "\n" #else diff --git a/inc/syntaxer.hpp b/inc/syntaxer.hpp index 2229486..ba53b10 100644 --- a/inc/syntaxer.hpp +++ b/inc/syntaxer.hpp @@ -8,7 +8,7 @@ namespace Syntax int prepare_token_vector(std::vector& tv); std::vector build_op_vector(const std::vector& tv); -Expression::TreeNode ov_to_tree(const std::vector tv, const std::vector& ov); -void print_op_tree(const std::vector tv, const std::vector& ov); +Expression::TreeNode ov_to_tree(const std::vector& tv, const std::vector& ov); +void print_op_tree(const std::vector& tv, const std::vector& ov); } diff --git a/src/assembler.cpp b/src/assembler.cpp new file mode 100644 index 0000000..fb772b5 --- /dev/null +++ b/src/assembler.cpp @@ -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& 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& program, + std::array& memory, + int& mem_used) +{ + (void) memory; + + int preload_mem = 0; + std::vector 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); + } +} + +} diff --git a/src/compiler.cpp b/src/compiler.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/dyn-pipeline.cpp b/src/dyn-pipeline.cpp new file mode 100644 index 0000000..0ba37b1 --- /dev/null +++ b/src/dyn-pipeline.cpp @@ -0,0 +1,161 @@ +#include "dyn-pipeline.hpp" +#include "print.h" + +namespace DynamicPipeline { + +void System::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; + } + + 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"); +} + +} diff --git a/src/main.cpp b/src/main.cpp index efdb27e..5f7b030 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 ov = Syntax::build_op_vector(tv); Expression::TreeNode root = Syntax::ov_to_tree(tv, ov); + + std::vector program; + std::array memory; + int mem_used; + Assembler::assemble(root, program, memory, mem_used); + + DynamicPipeline::System machine; + machine.init(&program, memory, mem_used); + machine.run(); } diff --git a/src/syntaxer.cpp b/src/syntaxer.cpp index f655b94..9b98521 100644 --- a/src/syntaxer.cpp +++ b/src/syntaxer.cpp @@ -1388,7 +1388,7 @@ finish: return ov; } -Expression::TreeNode ov_to_tree(const std::vector tv, const std::vector& ov) +Expression::TreeNode ov_to_tree(const std::vector& tv, const std::vector& ov) { Expression::TreeNode root; std::queue> queued_ops; @@ -1434,6 +1434,8 @@ Expression::TreeNode ov_to_tree(const std::vector tv, const s void print_op_tree(const Expression::TreeNode& root) { + (void) root; + std::vector> items_to_display; }