Support named blocks with local variables in VHDL target
This patch adds code to generate process-local variables for scopes of type IVL_SCT_BLOCK. This also handles using the correct assignment operator (:=) for the local VHDL variables.
This commit is contained in:
parent
3f0b798ef6
commit
501106dc92
|
|
@ -27,9 +27,6 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
static string make_safe_name(ivl_signal_t sig);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This represents the portion of a nexus that is visible within
|
* This represents the portion of a nexus that is visible within
|
||||||
* a VHDL scope. If that nexus portion does not contain a signal,
|
* a VHDL scope. If that nexus portion does not contain a signal,
|
||||||
|
|
@ -379,10 +376,8 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope)
|
||||||
draw_logic(arch, ivl_scope_log(scope, i));
|
draw_logic(arch, ivl_scope_log(scope, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Make sure a signal name conforms to VHDL naming rules.
|
||||||
* Make sure a signal name conforms to VHDL naming rules.
|
string make_safe_name(ivl_signal_t sig)
|
||||||
*/
|
|
||||||
static string make_safe_name(ivl_signal_t sig)
|
|
||||||
{
|
{
|
||||||
string base(ivl_signal_basename(sig));
|
string base(ivl_signal_basename(sig));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,14 +85,33 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate VHDL for a block of Verilog statements. This doesn't
|
* Generate VHDL for a block of Verilog statements. If this block
|
||||||
* actually do anything, other than recursively translate the
|
* doesn't have its own scope then this function does nothing, other
|
||||||
* block's statements and add them to the process. This is OK as
|
* than recursively translate the block's statements and add them
|
||||||
* the stmt_container class behaves like a Verilog block.
|
* to the process. This is OK as the stmt_container class behaves
|
||||||
|
* like a Verilog block.
|
||||||
|
*
|
||||||
|
* If this block has its own scope with local variables then these
|
||||||
|
* are added to the process as local variables and the statements
|
||||||
|
* are generated as above.
|
||||||
*/
|
*/
|
||||||
static int draw_block(vhdl_procedural *proc, stmt_container *container,
|
static int draw_block(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool is_last)
|
ivl_statement_t stmt, bool is_last)
|
||||||
{
|
{
|
||||||
|
ivl_scope_t block_scope = ivl_stmt_block_scope(stmt);
|
||||||
|
if (block_scope) {
|
||||||
|
int nsigs = ivl_scope_sigs(block_scope);
|
||||||
|
for (int i = 0; i < nsigs; i++) {
|
||||||
|
ivl_signal_t sig = ivl_scope_sig(block_scope, i);
|
||||||
|
remember_signal(sig, proc->get_scope());
|
||||||
|
|
||||||
|
vhdl_type* type = vhdl_type::type_for(ivl_signal_width(sig),
|
||||||
|
ivl_signal_signed(sig));
|
||||||
|
proc->get_scope()->add_decl
|
||||||
|
(new vhdl_var_decl(make_safe_name(sig), type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int count = ivl_stmt_block_count(stmt);
|
int count = ivl_stmt_block_count(stmt);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i);
|
ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i);
|
||||||
|
|
@ -112,6 +131,27 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
||||||
return 0;
|
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<vhdl_wait_stmt*>(stmts.back()))) {
|
||||||
|
if (wait0->get_type() == VHDL_WAIT_FOR0) {
|
||||||
|
delete wait0;
|
||||||
|
stmts.pop_back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
|
static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
|
||||||
{
|
{
|
||||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||||
|
|
@ -223,11 +263,13 @@ bool check_valid_assignment(vhdl_decl::assign_type_t atype, vhdl_procedural *pro
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Generate an assignment of type T for the Verilog statement stmt.
|
||||||
* Generate an assignment of type T for the Verilog statement stmt.
|
// If a statement was generated then `assign_type' will contain the
|
||||||
*/
|
// type of assignment that was generated; this should be initialised
|
||||||
|
// to some sensible default.
|
||||||
void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool blocking)
|
ivl_statement_t stmt, bool blocking,
|
||||||
|
vhdl_decl::assign_type_t& assign_type)
|
||||||
{
|
{
|
||||||
list<vhdl_var_ref*> lvals;
|
list<vhdl_var_ref*> lvals;
|
||||||
if (!assignment_lvals(stmt, proc, lvals))
|
if (!assignment_lvals(stmt, proc, lvals))
|
||||||
|
|
@ -257,6 +299,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
// of assignment statement to generate (is it a signal,
|
// of assignment statement to generate (is it a signal,
|
||||||
// a variable, etc?)
|
// a variable, etc?)
|
||||||
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
|
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
|
||||||
|
assign_type = decl->assignment_type();
|
||||||
|
|
||||||
// A small optimisation is to expand ternary RHSs into an
|
// A small optimisation is to expand ternary RHSs into an
|
||||||
// if statement (eliminates a function call and produces
|
// if statement (eliminates a function call and produces
|
||||||
|
|
@ -372,6 +415,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
// of assignment statement to generate (is it a signal,
|
// of assignment statement to generate (is it a signal,
|
||||||
// a variable, etc?)
|
// a variable, etc?)
|
||||||
vhdl_decl *decl = proc->get_scope()->get_decl((*it)->get_name());
|
vhdl_decl *decl = proc->get_scope()->get_decl((*it)->get_name());
|
||||||
|
assign_type = decl->assignment_type();
|
||||||
|
|
||||||
if (!check_valid_assignment(decl->assignment_type(), proc, stmt))
|
if (!check_valid_assignment(decl->assignment_type(), proc, stmt))
|
||||||
return;
|
return;
|
||||||
|
|
@ -386,6 +430,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
width_so_far += lval_width;
|
width_so_far += lval_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -398,7 +444,8 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
|
||||||
{
|
{
|
||||||
assert(proc->get_scope()->allow_signal_assignment());
|
assert(proc->get_scope()->allow_signal_assignment());
|
||||||
|
|
||||||
make_assignment(proc, container, stmt, false);
|
vhdl_decl::assign_type_t ignored;
|
||||||
|
make_assignment(proc, container, stmt, false, ignored);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -406,48 +453,30 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
|
||||||
static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
static int draw_assign(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool is_last)
|
ivl_statement_t stmt, bool is_last)
|
||||||
{
|
{
|
||||||
|
vhdl_decl::assign_type_t assign_type = vhdl_decl::ASSIGN_NONBLOCK;
|
||||||
if (proc->get_scope()->allow_signal_assignment()) {
|
if (proc->get_scope()->allow_signal_assignment()) {
|
||||||
// Blocking assignment is implemented as non-blocking assignment
|
// Blocking assignment is implemented as non-blocking assignment
|
||||||
// followed by a zero-time wait
|
// followed by a zero-time wait
|
||||||
// This follows the Verilog semantics fairly closely.
|
// This follows the Verilog semantics fairly closely.
|
||||||
|
|
||||||
make_assignment(proc, container, stmt, false);
|
make_assignment(proc, container, stmt, false, assign_type);
|
||||||
|
|
||||||
// Don't generate a zero-wait if this is the last statement in
|
// Don't generate a zero-wait if either:
|
||||||
// the process
|
// a) this is the last statement in the process
|
||||||
if (!is_last) {
|
// c) a blocking assignment was generated
|
||||||
|
if (!is_last && assign_type == vhdl_decl::ASSIGN_NONBLOCK) {
|
||||||
|
prune_wait_for_0(container);
|
||||||
container->add_stmt
|
container->add_stmt
|
||||||
(new vhdl_wait_stmt(VHDL_WAIT_FOR0));
|
(new vhdl_wait_stmt(VHDL_WAIT_FOR0));
|
||||||
proc->added_wait_stmt();
|
proc->added_wait_stmt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
make_assignment(proc, container, stmt, true);
|
make_assignment(proc, container, stmt, true, assign_type);
|
||||||
|
|
||||||
return 0;
|
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<vhdl_wait_stmt*>(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
|
* Delay statements are equivalent to the `wait for' form of the
|
||||||
* VHDL wait statement.
|
* VHDL wait statement.
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "vhdl_target.h"
|
#include "vhdl_target.h"
|
||||||
#include "vhdl_element.hh"
|
|
||||||
#include "state.hh"
|
#include "state.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@
|
||||||
#include "vhdl_config.h"
|
#include "vhdl_config.h"
|
||||||
#include "ivl_target.h"
|
#include "ivl_target.h"
|
||||||
|
|
||||||
#include "vhdl_syntax.hh"
|
|
||||||
#include "vhdl_type.hh"
|
|
||||||
|
|
||||||
#include "support.hh"
|
#include "support.hh"
|
||||||
|
#include "vhdl_syntax.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -29,6 +27,7 @@ vhdl_expr *translate_time_expr(ivl_expr_t e);
|
||||||
ivl_design_t get_vhdl_design();
|
ivl_design_t get_vhdl_design();
|
||||||
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
|
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
|
||||||
vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex);
|
vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex);
|
||||||
|
string make_safe_name(ivl_signal_t sig);
|
||||||
|
|
||||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool newline = true);
|
ivl_statement_t stmt, bool newline = true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue