Skip to content

Commit

Permalink
pipeline nesting
Browse files Browse the repository at this point in the history
  • Loading branch information
sylefeb committed Dec 9, 2023
1 parent aa9fb32 commit 9384354
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 59 deletions.
115 changes: 84 additions & 31 deletions src/Algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2456,7 +2456,7 @@ Algorithm::t_combinational_block *Algorithm::concatenatePipeline(siliceParser::P
resume = false; // no longer resuming
} else {
// set next stage
prev->pipeline_next(from, stage_end);
prev->pipeline_next(from);
}
// advance
prev = nfo->stages.back()->fsm->lastBlock;
Expand Down Expand Up @@ -2812,30 +2812,34 @@ bool Algorithm::isStateLessGraph(const t_combinational_block *head) const

// -------------------------------------------------

bool Algorithm::hasCombinationalExit(const t_combinational_block* head) const
void Algorithm::findNextStates( t_combinational_block* head, std::set< t_combinational_block*>& _exits) const
{
std::queue< const t_combinational_block* > q;
std::unordered_set< const t_combinational_block* > visited;
std::queue< t_combinational_block* > q;
std::unordered_set< t_combinational_block* > visited;
// initialize queue
q.push(head);
// explore
while (!q.empty()) {
auto cur = q.front();
q.pop();
visited.insert(cur);
// recurse
// get children
std::vector< t_combinational_block* > children;
cur->getChildren(children);
if (children.empty()) {
// we reached this combinational block and it has no children
// => combinational exit!
return true;
// ensure while is properly followed
if (cur->while_loop()) { // FIXME? this is due to when a while encloses the pipeline, as we do not explore other fsms
children.push_back(cur); // add self
}
// recurse
for (auto c : children) {
if (c == nullptr) {
// tags a forward ref (jump), non combinational exit => skip
sl_assert(false); // jumps should be resolved before
} else if (c->context.fsm != head->context.fsm) {
// other fsm => exit, store
_exits.insert(c);
} else if (c->is_state) {
// state, non combinational exit => skip
// state => exit, store
_exits.insert(c);
} else {
// explore further
if (visited.count(c) == 0) {
Expand All @@ -2844,7 +2848,6 @@ bool Algorithm::hasCombinationalExit(const t_combinational_block* head) const
}
}
}
return false;
}

// -------------------------------------------------
Expand Down Expand Up @@ -3043,7 +3046,7 @@ Algorithm::t_combinational_block *Algorithm::gatherIfElse(siliceParser::IfThenEl
}
// NOTE: We do not tag 'after' as being a state right now, so that we can then consider
// whether to collapse it into the 'else' of the conditional in case the 'if' jumps over it.
// NOTE: This prevent a special mechanism to avoid code duplication is preventIfElseCodeDup()
// NOTE: A special mechanism avoids code duplication, see preventIfElseCodeDup()
return after;
}

Expand All @@ -3070,7 +3073,7 @@ Algorithm::t_combinational_block *Algorithm::gatherIfThen(siliceParser::IfThenCo
}
// NOTE: We do not tag 'after' as being a state right now, so that we can then consider
// whether to collapse it into the 'else' of the conditional in case the 'if' jumps over it.
// NOTE: This prevent a special mechanism to avoid code duplication is preventIfElseCodeDup()
// NOTE: A special mechanism avoids code duplication, see preventIfElseCodeDup()
return after;
}

Expand Down Expand Up @@ -4146,6 +4149,63 @@ bool Algorithm::preventIfElseCodeDup(t_fsm_nfo* fsm)

// -------------------------------------------------

