From aa951af2b741eb8e6f8a3c6947b7ae721a2b14c3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 10 Jul 2008 19:27:17 +0100 Subject: [PATCH 01/57] Change 'signdness' to 'signdness' --- tgt-vhdl/expr.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index fadc0d3d4..28c8c7921 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -24,9 +24,9 @@ #include /* - * Change the signdness of a vector. + * Change the signedness of a vector. */ -static vhdl_expr *change_signdness(vhdl_expr *e, bool issigned) +static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned) { int msb = e->get_type()->get_msb(); int lsb = e->get_type()->get_lsb(); @@ -87,13 +87,13 @@ static vhdl_expr *translate_unary(ivl_expr_t e) //operand->print(); //std::cout << "^ should be signed but is not" << std::endl; - operand = change_signdness(operand, true); + operand = change_signedness(operand, true); } else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) { //operand->print(); //std::cout << "^ should be unsigned but is not" << std::endl; - operand = change_signdness(operand, false); + operand = change_signedness(operand, false); } char opcode = ivl_expr_opcode(e); @@ -284,13 +284,13 @@ static vhdl_expr *translate_binary(ivl_expr_t e) //result->print(); //std::cout << "^ should be signed but is not" << std::endl; - result = change_signdness(result, true); + result = change_signedness(result, true); } else if (result->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) { //result->print(); //std::cout << "^ should be unsigned but is not" << std::endl; - result = change_signdness(result, false); + result = change_signedness(result, false); } int actual_width = result->get_type()->get_width(); From 3bd480a375ee1e1c04f6b20ebeabd90b9be8a1b2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 12:41:02 +0100 Subject: [PATCH 02/57] Allow ouput to be read if connected to child output If output P of A is connected to output Q of B (and A is instantiated inside B) then VHDL does not allow B to read the value of Q (also P), but Verilog does. To get around this the output Q is mapped to P_Sig which is then connected to P, this allows B to read the value of P/Q via P_Sig. --- tgt-vhdl/scope.cc | 44 ++++++++++++++++++++++++++++++++++++++++- tgt-vhdl/vhdl.cc | 10 ++++++++++ tgt-vhdl/vhdl_syntax.cc | 1 + tgt-vhdl/vhdl_syntax.hh | 1 + tgt-vhdl/vhdl_target.h | 1 + 5 files changed, 56 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index a798efbd9..b01207bf8 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -389,7 +389,49 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, std::string name = make_safe_name(to); vhdl_var_ref *to_ref; if ((to_ref = dynamic_cast(to_e))) { - inst->map_port(name.c_str(), to_ref); + // If we're mapping an output of this entity to an output of + // the child entity, then VHDL will not let us read the value + // of the signal (i.e. it must pass straight through). + // However, Verilog allows the signal to be read in the parent. + // To get around this we create an internal signal name_Sig + // that takes the value of the output and can be read. + vhdl_decl *decl = + parent->get_arch()->get_scope()->get_decl(to_ref->get_name()); + vhdl_port_decl *pdecl; + if ((pdecl = dynamic_cast(decl)) + && pdecl->get_mode() == VHDL_PORT_OUT) { + + // We need to create a readable signal to shadow this output + std::string shadow_name(to_ref->get_name()); + shadow_name += "_Sig"; + + vhdl_signal_decl *shadow = + new vhdl_signal_decl(shadow_name.c_str(), + new vhdl_type(*decl->get_type())); + shadow->set_comment("Needed to make output readable"); + + parent->get_arch()->get_scope()->add_decl(shadow); + + // Make a continuous assignment of the shadow to the output + parent->get_arch()->add_stmt + (new vhdl_cassign_stmt + (to_ref, new vhdl_var_ref(shadow_name.c_str(), NULL))); + + // Make sure any future references to this signal read the + // shadow not the output + ivl_signal_t sig = find_signal_named(to_ref->get_name(), + parent->get_arch()->get_scope()); + rename_signal(sig, shadow_name); + + // Finally map the child port to the shadow signal + inst->map_port(name.c_str(), + new vhdl_var_ref(shadow_name.c_str(), NULL)); + } + else { + // Not an output port declaration therefore we can + // definitely read it + inst->map_port(name.c_str(), to_ref); + } } else { // Not a static expression diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index c8563c488..382f51b49 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -130,6 +130,16 @@ const std::string &get_renamed_signal(ivl_signal_t sig) return g_known_signals[sig].renamed; } +ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) +{ + signal_defn_map_t::const_iterator it; + for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) { + if ((*it).second.scope == scope && (*it).second.renamed == name) + return (*it).first; + } + assert(false); +} + ivl_design_t get_vhdl_design() { return g_design; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d509ebc00..fdae262b9 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -88,6 +88,7 @@ void vhdl_entity::emit(std::ostream &of, int level) const of << "use ieee.std_logic_1164.all;" << std::endl; of << "use ieee.numeric_std.all;" << std::endl; of << "use std.textio.all;" << std::endl; + //of << "use work.verilog_support.all;" << std::endl; of << std::endl; emit_comment(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 89b26d217..c866ee370 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -501,6 +501,7 @@ public: : vhdl_decl(name, type), mode_(mode) {} void emit(std::ostream &of, int level) const; + vhdl_port_mode_t get_mode() const { return mode_; } private: vhdl_port_mode_t mode_; }; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index c70870ca2..10438ce19 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -33,6 +33,7 @@ void remember_signal(ivl_signal_t sig, const vhdl_scope *scope); void rename_signal(ivl_signal_t sig, const std::string &renamed); const vhdl_scope *find_scope_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); +ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope); void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig); std::string strip_var(const std::string &str); From 27a40cfdcd0d01573c4131e0d49d954565a5b8d1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 13:02:17 +0100 Subject: [PATCH 03/57] Constant assignments to outputs If the Verilog source contained a continuous assignment of a constant to an output, it would not be present in the VHDL output. This patch generates a VHDL continous assignment in these cases. --- tgt-vhdl/scope.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b01207bf8..a939a2491 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -278,8 +278,21 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); break; case IVL_SIP_OUTPUT: - ent->get_scope()->add_decl - (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT)); + { + vhdl_port_decl *decl = + new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); + + // Check for constant values + // For outputs these must be continuous assigns of + // the constant to the port + vhdl_expr *init = nexus_to_const(ivl_signal_nex(sig, 0)); + if (init != NULL) { + vhdl_var_ref *ref = new vhdl_var_ref(name.c_str(), NULL); + ent->get_arch()->add_stmt(new vhdl_cassign_stmt(ref, init)); + } + + ent->get_scope()->add_decl(decl); + } if (ivl_signal_type(sig) == IVL_SIT_REG) { // A registered output @@ -292,7 +305,8 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) rename_signal(sig, newname.c_str()); vhdl_type *reg_type = new vhdl_type(*sig_type); - ent->get_arch()->get_scope()->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); + ent->get_arch()->get_scope()->add_decl + (new vhdl_signal_decl(newname.c_str(), reg_type)); // Create a concurrent assignment statement to // connect the register to the output From 6af201ea0332accb12f3ee78bb662ca190c9ea12 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 15:17:14 +0100 Subject: [PATCH 04/57] Refactor nexus expansion functions. Now a single function nexus_to_expr --- tgt-vhdl/scope.cc | 110 ++++++++++++++++------------------- tgt-vhdl/verilog_support.vhd | 6 ++ 2 files changed, 56 insertions(+), 60 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index a939a2491..e73b201f8 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -29,40 +29,24 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); static std::string make_safe_name(ivl_signal_t sig); /* - * Given a nexus find a constant value in it that can be used - * as an initial signal value. + * The types of VHDL object a nexus can be converted into. */ -static vhdl_expr *nexus_to_const(ivl_nexus_t nexus) -{ - int nptrs = ivl_nexus_ptrs(nexus); - for (int i = 0; i < nptrs; i++) { - ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); - - ivl_net_const_t con; - if ((con = ivl_nexus_ptr_con(nexus_ptr))) { - if (ivl_const_width(con) == 1) - return new vhdl_const_bit(ivl_const_bits(con)[0]); - else - return new vhdl_const_bits - (ivl_const_bits(con), ivl_const_width(con), - ivl_const_signed(con) != 0); - } - else { - // Ignore other types of nexus pointer - } - } - - return NULL; -} +enum vhdl_nexus_obj_t { + NEXUS_TO_VAR_REF = 1<<0, + NEXUS_TO_CONST = 1<<1, + NEXUS_TO_OTHER = 1<<2, +}; +#define NEXUS_TO_ANY \ + NEXUS_TO_VAR_REF | NEXUS_TO_CONST | NEXUS_TO_OTHER /* - * Given a nexus and an architecture scope, find the first signal - * that is connected to the nexus, if there is one. Never return - * a reference to 'ignore' if it is found in the nexus. + * Given a nexus, generate a VHDL expression object to represent it. + * The allowed VHDL expression types are given by vhdl_nexus_obj_t. */ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, + int allowed = NEXUS_TO_ANY, ivl_signal_t ignore = NULL) -{ +{ int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); @@ -70,7 +54,10 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_signal_t sig; ivl_net_logic_t log; ivl_lpm_t lpm; - if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { + ivl_net_const_t con; + ivl_switch_t sw; + if ((allowed & NEXUS_TO_VAR_REF) && + (sig = ivl_nexus_ptr_sig(nexus_ptr))) { if (!seen_signal_before(sig) || sig == ignore) continue; @@ -83,41 +70,28 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, vhdl_type *type = new vhdl_type(*(decl->get_type())); return new vhdl_var_ref(signame, type); } - else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { + else if ((allowed & NEXUS_TO_OTHER) && + (log = ivl_nexus_ptr_log(nexus_ptr))) { return translate_logic(arch_scope, log); } - else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { + else if ((allowed & NEXUS_TO_OTHER) && + (lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { vhdl_expr *e = lpm_to_expr(arch_scope, lpm); if (e) return e; } - else { - // Ignore other types of nexus pointer + else if ((allowed & NEXUS_TO_CONST) && + (con = ivl_nexus_ptr_con(nexus_ptr))) { + if (ivl_const_width(con) == 1) + return new vhdl_const_bit(ivl_const_bits(con)[0]); + else + return new vhdl_const_bits + (ivl_const_bits(con), ivl_const_width(con), + ivl_const_signed(con) != 0); } - } - - assert(false); -} - -vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) -{ - int nptrs = ivl_nexus_ptrs(nexus); - for (int i = 0; i < nptrs; i++) { - ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); - - ivl_signal_t sig; - if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - if (!seen_signal_before(sig)) - continue; - - const char *signame = get_renamed_signal(sig).c_str(); - - vhdl_decl *decl = arch_scope->get_decl(signame); - if (NULL == decl) - continue; // Not in this scope - - vhdl_type *type = new vhdl_type(*(decl->get_type())); - return new vhdl_var_ref(signame, type); + else if ((allowed & NEXUS_TO_OTHER) && + (sw = ivl_nexus_ptr_switch(nexus_ptr))) { + assert(false); } else { // Ignore other types of nexus pointer @@ -127,6 +101,17 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) return NULL; } +/* + * Guarantees the result will never be NULL. + */ +vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) +{ + vhdl_var_ref *ref = dynamic_cast + (nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF)); + assert(ref); + return ref; +} + /* * Convert the inputs of a logic gate to a binary expression. */ @@ -266,7 +251,9 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) // A local signal can have a constant initializer in VHDL // This may be found in the signal's nexus // TODO: Make this work for multiple words - vhdl_expr *init = nexus_to_const(ivl_signal_nex(sig, 0)); + vhdl_expr *init = + nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0), + NEXUS_TO_CONST); if (init != NULL) decl->set_initial(init); @@ -285,7 +272,9 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) // Check for constant values // For outputs these must be continuous assigns of // the constant to the port - vhdl_expr *init = nexus_to_const(ivl_signal_nex(sig, 0)); + vhdl_expr *init = + nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0), + NEXUS_TO_CONST); if (init != NULL) { vhdl_var_ref *ref = new vhdl_var_ref(name.c_str(), NULL); ent->get_arch()->add_stmt(new vhdl_cassign_stmt(ref, init)); @@ -390,7 +379,8 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, // TODO: Work for multiple words ivl_nexus_t nexus = ivl_signal_nex(to, 0); - vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(), nexus, to); + vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(), + nexus, NEXUS_TO_ANY, to); assert(to_e); // The expressions in a VHDL port map must be 'globally static' diff --git a/tgt-vhdl/verilog_support.vhd b/tgt-vhdl/verilog_support.vhd index 34ec5df20..b52cecd89 100644 --- a/tgt-vhdl/verilog_support.vhd +++ b/tgt-vhdl/verilog_support.vhd @@ -15,6 +15,7 @@ package Verilog_Support is -- Routines to implement Verilog reduction operators function Reduce_OR(X : unsigned) return std_logic; + function Reduce_Or(X : std_logic) return std_logic; -- Convert Boolean to std_logic function Active_High(B : Boolean) return std_logic; @@ -40,6 +41,11 @@ package body Verilog_Support is return '0'; end function; + function Reduce_OR(X : std_logic) return std_logic is + begin + return X; + end function; + function Active_High(B : Boolean) return std_logic is begin if B then From e5422dddd2c26fe831fc74ea34c48f5059cd31fc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 15:24:35 +0100 Subject: [PATCH 05/57] Remove useless `ignore' param to nexus_to_expr --- tgt-vhdl/scope.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e73b201f8..3aba665dc 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -42,10 +42,12 @@ enum vhdl_nexus_obj_t { /* * Given a nexus, generate a VHDL expression object to represent it. * The allowed VHDL expression types are given by vhdl_nexus_obj_t. + * + * If a vhdl_var_ref is returned, the reference is guaranteed to be + * to a signal in arch_scope or its parent (the entity's ports). */ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, - int allowed = NEXUS_TO_ANY, - ivl_signal_t ignore = NULL) + int allowed = NEXUS_TO_ANY) { int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { @@ -58,7 +60,9 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_switch_t sw; if ((allowed & NEXUS_TO_VAR_REF) && (sig = ivl_nexus_ptr_sig(nexus_ptr))) { - if (!seen_signal_before(sig) || sig == ignore) + if (!seen_signal_before(sig) || + (find_scope_for_signal(sig) != arch_scope + && find_scope_for_signal(sig) != arch_scope->get_parent())) continue; const char *signame = get_renamed_signal(sig).c_str(); @@ -91,6 +95,7 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, } else if ((allowed & NEXUS_TO_OTHER) && (sw = ivl_nexus_ptr_switch(nexus_ptr))) { + std::cout << "SWITCH type=" << ivl_switch_type(sw) << std::endl; assert(false); } else { @@ -380,7 +385,7 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, ivl_nexus_t nexus = ivl_signal_nex(to, 0); vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(), - nexus, NEXUS_TO_ANY, to); + nexus, NEXUS_TO_ANY); assert(to_e); // The expressions in a VHDL port map must be 'globally static' From 07c4ff7ea75862a834df891b4de50c3e381b7795 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 15:26:03 +0100 Subject: [PATCH 06/57] Add assertion about result of lpm_to_expr --- tgt-vhdl/scope.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 3aba665dc..f1a23536a 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -81,8 +81,8 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, else if ((allowed & NEXUS_TO_OTHER) && (lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { vhdl_expr *e = lpm_to_expr(arch_scope, lpm); - if (e) - return e; + assert(e); + return e; } else if ((allowed & NEXUS_TO_CONST) && (con = ivl_nexus_ptr_con(nexus_ptr))) { From 78ee61558da2ee6baa31e95a4e10b31b5dd1b4ce Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 13 Jul 2008 15:27:07 +0100 Subject: [PATCH 07/57] Remove redundant test Signal is guaranteed to appear in arch_scope or its parent by the surrounding `if' statement. --- tgt-vhdl/scope.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index f1a23536a..481e90bca 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -68,9 +68,6 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, const char *signame = get_renamed_signal(sig).c_str(); vhdl_decl *decl = arch_scope->get_decl(signame); - if (NULL == decl) - continue; // Not in this scope - vhdl_type *type = new vhdl_type(*(decl->get_type())); return new vhdl_var_ref(signame, type); } From e331e4831be71bb7062ce06a8f052221638acb06 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 11:53:38 +0100 Subject: [PATCH 08/57] Fix nexus_to_expr where nexus has IVL_LPM_SELECT_PV --- tgt-vhdl/lpm.cc | 93 ++++++++++++++++++++++++++++++------------ tgt-vhdl/scope.cc | 22 ++++------ tgt-vhdl/vhdl_target.h | 2 + 3 files changed, 78 insertions(+), 39 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index b6e6ae874..d13a651b9 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -23,7 +23,7 @@ #include #include -static vhdl_expr *draw_concat_lpm(vhdl_scope *scope, ivl_lpm_t lpm) +static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_type *result_type = vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); @@ -41,7 +41,7 @@ static vhdl_expr *draw_concat_lpm(vhdl_scope *scope, ivl_lpm_t lpm) return expr; } -static vhdl_expr *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) +static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { vhdl_type *result_type = vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); @@ -88,7 +88,7 @@ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) return off->cast(&integer); } -static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm) +static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) @@ -102,26 +102,40 @@ static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm) return selfrom; } +static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) +{ + vhdl_expr *off = part_select_base(scope, lpm);; + if (NULL == off) + return NULL; + + vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); + if (NULL == out) + return NULL; + + out->set_slice(off, ivl_lpm_width(lpm) - 1); + return out; +} + static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { - vhdl_var_ref *selfrom = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); - if (NULL == selfrom) - return 1; + vhdl_var_ref *out; + vhdl_var_ref *selfrom; + if (NULL == (out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0))) + || NULL == (selfrom = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)))) { + // Not continuous assignment to signal: ignore it + return 0; + } vhdl_expr *off = part_select_base(arch->get_scope(), lpm);; if (NULL == off) return 1; - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (NULL == out) - return 1; - out->set_slice(off, ivl_lpm_width(lpm) - 1); arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); return 0; } -static vhdl_expr *draw_ufunc_lpm(vhdl_scope *scope, ivl_lpm_t lpm) +static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL); @@ -136,7 +150,7 @@ static vhdl_expr *draw_ufunc_lpm(vhdl_scope *scope, ivl_lpm_t lpm) return fcall; } -static vhdl_expr *draw_reduction_lpm(vhdl_scope *scope, ivl_lpm_t lpm, +static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, const char *rfunc, bool invert) { vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic()); @@ -154,7 +168,7 @@ static vhdl_expr *draw_reduction_lpm(vhdl_scope *scope, ivl_lpm_t lpm, return fcall; } -static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm) +static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (ref) @@ -163,35 +177,62 @@ static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm) return NULL; } +static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) +{ + ivl_signal_t array = ivl_lpm_array(lpm); + if (!seen_signal_before(array)) + return NULL; + + const char *renamed = get_renamed_signal(array).c_str(); + + vhdl_decl *adecl = scope->get_decl(renamed); + assert(adecl); + + vhdl_type *atype = new vhdl_type(*adecl->get_type()); + + vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm)); + if (NULL == select) + return NULL; + + vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype); + ref->set_slice(select); + + return ref; +} + vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: - return draw_binop_lpm(scope, lpm, VHDL_BINOP_ADD); + return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD); case IVL_LPM_SUB: - return draw_binop_lpm(scope, lpm, VHDL_BINOP_SUB); + return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: - return draw_binop_lpm(scope, lpm, VHDL_BINOP_MULT); + return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT); case IVL_LPM_CONCAT: - return draw_concat_lpm(scope, lpm); + return concat_lpm_to_expr(scope, lpm); case IVL_LPM_PART_VP: - return draw_part_select_vp_lpm(scope, lpm); + return part_select_vp_lpm_to_expr(scope, lpm); + case IVL_LPM_PART_PV: + return part_select_pv_lpm_to_expr(scope, lpm); case IVL_LPM_UFUNC: - return draw_ufunc_lpm(scope, lpm); + return ufunc_lpm_to_expr(scope, lpm); case IVL_LPM_RE_AND: - return draw_reduction_lpm(scope, lpm, "Reduce_AND", false); + return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false); case IVL_LPM_RE_NAND: - return draw_reduction_lpm(scope, lpm, "Reduce_AND", true); + return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true); case IVL_LPM_RE_NOR: - return draw_reduction_lpm(scope, lpm, "Reduce_OR", true); + return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", true); case IVL_LPM_RE_OR: - return draw_reduction_lpm(scope, lpm, "Reduce_OR", false); + return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", false); case IVL_LPM_RE_XOR: - return draw_reduction_lpm(scope, lpm, "Reduce_XOR", false); + return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false); case IVL_LPM_RE_XNOR: - return draw_reduction_lpm(scope, lpm, "Reduce_XNOR", false); + return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false); case IVL_LPM_SIGN_EXT: - return draw_sign_extend_lpm(scope, lpm); + return sign_extend_lpm_to_expr(scope, lpm); + case IVL_LPM_ARRAY: + return array_lpm_to_expr(scope, lpm); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return NULL; diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 481e90bca..11a7c849c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -48,7 +48,7 @@ enum vhdl_nexus_obj_t { */ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, int allowed = NEXUS_TO_ANY) -{ +{ int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); @@ -59,12 +59,12 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_net_const_t con; ivl_switch_t sw; if ((allowed & NEXUS_TO_VAR_REF) && - (sig = ivl_nexus_ptr_sig(nexus_ptr))) { + (sig = ivl_nexus_ptr_sig(nexus_ptr))) { if (!seen_signal_before(sig) || (find_scope_for_signal(sig) != arch_scope && find_scope_for_signal(sig) != arch_scope->get_parent())) continue; - + const char *signame = get_renamed_signal(sig).c_str(); vhdl_decl *decl = arch_scope->get_decl(signame); @@ -77,9 +77,7 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, } else if ((allowed & NEXUS_TO_OTHER) && (lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - vhdl_expr *e = lpm_to_expr(arch_scope, lpm); - assert(e); - return e; + return lpm_to_expr(arch_scope, lpm); } else if ((allowed & NEXUS_TO_CONST) && (con = ivl_nexus_ptr_con(nexus_ptr))) { @@ -99,7 +97,7 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, // Ignore other types of nexus pointer } } - + return NULL; } @@ -108,10 +106,8 @@ static vhdl_expr *nexus_to_expr(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 *ref = dynamic_cast + return dynamic_cast (nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF)); - assert(ref); - return ref; } /* @@ -241,9 +237,9 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) vhdl_type *sig_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - std::string name = make_safe_name(sig); + string name(make_safe_name(sig)); rename_signal(sig, name); - + ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: @@ -254,7 +250,7 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) // This may be found in the signal's nexus // TODO: Make this work for multiple words vhdl_expr *init = - nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0), + nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0), NEXUS_TO_CONST); if (init != NULL) decl->set_initial(init); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 10438ce19..d59fbb12e 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -9,6 +9,8 @@ #include +using namespace std; + void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); From 6243736481ad6f0ea55ae391104adba7c9dabd0f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 12:04:20 +0100 Subject: [PATCH 09/57] Pull-up/pull-down logic devices --- tgt-vhdl/scope.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 11a7c849c..8a6669c87 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -157,6 +157,10 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) case IVL_LO_BUF: case IVL_LO_BUFZ: return nexus_to_expr(scope, ivl_logic_pin(log, 1)); + case IVL_LO_PULLUP: + return new vhdl_const_bit('1'); + case IVL_LO_PULLDOWN: + return new vhdl_const_bit('0'); default: error("Don't know how to translate logic type = %d", ivl_logic_type(log)); From 65720f49feb77f88c68bf2421650a410df26381a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 19:00:58 +0100 Subject: [PATCH 10/57] Simple bufif cases --- tgt-vhdl/scope.cc | 55 ++++++++++++++++++++++++++++++++--------- tgt-vhdl/vhdl_syntax.cc | 24 ++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 8 ++++++ 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 8a6669c87..3c2e48514 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -143,6 +143,29 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } +static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) +{ + ivl_nexus_t output = ivl_logic_pin(log, 0); + vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); + assert(lhs); + + vhdl_expr *val = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 1)); + assert(val); + + vhdl_expr *sel = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 2)); + assert(val); + + vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1'); + vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL); + + // TODO: This value needs to depend on the net type + vhdl_const_bit *z = new vhdl_const_bit('0'); + vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z); + cass->add_condition(val, cmp); + + arch->add_stmt(cass); +} + static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) { switch (ivl_logic_type(log)) { @@ -162,7 +185,7 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) case IVL_LO_PULLDOWN: return new vhdl_const_bit('0'); default: - error("Don't know how to translate logic type = %d", + error("Don't know how to translate logic type = %d to expression", ivl_logic_type(log)); return NULL; } @@ -178,16 +201,26 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) for (int i = 0; i < nlogs; i++) { ivl_net_logic_t log = ivl_scope_log(scope, i); - // The output is always pin zero - ivl_nexus_t output = ivl_logic_pin(log, 0); - vhdl_var_ref *lhs = - dynamic_cast(nexus_to_expr(arch->get_scope(), output)); - if (NULL == lhs) - continue; // Not suitable for continuous assignment - - vhdl_expr *rhs = translate_logic(arch->get_scope(), log); - - arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); + switch (ivl_logic_type(log)) { + case IVL_LO_BUFIF0: + bufif_logic(arch, log, true); + break; + case IVL_LO_BUFIF1: + bufif_logic(arch, log, false); + break; + default: + { + // The output is always pin zero + ivl_nexus_t output = ivl_logic_pin(log, 0); + vhdl_var_ref *lhs = + dynamic_cast(nexus_to_expr(arch->get_scope(), output)); + if (NULL == lhs) + continue; // Not suitable for continuous assignment + + vhdl_expr *rhs = translate_logic(arch->get_scope(), log); + arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); + } + } } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index fdae262b9..37550909c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -649,12 +649,36 @@ vhdl_cassign_stmt::~vhdl_cassign_stmt() { delete lhs_; delete rhs_; + + for (std::list::const_iterator it = whens_.begin(); + it != whens_.end(); + ++it) { + delete (*it).value; + delete (*it).cond; + } +} + +void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) +{ + when_part_t when = { value, cond }; + whens_.push_back(when); } void vhdl_cassign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " <= "; + if (!whens_.empty()) { + for (std::list::const_iterator it = whens_.begin(); + it != whens_.end(); + ++it) { + (*it).value->emit(of, level); + of << " when "; + (*it).cond->emit(of, level); + of << " "; + } + of << "else "; + } rhs_->emit(of, level); of << ";"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c866ee370..d8430063d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -216,6 +216,8 @@ typedef std::list conc_stmt_list_t; /* * A concurrent signal assignment (i.e. not part of a process). + * Can have any number of `when' clauses, in which case the original + * rhs becomes the `else' part. */ class vhdl_cassign_stmt : public vhdl_conc_stmt { public: @@ -224,9 +226,15 @@ public: ~vhdl_cassign_stmt(); void emit(std::ostream &of, int level) const; + void add_condition(vhdl_expr *value, vhdl_expr *cond); private: vhdl_var_ref *lhs_; vhdl_expr *rhs_; + + struct when_part_t { + vhdl_expr *value, *cond; + }; + std::list whens_; }; /* From f84f50842c00677228caa20b98eb2f7e1705073e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 19:13:11 +0100 Subject: [PATCH 11/57] Support bufif for tri1 nets --- tgt-vhdl/scope.cc | 17 +++++++++++++++-- tgt-vhdl/vhdl.cc | 4 +++- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 3c2e48514..33af741a8 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -158,8 +158,21 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1'); vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL); - // TODO: This value needs to depend on the net type - vhdl_const_bit *z = new vhdl_const_bit('0'); + ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope()); + char zbit; + switch (ivl_signal_type(sig)) { + case IVL_SIT_TRI0: + zbit = '0'; + break; + case IVL_SIT_TRI1: + zbit = '1'; + break; + case IVL_SIT_TRI: + default: + zbit = 'Z'; + } + + vhdl_const_bit *z = new vhdl_const_bit(zbit); vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z); cass->add_condition(val, cmp); diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 382f51b49..e04d7d7a0 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -134,7 +134,9 @@ ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) { signal_defn_map_t::const_iterator it; for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) { - if ((*it).second.scope == scope && (*it).second.renamed == name) + if (((*it).second.scope == scope + || (*it).second.scope == scope->get_parent()) + && (*it).second.renamed == name) return (*it).first; } assert(false); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 37550909c..1e77b22d2 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -57,7 +57,7 @@ bool vhdl_scope::have_declared(const std::string &name) const return get_decl(name) != NULL; } -vhdl_scope *vhdl_scope::get_parent() +vhdl_scope *vhdl_scope::get_parent() const { assert(parent_); return parent_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index d8430063d..8d8527346 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -557,7 +557,7 @@ public: void add_decl(vhdl_decl *decl); vhdl_decl *get_decl(const std::string &name) const; bool have_declared(const std::string &name) const; - vhdl_scope *get_parent(); + vhdl_scope *get_parent() const; bool empty() const { return decls_.empty(); } const decl_list_t &get_decls() const { return decls_; } From d22c9a8b05fb8b1a170e3d2ceb1eaca2fa05c602 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 19:54:45 +0100 Subject: [PATCH 12/57] Simplify blocking assignment Now generates 'wait for 0 ns' after non-blocking assignment --- tgt-vhdl/stmt.cc | 27 ++++++++++++++++++++++----- tgt-vhdl/vhdl_syntax.hh | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 302833b75..1f0240a05 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -163,7 +163,7 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, decl->set_initial(rhs); - if (blocking && proc->get_scope()->allow_signal_assignment()) { + /*if (blocking && proc->get_scope()->allow_signal_assignment()) { // This signal may be used e.g. in a loop test so we need // to make a variable as well blocking_assign_to(proc, sig); @@ -182,18 +182,18 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, return a; } - else + else*/ return NULL; // No statement need be emitted } else { - if (blocking && proc->get_scope()->allow_signal_assignment()) { + /*if (blocking && proc->get_scope()->allow_signal_assignment()) { // Remember we need to write the variable back to the // original signal blocking_assign_to(proc, sig); // The signal may have been renamed by the above call signame = get_renamed_signal(sig); - } + }*/ vhdl_type *ltype = new vhdl_type(*proc->get_scope()->get_decl(signame)->get_type()); @@ -292,7 +292,24 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { - make_assignment(proc, container, stmt, true); + if (proc->get_scope()->allow_signal_assignment()) { + // TODO: Explain blocking assignment here + + vhdl_nbassign_stmt *a = + make_assignment(proc, container, stmt, false); + + if (a != NULL) { + // Assignment is a statement and not moved into the initialisation + //if (after != NULL) + // a->set_after(after); + + container->add_stmt + (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); + } + } + else + make_assignment(proc, container, stmt, true); + return 0; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 8d8527346..29e72266c 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -158,7 +158,7 @@ enum time_unit_t { class vhdl_const_time : public vhdl_expr { public: - vhdl_const_time(int64_t value, time_unit_t units) + vhdl_const_time(int64_t value, time_unit_t units = TIME_UNIT_NS) : vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {} void emit(std::ostream &of, int level) const; private: From 99ef8ec4f17d79c34790d1d02c1d11aaa9b7595c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 20:29:49 +0100 Subject: [PATCH 13/57] Simplify edge detector code Now generates a `wait until' statement rather than a sensitivity list. --- tgt-vhdl/stmt.cc | 116 +++++++++++++--------------------------- tgt-vhdl/vhdl_syntax.cc | 5 ++ tgt-vhdl/vhdl_syntax.hh | 2 + 3 files changed, 44 insertions(+), 79 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1f0240a05..8fce8c02c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -161,7 +161,7 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, && container == proc->get_container() // Top-level container && !isvar) { - decl->set_initial(rhs); + // decl->set_initial(new vhdl_expr(*rhs)); /*if (blocking && proc->get_scope()->allow_signal_assignment()) { // This signal may be used e.g. in a loop test so we need @@ -183,9 +183,8 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, return a; } else*/ - return NULL; // No statement need be emitted } - else { + /*if (blocking && proc->get_scope()->allow_signal_assignment()) { // Remember we need to write the variable back to the // original signal @@ -205,7 +204,6 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, container->add_stmt(a); return a; - } } /* @@ -279,12 +277,9 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, vhdl_nbassign_stmt *a = make_assignment(proc, container, stmt, false); - - if (a != NULL) { - // Assignment is a statement and not moved into the initialisation - if (after != NULL) - a->set_after(after); - } + + if (after != NULL) + a->set_after(after); return 0; } @@ -298,14 +293,12 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, vhdl_nbassign_stmt *a = make_assignment(proc, container, stmt, false); - if (a != NULL) { - // Assignment is a statement and not moved into the initialisation - //if (after != NULL) - // a->set_after(after); - - container->add_stmt - (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); - } + // Assignment is a statement and not moved into the initialisation + //if (after != NULL) + // a->set_after(after); + + container->add_stmt + (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); } else make_assignment(proc, container, stmt, true); @@ -403,83 +396,48 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, // Wait statements only occur in processes vhdl_process *proc = dynamic_cast(_proc); assert(proc); // Catch not process - - ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - - // TODO: This should really be merged with the - // nexus_to_XXX code + vhdl_binop_expr *test = + new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); + int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); - // A list of the non-edge triggered signals to they can - // be added to the edge-detecting `if' statement later - string_list_t non_edges; - int nany = ivl_event_nany(event); for (int i = 0; i < nany; i++) { ivl_nexus_t nexus = ivl_event_any(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); - int nptrs = ivl_nexus_ptrs(nexus); - for (int j = 0; j < nptrs; j++) { - ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, j); - - ivl_signal_t sig; - if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - if (!seen_signal_before(sig)) - continue; - - std::string signame(get_renamed_signal(sig)); - - // Only add this signal to the sensitivity if it's part - // of the containing architecture (i.e. it has already - // been declared) - if (proc->get_scope()->get_parent()->have_declared(signame)) { - proc->add_sensitivity(signame.c_str()); - non_edges.push_back(signame); - break; - } - } - else { - // Ignore all other types of nexus pointer - } - } + ref->set_name(ref->get_name() + "'Event"); + test->add_expr(ref); } int nneg = ivl_event_nneg(event); - int npos = ivl_event_npos(event); - if (nneg + npos > 0) { - vhdl_binop_expr *test = - new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); - - // Generate falling_edge(..) calls for each negedge event - for (int i = 0; i < nneg; i++) - edge_detector(ivl_event_neg(event, i), proc, test, "falling_edge"); - - // Generate rising_edge(..) calls for each posedge event - for (int i = 0; i < npos; i++) - edge_detector(ivl_event_pos(event, i), proc, test, "rising_edge"); - - // Add Name'Event terms for each non-edge-triggered signal - string_list_t::iterator it; - for (it = non_edges.begin(); it != non_edges.end(); ++it) { - test->add_expr - (new vhdl_var_ref((*it + "'Event").c_str(), - vhdl_type::boolean())); - } - - vhdl_if_stmt *edge_det = new vhdl_if_stmt(test); - container->add_stmt(edge_det); + for (int i = 0; i < nneg; i++) { + ivl_nexus_t nexus = ivl_event_neg(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + vhdl_fcall *detect = + new vhdl_fcall("falling_edge", vhdl_type::boolean()); + detect->add_expr(ref); - draw_stmt(proc, edge_det->get_then_container(), sub_stmt); + test->add_expr(detect); } - else { - // Don't bother generating an edge detector if there - // are no edge-triggered events - draw_stmt(proc, container, sub_stmt); + + int npos = ivl_event_npos(event); + for (int i = 0; i < npos; i++) { + ivl_nexus_t nexus = ivl_event_pos(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + vhdl_fcall *detect = + new vhdl_fcall("rising_edge", vhdl_type::boolean()); + detect->add_expr(ref); + + test->add_expr(detect); } } + + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 1e77b22d2..525241901 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -293,6 +293,11 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const of << " for "; expr_->emit(of, level); break; + case VHDL_WAIT_UNTIL: + assert(expr_); + of << " until "; + expr_->emit(of, level); + break; } of << ";"; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 29e72266c..d76370b37 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -56,6 +56,7 @@ public: void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } + void set_name(const std::string &name) { name_ = name; } void set_slice(vhdl_expr *s, int w=0); private: std::string name_; @@ -303,6 +304,7 @@ public: enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR, // Wait for a constant amount of time + VHDL_WAIT_UNTIL, // Wait on a sensitivity list }; /* From 8589c0691b01d2d9f8a589c50927abfbad6e16e9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 21:04:09 +0100 Subject: [PATCH 14/57] Refactor assignment code --- tgt-vhdl/stmt.cc | 122 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 37 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 8fce8c02c..762bb9550 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -102,24 +102,21 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } -/* - * Generate an assignment of VHDL expr rhs to signal sig. This, unlike - * the procedure below, is a generic routine used for more than just - * Verilog signal assignment (e.g. it is used to expand ternary - * expressions). - */ -template -static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_signal_t sig, vhdl_expr *rhs, bool blocking, - vhdl_expr *base = NULL, unsigned lval_width = 0) +static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, + ivl_expr_t e, vhdl_expr *base, + int lval_width) { std::string signame(get_renamed_signal(sig)); - vhdl_decl *decl = proc->get_scope()->get_decl(signame); + vhdl_decl *decl = scope->get_decl(signame); assert(decl); + vhdl_expr *rhs = translate_expr(e); + if (rhs == NULL) + return rhs; + if (base == NULL) - rhs = rhs->cast(decl->get_type()); + return rhs->cast(decl->get_type()); else { vhdl_type integer(VHDL_TYPE_INTEGER); base = base->cast(&integer); @@ -131,15 +128,29 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, if (lval_width == 1) { vhdl_type t(VHDL_TYPE_STD_LOGIC); - rhs = rhs->cast(&t); + return rhs->cast(&t); } else { vhdl_type t(tname, lval_width); - rhs = rhs->cast(&t); + return rhs->cast(&t); } } +} + +/* + * Generate an assignment of VHDL expr rhs to signal sig. This, unlike + * the procedure below, is a generic routine used for more than just + * Verilog signal assignment (e.g. it is used to expand ternary + * expressions). + */ +template +static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, + ivl_signal_t sig, vhdl_expr *rhs, bool blocking, + vhdl_expr *base = NULL, unsigned lval_width = 0) +{ + - bool isvar = strip_var(signame) != signame; + // bool isvar = strip_var(signame) != signame; // Where possible, move constant assignments into the // declaration as initializers. This optimisation is only @@ -155,11 +166,11 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, // `always' process may then use the uninitialized signal value. // The second test ensures that we only try to initialise // internal signals not ports - if (proc->get_scope()->initializing() + /*if (proc->get_scope()->initializing() && ivl_signal_port(sig) == IVL_SIP_NONE && !decl->has_initial() && rhs->constant() && container == proc->get_container() // Top-level container - && !isvar) { + && !isvar) {*/ // decl->set_initial(new vhdl_expr(*rhs)); @@ -183,7 +194,7 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, return a; } else*/ - } + // } /*if (blocking && proc->get_scope()->allow_signal_assignment()) { // Remember we need to write the variable back to the @@ -194,16 +205,8 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, signame = get_renamed_signal(sig); }*/ - vhdl_type *ltype = - new vhdl_type(*proc->get_scope()->get_decl(signame)->get_type()); - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); - if (base) - lval_ref->set_slice(base, lval_width-1); - - T *a = new T(lval_ref, rhs); - container->add_stmt(a); - - return a; + + // return a; } /* @@ -243,20 +246,60 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, return NULL; vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); - make_vhdl_assignment(proc, vhdif->get_then_container(), sig, + /*make_vhdl_assignment(proc, vhdif->get_then_container(), sig, true_part, blocking, base, lval_width); make_vhdl_assignment(proc, vhdif->get_else_container(), sig, false_part, blocking, base, lval_width); - + */ container->add_stmt(vhdif); return NULL; } else { - vhdl_expr *rhs = translate_expr(rval); + vhdl_expr *rhs = + translate_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); if (NULL == rhs) return NULL; + + std::string signame(get_renamed_signal(sig)); + vhdl_decl *decl = proc->get_scope()->get_decl(signame); + + // Where possible, move constant assignments into the + // declaration as initializers. This optimisation is only + // performed on assignments of constant values to prevent + // ordering problems. - return make_vhdl_assignment(proc, container, sig, rhs, blocking, base, lval_width); + // This also has another application: If this is an `inital' + // process and we haven't yet generated a `wait' statement then + // moving the assignment to the initialization preserves the + // expected Verilog behaviour: VHDL does not distinguish + // `initial' and `always' processes so an `always' process might + // be activatated before an `initial' process at time 0. The + // `always' process may then use the uninitialized signal value. + // The second test ensures that we only try to initialise + // internal signals not ports + if (proc->get_scope()->initializing() + && ivl_signal_port(sig) == IVL_SIP_NONE + && !decl->has_initial() && rhs->constant() + && container == proc->get_container()) { // Top-level container + + vhdl_expr *rhs_copy = + translate_assign_rhs(sig, proc->get_scope(), rval, + base, lval_width); + decl->set_initial(rhs_copy); + + return NULL; + } + else { + vhdl_type *ltype = new vhdl_type(*decl->get_type()); + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); + if (base) + lval_ref->set_slice(base, lval_width-1); + + T *a = new T(lval_ref, rhs); + container->add_stmt(a); + + return a; + } } } else { @@ -278,8 +321,11 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, vhdl_nbassign_stmt *a = make_assignment(proc, container, stmt, false); - if (after != NULL) - a->set_after(after); + if (a != NULL) { + // Assignment wasn't moved to initialisation + if (after != NULL) + a->set_after(after); + } return 0; } @@ -293,9 +339,11 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, vhdl_nbassign_stmt *a = make_assignment(proc, container, stmt, false); - // Assignment is a statement and not moved into the initialisation - //if (after != NULL) - // a->set_after(after); + if (a != NULL) { + // Assignment is a statement and not moved into the initialisation + //if (after != NULL) + // a->set_after(after); + } container->add_stmt (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); From 6e965523a10206bd279f74aa54feac13647302af Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 21:09:19 +0100 Subject: [PATCH 15/57] Fix PV assignment (was broken in last commit) --- tgt-vhdl/stmt.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 762bb9550..e60ce5e75 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -118,9 +118,6 @@ static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, if (base == NULL) return rhs->cast(decl->get_type()); else { - vhdl_type integer(VHDL_TYPE_INTEGER); - base = base->cast(&integer); - // Doesn't make sense to part select on something that's // not a vector vhdl_type_name_t tname = decl->get_type()->get_name(); @@ -231,6 +228,9 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, if (e_off) { if ((base = translate_expr(e_off)) == NULL) return NULL; + + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); } unsigned lval_width = ivl_lval_width(lval); From 75b1db0adda0f47789190d8114bb4f297a0b1e73 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 21:27:21 +0100 Subject: [PATCH 16/57] Fix assignment with ternary RHS This was also broken in the last commit --- tgt-vhdl/stmt.cc | 123 +++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 84 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e60ce5e75..c0d1cf631 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -106,7 +106,7 @@ static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, ivl_expr_t e, vhdl_expr *base, int lval_width) { - std::string signame(get_renamed_signal(sig)); + string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); assert(decl); @@ -134,76 +134,18 @@ static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, } } -/* - * Generate an assignment of VHDL expr rhs to signal sig. This, unlike - * the procedure below, is a generic routine used for more than just - * Verilog signal assignment (e.g. it is used to expand ternary - * expressions). - */ -template -static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_signal_t sig, vhdl_expr *rhs, bool blocking, - vhdl_expr *base = NULL, unsigned lval_width = 0) +static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, + vhdl_expr *base, int lval_width) { + std::string signame(get_renamed_signal(sig)); + vhdl_decl *decl = scope->get_decl(signame); - - // bool isvar = strip_var(signame) != signame; + vhdl_type *ltype = new vhdl_type(*decl->get_type()); + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); + if (base) + lval_ref->set_slice(base, lval_width-1); - // Where possible, move constant assignments into the - // declaration as initializers. This optimisation is only - // performed on assignments of constant values to prevent - // ordering problems. - - // This also has another application: If this is an `inital' - // process and we haven't yet generated a `wait' statement then - // moving the assignment to the initialization preserves the - // expected Verilog behaviour: VHDL does not distinguish - // `initial' and `always' processes so an `always' process might - // be activatated before an `initial' process at time 0. The - // `always' process may then use the uninitialized signal value. - // The second test ensures that we only try to initialise - // internal signals not ports - /*if (proc->get_scope()->initializing() - && ivl_signal_port(sig) == IVL_SIP_NONE - && !decl->has_initial() && rhs->constant() - && container == proc->get_container() // Top-level container - && !isvar) {*/ - - // decl->set_initial(new vhdl_expr(*rhs)); - - /*if (blocking && proc->get_scope()->allow_signal_assignment()) { - // This signal may be used e.g. in a loop test so we need - // to make a variable as well - blocking_assign_to(proc, sig); - - // The signal may have been renamed by the above call - const std::string &renamed = get_renamed_signal(sig); - - vhdl_var_ref *lval_ref = new vhdl_var_ref(renamed.c_str(), NULL); - vhdl_var_ref *sig_ref = new vhdl_var_ref(signame.c_str(), NULL); - - if (base) - lval_ref->set_slice(base, lval_width-1); - - T *a = new T(lval_ref, sig_ref); - container->add_stmt(a); - - return a; - } - else*/ - // } - - /*if (blocking && proc->get_scope()->allow_signal_assignment()) { - // Remember we need to write the variable back to the - // original signal - blocking_assign_to(proc, sig); - - // The signal may have been renamed by the above call - signame = get_renamed_signal(sig); - }*/ - - - // return a; + return lval_ref; } /* @@ -239,18 +181,36 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, if (ivl_expr_type(rval) == IVL_EX_TERNARY) { // Expand ternary expressions into an if statement vhdl_expr *test = translate_expr(ivl_expr_oper1(rval)); - vhdl_expr *true_part = translate_expr(ivl_expr_oper2(rval)); - vhdl_expr *false_part = translate_expr(ivl_expr_oper3(rval)); + vhdl_expr *true_part = + translate_assign_rhs(sig, proc->get_scope(), + ivl_expr_oper2(rval), base, lval_width); + vhdl_expr *false_part = + translate_assign_rhs(sig, proc->get_scope(), + ivl_expr_oper3(rval), base, lval_width); if (!test || !true_part || !false_part) return NULL; vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); - /*make_vhdl_assignment(proc, vhdif->get_then_container(), sig, - true_part, blocking, base, lval_width); - make_vhdl_assignment(proc, vhdif->get_else_container(), sig, - false_part, blocking, base, lval_width); - */ + + // True part + { + vhdl_var_ref *lval_ref = + make_assign_lhs(sig, proc->get_scope(), base, lval_width); + + T *a = new T(lval_ref, true_part); + vhdif->get_then_container()->add_stmt(a); + } + + // False part + { + vhdl_var_ref *lval_ref = + make_assign_lhs(sig, proc->get_scope(), base, lval_width); + + T *a = new T(lval_ref, false_part); + vhdif->get_else_container()->add_stmt(a); + } + container->add_stmt(vhdif); return NULL; } @@ -262,7 +222,7 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); - + // Where possible, move constant assignments into the // declaration as initializers. This optimisation is only // performed on assignments of constant values to prevent @@ -282,18 +242,13 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, && !decl->has_initial() && rhs->constant() && container == proc->get_container()) { // Top-level container - vhdl_expr *rhs_copy = - translate_assign_rhs(sig, proc->get_scope(), rval, - base, lval_width); - decl->set_initial(rhs_copy); + decl->set_initial(rhs); return NULL; } else { - vhdl_type *ltype = new vhdl_type(*decl->get_type()); - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); - if (base) - lval_ref->set_slice(base, lval_width-1); + vhdl_var_ref *lval_ref = + make_assign_lhs(sig, proc->get_scope(), base, lval_width); T *a = new T(lval_ref, rhs); container->add_stmt(a); From d1e7e325b794123bd666ffd0e6d646dbc7ce676a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 14 Jul 2008 21:34:48 +0100 Subject: [PATCH 17/57] Remove redundant edge_detector function --- tgt-vhdl/stmt.cc | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c0d1cf631..6025d60f8 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -137,7 +137,7 @@ static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, vhdl_expr *base, int lval_width) { - std::string signame(get_renamed_signal(sig)); + string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); vhdl_type *ltype = new vhdl_type(*decl->get_type()); @@ -373,22 +373,6 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, return 0; } -/* - * Make edge detectors from the signals in `nexus' and add them - * to the expression `test'. Also adds the signals to the process - * sensitivity list. Type should be one of `rising_edge' or - * `falling_edge'. - */ -static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc, - vhdl_binop_expr *test, const char *type) -{ - vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope()->get_parent(), nexus); - vhdl_fcall *detect = new vhdl_fcall(type, vhdl_type::boolean()); - detect->add_expr(ref); - test->add_expr(detect); - proc->add_sensitivity(ref->get_name().c_str()); -} - /* * A wait statement waits for a level change on a @(..) list of * signals. From 0b48f69b4ef4ea89e64235b15fb9316f145fe917 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 10:44:48 +0100 Subject: [PATCH 18/57] Tidy up blocking assignment code --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/process.cc | 118 ----------------------------------------- tgt-vhdl/stmt.cc | 24 ++++----- tgt-vhdl/vhdl_target.h | 14 ++--- 4 files changed, 16 insertions(+), 142 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 28c8c7921..dc69cd687 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -58,7 +58,7 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) const char *renamed = get_renamed_signal(sig).c_str(); - const vhdl_decl *decl = scope->get_decl(strip_var(renamed)); + const vhdl_decl *decl = scope->get_decl(renamed); assert(decl); vhdl_type *type = new vhdl_type(*decl->get_type()); diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 73cc51e92..57326a11e 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -24,120 +24,6 @@ #include #include #include -#include - -/* - * Implementing blocking assignment is a little tricky since - * the semantics are a little different to VHDL: - * - * In Verilog a blocking assignment (=) can be used anywhere - * non-blocking assignment (<=) can be. In VHDL blocking - * assignment (:=) can only be used with variables, and - * non-blocking assignment (<=) can only be used with signals. - * All Verilog variables are translated into signals in the - * VHDL architecture. This means we cannot use the VHDL := - * operator directly. Furthermore, VHDL variables can only - * be declared within processes, so it wouldn't help to - * make all Verilog variables VHDL variables. - * - * The solution is to generate a VHDL variable in a process - * whenever a blocking assignment is made to a signal. The - * assignment is made to this variable instead, and - * g_assign_vars below remembers the temporary variables - * that have been generated. Any subsequent blocking assignments - * are made to the same variable. At either the end of the - * process or a `wait' statement, the temporaries are assigned - * back to the signals, and the temporaries are forgotten. - * - * For example: - * - * initial begin - * a = 5; - * b = a + 3; - * end - * - * Is translated to: - * - * process is - * variable a_Var : Some_Type; - * variable b_Var : Some_Type; - * begin - * a_Var := 5; - * b_Var := a_Var + 3; - * a <= a_Var; - * b <= b_Var; - * end process; - */ -typedef std::map var_temp_set_t; -static var_temp_set_t g_assign_vars; - -/* - * Called whenever a blocking assignment is made to sig. - */ -void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig) -{ - std::string var(get_renamed_signal(sig)); - std::string tmpname(var + "_Var"); - - if (g_assign_vars.find(var) == g_assign_vars.end()) { - // This is the first time a non-blocking assignment - // has been made to this signal: create a variable - // to shadow it. - if (!proc->get_scope()->have_declared(tmpname)) { - vhdl_decl *decl = proc->get_scope()->get_decl(var); - assert(decl); - vhdl_type *type = new vhdl_type(*decl->get_type()); - - proc->get_scope()->add_decl(new vhdl_var_decl(tmpname.c_str(), type)); - } - - rename_signal(sig, tmpname); - g_assign_vars[tmpname] = sig; - } -} - -/* - * Assign all _Var variables to the corresponding signals. This makes - * the new values visible outside the current process. This should be - * called before any `wait' statement or the end of the process. - */ -void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container) -{ - var_temp_set_t::const_iterator it; - for (it = g_assign_vars.begin(); it != g_assign_vars.end(); ++it) { - std::string stripped(strip_var((*it).first)); - - vhdl_decl *decl = proc->get_scope()->get_decl(stripped); - assert(decl); - vhdl_type *type = new vhdl_type(*decl->get_type()); - - vhdl_var_ref *lhs = new vhdl_var_ref(stripped.c_str(), NULL); - vhdl_expr *rhs = new vhdl_var_ref((*it).first.c_str(), type); - - container->add_stmt(new vhdl_nbassign_stmt(lhs, rhs)); - - // Undo the renaming (since the temporary is no longer needed) - rename_signal((*it).second, stripped); - } - - // If this this wait is within e.g. an `if' statement then - // we cannot correctly clear the variables list here (since - // they might not be assigned on another path) - if (container == proc->get_container()) - g_assign_vars.clear(); -} - -/* - * Remove _Var from the end of a string, if it is present. - */ -std::string strip_var(const std::string &str) -{ - std::string result(str); - size_t pos = result.find("_Var"); - if (pos != std::string::npos) - result.erase(pos, 4); - return result; -} /* * Convert a Verilog process to VHDL and add it to the architecture @@ -162,10 +48,6 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) if (rc != 0) return rc; - // Output any remaning blocking assignments - draw_blocking_assigns(vhdl_proc, vhdl_proc->get_container()); - g_assign_vars.clear(); - // Initial processes are translated to VHDL processes with // no sensitivity list and and indefinite wait statement at // the end diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 6025d60f8..a7ef4150a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -102,9 +102,9 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } -static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, - ivl_expr_t e, vhdl_expr *base, - int lval_width) +static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, + ivl_expr_t e, vhdl_expr *base, + int lval_width) { string signame(get_renamed_signal(sig)); @@ -182,11 +182,11 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, // Expand ternary expressions into an if statement vhdl_expr *test = translate_expr(ivl_expr_oper1(rval)); vhdl_expr *true_part = - translate_assign_rhs(sig, proc->get_scope(), - ivl_expr_oper2(rval), base, lval_width); + make_assign_rhs(sig, proc->get_scope(), + ivl_expr_oper2(rval), base, lval_width); vhdl_expr *false_part = - translate_assign_rhs(sig, proc->get_scope(), - ivl_expr_oper3(rval), base, lval_width); + make_assign_rhs(sig, proc->get_scope(), + ivl_expr_oper3(rval), base, lval_width); if (!test || !true_part || !false_part) return NULL; @@ -216,11 +216,11 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, } else { vhdl_expr *rhs = - translate_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); + make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); if (NULL == rhs) return NULL; - std::string signame(get_renamed_signal(sig)); + string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); // Where possible, move constant assignments into the @@ -349,11 +349,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, if (type == IVL_ST_ASSIGN_NB) { draw_nbassign(proc, container, sub_stmt, time); } - else { - // All blocking assignments need to be made visible - // at this point - draw_blocking_assigns(proc, container); - + else { vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR, time); container->add_stmt(wait); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index d59fbb12e..4d7f808e2 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -23,23 +23,19 @@ vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm); vhdl_expr *translate_expr(ivl_expr_t e); void remember_entity(vhdl_entity *ent); -vhdl_entity *find_entity(const std::string &tname); +vhdl_entity *find_entity(const string &tname); ivl_design_t get_vhdl_design(); -vhdl_entity *get_active_entity(); +//vhdl_entity *get_active_entity(); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); bool seen_signal_before(ivl_signal_t sig); void remember_signal(ivl_signal_t sig, const vhdl_scope *scope); -void rename_signal(ivl_signal_t sig, const std::string &renamed); +void rename_signal(ivl_signal_t sig, const string &renamed); const vhdl_scope *find_scope_for_signal(ivl_signal_t sig); -const std::string &get_renamed_signal(ivl_signal_t sig); -ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope); - -void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig); -std::string strip_var(const std::string &str); -void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container); +const string &get_renamed_signal(ivl_signal_t sig); +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); From b8e758edf01f2b57a9be2e112baeaa534b712c5a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 14:09:24 +0100 Subject: [PATCH 19/57] Refactor LPM code --- tgt-vhdl/lpm.cc | 116 ++++++++++++++++++++--------------------- tgt-vhdl/scope.cc | 21 ++++++-- tgt-vhdl/stmt.cc | 4 +- tgt-vhdl/vhdl_target.h | 2 +- 4 files changed, 77 insertions(+), 66 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index d13a651b9..a1f3ed846 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -23,6 +23,53 @@ #include #include +/* + * Return the base of a part select. + */ +static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) +{ + vhdl_expr *off; + ivl_nexus_t base = ivl_lpm_data(lpm, 1); + if (base != NULL) + off = nexus_to_var_ref(scope, base); + else + off = new vhdl_const_int(ivl_lpm_base(lpm)); + + // Array indexes must be integers + vhdl_type integer(VHDL_TYPE_INTEGER); + return off->cast(&integer); +} + +vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm) +{ + vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); + if (NULL == out) { + vhdl_type *type = + vhdl_type::type_for(ivl_lpm_width(lpm), + ivl_lpm_signed(lpm) != 0); + string name("LPM"); + name += ivl_lpm_basename(lpm); + name += "_Out"; + + if (!scope->have_declared(name)) { + scope->add_decl + (new vhdl_signal_decl(name.c_str(), new vhdl_type(*type))); + } + + out = new vhdl_var_ref(name.c_str(), type); + } + + if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) { + vhdl_expr *off = part_select_base(scope, lpm); + assert(off); + + out->set_slice(off, ivl_lpm_width(lpm) - 1); + } + + return out; +} + + static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_type *result_type = @@ -71,23 +118,6 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop return expr; } -/* - * Return the base of a part select. - */ -static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) -{ - vhdl_expr *off; - ivl_nexus_t base = ivl_lpm_data(lpm, 1); - if (base != NULL) - off = nexus_to_var_ref(scope, base); - else - off = new vhdl_const_int(ivl_lpm_base(lpm)); - - // Array indexes must be integers - vhdl_type integer(VHDL_TYPE_INTEGER); - return off->cast(&integer); -} - static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); @@ -102,37 +132,10 @@ static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return selfrom; } + static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { - vhdl_expr *off = part_select_base(scope, lpm);; - if (NULL == off) - return NULL; - - vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); - if (NULL == out) - return NULL; - - out->set_slice(off, ivl_lpm_width(lpm) - 1); - return out; -} - -static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) -{ - vhdl_var_ref *out; - vhdl_var_ref *selfrom; - if (NULL == (out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0))) - || NULL == (selfrom = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)))) { - // Not continuous assignment to signal: ignore it - return 0; - } - - vhdl_expr *off = part_select_base(arch->get_scope(), lpm);; - if (NULL == off) - return 1; - - out->set_slice(off, ivl_lpm_width(lpm) - 1); - arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); - return 0; + return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); } static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) @@ -200,7 +203,7 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return ref; } -vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) +static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: @@ -241,18 +244,13 @@ vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { - if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) - return draw_part_select_pv_lpm(arch, lpm); - else { - vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm); - if (NULL == f) - return 1; - - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (out) - arch->add_stmt(new vhdl_cassign_stmt(out, f)); - + vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm); + if (NULL == f) return 0; - } + + vhdl_var_ref *out = lpm_output(arch->get_scope(), lpm); + arch->add_stmt(new vhdl_cassign_stmt(out, f)); + + return 0; } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 33af741a8..76b959a5d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -77,7 +77,7 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, } else if ((allowed & NEXUS_TO_OTHER) && (lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - return lpm_to_expr(arch_scope, lpm); + return lpm_output(arch_scope, lpm); } else if ((allowed & NEXUS_TO_CONST) && (con = ivl_nexus_ptr_con(nexus_ptr))) { @@ -370,8 +370,9 @@ static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope) { int nlpms = ivl_scope_lpms(scope); for (int i = 0; i < nlpms; i++) { - if (draw_lpm(arch, ivl_scope_lpm(scope, i)) != 0) - error("Failed to translate LPM"); + ivl_lpm_t lpm = ivl_scope_lpm(scope, i); + if (draw_lpm(arch, lpm) != 0) + error("Failed to translate LPM %s", ivl_lpm_name(lpm)); } } @@ -423,7 +424,7 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) */ static void map_signal(ivl_signal_t to, vhdl_entity *parent, vhdl_comp_inst *inst) -{ +{ // TODO: Work for multiple words ivl_nexus_t nexus = ivl_signal_nex(to, 0); @@ -564,11 +565,21 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) } // And an instantiation statement - std::string inst_name(ivl_scope_basename(scope)); + string inst_name(ivl_scope_basename(scope)); if (inst_name == ent->get_name()) { // Cannot have instance name the same as type in VHDL inst_name += "_Inst"; } + + // Need to replace any [ and ] characters that result + // from generate statements + string::size_type loc = inst_name.find('[', 0); + if (loc != string::npos) + inst_name.erase(loc, 1); + + loc = inst_name.find(']', 0); + if (loc != string::npos) + inst_name.erase(loc, 1); vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a7ef4150a..106d1a24d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -289,7 +289,9 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { if (proc->get_scope()->allow_signal_assignment()) { - // TODO: Explain blocking assignment here + // Blocking assignment is implemented as non-blocking assignment + // followed by a zero-time wait + // This follows the Verilog semantics fairly closely. vhdl_nbassign_stmt *a = make_assignment(proc, container, stmt, false); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 4d7f808e2..9dc559c96 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -19,8 +19,8 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt); int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); -vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm); vhdl_expr *translate_expr(ivl_expr_t e); +vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const string &tname); From a9c98ad5f264b8ce1803584d2c7c5a8531d18bcd Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 14:26:19 +0100 Subject: [PATCH 20/57] Handle `if' with empty cond_true part Fixes assertion failure with following statement: if (foo) begin end else ... --- tgt-vhdl/stmt.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 106d1a24d..dfdd59263 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -436,8 +436,9 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container, vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); - draw_stmt(proc, vhdif->get_then_container(), - ivl_stmt_cond_true(stmt)); + ivl_statement_t cond_true_stmt = ivl_stmt_cond_true(stmt); + if (cond_true_stmt) + draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt); ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt); if (cond_false_stmt) From 40cabff44f1bd65fbfd7d2dcaae7baee27b6d4e9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 16:30:50 +0100 Subject: [PATCH 21/57] Leave blank line at end of function --- tgt-vhdl/vhdl_syntax.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 525241901..c0b1e3060 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -848,6 +848,7 @@ void vhdl_function::emit(std::ostream &of, int level) const of << " return Verilog_Result;"; newline(of, level); of << "end function;"; + newline(of, level); } void vhdl_param_decl::emit(std::ostream &of, int level) const From 45e289d32de0babbae31e022c1cbc2a4154846db Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 18:01:37 +0100 Subject: [PATCH 22/57] Implement IVL_LPM_SHIFTL/R --- tgt-vhdl/lpm.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index a1f3ed846..461969a93 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -203,6 +203,22 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return ref; } +static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, + vhdl_binop_t shift_op) +{ + vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); + vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1)); + if (!lhs || !rhs) + return NULL; + + // The RHS must be an integer + vhdl_type integer(VHDL_TYPE_INTEGER); + vhdl_expr *r_cast = rhs->cast(&integer); + + vhdl_type *rtype = new vhdl_type(*lhs->get_type()); + return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype); +} + static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -236,6 +252,10 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: return array_lpm_to_expr(scope, lpm); + case IVL_LPM_SHIFTL: + return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL); + case IVL_LPM_SHIFTR: + return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return NULL; From f3753ea9ad00c1ec241aad86840dab9ec6c61db7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 18:09:18 +0100 Subject: [PATCH 23/57] Add warning that arrays are not yet implemented --- tgt-vhdl/scope.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 76b959a5d..5edc0aa60 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -284,6 +284,9 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ivl_signal_t sig = ivl_scope_sig(scope, i); remember_signal(sig, ent->get_arch()->get_scope()); + if (ivl_signal_array_count(sig) > 1) + error("Arrays not implemented yet"); + vhdl_type *sig_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); From b5e12077b2920b98ed8be2c4389acd67937516e6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 15 Jul 2008 18:40:30 +0100 Subject: [PATCH 24/57] Fix assignment to lval slice It was broken in yeserday's refactoring --- tgt-vhdl/stmt.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index dfdd59263..3f4738989 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -128,7 +128,7 @@ static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, return rhs->cast(&t); } else { - vhdl_type t(tname, lval_width); + vhdl_type t(tname, lval_width - 1); return rhs->cast(&t); } } @@ -143,7 +143,7 @@ static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, vhdl_type *ltype = new vhdl_type(*decl->get_type()); vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); if (base) - lval_ref->set_slice(base, lval_width-1); + lval_ref->set_slice(base, lval_width - 1); return lval_ref; } From d343db34fd792f0a2d1bf611d92b42c1c41913f0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 12:00:11 +0100 Subject: [PATCH 25/57] Fix initialisation order Initial processes set a magic flag in the code generator which allows it to push constant assignments into the VHDL signal initialisation and omit the assignment. However, it should only do this if the signal has not already been read (otherwise the previous read would not get the undefined value as expected) --- tgt-vhdl/expr.cc | 7 ++++++- tgt-vhdl/process.cc | 4 ++-- tgt-vhdl/vhdl_syntax.cc | 19 ++++++++++++++----- tgt-vhdl/vhdl_syntax.hh | 8 +++++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index dc69cd687..b5a76ca37 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -58,9 +58,14 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) const char *renamed = get_renamed_signal(sig).c_str(); - const vhdl_decl *decl = scope->get_decl(renamed); + vhdl_decl *decl = scope->get_decl(renamed); assert(decl); + // Can't generate a constant initialiser for this signal + // later as it has already been read + if (scope->initializing()) + decl->set_initial(NULL); + vhdl_type *type = new vhdl_type(*decl->get_type()); return new vhdl_var_ref(renamed, type); diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 57326a11e..7333dff2b 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -40,8 +40,8 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // If this is an initial process, push signal initialisation // into the declarations - if (ivl_process_type(proc) == IVL_PR_INITIAL) - vhdl_proc->get_scope()->set_initializing(true); + vhdl_proc->get_scope()->set_initializing + (ivl_process_type(proc) == IVL_PR_INITIAL); ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index c0b1e3060..af65ee0a1 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -28,7 +28,7 @@ vhdl_scope::vhdl_scope() : parent_(NULL), init_(false), sig_assign_(true) { - + } vhdl_scope::~vhdl_scope() @@ -36,6 +36,13 @@ vhdl_scope::~vhdl_scope() delete_children(decls_); } +void vhdl_scope::set_initializing(bool i) +{ + init_ = i; + if (parent_) + parent_->set_initializing(i); +} + void vhdl_scope::add_decl(vhdl_decl *decl) { decls_.push_back(decl); @@ -318,10 +325,12 @@ const vhdl_type *vhdl_decl::get_type() const } void vhdl_decl::set_initial(vhdl_expr *initial) -{ - if (initial_ != NULL) - delete initial_; - initial_ = initial; +{ + if (!has_initial_) { + assert(initial_ == NULL); + initial_ = initial; + has_initial_ = true; + } } void vhdl_port_decl::emit(std::ostream &of, int level) const diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index d76370b37..5fa684e21 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -425,18 +425,20 @@ class vhdl_decl : public vhdl_element { public: vhdl_decl(const char *name, vhdl_type *type = NULL, vhdl_expr *initial = NULL) - : name_(name), type_(type), initial_(initial) {} + : name_(name), type_(type), initial_(initial), + has_initial_(initial != NULL) {} virtual ~vhdl_decl(); const std::string &get_name() const { return name_; } const vhdl_type *get_type() const; void set_type(vhdl_type *t) { type_ = t; } void set_initial(vhdl_expr *initial); - bool has_initial() const { return initial_ != NULL; } + bool has_initial() const { return has_initial_; } protected: std::string name_; vhdl_type *type_; vhdl_expr *initial_; + bool has_initial_; }; typedef std::list decl_list_t; @@ -566,7 +568,7 @@ public: void set_parent(vhdl_scope *p) { parent_ = p; } bool initializing() const { return init_; } - void set_initializing(bool i) { init_ = i; } + void set_initializing(bool i); void set_allow_signal_assignment(bool b) { sig_assign_ = b; } bool allow_signal_assignment() const { return sig_assign_; } From 4504c2bcebacbac0ae3d9d0844c429928f9cafa7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 12:11:00 +0100 Subject: [PATCH 26/57] Fix initialisation order bug with `if' statements If an assignment appears inside an if statement branch it could be incorrectly used as the signal's initial value. --- tgt-vhdl/stmt.cc | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 3f4738989..2a1390f5e 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -239,22 +239,26 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, // internal signals not ports if (proc->get_scope()->initializing() && ivl_signal_port(sig) == IVL_SIP_NONE - && !decl->has_initial() && rhs->constant() - && container == proc->get_container()) { // Top-level container + && !decl->has_initial() && rhs->constant()) { - decl->set_initial(rhs); - - return NULL; - } - else { - vhdl_var_ref *lval_ref = - make_assign_lhs(sig, proc->get_scope(), base, lval_width); - - T *a = new T(lval_ref, rhs); - container->add_stmt(a); - - return a; + // If this assignment is not in the top-level container + // it will not be made on all paths through the code + // This precludes any future extraction of an initialiser + if (container != proc->get_container()) + decl->set_initial(NULL); // Default initial value + else { + decl->set_initial(rhs); + return NULL; + } } + + vhdl_var_ref *lval_ref = + make_assign_lhs(sig, proc->get_scope(), base, lval_width); + + T *a = new T(lval_ref, rhs); + container->add_stmt(a); + + return a; } } else { From 646a6056a2f535f46341a9af0307e312a946f12e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 12:50:55 +0100 Subject: [PATCH 27/57] Add IVL_LPM_CMP_EEQ support --- tgt-vhdl/lpm.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 461969a93..5178b15f8 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -118,6 +118,21 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop return expr; } +static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) +{ + vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean()); + + for (int i = 0; i < 2; i++) { + vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i)); + if (NULL == e) + return NULL; + + expr->add_expr(e); + } + + return expr; +} + static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); @@ -230,6 +245,8 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT); case IVL_LPM_CONCAT: return concat_lpm_to_expr(scope, lpm); + case IVL_LPM_CMP_EEQ: + return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ); case IVL_LPM_PART_VP: return part_select_vp_lpm_to_expr(scope, lpm); case IVL_LPM_PART_PV: From f62a00bedbb5ee4dd01170c3f211a1d413dbf90e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 16:20:08 +0100 Subject: [PATCH 28/57] Fix LPM binop with different signedness Need to explicitly cast between signed/unsigned to make sure both arguments have the same type or the VHDL won't compile. --- tgt-vhdl/lpm.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 5178b15f8..64cef0499 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -90,8 +90,9 @@ static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { + unsigned out_width = ivl_lpm_width(lpm); vhdl_type *result_type = - vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); + vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0); vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type); for (int i = 0; i < 2; i++) { @@ -99,14 +100,13 @@ static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop if (NULL == e) return NULL; - expr->add_expr(e); + expr->add_expr(e->cast(result_type)); } if (op == VHDL_BINOP_MULT) { // Need to resize the output to the desired size, // as this does not happen automatically in VHDL - unsigned out_width = ivl_lpm_width(lpm); vhdl_fcall *resize = new vhdl_fcall("Resize", vhdl_type::nsigned(out_width)); resize->add_expr(expr); From be67cae29f190b6f512b7490727069b4ce12a565 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 16:42:44 +0100 Subject: [PATCH 29/57] Add translation for IVL_ST_CASEX --- tgt-vhdl/stmt.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 2a1390f5e..ffc37159a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -561,6 +561,7 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_CONDIT: return draw_if(proc, container, stmt); case IVL_ST_CASE: + case IVL_ST_CASEX: return draw_case(proc, container, stmt); case IVL_ST_WHILE: return draw_while(proc, container, stmt); From 395a2248d87fc54a9e226a63df47458ec21ca4ed Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 16 Jul 2008 16:52:15 +0100 Subject: [PATCH 30/57] Make sure 1-bit constants are std_logic not (un)signed --- tgt-vhdl/expr.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index b5a76ca37..18e37153d 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -76,8 +76,11 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) */ static vhdl_expr *translate_number(ivl_expr_t e) { - return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e), - ivl_expr_signed(e) != 0); + if (ivl_expr_width(e) == 1) + return new vhdl_const_bit(ivl_expr_bits(e)[0]); + else + return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e), + ivl_expr_signed(e) != 0); } static vhdl_expr *translate_unary(ivl_expr_t e) From 642fbe9fc594bded2702c2554f4cd4562cb7240b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 11:31:06 +0100 Subject: [PATCH 31/57] Correct check for arrays --- tgt-vhdl/scope.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5edc0aa60..de6770986 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -284,7 +284,7 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ivl_signal_t sig = ivl_scope_sig(scope, i); remember_signal(sig, ent->get_arch()->get_scope()); - if (ivl_signal_array_count(sig) > 1) + if (ivl_signal_dimensions(sig) > 0) error("Arrays not implemented yet"); vhdl_type *sig_type = From 553f3d77a98ca5b8c838938d84b97b7e81d92153 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 11:43:59 +0100 Subject: [PATCH 32/57] Code for VHDL array type --- tgt-vhdl/vhdl_type.cc | 23 +++++++++++++++++++++++ tgt-vhdl/vhdl_type.hh | 15 ++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index b431b02f1..38183b36e 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -20,6 +20,7 @@ #include "vhdl_type.hh" +#include #include @@ -63,6 +64,12 @@ vhdl_type *vhdl_type::time() return new vhdl_type(VHDL_TYPE_TIME); } +vhdl_type *vhdl_type::get_base() const +{ + assert(name_ == VHDL_TYPE_ARRAY); + return base_; +} + /* * This is just the name of the type, without any parameters. */ @@ -87,6 +94,9 @@ std::string vhdl_type::get_string() const return std::string("signed"); case VHDL_TYPE_UNSIGNED: return std::string("unsigned"); + case VHDL_TYPE_ARRAY: + // Each array has its own type declaration + return array_name_; default: return std::string("BadType"); } @@ -107,6 +117,14 @@ std::string vhdl_type::get_decl_string() const ss << " downto " << lsb_ << ")"; return ss.str(); } + case VHDL_TYPE_ARRAY: + { + std::ostringstream ss; + ss << "array (" << msb_ << " downto " + << lsb_ << ") of " + << base_->get_decl_string(); + return ss.str(); + } default: return get_string(); } @@ -131,3 +149,8 @@ vhdl_type *vhdl_type::type_for(int width, bool issigned, int lsb) else return vhdl_type::nunsigned(width, lsb); } + +vhdl_type *vhdl_type::array_of(vhdl_type *b, std::string &n, int m, int l) +{ + return new vhdl_type(b, n, m, l); +} diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 7b5878478..af9e1515b 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -34,6 +34,7 @@ enum vhdl_type_name_t { VHDL_TYPE_SIGNED, VHDL_TYPE_UNSIGNED, VHDL_TYPE_TIME, + VHDL_TYPE_ARRAY, }; /* @@ -43,14 +44,23 @@ enum vhdl_type_name_t { */ class vhdl_type : public vhdl_element { public: + // Scalar constructor vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0) - : name_(name), msb_(msb), lsb_(lsb) {} + : name_(name), msb_(msb), lsb_(lsb), base_(NULL) {} + + // Array constructor + vhdl_type(vhdl_type *base, const std::string &array_name, + int msb, int lsb) + : name_(VHDL_TYPE_ARRAY), msb_(msb), lsb_(lsb), base_(base), + array_name_(array_name) {} + virtual ~vhdl_type() {} void emit(std::ostream &of, int level) const; vhdl_type_name_t get_name() const { return name_; } std::string get_string() const; std::string get_decl_string() const; + vhdl_type *get_base() const; int get_width() const { return msb_ - lsb_ + 1; } int get_msb() const { return msb_; } int get_lsb() const { return lsb_; } @@ -67,9 +77,12 @@ public: static vhdl_type *time(); static vhdl_type *type_for(int width, bool issigned, int lsb=0); + static vhdl_type *array_of(vhdl_type *b, std::string &n, int m, int l); protected: vhdl_type_name_t name_; int msb_, lsb_; + vhdl_type *base_; // Array base type for VHDL_TYPE_ARRAY + std::string array_name_; // Type name for the array `type array_name_ is ...' }; #endif From c116808fdb229ae686d95af759a3d00d07905e96 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 11:46:36 +0100 Subject: [PATCH 33/57] Remove duplicated code --- tgt-vhdl/scope.cc | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index de6770986..005a36fd0 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -260,20 +260,6 @@ static std::string make_safe_name(ivl_signal_t sig) return name; } -/* - * Create a VHDL type for a Verilog signal. - */ -static vhdl_type *get_signal_type(ivl_signal_t sig) -{ - int width = ivl_signal_width(sig); - if (width == 1) - return vhdl_type::std_logic(); - else if (ivl_signal_signed(sig)) - return vhdl_type::nsigned(width); - else - return vhdl_type::nunsigned(width); -} - /* * Declare all signals and ports for a scope. */ @@ -624,7 +610,9 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - vhdl_type *sigtype = get_signal_type(sig); + vhdl_type *sigtype = + vhdl_type::type_for(ivl_signal_width(sig), + ivl_signal_signed(sig) != 0); std::string signame = make_safe_name(sig); From 7c5b0f737ca2ea291e384f3b1299f19e17ed4a91 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 11:59:02 +0100 Subject: [PATCH 34/57] Class for VHDL type declarations --- tgt-vhdl/vhdl_syntax.cc | 8 ++++++++ tgt-vhdl/vhdl_syntax.hh | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index af65ee0a1..1c4c1a82b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -380,6 +380,14 @@ void vhdl_signal_decl::emit(std::ostream &of, int level) const emit_comment(of, level, true); } +void vhdl_type_decl::emit(std::ofstream &of, int level) const +{ + of << "type " << name_ << " is "; + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); +} + vhdl_expr::~vhdl_expr() { if (type_ != NULL) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 5fa684e21..d0d7f5ff3 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -462,6 +462,14 @@ private: }; +class vhdl_type_decl : public vhdl_decl { +public: + vhdl_type_decl(const char *name, vhdl_type *base) + : vhdl_decl(name, base) {} + void emit(std::ofstream &of, int level) const; +}; + + /* * A variable declaration inside a process (although this isn't * enforced here). From 1d3ac6bc1fa94b1007e54878c3268a132cc9eb50 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 13:08:55 +0100 Subject: [PATCH 35/57] Generate VHDL array type declarations of Verilog arrays --- tgt-vhdl/scope.cc | 31 +++++++++++++++++++++++++------ tgt-vhdl/vhdl_syntax.cc | 5 ++--- tgt-vhdl/vhdl_syntax.hh | 2 +- tgt-vhdl/vhdl_type.cc | 32 ++++++++++++++++++++++++++++++-- tgt-vhdl/vhdl_type.hh | 8 ++++++-- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 005a36fd0..7d5b8e7ff 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -270,14 +270,33 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ivl_signal_t sig = ivl_scope_sig(scope, i); remember_signal(sig, ent->get_arch()->get_scope()); - if (ivl_signal_dimensions(sig) > 0) - error("Arrays not implemented yet"); - - vhdl_type *sig_type = - vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - string name(make_safe_name(sig)); rename_signal(sig, name); + + vhdl_type *sig_type; + unsigned dimensions = ivl_signal_dimensions(sig); + if (dimensions > 0) { + // Arrays are implemented by generating a separate type + // declaration for each array, and then declaring a + // signal of that type + + if (dimensions > 1) { + error("> 1 dimension arrays not implemented yet"); + return; + } + + string type_name = name + "_Type"; + vhdl_type *base_type = + vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); + vhdl_type *array_type = vhdl_type::array_of(base_type, type_name, 1, 0); + vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); + ent->get_arch()->get_scope()->add_decl(array_decl); + + sig_type = new vhdl_type(*array_type); + } + else + sig_type = + vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 1c4c1a82b..74c106c2b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -380,11 +380,10 @@ void vhdl_signal_decl::emit(std::ostream &of, int level) const emit_comment(of, level, true); } -void vhdl_type_decl::emit(std::ofstream &of, int level) const +void vhdl_type_decl::emit(std::ostream &of, int level) const { of << "type " << name_ << " is "; - type_->emit(of, level); - of << ";"; + of << type_->get_type_decl_string() << ";"; emit_comment(of, level, true); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index d0d7f5ff3..91c1161e6 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -466,7 +466,7 @@ class vhdl_type_decl : public vhdl_decl { public: vhdl_type_decl(const char *name, vhdl_type *base) : vhdl_decl(name, base) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 38183b36e..e14c3fbe9 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -22,6 +22,7 @@ #include #include +#include vhdl_type *vhdl_type::std_logic() @@ -117,16 +118,27 @@ std::string vhdl_type::get_decl_string() const ss << " downto " << lsb_ << ")"; return ss.str(); } + default: + return get_string(); + } +} + +/* + * Like get_decl_string but completely expands array declarations. + */ +std::string vhdl_type::get_type_decl_string() const +{ + switch (name_) { case VHDL_TYPE_ARRAY: { std::ostringstream ss; ss << "array (" << msb_ << " downto " << lsb_ << ") of " << base_->get_decl_string(); - return ss.str(); + return ss.str(); } default: - return get_string(); + return get_decl_string(); } } @@ -135,6 +147,22 @@ void vhdl_type::emit(std::ostream &of, int level) const of << get_decl_string(); } +vhdl_type::vhdl_type(const vhdl_type &other) + : name_(other.name_), msb_(other.msb_), lsb_(other.lsb_), + array_name_(other.array_name_) +{ + if (other.base_ != NULL) + base_ = new vhdl_type(*other.base_); + else + base_ = NULL; +} + +vhdl_type::~vhdl_type() +{ + if (base_ != NULL) + delete base_; +} + vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) { return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index af9e1515b..f3bfb2211 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -53,13 +53,17 @@ public: int msb, int lsb) : name_(VHDL_TYPE_ARRAY), msb_(msb), lsb_(lsb), base_(base), array_name_(array_name) {} - - virtual ~vhdl_type() {} + + // Copy constructor + vhdl_type(const vhdl_type &other); + + virtual ~vhdl_type(); void emit(std::ostream &of, int level) const; vhdl_type_name_t get_name() const { return name_; } std::string get_string() const; std::string get_decl_string() const; + std::string get_type_decl_string() const; vhdl_type *get_base() const; int get_width() const { return msb_ - lsb_ + 1; } int get_msb() const { return msb_; } From 2a791bfb38a9948a54c829ed55958a588bca8583 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 13:41:44 +0100 Subject: [PATCH 36/57] Assignment to arrays --- tgt-vhdl/stmt.cc | 16 +++++++++++++--- tgt-vhdl/vhdl_syntax.cc | 29 +++++++++++++++++------------ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index ffc37159a..c6e4deb44 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -117,6 +117,8 @@ static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope, if (base == NULL) return rhs->cast(decl->get_type()); + else if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) + return rhs->cast(decl->get_type()->get_base()); else { // Doesn't make sense to part select on something that's // not a vector @@ -142,8 +144,12 @@ static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, vhdl_type *ltype = new vhdl_type(*decl->get_type()); vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); - if (base) - lval_ref->set_slice(base, lval_width - 1); + if (base) { + if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) + lval_ref->set_slice(base, 0); + else + lval_ref->set_slice(base, lval_width - 1); + } return lval_ref; } @@ -167,6 +173,8 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_expr *base = NULL; ivl_expr_t e_off = ivl_lval_part_off(lval); + if (NULL == e_off) + e_off = ivl_lval_idx(lval); if (e_off) { if ((base = translate_expr(e_off)) == NULL) return NULL; @@ -239,7 +247,9 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, // internal signals not ports if (proc->get_scope()->initializing() && ivl_signal_port(sig) == IVL_SIP_NONE - && !decl->has_initial() && rhs->constant()) { + && !decl->has_initial() + && rhs->constant() + && decl->get_type()->get_name() != VHDL_TYPE_ARRAY) { // If this assignment is not in the top-level container // it will not be made on all paths through the code diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 74c106c2b..3773106fe 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -507,22 +507,27 @@ vhdl_var_ref::~vhdl_var_ref() void vhdl_var_ref::set_slice(vhdl_expr *s, int w) { assert(type_); - - vhdl_type_name_t tname = type_->get_name(); - assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED); - + slice_ = s; slice_width_ = w; + + vhdl_type_name_t tname = type_->get_name(); + if (tname == VHDL_TYPE_ARRAY) { + type_ = new vhdl_type(*type_->get_base()); + } + else { + assert(tname == VHDL_TYPE_UNSIGNED || tname == VHDL_TYPE_SIGNED); - if (type_) - delete type_; - - if (w > 0) - type_ = new vhdl_type(tname, w); - else - type_ = vhdl_type::std_logic(); + if (type_) + delete type_; + + if (w > 0) + type_ = new vhdl_type(tname, w); + else + type_ = vhdl_type::std_logic(); + } } - + void vhdl_var_ref::emit(std::ostream &of, int level) const { of << name_; From c86377790ffbfcf1b7c9dd92461d74699153ec0e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 14:26:35 +0100 Subject: [PATCH 37/57] Automatically convert constant bit strings to integers --- tgt-vhdl/vhdl_syntax.cc | 24 +++++++++++++++++------- tgt-vhdl/vhdl_syntax.hh | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3773106fe..f437a84f6 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -603,6 +603,21 @@ vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned) value_.push_back(*value++); } +int vhdl_const_bits::bits_to_int() const +{ + char msb = value_[value_.size() - 1]; + int result = 0, bit; + for (int i = sizeof(int)*8 - 1; i >= 0; i--) { + if (i > (int)value_.size() - 1) + bit = msb == '1' ? 1 : 0; + else + bit = value_[i] == '1' ? 1 : 0; + result = (result << 1) | bit; + } + + return result; +} + vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) { if (to->get_name() == VHDL_TYPE_STD_LOGIC) { @@ -626,13 +641,8 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) value_.resize(to->get_width(), value_[0]); return this; } - else if (to->get_name() == VHDL_TYPE_INTEGER) { - // Need to explicitly qualify the type (or the VHDL - // compiler gets confused between signed/unsigned) - qualified_ = true; - - return vhdl_expr::cast(to); - } + else if (to->get_name() == VHDL_TYPE_INTEGER) + return new vhdl_const_int(bits_to_int()); else return vhdl_expr::cast(to); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 91c1161e6..21a20510a 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -140,6 +140,8 @@ public: const std::string &get_value() const { return value_; } vhdl_expr *cast(const vhdl_type *to); private: + int bits_to_int() const; + std::string value_; bool qualified_, signed_; }; From 9916686c24d44481804d6451da18bb6eb41da357 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 14:29:56 +0100 Subject: [PATCH 38/57] Convert constant bits to integers --- tgt-vhdl/vhdl_syntax.cc | 8 ++++++++ tgt-vhdl/vhdl_syntax.hh | 1 + 2 files changed, 9 insertions(+) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index f437a84f6..8047baa9c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -662,6 +662,14 @@ void vhdl_const_bits::emit(std::ostream &of, int level) const of << (qualified_ ? "\")" : "\""); } +vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to) +{ + if (to->get_name() == VHDL_TYPE_INTEGER) + return new vhdl_const_int(bit_ == '1' ? 1 : 0); + else + return vhdl_expr::cast(to); +} + void vhdl_const_bit::emit(std::ostream &of, int level) const { of << "'" << vl_to_vhdl_bit(bit_) << "'"; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 21a20510a..9f9fdcfcb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -151,6 +151,7 @@ public: vhdl_const_bit(char bit) : vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {} void emit(std::ostream &of, int level) const; + vhdl_expr *cast(const vhdl_type *to); private: char bit_; }; From 4d9f02900041b7643a29f2693f34f63ddbe3e1bb Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 14:38:07 +0100 Subject: [PATCH 39/57] Generate correct array bounds --- tgt-vhdl/scope.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 7d5b8e7ff..9a6109b45 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -288,7 +288,12 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) string type_name = name + "_Type"; vhdl_type *base_type = vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - vhdl_type *array_type = vhdl_type::array_of(base_type, type_name, 1, 0); + + int lsb = ivl_signal_array_base(sig); + int msb = lsb + ivl_signal_array_count(sig) - 1; + + vhdl_type *array_type = + vhdl_type::array_of(base_type, type_name, msb, lsb); vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); ent->get_arch()->get_scope()->add_decl(array_decl); From 9cf4792d53762804ab1e7cb1eea9e9d26a461f7b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 14:47:10 +0100 Subject: [PATCH 40/57] Translate array references in expressions --- tgt-vhdl/expr.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 18e37153d..9d9316720 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -66,9 +66,21 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) if (scope->initializing()) decl->set_initial(NULL); - vhdl_type *type = new vhdl_type(*decl->get_type()); - - return new vhdl_var_ref(renamed, type); + vhdl_var_ref *ref = + new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type())); + + ivl_expr_t off; + if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) { + // Select from an array + vhdl_expr *vhd_off = translate_expr(off); + if (NULL == vhd_off) + return NULL; + + vhdl_type integer(VHDL_TYPE_INTEGER); + ref->set_slice(vhd_off->cast(&integer)); + } + + return ref; } /* From 7677b596505d999c2a727a4bca13d89293d153d3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 16:41:34 +0100 Subject: [PATCH 41/57] Make sure offset of IVL_LPM_ARRAY is integer --- tgt-vhdl/lpm.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 64cef0499..753d23096 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -138,7 +138,7 @@ static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) return NULL; - + vhdl_expr *off = part_select_base(scope, lpm);; if (NULL == off) return NULL; @@ -213,7 +213,8 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return NULL; vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype); - ref->set_slice(select); + vhdl_type integer(VHDL_TYPE_INTEGER); + ref->set_slice(select->cast(&integer)); return ref; } From 1f9ed2c5ec28ff3ea5d1d2b3d80a142e2d9bdce0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 17:23:21 +0100 Subject: [PATCH 42/57] VHDL AST element for `wait on' statement --- tgt-vhdl/stmt.cc | 2 +- tgt-vhdl/vhdl_syntax.cc | 10 ++++++++++ tgt-vhdl/vhdl_syntax.hh | 4 +++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c6e4deb44..e95ea65ef 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -435,8 +435,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } } - draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 8047baa9c..e1e1684d9 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -305,6 +305,16 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const of << " until "; expr_->emit(of, level); break; + case VHDL_WAIT_ON: + { + string_list_t::const_iterator it = sensitivity_.begin(); + while (it != sensitivity_.end()) { + of << *it; + if (++it != sensitivity_.end()) + of << ", "; + } + } + break; } of << ";"; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9f9fdcfcb..a920e8bfb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -307,7 +307,8 @@ public: enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR, // Wait for a constant amount of time - VHDL_WAIT_UNTIL, // Wait on a sensitivity list + VHDL_WAIT_UNTIL, // Wait on an expression + VHDL_WAIT_ON, // Wait on a sensitivity list }; /* @@ -325,6 +326,7 @@ public: private: vhdl_wait_type_t type_; vhdl_expr *expr_; + string_list_t sensitivity_; }; From e9637f6d11663708ca8bb803df6ce75c5d0e48cc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 17 Jul 2008 17:36:42 +0100 Subject: [PATCH 43/57] Generate synthesisable code for sequential processes Whilst adding `wait until ...' at the end of every process is a valid translation of the input, it is not actually synthesisable in at least one commercial synthesiser (XST). According to the XST manual the correct template is to use `wait until ...' at the start of sequential processes and `wait on ...' (equivalent to `wait until ...' with 'Event on all the signals) at the end of combinatorial processes. This patch implements that. --- tgt-vhdl/stmt.cc | 102 ++++++++++++++++++++++++++-------------- tgt-vhdl/vhdl_syntax.cc | 1 + tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e95ea65ef..eb387e79d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -387,7 +387,10 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, /* * A wait statement waits for a level change on a @(..) list of - * signals. + * signals. Purely combinatorial processes (i.e. no posedge/negedge + * events) produce a `wait on' statement at the end of the process. + * Sequential processes produce a `wait until' statement at the + * start of the process. */ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_statement_t stmt) @@ -398,45 +401,74 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, vhdl_binop_expr *test = new vhdl_binop_expr(VHDL_BINOP_OR, vhdl_type::boolean()); - + int nevents = ivl_stmt_nevent(stmt); + + bool combinatorial = true; // True if no negedge/posedge events for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); - - int nany = ivl_event_nany(event); - for (int i = 0; i < nany; i++) { - ivl_nexus_t nexus = ivl_event_any(event, i); - vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); - - ref->set_name(ref->get_name() + "'Event"); - test->add_expr(ref); - } - - int nneg = ivl_event_nneg(event); - for (int i = 0; i < nneg; i++) { - ivl_nexus_t nexus = ivl_event_neg(event, i); - vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); - vhdl_fcall *detect = - new vhdl_fcall("falling_edge", vhdl_type::boolean()); - detect->add_expr(ref); - - test->add_expr(detect); - } - - int npos = ivl_event_npos(event); - for (int i = 0; i < npos; i++) { - ivl_nexus_t nexus = ivl_event_pos(event, i); - vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); - vhdl_fcall *detect = - new vhdl_fcall("rising_edge", vhdl_type::boolean()); - detect->add_expr(ref); - - test->add_expr(detect); - } + if (ivl_event_npos(event) > 0 || ivl_event_nneg(event) > 0) + combinatorial = false; } - container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); - draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + if (combinatorial) { + vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_ON); + + for (int i = 0; i < nevents; i++) { + ivl_event_t event = ivl_stmt_events(stmt, i); + + int nany = ivl_event_nany(event); + for (int i = 0; i < nany; i++) { + ivl_nexus_t nexus = ivl_event_any(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + + wait->add_sensitivity(ref->get_name()); + delete ref; + } + } + + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + container->add_stmt(wait); + } + else { + for (int i = 0; i < nevents; i++) { + ivl_event_t event = ivl_stmt_events(stmt, i); + + int nany = ivl_event_nany(event); + for (int i = 0; i < nany; i++) { + ivl_nexus_t nexus = ivl_event_any(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + + ref->set_name(ref->get_name() + "'Event"); + test->add_expr(ref); + } + + int nneg = ivl_event_nneg(event); + for (int i = 0; i < nneg; i++) { + ivl_nexus_t nexus = ivl_event_neg(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + vhdl_fcall *detect = + new vhdl_fcall("falling_edge", vhdl_type::boolean()); + detect->add_expr(ref); + + test->add_expr(detect); + } + + int npos = ivl_event_npos(event); + for (int i = 0; i < npos; i++) { + ivl_nexus_t nexus = ivl_event_pos(event, i); + vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); + vhdl_fcall *detect = + new vhdl_fcall("rising_edge", vhdl_type::boolean()); + detect->add_expr(ref); + + test->add_expr(detect); + } + } + + container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + } return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e1e1684d9..b41bdf31c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -307,6 +307,7 @@ void vhdl_wait_stmt::emit(std::ostream &of, int level) const break; case VHDL_WAIT_ON: { + of << " on "; string_list_t::const_iterator it = sensitivity_.begin(); while (it != sensitivity_.end()) { of << *it; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a920e8bfb..00daee489 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -323,6 +323,7 @@ public: ~vhdl_wait_stmt(); void emit(std::ostream &of, int level) const; + void add_sensitivity(const std::string &s) { sensitivity_.push_back(s); } private: vhdl_wait_type_t type_; vhdl_expr *expr_; From 00317dd47f1e8926a78bf42d840e037d516c8d06 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 11:50:05 +0100 Subject: [PATCH 44/57] Dummy implementation of $time --- tgt-vhdl/expr.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 9d9316720..9917e3c9c 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -22,6 +22,8 @@ #include #include +#include + /* * Change the signedness of a vector. @@ -402,6 +404,23 @@ static vhdl_expr *translate_concat(ivl_expr_t e) return translate_parms(concat, e); } +vhdl_expr *translate_sfunc_time(ivl_expr_t e) +{ + cerr << "warning: no translation for time (returning 0)" << endl; + return new vhdl_const_int(0); +} + +vhdl_expr *translate_sfunc(ivl_expr_t e) +{ + const char *name = ivl_expr_name(e); + if (strcmp(name, "$time") == 0) + return translate_sfunc_time(e); + else { + error("No translation for system function %s", name); + return NULL; + } +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -429,6 +448,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_ternary(e); case IVL_EX_CONCAT: return translate_concat(e); + case IVL_EX_SFUNC: + return translate_sfunc(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); From fd8f01e3172b02ae522989a8a49b2afbd3f340a1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 11:56:00 +0100 Subject: [PATCH 45/57] Add IVL_LPM_CMP_GE --- tgt-vhdl/lpm.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 753d23096..0f6ccf051 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -246,6 +246,8 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT); case IVL_LPM_CONCAT: return concat_lpm_to_expr(scope, lpm); + case IVL_LPM_CMP_GE: + return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ); case IVL_LPM_CMP_EEQ: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ); case IVL_LPM_PART_VP: From 8b6b111541aa5859137eb87763727c48ce3dcbea Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 11:58:26 +0100 Subject: [PATCH 46/57] Add IVL_LPM_CMP_EQ --- tgt-vhdl/lpm.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 0f6ccf051..4f097b893 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -248,6 +248,7 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return concat_lpm_to_expr(scope, lpm); case IVL_LPM_CMP_GE: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ); + case IVL_LPM_CMP_EQ: case IVL_LPM_CMP_EEQ: return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ); case IVL_LPM_PART_VP: From 6ff80e80a4423118c39d23d86be2e6a96622857d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 12:30:24 +0100 Subject: [PATCH 47/57] Catch case where (un)signed is converted to boolean --- tgt-vhdl/vhdl_syntax.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index b41bdf31c..7eda301da 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -422,10 +422,15 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return resize(to->get_width()); } else if (to->get_name() == VHDL_TYPE_BOOLEAN) { - // '1' is true all else are false - vhdl_const_bit *one = new vhdl_const_bit('1'); - return new vhdl_binop_expr - (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); + if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { + // '1' is true all else are false + vhdl_const_bit *one = new vhdl_const_bit('1'); + return new vhdl_binop_expr + (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); + } + else { + assert(false); + } } else if (to->get_name() == VHDL_TYPE_INTEGER) { vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); From df4a380e42ae18d932be1fa51e0568c0361bc8dc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 14:31:12 +0100 Subject: [PATCH 48/57] Fix implementation of IVL_LPM_UFUNC Function name was not correct. --- tgt-vhdl/lpm.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 4f097b893..0a29d255f 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -155,7 +155,8 @@ static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { - vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL); + ivl_scope_t f_scope = ivl_lpm_define(lpm); + vhdl_fcall *fcall = new vhdl_fcall(ivl_scope_basename(f_scope), NULL); for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) { vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i)); From 7b311b6adb60905872a386a857013b551745965f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 18 Jul 2008 14:47:35 +0100 Subject: [PATCH 49/57] Translate internal delays in assignments --- tgt-vhdl/expr.cc | 7 +++++++ tgt-vhdl/stmt.cc | 40 ++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 9917e3c9c..6cc6b5827 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -97,6 +97,11 @@ static vhdl_expr *translate_number(ivl_expr_t e) ivl_expr_signed(e) != 0); } +static vhdl_expr *translate_ulong(ivl_expr_t e) +{ + return new vhdl_const_int(ivl_expr_uvalue(e)); +} + static vhdl_expr *translate_unary(ivl_expr_t e) { vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); @@ -436,6 +441,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_signal(e); case IVL_EX_NUMBER: return translate_number(e); + case IVL_EX_ULONG: + return translate_ulong(e); case IVL_EX_UNARY: return translate_unary(e); case IVL_EX_BINARY: diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index eb387e79d..87efac0e2 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -159,7 +159,7 @@ static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, */ template static T *make_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, bool blocking) + ivl_statement_t stmt, bool blocking, vhdl_expr *after) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -268,6 +268,24 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, T *a = new T(lval_ref, rhs); container->add_stmt(a); + ivl_expr_t i_delay; + if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) { + if ((after = translate_expr(i_delay)) == NULL) + return NULL; + + // Need to make 'after' a time value + // we can do this by multiplying by 1ns + vhdl_type integer(VHDL_TYPE_INTEGER); + after = after->cast(&integer); + + vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS); + after = new vhdl_binop_expr(after, VHDL_BINOP_MULT, ns1, + vhdl_type::time()); + } + + if (after != NULL) + a->set_after(after); + return a; } } @@ -287,15 +305,8 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, { assert(proc->get_scope()->allow_signal_assignment()); - vhdl_nbassign_stmt *a = - make_assignment(proc, container, stmt, false); + make_assignment(proc, container, stmt, false, after); - if (a != NULL) { - // Assignment wasn't moved to initialisation - if (after != NULL) - a->set_after(after); - } - return 0; } @@ -307,20 +318,13 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, // followed by a zero-time wait // This follows the Verilog semantics fairly closely. - vhdl_nbassign_stmt *a = - make_assignment(proc, container, stmt, false); - - if (a != NULL) { - // Assignment is a statement and not moved into the initialisation - //if (after != NULL) - // a->set_after(after); - } + make_assignment(proc, container, stmt, false, NULL); container->add_stmt (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); } else - make_assignment(proc, container, stmt, true); + make_assignment(proc, container, stmt, true, NULL); return 0; } From 2d79e1a2e031696383b502384d92e963c18e5a22 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 19 Jul 2008 14:45:00 +0100 Subject: [PATCH 50/57] Store the currently active entity --- tgt-vhdl/process.cc | 2 ++ tgt-vhdl/scope.cc | 16 ++++++++++++++++ tgt-vhdl/vhdl_target.h | 3 ++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 7333dff2b..5276feed6 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -31,6 +31,8 @@ */ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { + set_active_entity(ent); + // Create a new process and store it in the entity's // architecture. This needs to be done first or the // parent link won't be valid (and draw_stmt needs this diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 9a6109b45..ac1202fff 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -28,6 +28,19 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); static std::string make_safe_name(ivl_signal_t sig); +static vhdl_entity *g_active_entity = NULL; + +vhdl_entity *get_active_entity() +{ + return g_active_entity; +} + +void set_active_entity(vhdl_entity *ent) +{ + g_active_entity = ent; +} + + /* * The types of VHDL object a nexus can be converted into. */ @@ -409,6 +422,8 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // retain a 1-to-1 mapping of scope to VHDL element) vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog"); vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch); + + set_active_entity(ent); // Locate all the signals in this module and add them to // the architecture @@ -558,6 +573,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) if (NULL == ent) ent = create_entity_for(scope); assert(ent); + set_active_entity(ent); // Is this module instantiated inside another? if (parent != NULL) { diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 9dc559c96..d667783fe 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -26,7 +26,8 @@ void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const string &tname); ivl_design_t get_vhdl_design(); -//vhdl_entity *get_active_entity(); +vhdl_entity *get_active_entity(); +void set_active_entity(vhdl_entity *ent); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); From b6df73d3b9b2ebbbdddf71dc2141bce745dd3aec Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 19 Jul 2008 15:15:16 +0100 Subject: [PATCH 51/57] Support functions for converting (un)signed -> boolean --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/support.cc | 50 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/support.hh | 45 +++++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 22 ++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 2 +- tgt-vhdl/vhdl_target.h | 8 +++++++ 6 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 tgt-vhdl/support.cc create mode 100644 tgt-vhdl/support.hh diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 1b2f15a1c..a6232b0e1 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -50,7 +50,7 @@ dep: mv $*.d dep O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ - stmt.o expr.o lpm.o display.o + stmt.o expr.o lpm.o display.o support.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc new file mode 100644 index 000000000..b8493c263 --- /dev/null +++ b/tgt-vhdl/support.cc @@ -0,0 +1,50 @@ +/* + * Support functions for VHDL output. + * + * Copyright (C) 2008 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "vhdl_target.h" +#include "support.hh" + +#include + +void unsigned_to_boolean::emit(std::ostream &of, int level) const +{ + of << "function " << function_name() + << "(X : unsigned) return Boolean is"; + newline(of, level); + of << "begin"; + newline(of, indent(level)); + of << "return X /= To_Unsigned(0, X'Length);"; + newline(of, level); + of << "end function;"; + newline(of, level); +} + +void signed_to_boolean::emit(std::ostream &of, int level) const +{ + of << "function " << function_name() + << "(X : signed) return Boolean is"; + newline(of, level); + of << "begin"; + newline(of, indent(level)); + of << "return X /= To_Signed(0, X'Length);"; + newline(of, level); + of << "end function;"; + newline(of, level); +} diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh new file mode 100644 index 000000000..386e96f0e --- /dev/null +++ b/tgt-vhdl/support.hh @@ -0,0 +1,45 @@ +/* + * Support functions for VHDL output. + * + * Copyright (C) 2008 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INC_SUPPORT_HH +#define INC_SUPPORT_HH + +#include "vhdl_syntax.hh" + +class unsigned_to_boolean : public vhdl_function { +public: + unsigned_to_boolean() + : vhdl_function(function_name(), vhdl_type::boolean()) {} + void emit(std::ostream &of, int level) const; + + static const char *function_name() { return "Unsigned_To_Boolean"; } +}; + + +class signed_to_boolean : public vhdl_function { +public: + signed_to_boolean() + : vhdl_function(function_name(), vhdl_type::boolean()) {} + void emit(std::ostream &of, int level) const; + + static const char *function_name() { return "Signed_To_Boolean"; } +}; + +#endif diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 7eda301da..34dc9062c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -21,6 +21,9 @@ #include "vhdl_syntax.hh" #include "vhdl_helper.hh" +#include "vhdl_target.h" +#include "support.hh" + #include #include #include @@ -428,6 +431,25 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return new vhdl_binop_expr (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); } + else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { + // Need to use a support function for this conversion + require_support_function(); + + vhdl_fcall *conv = + new vhdl_fcall(unsigned_to_boolean::function_name(), + vhdl_type::boolean()); + conv->add_expr(this); + return conv; + } + else if (type_->get_name() == VHDL_TYPE_SIGNED) { + require_support_function(); + + vhdl_fcall *conv = + new vhdl_fcall(signed_to_boolean::function_name(), + vhdl_type::boolean()); + conv->add_expr(this); + return conv; + } else { assert(false); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 00daee489..fcf06286a 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -614,7 +614,7 @@ class vhdl_function : public vhdl_decl, public vhdl_procedural { public: vhdl_function(const char *name, vhdl_type *ret_type); - void emit(std::ostream &of, int level) const; + virtual void emit(std::ostream &of, int level) const; vhdl_scope *get_scope() { return &variables_; } void add_param(vhdl_param_decl *p) { scope_.add_decl(p); } private: diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index d667783fe..db583206d 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -41,5 +41,13 @@ 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); +template +void require_support_function() +{ + vhdl_scope *scope = get_active_entity()->get_arch()->get_scope(); + if (!scope->have_declared(T::function_name())) + scope->add_decl(new T); +} + #endif /* #ifndef INC_VHDL_TARGET_H */ From 0cb6ea34d7f68bba7dbdb618a0c708f4e662dad7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 19 Jul 2008 15:23:47 +0100 Subject: [PATCH 52/57] Move type conversion code into a separate file --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/cast.cc | 172 ++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 151 ----------------------------------- 3 files changed, 173 insertions(+), 152 deletions(-) create mode 100644 tgt-vhdl/cast.cc diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index a6232b0e1..36727ce67 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -50,7 +50,7 @@ dep: mv $*.d dep O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ - stmt.o expr.o lpm.o display.o support.o + stmt.o expr.o lpm.o display.o support.o cast.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc new file mode 100644 index 000000000..2b558fc81 --- /dev/null +++ b/tgt-vhdl/cast.cc @@ -0,0 +1,172 @@ +/* + * Generate code to convert between VHDL types. + * + * Copyright (C) 2008 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "vhdl_syntax.hh" + +#include "vhdl_target.h" +#include "support.hh" + +#include +#include + +vhdl_expr *vhdl_expr::cast(const vhdl_type *to) +{ + //std::cout << "Cast: from=" << type_->get_string() + // << " (" << type_->get_width() << ") " + // << " to=" << to->get_string() << " (" + // << to->get_width() << ")" << std::endl; + + if (to->get_name() == type_->get_name()) { + if (to->get_width() == type_->get_width()) + return this; // Identical + else + return resize(to->get_width()); + } + else if (to->get_name() == VHDL_TYPE_BOOLEAN) { + if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { + // '1' is true all else are false + vhdl_const_bit *one = new vhdl_const_bit('1'); + return new vhdl_binop_expr + (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); + } + else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { + // Need to use a support function for this conversion + require_support_function(); + + vhdl_fcall *conv = + new vhdl_fcall(unsigned_to_boolean::function_name(), + vhdl_type::boolean()); + conv->add_expr(this); + return conv; + } + else if (type_->get_name() == VHDL_TYPE_SIGNED) { + require_support_function(); + + vhdl_fcall *conv = + new vhdl_fcall(signed_to_boolean::function_name(), + vhdl_type::boolean()); + conv->add_expr(this); + return conv; + } + else { + assert(false); + } + } + else if (to->get_name() == VHDL_TYPE_INTEGER) { + vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); + conv->add_expr(this); + + return conv; + } + else if (to->get_name() == VHDL_TYPE_STD_LOGIC && + type_->get_name() == VHDL_TYPE_BOOLEAN) { + // Verilog assumes active-high logic and there + // is a special routine in verilog_support.vhd + // to do this for us + vhdl_fcall *ah = new vhdl_fcall("Active_High", vhdl_type::std_logic()); + ah->add_expr(this); + + return ah; + } + else { + // We have to cast the expression before resizing or the + // wrong sign bit may be extended (i.e. when casting between + // signed/unsigned *and* resizing) + vhdl_fcall *conv = + new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); + conv->add_expr(this); + + if (to->get_width() != type_->get_width()) + return conv->resize(to->get_width()); + else + return conv; + } +} + +vhdl_expr *vhdl_expr::resize(int newwidth) +{ + vhdl_type *rtype; + assert(type_); + if (type_->get_name() == VHDL_TYPE_SIGNED) + rtype = vhdl_type::nsigned(newwidth); + else if (type_->get_name() == VHDL_TYPE_UNSIGNED) + rtype = vhdl_type::nunsigned(newwidth); + else + return this; // Doesn't make sense to resize non-vector type + + vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); + resize->add_expr(this); + resize->add_expr(new vhdl_const_int(newwidth)); + + return resize; +} + + +int vhdl_const_bits::bits_to_int() const +{ + char msb = value_[value_.size() - 1]; + int result = 0, bit; + for (int i = sizeof(int)*8 - 1; i >= 0; i--) { + if (i > (int)value_.size() - 1) + bit = msb == '1' ? 1 : 0; + else + bit = value_[i] == '1' ? 1 : 0; + result = (result << 1) | bit; + } + + return result; +} + +vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) +{ + if (to->get_name() == VHDL_TYPE_STD_LOGIC) { + // VHDL won't let us cast directly between a vector and + // a scalar type + // But we don't need to here as we have the bits available + + // Take the least significant bit + char lsb = value_[0]; + + return new vhdl_const_bit(lsb); + } + else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) { + // Don't need to do anything + return this; + } + else if (to->get_name() == VHDL_TYPE_SIGNED + || to->get_name() == VHDL_TYPE_UNSIGNED) { + + // Extend with sign bit + value_.resize(to->get_width(), value_[0]); + return this; + } + else if (to->get_name() == VHDL_TYPE_INTEGER) + return new vhdl_const_int(bits_to_int()); + else + return vhdl_expr::cast(to); +} + +vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to) +{ + if (to->get_name() == VHDL_TYPE_INTEGER) + return new vhdl_const_int(bit_ == '1' ? 1 : 0); + else + return vhdl_expr::cast(to); +} diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 34dc9062c..3cc70853a 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -21,9 +21,6 @@ #include "vhdl_syntax.hh" #include "vhdl_helper.hh" -#include "vhdl_target.h" -#include "support.hh" - #include #include #include @@ -407,102 +404,6 @@ vhdl_expr::~vhdl_expr() delete type_; } -/* - * The default cast just assumes there's a VHDL cast function to - * do the job for us. - */ -vhdl_expr *vhdl_expr::cast(const vhdl_type *to) -{ - //std::cout << "Cast: from=" << type_->get_string() - // << " (" << type_->get_width() << ") " - // << " to=" << to->get_string() << " (" - // << to->get_width() << ")" << std::endl; - - if (to->get_name() == type_->get_name()) { - if (to->get_width() == type_->get_width()) - return this; // Identical - else - return resize(to->get_width()); - } - else if (to->get_name() == VHDL_TYPE_BOOLEAN) { - if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { - // '1' is true all else are false - vhdl_const_bit *one = new vhdl_const_bit('1'); - return new vhdl_binop_expr - (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); - } - else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { - // Need to use a support function for this conversion - require_support_function(); - - vhdl_fcall *conv = - new vhdl_fcall(unsigned_to_boolean::function_name(), - vhdl_type::boolean()); - conv->add_expr(this); - return conv; - } - else if (type_->get_name() == VHDL_TYPE_SIGNED) { - require_support_function(); - - vhdl_fcall *conv = - new vhdl_fcall(signed_to_boolean::function_name(), - vhdl_type::boolean()); - conv->add_expr(this); - return conv; - } - else { - assert(false); - } - } - else if (to->get_name() == VHDL_TYPE_INTEGER) { - vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); - conv->add_expr(this); - - return conv; - } - else if (to->get_name() == VHDL_TYPE_STD_LOGIC && - type_->get_name() == VHDL_TYPE_BOOLEAN) { - // Verilog assumes active-high logic and there - // is a special routine in verilog_support.vhd - // to do this for us - vhdl_fcall *ah = new vhdl_fcall("Active_High", vhdl_type::std_logic()); - ah->add_expr(this); - - return ah; - } - else { - // We have to cast the expression before resizing or the - // wrong sign bit may be extended (i.e. when casting between - // signed/unsigned *and* resizing) - vhdl_fcall *conv = - new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); - conv->add_expr(this); - - if (to->get_width() != type_->get_width()) - return conv->resize(to->get_width()); - else - return conv; - } -} - -vhdl_expr *vhdl_expr::resize(int newwidth) -{ - vhdl_type *rtype; - assert(type_); - if (type_->get_name() == VHDL_TYPE_SIGNED) - rtype = vhdl_type::nsigned(newwidth); - else if (type_->get_name() == VHDL_TYPE_UNSIGNED) - rtype = vhdl_type::nunsigned(newwidth); - else - return this; // Doesn't make sense to resize non-vector type - - vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); - resize->add_expr(this); - resize->add_expr(new vhdl_const_int(newwidth)); - - return resize; -} - void vhdl_expr_list::add_expr(vhdl_expr *e) { exprs_.push_back(e); @@ -641,50 +542,6 @@ vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned) value_.push_back(*value++); } -int vhdl_const_bits::bits_to_int() const -{ - char msb = value_[value_.size() - 1]; - int result = 0, bit; - for (int i = sizeof(int)*8 - 1; i >= 0; i--) { - if (i > (int)value_.size() - 1) - bit = msb == '1' ? 1 : 0; - else - bit = value_[i] == '1' ? 1 : 0; - result = (result << 1) | bit; - } - - return result; -} - -vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) -{ - if (to->get_name() == VHDL_TYPE_STD_LOGIC) { - // VHDL won't let us cast directly between a vector and - // a scalar type - // But we don't need to here as we have the bits available - - // Take the least significant bit - char lsb = value_[0]; - - return new vhdl_const_bit(lsb); - } - else if (to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) { - // Don't need to do anything - return this; - } - else if (to->get_name() == VHDL_TYPE_SIGNED - || to->get_name() == VHDL_TYPE_UNSIGNED) { - - // Extend with sign bit - value_.resize(to->get_width(), value_[0]); - return this; - } - else if (to->get_name() == VHDL_TYPE_INTEGER) - return new vhdl_const_int(bits_to_int()); - else - return vhdl_expr::cast(to); -} - void vhdl_const_bits::emit(std::ostream &of, int level) const { if (qualified_) @@ -700,14 +557,6 @@ void vhdl_const_bits::emit(std::ostream &of, int level) const of << (qualified_ ? "\")" : "\""); } -vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to) -{ - if (to->get_name() == VHDL_TYPE_INTEGER) - return new vhdl_const_int(bit_ == '1' ? 1 : 0); - else - return vhdl_expr::cast(to); -} - void vhdl_const_bit::emit(std::ostream &of, int level) const { of << "'" << vl_to_vhdl_bit(bit_) << "'"; From af3ee49f57781c8a1c1989c71be47846243fb985 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 19 Jul 2008 20:49:55 +0100 Subject: [PATCH 53/57] Refactor support function code a bit --- tgt-vhdl/cast.cc | 17 ++++---- tgt-vhdl/support.cc | 90 +++++++++++++++++++++++++++++++++--------- tgt-vhdl/support.hh | 24 +++++------ tgt-vhdl/vhdl_target.h | 10 ++--- 4 files changed, 96 insertions(+), 45 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 2b558fc81..7d83a67f4 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -48,19 +48,19 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) } else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { // Need to use a support function for this conversion - require_support_function(); + require_support_function(SF_UNSIGNED_TO_BOOLEAN); vhdl_fcall *conv = - new vhdl_fcall(unsigned_to_boolean::function_name(), + new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN), vhdl_type::boolean()); conv->add_expr(this); return conv; } else if (type_->get_name() == VHDL_TYPE_SIGNED) { - require_support_function(); + require_support_function(SF_SIGNED_TO_BOOLEAN); vhdl_fcall *conv = - new vhdl_fcall(signed_to_boolean::function_name(), + new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN), vhdl_type::boolean()); conv->add_expr(this); return conv; @@ -77,10 +77,11 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) } else if (to->get_name() == VHDL_TYPE_STD_LOGIC && type_->get_name() == VHDL_TYPE_BOOLEAN) { - // Verilog assumes active-high logic and there - // is a special routine in verilog_support.vhd - // to do this for us - vhdl_fcall *ah = new vhdl_fcall("Active_High", vhdl_type::std_logic()); + require_support_function(SF_BOOLEAN_TO_LOGIC); + + vhdl_fcall *ah = + new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC), + vhdl_type::std_logic()); ah->add_expr(this); return ah; diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index b8493c263..e76730241 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -23,28 +23,82 @@ #include -void unsigned_to_boolean::emit(std::ostream &of, int level) const +void require_support_function(support_function_t f) { - of << "function " << function_name() - << "(X : unsigned) return Boolean is"; - newline(of, level); - of << "begin"; - newline(of, indent(level)); - of << "return X /= To_Unsigned(0, X'Length);"; - newline(of, level); - of << "end function;"; - newline(of, level); + vhdl_scope *scope = get_active_entity()->get_arch()->get_scope(); + if (!scope->have_declared(support_function::function_name(f))) + scope->add_decl(new support_function(f)); } -void signed_to_boolean::emit(std::ostream &of, int level) const +const char *support_function::function_name(support_function_t type) { - of << "function " << function_name() - << "(X : signed) return Boolean is"; - newline(of, level); - of << "begin"; - newline(of, indent(level)); - of << "return X /= To_Signed(0, X'Length);"; - newline(of, level); + switch (type) { + case SF_UNSIGNED_TO_BOOLEAN: + return "Unsigned_To_Boolean"; + case SF_SIGNED_TO_BOOLEAN: + return "Signed_To_Boolean"; + case SF_BOOLEAN_TO_LOGIC: + return "Boolean_To_Logic"; + default: + assert(false); + } +} + +vhdl_type *support_function::function_type(support_function_t type) +{ + switch (type) { + case SF_UNSIGNED_TO_BOOLEAN: + return vhdl_type::boolean(); + case SF_SIGNED_TO_BOOLEAN: + return vhdl_type::boolean(); + case SF_BOOLEAN_TO_LOGIC: + return vhdl_type::std_logic(); + default: + assert(false); + } +} + +void support_function::emit(std::ostream &of, int level) const +{ + of << "function " << function_name(type_); + + switch (type_) { + case SF_UNSIGNED_TO_BOOLEAN: + of << "(X : unsigned) return Boolean is"; + newline(of, level); + of << "begin"; + newline(of, indent(level)); + of << "return X /= To_Unsigned(0, X'Length);"; + newline(of, level); + break; + case SF_SIGNED_TO_BOOLEAN: + of << "(X : signed) return Boolean is"; + newline(of, level); + of << "begin"; + newline(of, indent(level)); + of << "return X /= To_Signed(0, X'Length);"; + newline(of, level); + break; + case SF_BOOLEAN_TO_LOGIC: + of << "(B : Boolean) return std_logic is"; + newline(of, level); + of << "begin"; + newline(of, indent(level)); + of << "if B then"; + newline(of, indent(indent(level))); + of << "return '1'"; + newline(of, indent(level)); + of << "else"; + newline(of, indent(indent(level))); + of << "return '0'"; + newline(of, indent(level)); + of << "end if;"; + newline(of, level); + break; + default: + assert(false); + } + of << "end function;"; newline(of, level); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index 386e96f0e..67a9ea2e8 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -23,23 +23,23 @@ #include "vhdl_syntax.hh" -class unsigned_to_boolean : public vhdl_function { -public: - unsigned_to_boolean() - : vhdl_function(function_name(), vhdl_type::boolean()) {} - void emit(std::ostream &of, int level) const; - - static const char *function_name() { return "Unsigned_To_Boolean"; } +enum support_function_t { + SF_UNSIGNED_TO_BOOLEAN, + SF_SIGNED_TO_BOOLEAN, + SF_BOOLEAN_TO_LOGIC, }; - -class signed_to_boolean : public vhdl_function { +class support_function : public vhdl_function { public: - signed_to_boolean() - : vhdl_function(function_name(), vhdl_type::boolean()) {} + support_function(support_function_t type) + : vhdl_function(function_name(type), function_type(type)), + type_(type) {} void emit(std::ostream &of, int level) const; + static const char *function_name(support_function_t type); + static vhdl_type *function_type(support_function_t type); - static const char *function_name() { return "Signed_To_Boolean"; } +private: + support_function_t type_; }; #endif diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index db583206d..20584eecf 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -7,6 +7,8 @@ #include "vhdl_syntax.hh" #include "vhdl_type.hh" +#include "support.hh" + #include using namespace std; @@ -41,13 +43,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); -template -void require_support_function() -{ - vhdl_scope *scope = get_active_entity()->get_arch()->get_scope(); - if (!scope->have_declared(T::function_name())) - scope->add_decl(new T); -} +void require_support_function(support_function_t f); #endif /* #ifndef INC_VHDL_TARGET_H */ From 38de6ebf3a48babe692e3e024bffeee3c3821b9a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 19 Jul 2008 21:04:52 +0100 Subject: [PATCH 54/57] Compress support function definitions a bit --- tgt-vhdl/support.cc | 42 ++++++++++++++-------------------------- tgt-vhdl/vhdl_element.cc | 7 +++++++ tgt-vhdl/vhdl_element.hh | 1 + 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index e76730241..bdbeab6f8 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -64,41 +64,27 @@ void support_function::emit(std::ostream &of, int level) const switch (type_) { case SF_UNSIGNED_TO_BOOLEAN: - of << "(X : unsigned) return Boolean is"; - newline(of, level); - of << "begin"; - newline(of, indent(level)); - of << "return X /= To_Unsigned(0, X'Length);"; - newline(of, level); + of << "(X : unsigned) return Boolean is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "return X /= To_Unsigned(0, X'Length);" << nl_string(level); break; case SF_SIGNED_TO_BOOLEAN: - of << "(X : signed) return Boolean is"; - newline(of, level); - of << "begin"; - newline(of, indent(level)); - of << "return X /= To_Signed(0, X'Length);"; - newline(of, level); + of << "(X : signed) return Boolean is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "return X /= To_Signed(0, X'Length);" << nl_string (level); break; case SF_BOOLEAN_TO_LOGIC: - of << "(B : Boolean) return std_logic is"; - newline(of, level); - of << "begin"; - newline(of, indent(level)); - of << "if B then"; - newline(of, indent(indent(level))); - of << "return '1'"; - newline(of, indent(level)); - of << "else"; - newline(of, indent(indent(level))); - of << "return '0'"; - newline(of, indent(level)); - of << "end if;"; - newline(of, level); + of << "(B : Boolean) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "if B then" << nl_string(indent(indent(level))) + << "return '1'" << nl_string(indent(level)) + << "else" << nl_string(indent(indent(level))) + << "return '0'" << nl_string(indent(level)) + << "end if;" << nl_string(level); break; default: assert(false); } - of << "end function;"; - newline(of, level); + of << "end function;" << nl_string(level); } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index e631319fc..fc09fe158 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -35,6 +35,13 @@ int indent(int level) return level + VHDL_INDENT; } +std::string nl_string(int level) +{ + std::ostringstream ss; + newline(ss, level); + return ss.str(); +} + /* * Emit a newline and indent to the correct level. */ diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index abccdfdb2..f4248500b 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -49,6 +49,7 @@ typedef std::list element_list_t; int indent(int level); void newline(std::ostream &of, int level); +std::string nl_string(int level); void blank_line(std::ostream &of, int level); #endif From 77508b9afa1100ed5766cbd1be2a78408adf0597 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 20 Jul 2008 15:10:00 +0100 Subject: [PATCH 55/57] Reduction OR operator --- tgt-vhdl/expr.cc | 6 +++++- tgt-vhdl/lpm.cc | 23 +++++++++++++---------- tgt-vhdl/support.cc | 15 ++++++++++++++- tgt-vhdl/support.hh | 1 + 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 6cc6b5827..4f420a3a0 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -19,6 +19,7 @@ */ #include "vhdl_target.h" +#include "support.hh" #include #include @@ -132,7 +133,10 @@ static vhdl_expr *translate_unary(ivl_expr_t e) case 'N': // NOR case '|': { - vhdl_fcall *f = new vhdl_fcall("Reduce_OR", vhdl_type::std_logic()); + require_support_function(SF_REDUCE_OR); + vhdl_fcall *f = + new vhdl_fcall(support_function::function_name(SF_REDUCE_OR), + vhdl_type::std_logic()); f->add_expr(operand); if ('N' == opcode) return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, f, vhdl_type::std_logic()); diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 0a29d255f..0a619c0df 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -170,15 +170,18 @@ static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) } static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, - const char *rfunc, bool invert) + support_function_t f, bool invert) { - vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic()); + require_support_function(f); + vhdl_fcall *fcall = new vhdl_fcall(support_function::function_name(f), + vhdl_type::std_logic()); vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == ref) return NULL; - - fcall->add_expr(ref); + + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + fcall->add_expr(ref->cast(&std_logic_vector)); if (invert) return new vhdl_unaryop_expr @@ -258,18 +261,18 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return part_select_pv_lpm_to_expr(scope, lpm); case IVL_LPM_UFUNC: return ufunc_lpm_to_expr(scope, lpm); - case IVL_LPM_RE_AND: + /*case IVL_LPM_RE_AND: return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false); case IVL_LPM_RE_NAND: - return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true); + return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true);*/ case IVL_LPM_RE_NOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", true); + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true); case IVL_LPM_RE_OR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", false); - case IVL_LPM_RE_XOR: + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false); + /*case IVL_LPM_RE_XOR: return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false); case IVL_LPM_RE_XNOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false); + return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false);*/ case IVL_LPM_SIGN_EXT: return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index bdbeab6f8..33c5bb4c8 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -22,6 +22,7 @@ #include "support.hh" #include +#include void require_support_function(support_function_t f) { @@ -39,6 +40,8 @@ const char *support_function::function_name(support_function_t type) return "Signed_To_Boolean"; case SF_BOOLEAN_TO_LOGIC: return "Boolean_To_Logic"; + case SF_REDUCE_OR: + return "Reduce_OR"; default: assert(false); } @@ -48,10 +51,10 @@ vhdl_type *support_function::function_type(support_function_t type) { switch (type) { case SF_UNSIGNED_TO_BOOLEAN: - return vhdl_type::boolean(); case SF_SIGNED_TO_BOOLEAN: return vhdl_type::boolean(); case SF_BOOLEAN_TO_LOGIC: + case SF_REDUCE_OR: return vhdl_type::std_logic(); default: assert(false); @@ -82,6 +85,16 @@ void support_function::emit(std::ostream &of, int level) const << "return '0'" << nl_string(indent(level)) << "end if;" << nl_string(level); break; + case SF_REDUCE_OR: + of << "(X : std_logic_vector) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "for I in X'Range loop" << nl_string(indent(indent(level))) + << "if X(I) = '1' then" << nl_string(indent(indent(indent(level)))) + << "return '1';" << nl_string(indent(indent(level))) + << "end if;" << nl_string(indent(level)) + << "end loop;" << nl_string(indent(level)) + << "return '0';" << nl_string(level); + break; default: assert(false); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index 67a9ea2e8..eff12b3f3 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -27,6 +27,7 @@ enum support_function_t { SF_UNSIGNED_TO_BOOLEAN, SF_SIGNED_TO_BOOLEAN, SF_BOOLEAN_TO_LOGIC, + SF_REDUCE_OR, }; class support_function : public vhdl_function { From d8351ec1b2fe25d701049d268b47b4b7fcbc3bd1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 20 Jul 2008 15:13:20 +0100 Subject: [PATCH 56/57] Fix reduction OR in procedural code --- tgt-vhdl/expr.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 4f420a3a0..8582c7eeb 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -137,7 +137,9 @@ static vhdl_expr *translate_unary(ivl_expr_t e) vhdl_fcall *f = new vhdl_fcall(support_function::function_name(SF_REDUCE_OR), vhdl_type::std_logic()); - f->add_expr(operand); + + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + f->add_expr(operand->cast(&std_logic_vector)); if ('N' == opcode) return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, f, vhdl_type::std_logic()); else From 3ca85491ee1b184d55abae4955eb2aff3202c8b5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 20 Jul 2008 16:41:57 +0100 Subject: [PATCH 57/57] Unary AND and XOR --- tgt-vhdl/expr.cc | 42 +++++++++++++++++++++++++++--------------- tgt-vhdl/lpm.cc | 12 ++++++------ tgt-vhdl/support.cc | 26 ++++++++++++++++++++++++++ tgt-vhdl/support.hh | 2 ++ 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 8582c7eeb..f64ac4ac6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -103,6 +103,23 @@ static vhdl_expr *translate_ulong(ivl_expr_t e) return new vhdl_const_int(ivl_expr_uvalue(e)); } +static vhdl_expr *translate_reduction(support_function_t f, bool neg, + vhdl_expr *operand) +{ + require_support_function(f); + vhdl_fcall *fcall = + new vhdl_fcall(support_function::function_name(f), + vhdl_type::std_logic()); + + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + fcall->add_expr(operand->cast(&std_logic_vector)); + if (neg) + return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall, + vhdl_type::std_logic()); + else + return fcall; +} + static vhdl_expr *translate_unary(ivl_expr_t e) { vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); @@ -111,13 +128,15 @@ static vhdl_expr *translate_unary(ivl_expr_t e) bool should_be_signed = ivl_expr_signed(e) != 0; - if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { + if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED + && should_be_signed) { //operand->print(); //std::cout << "^ should be signed but is not" << std::endl; operand = change_signedness(operand, true); } - else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED && !should_be_signed) { + else if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED + && !should_be_signed) { //operand->print(); //std::cout << "^ should be unsigned but is not" << std::endl; @@ -131,20 +150,13 @@ static vhdl_expr *translate_unary(ivl_expr_t e) return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); case 'N': // NOR + return translate_reduction(SF_REDUCE_OR, true, operand); case '|': - { - require_support_function(SF_REDUCE_OR); - vhdl_fcall *f = - new vhdl_fcall(support_function::function_name(SF_REDUCE_OR), - vhdl_type::std_logic()); - - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); - f->add_expr(operand->cast(&std_logic_vector)); - if ('N' == opcode) - return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, f, vhdl_type::std_logic()); - else - return f; - } + return translate_reduction(SF_REDUCE_OR, false, operand); + case 'A': // NAND + return translate_reduction(SF_REDUCE_AND, true, operand); + case '&': + return translate_reduction(SF_REDUCE_AND, false, operand); default: error("No translation for unary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 0a619c0df..3221b85c6 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -261,18 +261,18 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return part_select_pv_lpm_to_expr(scope, lpm); case IVL_LPM_UFUNC: return ufunc_lpm_to_expr(scope, lpm); - /*case IVL_LPM_RE_AND: - return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false); + case IVL_LPM_RE_AND: + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, false); case IVL_LPM_RE_NAND: - return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true);*/ + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_AND, true); case IVL_LPM_RE_NOR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, true); case IVL_LPM_RE_OR: return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_OR, false); - /*case IVL_LPM_RE_XOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false); + case IVL_LPM_RE_XOR: + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false); case IVL_LPM_RE_XNOR: - return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false);*/ + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, false); case IVL_LPM_SIGN_EXT: return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 33c5bb4c8..159618739 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -42,6 +42,10 @@ const char *support_function::function_name(support_function_t type) return "Boolean_To_Logic"; case SF_REDUCE_OR: return "Reduce_OR"; + case SF_REDUCE_AND: + return "Reduce_AND"; + case SF_REDUCE_XOR: + return "Reduce_XOR"; default: assert(false); } @@ -55,6 +59,8 @@ vhdl_type *support_function::function_type(support_function_t type) return vhdl_type::boolean(); case SF_BOOLEAN_TO_LOGIC: case SF_REDUCE_OR: + case SF_REDUCE_AND: + case SF_REDUCE_XOR: return vhdl_type::std_logic(); default: assert(false); @@ -95,6 +101,26 @@ void support_function::emit(std::ostream &of, int level) const << "end loop;" << nl_string(indent(level)) << "return '0';" << nl_string(level); break; + case SF_REDUCE_AND: + of << "(X : std_logic_vector) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "for I in X'Range loop" << nl_string(indent(indent(level))) + << "if X(I) = '0' then" << nl_string(indent(indent(indent(level)))) + << "return '0';" << nl_string(indent(indent(level))) + << "end if;" << nl_string(indent(level)) + << "end loop;" << nl_string(indent(level)) + << "return '1';" << nl_string(level); + break; + case SF_REDUCE_XOR: + of << "(X : std_logic_vector) return std_logic is" + << nl_string(indent(level)) + << "variable R : std_logic := '0';" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "for I in X'Range loop" << nl_string(indent(indent(level))) + << "R := X(I) xor R;" << nl_string(indent(level)) + << "end loop;" << nl_string(indent(level)) + << "return R;" << nl_string(level); + break; default: assert(false); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index eff12b3f3..a5e247c94 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -28,6 +28,8 @@ enum support_function_t { SF_SIGNED_TO_BOOLEAN, SF_BOOLEAN_TO_LOGIC, SF_REDUCE_OR, + SF_REDUCE_AND, + SF_REDUCE_XOR, }; class support_function : public vhdl_function {