Fix assignment to VHDL function arguments
This patch is a fix for pr2516774. The idea is to generate a local variable inside a function whenever an argument is assigned to. The variable has an initial value of the argument value and is used in its place for the remainder of the function. This patch also handles the case where the argument is assigned to inside a while loop.
This commit is contained in:
parent
e6846ea3a7
commit
78bc4b5d47
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL code generation for statements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -137,9 +137,29 @@ static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope)
|
|||
string signame(get_renamed_signal(sig));
|
||||
vhdl_decl *decl = scope->get_decl(signame);
|
||||
assert(decl);
|
||||
|
||||
// Verilog allows assignments to elements that are constant in VHDL:
|
||||
// function parameters, for example
|
||||
// To work around this we generate a local variable to shadow the
|
||||
// constant and assign to that
|
||||
if (decl->assignment_type() == vhdl_decl::ASSIGN_CONST) {
|
||||
const string shadow_name = signame + "_Shadow";
|
||||
vhdl_var_decl* shadow_decl =
|
||||
new vhdl_var_decl(shadow_name, decl->get_type());
|
||||
shadow_decl->set_initial
|
||||
(new vhdl_var_ref(signame, decl->get_type()));
|
||||
scope->add_decl(shadow_decl);
|
||||
|
||||
// Make sure all future references to this signal use the
|
||||
// shadow variable
|
||||
rename_signal(sig, shadow_name);
|
||||
|
||||
// ...and use this new variable as the assignment LHS
|
||||
decl = shadow_decl;
|
||||
}
|
||||
|
||||
vhdl_type *ltype = new vhdl_type(*decl->get_type());
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype);
|
||||
vhdl_var_ref *lval_ref = new vhdl_var_ref(decl->get_name(), ltype);
|
||||
if (base) {
|
||||
if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY)
|
||||
lval_ref->set_slice(base, 0);
|
||||
|
|
@ -175,6 +195,7 @@ assign_for(vhdl_decl::assign_type_t atype, vhdl_var_ref *lhs, vhdl_expr *rhs)
|
|||
{
|
||||
switch (atype) {
|
||||
case vhdl_decl::ASSIGN_BLOCK:
|
||||
case vhdl_decl::ASSIGN_CONST:
|
||||
return new vhdl_assign_stmt(lhs, rhs);
|
||||
case vhdl_decl::ASSIGN_NONBLOCK:
|
||||
return new vhdl_nbassign_stmt(lhs, rhs);
|
||||
|
|
@ -1336,6 +1357,16 @@ int draw_casezx(vhdl_procedural *proc, stmt_container *container,
|
|||
int draw_while(vhdl_procedural *proc, stmt_container *container,
|
||||
ivl_statement_t stmt)
|
||||
{
|
||||
// Generate the body inside a temporary container before
|
||||
// generating the test
|
||||
// The reason for this is that some of the signals in the
|
||||
// test might be renamed while expanding the body (e.g. if
|
||||
// we need to generate an assignment to a constant signal)
|
||||
stmt_container tmp_container;
|
||||
int rc = draw_stmt(proc, &tmp_container, ivl_stmt_sub_stmt(stmt));
|
||||
if (rc != 0)
|
||||
return 1;
|
||||
|
||||
vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt));
|
||||
if (NULL == test)
|
||||
return 1;
|
||||
|
|
@ -1346,10 +1377,9 @@ int draw_while(vhdl_procedural *proc, stmt_container *container,
|
|||
test = test->cast(&boolean);
|
||||
|
||||
vhdl_while_stmt *loop = new vhdl_while_stmt(test);
|
||||
container->add_stmt(loop);
|
||||
|
||||
draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt));
|
||||
|
||||
container->add_stmt(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* VHDL abstract syntax elements.
|
||||
*
|
||||
* Copyright (C) 2008 Nick Gasson (nick@nickg.me.uk)
|
||||
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
|
@ -26,13 +26,15 @@
|
|||
#include "vhdl_element.hh"
|
||||
#include "vhdl_type.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class vhdl_scope;
|
||||
class vhdl_entity;
|
||||
class vhdl_arch;
|
||||
|
||||
class vhdl_expr : public vhdl_element {
|
||||
public:
|
||||
vhdl_expr(vhdl_type* type, bool isconst=false)
|
||||
vhdl_expr(const vhdl_type* type, bool isconst=false)
|
||||
: type_(type), isconst_(isconst) {}
|
||||
virtual ~vhdl_expr();
|
||||
|
||||
|
|
@ -46,7 +48,7 @@ public:
|
|||
virtual vhdl_expr *to_std_logic();
|
||||
virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w);
|
||||
protected:
|
||||
vhdl_type *type_;
|
||||
const vhdl_type *type_;
|
||||
bool isconst_;
|
||||
};
|
||||
|
||||
|
|
@ -56,7 +58,7 @@ protected:
|
|||
*/
|
||||
class vhdl_var_ref : public vhdl_expr {
|
||||
public:
|
||||
vhdl_var_ref(const char *name, vhdl_type *type,
|
||||
vhdl_var_ref(const string& name, const vhdl_type *type,
|
||||
vhdl_expr *slice = NULL)
|
||||
: vhdl_expr(type), name_(name), slice_(slice) {}
|
||||
~vhdl_var_ref();
|
||||
|
|
@ -538,7 +540,7 @@ private:
|
|||
*/
|
||||
class vhdl_decl : public vhdl_element {
|
||||
public:
|
||||
vhdl_decl(const char *name, vhdl_type *type = NULL,
|
||||
vhdl_decl(const string& name, const vhdl_type *type = NULL,
|
||||
vhdl_expr *initial = NULL)
|
||||
: name_(name), type_(type), initial_(initial),
|
||||
has_initial_(initial != NULL) {}
|
||||
|
|
@ -551,7 +553,9 @@ public:
|
|||
bool has_initial() const { return has_initial_; }
|
||||
|
||||
// The different sorts of assignment statement
|
||||
enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK };
|
||||
// ASSIGN_CONST is used to generate a variable to shadow a
|
||||
// constant that cannot be assigned to (e.g. a function parameter)
|
||||
enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK, ASSIGN_CONST };
|
||||
|
||||
// Get the sort of assignment statement to generate for
|
||||
// assignemnts to this declaration
|
||||
|
|
@ -561,7 +565,7 @@ public:
|
|||
virtual assign_type_t assignment_type() const { assert(false); }
|
||||
protected:
|
||||
std::string name_;
|
||||
vhdl_type *type_;
|
||||
const vhdl_type *type_;
|
||||
vhdl_expr *initial_;
|
||||
bool has_initial_;
|
||||
};
|
||||
|
|
@ -589,7 +593,7 @@ private:
|
|||
|
||||
class vhdl_type_decl : public vhdl_decl {
|
||||
public:
|
||||
vhdl_type_decl(const char *name, vhdl_type *base)
|
||||
vhdl_type_decl(const string& name, const vhdl_type *base)
|
||||
: vhdl_decl(name, base) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
};
|
||||
|
|
@ -600,7 +604,7 @@ public:
|
|||
*/
|
||||
class vhdl_var_decl : public vhdl_decl {
|
||||
public:
|
||||
vhdl_var_decl(const char *name, vhdl_type *type)
|
||||
vhdl_var_decl(const string& name, const vhdl_type *type)
|
||||
: vhdl_decl(name, type) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
assign_type_t assignment_type() const { return ASSIGN_BLOCK; }
|
||||
|
|
@ -627,6 +631,7 @@ public:
|
|||
vhdl_param_decl(const char *name, vhdl_type *type)
|
||||
: vhdl_decl(name, type) {}
|
||||
void emit(std::ostream &of, int level) const;
|
||||
assign_type_t assignment_type() const { return ASSIGN_CONST; }
|
||||
};
|
||||
|
||||
enum vhdl_port_mode_t {
|
||||
|
|
|
|||
Loading…
Reference in New Issue