/*
padPipeline ensures that the last state of the pipeline stage fsm only
exit towards antoher stage fsm. If not, this implies the last state
may loop within the stage (e.g. on itself with a while or using gotos)
in which case the pipeline trigger will be incorrect. Such cases require
adding a state before termination, and hence preventing collapse of
next cycles within while loops and if-else (CL0004, CL0005)
*/
bool Algorithm::padPipeline(t_fsm_nfo* fsm)
{
// NOTE: expects stage ids to have been generate
bool changed = false;
if (!fsmIsEmpty(fsm)) {
// get blocks
std::unordered_set<t_combinational_block*> blocks;
fsmGetBlocks(fsm, blocks);
// last state
int last_state_id = fsm->lastBlock->parent_state_id;
// find the block
t_combinational_block* last = nullptr;
for (auto b : blocks) {
if (b->state_id == last_state_id) {
last = b;
break;
}
}
// find all possible exits
std::set<t_combinational_block*> exits;
findNextStates(last, exits);
// count exits which are in the same fsm (other are ok; they won't lead to an incorrect pipeline start)
int same_fsm_exits = 0;
for (auto e : exits) {
if (e->context.fsm == fsm) {
++same_fsm_exits;
}
}
// check: multiple exits, and one at least in same fsm
if (exits.size() > 1 && same_fsm_exits > 0) {
// TODO: can we do better than to explictely list all cases?
if (last->while_loop()) {
warn(Standard, last->srcloc, "The last state of the pipeline stage loops into the stage, an additional cycle has to be introduced after.");
last->while_loop()->after->is_state = true;
changed |= true;
} else if (last->if_then_else()) {
warn(Standard, last->srcloc, "The last state of the pipeline stage loops into the stage, an additional cycle has to be introduced after.");
last->if_then_else()->after->is_state = true;
changed |= true;
} else {
sl_assert(false);
}
}
}
return changed;
}

// -------------------------------------------------

