diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 0eb413ff6..0827b5f5c 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 \ + stmt.o expr.o lpm.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc new file mode 100644 index 000000000..bc6f92207 --- /dev/null +++ b/tgt-vhdl/lpm.cc @@ -0,0 +1,58 @@ +/* + * VHDL code generation for LPM devices. + * + * 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 +#include + +static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) +{ + vhdl_expr *lhs = nexus_to_var_ref(arch, ivl_lpm_data(lpm, 0)); + if (NULL == lhs) + return 1; + + vhdl_expr *rhs = nexus_to_var_ref(arch, ivl_lpm_data(lpm, 1)); + if (NULL == rhs) + return 1; + + vhdl_var_ref *out = nexus_to_var_ref(arch, ivl_lpm_q(lpm, 0)); + if (NULL == out) + return 1; + + vhdl_type *result_type = new vhdl_type(*lhs->get_type()); + vhdl_binop_expr *expr = new vhdl_binop_expr(lhs, op, rhs, result_type); + + arch->add_stmt(new vhdl_cassign_stmt(out, expr)); + + return 0; +} + +int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +{ + switch (ivl_lpm_type(lpm)) { + case IVL_LPM_ADD: + return draw_binop_lpm(arch, lpm, VHDL_BINOP_ADD); + default: + error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); + return 1; + } +} + diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 77d65e44e..51ad1f2c3 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -29,7 +29,7 @@ * Given a nexus and an architecture, find the first signal * that is connected to the nexus, if there is one. */ -static vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) +vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) { int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { @@ -188,6 +188,16 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) } } +/* + * Generate VHDL for LPM instances in a module. + */ +static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope) +{ + int nlpms = ivl_scope_lpms(scope); + for (int i = 0; i < nlpms; i++) + draw_lpm(arch, ivl_scope_lpm(scope, i)); +} + /* * Create a VHDL entity for scopes of type IVL_SCT_MODULE. */ @@ -215,6 +225,9 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // Similarly, add all the primitive logic gates declare_logic(arch, scope); + + // ...and all the LPM devices + declare_lpm(arch, scope); // Build a comment to add to the entity/architecture std::ostringstream ss; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index bb29cc82d..3612d0e4f 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -15,12 +15,14 @@ int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); int draw_stmt(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt); +int draw_lpm(vhdl_arch *arch, 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_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus); void remember_signal(ivl_signal_t sig, const vhdl_entity *ent); void rename_signal(ivl_signal_t sig, const std::string &renamed);