Compare commits
29
Commits
0777faa11d
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b32df937f | ||
|
|
ce9e806b4a | ||
|
|
0f0dac6a25 | ||
|
|
e8f3f76117 | ||
|
|
81deb637c0 | ||
|
|
f43a16d1b2 | ||
|
|
7a90247dc0 | ||
|
|
36b4596bd4 | ||
|
|
79a96aea77 | ||
|
|
ab4afb48e7 | ||
|
|
b15ae562fd | ||
|
|
0329ed8326 | ||
|
|
4c26353876 | ||
|
|
360628d65c | ||
|
|
e837671d15 | ||
|
|
10e0a487ab | ||
|
|
1a258cd051 | ||
|
|
f430b3616a | ||
|
|
ddcf261af7 | ||
|
|
89335fbdc6 | ||
|
|
1b4693029f | ||
|
|
e8c2293b50 | ||
|
|
0d39290709 | ||
|
|
84d28d3845 | ||
|
|
433ee2bb2e | ||
|
|
35e38127e7 | ||
|
|
1d056a736f | ||
|
|
a94e584f35 | ||
|
|
d97160e6ed |
+21
-1
@@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "-g")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra -Wpedantic")
|
||||
|
||||
project(pzks)
|
||||
|
||||
@@ -26,6 +26,24 @@ target_include_directories(syntaxer PRIVATE
|
||||
${GLOBAL_INC}
|
||||
)
|
||||
|
||||
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}
|
||||
)
|
||||
|
||||
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 +69,6 @@ target_include_directories(main PRIVATE
|
||||
target_link_libraries(main PRIVATE
|
||||
parser
|
||||
syntaxer
|
||||
assembler
|
||||
dyn-pipeline
|
||||
)
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
#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
|
||||
#define DYN_PIPELINE_OUT_OF_ORDER_EXECUTION 1
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "expression.hpp"
|
||||
#include "dyn-pipeline.hpp"
|
||||
|
||||
namespace Assembler {
|
||||
|
||||
void assemble(
|
||||
const Expression::TreeNode& root,
|
||||
std::vector<DynamicPipeline::Command>& program,
|
||||
std::array<double, DYN_PIPELINE_MEM_SIZE>& memory,
|
||||
int& mem_used);
|
||||
void to_ooe(
|
||||
std::vector<DynamicPipeline::CommandOOE>& p_ooe,
|
||||
std::vector<DynamicPipeline::Command>& p);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace DynamicPipeline {
|
||||
|
||||
enum CommandType : uint16_t
|
||||
{
|
||||
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 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;
|
||||
int ready;
|
||||
};
|
||||
|
||||
class System
|
||||
{
|
||||
private:
|
||||
std::vector<Command> *program_memory;
|
||||
std::array<MemCell, DYN_PIPELINE_MEM_SIZE> data_memory;
|
||||
std::array<int, DYN_PIPELINE_LAYERS> layer_cmd {-1};
|
||||
std::vector<std::pair<int, int>> layer_util;
|
||||
unsigned int pc {0};
|
||||
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;
|
||||
bool instruction_ready(void) const;
|
||||
void step(void);
|
||||
|
||||
public:
|
||||
void init(const std::vector<Command> * const prg, const std::array<double, DYN_PIPELINE_MEM_SIZE>& mem, const int init_mem_size);
|
||||
void run(void);
|
||||
void print_stats(void) const;
|
||||
};
|
||||
|
||||
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};
|
||||
std::vector<std::pair<int, int>> layer_util;
|
||||
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);
|
||||
void print_stats(void) const;
|
||||
};
|
||||
|
||||
}
|
||||
+110
-4
@@ -5,6 +5,8 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "print.h"
|
||||
|
||||
namespace Expression {
|
||||
|
||||
class Token {
|
||||
@@ -24,9 +26,35 @@ public:
|
||||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
POW
|
||||
POW,
|
||||
NOP // not an operator
|
||||
};
|
||||
|
||||
[[nodiscard]] static int weight_op(Operator o)
|
||||
{
|
||||
switch (o)
|
||||
{
|
||||
case Expression::Token::OPA:
|
||||
case Expression::Token::CPA:
|
||||
case Expression::Token::NOP:
|
||||
pr_warn("Unweightable operator - this is probably a bug!");
|
||||
return 0;
|
||||
case Expression::Token::ADD:
|
||||
return 1;
|
||||
case Expression::Token::SUB:
|
||||
return 1;
|
||||
case Expression::Token::MUL:
|
||||
return 2;
|
||||
case Expression::Token::DIV:
|
||||
return 2;
|
||||
case Expression::Token::POW:
|
||||
return 3;
|
||||
default:
|
||||
pr_warn("Impossible operator - this is a bug!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
union TokenValue {
|
||||
std::shared_ptr<std::string> s;
|
||||
double d;
|
||||
@@ -52,6 +80,7 @@ public:
|
||||
}
|
||||
|
||||
explicit TokenValue(void)
|
||||
: s(std::shared_ptr<std::string>())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -144,6 +173,7 @@ public:
|
||||
switch (t)
|
||||
{
|
||||
case VAR:
|
||||
new(&v.s) std::shared_ptr<std::string>;
|
||||
v.s = other.v.s;
|
||||
break;
|
||||
case CONST:
|
||||
@@ -174,7 +204,6 @@ public:
|
||||
return v.s;
|
||||
case CONST:
|
||||
{
|
||||
char buffer[128] = {0};
|
||||
return std::make_shared<std::string>((std::ostringstream() << v.d).str());
|
||||
}
|
||||
case OPERATOR:
|
||||
@@ -192,11 +221,14 @@ public:
|
||||
return v.s;
|
||||
case CONST:
|
||||
{
|
||||
char buffer[128] = {0};
|
||||
return std::make_shared<std::string>((std::ostringstream() << v.d).str());
|
||||
}
|
||||
case OPERATOR:
|
||||
return std::make_shared<std::string>(op_math_str());
|
||||
case CV:
|
||||
return std::make_shared<std::string>((std::ostringstream() << "t" << v.cv.i).str());
|
||||
case NAT:
|
||||
return std::make_shared<std::string>("");
|
||||
default:
|
||||
return std::make_shared<std::string>("Not a valid token!");
|
||||
}
|
||||
@@ -272,6 +304,58 @@ public:
|
||||
return "Invalid operator";
|
||||
}
|
||||
}
|
||||
|
||||
int negative_operator(void) const
|
||||
{
|
||||
if (t != OPERATOR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (v.o == SUB || v.o == DIV);
|
||||
}
|
||||
|
||||
static int is_negative(Operator o)
|
||||
{
|
||||
return (o == SUB || o == DIV);
|
||||
}
|
||||
|
||||
int is_math_op(void) const
|
||||
{
|
||||
if (t != OPERATOR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (v.o)
|
||||
{
|
||||
case OPA:
|
||||
case CPA:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int is_opa(void) const
|
||||
{
|
||||
if (t != OPERATOR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return v.o == OPA;
|
||||
}
|
||||
|
||||
int is_cpa(void) const
|
||||
{
|
||||
if (t != OPERATOR)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return v.o == CPA;
|
||||
}
|
||||
};
|
||||
|
||||
struct Operation
|
||||
@@ -302,7 +386,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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -323,6 +407,28 @@ public:
|
||||
delete r;
|
||||
}
|
||||
}
|
||||
|
||||
int weight() const
|
||||
{
|
||||
int w = 0;
|
||||
|
||||
if (l != nullptr)
|
||||
{
|
||||
w += l->weight();
|
||||
}
|
||||
|
||||
if (r != nullptr)
|
||||
{
|
||||
w += r->weight();
|
||||
}
|
||||
|
||||
if (o.t == Token::OPERATOR)
|
||||
{
|
||||
w += Token::weight_op(o.v.o);
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@ std::vector<Expression::Token> tokenize_input(const char * const input_string);
|
||||
int assert_same(const std::vector<Expression::Token>& a, const std::vector<Expression::Token>& b);
|
||||
void print_token_vector(const std::vector<Expression::Token>& tv);
|
||||
void print_math_vector(const std::vector<Expression::Token>& tv);
|
||||
void print_math_vector(const std::vector<Expression::Token>& tv, const std::vector<int>& highlight_locations);
|
||||
|
||||
}
|
||||
|
||||
+18
-1
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#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
|
||||
|
||||
+3
-4
@@ -6,10 +6,9 @@
|
||||
namespace Syntax
|
||||
{
|
||||
|
||||
int check_syntax(std::vector<Expression::Token>& tv);
|
||||
void apply_corrections(std::vector<Expression::Token>& tv);
|
||||
int prepare_token_vector(std::vector<Expression::Token>& tv);
|
||||
std::vector<Expression::Operation> build_op_vector(const std::vector<Expression::Token>& tv);
|
||||
Expression::TreeNode ov_to_tree(const std::vector<Expression::Token> tv, const std::vector<Expression::Operation>& ov);
|
||||
void print_op_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);
|
||||
void print_op_tree(const Expression::TreeNode &node);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#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;
|
||||
const Expression::TreeNode * node;
|
||||
|
||||
Command(DynamicPipeline::CommandType opcode, OpSrc left_src, OpSrc right_src, int left_index, int right_index, const Expression::TreeNode * const node)
|
||||
: opcode(opcode), left_src(left_src), left_index(left_index), right_src(right_src), right_index(right_index)
|
||||
{
|
||||
this->node = const_cast<const Expression::TreeNode *>(node);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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.v.o - 2), lo, ro, left, right, &node);
|
||||
|
||||
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());
|
||||
|
||||
std::vector<bool> command_used;
|
||||
for (int i = 0, l = commands.size(); i < l; i++)
|
||||
{
|
||||
command_used.emplace_back(false);
|
||||
}
|
||||
|
||||
for (int i = 0, l = commands.size(); i < l; i++)
|
||||
{
|
||||
int lowest_weight_idx = 0;
|
||||
|
||||
for (int j = 0; j < l; j++)
|
||||
{
|
||||
if (!command_used[j])
|
||||
{
|
||||
pr_debug("Starting from " << j);
|
||||
lowest_weight_idx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = lowest_weight_idx + 1; j < l; j++)
|
||||
{
|
||||
if (!command_used[j] && commands[j].node->weight() < commands[lowest_weight_idx].node->weight())
|
||||
{
|
||||
lowest_weight_idx = j;
|
||||
}
|
||||
}
|
||||
|
||||
Command &cmd = commands[lowest_weight_idx];
|
||||
pr_debug("Selecting command idx=" << lowest_weight_idx << " with weight=" << cmd.node->weight());
|
||||
pr_debug(cmd.opcode << " "
|
||||
<< cmd.left_src << " " << cmd.left_index << " "
|
||||
<< cmd.right_src << " " << cmd.right_index << " "
|
||||
<< preload_mem + lowest_weight_idx);
|
||||
|
||||
program.emplace_back(cmd.opcode, cmd.left_src * preload_mem + cmd.left_index, cmd.right_src * preload_mem + cmd.right_index, preload_mem + lowest_weight_idx);
|
||||
|
||||
command_used[lowest_weight_idx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
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,251 @@
|
||||
#include "dyn-pipeline.hpp"
|
||||
#include "print.h"
|
||||
#include "expression.hpp"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace DynamicPipeline {
|
||||
|
||||
[[nodiscard]] 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 + record layer_util
|
||||
int time_taken = 0;
|
||||
int util = 0;
|
||||
for (int i = 0; i < DYN_PIPELINE_LAYERS; i++)
|
||||
{
|
||||
if (layer_cmd[i] == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
util++; // layer is loaded with operation
|
||||
|
||||
if (const int d = weight_op((*program_memory)[layer_cmd[i]].t); d > time_taken)
|
||||
{
|
||||
time_taken = d;
|
||||
}
|
||||
}
|
||||
layer_util.emplace_back(util, time_taken);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
void SystemOOE::print_stats(void) const
|
||||
{
|
||||
int total_prog_time = 0;
|
||||
|
||||
for (unsigned int i = 0; i < program_memory->size(); i++)
|
||||
{
|
||||
total_prog_time += weight_op((*program_memory)[i].t) * DYN_PIPELINE_LAYERS;
|
||||
}
|
||||
|
||||
pr_info("S = " << total_prog_time << " / " << system_time
|
||||
<< " = " << (float) total_prog_time / system_time);
|
||||
|
||||
int total_pipeline_used = 0;
|
||||
|
||||
for (unsigned int i = 0; i < layer_util.size(); i++)
|
||||
{
|
||||
total_pipeline_used += layer_util[i].first * layer_util[i].second;
|
||||
}
|
||||
|
||||
pr_info("E = " << total_pipeline_used << " / " << system_time * DYN_PIPELINE_LAYERS
|
||||
<< " = " << (float) total_pipeline_used / (system_time * DYN_PIPELINE_LAYERS));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
#include "dyn-pipeline.hpp"
|
||||
#include "print.h"
|
||||
#include "expression.hpp"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace DynamicPipeline {
|
||||
|
||||
[[nodiscard]] 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 System::print_program_memory(void) const
|
||||
{
|
||||
pr_info("Program memory dump: " << program_memory->size() * sizeof(struct Command) << " bytes");
|
||||
pr_info("### cmd op1 op2 res");
|
||||
|
||||
for (int i = 0, l = program_memory->size(); i < l; i++)
|
||||
{
|
||||
const struct Command &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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
print_program_memory();
|
||||
pri_info("\n");
|
||||
}
|
||||
|
||||
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] << " (" << 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 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 + record layer_util
|
||||
int time_taken = 1;
|
||||
int util = 0;
|
||||
for (int i = 0; i < DYN_PIPELINE_LAYERS; i++)
|
||||
{
|
||||
if (layer_cmd[i] == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
util++; // layer is loaded with operation
|
||||
|
||||
if (const int d = weight_op((*program_memory)[layer_cmd[i]].t); d > time_taken)
|
||||
{
|
||||
time_taken = d;
|
||||
}
|
||||
}
|
||||
layer_util.emplace_back(util, time_taken);
|
||||
|
||||
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 << " (" << 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 (instruction_ready())
|
||||
{
|
||||
Command &cmd = (*program_memory)[pc];
|
||||
pr_info("Instruction " << pc << " (" << op_to_str(cmd.t) << ") reads " << cmd.op1 << " and " << cmd.op2 << " and enters the pipeline");
|
||||
|
||||
layer_cmd[0] = pc;
|
||||
|
||||
pc++;
|
||||
}
|
||||
|
||||
pr_info("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");
|
||||
}
|
||||
|
||||
void System::print_stats(void) const
|
||||
{
|
||||
int total_prog_time = 0;
|
||||
|
||||
for (unsigned int i = 0; i < program_memory->size(); i++)
|
||||
{
|
||||
total_prog_time += weight_op((*program_memory)[i].t) * DYN_PIPELINE_LAYERS;
|
||||
}
|
||||
|
||||
pr_info("S = " << total_prog_time << " / " << system_time
|
||||
<< " = " << (float) total_prog_time / system_time);
|
||||
|
||||
int total_pipeline_used = 0;
|
||||
|
||||
for (unsigned int i = 0; i < layer_util.size(); i++)
|
||||
{
|
||||
total_pipeline_used += layer_util[i].first * layer_util[i].second;
|
||||
}
|
||||
|
||||
pr_info("E = " << total_pipeline_used << " / " << system_time * DYN_PIPELINE_LAYERS
|
||||
<< " = " << (float) total_pipeline_used / (system_time * DYN_PIPELINE_LAYERS));
|
||||
}
|
||||
|
||||
}
|
||||
+24
-3
@@ -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)
|
||||
{
|
||||
@@ -10,14 +14,31 @@ int main(int argc, char **argv)
|
||||
|
||||
std::vector<Expression::Token> tv = Parser::tokenize_input(argv[1]);
|
||||
|
||||
if (Syntax::check_syntax(tv))
|
||||
if (Syntax::prepare_token_vector(tv))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Syntax::apply_corrections(tv);
|
||||
|
||||
std::vector<Expression::Operation> ov = Syntax::build_op_vector(tv);
|
||||
|
||||
Expression::TreeNode root = Syntax::ov_to_tree(tv, ov);
|
||||
Syntax::print_op_tree(root);
|
||||
|
||||
std::vector<DynamicPipeline::Command> program;
|
||||
std::array<double, DYN_PIPELINE_MEM_SIZE> memory;
|
||||
int 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;
|
||||
machine.init(&program, memory, mem_used);
|
||||
#endif
|
||||
machine.run();
|
||||
machine.print_stats();
|
||||
}
|
||||
|
||||
+29
-4
@@ -35,8 +35,6 @@ class Parser
|
||||
|
||||
int switch_state(enum State e)
|
||||
{
|
||||
pr_debug("Leaving " << state_str(s) << ", entering " << state_str(e));
|
||||
|
||||
int cumulative_backtrack = 0;
|
||||
|
||||
switch (s)
|
||||
@@ -79,8 +77,6 @@ class Parser
|
||||
|
||||
s = e;
|
||||
|
||||
pr_debug("Cumulative backtrack is " << cumulative_backtrack);
|
||||
|
||||
return cumulative_backtrack;
|
||||
}
|
||||
|
||||
@@ -397,4 +393,33 @@ void print_math_vector(const std::vector<Expression::Token>& tv)
|
||||
}
|
||||
}
|
||||
|
||||
void print_math_vector(const std::vector<Expression::Token>& tv, const std::vector<int>& highlight_locations)
|
||||
{
|
||||
int i, l, h, hl;
|
||||
for (i = 0, l = tv.size() - 1, h = 0, hl = highlight_locations.size(); i < l; i++)
|
||||
{
|
||||
if (h < hl && highlight_locations[h] == i)
|
||||
{
|
||||
std::cout << "\033[31m" << *tv[i].to_math_str() << "\033[0m";
|
||||
h++;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << *tv[i].to_math_str();;
|
||||
}
|
||||
}
|
||||
|
||||
if (tv.size())
|
||||
{
|
||||
if (highlight_locations[highlight_locations.size()-1] == (long) (tv.size() - 1))
|
||||
{
|
||||
std::cout << "\033[31m" << *tv[tv.size() - 1].to_math_str() << "\033[0m\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << *tv[tv.size() - 1].to_math_str() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1091
-479
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -99,7 +99,10 @@ TEST(tree_proper_test_1)
|
||||
TEST(tree_proper_test_2)
|
||||
{
|
||||
std::vector<Expression::Token> o = Parser::tokenize_input("(1**5 * (1-2-3-4-5-6-7-8))");
|
||||
Syntax::apply_corrections(o);
|
||||
if (Syntax::prepare_token_vector(o))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
std::vector<Expression::Operation> ov = Syntax::build_op_vector(o);
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user