diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index a67f95864..dc6a82755 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -56,10 +56,15 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // However, if no statements were added to the container // by draw_stmt, don't bother adding a wait as `emit' // will optimise the process out of the output - if (ivl_process_type(proc) == IVL_PR_INITIAL - && !vhdl_proc->get_container()->empty()) { - vhdl_wait_stmt *wait = new vhdl_wait_stmt(); - vhdl_proc->get_container()->add_stmt(wait); + if (ivl_process_type(proc) == IVL_PR_INITIAL) { + // Get rid of any useless `wait for 0 ns's at the end of the process + prune_wait_for_0(vhdl_proc->get_container()); + + // The above pruning might have removed all logic from the process + if (!vhdl_proc->get_container()->empty()) { + vhdl_wait_stmt *wait = new vhdl_wait_stmt(); + vhdl_proc->get_container()->add_stmt(wait); + } } // Add a comment indicating where it came from diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 919e420d1..19e4ea3ad 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -396,7 +396,7 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, // the process if (!is_last) container->add_stmt - (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); + (new vhdl_wait_stmt(VHDL_WAIT_FOR0)); } else make_assignment(proc, container, stmt, true); @@ -404,6 +404,27 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, return 0; } +/* + * The VHDL code generator inserts `wait for 0 ns' after each + * not-last-in-block blocking assignment. + * If this is immediately followed by another `wait for ...' then + * we might as well not emit the first zero-time wait. + */ +void prune_wait_for_0(stmt_container *container) +{ + vhdl_wait_stmt *wait0; + stmt_container::stmt_list_t &stmts = container->get_stmts(); + while (stmts.size() > 0 + && (wait0 = dynamic_cast(stmts.back()))) { + if (wait0->get_type() == VHDL_WAIT_FOR0) { + delete wait0; + stmts.pop_back(); + } + else + break; + } +} + /* * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. @@ -429,6 +450,8 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, return 1; } + prune_wait_for_0(container); + ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR, time); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index b40176b85..c610e10c5 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -316,6 +316,9 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const of << " for "; expr_->emit(of, level); break; + case VHDL_WAIT_FOR0: + of << " for 0 ns"; + break; case VHDL_WAIT_UNTIL: assert(expr_); of << " until "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 17eae7758..d7f30c43c 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -335,8 +335,11 @@ public: void add_stmt(vhdl_seq_stmt *stmt); void emit(std::ostream &of, int level, bool newline=true) const; bool empty() const { return stmts_.empty(); } + + typedef std::list stmt_list_t; + stmt_list_t &get_stmts() { return stmts_; } private: - std::list stmts_; + stmt_list_t stmts_; }; @@ -381,6 +384,7 @@ public: enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR, // Wait for a constant amount of time + VHDL_WAIT_FOR0, // Special wait for zero time VHDL_WAIT_UNTIL, // Wait on an expression VHDL_WAIT_ON, // Wait on a sensitivity list }; @@ -398,6 +402,7 @@ public: void emit(std::ostream &of, int level) const; void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); } + vhdl_wait_type_t get_type() const { return type_; } private: vhdl_wait_type_t type_; vhdl_expr *expr_; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index cf0adf890..031428d9a 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -44,7 +44,7 @@ ivl_signal_t find_signal_named(const string &name, const vhdl_scope *scope); int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true); - +void prune_wait_for_0(stmt_container *container); void require_support_function(support_function_t f); #endif /* #ifndef INC_VHDL_TARGET_H */