void Algorithm::renumberStates(t_fsm_nfo *fsm)
{
typedef struct {
Expand Down Expand Up @@ -4214,6 +4274,11 @@ void Algorithm::renumberStates(t_fsm_nfo *fsm)
void Algorithm::generateStates(t_fsm_nfo* fsm)
{
renumberStates(fsm);
if (fsm != &m_RootFSM) {
if (padPipeline(fsm)) { // only on pipeline fsms
renumberStates(fsm);
}
}
if (preventIfElseCodeDup(fsm)) { // NOTE: commenting this enables code duplication in if/else
renumberStates(fsm);
}
Expand Down Expand Up @@ -4272,11 +4337,6 @@ std::string Algorithm::fsmPipelineFirstStateDisable(const t_fsm_nfo *fsm) const
return "_1stdisable_" + fsm->name;
}

std::string Algorithm::fsmPipelineStageReachedEnd(const t_fsm_nfo* fsm) const
{
return "_reachedend_" + fsm->name;
}

// -------------------------------------------------

std::string Algorithm::fsmNextState(std::string prefix,const t_fsm_nfo *fsm) const
Expand Down Expand Up @@ -7487,17 +7547,15 @@ void Algorithm::writeFlipFlopDeclarations(std::string prefix, std::ostream& out,
if (!fsmIsEmpty(fsm)) {
out << "reg [" << stateWidth(fsm) - 1 << ":0] " FF_D << prefix << fsmIndex(fsm)
<< "," FF_Q << prefix << fsmIndex(fsm) << ';' << nxl;
out << "wire " << fsmPipelineStageReady(fsm) << " = "
// this condition allows to trigger the stage immediately after it reached its end state
<< "(" << FF_Q << prefix << fsmIndex(fsm) << " == " << toFSMState(fsm, lastPipelineStageState(fsm)) << " && " << FF_Q << prefix << fsmPipelineStageReachedEnd(fsm) << ')'
// this condition allows to trigger the stage when idle (becomes idle one cycle after it reached end)
<< " || (" << FF_Q << prefix << fsmIndex(fsm) << " == " << toFSMState(fsm, terminationState(fsm)) << ");" << nxl;
out << "wire " << fsmPipelineStageReady(fsm) << " = ";
// this condition allows to trigger the stage immediately after it reached its end state
out << "(" << FF_Q << prefix << fsmIndex(fsm) << " == " << toFSMState(fsm, lastPipelineStageState(fsm)) << ')';
// this condition allows to trigger the stage when idle (becomes idle one cycle after it reached end)
out << " || (" << FF_Q << prefix << fsmIndex(fsm) << " == " << toFSMState(fsm, terminationState(fsm)) << ");" << nxl;
out << "reg [0:0] " FF_D << prefix << fsmPipelineStageFull(fsm) << " = 0"
<< "," FF_Q << prefix << fsmPipelineStageFull(fsm) << " = 0;" << nxl;
out << "reg [0:0] " FF_TMP << prefix << fsmPipelineStageStall(fsm) << " = 0;" << nxl;
out << "reg [0:0] " FF_TMP << prefix << fsmPipelineFirstStateDisable(fsm) << " = 0;" << nxl;
out << "reg [0:0] " FF_D << prefix << fsmPipelineStageReachedEnd(fsm) << " = 0"
<< "," FF_Q << prefix << fsmPipelineStageReachedEnd(fsm) << " = 0;" << nxl;
}
}
// state machine caller id (subroutines)
Expand Down Expand Up @@ -7779,7 +7837,6 @@ void Algorithm::writeCombinationalAlwaysPre(
w.out << FF_D << "_" << fsmPipelineStageFull(fsm) << " = " << FF_Q << "_" << fsmPipelineStageFull(fsm) << ';' << nxl;
w.out << FF_TMP << "_" << fsmPipelineStageStall(fsm) << " = 0;" << nxl;
w.out << FF_TMP << "_" << fsmPipelineFirstStateDisable(fsm) << " = 0;" << nxl;
w.out << FF_D << "_" << fsmPipelineStageReachedEnd(fsm) << " = 0;" << nxl;
}
// instanced algorithms run, maintain high
for (const auto& iaiordr : m_InstancedBlueprintsInDeclOrder) {
Expand Down Expand Up @@ -8384,8 +8441,6 @@ void Algorithm::writeStatelessBlockGraph(
if (!fsmIsEmpty(fsm)) {
// stage full
w.out << FF_D << '_' << fsmPipelineStageFull(fsm) << " = 1;" << nxl;
// reached end
w.out << FF_D << "_" << fsmPipelineStageReachedEnd(fsm) << " = 1;" << nxl;
// first state of pipeline first stage?
sl_assert(block->context.pipeline_stage);
if (enclosed_in_conditional) { w.out << "end // 0" << nxl; } // end conditional
Expand Down Expand Up @@ -8674,8 +8729,6 @@ void Algorithm::writeStatelessBlockGraph(
if (!fsmIsEmpty(fsm)) {
// stage full
w.out << FF_D << '_' << fsmPipelineStageFull(fsm) << " = 1;" << nxl;
// reached end
w.out << FF_D << "_" << fsmPipelineStageReachedEnd(fsm) << " = 1;" << nxl;
// first state of pipeline first stage?
sl_assert(block->context.pipeline_stage);
if (enclosed_in_conditional) { w.out << "end // 7" << nxl; } // end conditional
Expand Down
18 changes: 8 additions & 10 deletions src/Algorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,9 +511,8 @@ namespace Silice
{
public:
t_combinational_block *next;
t_combinational_block *after;
end_action_pipeline_next(t_combinational_block *next_, t_combinational_block *after_) : next(next_), after(after_) { }
void getChildren(std::vector<t_combinational_block*>& _ch) const override { _ch.push_back(next); if (after != next) { _ch.push_back(after); } }
end_action_pipeline_next(t_combinational_block *next_) : next(next_) { }
void getChildren(std::vector<t_combinational_block*>& _ch) const override { _ch.push_back(next); }
std::string name() const override { return "end_action_pipeline_next";}
};

Expand Down Expand Up @@ -610,9 +609,9 @@ namespace Silice
}
const end_action_goto_and_return_to * goto_and_return_to() const { return dynamic_cast<const end_action_goto_and_return_to*>(end_action); }

void pipeline_next(t_combinational_block *next, t_combinational_block *after)
void pipeline_next(t_combinational_block *next)
{
swap_end(new end_action_pipeline_next(next, after));
swap_end(new end_action_pipeline_next(next));
}
const end_action_pipeline_next *pipeline_next() const { return dynamic_cast<const end_action_pipeline_next*>(end_action); }

Expand Down Expand Up @@ -833,8 +832,8 @@ namespace Silice
t_combinational_block *gatherJoinExec(siliceParser::JoinExecContext* join, t_combinational_block *_current, t_gather_context *_context);
/// \brief tests whether a graph of block is stateless
bool isStateLessGraph(const t_combinational_block *head) const;
/// \brief returns true if the graph has a combinational exit (one path that does not jump to an actual state)
bool hasCombinationalExit(const t_combinational_block *head) const;
/// \brief returns all the blocks which are next states
void findNextStates(t_combinational_block* head, std::set< t_combinational_block*>& _exits) const;
/// \brief gather an if-then-else
t_combinational_block *gatherIfElse(siliceParser::IfThenElseContext* ifelse, t_combinational_block *_current, t_gather_context *_context);
/// \brief gather an if-then
Expand Down Expand Up @@ -889,6 +888,8 @@ namespace Silice
void resolveForwardJumpRefs();
/// \brief performs a pass on all ifelse to prevent code duplication of after, returns true if states where changed
bool preventIfElseCodeDup(t_fsm_nfo* fsm);
/// \brief pad pipeline to ensure it ends on a 'simple' state (without multiple possible next state), returns true if states where changed
bool padPipeline(t_fsm_nfo* fsm);
/// \brief performs a numbering pass on the fsm states
void renumberStates(t_fsm_nfo*);
/// \brief generates the states of an fsm
Expand All @@ -905,9 +906,6 @@ namespace Silice
std::string fsmPipelineStageStall(const t_fsm_nfo *) const;
/// \brief returns the 'first state disable' signal name of the pipeline stage fsm
std::string fsmPipelineFirstStateDisable(const t_fsm_nfo *) const;
/// \brief returns the 'end of pipeline stage' signal name of the pipeline stage fsm
/// (signals the stage just passed the end of the last state, pulses once)
std::string fsmPipelineStageReachedEnd(const t_fsm_nfo* fsm) const;
/// \brief returns an expression that evaluates to the fsm next state
std::string fsmNextState(std::string prefix, const t_fsm_nfo *) const;
/// \brief returns whether the fsm is empty (no state)
Expand Down
50 changes: 32 additions & 18 deletions tests/pipeline29.si
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ algorithm main(output uint8 leds)
// stage 1
uint5 j = 0;
while (j != 3) {
{
// nested pipeline
__display("[B,A] %d,%d",n,j);
uint8 q = j + 10;
Expand All @@ -28,6 +29,7 @@ algorithm main(output uint8 leds)
q = q + 100;
->
__display("[B,C] %d,%d",n,q);
}
}
__display("[B] after (%d)",n);

Expand All @@ -38,52 +40,64 @@ algorithm main(output uint8 leds)
/*

[A] ( 0)
[B] before ( 0)
[A] ( 1)
[B] before ( 0)
[B,A] 0, 0
[B,B] 0, 10
[B,A] 0, 1
[B,C] 0,110
[B,B] 0, 11
[B,B] 0, 10
[B,A] 0, 2
[B,B] 0, 11
[B,C] 0,110
[B,A] 0, 3
[B,B] 0, 12
[B,C] 0,111
[B] after ( 0)
[B,B] 0, 12
[B,B] 0, 13
[B,C] 0,112
[A] ( 2)
[B] before ( 1)
[B,C] 1,113
[B,A] 1, 0
[B,B] 1, 10
[B,A] 1, 1
[B,C] 1,110
[B,B] 1, 11
[B,B] 1, 10
[B,A] 1, 2
[B,B] 1, 11
[B,C] 1,110
[B,A] 1, 3
[B,B] 1, 12
[B,C] 1,111
[B] after ( 1)
[B,B] 1, 12
[B,B] 1, 13
[B,C] 1,112
[A] ( 3)
[B] before ( 2)
[B,C] 2,113
[B,A] 2, 0
[B,B] 2, 10
[B,A] 2, 1
[B,C] 2,110
[B,B] 2, 11
[B,B] 2, 10
[B,A] 2, 2
[B,B] 2, 11
[B,C] 2,110
[B,A] 2, 3
[B,B] 2, 12
[B,C] 2,111
[B] after ( 2)
[B,B] 2, 12
[B,B] 2, 13
[B,C] 2,112
[B] before ( 3)
[B,C] 3,113
[B,A] 3, 0
[B,B] 3, 10
[B,A] 3, 1
[B,C] 3,110
[B,B] 3, 11
[B,B] 3, 10
[B,A] 3, 2
[B,B] 3, 11
[B,C] 3,110
[B,A] 3, 3
[B,B] 3, 12
[B,C] 3,111
[B] after ( 3)
[B,B] 3, 12
[B,B] 3, 13
[B,C] 3,112
[B,C] 3,113

*/
*/
Loading

0 comments on commit 9384354

Please sign in to comment.