From bfa2bfc8aed0a61aaeda36e30d67c6499abb13a1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 28 May 2008 17:17:39 +0100 Subject: [PATCH 001/377] Makefile and autoconf changes to build VHDL code generator --- autoconf.sh | 2 +- configure.in | 4 +- tgt-vhdl/Makefile.in | 91 +++++++++++++++++++++++++++++++++++++++ tgt-vhdl/configure.in | 30 +++++++++++++ tgt-vhdl/vhdl.cc | 50 +++++++++++++++++++++ tgt-vhdl/vhdl.conf | 4 ++ tgt-vhdl/vhdl_config.h.in | 49 +++++++++++++++++++++ tgt-vhdl/vhdl_element.cc | 56 ++++++++++++++++++++++++ tgt-vhdl/vhdl_element.hh | 49 +++++++++++++++++++++ tgt-vhdl/vhdl_target.h | 8 ++++ 10 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 tgt-vhdl/Makefile.in create mode 100644 tgt-vhdl/configure.in create mode 100644 tgt-vhdl/vhdl.cc create mode 100644 tgt-vhdl/vhdl.conf create mode 100644 tgt-vhdl/vhdl_config.h.in create mode 100644 tgt-vhdl/vhdl_element.cc create mode 100644 tgt-vhdl/vhdl_element.hh create mode 100644 tgt-vhdl/vhdl_target.h diff --git a/autoconf.sh b/autoconf.sh index 1ace2dc34..a92a6fa65 100644 --- a/autoconf.sh +++ b/autoconf.sh @@ -9,7 +9,7 @@ echo "Autoconf in root..." autoconf -f -for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub libveriuser cadpli +for dir in vpip vpi vvp tgt-vvp tgt-fpga tgt-stub tgt-vhdl libveriuser cadpli do echo "Autoconf in $dir..." ( cd ./$dir ; autoconf -f --include=.. ) diff --git a/configure.in b/configure.in index 46529fbe9..1a975b173 100644 --- a/configure.in +++ b/configure.in @@ -122,6 +122,6 @@ AX_C_UNDERSCORES_TRAILING AX_CPP_IDENT # XXX disable tgt-fpga for the moment -AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp libveriuser cadpli) +AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp tgt-vhdl libveriuser cadpli) -AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile) +AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vhdl/Makefile) diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in new file mode 100644 index 000000000..7f5ffe2fd --- /dev/null +++ b/tgt-vhdl/Makefile.in @@ -0,0 +1,91 @@ +# +# This source code is free software; you can redistribute it +# and/or modify it in source code form under the terms of the GNU +# Library 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 Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., +# 59 Temple Place - Suite 330 +# Boston, MA 02111-1307, USA +# +SHELL = /bin/sh + +VERSION = 0.0 + +prefix = @prefix@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +srcdir = @srcdir@ + +VPATH = $(srcdir) + +bindir = @bindir@ +libdir = @libdir@ +includedir = $(prefix)/include + +CXX = @CXX@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ +CXXFLAGS = -Wall @CXXFLAGS@ +LDFLAGS = @LDFLAGS@ + +all: dep vhdl.tgt vhdl.conf + +dep: + mkdir dep + +%.o: %.cc + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o + mv $*.d dep + +O = vhdl.o vhdl_element.o + +ifeq (@WIN32@,yes) + TGTLDFLAGS=-L.. -livl + TGTDEPLIBS=../libivl.a +else + TGTLDFLAGS= + TGTDEPLIBS= +endif + +vhdl.tgt: $O $(TGTDEPLIBS) + $(CXX) @shared@ -o $@ $O $(TGTLDFLAGS) + +Makefile: Makefile.in config.status + ./config.status + +clean: + rm -rf $(O) dep vhdl.tgt + +distclean: clean + rm -f Makefile config.status config.log config.cache vhdl_config.h + +check: all + +install: all installdirs $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf + +$(libdir)/ivl/vhdl.tgt: ./vhdl.tgt + $(INSTALL_PROGRAM) ./vhdl.tgt $(libdir)/ivl/vhdl.tgt + +$(libdir)/ivl/vhdl.conf: vhdl.conf + $(INSTALL_DATA) $< $(libdir)/ivl/vhdl.conf + +installdirs: ../mkinstalldirs + $(srcdir)/../mkinstalldirs $(libdir)/ivl + +uninstall: + rm -f $(libdir)/ivl/vhdl.tgt $(libdir)/ivl/vhdl.conf + + +-include $(patsubst %.o, dep/%.d, $O) diff --git a/tgt-vhdl/configure.in b/tgt-vhdl/configure.in new file mode 100644 index 000000000..3223b50e8 --- /dev/null +++ b/tgt-vhdl/configure.in @@ -0,0 +1,30 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(vhdl.cc) +AC_CONFIG_HEADER(vhdl_config.h) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_CXX + +AC_PROG_INSTALL + +AC_CANONICAL_HOST +# $host + +# Combined check for Microsoft-related bogosities; sets WIN32 if found +AX_WIN32 + +AC_CHECK_HEADERS(malloc.h stdint.h inttypes.h) + +# may modify CPPFLAGS and CFLAGS +AX_CPP_PRECOMP + +# Compiler option for position independent code, needed when making shared objects. +AX_C_PICFLAG + +# linker options when building a shared library +AX_LD_SHAREDLIB_OPTS + +AX_CPP_IDENT + +AC_OUTPUT(Makefile) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc new file mode 100644 index 000000000..bd9b0e052 --- /dev/null +++ b/tgt-vhdl/vhdl.cc @@ -0,0 +1,50 @@ +/* + * VHDL code generator for Icarus Verilog. + * + * 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 "vhdl_element.hh" + +#include +#include + +extern "C" int target_design(ivl_design_t des) +{ + ivl_scope_t *roots; + unsigned int nroots; + ivl_design_roots(des, &roots, &nroots); + + const char *ofname = ivl_design_flag(des, "-o"); + std::ofstream outfile(ofname); + + for (unsigned int i = 0; i < nroots; i++) { + ivl_scope_t scope = roots[i]; + const char *scope_name = ivl_scope_basename(scope); + + // Dummy output to test regression script + vhdl_entity test_ent(scope_name); + vhdl_arch test_arch(scope_name); + test_ent.emit(outfile); + test_arch.emit(outfile); + } + + outfile.close(); + + return 0; +} diff --git a/tgt-vhdl/vhdl.conf b/tgt-vhdl/vhdl.conf new file mode 100644 index 000000000..b96c4c05e --- /dev/null +++ b/tgt-vhdl/vhdl.conf @@ -0,0 +1,4 @@ +functor:cprop +functor:nodangle +-t:dll +flag:DLL=vhdl.tgt diff --git a/tgt-vhdl/vhdl_config.h.in b/tgt-vhdl/vhdl_config.h.in new file mode 100644 index 000000000..23193ebc2 --- /dev/null +++ b/tgt-vhdl/vhdl_config.h.in @@ -0,0 +1,49 @@ +/* vhdl_config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc new file mode 100644 index 000000000..4f703672f --- /dev/null +++ b/tgt-vhdl/vhdl_element.cc @@ -0,0 +1,56 @@ +/* + * VHDL abstract syntax elements. + * + * 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_element.hh" + + +//////// ENTITY //////// + +vhdl_entity::vhdl_entity(const char *name) + : name_(name) +{ + +} + +void vhdl_entity::emit(std::ofstream &of) +{ + of << "entity " << name_ << " is" << std::endl; + // ...ports... + of << "end entity; " << std::endl; +} + + +//////// ARCHITECTURE //////// + +vhdl_arch::vhdl_arch(const char *entity, const char *name) + : name_(name), entity_(entity) +{ + +} + +void vhdl_arch::emit(std::ofstream &of) +{ + of << "architecture " << name_ << " of " << entity_; + of << " is" << std::endl; + // ...declarations... + of << "begin" << std::endl; + // ...statements... + of << "end architecture;" << std::endl; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh new file mode 100644 index 000000000..0cf19768f --- /dev/null +++ b/tgt-vhdl/vhdl_element.hh @@ -0,0 +1,49 @@ +/* + * VHDL abstract syntax elements. + * + * 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_VHDL_ELEMENT_HH +#define INC_VHDL_ELEMENT_HH + +#include + +class vhdl_element { +public: + virtual void emit(std::ofstream &of) = 0; +}; + +class vhdl_entity : public vhdl_element { +public: + vhdl_entity(const char *name); + + void emit(std::ofstream &of); +private: + const char *name_; +}; + +class vhdl_arch : public vhdl_element { +public: + vhdl_arch(const char *entity, const char *name="Behavioural"); + + void emit(std::ofstream &of); +private: + const char *name_, *entity_; +}; + +#endif diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h new file mode 100644 index 000000000..e40591fca --- /dev/null +++ b/tgt-vhdl/vhdl_target.h @@ -0,0 +1,8 @@ +#ifndef INC_VHDL_TARGET_H +#define INC_VHDL_TARGET_H + +#include "vhdl_config.h" +#include "ivl_target.h" + +#endif /* #ifndef INC_VHDL_TARGET_H */ + From e38494a10c8d39579699ef6408c987847cf11895 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 29 May 2008 16:24:16 +0100 Subject: [PATCH 002/377] Pretty-print VHDL output --- tgt-vhdl/vhdl.cc | 26 +++++++- tgt-vhdl/vhdl_element.cc | 126 +++++++++++++++++++++++++++++++++++---- tgt-vhdl/vhdl_element.hh | 44 ++++++++++++-- tgt-vhdl/vhdl_target.h | 2 + 4 files changed, 183 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index bd9b0e052..91233122d 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -23,6 +23,26 @@ #include #include +#include +#include + +static int g_errors = 0; // Total number of errors encountered + +/* + * Called when an unrecoverable problem is encountered. + */ +void error(const char *fmt, ...) +{ + std::va_list args; + + va_start(args, fmt); + std::printf("VHDL conversion error: "); // Source/line number? + std::vprintf(fmt, args); + std::putchar('\n'); + va_end(args); + + g_errors++; +} extern "C" int target_design(ivl_design_t des) { @@ -40,11 +60,15 @@ extern "C" int target_design(ivl_design_t des) // Dummy output to test regression script vhdl_entity test_ent(scope_name); vhdl_arch test_arch(scope_name); + vhdl_process test_proc; + test_arch.set_comment("I am a comment"); + test_arch.add_stmt(&test_proc); + test_proc.set_comment("I am a process"); test_ent.emit(outfile); test_arch.emit(outfile); } outfile.close(); - return 0; + return g_errors; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 4f703672f..c92c182b2 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -20,6 +20,68 @@ #include "vhdl_element.hh" +#include + + +//////// HELPER FUNCTIONS //////// + +static const int VHDL_INDENT = 2; // Spaces to indent + +static int indent(int level) +{ + return level + VHDL_INDENT; +} + +/* + * Emit a newline and indent to the correct level. + */ +static void newline(std::ofstream &of, int level) +{ + of << std::endl; + while (level--) + of << ' '; +} + +static void blank_line(std::ofstream &of, int level) +{ + of << std::endl; + newline(of, level); +} + +template +void emit_children(std::ofstream &of, + const std::list &children, + int level) +{ + // Don't indent if there are no children + if (children.size() == 0) + newline(of, level); + else { + typename std::list::const_iterator it; + for (it = children.begin(); it != children.end(); ++it) { + newline(of, indent(level)); + (*it)->emit(of, indent(level)); + } + newline(of, level); + } +} + + +//////// ALL ELEMENTS //////// + +void vhdl_element::set_comment(std::string comment) +{ + comment_ = comment; +} + +void vhdl_element::emit_comment(std::ofstream &of, int level) const +{ + if (comment_.size() > 0) { + of << "-- " << comment_; + newline(of, level); + } +} + //////// ENTITY //////// @@ -29,11 +91,15 @@ vhdl_entity::vhdl_entity(const char *name) } -void vhdl_entity::emit(std::ofstream &of) +void vhdl_entity::emit(std::ofstream &of, int level) const { - of << "entity " << name_ << " is" << std::endl; + emit_comment(of, level); + of << "entity " << name_ << " is"; // ...ports... - of << "end entity; " << std::endl; + // newline(indent(level)); + newline(of, level); + of << "end entity; "; + blank_line(of, level); // Extra blank line after entities } @@ -45,12 +111,52 @@ vhdl_arch::vhdl_arch(const char *entity, const char *name) } -void vhdl_arch::emit(std::ofstream &of) +void vhdl_arch::add_stmt(vhdl_conc_stmt* stmt) { - of << "architecture " << name_ << " of " << entity_; - of << " is" << std::endl; - // ...declarations... - of << "begin" << std::endl; - // ...statements... - of << "end architecture;" << std::endl; + stmts_.push_back(stmt); +} + +void vhdl_arch::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + of << "architecture " << name_ << " of " << entity_; + of << " is"; + // ...declarations... + // newline(indent(level)); + newline(of, level); + of << "begin"; + emit_children(of, stmts_, level); + of << "end architecture;"; + blank_line(of, level); // Extra blank line after architectures; +} + + +//////// PROCESS //////// + +vhdl_process::vhdl_process(const char *name) + : name_(name) +{ + +} + +void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) +{ + stmts_.push_back(stmt); +} + +void vhdl_process::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + if (name_) + of << name_ << ": "; + of << "process is"; // TODO: sensitivity + newline(of, level); + // ...declarations... + of << "begin"; + newline(of, level); + // ...statements... + of << "wait;"; // Just to stop the simulation hanging + newline(of, level); + of << "end process;"; + newline(of, level); } diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 0cf19768f..b47fe843c 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -22,28 +22,64 @@ #define INC_VHDL_ELEMENT_HH #include +#include +#include + + +class vhdl_element; +typedef std::list element_list_t; class vhdl_element { -public: - virtual void emit(std::ofstream &of) = 0; +public: + virtual void emit(std::ofstream &of, int level=0) const = 0; + + void set_comment(std::string comment); +protected: + void emit_comment(std::ofstream &of, int level) const; +private: + std::string comment_; }; class vhdl_entity : public vhdl_element { public: vhdl_entity(const char *name); - void emit(std::ofstream &of); + void emit(std::ofstream &of, int level=0) const; private: const char *name_; }; +class vhdl_conc_stmt : public vhdl_element { +}; + +typedef std::list conc_stmt_list_t; + +class vhdl_seq_stmt : public vhdl_element { +}; + +typedef std::list seq_stmt_list_t; + +class vhdl_process : public vhdl_conc_stmt { +public: + vhdl_process(const char *name = NULL); + + void emit(std::ofstream &of, int level) const; + void add_stmt(vhdl_seq_stmt* stmt); +private: + seq_stmt_list_t stmts_; + const char *name_; +}; + class vhdl_arch : public vhdl_element { public: vhdl_arch(const char *entity, const char *name="Behavioural"); - void emit(std::ofstream &of); + void emit(std::ofstream &of, int level=0) const; + void add_stmt(vhdl_conc_stmt* stmt); private: + conc_stmt_list_t stmts_; const char *name_, *entity_; }; #endif + diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index e40591fca..dc14b8f50 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -4,5 +4,7 @@ #include "vhdl_config.h" #include "ivl_target.h" +void error(const char *fmt, ...); + #endif /* #ifndef INC_VHDL_TARGET_H */ From 05de2f56b428b25191e827c57d7e1778b6d35c9f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 30 May 2008 01:04:47 +0100 Subject: [PATCH 003/377] Dummy code for processes --- tgt-vhdl/vhdl.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 91233122d..23fa669d6 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -44,6 +44,16 @@ void error(const char *fmt, ...) g_errors++; } +int dummy(ivl_process_t net, void *cd) +{ + std::cout << "process" << std::endl; + + ivl_scope_t scope = ivl_process_scope(net); + std::cout << ivl_scope_name(scope) << std::endl; + + return 0; +} + extern "C" int target_design(ivl_design_t des) { ivl_scope_t *roots; @@ -67,6 +77,8 @@ extern "C" int target_design(ivl_design_t des) test_ent.emit(outfile); test_arch.emit(outfile); } + + ivl_design_process(des, dummy, 0); outfile.close(); From 8189c4ee4371c73d7fef3a82c5e2fa662a9212af Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 31 May 2008 15:28:25 +0100 Subject: [PATCH 004/377] Generate VHDL entities and architectures for all module scopes --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/vhdl.cc | 54 ++++++++++++++++++++++++---------------- tgt-vhdl/vhdl_element.cc | 5 ++-- tgt-vhdl/vhdl_element.hh | 35 ++++++++++++++++++-------- tgt-vhdl/vhdl_target.h | 8 ++++++ 5 files changed, 69 insertions(+), 35 deletions(-) diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 7f5ffe2fd..1acdd24d7 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -49,7 +49,7 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vhdl.o vhdl_element.o +O = vhdl.o vhdl_element.o scope.o process.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 23fa669d6..07e5f92fa 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -25,9 +25,13 @@ #include #include #include +#include +#include static int g_errors = 0; // Total number of errors encountered +static entity_list_t g_entities; // All entities to emit + /* * Called when an unrecoverable problem is encountered. */ @@ -44,14 +48,27 @@ void error(const char *fmt, ...) g_errors++; } -int dummy(ivl_process_t net, void *cd) +/* + * Find an entity given a type name. + */ +vhdl_entity *find_entity(const char *tname) { - std::cout << "process" << std::endl; + entity_list_t::const_iterator it; + for (it = g_entities.begin(); it != g_entities.end(); ++it) { + if (strcmp((*it)->get_name(), tname) == 0) + return *it; + } + return NULL; +} - ivl_scope_t scope = ivl_process_scope(net); - std::cout << ivl_scope_name(scope) << std::endl; - - return 0; +/* + * Add an entity/architecture pair to the list of entities + * to emit. + */ +void remember_entity(vhdl_entity* ent) +{ + assert(find_entity(ent->get_name()) == NULL); + g_entities.push_back(ent); } extern "C" int target_design(ivl_design_t des) @@ -60,25 +77,18 @@ extern "C" int target_design(ivl_design_t des) unsigned int nroots; ivl_design_roots(des, &roots, &nroots); + for (unsigned int i = 0; i < nroots; i++) + draw_scope(roots[i], NULL); + + ivl_design_process(des, draw_process, NULL); + + // Write the generated elements to the output file const char *ofname = ivl_design_flag(des, "-o"); std::ofstream outfile(ofname); - for (unsigned int i = 0; i < nroots; i++) { - ivl_scope_t scope = roots[i]; - const char *scope_name = ivl_scope_basename(scope); - - // Dummy output to test regression script - vhdl_entity test_ent(scope_name); - vhdl_arch test_arch(scope_name); - vhdl_process test_proc; - test_arch.set_comment("I am a comment"); - test_arch.add_stmt(&test_proc); - test_proc.set_comment("I am a process"); - test_ent.emit(outfile); - test_arch.emit(outfile); - } - - ivl_design_process(des, dummy, 0); + entity_list_t::const_iterator it; + for (it = g_entities.begin(); it != g_entities.end(); ++it) + (*it)->emit(outfile); outfile.close(); diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index c92c182b2..360f16ae0 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -85,8 +85,8 @@ void vhdl_element::emit_comment(std::ofstream &of, int level) const //////// ENTITY //////// -vhdl_entity::vhdl_entity(const char *name) - : name_(name) +vhdl_entity::vhdl_entity(const char *name, vhdl_arch *arch) + : name_(name), arch_(arch) { } @@ -100,6 +100,7 @@ void vhdl_entity::emit(std::ofstream &of, int level) const newline(of, level); of << "end entity; "; blank_line(of, level); // Extra blank line after entities + arch_->emit(of, level); } diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index b47fe843c..deeff2c68 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -30,7 +30,9 @@ class vhdl_element; typedef std::list element_list_t; class vhdl_element { -public: +public: + virtual ~vhdl_element() {} + virtual void emit(std::ofstream &of, int level=0) const = 0; void set_comment(std::string comment); @@ -40,21 +42,16 @@ private: std::string comment_; }; -class vhdl_entity : public vhdl_element { -public: - vhdl_entity(const char *name); - - void emit(std::ofstream &of, int level=0) const; -private: - const char *name_; -}; - class vhdl_conc_stmt : public vhdl_element { +public: + virtual ~vhdl_conc_stmt() {} }; typedef std::list conc_stmt_list_t; class vhdl_seq_stmt : public vhdl_element { +public: + virtual ~vhdl_seq_stmt() {} }; typedef std::list seq_stmt_list_t; @@ -62,6 +59,7 @@ typedef std::list seq_stmt_list_t; class vhdl_process : public vhdl_conc_stmt { public: vhdl_process(const char *name = NULL); + virtual ~vhdl_process() {} void emit(std::ofstream &of, int level) const; void add_stmt(vhdl_seq_stmt* stmt); @@ -73,6 +71,7 @@ private: class vhdl_arch : public vhdl_element { public: vhdl_arch(const char *entity, const char *name="Behavioural"); + virtual ~vhdl_arch() {} void emit(std::ofstream &of, int level=0) const; void add_stmt(vhdl_conc_stmt* stmt); @@ -81,5 +80,21 @@ private: const char *name_, *entity_; }; +class vhdl_entity : public vhdl_element { +public: + vhdl_entity(const char *name, vhdl_arch *arch); + virtual ~vhdl_entity() {} + + void emit(std::ofstream &of, int level=0) const; + vhdl_arch *get_arch() const { return arch_; } + const char *get_name() const { return name_; } +private: + const char *name_; + vhdl_arch *arch_; // Entity may only have a single architecture +}; + +typedef std::list entity_list_t; + + #endif diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index dc14b8f50..5eabd8770 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -4,7 +4,15 @@ #include "vhdl_config.h" #include "ivl_target.h" +#include "vhdl_element.hh" + void error(const char *fmt, ...); +int draw_scope(ivl_scope_t scope, void *_parent); +int draw_process(ivl_process_t net, void *cd); + +void remember_entity(vhdl_entity *ent); +vhdl_entity *find_entity(const char *tname); + #endif /* #ifndef INC_VHDL_TARGET_H */ From 7c9d154461df2b5c835273e3707715b792052ab9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 31 May 2008 15:31:48 +0100 Subject: [PATCH 005/377] Forgot source files for entity generation --- tgt-vhdl/process.cc | 34 ++++++++++++++ tgt-vhdl/scope.cc | 108 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 tgt-vhdl/process.cc create mode 100644 tgt-vhdl/scope.cc diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc new file mode 100644 index 000000000..30869c458 --- /dev/null +++ b/tgt-vhdl/process.cc @@ -0,0 +1,34 @@ +/* + * VHDL code generation for processes. + * + * 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 "vhdl_element.hh" + +#include + +int draw_process(ivl_process_t proc, void *cd) +{ + ivl_scope_t scope = ivl_process_scope(proc); + const char *scope_name = ivl_scope_name(scope); + + std::cout << "process: scope " << scope_name << std::endl; + + return 0; +} diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc new file mode 100644 index 000000000..e761f58a8 --- /dev/null +++ b/tgt-vhdl/scope.cc @@ -0,0 +1,108 @@ +/* + * VHDL code generation for scopes. + * + * 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 "vhdl_element.hh" + +#include +#include +#include + +/* + * Create a VHDL entity for scopes of type IVL_SCT_MODULE. + */ +static vhdl_entity *create_entity_for(ivl_scope_t scope) +{ + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); + + // The type name will become the entity name + const char *tname = ivl_scope_tname(scope); + + // Verilog does not have the entity/architecture distinction + // so we always create a pair and associate the architecture + // with the entity for convenience (this also means that we + // retain a 1-to-1 mapping of scope to VHDL element) + vhdl_arch *arch = new vhdl_arch(tname); + vhdl_entity *ent = new vhdl_entity(tname, arch); + + // Build a comment to add to the entity/architecture + std::ostringstream ss; + ss << "Generated from " << ivl_scope_name(scope); + ss << " (" << ivl_scope_def_file(scope) << ":"; + ss << ivl_scope_def_lineno(scope) << ")"; + + arch->set_comment(ss.str()); + ent->set_comment(ss.str()); + + remember_entity(ent); + return ent; +} + +/* + * Instantiate an entity in the hierarchy, and possibly create + * that entity if it hasn't been encountered yet. + */ +static int draw_module(ivl_scope_t scope, ivl_scope_t parent) +{ + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); + + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + if (NULL == ent) + ent = create_entity_for(scope); + assert(ent); + + if (parent != NULL) { + std::cout << "parent " << ivl_scope_name(parent) << std::endl; + } + + return 0; +} + +int draw_scope(ivl_scope_t scope, void *_parent) +{ + ivl_scope_t parent = static_cast(_parent); + + const char *name = ivl_scope_name(scope); + const char *basename = ivl_scope_basename(scope); + + std::cout << "scope " << name << " (" << basename << ")" << std::endl; + + ivl_scope_type_t type = ivl_scope_type(scope); + int rc = 0; + switch (type) { + case IVL_SCT_MODULE: + rc = draw_module(scope, parent); + break; + default: + error("No VHDL conversion for %s (at %s)", + ivl_scope_tname(scope), + ivl_scope_name(scope)); + break; + } + if (rc != 0) + return rc; + + rc = ivl_scope_children(scope, draw_scope, scope); + if (rc != 0) + return rc; + + return 0; +} + From 5cbd5878339a5e1c8ae21d33481757854524e227 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 31 May 2008 16:08:57 +0100 Subject: [PATCH 006/377] Clean up generated objects --- tgt-vhdl/vhdl.cc | 7 ++++++- tgt-vhdl/vhdl_element.cc | 21 +++++++++++++++++++++ tgt-vhdl/vhdl_element.hh | 6 +++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 07e5f92fa..4e7e0e549 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -91,6 +91,11 @@ extern "C" int target_design(ivl_design_t des) (*it)->emit(outfile); outfile.close(); - + + // Clean up + for (it = g_entities.begin(); it != g_entities.end(); ++it) + delete (*it); + g_entities.clear(); + return g_errors; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 360f16ae0..5ee2ccb57 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -91,6 +91,11 @@ vhdl_entity::vhdl_entity(const char *name, vhdl_arch *arch) } +vhdl_entity::~vhdl_entity() +{ + delete arch_; +} + void vhdl_entity::emit(std::ofstream &of, int level) const { emit_comment(of, level); @@ -112,6 +117,14 @@ vhdl_arch::vhdl_arch(const char *entity, const char *name) } +vhdl_arch::~vhdl_arch() +{ + conc_stmt_list_t::iterator it; + for (it = stmts_.begin(); it != stmts_.end(); ++it) + delete (*it); + stmts_.clear(); +} + void vhdl_arch::add_stmt(vhdl_conc_stmt* stmt) { stmts_.push_back(stmt); @@ -140,6 +153,14 @@ vhdl_process::vhdl_process(const char *name) } +vhdl_process::~vhdl_process() +{ + seq_stmt_list_t::iterator it; + for (it = stmts_.begin(); it != stmts_.end(); ++it) + delete (*it); + stmts_.clear(); +} + void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) { stmts_.push_back(stmt); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index deeff2c68..ce4f18d9d 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -59,7 +59,7 @@ typedef std::list seq_stmt_list_t; class vhdl_process : public vhdl_conc_stmt { public: vhdl_process(const char *name = NULL); - virtual ~vhdl_process() {} + virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; void add_stmt(vhdl_seq_stmt* stmt); @@ -71,7 +71,7 @@ private: class vhdl_arch : public vhdl_element { public: vhdl_arch(const char *entity, const char *name="Behavioural"); - virtual ~vhdl_arch() {} + virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; void add_stmt(vhdl_conc_stmt* stmt); @@ -83,7 +83,7 @@ private: class vhdl_entity : public vhdl_element { public: vhdl_entity(const char *name, vhdl_arch *arch); - virtual ~vhdl_entity() {} + virtual ~vhdl_entity(); void emit(std::ofstream &of, int level=0) const; vhdl_arch *get_arch() const { return arch_; } From fef0fd82ffa7c3788a73aa23fbf11dbcd604b84e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 2 Jun 2008 00:12:47 +0100 Subject: [PATCH 007/377] Comments --- tgt-vhdl/vhdl_element.hh | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index ce4f18d9d..a7ace1012 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -25,10 +25,9 @@ #include #include - -class vhdl_element; -typedef std::list element_list_t; - +/* + * Any VHDL syntax element. Each element can also contain a comment. + */ class vhdl_element { public: virtual ~vhdl_element() {} @@ -42,6 +41,13 @@ private: std::string comment_; }; +typedef std::list element_list_t; + + +/* + * A concurrent statement appears in architecture bodies but not + * processes. + */ class vhdl_conc_stmt : public vhdl_element { public: virtual ~vhdl_conc_stmt() {} @@ -49,6 +55,10 @@ public: typedef std::list conc_stmt_list_t; + +/* + * Any sequential statement in a process. + */ class vhdl_seq_stmt : public vhdl_element { public: virtual ~vhdl_seq_stmt() {} @@ -56,6 +66,10 @@ public: typedef std::list seq_stmt_list_t; + +/* + * Container for sequential statements. + */ class vhdl_process : public vhdl_conc_stmt { public: vhdl_process(const char *name = NULL); @@ -68,6 +82,10 @@ private: const char *name_; }; + +/* + * An architecture which implements an entity. + */ class vhdl_arch : public vhdl_element { public: vhdl_arch(const char *entity, const char *name="Behavioural"); @@ -80,6 +98,11 @@ private: const char *name_, *entity_; }; +/* + * An entity defines the ports, parameters, etc. of a module. Each + * entity is associated with a single architecture (although + * technically this need not be the case). + */ class vhdl_entity : public vhdl_element { public: vhdl_entity(const char *name, vhdl_arch *arch); From 9292a087e880430edef282d01f8e327726a350f6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 2 Jun 2008 16:17:01 +0100 Subject: [PATCH 008/377] Generate VHDL processes from Verilog processes --- tgt-vhdl/process.cc | 50 +++++++++++++++++++++++++++++++++++++--- tgt-vhdl/scope.cc | 13 +++++++---- tgt-vhdl/vhdl.cc | 4 ++-- tgt-vhdl/vhdl_element.cc | 7 +++--- tgt-vhdl/vhdl_element.hh | 19 +++++++++------ tgt-vhdl/vhdl_target.h | 4 +++- 6 files changed, 76 insertions(+), 21 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 30869c458..ce4c6c205 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -22,13 +22,57 @@ #include "vhdl_element.hh" #include +#include +#include + +/* + * Convert a Verilog process to VHDL and add it to the architecture + * of the given entity. + */ +static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) +{ + vhdl_process *vhdl_proc = new vhdl_process(); + + // TODO: Add statements + + // Add a comment indicating where it came from + ivl_scope_t scope = ivl_process_scope(proc); + const char *type = ivl_process_type(proc) == IVL_PR_INITIAL + ? "initial" : "always"; + std::ostringstream ss; + ss << "Generated from " << type << " process in scope "; + ss << ivl_scope_name(scope); + vhdl_proc->set_comment(ss.str()); + + // Store it in the entity's architecture + ent->get_arch()->add_stmt(vhdl_proc); + + return 0; +} int draw_process(ivl_process_t proc, void *cd) { ivl_scope_t scope = ivl_process_scope(proc); const char *scope_name = ivl_scope_name(scope); - std::cout << "process: scope " << scope_name << std::endl; - - return 0; + // A process should occur in a module scope, therefore it + // should have already been assigned a VHDL entity + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + assert(ent != NULL); + + // If the scope this process belongs to is the same as the + // VHDL entity was generated from, then create a VHDL process + // from this Verilog process. This ensures that each process + // is translated at most once, no matter how many times it + // appears in the hierarchy. + if (ent->get_derived_from() == scope_name) { + std::cout << "New process encountered in " << scope_name << std::endl; + return generate_vhdl_process(ent, proc); + } + else { + std::cout << "Ignoring already seen process in "; + std::cout << scope_name << std::endl; + return 0; + } } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e761f58a8..641228bb3 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -35,12 +35,16 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // The type name will become the entity name const char *tname = ivl_scope_tname(scope); + // Remember the scope name this entity was derived from so + // the correct processes can be added later + const char *derived_from = ivl_scope_name(scope); + // Verilog does not have the entity/architecture distinction // so we always create a pair and associate the architecture // with the entity for convenience (this also means that we // retain a 1-to-1 mapping of scope to VHDL element) vhdl_arch *arch = new vhdl_arch(tname); - vhdl_entity *ent = new vhdl_entity(tname, arch); + vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch); // Build a comment to add to the entity/architecture std::ostringstream ss; @@ -51,6 +55,9 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) arch->set_comment(ss.str()); ent->set_comment(ss.str()); + std::cout << "Generated entity " << tname; + std::cout << " from " << ivl_scope_name(scope) << std::endl; + remember_entity(ent); return ent; } @@ -67,10 +74,6 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) if (NULL == ent) ent = create_entity_for(scope); assert(ent); - - if (parent != NULL) { - std::cout << "parent " << ivl_scope_name(parent) << std::endl; - } return 0; } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 4e7e0e549..3eb64f98a 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -51,11 +51,11 @@ void error(const char *fmt, ...) /* * Find an entity given a type name. */ -vhdl_entity *find_entity(const char *tname) +vhdl_entity *find_entity(const std::string &tname) { entity_list_t::const_iterator it; for (it = g_entities.begin(); it != g_entities.end(); ++it) { - if (strcmp((*it)->get_name(), tname) == 0) + if ((*it)->get_name() == tname) return *it; } return NULL; diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 5ee2ccb57..4d36a5f16 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -85,8 +85,9 @@ void vhdl_element::emit_comment(std::ofstream &of, int level) const //////// ENTITY //////// -vhdl_entity::vhdl_entity(const char *name, vhdl_arch *arch) - : name_(name), arch_(arch) +vhdl_entity::vhdl_entity(const char *name, const char *derived_from, + vhdl_arch *arch) + : name_(name), arch_(arch), derived_from_(derived_from) { } @@ -169,7 +170,7 @@ void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) void vhdl_process::emit(std::ofstream &of, int level) const { emit_comment(of, level); - if (name_) + if (name_.size() > 0) of << name_ << ": "; of << "process is"; // TODO: sensitivity newline(of, level); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index a7ace1012..e60127025 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -72,19 +72,20 @@ typedef std::list seq_stmt_list_t; */ class vhdl_process : public vhdl_conc_stmt { public: - vhdl_process(const char *name = NULL); + vhdl_process(const char *name = ""); virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; void add_stmt(vhdl_seq_stmt* stmt); private: seq_stmt_list_t stmts_; - const char *name_; + std::string name_; }; /* - * An architecture which implements an entity. + * An architecture which implements an entity. Entities are `derived' + * from instantiations of Verilog module scopes in the hierarchy. */ class vhdl_arch : public vhdl_element { public: @@ -95,7 +96,7 @@ public: void add_stmt(vhdl_conc_stmt* stmt); private: conc_stmt_list_t stmts_; - const char *name_, *entity_; + std::string name_, entity_; }; /* @@ -105,15 +106,19 @@ private: */ class vhdl_entity : public vhdl_element { public: - vhdl_entity(const char *name, vhdl_arch *arch); + vhdl_entity(const char *name, const char *derived_from, + vhdl_arch *arch); virtual ~vhdl_entity(); void emit(std::ofstream &of, int level=0) const; vhdl_arch *get_arch() const { return arch_; } - const char *get_name() const { return name_; } + const std::string &get_name() const { return name_; } + + const std::string &get_derived_from() const { return derived_from_; } private: - const char *name_; + std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture + std::string derived_from_; }; typedef std::list entity_list_t; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 5eabd8770..ec44ee95f 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -6,13 +6,15 @@ #include "vhdl_element.hh" +#include + void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); void remember_entity(vhdl_entity *ent); -vhdl_entity *find_entity(const char *tname); +vhdl_entity *find_entity(const std::string &tname); #endif /* #ifndef INC_VHDL_TARGET_H */ From 041925c12397b7cc6bd721aa6774a968efee53f8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 2 Jun 2008 17:45:58 +0100 Subject: [PATCH 009/377] Component instantiation to replicate Verilog hierarchy --- tgt-vhdl/scope.cc | 23 ++++++++++ tgt-vhdl/vhdl_element.cc | 90 +++++++++++++++++++++++++++++++++++++--- tgt-vhdl/vhdl_element.hh | 69 +++++++++++++++++++++++++++--- 3 files changed, 171 insertions(+), 11 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 641228bb3..be5a92720 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -70,11 +70,34 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) { assert(ivl_scope_type(scope) == IVL_SCT_MODULE); + // Maybe we need to create this entity first? vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); if (NULL == ent) ent = create_entity_for(scope); assert(ent); + + // Is this module instantiated inside another? + if (parent != NULL) { + vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); + assert(parent_ent != NULL); + vhdl_arch *parent_arch = parent_ent->get_arch(); + assert(parent_arch != NULL); + // Create a forward declaration for it + if (!parent_arch->have_declared_component(ent->get_name())) { + vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); + parent_arch->add_decl(comp_decl); + } + + // And an instantiation statement + const char *inst_name = ivl_scope_basename(scope); + vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name, ent->get_name().c_str()); + std::ostringstream ss; + ss << "Scope name " << ivl_scope_name(scope); + inst->set_comment(ss.str()); + parent_arch->add_stmt(inst); + } + return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 4d36a5f16..6578cb1c0 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -21,6 +21,9 @@ #include "vhdl_element.hh" #include +#include +#include +#include //////// HELPER FUNCTIONS //////// @@ -120,31 +123,58 @@ vhdl_arch::vhdl_arch(const char *entity, const char *name) vhdl_arch::~vhdl_arch() { - conc_stmt_list_t::iterator it; - for (it = stmts_.begin(); it != stmts_.end(); ++it) + for (conc_stmt_list_t::iterator it = stmts_.begin(); + it != stmts_.end(); + ++it) delete (*it); stmts_.clear(); + + for (decl_list_t::iterator it = decls_.begin(); + it != decls_.end(); + ++it) + delete (*it); + decls_.clear(); } -void vhdl_arch::add_stmt(vhdl_conc_stmt* stmt) +void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) { stmts_.push_back(stmt); } +void vhdl_arch::add_decl(vhdl_decl *decl) +{ + decls_.push_back(decl); +} + void vhdl_arch::emit(std::ofstream &of, int level) const { emit_comment(of, level); of << "architecture " << name_ << " of " << entity_; of << " is"; - // ...declarations... - // newline(indent(level)); - newline(of, level); + emit_children(of, decls_, level); of << "begin"; emit_children(of, stmts_, level); of << "end architecture;"; blank_line(of, level); // Extra blank line after architectures; } +/* + * True if component `name' has already been declared in this + * architecture. This is a bit of hack, since it uses typeid + * to distinguish between components and other declarations. + */ +bool vhdl_arch::have_declared_component(const std::string &name) const +{ + std::string comp_typename(typeid(vhdl_component_decl).name()); + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if (comp_typename == typeid(**it).name() + && (*it)->get_name() == name) + return true; + } + return false; +} + //////// PROCESS //////// @@ -183,3 +213,51 @@ void vhdl_process::emit(std::ofstream &of, int level) const of << "end process;"; newline(of, level); } + + +//////// COMPONENT INSTANTIATION //////// + +vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) + : comp_name_(comp_name), inst_name_(inst_name) +{ + +} + +void vhdl_comp_inst::emit(std::ofstream &of, int level) const +{ + // If there are no ports or generics we don't need to mention them... + emit_comment(of, level); + of << inst_name_ << ": " << comp_name_ << ";"; + newline(of, level); +} + + +//////// COMPONENT DECLARATIONS //////// + +vhdl_component_decl::vhdl_component_decl(const char *name) + : vhdl_decl(name) +{ + +} + +/* + * Create a component declaration for the given entity. + */ +vhdl_component_decl *vhdl_component_decl::component_decl_for(const vhdl_entity *ent) +{ + assert(ent != NULL); + + vhdl_component_decl *decl = new vhdl_component_decl + (ent->get_name().c_str()); + + return decl; +} + +void vhdl_component_decl::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + of << "component " << name_ << " is"; + // ...ports... + newline(of, level); + of << "end component;"; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index e60127025..b178ff325 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -25,6 +25,8 @@ #include #include +class vhdl_entity; + /* * Any VHDL syntax element. Each element can also contain a comment. */ @@ -66,6 +68,60 @@ public: typedef std::list seq_stmt_list_t; +/* + * A declaration of some sort (variable, component, etc.). + * Declarations have names, which is the identifier of the variable, + * constant, etc. not the type. + */ +class vhdl_decl : public vhdl_element { +public: + vhdl_decl(const char *name) : name_(name) {} + virtual ~vhdl_decl() {}; + + const std::string &get_name() const { return name_; } +protected: + std::string name_; +}; + +typedef std::list decl_list_t; + + +/* + * A forward declaration of a component. At the moment it is assumed + * that components declarations will only ever be for entities + * generated by this code generator. This is enforced by making the + * constructor private (use component_decl_for instead). + */ +class vhdl_component_decl : public vhdl_decl { +public: + virtual ~vhdl_component_decl() {}; + + static vhdl_component_decl *component_decl_for(const vhdl_entity *ent); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_component_decl(const char *name); + + // TODO: Ports, etc. +}; + + +/* + * Instantiation of component. This is really only a placeholder + * at the moment until the port mappings are worked out. + */ +class vhdl_comp_inst : public vhdl_conc_stmt { +public: + vhdl_comp_inst(const char *inst_name, const char *comp_name); + virtual ~vhdl_comp_inst() {} + + void emit(std::ofstream &of, int level) const; +private: + std::string comp_name_, inst_name_; + + // TODO: Port mappings, etc. +}; + /* * Container for sequential statements. @@ -76,7 +132,7 @@ public: virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; - void add_stmt(vhdl_seq_stmt* stmt); + void add_stmt(vhdl_seq_stmt *stmt); private: seq_stmt_list_t stmts_; std::string name_; @@ -84,8 +140,7 @@ private: /* - * An architecture which implements an entity. Entities are `derived' - * from instantiations of Verilog module scopes in the hierarchy. + * An architecture which implements an entity. */ class vhdl_arch : public vhdl_element { public: @@ -93,16 +148,20 @@ public: virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; - void add_stmt(vhdl_conc_stmt* stmt); + bool have_declared_component(const std::string &name) const; + void add_decl(vhdl_decl *decl); + void add_stmt(vhdl_conc_stmt *stmt); private: conc_stmt_list_t stmts_; + decl_list_t decls_; std::string name_, entity_; }; /* * An entity defines the ports, parameters, etc. of a module. Each * entity is associated with a single architecture (although - * technically this need not be the case). + * technically this need not be the case). Entities are `derived' + * from instantiations of Verilog module scopes in the hierarchy. */ class vhdl_entity : public vhdl_element { public: From 17ae0a6a0943131923a136ecbb20d5cc005ab5c8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 2 Jun 2008 18:05:39 +0100 Subject: [PATCH 010/377] Fix a bug where the same instantiation appeared multiple times --- tgt-vhdl/scope.cc | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index be5a92720..14f764cf9 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -80,22 +80,33 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) if (parent != NULL) { vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); assert(parent_ent != NULL); - vhdl_arch *parent_arch = parent_ent->get_arch(); - assert(parent_arch != NULL); - - // Create a forward declaration for it - if (!parent_arch->have_declared_component(ent->get_name())) { - vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); - parent_arch->add_decl(comp_decl); - } - // And an instantiation statement - const char *inst_name = ivl_scope_basename(scope); - vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name, ent->get_name().c_str()); - std::ostringstream ss; - ss << "Scope name " << ivl_scope_name(scope); - inst->set_comment(ss.str()); - parent_arch->add_stmt(inst); + + // Make sure we only collect instantiations from *one* + // example of this module in the hieararchy + if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { + + vhdl_arch *parent_arch = parent_ent->get_arch(); + assert(parent_arch != NULL); + + // Create a forward declaration for it + if (!parent_arch->have_declared_component(ent->get_name())) { + vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); + parent_arch->add_decl(comp_decl); + } + + // And an instantiation statement + const char *inst_name = ivl_scope_basename(scope); + vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name, ent->get_name().c_str()); + std::ostringstream ss; + ss << "Generated from " << ivl_scope_name(scope); + inst->set_comment(ss.str()); + parent_arch->add_stmt(inst); + } + else { + std::cout << "Ignoring instantiation " << ivl_scope_name(scope); + std::cout << " (already accounted for)" << std::endl; + } } return 0; From ab6ae621cba1a073f3fbd7a52b072152162a8527 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 2 Jun 2008 20:24:25 +0100 Subject: [PATCH 011/377] Remove useless comments in output --- tgt-vhdl/process.cc | 4 ++-- tgt-vhdl/scope.cc | 10 +++------- tgt-vhdl/vhdl_element.cc | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index ce4c6c205..4542469f2 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) const char *type = ivl_process_type(proc) == IVL_PR_INITIAL ? "initial" : "always"; std::ostringstream ss; - ss << "Generated from " << type << " process in scope "; - ss << ivl_scope_name(scope); + ss << "Generated from " << type << " process in "; + ss << ivl_scope_tname(scope); vhdl_proc->set_comment(ss.str()); // Store it in the entity's architecture diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 14f764cf9..e0e1a475c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -48,9 +48,7 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // Build a comment to add to the entity/architecture std::ostringstream ss; - ss << "Generated from " << ivl_scope_name(scope); - ss << " (" << ivl_scope_def_file(scope) << ":"; - ss << ivl_scope_def_lineno(scope) << ")"; + ss << "Generated from Verilog module " << ivl_scope_tname(scope); arch->set_comment(ss.str()); ent->set_comment(ss.str()); @@ -97,10 +95,8 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) // And an instantiation statement const char *inst_name = ivl_scope_basename(scope); - vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name, ent->get_name().c_str()); - std::ostringstream ss; - ss << "Generated from " << ivl_scope_name(scope); - inst->set_comment(ss.str()); + vhdl_comp_inst *inst = + new vhdl_comp_inst(inst_name, ent->get_name().c_str()); parent_arch->add_stmt(inst); } else { diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 6578cb1c0..2cce979c6 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -208,7 +208,7 @@ void vhdl_process::emit(std::ofstream &of, int level) const of << "begin"; newline(of, level); // ...statements... - of << "wait;"; // Just to stop the simulation hanging + of << " wait;"; // Just to stop the simulation hanging newline(of, level); of << "end process;"; newline(of, level); From a09b4e3b922e9dde43f9449f3e3c0d0d967f7572 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 17:39:24 +0100 Subject: [PATCH 012/377] Initial process have wait at the end (do it properly this time rather than a hack :-) --- tgt-vhdl/process.cc | 10 ++++++++-- tgt-vhdl/vhdl_element.cc | 14 ++++++++++---- tgt-vhdl/vhdl_element.hh | 11 +++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 4542469f2..91e109214 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -33,8 +33,14 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { vhdl_process *vhdl_proc = new vhdl_process(); - // TODO: Add statements - + // Initial processes are translated to VHDL processes with + // no sensitivity list and and indefinite wait statement at + // the end + if (ivl_process_type(proc) == IVL_PR_INITIAL) { + vhdl_wait_stmt *wait = new vhdl_wait_stmt(); + vhdl_proc->add_stmt(wait); + } + // Add a comment indicating where it came from ivl_scope_t scope = ivl_process_scope(proc); const char *type = ivl_process_type(proc) == IVL_PR_INITIAL diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 2cce979c6..483064acb 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -206,10 +206,7 @@ void vhdl_process::emit(std::ofstream &of, int level) const newline(of, level); // ...declarations... of << "begin"; - newline(of, level); - // ...statements... - of << " wait;"; // Just to stop the simulation hanging - newline(of, level); + emit_children(of, stmts_, level); of << "end process;"; newline(of, level); } @@ -261,3 +258,12 @@ void vhdl_component_decl::emit(std::ofstream &of, int level) const newline(of, level); of << "end component;"; } + + +//////// WAIT STATEMENT //////// + +void vhdl_wait_stmt::emit(std::ofstream &of, int level) const +{ + // TODO: There are lots of different types of `wait' + of << "wait;"; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index b178ff325..a03e5785f 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -68,6 +68,17 @@ public: typedef std::list seq_stmt_list_t; + +/* + * Delay simulation indefinitely, until an event, or for a + * specified time. + */ +class vhdl_wait_stmt : public vhdl_seq_stmt { +public: + void emit(std::ofstream &of, int level) const; +}; + + /* * A declaration of some sort (variable, component, etc.). * Declarations have names, which is the identifier of the variable, From f9e128946318ce4bff9e042e634563716bc8fcdd Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 17:43:54 +0100 Subject: [PATCH 013/377] Tidy up vhdl_element.cc --- tgt-vhdl/vhdl_element.cc | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 483064acb..da7f961c4 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -26,8 +26,6 @@ #include -//////// HELPER FUNCTIONS //////// - static const int VHDL_INDENT = 2; // Spaces to indent static int indent(int level) @@ -69,9 +67,6 @@ void emit_children(std::ofstream &of, } } - -//////// ALL ELEMENTS //////// - void vhdl_element::set_comment(std::string comment) { comment_ = comment; @@ -85,9 +80,6 @@ void vhdl_element::emit_comment(std::ofstream &of, int level) const } } - -//////// ENTITY //////// - vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) : name_(name), arch_(arch), derived_from_(derived_from) @@ -112,9 +104,6 @@ void vhdl_entity::emit(std::ofstream &of, int level) const arch_->emit(of, level); } - -//////// ARCHITECTURE //////// - vhdl_arch::vhdl_arch(const char *entity, const char *name) : name_(name), entity_(entity) { @@ -175,9 +164,6 @@ bool vhdl_arch::have_declared_component(const std::string &name) const return false; } - -//////// PROCESS //////// - vhdl_process::vhdl_process(const char *name) : name_(name) { @@ -211,9 +197,6 @@ void vhdl_process::emit(std::ofstream &of, int level) const newline(of, level); } - -//////// COMPONENT INSTANTIATION //////// - vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) : comp_name_(comp_name), inst_name_(inst_name) { @@ -228,9 +211,6 @@ void vhdl_comp_inst::emit(std::ofstream &of, int level) const newline(of, level); } - -//////// COMPONENT DECLARATIONS //////// - vhdl_component_decl::vhdl_component_decl(const char *name) : vhdl_decl(name) { @@ -259,9 +239,6 @@ void vhdl_component_decl::emit(std::ofstream &of, int level) const of << "end component;"; } - -//////// WAIT STATEMENT //////// - void vhdl_wait_stmt::emit(std::ofstream &of, int level) const { // TODO: There are lots of different types of `wait' From 4211e651d0261c9b23bd5ce217bc8d63962eb1ad Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 18:26:36 +0100 Subject: [PATCH 014/377] Stub file for processing statements --- tgt-vhdl/process.cc | 5 +++++ tgt-vhdl/stmt.cc | 32 ++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_target.h | 1 + 3 files changed, 38 insertions(+) create mode 100644 tgt-vhdl/stmt.cc diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 91e109214..948b15259 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -33,6 +33,11 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { vhdl_process *vhdl_proc = new vhdl_process(); + ivl_statement_t stmt = ivl_process_stmt(proc); + int rc = draw_stmt(vhdl_proc, stmt); + if (rc != 0) + return rc; + // 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 new file mode 100644 index 000000000..33e07da42 --- /dev/null +++ b/tgt-vhdl/stmt.cc @@ -0,0 +1,32 @@ +/* + * VHDL code generation for statements. + * + * 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 + +/* + * Generate VHDL statements for the given Verilog statement and + * add them to the given VHDL process. + */ +int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) +{ + return 0; +} diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index ec44ee95f..3612f426a 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -12,6 +12,7 @@ void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); +int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); From 82aca1b02eca47095205c88410d43abe1a976b61 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 18:44:17 +0100 Subject: [PATCH 015/377] Stub code for handling $display --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/stmt.cc | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 1acdd24d7..aa9cf5953 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -49,7 +49,7 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vhdl.o vhdl_element.o scope.o process.o +O = vhdl.o vhdl_element.o scope.o process.o stmt.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 33e07da42..a818df38b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -21,6 +21,34 @@ #include "vhdl_target.h" #include +#include + +/* + * Generate VHDL for the $display system task. + * TODO: How is this going to work?? + */ +static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) +{ + return 0; +} + +/* + * Generate VHDL for system tasks (like $display). Not all of + * these are supported. + */ +static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) +{ + const char *name = ivl_stmt_name(stmt); + + std::cout << "IVL_ST_STASK " << name << std::endl; + + if (strcmp(name, "$display") == 0) + return draw_stask_display(proc, stmt); + else { + error("No VHDL translation for system task %s", name); + return 0; + } +} /* * Generate VHDL statements for the given Verilog statement and @@ -28,5 +56,13 @@ */ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) { - return 0; + switch (ivl_statement_type(stmt)) { + case IVL_ST_STASK: + return draw_stask(proc, stmt); + default: + error("No VHDL translation for statement at %s:%d (type = %d)", + ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), + ivl_statement_type(stmt)); + return 1; + } } From fe80da362c30c56f998d7f69f1253c7e8d67f408 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 19:14:47 +0100 Subject: [PATCH 016/377] Collect required packages as compilation progresses --- tgt-vhdl/stmt.cc | 14 +++++++++++++- tgt-vhdl/vhdl.cc | 39 ++++++++++++++++++++++++++++++++++++--- tgt-vhdl/vhdl_target.h | 1 + 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a818df38b..1055a9667 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -25,10 +25,22 @@ /* * Generate VHDL for the $display system task. - * TODO: How is this going to work?? + * This is implemented using the functions in std.textio. Each + * parameter is written to a line variable in the process and + * then the line is written to the special variable `Output' + * (which represents the console). Subsequent $displays will use + * the same line variable. + * + * It's possible, although quite unlikely, that there will be + * name collision with an existing variable called + * `Verilog_Display_Line' - do something about this? It's also + * possible for there to be a name collision with the special + * variable `Output'. */ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) { + require_package("std.textio"); + return 0; } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 3eb64f98a..09e56b6c2 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -27,11 +27,18 @@ #include #include #include +#include static int g_errors = 0; // Total number of errors encountered static entity_list_t g_entities; // All entities to emit +typedef std::string package_name_t; +typedef std::list require_list_t; + +static require_list_t g_requires; // External packages required + + /* * Called when an unrecoverable problem is encountered. */ @@ -71,6 +78,21 @@ void remember_entity(vhdl_entity* ent) g_entities.push_back(ent); } +/* + * Add a package to the list of packages that should be + * use-ed at the start of the program. + */ +void require_package(const char *name) +{ + package_name_t pname(name); + require_list_t::iterator it; + for (it = g_requires.begin(); it != g_requires.end(); ++it) { + if (*it == pname) + return; + } + g_requires.push_back(pname); +} + extern "C" int target_design(ivl_design_t des) { ivl_scope_t *roots; @@ -86,14 +108,25 @@ extern "C" int target_design(ivl_design_t des) const char *ofname = ivl_design_flag(des, "-o"); std::ofstream outfile(ofname); - entity_list_t::const_iterator it; - for (it = g_entities.begin(); it != g_entities.end(); ++it) + // Write all the required packages (and libraries?) + //outfile << "library ieee;" << std::endl; + for (require_list_t::iterator it = g_requires.begin(); + it != g_requires.end(); + ++it) + outfile << "use " << *it << ".all;" << std::endl; + outfile << std::endl; + + for (entity_list_t::iterator it = g_entities.begin(); + it != g_entities.end(); + ++it) (*it)->emit(outfile); outfile.close(); // Clean up - for (it = g_entities.begin(); it != g_entities.end(); ++it) + for (entity_list_t::iterator it = g_entities.begin(); + it != g_entities.end(); + ++it) delete (*it); g_entities.clear(); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 3612f426a..35027bec1 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -16,6 +16,7 @@ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); +void require_package(const char *name); #endif /* #ifndef INC_VHDL_TARGET_H */ From 2e6ec91ce05eb4f6a479d5dc55ba4116247b9ac8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 19:20:45 +0100 Subject: [PATCH 017/377] Scalar types --- tgt-vhdl/vhdl_element.cc | 5 +++++ tgt-vhdl/vhdl_element.hh | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index da7f961c4..5c0b343c9 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -244,3 +244,8 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const // TODO: There are lots of different types of `wait' of << "wait;"; } + +void vhdl_scalar_type::emit(std::ofstream &of, int level) const +{ + of << name_; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index a03e5785f..f655ac106 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -45,6 +45,24 @@ private: typedef std::list element_list_t; +class vhdl_type : public vhdl_element { +public: + virtual ~vhdl_type() {} +}; + +/* + * A type at the moment is just a name. It shouldn't get + * too much more complex, as Verilog's type system is much + * simpler than VHDL's. + */ +class vhdl_scalar_type : public vhdl_element { +public: + vhdl_scalar_type(const char *name) : name_(name) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string name_; +}; /* * A concurrent statement appears in architecture bodies but not @@ -117,6 +135,16 @@ private: }; +/* + * A variable declaration inside a process (although this isn't + * enforced here). + */ +class vhdl_var_decl : public vhdl_decl { +public: + +}; + + /* * Instantiation of component. This is really only a placeholder * at the moment until the port mappings are worked out. From 94006cb44cc482808568d0b4f60a8c6452e6c805 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 3 Jun 2008 19:46:10 +0100 Subject: [PATCH 018/377] Working on code generation for $display task --- tgt-vhdl/stmt.cc | 24 +++++++++++--- tgt-vhdl/vhdl_element.cc | 72 +++++++++++++++++++++++++++++----------- tgt-vhdl/vhdl_element.hh | 14 ++++++-- 3 files changed, 84 insertions(+), 26 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1055a9667..2ee58bfc6 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -28,18 +28,32 @@ * This is implemented using the functions in std.textio. Each * parameter is written to a line variable in the process and * then the line is written to the special variable `Output' - * (which represents the console). Subsequent $displays will use - * the same line variable. + * (which represents the console). Subsequent $displays will + * use the same line variable. * * It's possible, although quite unlikely, that there will be * name collision with an existing variable called - * `Verilog_Display_Line' - do something about this? It's also - * possible for there to be a name collision with the special - * variable `Output'. + * `Verilog_Display_Line' -- do something about this? + * It's also possible for there to be a name collision with + * the special variable `Output'. */ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) { require_package("std.textio"); + + const char *display_line = "Verilog_Display_Line"; + + if (!proc->have_declared_var(display_line)) { + vhdl_type *line_type = new vhdl_scalar_type("Line"); + vhdl_var_decl *line_var = + new vhdl_var_decl(display_line, line_type); + line_var->set_comment("For generating $display output"); + proc->add_decl(line_var); + } + + // TODO: Write the data into the line + + // TODO: Write_Line(Output, Verilog_Display_Line) return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 5c0b343c9..f5f7d5f90 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -67,16 +67,34 @@ void emit_children(std::ofstream &of, } } +template +void delete_children(std::list &children) +{ + typename std::list::iterator it; + for (it = children.begin(); it != children.end(); ++it) + delete *it; + children.clear(); +} + void vhdl_element::set_comment(std::string comment) { comment_ = comment; } -void vhdl_element::emit_comment(std::ofstream &of, int level) const +/* + * Draw the comment for any element. The comment is either on + * a line before the element (end_of_line is false) or at the + * end of the line containing the element (end_of_line is true). + */ +void vhdl_element::emit_comment(std::ofstream &of, int level, + bool end_of_line) const { if (comment_.size() > 0) { + if (end_of_line) + of << " "; of << "-- " << comment_; - newline(of, level); + if (!end_of_line) + newline(of, level); } } @@ -112,17 +130,8 @@ vhdl_arch::vhdl_arch(const char *entity, const char *name) vhdl_arch::~vhdl_arch() { - for (conc_stmt_list_t::iterator it = stmts_.begin(); - it != stmts_.end(); - ++it) - delete (*it); - stmts_.clear(); - - for (decl_list_t::iterator it = decls_.begin(); - it != decls_.end(); - ++it) - delete (*it); - decls_.clear(); + delete_children(stmts_); + delete_children(decls_); } void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) @@ -172,10 +181,8 @@ vhdl_process::vhdl_process(const char *name) vhdl_process::~vhdl_process() { - seq_stmt_list_t::iterator it; - for (it = stmts_.begin(); it != stmts_.end(); ++it) - delete (*it); - stmts_.clear(); + delete_children(stmts_); + delete_children(decls_); } void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) @@ -183,14 +190,28 @@ void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) stmts_.push_back(stmt); } +void vhdl_process::add_decl(vhdl_decl* decl) +{ + decls_.push_back(decl); +} + +bool vhdl_process::have_declared_var(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return true; + } + return false; +} + void vhdl_process::emit(std::ofstream &of, int level) const { emit_comment(of, level); if (name_.size() > 0) of << name_ << ": "; of << "process is"; // TODO: sensitivity - newline(of, level); - // ...declarations... + emit_children(of, decls_, level); of << "begin"; emit_children(of, stmts_, level); of << "end process;"; @@ -249,3 +270,16 @@ void vhdl_scalar_type::emit(std::ofstream &of, int level) const { of << name_; } + +vhdl_var_decl::~vhdl_var_decl() +{ + delete type_; +} + +void vhdl_var_decl::emit(std::ofstream &of, int level) const +{ + of << "variable " << name_ << " : "; + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index f655ac106..3082aad76 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -38,7 +38,8 @@ public: void set_comment(std::string comment); protected: - void emit_comment(std::ofstream &of, int level) const; + void emit_comment(std::ofstream &of, int level, + bool end_of_line=false) const; private: std::string comment_; }; @@ -55,7 +56,7 @@ public: * too much more complex, as Verilog's type system is much * simpler than VHDL's. */ -class vhdl_scalar_type : public vhdl_element { +class vhdl_scalar_type : public vhdl_type { public: vhdl_scalar_type(const char *name) : name_(name) {} @@ -141,7 +142,13 @@ private: */ class vhdl_var_decl : public vhdl_decl { public: + vhdl_var_decl(const char *name, vhdl_type *type) + : vhdl_decl(name), type_(type) {} + ~vhdl_var_decl(); + void emit(std::ofstream &of, int level) const; +private: + vhdl_type *type_; }; @@ -172,8 +179,11 @@ public: void emit(std::ofstream &of, int level) const; void add_stmt(vhdl_seq_stmt *stmt); + void add_decl(vhdl_decl *decl); + bool have_declared_var(const std::string &name) const; private: seq_stmt_list_t stmts_; + decl_list_t decls_; std::string name_; }; From dd30c1b39d2f872f719c6f9b7a48a009a0744817 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 13:27:42 +0100 Subject: [PATCH 019/377] Support procedure call generation for $display --- tgt-vhdl/stmt.cc | 8 +++++++- tgt-vhdl/vhdl_element.cc | 37 +++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_element.hh | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 2ee58bfc6..d05e6209b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -53,7 +53,13 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // TODO: Write the data into the line - // TODO: Write_Line(Output, Verilog_Display_Line) + // Write_Line(Output, Verilog_Display_Line) + vhdl_var_ref *output_ref = new vhdl_var_ref("Output"); + vhdl_var_ref *line_ref = new vhdl_var_ref(display_line); + vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("Write_Line"); + write_line->add_expr(output_ref); + write_line->add_expr(line_ref); + proc->add_stmt(write_line); return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index f5f7d5f90..7f9ce9b4c 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -283,3 +283,40 @@ void vhdl_var_decl::emit(std::ofstream &of, int level) const of << ";"; emit_comment(of, level, true); } + +void vhdl_expr_list::add_expr(vhdl_expr *e) +{ + exprs_.push_back(e); +} + +vhdl_expr_list::~vhdl_expr_list() +{ + delete_children(exprs_); +} + +void vhdl_expr_list::emit(std::ofstream &of, int level) const +{ + of << "("; + + int size = exprs_.size(); + std::list::const_iterator it; + for (it = exprs_.begin(); it != exprs_.end(); ++it) { + (*it)->emit(of, level); + if (--size > 0) + of << ", "; + } + + of << ")"; +} + +void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const +{ + of << name_; + exprs_.emit(of, level); + of << ";"; +} + +void vhdl_var_ref::emit(std::ofstream &of, int level) const +{ + of << name_; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 3082aad76..ab0646597 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -65,6 +65,34 @@ private: std::string name_; }; +class vhdl_expr : public vhdl_element { +public: + virtual ~vhdl_expr() {} +}; + +/* + * A normal scalar variable reference. + */ +class vhdl_var_ref : public vhdl_expr { +public: + vhdl_var_ref(const char *name) : name_(name) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string name_; +}; + +class vhdl_expr_list : public vhdl_element { +public: + ~vhdl_expr_list(); + + void emit(std::ofstream &of, int level) const; + void add_expr(vhdl_expr *e); +private: + std::list exprs_; +}; + + /* * A concurrent statement appears in architecture bodies but not * processes. @@ -98,6 +126,22 @@ public: }; +/* + * A procedure call. Which is a statement, unlike a function + * call which is an expression. + */ +class vhdl_pcall_stmt : public vhdl_seq_stmt { +public: + vhdl_pcall_stmt(const char *name) : name_(name) {} + + void emit(std::ofstream &of, int level) const; + void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } +private: + std::string name_; + vhdl_expr_list exprs_; +}; + + /* * A declaration of some sort (variable, component, etc.). * Declarations have names, which is the identifier of the variable, From 4bf2e1669d3ebdca70b146e8cbb8739b612d0f3e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 13:52:56 +0100 Subject: [PATCH 020/377] Store packages required with entity rather than globally Add parent link to architecture and process so code generators can push things higher up $display now prints blank lines --- tgt-vhdl/process.cc | 11 +++++++---- tgt-vhdl/stmt.cc | 7 ++++--- tgt-vhdl/vhdl.cc | 28 ---------------------------- tgt-vhdl/vhdl_element.cc | 38 ++++++++++++++++++++++++++++++++++++-- tgt-vhdl/vhdl_element.hh | 13 ++++++++++++- tgt-vhdl/vhdl_target.h | 1 - 6 files changed, 59 insertions(+), 39 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 948b15259..3a6cf7744 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -31,8 +31,14 @@ */ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { + + // 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 + // to add information to the architecture) vhdl_process *vhdl_proc = new vhdl_process(); - + ent->get_arch()->add_stmt(vhdl_proc); + ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, stmt); if (rc != 0) @@ -55,9 +61,6 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ss << ivl_scope_tname(scope); vhdl_proc->set_comment(ss.str()); - // Store it in the entity's architecture - ent->get_arch()->add_stmt(vhdl_proc); - return 0; } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index d05e6209b..9d97a75c9 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -39,7 +39,8 @@ */ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) { - require_package("std.textio"); + // Add the package requirement to the containing entity + proc->get_parent()->get_parent()->requires_package("std.textio"); const char *display_line = "Verilog_Display_Line"; @@ -53,10 +54,10 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // TODO: Write the data into the line - // Write_Line(Output, Verilog_Display_Line) + // WriteLine(Output, Verilog_Display_Line) vhdl_var_ref *output_ref = new vhdl_var_ref("Output"); vhdl_var_ref *line_ref = new vhdl_var_ref(display_line); - vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("Write_Line"); + vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); write_line->add_expr(output_ref); write_line->add_expr(line_ref); proc->add_stmt(write_line); diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 09e56b6c2..d060f979d 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -33,11 +33,6 @@ static int g_errors = 0; // Total number of errors encountered static entity_list_t g_entities; // All entities to emit -typedef std::string package_name_t; -typedef std::list require_list_t; - -static require_list_t g_requires; // External packages required - /* * Called when an unrecoverable problem is encountered. @@ -78,21 +73,6 @@ void remember_entity(vhdl_entity* ent) g_entities.push_back(ent); } -/* - * Add a package to the list of packages that should be - * use-ed at the start of the program. - */ -void require_package(const char *name) -{ - package_name_t pname(name); - require_list_t::iterator it; - for (it = g_requires.begin(); it != g_requires.end(); ++it) { - if (*it == pname) - return; - } - g_requires.push_back(pname); -} - extern "C" int target_design(ivl_design_t des) { ivl_scope_t *roots; @@ -108,14 +88,6 @@ extern "C" int target_design(ivl_design_t des) const char *ofname = ivl_design_flag(des, "-o"); std::ofstream outfile(ofname); - // Write all the required packages (and libraries?) - //outfile << "library ieee;" << std::endl; - for (require_list_t::iterator it = g_requires.begin(); - it != g_requires.end(); - ++it) - outfile << "use " << *it << ".all;" << std::endl; - outfile << std::endl; - for (entity_list_t::iterator it = g_entities.begin(); it != g_entities.end(); ++it) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 7f9ce9b4c..c2e4a6b7d 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -102,7 +102,7 @@ vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) : name_(name), arch_(arch), derived_from_(derived_from) { - + arch->parent_ = this; } vhdl_entity::~vhdl_entity() @@ -110,8 +110,29 @@ vhdl_entity::~vhdl_entity() delete arch_; } +/* + * Add a package to the list of `use' statements before + * the entity. + */ +void vhdl_entity::requires_package(const char *spec) +{ + std::string pname(spec); + std::list::iterator it; + for (it = uses_.begin(); it != uses_.end(); ++it) { + if (*it == pname) + return; + } + uses_.push_back(spec); +} + void vhdl_entity::emit(std::ofstream &of, int level) const { + for (std::list::const_iterator it = uses_.begin(); + it != uses_.end(); + ++it) + of << "use " << *it << ".all;" << std::endl; + of << std::endl; + emit_comment(of, level); of << "entity " << name_ << " is"; // ...ports... @@ -123,7 +144,7 @@ void vhdl_entity::emit(std::ofstream &of, int level) const } vhdl_arch::vhdl_arch(const char *entity, const char *name) - : name_(name), entity_(entity) + : parent_(NULL), name_(name), entity_(entity) { } @@ -136,6 +157,7 @@ vhdl_arch::~vhdl_arch() void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) { + stmt->parent_ = this; stmts_.push_back(stmt); } @@ -144,6 +166,12 @@ void vhdl_arch::add_decl(vhdl_decl *decl) decls_.push_back(decl); } +vhdl_entity *vhdl_arch::get_parent() const +{ + assert(parent_); + return parent_; +} + void vhdl_arch::emit(std::ofstream &of, int level) const { emit_comment(of, level); @@ -173,6 +201,12 @@ bool vhdl_arch::have_declared_component(const std::string &name) const return false; } +vhdl_arch *vhdl_conc_stmt::get_parent() const +{ + assert(parent_); + return parent_; +} + vhdl_process::vhdl_process(const char *name) : name_(name) { diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index ab0646597..553dcb013 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -26,6 +26,7 @@ #include class vhdl_entity; +class vhdl_arch; /* * Any VHDL syntax element. Each element can also contain a comment. @@ -98,8 +99,14 @@ private: * processes. */ class vhdl_conc_stmt : public vhdl_element { + friend class vhdl_arch; // Can set its parent public: + vhdl_conc_stmt() : parent_(NULL) {} virtual ~vhdl_conc_stmt() {} + + vhdl_arch *get_parent() const; +private: + vhdl_arch *parent_; }; typedef std::list conc_stmt_list_t; @@ -236,6 +243,7 @@ private: * An architecture which implements an entity. */ class vhdl_arch : public vhdl_element { + friend class vhdl_entity; // Can set its parent public: vhdl_arch(const char *entity, const char *name="Behavioural"); virtual ~vhdl_arch(); @@ -244,7 +252,9 @@ public: bool have_declared_component(const std::string &name) const; void add_decl(vhdl_decl *decl); void add_stmt(vhdl_conc_stmt *stmt); + vhdl_entity *get_parent() const; private: + vhdl_entity *parent_; conc_stmt_list_t stmts_; decl_list_t decls_; std::string name_, entity_; @@ -265,12 +275,13 @@ public: void emit(std::ofstream &of, int level=0) const; vhdl_arch *get_arch() const { return arch_; } const std::string &get_name() const { return name_; } - + void requires_package(const char *spec); const std::string &get_derived_from() const { return derived_from_; } private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture std::string derived_from_; + std::list uses_; }; typedef std::list entity_list_t; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 35027bec1..3612f426a 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -16,7 +16,6 @@ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); -void require_package(const char *name); #endif /* #ifndef INC_VHDL_TARGET_H */ From 9f035108e18204b6186b6f9e51ba2cc61e07a818 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 14:59:04 +0100 Subject: [PATCH 021/377] Stub code for translating expressions --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/expr.cc | 33 +++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_target.h | 2 ++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 tgt-vhdl/expr.cc diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index aa9cf5953..c63aa9134 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -49,7 +49,7 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vhdl.o vhdl_element.o scope.o process.o stmt.o +O = vhdl.o vhdl_element.o scope.o process.o stmt.o expr.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc new file mode 100644 index 000000000..78cb14b37 --- /dev/null +++ b/tgt-vhdl/expr.cc @@ -0,0 +1,33 @@ +/* + * VHDL code generation for expressions. + * + * 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 + + +/* + * Generate a VHDL expression from a Verilog expression. + */ +vhdl_expr *translate_expr(ivl_expr_t e) +{ + assert(false); +} diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 3612f426a..8e23e8829 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -14,6 +14,8 @@ int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); +vhdl_expr *translate_expr(ivl_expr_t e); + void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); From 6e448da90d483126b98c1709f034c6cf45eaa3c4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 15:19:44 +0100 Subject: [PATCH 022/377] Emit Write() calls for parameters of $display --- tgt-vhdl/expr.cc | 20 +++++++++++++++++++- tgt-vhdl/process.cc | 1 - tgt-vhdl/stmt.cc | 26 +++++++++++++++++++++----- tgt-vhdl/vhdl_element.cc | 5 +++++ tgt-vhdl/vhdl_element.hh | 9 +++++++++ 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 78cb14b37..3501bc188 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -23,11 +23,29 @@ #include #include +/* + * Convert a constant Verilog string to a constant VHDL string. + */ +static vhdl_expr *translate_string(ivl_expr_t e) +{ + // TODO: May need to inspect or escape parts of this + const char *str = ivl_expr_string(e); + return new vhdl_const_string(str); +} /* * Generate a VHDL expression from a Verilog expression. */ vhdl_expr *translate_expr(ivl_expr_t e) { - assert(false); + ivl_expr_type_t type = ivl_expr_type(e); + + switch (type) { + case IVL_EX_STRING: + return translate_string(e); + default: + error("No VHDL translation for expression at %s:%d (type = %d)", + ivl_expr_file(e), ivl_expr_lineno(e), type); + return NULL; + } } diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 3a6cf7744..f0945b86a 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -31,7 +31,6 @@ */ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) { - // 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/stmt.cc b/tgt-vhdl/stmt.cc index 9d97a75c9..d64ff8253 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -52,14 +52,30 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) proc->add_decl(line_var); } - // TODO: Write the data into the line + + + // Write the data into the line + int count = ivl_stmt_parm_count(stmt); + for (int i = 0; i < count; i++) { + // TODO: This is a bit simplistic since it will only + // work with strings + // --> Need to add a call to Type'Image for non-string + // expressions + vhdl_expr *e = translate_expr(ivl_stmt_parm(stmt, i)); + if (NULL == e) + return 1; + + vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); + write->add_expr(new vhdl_var_ref(display_line)); + write->add_expr(e); + + proc->add_stmt(write); + } // WriteLine(Output, Verilog_Display_Line) - vhdl_var_ref *output_ref = new vhdl_var_ref("Output"); - vhdl_var_ref *line_ref = new vhdl_var_ref(display_line); vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); - write_line->add_expr(output_ref); - write_line->add_expr(line_ref); + write_line->add_expr(new vhdl_var_ref("Output")); + write_line->add_expr(new vhdl_var_ref(display_line)); proc->add_stmt(write_line); return 0; diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index c2e4a6b7d..c2e77aacd 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -354,3 +354,8 @@ void vhdl_var_ref::emit(std::ofstream &of, int level) const { of << name_; } + +void vhdl_const_string::emit(std::ofstream &of, int level) const +{ + of << "\"" << value_ << "\""; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 553dcb013..38fe6b537 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -83,6 +83,15 @@ private: std::string name_; }; +class vhdl_const_string : public vhdl_expr { +public: + vhdl_const_string(const char *value) : value_(value) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string value_; +}; + class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); From 7bd1565cfb6cd41c75257bebe8efa8f29d0fbb3c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 20:42:44 +0100 Subject: [PATCH 023/377] $display now (mostly) working --- tgt-vhdl/scope.cc | 1 - tgt-vhdl/stmt.cc | 6 ++---- tgt-vhdl/vhdl_element.cc | 6 +++++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e0e1a475c..521f2e5a7 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -79,7 +79,6 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); assert(parent_ent != NULL); - // Make sure we only collect instantiations from *one* // example of this module in the hieararchy if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index d64ff8253..27cf61a50 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -57,10 +57,8 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // Write the data into the line int count = ivl_stmt_parm_count(stmt); for (int i = 0; i < count; i++) { - // TODO: This is a bit simplistic since it will only - // work with strings - // --> Need to add a call to Type'Image for non-string - // expressions + // TODO: Need to add a call to Type'Image for types not + // supported by std.textio vhdl_expr *e = translate_expr(ivl_stmt_parm(stmt, i)); if (NULL == e) return 1; diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index c2e77aacd..63dd8724d 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -357,5 +357,9 @@ void vhdl_var_ref::emit(std::ofstream &of, int level) const void vhdl_const_string::emit(std::ofstream &of, int level) const { - of << "\"" << value_ << "\""; + // In some instances a string literal can be ambiguous between + // a String type and some other types (e.g. std_logic_vector) + // The explicit cast to String removes this ambiguity (although + // isn't always strictly necessary) + of << "String'(\"" << value_ << "\")"; } From f49dd97d24bb4c2ee1fb9f64116b5488cfa12615 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 20:57:15 +0100 Subject: [PATCH 024/377] Add support for blocks and make hello1.v test pass --- tgt-vhdl/stmt.cc | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 27cf61a50..e70de2784 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -22,6 +22,7 @@ #include #include +#include /* * Generate VHDL for the $display system task. @@ -51,17 +52,24 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) line_var->set_comment("For generating $display output"); proc->add_decl(line_var); } - - // Write the data into the line int count = ivl_stmt_parm_count(stmt); for (int i = 0; i < count; i++) { - // TODO: Need to add a call to Type'Image for types not - // supported by std.textio - vhdl_expr *e = translate_expr(ivl_stmt_parm(stmt, i)); - if (NULL == e) - return 1; + // $display may have an empty parameter, in which case + // the expression will be null + // The behaviour here seems to be to output a space + ivl_expr_t net = ivl_stmt_parm(stmt, i); + vhdl_expr *e = NULL; + if (net) { + // TODO: Need to add a call to Type'Image for types not + // supported by std.textio + e = translate_expr(net); + if (NULL == e) + return 1; + } + else + e = new vhdl_const_string(" "); vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); write->add_expr(new vhdl_var_ref(display_line)); @@ -97,6 +105,22 @@ static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) } } +/* + * Generate VHDL for a block of Verilog statements. This doesn't + * actually do anything, other than recursively translate the + * block's statements and add them to the process. This is OK as + * `begin' and `end process' function like a Verilog block. + */ +static int draw_block(vhdl_process *proc, ivl_statement_t stmt) +{ + int count = ivl_stmt_block_count(stmt); + for (int i = 0; i < count; i++) { + if (draw_stmt(proc, ivl_stmt_block_stmt(stmt, i)) != 0) + return 1; + } + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. @@ -106,6 +130,8 @@ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: return draw_stask(proc, stmt); + case IVL_ST_BLOCK: + return draw_block(proc, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), From 234f73e7bf057ed8519382fda6dfeb371d8a6d48 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 21:03:36 +0100 Subject: [PATCH 025/377] Don't generate any output if there were errors --- tgt-vhdl/vhdl.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index d060f979d..fb4009e49 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -85,16 +85,19 @@ extern "C" int target_design(ivl_design_t des) ivl_design_process(des, draw_process, NULL); // Write the generated elements to the output file - const char *ofname = ivl_design_flag(des, "-o"); - std::ofstream outfile(ofname); - - for (entity_list_t::iterator it = g_entities.begin(); - it != g_entities.end(); - ++it) - (*it)->emit(outfile); + // only if there are no errors + if (0 == g_errors) { + const char *ofname = ivl_design_flag(des, "-o"); + std::ofstream outfile(ofname); + + for (entity_list_t::iterator it = g_entities.begin(); + it != g_entities.end(); + ++it) + (*it)->emit(outfile); + + outfile.close(); + } - outfile.close(); - // Clean up for (entity_list_t::iterator it = g_entities.begin(); it != g_entities.end(); From c3ac1aac8c92d59a12357f5f7d7f7da708c55fcc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 21:07:50 +0100 Subject: [PATCH 026/377] Remove debugging messages from output --- tgt-vhdl/process.cc | 9 ++------- tgt-vhdl/scope.cc | 11 +---------- tgt-vhdl/stmt.cc | 2 -- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index f0945b86a..2ce594aac 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -79,13 +79,8 @@ int draw_process(ivl_process_t proc, void *cd) // from this Verilog process. This ensures that each process // is translated at most once, no matter how many times it // appears in the hierarchy. - if (ent->get_derived_from() == scope_name) { - std::cout << "New process encountered in " << scope_name << std::endl; + if (ent->get_derived_from() == scope_name) return generate_vhdl_process(ent, proc); - } - else { - std::cout << "Ignoring already seen process in "; - std::cout << scope_name << std::endl; + else return 0; - } } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 521f2e5a7..40aefcc3d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -52,9 +52,6 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) arch->set_comment(ss.str()); ent->set_comment(ss.str()); - - std::cout << "Generated entity " << tname; - std::cout << " from " << ivl_scope_name(scope) << std::endl; remember_entity(ent); return ent; @@ -99,8 +96,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) parent_arch->add_stmt(inst); } else { - std::cout << "Ignoring instantiation " << ivl_scope_name(scope); - std::cout << " (already accounted for)" << std::endl; + // Ignore this instantiation (already accounted for) } } @@ -111,11 +107,6 @@ int draw_scope(ivl_scope_t scope, void *_parent) { ivl_scope_t parent = static_cast(_parent); - const char *name = ivl_scope_name(scope); - const char *basename = ivl_scope_basename(scope); - - std::cout << "scope " << name << " (" << basename << ")" << std::endl; - ivl_scope_type_t type = ivl_scope_type(scope); int rc = 0; switch (type) { diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e70de2784..48e624c7b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -94,8 +94,6 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) { const char *name = ivl_stmt_name(stmt); - - std::cout << "IVL_ST_STASK " << name << std::endl; if (strcmp(name, "$display") == 0) return draw_stask_display(proc, stmt); From e258058cf1d3dd5b459f2be81cbef1277fd3dd22 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 4 Jun 2008 21:58:51 +0100 Subject: [PATCH 027/377] Fully qualify std.textio.Output to avoid name collisions --- tgt-vhdl/stmt.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 48e624c7b..557f096a6 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -35,8 +35,6 @@ * It's possible, although quite unlikely, that there will be * name collision with an existing variable called * `Verilog_Display_Line' -- do something about this? - * It's also possible for there to be a name collision with - * the special variable `Output'. */ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) { @@ -80,7 +78,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // WriteLine(Output, Verilog_Display_Line) vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); - write_line->add_expr(new vhdl_var_ref("Output")); + write_line->add_expr(new vhdl_var_ref("std.textio.Output")); write_line->add_expr(new vhdl_var_ref(display_line)); proc->add_stmt(write_line); From d36bbec5b53e9eda15deef71bae7640a16eda771 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 5 Jun 2008 13:16:35 +0100 Subject: [PATCH 028/377] Generate VHDL for no-op statements --- tgt-vhdl/stmt.cc | 12 ++++++++++++ tgt-vhdl/vhdl_element.cc | 5 +++++ tgt-vhdl/vhdl_element.hh | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 557f096a6..a9ebed944 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -117,6 +117,16 @@ static int draw_block(vhdl_process *proc, ivl_statement_t stmt) return 0; } +/* + * A no-op statement. This corresponds to a `null' statement in + * VHDL. + */ +static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) +{ + proc->add_stmt(new vhdl_null_stmt()); + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. @@ -128,6 +138,8 @@ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) return draw_stask(proc, stmt); case IVL_ST_BLOCK: return draw_block(proc, stmt); + case IVL_ST_NOOP: + return draw_noop(proc, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 63dd8724d..68e0d4721 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -363,3 +363,8 @@ void vhdl_const_string::emit(std::ofstream &of, int level) const // isn't always strictly necessary) of << "String'(\"" << value_ << "\")"; } + +void vhdl_null_stmt::emit(std::ofstream &of, int level) const +{ + of << "null;"; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 38fe6b537..bbd7de589 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -142,6 +142,12 @@ public: }; +class vhdl_null_stmt : public vhdl_seq_stmt { +public: + void emit(std::ofstream &of, int level) const; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From 4f472e451ec39f46be81acee868fe17a8ce65a63 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 6 Jun 2008 16:55:45 +0100 Subject: [PATCH 029/377] Stubs for statement types in mux2.v test --- tgt-vhdl/stmt.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a9ebed944..93c14fdaf 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -127,6 +127,39 @@ static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) return 0; } +/* + * A non-blocking assignment inside a process. The semantics for + * this are essentially the same as VHDL's non-blocking signal + * assignment. + */ +static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) +{ + std::cout << "draw_nbassign" << std::endl; + return 0; +} + +/* + * Delay statements are equivalent to the `wait for' form of the + * VHDL wait statement. + */ +static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) +{ + std::cout << "draw_delay" << std::endl; + return 0; +} + +/* + * A wait statement waits for a level change on a @(..) list of + * signals. This needs to be implemented by an `if' statement + * inside the process (which the appropriate signals added to + * the sensitivity list). + */ +static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) +{ + std::cout << "draw_wait" << std::endl; + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. @@ -140,6 +173,12 @@ int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) return draw_block(proc, stmt); case IVL_ST_NOOP: return draw_noop(proc, stmt); + case IVL_ST_ASSIGN_NB: + return draw_nbassign(proc, stmt); + case IVL_ST_DELAY: + return draw_delay(proc, stmt); + case IVL_ST_WAIT: + return draw_wait(proc, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), From 373832ba2278ab987fab39fb814b5586e63d423c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 6 Jun 2008 17:36:15 +0100 Subject: [PATCH 030/377] Specify correct sensitivity list --- tgt-vhdl/stmt.cc | 48 ++++++++++++++++++++++++++++++++++++---- tgt-vhdl/vhdl_element.cc | 21 +++++++++++++++++- tgt-vhdl/vhdl_element.hh | 6 ++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 93c14fdaf..30637d7e1 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -150,13 +150,53 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) /* * A wait statement waits for a level change on a @(..) list of - * signals. This needs to be implemented by an `if' statement - * inside the process (which the appropriate signals added to - * the sensitivity list). + * signals. + * TODO: This won't yet handle the posedge to rising_edge, etc. + * mapping. */ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) { - std::cout << "draw_wait" << std::endl; + int nevents = ivl_stmt_nevent(stmt); + for (int i = 0; i < nevents; i++) { + ivl_event_t event = ivl_stmt_events(stmt, i); + + if (ivl_event_nneg(event) != 0) + error("Negative edge events not supported yet"); + if (ivl_event_npos(event) != 0) + error("Positive edge events not supported yet"); + + int nany = ivl_event_nany(event); + for (int i = 0; i < nany; i++) { + ivl_nexus_t nexus = ivl_event_any(event, i); + std::cout << "event nexus " << ivl_nexus_name(nexus) << std::endl; + + 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_net_logic_t log; + ivl_signal_t sig; + if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { + const char *signame = ivl_signal_basename(sig); + std::cout << "signal " << signame << std::endl; + + proc->add_sensitivity(signame); + return 0; + } + else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { + error("Nexus points to net logic"); + return 1; + } + else { + error("Nexus points to unknown"); + return 1; + } + } + } + } + + ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); + return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 68e0d4721..bd59b40d2 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -229,6 +229,11 @@ void vhdl_process::add_decl(vhdl_decl* decl) decls_.push_back(decl); } +void vhdl_process::add_sensitivity(const char *name) +{ + sens_.push_back(name); +} + bool vhdl_process::have_declared_var(const std::string &name) const { decl_list_t::const_iterator it; @@ -244,7 +249,21 @@ void vhdl_process::emit(std::ofstream &of, int level) const emit_comment(of, level); if (name_.size() > 0) of << name_ << ": "; - of << "process is"; // TODO: sensitivity + of << "process "; + + int num_sens = sens_.size(); + if (num_sens > 0) { + of << "("; + string_list_t::const_iterator it; + for (it = sens_.begin(); it != sens_.end(); ++it) { + of << *it; + if (--num_sens > 0) + of << ", "; + } + of << ") "; + } + + of << "is"; emit_children(of, decls_, level); of << "begin"; emit_children(of, stmts_, level); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index bbd7de589..76e475d3a 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -28,6 +28,8 @@ class vhdl_entity; class vhdl_arch; +typedef std::list string_list_t; + /* * Any VHDL syntax element. Each element can also contain a comment. */ @@ -246,11 +248,13 @@ public: void emit(std::ofstream &of, int level) const; void add_stmt(vhdl_seq_stmt *stmt); void add_decl(vhdl_decl *decl); + void add_sensitivity(const char *name); bool have_declared_var(const std::string &name) const; private: seq_stmt_list_t stmts_; decl_list_t decls_; std::string name_; + string_list_t sens_; }; @@ -296,7 +300,7 @@ private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture std::string derived_from_; - std::list uses_; + string_list_t uses_; }; typedef std::list entity_list_t; From 96cf1907203e511d0752fbf5dfda07b07aafa3e3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 6 Jun 2008 17:56:52 +0100 Subject: [PATCH 031/377] Generate signals and sensitivity list for @(..) statement --- tgt-vhdl/stmt.cc | 12 +++++++++++- tgt-vhdl/vhdl_element.cc | 34 +++++++++++++++++++++++++++++++++- tgt-vhdl/vhdl_element.hh | 18 +++++++++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 30637d7e1..8d98a52d4 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -179,7 +179,17 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { const char *signame = ivl_signal_basename(sig); std::cout << "signal " << signame << std::endl; - + + if (!proc->get_parent()->have_declared(signame)) { + // First time this signal has been encountered + vhdl_scalar_type *std_logic = + new vhdl_scalar_type("std_logic"); + vhdl_signal_decl *sig_decl = + new vhdl_signal_decl(signame, std_logic); + + proc->get_parent()->add_decl(sig_decl); + } + proc->add_sensitivity(signame); return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index bd59b40d2..073ddc267 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -106,7 +106,7 @@ vhdl_entity::vhdl_entity(const char *name, const char *derived_from, } vhdl_entity::~vhdl_entity() -{ +{ delete arch_; } @@ -127,6 +127,11 @@ void vhdl_entity::requires_package(const char *spec) void vhdl_entity::emit(std::ofstream &of, int level) const { + // Pretty much every design will use std_logic so we + // might as well include it by default + of << "library ieee;" << std::endl; + of << "use ieee.std_logic_1164.all;" << std::endl; + for (std::list::const_iterator it = uses_.begin(); it != uses_.end(); ++it) @@ -201,6 +206,20 @@ bool vhdl_arch::have_declared_component(const std::string &name) const return false; } +/* + * True if any declaration of `name' has been added to the + * architecture. + */ +bool vhdl_arch::have_declared(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return true; + } + return false; +} + vhdl_arch *vhdl_conc_stmt::get_parent() const { assert(parent_); @@ -337,6 +356,19 @@ void vhdl_var_decl::emit(std::ofstream &of, int level) const emit_comment(of, level, true); } +vhdl_signal_decl::~vhdl_signal_decl() +{ + delete type_; +} + +void vhdl_signal_decl::emit(std::ofstream &of, int level) const +{ + of << "signal " << name_ << " : "; + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); +} + void vhdl_expr_list::add_expr(vhdl_expr *e) { exprs_.push_back(e); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 76e475d3a..3498fead3 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -220,6 +220,21 @@ private: }; +/* + * A signal declaration in architecture. + */ +class vhdl_signal_decl : public vhdl_decl { +public: + vhdl_signal_decl(const char *name, vhdl_type *type) + : vhdl_decl(name), type_(type) {} + ~vhdl_signal_decl(); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_type *type_; +}; + + /* * Instantiation of component. This is really only a placeholder * at the moment until the port mappings are worked out. @@ -269,6 +284,7 @@ public: void emit(std::ofstream &of, int level=0) const; bool have_declared_component(const std::string &name) const; + bool have_declared(const std::string &name) const; void add_decl(vhdl_decl *decl); void add_stmt(vhdl_conc_stmt *stmt); vhdl_entity *get_parent() const; @@ -295,7 +311,7 @@ public: vhdl_arch *get_arch() const { return arch_; } const std::string &get_name() const { return name_; } void requires_package(const char *spec); - const std::string &get_derived_from() const { return derived_from_; } + const std::string &get_derived_from() const { return derived_from_; } private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture From 5f90a3e48c07512e0d4ed44fb925abcebebdf14d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 6 Jun 2008 18:22:03 +0100 Subject: [PATCH 032/377] Translate sub-statement of @{..} --- tgt-vhdl/stmt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 8d98a52d4..44b8ebc4a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -191,7 +191,6 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) } proc->add_sensitivity(signame); - return 0; } else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { error("Nexus points to net logic"); @@ -206,6 +205,7 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) } ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); + draw_stmt(proc, sub_stmt); return 0; } From 305f448d05b25b5d85546fca2e89023e33159668 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 11:24:09 +0100 Subject: [PATCH 033/377] Generate code for signal references --- tgt-vhdl/expr.cc | 12 ++++++++++++ tgt-vhdl/stmt.cc | 17 +++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 3501bc188..ead20f2bf 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -33,6 +33,16 @@ static vhdl_expr *translate_string(ivl_expr_t e) return new vhdl_const_string(str); } +/* + * A reference to a signal in an expression. It's assumed that the + * signal has already been defined elsewhere. + */ +static vhdl_expr *translate_signal(ivl_expr_t e) +{ + ivl_signal_t sig = ivl_expr_signal(e); + return new vhdl_var_ref(ivl_signal_basename(sig)); +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -43,6 +53,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) switch (type) { case IVL_EX_STRING: return translate_string(e); + case IVL_EX_SIGNAL: + return translate_signal(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 44b8ebc4a..e5e70d64b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -178,23 +178,12 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { const char *signame = ivl_signal_basename(sig); - std::cout << "signal " << signame << std::endl; - - if (!proc->get_parent()->have_declared(signame)) { - // First time this signal has been encountered - vhdl_scalar_type *std_logic = - new vhdl_scalar_type("std_logic"); - vhdl_signal_decl *sig_decl = - new vhdl_signal_decl(signame, std_logic); - - proc->get_parent()->add_decl(sig_decl); - } - + std::cout << "signal " << signame << std::endl; proc->add_sensitivity(signame); } else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { - error("Nexus points to net logic"); - return 1; + std::cout << "net logic " << ivl_logic_basename(log) << " "; + std::cout << "type = " << ivl_logic_type(log) << std::endl; } else { error("Nexus points to unknown"); From 8c3461f0ffea109195b219467c60f0818a685c09 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 11:48:38 +0100 Subject: [PATCH 034/377] Generate sensitivity lists properly and add signal declarations --- tgt-vhdl/scope.cc | 20 ++++++++++++++++++++ tgt-vhdl/stmt.cc | 17 +++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 40aefcc3d..4c9f46a08 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,6 +25,22 @@ #include #include +/* + * Declare all signals for a scope in an architecture. + */ +static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) +{ + int nsigs = ivl_scope_sigs(scope); + for (int i = 0; i < nsigs; i++) { + ivl_signal_t sig = ivl_scope_sig(scope, i); + vhdl_scalar_type *std_logic = + new vhdl_scalar_type("std_logic"); + vhdl_signal_decl *decl = + new vhdl_signal_decl(ivl_signal_basename(sig), std_logic); + arch->add_decl(decl); + } +} + /* * Create a VHDL entity for scopes of type IVL_SCT_MODULE. */ @@ -46,6 +62,10 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) vhdl_arch *arch = new vhdl_arch(tname); vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch); + // Locate all the signals in this module and add them to + // the architecture + declare_signals(arch, scope); + // Build a comment to add to the entity/architecture std::ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e5e70d64b..bdeb5d2e7 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -168,26 +168,23 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) int nany = ivl_event_nany(event); for (int i = 0; i < nany; i++) { ivl_nexus_t nexus = ivl_event_any(event, i); - std::cout << "event nexus " << ivl_nexus_name(nexus) << std::endl; 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_net_logic_t log; ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { const char *signame = ivl_signal_basename(sig); - std::cout << "signal " << signame << std::endl; - proc->add_sensitivity(signame); - } - else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { - std::cout << "net logic " << ivl_logic_basename(log) << " "; - std::cout << "type = " << ivl_logic_type(log) << std::endl; + + // 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_parent()->have_declared(signame)) + proc->add_sensitivity(signame); } else { - error("Nexus points to unknown"); - return 1; + // Ignore all other types of nexus pointer } } } From a8ecce74219050df48b25c01690438734f373108 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 12:15:46 +0100 Subject: [PATCH 035/377] Make sure all declarations have a type --- tgt-vhdl/vhdl_element.cc | 17 +++++++++++------ tgt-vhdl/vhdl_element.hh | 14 +++++++------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 073ddc267..648cde01d 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -189,6 +189,16 @@ void vhdl_arch::emit(std::ofstream &of, int level) const blank_line(of, level); // Extra blank line after architectures; } +vhdl_decl *vhdl_arch::get_decl(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return *it; + } + return NULL; +} + /* * True if component `name' has already been declared in this * architecture. This is a bit of hack, since it uses typeid @@ -212,12 +222,7 @@ bool vhdl_arch::have_declared_component(const std::string &name) const */ bool vhdl_arch::have_declared(const std::string &name) const { - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return true; - } - return false; + return get_decl(name) != NULL; } vhdl_arch *vhdl_conc_stmt::get_parent() const diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 3498fead3..3e14a2bd6 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -173,12 +173,15 @@ private: */ class vhdl_decl : public vhdl_element { public: - vhdl_decl(const char *name) : name_(name) {} + vhdl_decl(const char *name, vhdl_type *type=NULL) + : name_(name), type_(type) {} virtual ~vhdl_decl() {}; const std::string &get_name() const { return name_; } + const vhdl_type *get_type() const { return type_; } protected: std::string name_; + vhdl_type *type_; }; typedef std::list decl_list_t; @@ -211,12 +214,10 @@ private: class vhdl_var_decl : public vhdl_decl { public: vhdl_var_decl(const char *name, vhdl_type *type) - : vhdl_decl(name), type_(type) {} + : vhdl_decl(name, type) {} ~vhdl_var_decl(); void emit(std::ofstream &of, int level) const; -private: - vhdl_type *type_; }; @@ -226,12 +227,10 @@ private: class vhdl_signal_decl : public vhdl_decl { public: vhdl_signal_decl(const char *name, vhdl_type *type) - : vhdl_decl(name), type_(type) {} + : vhdl_decl(name, type) {} ~vhdl_signal_decl(); void emit(std::ofstream &of, int level) const; -private: - vhdl_type *type_; }; @@ -285,6 +284,7 @@ public: void emit(std::ofstream &of, int level=0) const; bool have_declared_component(const std::string &name) const; bool have_declared(const std::string &name) const; + vhdl_decl *get_decl(const std::string &name) const; void add_decl(vhdl_decl *decl); void add_stmt(vhdl_conc_stmt *stmt); vhdl_entity *get_parent() const; From cdb180e1d49454f82f41e2c60544904c91ecbcf8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 13:23:21 +0100 Subject: [PATCH 036/377] Associate a type with each VHDL expression node --- tgt-vhdl/expr.cc | 6 +++++- tgt-vhdl/stmt.cc | 12 +++++++++--- tgt-vhdl/vhdl_element.cc | 20 ++++++++++++++++++++ tgt-vhdl/vhdl_element.hh | 16 +++++++++++++--- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index ead20f2bf..80b9a05bc 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -40,7 +40,11 @@ static vhdl_expr *translate_string(ivl_expr_t e) static vhdl_expr *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); - return new vhdl_var_ref(ivl_signal_basename(sig)); + + // Assume all signals are single bits at the moment + vhdl_type *type = vhdl_scalar_type::std_logic(); + + return new vhdl_var_ref(ivl_signal_basename(sig), type); } /* diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index bdeb5d2e7..c42110707 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -70,7 +70,9 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) e = new vhdl_const_string(" "); vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); - write->add_expr(new vhdl_var_ref(display_line)); + vhdl_var_ref *ref = + new vhdl_var_ref(display_line, vhdl_scalar_type::line()); + write->add_expr(ref); write->add_expr(e); proc->add_stmt(write); @@ -78,8 +80,12 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // WriteLine(Output, Verilog_Display_Line) vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); - write_line->add_expr(new vhdl_var_ref("std.textio.Output")); - write_line->add_expr(new vhdl_var_ref(display_line)); + vhdl_var_ref *output_ref = + new vhdl_var_ref("std.textio.Output", new vhdl_scalar_type("File")); + write_line->add_expr(output_ref); + vhdl_var_ref *ref = + new vhdl_var_ref(display_line, vhdl_scalar_type::line()); + write_line->add_expr(ref); proc->add_stmt(write_line); return 0; diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 648cde01d..ab3d49b14 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -343,6 +343,21 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const of << "wait;"; } +vhdl_scalar_type *vhdl_scalar_type::std_logic() +{ + return new vhdl_scalar_type("std_logic"); +} + +vhdl_scalar_type *vhdl_scalar_type::string() +{ + return new vhdl_scalar_type("String"); +} + +vhdl_scalar_type *vhdl_scalar_type::line() +{ + return new vhdl_scalar_type("Line"); +} + void vhdl_scalar_type::emit(std::ofstream &of, int level) const { of << name_; @@ -374,6 +389,11 @@ void vhdl_signal_decl::emit(std::ofstream &of, int level) const emit_comment(of, level, true); } +vhdl_expr::~vhdl_expr() +{ + delete type_; +} + void vhdl_expr_list::add_expr(vhdl_expr *e) { exprs_.push_back(e); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 3e14a2bd6..80029e585 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -64,13 +64,21 @@ public: vhdl_scalar_type(const char *name) : name_(name) {} void emit(std::ofstream &of, int level) const; + + // Common types + static vhdl_scalar_type *std_logic(); + static vhdl_scalar_type *string(); + static vhdl_scalar_type *line(); private: std::string name_; }; class vhdl_expr : public vhdl_element { public: - virtual ~vhdl_expr() {} + vhdl_expr(vhdl_type* type) : type_(type) {} + virtual ~vhdl_expr(); +private: + vhdl_type *type_; }; /* @@ -78,7 +86,8 @@ public: */ class vhdl_var_ref : public vhdl_expr { public: - vhdl_var_ref(const char *name) : name_(name) {} + vhdl_var_ref(const char *name, vhdl_type *type) + : vhdl_expr(type), name_(name) {} void emit(std::ofstream &of, int level) const; private: @@ -87,7 +96,8 @@ private: class vhdl_const_string : public vhdl_expr { public: - vhdl_const_string(const char *value) : value_(value) {} + vhdl_const_string(const char *value) + : vhdl_expr(vhdl_scalar_type::string()), value_(value) {} void emit(std::ofstream &of, int level) const; private: From 066a9b7a61decaba3e19b3918b6c68e7f49ebb09 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 13:29:27 +0100 Subject: [PATCH 037/377] Add AST element for function call expressions --- tgt-vhdl/vhdl_element.cc | 7 +++++++ tgt-vhdl/vhdl_element.hh | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index ab3d49b14..3deff1a69 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -444,3 +444,10 @@ void vhdl_null_stmt::emit(std::ofstream &of, int level) const { of << "null;"; } + +void vhdl_fcall::emit(std::ofstream &of, int level) const +{ + of << name_; + exprs_.emit(of, level); +} + diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 80029e585..0b15c7362 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -81,6 +81,7 @@ private: vhdl_type *type_; }; + /* * A normal scalar variable reference. */ @@ -94,6 +95,7 @@ private: std::string name_; }; + class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) @@ -104,6 +106,7 @@ private: std::string value_; }; + class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); @@ -115,6 +118,23 @@ private: }; +/* + * A function call within an expression. + */ +class vhdl_fcall : public vhdl_expr { +public: + vhdl_fcall(const char *name, vhdl_type *rtype) + : vhdl_expr(rtype), name_(name) {}; + ~vhdl_fcall() {} + + void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } + void emit(std::ofstream &of, int level) const; +private: + std::string name_; + vhdl_expr_list exprs_; +}; + + /* * A concurrent statement appears in architecture bodies but not * processes. From 12e223713100605e01c0565aeb9aa40a5b4e4f35 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 14:21:50 +0100 Subject: [PATCH 038/377] Add Type'Image cast to $display parameters --- tgt-vhdl/stmt.cc | 22 ++++++++++++++++++---- tgt-vhdl/vhdl_element.hh | 12 +++++++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c42110707..a19dc8610 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -23,6 +23,7 @@ #include #include #include +#include /* * Generate VHDL for the $display system task. @@ -60,11 +61,24 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) ivl_expr_t net = ivl_stmt_parm(stmt, i); vhdl_expr *e = NULL; if (net) { - // TODO: Need to add a call to Type'Image for types not - // supported by std.textio - e = translate_expr(net); - if (NULL == e) + vhdl_expr *base = translate_expr(net); + if (NULL == base) return 1; + + + // Need to add a call to Type'Image for types not + // supported by std.textio + if (base->get_type()->get_name() != "String") { + std::string name(base->get_type()->get_name()); + name += "'Image"; + + vhdl_fcall *cast + = new vhdl_fcall(name.c_str(), vhdl_scalar_type::string()); + cast->add_expr(base); + e = cast; + } + else + e = base; } else e = new vhdl_const_string(" "); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 0b15c7362..e9788c7d2 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -51,7 +51,12 @@ typedef std::list element_list_t; class vhdl_type : public vhdl_element { public: + vhdl_type(const char *name) : name_(name) {} virtual ~vhdl_type() {} + + const std::string &get_name() const { return name_; } +protected: + std::string name_; }; /* @@ -61,7 +66,8 @@ public: */ class vhdl_scalar_type : public vhdl_type { public: - vhdl_scalar_type(const char *name) : name_(name) {} + vhdl_scalar_type(const char *name) + : vhdl_type(name) {} void emit(std::ofstream &of, int level) const; @@ -69,14 +75,14 @@ public: static vhdl_scalar_type *std_logic(); static vhdl_scalar_type *string(); static vhdl_scalar_type *line(); -private: - std::string name_; }; class vhdl_expr : public vhdl_element { public: vhdl_expr(vhdl_type* type) : type_(type) {} virtual ~vhdl_expr(); + + const vhdl_type *get_type() const { return type_; } private: vhdl_type *type_; }; From 39228f34951d3cab9c1b68abbb7bae03f4a5da02 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 14:31:33 +0100 Subject: [PATCH 039/377] VHDL AST element for non-blocking assignment --- tgt-vhdl/stmt.cc | 1 - tgt-vhdl/vhdl_element.cc | 7 +++++++ tgt-vhdl/vhdl_element.hh | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a19dc8610..eb96339e9 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -64,7 +64,6 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) vhdl_expr *base = translate_expr(net); if (NULL == base) return 1; - // Need to add a call to Type'Image for types not // supported by std.textio diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 3deff1a69..2411be773 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -451,3 +451,10 @@ void vhdl_fcall::emit(std::ofstream &of, int level) const exprs_.emit(of, level); } +void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const +{ + lhs_->emit(of, level); + of << " <= "; + rhs_->emit(of, level); + of << ";"; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index e9788c7d2..0a44e9a6d 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -170,6 +170,21 @@ public: typedef std::list seq_stmt_list_t; +/* + * Similar to Verilog non-blocking assignment, except the LHS + * must be a signal not a variable. + */ +class vhdl_nbassign_stmt : public vhdl_seq_stmt { +public: + vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) + : lhs_(lhs), rhs_(rhs) {} + + void emit(std::ofstream &of, int level); +private: + vhdl_var_ref *lhs_; + vhdl_expr *rhs_; +}; + /* * Delay simulation indefinitely, until an event, or for a * specified time. From c064ae6bc37e89c2b4879340051b67fb42cc522f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 14:54:00 +0100 Subject: [PATCH 040/377] Generate VHDL for non-blocking assignments --- tgt-vhdl/stmt.cc | 32 +++++++++++++++++++++++++++++++- tgt-vhdl/vhdl_element.cc | 9 +++++++++ tgt-vhdl/vhdl_element.hh | 5 ++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index eb96339e9..636c4f283 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -153,7 +153,37 @@ static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) */ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) { - std::cout << "draw_nbassign" << std::endl; + int nlvals = ivl_stmt_lvals(stmt); + if (nlvals != 1) { + error("Can only have 1 lval at the moment (found %d)", nlvals); + return 1; + } + + ivl_lval_t lval = ivl_stmt_lval(stmt, 0); + ivl_signal_t sig; + if ((sig = ivl_lval_sig(lval))) { + const char *signame = ivl_signal_basename(sig); + + vhdl_expr *rhs = translate_expr(ivl_stmt_rval(stmt)); + if (NULL == rhs) + return 1; + + vhdl_decl *decl = proc->get_parent()->get_decl(signame); + assert(decl); + + vhdl_type *lval_type = decl->get_type()->clone(); + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, lval_type); + + // TODO: Internal sanity check: + // ensure rhs->get_type() == lval_type + + proc->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); + } + else { + error("Only signals as lvals supported at the moment"); + return 1; + } + return 0; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 2411be773..a3b499a95 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -343,6 +343,15 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const of << "wait;"; } +/* + * Create a deep copy of this type, so it can appear in more + * than one place in the AST. + */ +vhdl_type *vhdl_scalar_type::clone() const +{ + return new vhdl_scalar_type(name_.c_str()); +} + vhdl_scalar_type *vhdl_scalar_type::std_logic() { return new vhdl_scalar_type("std_logic"); diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 0a44e9a6d..28d38b6bf 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -54,6 +54,8 @@ public: vhdl_type(const char *name) : name_(name) {} virtual ~vhdl_type() {} + virtual vhdl_type *clone() const = 0; + const std::string &get_name() const { return name_; } protected: std::string name_; @@ -70,6 +72,7 @@ public: : vhdl_type(name) {} void emit(std::ofstream &of, int level) const; + vhdl_type *clone() const; // Common types static vhdl_scalar_type *std_logic(); @@ -179,7 +182,7 @@ public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : lhs_(lhs), rhs_(rhs) {} - void emit(std::ofstream &of, int level); + void emit(std::ofstream &of, int level) const; private: vhdl_var_ref *lhs_; vhdl_expr *rhs_; From 1e4b96aa0adf275b12491925dc8f864bcd902239 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 14:57:20 +0100 Subject: [PATCH 041/377] Simplify code a bit as rval type is never needed --- tgt-vhdl/stmt.cc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 636c4f283..edb18d585 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -167,15 +167,9 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) vhdl_expr *rhs = translate_expr(ivl_stmt_rval(stmt)); if (NULL == rhs) return 1; - - vhdl_decl *decl = proc->get_parent()->get_decl(signame); - assert(decl); - - vhdl_type *lval_type = decl->get_type()->clone(); - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, lval_type); - - // TODO: Internal sanity check: - // ensure rhs->get_type() == lval_type + + // The type here can be null as it is never actually needed + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); proc->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); } From fbf85398da7db7f9ac7e4651373636f2cff67694 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 16:19:10 +0100 Subject: [PATCH 042/377] Support converting bit strings to std_logic --- tgt-vhdl/expr.cc | 10 +++++ tgt-vhdl/scope.cc | 11 ++++-- tgt-vhdl/stmt.cc | 6 ++- tgt-vhdl/vhdl_element.cc | 83 +++++++++++++++++++++++++++++++++++----- tgt-vhdl/vhdl_element.hh | 41 ++++++++++++++++++-- 5 files changed, 135 insertions(+), 16 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 80b9a05bc..b208700c8 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -47,6 +47,14 @@ static vhdl_expr *translate_signal(ivl_expr_t e) return new vhdl_var_ref(ivl_signal_basename(sig), type); } +/* + * A numeric literal ends up as std_logic bit string. + */ +static vhdl_expr *translate_number(ivl_expr_t e) +{ + return new vhdl_const_bits(ivl_expr_bits(e)); +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -59,6 +67,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_string(e); case IVL_EX_SIGNAL: return translate_signal(e); + case IVL_EX_NUMBER: + return translate_number(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 4c9f46a08..d804e67dd 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -33,10 +33,15 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - vhdl_scalar_type *std_logic = - new vhdl_scalar_type("std_logic"); + + int width = ivl_signal_width(sig); + vhdl_type *sig_type; + if (width > 0) + sig_type = vhdl_scalar_type::std_logic(); + else + sig_type = vhdl_vector_type::std_logic_vector(width-1, 0); vhdl_signal_decl *decl = - new vhdl_signal_decl(ivl_signal_basename(sig), std_logic); + new vhdl_signal_decl(ivl_signal_basename(sig), sig_type); arch->add_decl(decl); } } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index edb18d585..fb4e071fc 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -164,7 +164,11 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) if ((sig = ivl_lval_sig(lval))) { const char *signame = ivl_signal_basename(sig); - vhdl_expr *rhs = translate_expr(ivl_stmt_rval(stmt)); + vhdl_decl *decl = proc->get_parent()->get_decl(signame); + assert(decl); + + vhdl_expr *rhs = + decl->get_type()->cast(translate_expr(ivl_stmt_rval(stmt))); if (NULL == rhs) return 1; diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index a3b499a95..211102aef 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -343,15 +344,6 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const of << "wait;"; } -/* - * Create a deep copy of this type, so it can appear in more - * than one place in the AST. - */ -vhdl_type *vhdl_scalar_type::clone() const -{ - return new vhdl_scalar_type(name_.c_str()); -} - vhdl_scalar_type *vhdl_scalar_type::std_logic() { return new vhdl_scalar_type("std_logic"); @@ -372,6 +364,55 @@ void vhdl_scalar_type::emit(std::ofstream &of, int level) const of << name_; } +/* + * Cast something to a scalar type. There are a few ugly hacks here + * to handle special cases. + */ +vhdl_expr *vhdl_scalar_type::cast(vhdl_expr *expr) const +{ + if (typeid(*expr) == typeid(vhdl_const_bits) + && name_ == "std_logic") { + + // Converting a literal bit string to std_logic is fairly + // common so this hack is justified by the increase in + // output readability :-) + + const std::string &value = + dynamic_cast(expr)->get_value(); + + // Take the least significant bit + char lsb = value[0]; + + // Discard the given expression and return a brand new one + delete expr; + return new vhdl_const_bit(lsb); + } + else { + // Otherwise just assume there's a pre-defined conversion + const char *c_name = name_.c_str(); + vhdl_fcall *conv = + new vhdl_fcall(c_name, new vhdl_scalar_type(c_name)); + conv->add_expr(expr); + + return conv; + } +} + +vhdl_vector_type *vhdl_vector_type::std_logic_vector(int msb, int lsb) +{ + return new vhdl_vector_type("std_logic_vector", msb, lsb); +} + +void vhdl_vector_type::emit(std::ofstream &of, int level) const +{ + of << name_ << "(" << msb_ << " downto " << lsb_ << ")"; +} + +vhdl_expr *vhdl_vector_type::cast(vhdl_expr *expr) const +{ + return expr; +} + vhdl_var_decl::~vhdl_var_decl() { delete type_; @@ -467,3 +508,27 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const rhs_->emit(of, level); of << ";"; } + +vhdl_const_bits::vhdl_const_bits(const char *value) + : vhdl_expr(vhdl_vector_type::std_logic_vector(strlen(value)-1, 0)), + value_(value) +{ + +} + +void vhdl_const_bits::emit(std::ofstream &of, int level) const +{ + of << "std_logic_vector'(\""; + + // The bits appear to be in reverse order + std::string::const_reverse_iterator it; + for (it = value_.rbegin(); it != value_.rend(); ++it) + of << *it; + + of << "\")"; +} + +void vhdl_const_bit::emit(std::ofstream &of, int level) const +{ + of << "'" << bit_ << "'"; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 28d38b6bf..dd5b27129 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -27,6 +27,7 @@ class vhdl_entity; class vhdl_arch; +class vhdl_expr; typedef std::list string_list_t; @@ -54,7 +55,7 @@ public: vhdl_type(const char *name) : name_(name) {} virtual ~vhdl_type() {} - virtual vhdl_type *clone() const = 0; + virtual vhdl_expr *cast(vhdl_expr *expr) const = 0; const std::string &get_name() const { return name_; } protected: @@ -72,14 +73,31 @@ public: : vhdl_type(name) {} void emit(std::ofstream &of, int level) const; - vhdl_type *clone() const; - + vhdl_expr *cast(vhdl_expr *expr) const; + // Common types static vhdl_scalar_type *std_logic(); static vhdl_scalar_type *string(); static vhdl_scalar_type *line(); }; +/* + * A vector type like std_logic_vector. + */ +class vhdl_vector_type : public vhdl_type { +public: + vhdl_vector_type(const char *name, int msb, int lsb) + : vhdl_type(name), msb_(msb), lsb_(lsb) {} + + void emit(std::ofstream &of, int level) const; + vhdl_expr *cast(vhdl_expr *expr) const; + + // Common types + static vhdl_vector_type *std_logic_vector(int msb, int lsb); +private: + int msb_, lsb_; +}; + class vhdl_expr : public vhdl_element { public: vhdl_expr(vhdl_type* type) : type_(type) {} @@ -115,6 +133,23 @@ private: std::string value_; }; +class vhdl_const_bits : public vhdl_expr { +public: + vhdl_const_bits(const char *value); + void emit(std::ofstream &of, int level) const; + const std::string &get_value() const { return value_; } +private: + std::string value_; +}; + +class vhdl_const_bit : public vhdl_expr { +public: + vhdl_const_bit(char bit) + : vhdl_expr(vhdl_scalar_type::std_logic()), bit_(bit) {} + void emit(std::ofstream &of, int level) const; +private: + char bit_; +}; class vhdl_expr_list : public vhdl_element { public: From 79558910d1c9f3c55f06f8ebd4bb9eb303b9817f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 7 Jun 2008 16:44:01 +0100 Subject: [PATCH 043/377] Catch case where NULL return wasn't detected --- tgt-vhdl/stmt.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fb4e071fc..9d4fa789a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -166,11 +166,11 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) vhdl_decl *decl = proc->get_parent()->get_decl(signame); assert(decl); - - vhdl_expr *rhs = - decl->get_type()->cast(translate_expr(ivl_stmt_rval(stmt))); - if (NULL == rhs) + + vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); + if (NULL == rhs_raw) return 1; + vhdl_expr *rhs = decl->get_type()->cast(rhs_raw); // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); From 110a1b2ac7f36d4a34d97e5cbf5c4cb2ec6bb31a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 8 Jun 2008 12:48:56 +0100 Subject: [PATCH 044/377] Replace type classes with enumeration --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/scope.cc | 4 +-- tgt-vhdl/stmt.cc | 17 +++++----- tgt-vhdl/vhdl_element.cc | 73 +++++++++++++++++++++++++++------------- tgt-vhdl/vhdl_element.hh | 57 +++++++++++++------------------ 5 files changed, 84 insertions(+), 69 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index b208700c8..29f1d312c 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -42,7 +42,7 @@ static vhdl_expr *translate_signal(ivl_expr_t e) ivl_signal_t sig = ivl_expr_signal(e); // Assume all signals are single bits at the moment - vhdl_type *type = vhdl_scalar_type::std_logic(); + vhdl_type *type = vhdl_type::std_logic(); return new vhdl_var_ref(ivl_signal_basename(sig), type); } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d804e67dd..b6f19d57a 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -37,9 +37,9 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) int width = ivl_signal_width(sig); vhdl_type *sig_type; if (width > 0) - sig_type = vhdl_scalar_type::std_logic(); + sig_type = vhdl_type::std_logic(); else - sig_type = vhdl_vector_type::std_logic_vector(width-1, 0); + sig_type = vhdl_type::std_logic_vector(width-1, 0); vhdl_signal_decl *decl = new vhdl_signal_decl(ivl_signal_basename(sig), sig_type); arch->add_decl(decl); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 9d4fa789a..51f3b113c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -45,9 +45,8 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) const char *display_line = "Verilog_Display_Line"; if (!proc->have_declared_var(display_line)) { - vhdl_type *line_type = new vhdl_scalar_type("Line"); vhdl_var_decl *line_var = - new vhdl_var_decl(display_line, line_type); + new vhdl_var_decl(display_line, vhdl_type::line()); line_var->set_comment("For generating $display output"); proc->add_decl(line_var); } @@ -67,12 +66,12 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // Need to add a call to Type'Image for types not // supported by std.textio - if (base->get_type()->get_name() != "String") { - std::string name(base->get_type()->get_name()); + if (base->get_type()->get_name() != VHDL_TYPE_STRING) { + std::string name(base->get_type()->get_string()); name += "'Image"; vhdl_fcall *cast - = new vhdl_fcall(name.c_str(), vhdl_scalar_type::string()); + = new vhdl_fcall(name.c_str(), vhdl_type::string()); cast->add_expr(base); e = cast; } @@ -84,7 +83,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); vhdl_var_ref *ref = - new vhdl_var_ref(display_line, vhdl_scalar_type::line()); + new vhdl_var_ref(display_line, vhdl_type::line()); write->add_expr(ref); write->add_expr(e); @@ -94,10 +93,10 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) // WriteLine(Output, Verilog_Display_Line) vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); vhdl_var_ref *output_ref = - new vhdl_var_ref("std.textio.Output", new vhdl_scalar_type("File")); + new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE)); write_line->add_expr(output_ref); vhdl_var_ref *ref = - new vhdl_var_ref(display_line, vhdl_scalar_type::line()); + new vhdl_var_ref(display_line, vhdl_type::line()); write_line->add_expr(ref); proc->add_stmt(write_line); @@ -170,7 +169,7 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); if (NULL == rhs_raw) return 1; - vhdl_expr *rhs = decl->get_type()->cast(rhs_raw); + vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 211102aef..fdc47b76f 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -25,6 +25,7 @@ #include #include #include +#include static const int VHDL_INDENT = 2; // Spaces to indent @@ -344,31 +345,67 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const of << "wait;"; } -vhdl_scalar_type *vhdl_scalar_type::std_logic() +vhdl_type *vhdl_type::std_logic() { - return new vhdl_scalar_type("std_logic"); + return new vhdl_type(VHDL_TYPE_STD_LOGIC); } -vhdl_scalar_type *vhdl_scalar_type::string() +vhdl_type *vhdl_type::string() { - return new vhdl_scalar_type("String"); + return new vhdl_type(VHDL_TYPE_STRING); } -vhdl_scalar_type *vhdl_scalar_type::line() +vhdl_type *vhdl_type::line() { - return new vhdl_scalar_type("Line"); + return new vhdl_type(VHDL_TYPE_LINE); } -void vhdl_scalar_type::emit(std::ofstream &of, int level) const +std::string vhdl_type::get_string() const { - of << name_; + switch (name_) { + case VHDL_TYPE_STD_LOGIC: + return std::string("std_logic"); + case VHDL_TYPE_STD_LOGIC_VECTOR: + { + std::ostringstream ss; + ss << "std_logic_vector(" << msb_; + ss << " downto " << lsb_ << ")"; + return ss.str(); + } + case VHDL_TYPE_STRING: + return std::string("String"); + case VHDL_TYPE_LINE: + return std::string("Line"); + case VHDL_TYPE_FILE: + return std::string("File"); + default: + return std::string("BadType"); + } +} + +void vhdl_type::emit(std::ofstream &of, int level) const +{ + of << get_string(); +} + +/* + * 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) +{ + vhdl_fcall *conv = + new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); + conv->add_expr(this); + + return conv; } /* * Cast something to a scalar type. There are a few ugly hacks here * to handle special cases. */ -vhdl_expr *vhdl_scalar_type::cast(vhdl_expr *expr) const +/*vhdl_expr *vhdl_scalar_type::cast(vhdl_expr *expr) const { if (typeid(*expr) == typeid(vhdl_const_bits) && name_ == "std_logic") { @@ -396,21 +433,11 @@ vhdl_expr *vhdl_scalar_type::cast(vhdl_expr *expr) const return conv; } -} + }*/ -vhdl_vector_type *vhdl_vector_type::std_logic_vector(int msb, int lsb) +vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) { - return new vhdl_vector_type("std_logic_vector", msb, lsb); -} - -void vhdl_vector_type::emit(std::ofstream &of, int level) const -{ - of << name_ << "(" << msb_ << " downto " << lsb_ << ")"; -} - -vhdl_expr *vhdl_vector_type::cast(vhdl_expr *expr) const -{ - return expr; + return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); } vhdl_var_decl::~vhdl_var_decl() @@ -510,7 +537,7 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const } vhdl_const_bits::vhdl_const_bits(const char *value) - : vhdl_expr(vhdl_vector_type::std_logic_vector(strlen(value)-1, 0)), + : vhdl_expr(vhdl_type::std_logic_vector(strlen(value)-1, 0)), value_(value) { diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index dd5b27129..5454fd6ed 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -50,16 +50,13 @@ private: typedef std::list element_list_t; -class vhdl_type : public vhdl_element { -public: - vhdl_type(const char *name) : name_(name) {} - virtual ~vhdl_type() {} - virtual vhdl_expr *cast(vhdl_expr *expr) const = 0; - - const std::string &get_name() const { return name_; } -protected: - std::string name_; +enum vhdl_type_name_t { + VHDL_TYPE_STD_LOGIC, + VHDL_TYPE_STD_LOGIC_VECTOR, + VHDL_TYPE_STRING, + VHDL_TYPE_LINE, + VHDL_TYPE_FILE }; /* @@ -67,43 +64,35 @@ protected: * too much more complex, as Verilog's type system is much * simpler than VHDL's. */ -class vhdl_scalar_type : public vhdl_type { +class vhdl_type : public vhdl_element { public: - vhdl_scalar_type(const char *name) - : vhdl_type(name) {} + vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0) + : name_(name), msb_(msb), lsb_(lsb) {} + virtual ~vhdl_type() {} void emit(std::ofstream &of, int level) const; - vhdl_expr *cast(vhdl_expr *expr) const; + vhdl_type_name_t get_name() const { return name_; } + std::string get_string() const; + int get_width() const { return msb_ - lsb_ + 1; } // Common types - static vhdl_scalar_type *std_logic(); - static vhdl_scalar_type *string(); - static vhdl_scalar_type *line(); -}; - -/* - * A vector type like std_logic_vector. - */ -class vhdl_vector_type : public vhdl_type { -public: - vhdl_vector_type(const char *name, int msb, int lsb) - : vhdl_type(name), msb_(msb), lsb_(lsb) {} - - void emit(std::ofstream &of, int level) const; - vhdl_expr *cast(vhdl_expr *expr) const; - - // Common types - static vhdl_vector_type *std_logic_vector(int msb, int lsb); -private: + static vhdl_type *std_logic(); + static vhdl_type *string(); + static vhdl_type *line(); + static vhdl_type *std_logic_vector(int msb, int lsb); +protected: + vhdl_type_name_t name_; int msb_, lsb_; }; + class vhdl_expr : public vhdl_element { public: vhdl_expr(vhdl_type* type) : type_(type) {} virtual ~vhdl_expr(); const vhdl_type *get_type() const { return type_; } + virtual vhdl_expr *cast(const vhdl_type *to); private: vhdl_type *type_; }; @@ -126,7 +115,7 @@ private: class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) - : vhdl_expr(vhdl_scalar_type::string()), value_(value) {} + : vhdl_expr(vhdl_type::string()), value_(value) {} void emit(std::ofstream &of, int level) const; private: @@ -145,7 +134,7 @@ private: class vhdl_const_bit : public vhdl_expr { public: vhdl_const_bit(char bit) - : vhdl_expr(vhdl_scalar_type::std_logic()), bit_(bit) {} + : vhdl_expr(vhdl_type::std_logic()), bit_(bit) {} void emit(std::ofstream &of, int level) const; private: char bit_; From 4b4a1c6cac77d4b64b820554a751c4da8b803139 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 8 Jun 2008 12:55:18 +0100 Subject: [PATCH 045/377] Tidy up type casting --- tgt-vhdl/vhdl_element.cc | 76 +++++++++++++++------------------------- tgt-vhdl/vhdl_element.hh | 1 + 2 files changed, 30 insertions(+), 47 deletions(-) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index fdc47b76f..216d04d16 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -388,53 +388,6 @@ void vhdl_type::emit(std::ofstream &of, int level) const of << get_string(); } -/* - * 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) -{ - vhdl_fcall *conv = - new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); - conv->add_expr(this); - - return conv; -} - -/* - * Cast something to a scalar type. There are a few ugly hacks here - * to handle special cases. - */ -/*vhdl_expr *vhdl_scalar_type::cast(vhdl_expr *expr) const -{ - if (typeid(*expr) == typeid(vhdl_const_bits) - && name_ == "std_logic") { - - // Converting a literal bit string to std_logic is fairly - // common so this hack is justified by the increase in - // output readability :-) - - const std::string &value = - dynamic_cast(expr)->get_value(); - - // Take the least significant bit - char lsb = value[0]; - - // Discard the given expression and return a brand new one - delete expr; - return new vhdl_const_bit(lsb); - } - else { - // Otherwise just assume there's a pre-defined conversion - const char *c_name = name_.c_str(); - vhdl_fcall *conv = - new vhdl_fcall(c_name, new vhdl_scalar_type(c_name)); - conv->add_expr(expr); - - return conv; - } - }*/ - vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) { return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); @@ -471,6 +424,19 @@ 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) +{ + vhdl_fcall *conv = + new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); + conv->add_expr(this); + + return conv; +} + void vhdl_expr_list::add_expr(vhdl_expr *e) { exprs_.push_back(e); @@ -543,6 +509,22 @@ vhdl_const_bits::vhdl_const_bits(const char *value) } +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 + return vhdl_expr::cast(to); +} + void vhdl_const_bits::emit(std::ofstream &of, int level) const { of << "std_logic_vector'(\""; diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 5454fd6ed..c657039f4 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -127,6 +127,7 @@ public: vhdl_const_bits(const char *value); void emit(std::ofstream &of, int level) const; const std::string &get_value() const { return value_; } + vhdl_expr *cast(const vhdl_type *to); private: std::string value_; }; From 1d28b935e8612c85f96d472af901c4acbfb1da38 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 8 Jun 2008 13:27:48 +0100 Subject: [PATCH 046/377] Split vhdl_element.cc into multiple files --- tgt-vhdl/Makefile.in | 3 +- tgt-vhdl/vhdl_element.cc | 475 +-------------------------------------- tgt-vhdl/vhdl_element.hh | 359 +---------------------------- tgt-vhdl/vhdl_helper.hh | 54 +++++ tgt-vhdl/vhdl_syntax.cc | 419 ++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 345 ++++++++++++++++++++++++++++ tgt-vhdl/vhdl_target.h | 3 +- tgt-vhdl/vhdl_type.cc | 72 ++++++ tgt-vhdl/vhdl_type.hh | 60 +++++ 9 files changed, 961 insertions(+), 829 deletions(-) create mode 100644 tgt-vhdl/vhdl_helper.hh create mode 100644 tgt-vhdl/vhdl_syntax.cc create mode 100644 tgt-vhdl/vhdl_syntax.hh create mode 100644 tgt-vhdl/vhdl_type.cc create mode 100644 tgt-vhdl/vhdl_type.hh diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index c63aa9134..0eb413ff6 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -49,7 +49,8 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vhdl.o vhdl_element.o scope.o process.o stmt.o expr.o +O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ + stmt.o expr.o \ ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 216d04d16..5391736f7 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -30,7 +30,7 @@ static const int VHDL_INDENT = 2; // Spaces to indent -static int indent(int level) +int indent(int level) { return level + VHDL_INDENT; } @@ -38,46 +38,19 @@ static int indent(int level) /* * Emit a newline and indent to the correct level. */ -static void newline(std::ofstream &of, int level) +void newline(std::ofstream &of, int level) { of << std::endl; while (level--) of << ' '; } -static void blank_line(std::ofstream &of, int level) +void blank_line(std::ofstream &of, int level) { of << std::endl; newline(of, level); } -template -void emit_children(std::ofstream &of, - const std::list &children, - int level) -{ - // Don't indent if there are no children - if (children.size() == 0) - newline(of, level); - else { - typename std::list::const_iterator it; - for (it = children.begin(); it != children.end(); ++it) { - newline(of, indent(level)); - (*it)->emit(of, indent(level)); - } - newline(of, level); - } -} - -template -void delete_children(std::list &children) -{ - typename std::list::iterator it; - for (it = children.begin(); it != children.end(); ++it) - delete *it; - children.clear(); -} - void vhdl_element::set_comment(std::string comment) { comment_ = comment; @@ -99,445 +72,3 @@ void vhdl_element::emit_comment(std::ofstream &of, int level, newline(of, level); } } - -vhdl_entity::vhdl_entity(const char *name, const char *derived_from, - vhdl_arch *arch) - : name_(name), arch_(arch), derived_from_(derived_from) -{ - arch->parent_ = this; -} - -vhdl_entity::~vhdl_entity() -{ - delete arch_; -} - -/* - * Add a package to the list of `use' statements before - * the entity. - */ -void vhdl_entity::requires_package(const char *spec) -{ - std::string pname(spec); - std::list::iterator it; - for (it = uses_.begin(); it != uses_.end(); ++it) { - if (*it == pname) - return; - } - uses_.push_back(spec); -} - -void vhdl_entity::emit(std::ofstream &of, int level) const -{ - // Pretty much every design will use std_logic so we - // might as well include it by default - of << "library ieee;" << std::endl; - of << "use ieee.std_logic_1164.all;" << std::endl; - - for (std::list::const_iterator it = uses_.begin(); - it != uses_.end(); - ++it) - of << "use " << *it << ".all;" << std::endl; - of << std::endl; - - emit_comment(of, level); - of << "entity " << name_ << " is"; - // ...ports... - // newline(indent(level)); - newline(of, level); - of << "end entity; "; - blank_line(of, level); // Extra blank line after entities - arch_->emit(of, level); -} - -vhdl_arch::vhdl_arch(const char *entity, const char *name) - : parent_(NULL), name_(name), entity_(entity) -{ - -} - -vhdl_arch::~vhdl_arch() -{ - delete_children(stmts_); - delete_children(decls_); -} - -void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) -{ - stmt->parent_ = this; - stmts_.push_back(stmt); -} - -void vhdl_arch::add_decl(vhdl_decl *decl) -{ - decls_.push_back(decl); -} - -vhdl_entity *vhdl_arch::get_parent() const -{ - assert(parent_); - return parent_; -} - -void vhdl_arch::emit(std::ofstream &of, int level) const -{ - emit_comment(of, level); - of << "architecture " << name_ << " of " << entity_; - of << " is"; - emit_children(of, decls_, level); - of << "begin"; - emit_children(of, stmts_, level); - of << "end architecture;"; - blank_line(of, level); // Extra blank line after architectures; -} - -vhdl_decl *vhdl_arch::get_decl(const std::string &name) const -{ - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return *it; - } - return NULL; -} - -/* - * True if component `name' has already been declared in this - * architecture. This is a bit of hack, since it uses typeid - * to distinguish between components and other declarations. - */ -bool vhdl_arch::have_declared_component(const std::string &name) const -{ - std::string comp_typename(typeid(vhdl_component_decl).name()); - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if (comp_typename == typeid(**it).name() - && (*it)->get_name() == name) - return true; - } - return false; -} - -/* - * True if any declaration of `name' has been added to the - * architecture. - */ -bool vhdl_arch::have_declared(const std::string &name) const -{ - return get_decl(name) != NULL; -} - -vhdl_arch *vhdl_conc_stmt::get_parent() const -{ - assert(parent_); - return parent_; -} - -vhdl_process::vhdl_process(const char *name) - : name_(name) -{ - -} - -vhdl_process::~vhdl_process() -{ - delete_children(stmts_); - delete_children(decls_); -} - -void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) -{ - stmts_.push_back(stmt); -} - -void vhdl_process::add_decl(vhdl_decl* decl) -{ - decls_.push_back(decl); -} - -void vhdl_process::add_sensitivity(const char *name) -{ - sens_.push_back(name); -} - -bool vhdl_process::have_declared_var(const std::string &name) const -{ - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return true; - } - return false; -} - -void vhdl_process::emit(std::ofstream &of, int level) const -{ - emit_comment(of, level); - if (name_.size() > 0) - of << name_ << ": "; - of << "process "; - - int num_sens = sens_.size(); - if (num_sens > 0) { - of << "("; - string_list_t::const_iterator it; - for (it = sens_.begin(); it != sens_.end(); ++it) { - of << *it; - if (--num_sens > 0) - of << ", "; - } - of << ") "; - } - - of << "is"; - emit_children(of, decls_, level); - of << "begin"; - emit_children(of, stmts_, level); - of << "end process;"; - newline(of, level); -} - -vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) - : comp_name_(comp_name), inst_name_(inst_name) -{ - -} - -void vhdl_comp_inst::emit(std::ofstream &of, int level) const -{ - // If there are no ports or generics we don't need to mention them... - emit_comment(of, level); - of << inst_name_ << ": " << comp_name_ << ";"; - newline(of, level); -} - -vhdl_component_decl::vhdl_component_decl(const char *name) - : vhdl_decl(name) -{ - -} - -/* - * Create a component declaration for the given entity. - */ -vhdl_component_decl *vhdl_component_decl::component_decl_for(const vhdl_entity *ent) -{ - assert(ent != NULL); - - vhdl_component_decl *decl = new vhdl_component_decl - (ent->get_name().c_str()); - - return decl; -} - -void vhdl_component_decl::emit(std::ofstream &of, int level) const -{ - emit_comment(of, level); - of << "component " << name_ << " is"; - // ...ports... - newline(of, level); - of << "end component;"; -} - -void vhdl_wait_stmt::emit(std::ofstream &of, int level) const -{ - // TODO: There are lots of different types of `wait' - of << "wait;"; -} - -vhdl_type *vhdl_type::std_logic() -{ - return new vhdl_type(VHDL_TYPE_STD_LOGIC); -} - -vhdl_type *vhdl_type::string() -{ - return new vhdl_type(VHDL_TYPE_STRING); -} - -vhdl_type *vhdl_type::line() -{ - return new vhdl_type(VHDL_TYPE_LINE); -} - -std::string vhdl_type::get_string() const -{ - switch (name_) { - case VHDL_TYPE_STD_LOGIC: - return std::string("std_logic"); - case VHDL_TYPE_STD_LOGIC_VECTOR: - { - std::ostringstream ss; - ss << "std_logic_vector(" << msb_; - ss << " downto " << lsb_ << ")"; - return ss.str(); - } - case VHDL_TYPE_STRING: - return std::string("String"); - case VHDL_TYPE_LINE: - return std::string("Line"); - case VHDL_TYPE_FILE: - return std::string("File"); - default: - return std::string("BadType"); - } -} - -void vhdl_type::emit(std::ofstream &of, int level) const -{ - of << get_string(); -} - -vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) -{ - return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); -} - -vhdl_var_decl::~vhdl_var_decl() -{ - delete type_; -} - -void vhdl_var_decl::emit(std::ofstream &of, int level) const -{ - of << "variable " << name_ << " : "; - type_->emit(of, level); - of << ";"; - emit_comment(of, level, true); -} - -vhdl_signal_decl::~vhdl_signal_decl() -{ - delete type_; -} - -void vhdl_signal_decl::emit(std::ofstream &of, int level) const -{ - of << "signal " << name_ << " : "; - type_->emit(of, level); - of << ";"; - emit_comment(of, level, true); -} - -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) -{ - vhdl_fcall *conv = - new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); - conv->add_expr(this); - - return conv; -} - -void vhdl_expr_list::add_expr(vhdl_expr *e) -{ - exprs_.push_back(e); -} - -vhdl_expr_list::~vhdl_expr_list() -{ - delete_children(exprs_); -} - -void vhdl_expr_list::emit(std::ofstream &of, int level) const -{ - of << "("; - - int size = exprs_.size(); - std::list::const_iterator it; - for (it = exprs_.begin(); it != exprs_.end(); ++it) { - (*it)->emit(of, level); - if (--size > 0) - of << ", "; - } - - of << ")"; -} - -void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const -{ - of << name_; - exprs_.emit(of, level); - of << ";"; -} - -void vhdl_var_ref::emit(std::ofstream &of, int level) const -{ - of << name_; -} - -void vhdl_const_string::emit(std::ofstream &of, int level) const -{ - // In some instances a string literal can be ambiguous between - // a String type and some other types (e.g. std_logic_vector) - // The explicit cast to String removes this ambiguity (although - // isn't always strictly necessary) - of << "String'(\"" << value_ << "\")"; -} - -void vhdl_null_stmt::emit(std::ofstream &of, int level) const -{ - of << "null;"; -} - -void vhdl_fcall::emit(std::ofstream &of, int level) const -{ - of << name_; - exprs_.emit(of, level); -} - -void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const -{ - lhs_->emit(of, level); - of << " <= "; - rhs_->emit(of, level); - of << ";"; -} - -vhdl_const_bits::vhdl_const_bits(const char *value) - : vhdl_expr(vhdl_type::std_logic_vector(strlen(value)-1, 0)), - value_(value) -{ - -} - -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 - return vhdl_expr::cast(to); -} - -void vhdl_const_bits::emit(std::ofstream &of, int level) const -{ - of << "std_logic_vector'(\""; - - // The bits appear to be in reverse order - std::string::const_reverse_iterator it; - for (it = value_.rbegin(); it != value_.rend(); ++it) - of << *it; - - of << "\")"; -} - -void vhdl_const_bit::emit(std::ofstream &of, int level) const -{ - of << "'" << bit_ << "'"; -} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index c657039f4..f73ea0949 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -25,10 +25,6 @@ #include #include -class vhdl_entity; -class vhdl_arch; -class vhdl_expr; - typedef std::list string_list_t; /* @@ -48,358 +44,11 @@ private: std::string comment_; }; -typedef std::list element_list_t; - - -enum vhdl_type_name_t { - VHDL_TYPE_STD_LOGIC, - VHDL_TYPE_STD_LOGIC_VECTOR, - VHDL_TYPE_STRING, - VHDL_TYPE_LINE, - VHDL_TYPE_FILE -}; - -/* - * A type at the moment is just a name. It shouldn't get - * too much more complex, as Verilog's type system is much - * simpler than VHDL's. - */ -class vhdl_type : public vhdl_element { -public: - vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0) - : name_(name), msb_(msb), lsb_(lsb) {} - virtual ~vhdl_type() {} - - void emit(std::ofstream &of, int level) const; - vhdl_type_name_t get_name() const { return name_; } - std::string get_string() const; - int get_width() const { return msb_ - lsb_ + 1; } - - // Common types - static vhdl_type *std_logic(); - static vhdl_type *string(); - static vhdl_type *line(); - static vhdl_type *std_logic_vector(int msb, int lsb); -protected: - vhdl_type_name_t name_; - int msb_, lsb_; -}; - - -class vhdl_expr : public vhdl_element { -public: - vhdl_expr(vhdl_type* type) : type_(type) {} - virtual ~vhdl_expr(); - - const vhdl_type *get_type() const { return type_; } - virtual vhdl_expr *cast(const vhdl_type *to); -private: - vhdl_type *type_; -}; - - -/* - * A normal scalar variable reference. - */ -class vhdl_var_ref : public vhdl_expr { -public: - vhdl_var_ref(const char *name, vhdl_type *type) - : vhdl_expr(type), name_(name) {} - - void emit(std::ofstream &of, int level) const; -private: - std::string name_; -}; - - -class vhdl_const_string : public vhdl_expr { -public: - vhdl_const_string(const char *value) - : vhdl_expr(vhdl_type::string()), value_(value) {} - - void emit(std::ofstream &of, int level) const; -private: - std::string value_; -}; - -class vhdl_const_bits : public vhdl_expr { -public: - vhdl_const_bits(const char *value); - void emit(std::ofstream &of, int level) const; - const std::string &get_value() const { return value_; } - vhdl_expr *cast(const vhdl_type *to); -private: - std::string value_; -}; - -class vhdl_const_bit : public vhdl_expr { -public: - vhdl_const_bit(char bit) - : vhdl_expr(vhdl_type::std_logic()), bit_(bit) {} - void emit(std::ofstream &of, int level) const; -private: - char bit_; -}; - -class vhdl_expr_list : public vhdl_element { -public: - ~vhdl_expr_list(); - - void emit(std::ofstream &of, int level) const; - void add_expr(vhdl_expr *e); -private: - std::list exprs_; -}; - - -/* - * A function call within an expression. - */ -class vhdl_fcall : public vhdl_expr { -public: - vhdl_fcall(const char *name, vhdl_type *rtype) - : vhdl_expr(rtype), name_(name) {}; - ~vhdl_fcall() {} - - void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } - void emit(std::ofstream &of, int level) const; -private: - std::string name_; - vhdl_expr_list exprs_; -}; - - -/* - * A concurrent statement appears in architecture bodies but not - * processes. - */ -class vhdl_conc_stmt : public vhdl_element { - friend class vhdl_arch; // Can set its parent -public: - vhdl_conc_stmt() : parent_(NULL) {} - virtual ~vhdl_conc_stmt() {} - - vhdl_arch *get_parent() const; -private: - vhdl_arch *parent_; -}; - -typedef std::list conc_stmt_list_t; - - -/* - * Any sequential statement in a process. - */ -class vhdl_seq_stmt : public vhdl_element { -public: - virtual ~vhdl_seq_stmt() {} -}; - -typedef std::list seq_stmt_list_t; - - -/* - * Similar to Verilog non-blocking assignment, except the LHS - * must be a signal not a variable. - */ -class vhdl_nbassign_stmt : public vhdl_seq_stmt { -public: - vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) - : lhs_(lhs), rhs_(rhs) {} - - void emit(std::ofstream &of, int level) const; -private: - vhdl_var_ref *lhs_; - vhdl_expr *rhs_; -}; - -/* - * Delay simulation indefinitely, until an event, or for a - * specified time. - */ -class vhdl_wait_stmt : public vhdl_seq_stmt { -public: - void emit(std::ofstream &of, int level) const; -}; - - -class vhdl_null_stmt : public vhdl_seq_stmt { -public: - void emit(std::ofstream &of, int level) const; -}; - - -/* - * A procedure call. Which is a statement, unlike a function - * call which is an expression. - */ -class vhdl_pcall_stmt : public vhdl_seq_stmt { -public: - vhdl_pcall_stmt(const char *name) : name_(name) {} - - void emit(std::ofstream &of, int level) const; - void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } -private: - std::string name_; - vhdl_expr_list exprs_; -}; - - -/* - * A declaration of some sort (variable, component, etc.). - * Declarations have names, which is the identifier of the variable, - * constant, etc. not the type. - */ -class vhdl_decl : public vhdl_element { -public: - vhdl_decl(const char *name, vhdl_type *type=NULL) - : name_(name), type_(type) {} - virtual ~vhdl_decl() {}; - - const std::string &get_name() const { return name_; } - const vhdl_type *get_type() const { return type_; } -protected: - std::string name_; - vhdl_type *type_; -}; - -typedef std::list decl_list_t; - - -/* - * A forward declaration of a component. At the moment it is assumed - * that components declarations will only ever be for entities - * generated by this code generator. This is enforced by making the - * constructor private (use component_decl_for instead). - */ -class vhdl_component_decl : public vhdl_decl { -public: - virtual ~vhdl_component_decl() {}; - - static vhdl_component_decl *component_decl_for(const vhdl_entity *ent); - - void emit(std::ofstream &of, int level) const; -private: - vhdl_component_decl(const char *name); - - // TODO: Ports, etc. -}; - - -/* - * A variable declaration inside a process (although this isn't - * enforced here). - */ -class vhdl_var_decl : public vhdl_decl { -public: - vhdl_var_decl(const char *name, vhdl_type *type) - : vhdl_decl(name, type) {} - ~vhdl_var_decl(); - - void emit(std::ofstream &of, int level) const; -}; - - -/* - * A signal declaration in architecture. - */ -class vhdl_signal_decl : public vhdl_decl { -public: - vhdl_signal_decl(const char *name, vhdl_type *type) - : vhdl_decl(name, type) {} - ~vhdl_signal_decl(); - - void emit(std::ofstream &of, int level) const; -}; - - -/* - * Instantiation of component. This is really only a placeholder - * at the moment until the port mappings are worked out. - */ -class vhdl_comp_inst : public vhdl_conc_stmt { -public: - vhdl_comp_inst(const char *inst_name, const char *comp_name); - virtual ~vhdl_comp_inst() {} - - void emit(std::ofstream &of, int level) const; -private: - std::string comp_name_, inst_name_; - - // TODO: Port mappings, etc. -}; - - -/* - * Container for sequential statements. - */ -class vhdl_process : public vhdl_conc_stmt { -public: - vhdl_process(const char *name = ""); - virtual ~vhdl_process(); - - void emit(std::ofstream &of, int level) const; - void add_stmt(vhdl_seq_stmt *stmt); - void add_decl(vhdl_decl *decl); - void add_sensitivity(const char *name); - bool have_declared_var(const std::string &name) const; -private: - seq_stmt_list_t stmts_; - decl_list_t decls_; - std::string name_; - string_list_t sens_; -}; - - -/* - * An architecture which implements an entity. - */ -class vhdl_arch : public vhdl_element { - friend class vhdl_entity; // Can set its parent -public: - vhdl_arch(const char *entity, const char *name="Behavioural"); - virtual ~vhdl_arch(); - - void emit(std::ofstream &of, int level=0) const; - bool have_declared_component(const std::string &name) const; - bool have_declared(const std::string &name) const; - vhdl_decl *get_decl(const std::string &name) const; - void add_decl(vhdl_decl *decl); - void add_stmt(vhdl_conc_stmt *stmt); - vhdl_entity *get_parent() const; -private: - vhdl_entity *parent_; - conc_stmt_list_t stmts_; - decl_list_t decls_; - std::string name_, entity_; -}; - -/* - * An entity defines the ports, parameters, etc. of a module. Each - * entity is associated with a single architecture (although - * technically this need not be the case). Entities are `derived' - * from instantiations of Verilog module scopes in the hierarchy. - */ -class vhdl_entity : public vhdl_element { -public: - vhdl_entity(const char *name, const char *derived_from, - vhdl_arch *arch); - virtual ~vhdl_entity(); - - void emit(std::ofstream &of, int level=0) const; - vhdl_arch *get_arch() const { return arch_; } - const std::string &get_name() const { return name_; } - void requires_package(const char *spec); - const std::string &get_derived_from() const { return derived_from_; } -private: - std::string name_; - vhdl_arch *arch_; // Entity may only have a single architecture - std::string derived_from_; - string_list_t uses_; -}; - -typedef std::list entity_list_t; +typedef std::list element_list_t; +int indent(int level); +void newline(std::ofstream &of, int level); +void blank_line(std::ofstream &of, int level); #endif diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh new file mode 100644 index 000000000..b6dc0444f --- /dev/null +++ b/tgt-vhdl/vhdl_helper.hh @@ -0,0 +1,54 @@ +/* + * Helper functions for VHDL syntax elements. + * + * 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_VHDL_HELPER_HH +#define INC_VHDL_HELPER_HH + +#include +#include + +template +void emit_children(std::ofstream &of, + const std::list &children, + int level) +{ + // Don't indent if there are no children + if (children.size() == 0) + newline(of, level); + else { + typename std::list::const_iterator it; + for (it = children.begin(); it != children.end(); ++it) { + newline(of, indent(level)); + (*it)->emit(of, indent(level)); + } + newline(of, level); + } +} + +template +void delete_children(std::list &children) +{ + typename std::list::iterator it; + for (it = children.begin(); it != children.end(); ++it) + delete *it; + children.clear(); +} + +#endif diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc new file mode 100644 index 000000000..3924ec22b --- /dev/null +++ b/tgt-vhdl/vhdl_syntax.cc @@ -0,0 +1,419 @@ +/* + * VHDL abstract syntax elements. + * + * 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_helper.hh" + +#include + +vhdl_entity::vhdl_entity(const char *name, const char *derived_from, + vhdl_arch *arch) + : name_(name), arch_(arch), derived_from_(derived_from) +{ + arch->parent_ = this; +} + +vhdl_entity::~vhdl_entity() +{ + delete arch_; +} + +/* + * Add a package to the list of `use' statements before + * the entity. + */ +void vhdl_entity::requires_package(const char *spec) +{ + std::string pname(spec); + std::list::iterator it; + for (it = uses_.begin(); it != uses_.end(); ++it) { + if (*it == pname) + return; + } + uses_.push_back(spec); +} + +void vhdl_entity::emit(std::ofstream &of, int level) const +{ + // Pretty much every design will use std_logic so we + // might as well include it by default + of << "library ieee;" << std::endl; + of << "use ieee.std_logic_1164.all;" << std::endl; + + for (std::list::const_iterator it = uses_.begin(); + it != uses_.end(); + ++it) + of << "use " << *it << ".all;" << std::endl; + of << std::endl; + + emit_comment(of, level); + of << "entity " << name_ << " is"; + // ...ports... + // newline(indent(level)); + newline(of, level); + of << "end entity; "; + blank_line(of, level); // Extra blank line after entities + arch_->emit(of, level); +} + +vhdl_arch::vhdl_arch(const char *entity, const char *name) + : parent_(NULL), name_(name), entity_(entity) +{ + +} + +vhdl_arch::~vhdl_arch() +{ + delete_children(stmts_); + delete_children(decls_); +} + +void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) +{ + stmt->parent_ = this; + stmts_.push_back(stmt); +} + +void vhdl_arch::add_decl(vhdl_decl *decl) +{ + decls_.push_back(decl); +} + +vhdl_entity *vhdl_arch::get_parent() const +{ + assert(parent_); + return parent_; +} + +void vhdl_arch::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + of << "architecture " << name_ << " of " << entity_; + of << " is"; + emit_children(of, decls_, level); + of << "begin"; + emit_children(of, stmts_, level); + of << "end architecture;"; + blank_line(of, level); // Extra blank line after architectures; +} + +vhdl_decl *vhdl_arch::get_decl(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return *it; + } + return NULL; +} + +/* + * True if component `name' has already been declared in this + * architecture. This is a bit of hack, since it uses typeid + * to distinguish between components and other declarations. + */ +bool vhdl_arch::have_declared_component(const std::string &name) const +{ + std::string comp_typename(typeid(vhdl_component_decl).name()); + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if (comp_typename == typeid(**it).name() + && (*it)->get_name() == name) + return true; + } + return false; +} + +/* + * True if any declaration of `name' has been added to the + * architecture. + */ +bool vhdl_arch::have_declared(const std::string &name) const +{ + return get_decl(name) != NULL; +} + +vhdl_arch *vhdl_conc_stmt::get_parent() const +{ + assert(parent_); + return parent_; +} + +vhdl_process::vhdl_process(const char *name) + : name_(name) +{ + +} + +vhdl_process::~vhdl_process() +{ + delete_children(stmts_); + delete_children(decls_); +} + +void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) +{ + stmts_.push_back(stmt); +} + +void vhdl_process::add_decl(vhdl_decl* decl) +{ + decls_.push_back(decl); +} + +void vhdl_process::add_sensitivity(const char *name) +{ + sens_.push_back(name); +} + +bool vhdl_process::have_declared_var(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return true; + } + return false; +} + +void vhdl_process::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + if (name_.size() > 0) + of << name_ << ": "; + of << "process "; + + int num_sens = sens_.size(); + if (num_sens > 0) { + of << "("; + string_list_t::const_iterator it; + for (it = sens_.begin(); it != sens_.end(); ++it) { + of << *it; + if (--num_sens > 0) + of << ", "; + } + of << ") "; + } + + of << "is"; + emit_children(of, decls_, level); + of << "begin"; + emit_children(of, stmts_, level); + of << "end process;"; + newline(of, level); +} + +vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) + : comp_name_(comp_name), inst_name_(inst_name) +{ + +} + +void vhdl_comp_inst::emit(std::ofstream &of, int level) const +{ + // If there are no ports or generics we don't need to mention them... + emit_comment(of, level); + of << inst_name_ << ": " << comp_name_ << ";"; + newline(of, level); +} + +vhdl_component_decl::vhdl_component_decl(const char *name) + : vhdl_decl(name) +{ + +} + +/* + * Create a component declaration for the given entity. + */ +vhdl_component_decl *vhdl_component_decl::component_decl_for(const vhdl_entity *ent) +{ + assert(ent != NULL); + + vhdl_component_decl *decl = new vhdl_component_decl + (ent->get_name().c_str()); + + return decl; +} + +void vhdl_component_decl::emit(std::ofstream &of, int level) const +{ + emit_comment(of, level); + of << "component " << name_ << " is"; + // ...ports... + newline(of, level); + of << "end component;"; +} + +void vhdl_wait_stmt::emit(std::ofstream &of, int level) const +{ + // TODO: There are lots of different types of `wait' + of << "wait;"; +} + + +vhdl_var_decl::~vhdl_var_decl() +{ + delete type_; +} + +void vhdl_var_decl::emit(std::ofstream &of, int level) const +{ + of << "variable " << name_ << " : "; + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); +} + +vhdl_signal_decl::~vhdl_signal_decl() +{ + delete type_; +} + +void vhdl_signal_decl::emit(std::ofstream &of, int level) const +{ + of << "signal " << name_ << " : "; + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); +} + +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) +{ + vhdl_fcall *conv = + new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); + conv->add_expr(this); + + return conv; +} + +void vhdl_expr_list::add_expr(vhdl_expr *e) +{ + exprs_.push_back(e); +} + +vhdl_expr_list::~vhdl_expr_list() +{ + delete_children(exprs_); +} + +void vhdl_expr_list::emit(std::ofstream &of, int level) const +{ + of << "("; + + int size = exprs_.size(); + std::list::const_iterator it; + for (it = exprs_.begin(); it != exprs_.end(); ++it) { + (*it)->emit(of, level); + if (--size > 0) + of << ", "; + } + + of << ")"; +} + +void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const +{ + of << name_; + exprs_.emit(of, level); + of << ";"; +} + +void vhdl_var_ref::emit(std::ofstream &of, int level) const +{ + of << name_; +} + +void vhdl_const_string::emit(std::ofstream &of, int level) const +{ + // In some instances a string literal can be ambiguous between + // a String type and some other types (e.g. std_logic_vector) + // The explicit cast to String removes this ambiguity (although + // isn't always strictly necessary) + of << "String'(\"" << value_ << "\")"; +} + +void vhdl_null_stmt::emit(std::ofstream &of, int level) const +{ + of << "null;"; +} + +void vhdl_fcall::emit(std::ofstream &of, int level) const +{ + of << name_; + exprs_.emit(of, level); +} + +void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const +{ + lhs_->emit(of, level); + of << " <= "; + rhs_->emit(of, level); + of << ";"; +} + +vhdl_const_bits::vhdl_const_bits(const char *value) + : vhdl_expr(vhdl_type::std_logic_vector(strlen(value)-1, 0)), + value_(value) +{ + +} + +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 + return vhdl_expr::cast(to); +} + +void vhdl_const_bits::emit(std::ofstream &of, int level) const +{ + of << "std_logic_vector'(\""; + + // The bits appear to be in reverse order + std::string::const_reverse_iterator it; + for (it = value_.rbegin(); it != value_.rend(); ++it) + of << *it; + + of << "\")"; +} + +void vhdl_const_bit::emit(std::ofstream &of, int level) const +{ + of << "'" << bit_ << "'"; +} diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh new file mode 100644 index 000000000..525fc1493 --- /dev/null +++ b/tgt-vhdl/vhdl_syntax.hh @@ -0,0 +1,345 @@ +/* + * VHDL abstract syntax elements. + * + * 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_VHDL_SYNTAX_HH +#define INC_VHDL_SYNTAX_HH + +#include "vhdl_element.hh" +#include "vhdl_type.hh" + +class vhdl_entity; +class vhdl_arch; + +class vhdl_expr : public vhdl_element { +public: + vhdl_expr(vhdl_type* type) : type_(type) {} + virtual ~vhdl_expr(); + + const vhdl_type *get_type() const { return type_; } + virtual vhdl_expr *cast(const vhdl_type *to); +private: + vhdl_type *type_; +}; + + +/* + * A normal scalar variable reference. + */ +class vhdl_var_ref : public vhdl_expr { +public: + vhdl_var_ref(const char *name, vhdl_type *type) + : vhdl_expr(type), name_(name) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string name_; +}; + + +class vhdl_const_string : public vhdl_expr { +public: + vhdl_const_string(const char *value) + : vhdl_expr(vhdl_type::string()), value_(value) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string value_; +}; + +class vhdl_const_bits : public vhdl_expr { +public: + vhdl_const_bits(const char *value); + void emit(std::ofstream &of, int level) const; + const std::string &get_value() const { return value_; } + vhdl_expr *cast(const vhdl_type *to); +private: + std::string value_; +}; + +class vhdl_const_bit : public vhdl_expr { +public: + vhdl_const_bit(char bit) + : vhdl_expr(vhdl_type::std_logic()), bit_(bit) {} + void emit(std::ofstream &of, int level) const; +private: + char bit_; +}; + +class vhdl_expr_list : public vhdl_element { +public: + ~vhdl_expr_list(); + + void emit(std::ofstream &of, int level) const; + void add_expr(vhdl_expr *e); +private: + std::list exprs_; +}; + + +/* + * A function call within an expression. + */ +class vhdl_fcall : public vhdl_expr { +public: + vhdl_fcall(const char *name, vhdl_type *rtype) + : vhdl_expr(rtype), name_(name) {}; + ~vhdl_fcall() {} + + void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } + void emit(std::ofstream &of, int level) const; +private: + std::string name_; + vhdl_expr_list exprs_; +}; + + +/* + * A concurrent statement appears in architecture bodies but not + * processes. + */ +class vhdl_conc_stmt : public vhdl_element { + friend class vhdl_arch; // Can set its parent +public: + vhdl_conc_stmt() : parent_(NULL) {} + virtual ~vhdl_conc_stmt() {} + + vhdl_arch *get_parent() const; +private: + vhdl_arch *parent_; +}; + +typedef std::list conc_stmt_list_t; + + +/* + * Any sequential statement in a process. + */ +class vhdl_seq_stmt : public vhdl_element { +public: + virtual ~vhdl_seq_stmt() {} +}; + +typedef std::list seq_stmt_list_t; + + +/* + * Similar to Verilog non-blocking assignment, except the LHS + * must be a signal not a variable. + */ +class vhdl_nbassign_stmt : public vhdl_seq_stmt { +public: + vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) + : lhs_(lhs), rhs_(rhs) {} + + void emit(std::ofstream &of, int level) const; +private: + vhdl_var_ref *lhs_; + vhdl_expr *rhs_; +}; + +/* + * Delay simulation indefinitely, until an event, or for a + * specified time. + */ +class vhdl_wait_stmt : public vhdl_seq_stmt { +public: + void emit(std::ofstream &of, int level) const; +}; + + +class vhdl_null_stmt : public vhdl_seq_stmt { +public: + void emit(std::ofstream &of, int level) const; +}; + + +/* + * A procedure call. Which is a statement, unlike a function + * call which is an expression. + */ +class vhdl_pcall_stmt : public vhdl_seq_stmt { +public: + vhdl_pcall_stmt(const char *name) : name_(name) {} + + void emit(std::ofstream &of, int level) const; + void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } +private: + std::string name_; + vhdl_expr_list exprs_; +}; + + +/* + * A declaration of some sort (variable, component, etc.). + * Declarations have names, which is the identifier of the variable, + * constant, etc. not the type. + */ +class vhdl_decl : public vhdl_element { +public: + vhdl_decl(const char *name, vhdl_type *type=NULL) + : name_(name), type_(type) {} + virtual ~vhdl_decl() {}; + + const std::string &get_name() const { return name_; } + const vhdl_type *get_type() const { return type_; } +protected: + std::string name_; + vhdl_type *type_; +}; + +typedef std::list decl_list_t; + + +/* + * A forward declaration of a component. At the moment it is assumed + * that components declarations will only ever be for entities + * generated by this code generator. This is enforced by making the + * constructor private (use component_decl_for instead). + */ +class vhdl_component_decl : public vhdl_decl { +public: + virtual ~vhdl_component_decl() {}; + + static vhdl_component_decl *component_decl_for(const vhdl_entity *ent); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_component_decl(const char *name); + + // TODO: Ports, etc. +}; + + +/* + * A variable declaration inside a process (although this isn't + * enforced here). + */ +class vhdl_var_decl : public vhdl_decl { +public: + vhdl_var_decl(const char *name, vhdl_type *type) + : vhdl_decl(name, type) {} + ~vhdl_var_decl(); + + void emit(std::ofstream &of, int level) const; +}; + + +/* + * A signal declaration in architecture. + */ +class vhdl_signal_decl : public vhdl_decl { +public: + vhdl_signal_decl(const char *name, vhdl_type *type) + : vhdl_decl(name, type) {} + ~vhdl_signal_decl(); + + void emit(std::ofstream &of, int level) const; +}; + + +/* + * Instantiation of component. This is really only a placeholder + * at the moment until the port mappings are worked out. + */ +class vhdl_comp_inst : public vhdl_conc_stmt { +public: + vhdl_comp_inst(const char *inst_name, const char *comp_name); + virtual ~vhdl_comp_inst() {} + + void emit(std::ofstream &of, int level) const; +private: + std::string comp_name_, inst_name_; + + // TODO: Port mappings, etc. +}; + + +/* + * Container for sequential statements. + */ +class vhdl_process : public vhdl_conc_stmt { +public: + vhdl_process(const char *name = ""); + virtual ~vhdl_process(); + + void emit(std::ofstream &of, int level) const; + void add_stmt(vhdl_seq_stmt *stmt); + void add_decl(vhdl_decl *decl); + void add_sensitivity(const char *name); + bool have_declared_var(const std::string &name) const; +private: + seq_stmt_list_t stmts_; + decl_list_t decls_; + std::string name_; + string_list_t sens_; +}; + + +/* + * An architecture which implements an entity. + */ +class vhdl_arch : public vhdl_element { + friend class vhdl_entity; // Can set its parent +public: + vhdl_arch(const char *entity, const char *name="Behavioural"); + virtual ~vhdl_arch(); + + void emit(std::ofstream &of, int level=0) const; + bool have_declared_component(const std::string &name) const; + bool have_declared(const std::string &name) const; + vhdl_decl *get_decl(const std::string &name) const; + void add_decl(vhdl_decl *decl); + void add_stmt(vhdl_conc_stmt *stmt); + vhdl_entity *get_parent() const; +private: + vhdl_entity *parent_; + conc_stmt_list_t stmts_; + decl_list_t decls_; + std::string name_, entity_; +}; + +/* + * An entity defines the ports, parameters, etc. of a module. Each + * entity is associated with a single architecture (although + * technically this need not be the case). Entities are `derived' + * from instantiations of Verilog module scopes in the hierarchy. + */ +class vhdl_entity : public vhdl_element { +public: + vhdl_entity(const char *name, const char *derived_from, + vhdl_arch *arch); + virtual ~vhdl_entity(); + + void emit(std::ofstream &of, int level=0) const; + vhdl_arch *get_arch() const { return arch_; } + const std::string &get_name() const { return name_; } + void requires_package(const char *spec); + const std::string &get_derived_from() const { return derived_from_; } +private: + std::string name_; + vhdl_arch *arch_; // Entity may only have a single architecture + std::string derived_from_; + string_list_t uses_; +}; + +typedef std::list entity_list_t; + +#endif + diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 8e23e8829..b154c5f18 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -4,7 +4,8 @@ #include "vhdl_config.h" #include "ivl_target.h" -#include "vhdl_element.hh" +#include "vhdl_syntax.hh" +#include "vhdl_type.hh" #include diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc new file mode 100644 index 000000000..1896f113f --- /dev/null +++ b/tgt-vhdl/vhdl_type.cc @@ -0,0 +1,72 @@ +/* + * VHDL variable and signal 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_type.hh" + +#include + + +vhdl_type *vhdl_type::std_logic() +{ + return new vhdl_type(VHDL_TYPE_STD_LOGIC); +} + +vhdl_type *vhdl_type::string() +{ + return new vhdl_type(VHDL_TYPE_STRING); +} + +vhdl_type *vhdl_type::line() +{ + return new vhdl_type(VHDL_TYPE_LINE); +} + +std::string vhdl_type::get_string() const +{ + switch (name_) { + case VHDL_TYPE_STD_LOGIC: + return std::string("std_logic"); + case VHDL_TYPE_STD_LOGIC_VECTOR: + { + std::ostringstream ss; + ss << "std_logic_vector(" << msb_; + ss << " downto " << lsb_ << ")"; + return ss.str(); + } + case VHDL_TYPE_STRING: + return std::string("String"); + case VHDL_TYPE_LINE: + return std::string("Line"); + case VHDL_TYPE_FILE: + return std::string("File"); + default: + return std::string("BadType"); + } +} + +void vhdl_type::emit(std::ofstream &of, int level) const +{ + of << get_string(); +} + +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 new file mode 100644 index 000000000..2bc28ad1f --- /dev/null +++ b/tgt-vhdl/vhdl_type.hh @@ -0,0 +1,60 @@ +/* + * VHDL variable and signal 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. + */ + +#ifndef INC_VHDL_TYPE_HH +#define INC_VHDL_TYPE_HH + +#include "vhdl_element.hh" + +enum vhdl_type_name_t { + VHDL_TYPE_STD_LOGIC, + VHDL_TYPE_STD_LOGIC_VECTOR, + VHDL_TYPE_STRING, + VHDL_TYPE_LINE, + VHDL_TYPE_FILE +}; + +/* + * A type at the moment is just a name. It shouldn't get + * too much more complex, as Verilog's type system is much + * simpler than VHDL's. + */ +class vhdl_type : public vhdl_element { +public: + vhdl_type(vhdl_type_name_t name, int msb = 0, int lsb = 0) + : name_(name), msb_(msb), lsb_(lsb) {} + virtual ~vhdl_type() {} + + void emit(std::ofstream &of, int level) const; + vhdl_type_name_t get_name() const { return name_; } + std::string get_string() const; + int get_width() const { return msb_ - lsb_ + 1; } + + // Common types + static vhdl_type *std_logic(); + static vhdl_type *string(); + static vhdl_type *line(); + static vhdl_type *std_logic_vector(int msb, int lsb); +protected: + vhdl_type_name_t name_; + int msb_, lsb_; +}; + +#endif From d762253f7412a949d8b9cd8e316135c69da4c4e3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 12:40:59 +0100 Subject: [PATCH 047/377] Wait statements --- tgt-vhdl/process.cc | 2 +- tgt-vhdl/stmt.cc | 17 ++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 22 ++++++++++++++++++++-- tgt-vhdl/vhdl_syntax.hh | 13 +++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 2ce594aac..5a650aa0b 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -73,7 +73,7 @@ int draw_process(ivl_process_t proc, void *cd) assert(ivl_scope_type(scope) == IVL_SCT_MODULE); vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); assert(ent != NULL); - + // If the scope this process belongs to is the same as the // VHDL entity was generated from, then create a VHDL process // from this Verilog process. This ensures that each process diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 51f3b113c..7be5d58ae 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -190,7 +190,22 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) */ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) { - std::cout << "draw_delay" << std::endl; + uint64_t value = ivl_stmt_delay_val(stmt); + + // This currently ignores the time units and precision + // of the enclosing scope + // A neat way to do this would be to make these values + // constants in the scope (type is Time), and have the + // VHDL wait statement compute the value from that. + // The other solution is to add them as parameters to + // the vhdl_process class + std::cout << "Delay for " << value << std::endl; + + // Expand the sub-statement as well + // Often this can result in a useless `null' statement + // Maybe add a check here and ignore it if it IVL_ST_NOOP? + draw_stmt(proc, ivl_stmt_sub_stmt(stmt)); + return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3924ec22b..5b997445a 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -262,10 +262,28 @@ void vhdl_component_decl::emit(std::ofstream &of, int level) const of << "end component;"; } +vhdl_wait_stmt::~vhdl_wait_stmt() +{ + if (expr_ != NULL) + delete expr_; +} + void vhdl_wait_stmt::emit(std::ofstream &of, int level) const { - // TODO: There are lots of different types of `wait' - of << "wait;"; + of << "wait"; + + switch (type_) { + case VHDL_WAIT_INDEF: + break; + case VHDL_WAIT_FOR_NS: + assert(expr_); + of << " for "; + expr_->emit(of, level); + of << " ns"; + break; + } + + of << ";"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 525fc1493..c15fdbdfe 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -154,13 +154,26 @@ private: vhdl_expr *rhs_; }; +enum vhdl_wait_type_t { + VHDL_WAIT_INDEF, // Suspend indefinitely + VHDL_WAIT_FOR_NS, // Wait for a constant number of nanoseconds +}; + /* * Delay simulation indefinitely, until an event, or for a * specified time. */ class vhdl_wait_stmt : public vhdl_seq_stmt { public: + vhdl_wait_stmt(vhdl_wait_type_t type = VHDL_WAIT_INDEF, + vhdl_expr *expr = NULL) + : type_(type), expr_(expr) {} + ~vhdl_wait_stmt(); + void emit(std::ofstream &of, int level) const; +private: + vhdl_wait_type_t type_; + vhdl_expr *expr_; }; From 120b5dc80eeaf356753783cb7e6425200eb5d1da Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 12:46:55 +0100 Subject: [PATCH 048/377] Add constant integers --- tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 9 +++++++++ tgt-vhdl/vhdl_type.cc | 7 +++++++ tgt-vhdl/vhdl_type.hh | 4 +++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 5b997445a..12e9d4afb 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -435,3 +435,9 @@ void vhdl_const_bit::emit(std::ofstream &of, int level) const { of << "'" << bit_ << "'"; } + +void vhdl_const_int::emit(std::ofstream &of, int level) const +{ + of << value_; +} + diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c15fdbdfe..a027221d3 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -82,6 +82,15 @@ private: char bit_; }; +class vhdl_const_int : public vhdl_expr { +public: + vhdl_const_int(int64_t value) + : vhdl_expr(vhdl_type::integer()), value_(value) {} + void emit(std::ofstream &of, int level) const; +private: + int64_t value_; +}; + class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 1896f113f..060961178 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -38,6 +38,11 @@ vhdl_type *vhdl_type::line() return new vhdl_type(VHDL_TYPE_LINE); } +vhdl_type *vhdl_type::integer() +{ + return new vhdl_type(VHDL_TYPE_INTEGER); +} + std::string vhdl_type::get_string() const { switch (name_) { @@ -56,6 +61,8 @@ std::string vhdl_type::get_string() const return std::string("Line"); case VHDL_TYPE_FILE: return std::string("File"); + case VHDL_TYPE_INTEGER: + return std::string("Integer"); default: return std::string("BadType"); } diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 2bc28ad1f..574de501b 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -28,7 +28,8 @@ enum vhdl_type_name_t { VHDL_TYPE_STD_LOGIC_VECTOR, VHDL_TYPE_STRING, VHDL_TYPE_LINE, - VHDL_TYPE_FILE + VHDL_TYPE_FILE, + VHDL_TYPE_INTEGER, }; /* @@ -52,6 +53,7 @@ public: static vhdl_type *string(); static vhdl_type *line(); static vhdl_type *std_logic_vector(int msb, int lsb); + static vhdl_type *integer(); protected: vhdl_type_name_t name_; int msb_, lsb_; From 2f5dcda3b6b5b85ff31fa341ee86f9ba16576f19 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 12:49:38 +0100 Subject: [PATCH 049/377] Delay statements now translated correctly --- tgt-vhdl/stmt.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 7be5d58ae..eda40a6ff 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -199,8 +199,10 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) // VHDL wait statement compute the value from that. // The other solution is to add them as parameters to // the vhdl_process class - std::cout << "Delay for " << value << std::endl; - + vhdl_wait_stmt *wait = + new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, new vhdl_const_int(value)); + proc->add_stmt(wait); + // Expand the sub-statement as well // Often this can result in a useless `null' statement // Maybe add a check here and ignore it if it IVL_ST_NOOP? From 7120ab7b13ae926b5ac1680e2b0180c664aff8de Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 12:54:21 +0100 Subject: [PATCH 050/377] Expression type might be null in some cases --- tgt-vhdl/vhdl_syntax.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 12e9d4afb..a4841f762 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -315,7 +315,8 @@ void vhdl_signal_decl::emit(std::ofstream &of, int level) const vhdl_expr::~vhdl_expr() { - delete type_; + if (type != NULL) + delete type_; } /* From b96e471fa2de7ba1bece010d142db7dee5324d7f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 14:08:27 +0100 Subject: [PATCH 051/377] Stub code for handling logic gates --- tgt-vhdl/scope.cc | 12 ++++++++++++ tgt-vhdl/vhdl_syntax.cc | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b6f19d57a..44c47bc1f 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,6 +25,15 @@ #include #include +/* + * Translate all the primitive logic gates into concurrent + * signal assignments. + */ +static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) +{ + +} + /* * Declare all signals for a scope in an architecture. */ @@ -71,6 +80,9 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // the architecture declare_signals(arch, scope); + // Similarly, add all the primitive logic gates + declare_logic(arch, scope); + // Build a comment to add to the entity/architecture std::ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a4841f762..99ec94d5b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -315,7 +315,7 @@ void vhdl_signal_decl::emit(std::ofstream &of, int level) const vhdl_expr::~vhdl_expr() { - if (type != NULL) + if (type_ != NULL) delete type_; } From d08f5af9c616ab951d1e4de3f8721a58b88c38c9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 14:21:55 +0100 Subject: [PATCH 052/377] Add concurrent assignments --- tgt-vhdl/scope.cc | 18 +++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 13 +++++++++++++ tgt-vhdl/vhdl_syntax.hh | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 44c47bc1f..bc4492231 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -31,7 +31,23 @@ */ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) { - + int nlogs = ivl_scope_logs(scope); + for (int i = 0; i < nlogs; i++) { + ivl_net_logic_t log = ivl_scope_log(scope, i); + + switch (ivl_logic_type(log)) { + case IVL_LO_NOT: + break; + case IVL_LO_AND: + break; + case IVL_LO_OR: + break; + default: + error("Don't know how to translate logic type = %d", + ivl_logic_type(log)); + break; + } + } } /* diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 99ec94d5b..9a9717156 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -442,3 +442,16 @@ void vhdl_const_int::emit(std::ofstream &of, int level) const of << value_; } +vhdl_cassign_stmt::~vhdl_cassign_stmt() +{ + delete lhs_; + delete rhs_; +} + +void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const +{ + lhs_->emit(of, level); + of << " <= "; + rhs_->emit(of, level); + of << ";"; +} diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a027221d3..600bea11c 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -136,6 +136,20 @@ private: typedef std::list conc_stmt_list_t; +/* + * A concurrent signal assignment (i.e. not part of a process). + */ +class vhdl_cassign_stmt : public vhdl_conc_stmt { +public: + vhdl_cassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) + : lhs_(lhs), rhs_(rhs) {} + ~vhdl_cassign_stmt(); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_var_ref *lhs_; + vhdl_expr *rhs_; +}; /* * Any sequential statement in a process. From aa91186119f6b09b873746be04c481a90103000c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 14:39:58 +0100 Subject: [PATCH 053/377] Add AST elements for unary/binary expressions to model logic gates --- tgt-vhdl/scope.cc | 32 ++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 46 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index bc4492231..1ff2f5031 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,6 +25,34 @@ #include #include +/* + * 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) +{ + 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))) { + const char *signame = ivl_signal_basename(sig); + + vhdl_decl *decl = arch->get_decl(signame); + assert(decl); + + vhdl_type *type = new vhdl_type(*(decl->get_type())); + return new vhdl_var_ref(signame, type); + } + else { + // Ignore other types of nexus pointer + } + } + + assert(false); +} + /* * Translate all the primitive logic gates into concurrent * signal assignments. @@ -35,6 +63,10 @@ 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 = nexus_to_var_ref(arch, output); + switch (ivl_logic_type(log)) { case IVL_LO_NOT: break; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 9a9717156..bcd1751b9 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -455,3 +455,49 @@ void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const rhs_->emit(of, level); of << ";"; } + +vhdl_unaryop_expr::~vhdl_unaryop_expr() +{ + delete operand_; +} + +void vhdl_unaryop_expr::emit(std::ofstream &of, int level) const +{ + switch (op_) { + case VHDL_UNARYOP_NOT: + of << "not "; + break; + } + operand_->emit(of, level); +} + +vhdl_binop_expr::~vhdl_binop_expr() +{ + delete left_; + delete right_; +} + +void vhdl_binop_expr::emit(std::ofstream &of, int level) const +{ + // Expressions are fully parenthesized to remove any + // ambiguity in the output + of << "("; + right_->emit(of, level); + + switch (op_) { + case VHDL_BINOP_AND: + of << " and "; + break; + case VHDL_BINOP_OR: + of << " or "; + break; + } + + right_->emit(of, level); + of << ")"; +} + + + + + diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 600bea11c..9b9c9a9cc 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -53,6 +53,43 @@ private: }; +enum vhdl_binop_t { + VHDL_BINOP_AND, + VHDL_BINOP_OR, +}; + +class vhdl_binop_expr : public vhdl_expr { +public: + vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, + vhdl_expr *right, vhdl_type *type) + : vhdl_expr(type), left_(left), right_(right), op_(op) {} + ~vhdl_binop_expr(); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *left_, *right_; + vhdl_binop_t op_; +}; + + +enum vhdl_unaryop_t { + VHDL_UNARYOP_NOT, +}; + +class vhdl_unaryop_expr : public vhdl_expr { +public: + vhdl_unaryop_expr(vhdl_unaryop_t op, vhdl_expr *operand, + vhdl_type *type) + : vhdl_expr(type), op_(op), operand_(operand) {} + ~vhdl_unaryop_expr(); + + void emit(std::ofstream &of, int level) const; +private: + vhdl_unaryop_t op_; + vhdl_expr *operand_; +}; + + class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) From 3b5d56e087cbd0d4d351b531b67333a1d33fa2e1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 14:53:50 +0100 Subject: [PATCH 054/377] Allow n-ary expressions --- tgt-vhdl/scope.cc | 4 ++++ tgt-vhdl/vhdl_syntax.cc | 42 +++++++++++++++++++++++++++++------------ tgt-vhdl/vhdl_syntax.hh | 14 +++++++++++--- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 1ff2f5031..18c3a7679 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -53,6 +53,10 @@ static vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) assert(false); } +/* + * Convert the inputs of a logic gate to a binary expression. + */ + /* * Translate all the primitive logic gates into concurrent * signal assignments. diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index bcd1751b9..572667f74 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -471,29 +471,47 @@ void vhdl_unaryop_expr::emit(std::ofstream &of, int level) const operand_->emit(of, level); } +vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, + vhdl_expr *right, vhdl_type *type) + : vhdl_expr(type), op_(op) +{ + add_expr(left); + add_expr(right); +} + vhdl_binop_expr::~vhdl_binop_expr() { - delete left_; - delete right_; + delete_children(operands_); +} + +void vhdl_binop_expr::add_expr(vhdl_expr *e) +{ + operands_.push_back(e); } void vhdl_binop_expr::emit(std::ofstream &of, int level) const { // Expressions are fully parenthesized to remove any // ambiguity in the output + of << "("; - right_->emit(of, level); - switch (op_) { - case VHDL_BINOP_AND: - of << " and "; - break; - case VHDL_BINOP_OR: - of << " or "; - break; - } + assert(operands_.size() > 0); + std::list::const_iterator it = operands_.begin(); + + do { + (*it)->emit(of, level); + + switch (op_) { + case VHDL_BINOP_AND: + of << " and "; + break; + case VHDL_BINOP_OR: + of << " or "; + break; + } + } while (++it != operands_.end()); - right_->emit(of, level); of << ")"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9b9c9a9cc..12f14cfff 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -58,16 +58,24 @@ enum vhdl_binop_t { VHDL_BINOP_OR, }; +/* + * A binary expression contains a list of operands rather + * than just two: this is to model n-input gates and the + * like. A second constructor is provided to handle the + * common case of a true binary expression. + */ class vhdl_binop_expr : public vhdl_expr { public: + vhdl_binop_expr(vhdl_binop_t op, vhdl_type *type) + : vhdl_expr(type), op_(op) {} vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, - vhdl_expr *right, vhdl_type *type) - : vhdl_expr(type), left_(left), right_(right), op_(op) {} + vhdl_expr *right, vhdl_type *type); ~vhdl_binop_expr(); + void add_expr(vhdl_expr *e); void emit(std::ofstream &of, int level) const; private: - vhdl_expr *left_, *right_; + std::list operands_; vhdl_binop_t op_; }; From e29954e03f64993f9284d285ce9d3fcb4728658f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 15:05:32 +0100 Subject: [PATCH 055/377] Generate concurrent assignments from logic gates --- tgt-vhdl/scope.cc | 38 +++++++++++++++++++++++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 9 +++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 18c3a7679..b25d8b5f1 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -56,6 +56,35 @@ static vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) /* * Convert the inputs of a logic gate to a binary expression. */ +static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, + ivl_net_logic_t log) +{ + // Not always std_logic but this is probably OK since + // the program has already been type checked + vhdl_binop_expr *gate = + new vhdl_binop_expr(op, vhdl_type::std_logic()); + + int npins = ivl_logic_pins(log); + for (int i = 1; i < npins; i++) { + ivl_nexus_t input = ivl_logic_pin(log, i); + gate->add_expr(nexus_to_var_ref(arch, input)); + } + + return gate; +} + +/* + * Covert a gate intput to an unary expression. + */ +static vhdl_expr *input_to_expr(vhdl_arch *arch, vhdl_unaryop_t op, + ivl_net_logic_t log) +{ + ivl_nexus_t input = ivl_logic_pin(log, 1); + assert(input); + + vhdl_expr *operand = nexus_to_var_ref(arch, input); + return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); +} /* * Translate all the primitive logic gates into concurrent @@ -71,18 +100,25 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = nexus_to_var_ref(arch, output); + vhdl_expr *rhs = NULL; switch (ivl_logic_type(log)) { case IVL_LO_NOT: + rhs = input_to_expr(arch, VHDL_UNARYOP_NOT, log); break; case IVL_LO_AND: + rhs = inputs_to_expr(arch, VHDL_BINOP_AND, log); break; case IVL_LO_OR: + rhs = inputs_to_expr(arch, VHDL_BINOP_OR, log); break; default: error("Don't know how to translate logic type = %d", ivl_logic_type(log)); - break; + continue; } + assert(rhs); + + arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 572667f74..1c029aef2 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -499,9 +499,8 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const assert(operands_.size() > 0); std::list::const_iterator it = operands_.begin(); - do { - (*it)->emit(of, level); - + (*it)->emit(of, level); + while (++it != operands_.end()) { switch (op_) { case VHDL_BINOP_AND: of << " and "; @@ -510,7 +509,9 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const of << " or "; break; } - } while (++it != operands_.end()); + + (*it)->emit(of, level); + } of << ")"; } From 3106fe0ed6aa28b56bad763e57879b394e43054e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 16:27:04 +0100 Subject: [PATCH 056/377] Generate port declarations for entities. But doesn't emit them yet! --- tgt-vhdl/scope.cc | 25 +++++++++++++++--- tgt-vhdl/vhdl_syntax.cc | 57 ++++++++++++++++++++++++++++++++++------- tgt-vhdl/vhdl_syntax.hh | 32 ++++++++++++++++++----- 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b25d8b5f1..4f7f78397 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -74,7 +74,7 @@ static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, } /* - * Covert a gate intput to an unary expression. + * Convert a gate intput to an unary expression. */ static vhdl_expr *input_to_expr(vhdl_arch *arch, vhdl_unaryop_t op, ivl_net_logic_t log) @@ -137,9 +137,26 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) sig_type = vhdl_type::std_logic(); else sig_type = vhdl_type::std_logic_vector(width-1, 0); - vhdl_signal_decl *decl = - new vhdl_signal_decl(ivl_signal_basename(sig), sig_type); - arch->add_decl(decl); + + const char *name = ivl_signal_basename(sig); + ivl_signal_port_t mode = ivl_signal_port(sig); + switch (mode) { + case IVL_SIP_NONE: + arch->add_decl(new vhdl_signal_decl(name, sig_type)); + break; + case IVL_SIP_INPUT: + arch->get_parent()->add_port + (new vhdl_port_decl(name, sig_type, VHDL_PORT_IN)); + break; + case IVL_SIP_OUTPUT: + arch->get_parent()->add_port + (new vhdl_port_decl(name, sig_type, VHDL_PORT_OUT)); + break; + case IVL_SIP_INOUT: + arch->get_parent()->add_port + (new vhdl_port_decl(name, sig_type, VHDL_PORT_INOUT)); + break; + } } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 1c029aef2..f25449108 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -22,6 +22,7 @@ #include "vhdl_helper.hh" #include +#include vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) @@ -33,6 +34,7 @@ vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_entity::~vhdl_entity() { delete arch_; + delete_children(ports_); } /* @@ -50,6 +52,24 @@ void vhdl_entity::requires_package(const char *spec) uses_.push_back(spec); } +/* + * Find a port declaration by name + */ +vhdl_decl *vhdl_entity::get_decl(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = ports_.begin(); it != ports_.end(); ++it) { + if ((*it)->get_name() == name) + return *it; + } + return NULL; +} + +void vhdl_entity::add_port(vhdl_port_decl *decl) +{ + ports_.push_back(decl); +} + void vhdl_entity::emit(std::ofstream &of, int level) const { // Pretty much every design will use std_logic so we @@ -121,7 +141,10 @@ vhdl_decl *vhdl_arch::get_decl(const std::string &name) const if ((*it)->get_name() == name) return *it; } - return NULL; + + // Maybe it's a port rather than an internal signal? + assert(parent_); + return parent_->get_decl(name); } /* @@ -286,10 +309,31 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const of << ";"; } - -vhdl_var_decl::~vhdl_var_decl() +vhdl_decl::~vhdl_decl() { - delete type_; + if (type_ != NULL) + delete type_; +} + +void vhdl_port_decl::emit(std::ofstream &of, int level) const +{ + of << name_ << " : "; + + switch (mode_) { + case VHDL_PORT_IN: + of << "in "; + break; + case VHDL_PORT_OUT: + of << "out "; + break; + case VHDL_PORT_INOUT: + of << "inout "; + break; + } + + type_->emit(of, level); + of << ";"; + emit_comment(of, level, true); } void vhdl_var_decl::emit(std::ofstream &of, int level) const @@ -300,11 +344,6 @@ void vhdl_var_decl::emit(std::ofstream &of, int level) const emit_comment(of, level, true); } -vhdl_signal_decl::~vhdl_signal_decl() -{ - delete type_; -} - void vhdl_signal_decl::emit(std::ofstream &of, int level) const { of << "signal " << name_ << " : "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 12f14cfff..0b85a2ff1 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -276,7 +276,7 @@ class vhdl_decl : public vhdl_element { public: vhdl_decl(const char *name, vhdl_type *type=NULL) : name_(name), type_(type) {} - virtual ~vhdl_decl() {}; + virtual ~vhdl_decl(); const std::string &get_name() const { return name_; } const vhdl_type *get_type() const { return type_; } @@ -296,8 +296,6 @@ typedef std::list decl_list_t; */ class vhdl_component_decl : public vhdl_decl { public: - virtual ~vhdl_component_decl() {}; - static vhdl_component_decl *component_decl_for(const vhdl_entity *ent); void emit(std::ofstream &of, int level) const; @@ -316,8 +314,6 @@ class vhdl_var_decl : public vhdl_decl { public: vhdl_var_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} - ~vhdl_var_decl(); - void emit(std::ofstream &of, int level) const; }; @@ -329,9 +325,30 @@ class vhdl_signal_decl : public vhdl_decl { public: vhdl_signal_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} - ~vhdl_signal_decl(); + virtual void emit(std::ofstream &of, int level) const; +}; + + +enum vhdl_port_mode_t { + VHDL_PORT_IN, + VHDL_PORT_OUT, + VHDL_PORT_INOUT, +}; + +/* + * A port declaration is like a signal declaration except + * it has a direction and appears in the entity rather than + * the architecture. + */ +class vhdl_port_decl : public vhdl_decl { +public: + vhdl_port_decl(const char *name, vhdl_type *type, + vhdl_port_mode_t mode) + : vhdl_decl(name, type), mode_(mode) {} void emit(std::ofstream &of, int level) const; +private: + vhdl_port_mode_t mode_; }; @@ -409,7 +426,9 @@ public: virtual ~vhdl_entity(); void emit(std::ofstream &of, int level=0) const; + void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } + vhdl_decl *get_decl(const std::string &name) const; const std::string &get_name() const { return name_; } void requires_package(const char *spec); const std::string &get_derived_from() const { return derived_from_; } @@ -418,6 +437,7 @@ private: vhdl_arch *arch_; // Entity may only have a single architecture std::string derived_from_; string_list_t uses_; + decl_list_t ports_; }; typedef std::list entity_list_t; From 1fb01d4d9815dc93a1056fb1c7fe226cb9405db4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 16:37:05 +0100 Subject: [PATCH 057/377] Emit port declarations --- tgt-vhdl/vhdl_helper.hh | 5 ++++- tgt-vhdl/vhdl_syntax.cc | 12 ++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index b6dc0444f..656a35409 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -27,16 +27,19 @@ template void emit_children(std::ofstream &of, const std::list &children, - int level) + int level, const char *delim="") { // Don't indent if there are no children if (children.size() == 0) newline(of, level); else { typename std::list::const_iterator it; + int sz = children.size(); for (it = children.begin(); it != children.end(); ++it) { newline(of, indent(level)); (*it)->emit(of, indent(level)); + if (--sz > 0) + of << delim; } newline(of, level); } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index f25449108..3a96d107b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -85,8 +85,14 @@ void vhdl_entity::emit(std::ofstream &of, int level) const emit_comment(of, level); of << "entity " << name_ << " is"; - // ...ports... - // newline(indent(level)); + + if (ports_.size() > 0) { + newline(of, indent(level)); + of << "port ("; + emit_children(of, ports_, indent(level), ";"); + of << ");"; + } + newline(of, level); of << "end entity; "; blank_line(of, level); // Extra blank line after entities @@ -332,8 +338,6 @@ void vhdl_port_decl::emit(std::ofstream &of, int level) const } type_->emit(of, level); - of << ";"; - emit_comment(of, level, true); } void vhdl_var_decl::emit(std::ofstream &of, int level) const From 191187ed1b7c714f949f3d9d8e7f6961ebc291ea Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 9 Jun 2008 16:40:32 +0100 Subject: [PATCH 058/377] Cosmetic change to avoid useless `null' statement after delay --- tgt-vhdl/stmt.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index eda40a6ff..3c4301c7a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -204,9 +204,11 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) proc->add_stmt(wait); // Expand the sub-statement as well - // Often this can result in a useless `null' statement - // Maybe add a check here and ignore it if it IVL_ST_NOOP? - draw_stmt(proc, ivl_stmt_sub_stmt(stmt)); + // Often this would result in a useless `null' statement which + // is caught here instead + ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); + if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) + draw_stmt(proc, sub_stmt); return 0; } From f6753a9013da17a32c02e114add3de42c73f8242 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 10 Jun 2008 11:24:16 +0100 Subject: [PATCH 059/377] Add ports to component declarations --- tgt-vhdl/vhdl_syntax.cc | 11 ++++++++++- tgt-vhdl/vhdl_syntax.hh | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3a96d107b..9593ca385 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -279,6 +279,8 @@ vhdl_component_decl *vhdl_component_decl::component_decl_for(const vhdl_entity * vhdl_component_decl *decl = new vhdl_component_decl (ent->get_name().c_str()); + decl->ports_ = ent->get_ports(); + return decl; } @@ -286,7 +288,14 @@ void vhdl_component_decl::emit(std::ofstream &of, int level) const { emit_comment(of, level); of << "component " << name_ << " is"; - // ...ports... + + if (ports_.size() > 0) { + newline(of, indent(level)); + of << "port ("; + emit_children(of, ports_, indent(level), ";"); + of << ");"; + } + newline(of, level); of << "end component;"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 0b85a2ff1..2e351e3b2 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -302,7 +302,7 @@ public: private: vhdl_component_decl(const char *name); - // TODO: Ports, etc. + decl_list_t ports_; }; @@ -429,6 +429,7 @@ public: void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } vhdl_decl *get_decl(const std::string &name) const; + const decl_list_t &get_ports() const { return ports_; } const std::string &get_name() const { return name_; } void requires_package(const char *spec); const std::string &get_derived_from() const { return derived_from_; } From 7560b29fb9ba799bd18c995b567e0546937867c5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 10 Jun 2008 12:21:48 +0100 Subject: [PATCH 060/377] Find signals to map together --- tgt-vhdl/scope.cc | 67 +++++++++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/stmt.cc | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 4f7f78397..5de2dd702 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -199,6 +199,71 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) return ent; } +/* + * Map two signals together in an instantiation. + * The signals are joined by a nexus. + */ +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); + + int nptrs = ivl_nexus_ptrs(nexus); + for (int i = 0; i < nptrs; i++) { + ivl_signal_t sig; + vhdl_decl *decl; + + ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nexus, i); + if ((sig = ivl_nexus_ptr_sig(ptr)) != NULL) { + const char *basename = ivl_signal_basename(sig); + std::cout << "checking " << basename << std::endl; + if (sig == to) { + // Don't map a signal to itself! + continue; + } + else if ((decl = parent->get_arch()->get_decl(basename))) { + // It's a signal declared in the parent + // Pick this one (any one will do as they're all + // connected together if there's more than one) + std::cout << "= " << std::hex << sig << std::endl; + std::cout << "-> " << ivl_signal_basename(sig) << std::endl; + return; + } + } + } + + error("Failed to find signal to connect to port %s", + ivl_signal_basename(to)); +} + +/* + * Find all the port mappings of a module instantiation. + */ +static void port_map(ivl_scope_t scope, vhdl_entity *parent, + vhdl_comp_inst *inst) +{ + // Find all the port mappings + int nsigs = ivl_scope_sigs(scope); + for (int i = 0; i < nsigs; i++) { + ivl_signal_t sig = ivl_scope_sig(scope, i); + + const char *basename = ivl_signal_basename(sig); + + ivl_signal_port_t mode = ivl_signal_port(sig); + switch (mode) { + case IVL_SIP_NONE: + // Internal signals don't appear in the port map + break; + case IVL_SIP_INPUT: + case IVL_SIP_OUTPUT: + case IVL_SIP_INOUT: + map_signal(sig, parent, inst); + break; + } + } +} + /* * Instantiate an entity in the hierarchy, and possibly create * that entity if it hasn't been encountered yet. @@ -235,6 +300,8 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) const char *inst_name = ivl_scope_basename(scope); vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name, ent->get_name().c_str()); + port_map(scope, parent_ent, inst); + parent_arch->add_stmt(inst); } else { diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 3c4301c7a..9cb490410 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -50,7 +50,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) line_var->set_comment("For generating $display output"); proc->add_decl(line_var); } - + // Write the data into the line int count = ivl_stmt_parm_count(stmt); for (int i = 0; i < count; i++) { From babe694366d2a638319e7c7cb3b60e076d4eef1e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 10 Jun 2008 13:58:41 +0100 Subject: [PATCH 061/377] Generate port mappings --- tgt-vhdl/scope.cc | 9 ++++----- tgt-vhdl/vhdl_syntax.cc | 29 +++++++++++++++++++++++++++-- tgt-vhdl/vhdl_syntax.hh | 13 +++++++++++-- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5de2dd702..baf47162c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -217,7 +217,6 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nexus, i); if ((sig = ivl_nexus_ptr_sig(ptr)) != NULL) { const char *basename = ivl_signal_basename(sig); - std::cout << "checking " << basename << std::endl; if (sig == to) { // Don't map a signal to itself! continue; @@ -226,8 +225,10 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, // It's a signal declared in the parent // Pick this one (any one will do as they're all // connected together if there's more than one) - std::cout << "= " << std::hex << sig << std::endl; - std::cout << "-> " << ivl_signal_basename(sig) << std::endl; + vhdl_var_ref *ref = + new vhdl_var_ref(basename, vhdl_type::std_logic()); + inst->map_port(ivl_signal_basename(to), ref); + return; } } @@ -247,8 +248,6 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - - const char *basename = ivl_signal_basename(sig); 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 9593ca385..844d8ba9f 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -255,11 +255,36 @@ vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) } +void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr) +{ + port_map_t pmap = { name, expr }; + mapping_.push_back(pmap); +} + void vhdl_comp_inst::emit(std::ofstream &of, int level) const { - // If there are no ports or generics we don't need to mention them... emit_comment(of, level); - of << inst_name_ << ": " << comp_name_ << ";"; + of << inst_name_ << ": " << comp_name_; + + // If there are no ports or generics we don't need to mention them... + if (mapping_.size() > 0) { + newline(of, indent(level)); + of << "port map ("; + + int sz = mapping_.size(); + port_map_list_t::const_iterator it; + for (it = mapping_.begin(); it != mapping_.end(); ++it) { + newline(of, indent(indent(level))); + of << (*it).name << " => "; + (*it).expr->emit(of, level); + if (--sz > 0) + of << ","; + } + newline(of, indent(level)); + of << ")"; + } + + of << ";"; newline(of, level); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 2e351e3b2..15cd12e03 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -351,6 +351,15 @@ private: vhdl_port_mode_t mode_; }; +/* + * A mapping from port name to an expression. + */ +struct port_map_t { + std::string name; + vhdl_expr *expr; +}; + +typedef std::list port_map_list_t; /* * Instantiation of component. This is really only a placeholder @@ -362,10 +371,10 @@ public: virtual ~vhdl_comp_inst() {} void emit(std::ofstream &of, int level) const; + void map_port(const char *name, vhdl_expr *expr); private: std::string comp_name_, inst_name_; - - // TODO: Port mappings, etc. + port_map_list_t mapping_; }; From 5a7cfd8c0225867c6004db07530eefa3079b033d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 10 Jun 2008 14:00:15 +0100 Subject: [PATCH 062/377] Clean up vhdl_comp_inst --- tgt-vhdl/vhdl_syntax.cc | 9 +++++++++ tgt-vhdl/vhdl_syntax.hh | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 844d8ba9f..ec545f3c9 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -255,6 +255,15 @@ vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) } +vhdl_comp_inst::~vhdl_comp_inst() +{ + port_map_list_t::iterator it; + for (it = mapping_.begin(); it != mapping_.end(); ++it) { + delete (*it).expr; + } + mapping_.clear(); +} + void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr) { port_map_t pmap = { name, expr }; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 15cd12e03..eb89751b9 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -368,7 +368,7 @@ typedef std::list port_map_list_t; class vhdl_comp_inst : public vhdl_conc_stmt { public: vhdl_comp_inst(const char *inst_name, const char *comp_name); - virtual ~vhdl_comp_inst() {} + ~vhdl_comp_inst(); void emit(std::ofstream &of, int level) const; void map_port(const char *name, vhdl_expr *expr); From 26a2c69c2e8c0cae72c4b5c71a3e891f7661332f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 11 Jun 2008 11:31:43 +0100 Subject: [PATCH 063/377] Change architecture name to `FromVerilog' --- tgt-vhdl/scope.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index baf47162c..87de6052c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -178,7 +178,7 @@ static vhdl_entity *create_entity_for(ivl_scope_t scope) // so we always create a pair and associate the architecture // with the entity for convenience (this also means that we // retain a 1-to-1 mapping of scope to VHDL element) - vhdl_arch *arch = new vhdl_arch(tname); + vhdl_arch *arch = new vhdl_arch(tname, "FromVerilog"); vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch); // Locate all the signals in this module and add them to diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index eb89751b9..f6a2db031 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -405,7 +405,7 @@ private: class vhdl_arch : public vhdl_element { friend class vhdl_entity; // Can set its parent public: - vhdl_arch(const char *entity, const char *name="Behavioural"); + vhdl_arch(const char *entity, const char *name); virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; From b010b8e3cad8f6bec71f5a9450296714ea721273 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 11 Jun 2008 13:37:21 +0100 Subject: [PATCH 064/377] Use `assert false' as initial translation of $finish --- tgt-vhdl/stmt.cc | 15 +++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 9cb490410..debd6ec75 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -103,6 +103,19 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) return 0; } +/* + * VHDL has no real equivalent of Verilog's $finish task. The + * current solution is to use `assert false ...' to terminate + * the simulator. This isn't great, as the simulator will + * return a failure exit code when in fact it completed + * successfully. + */ +static int draw_stask_finish(vhdl_process *proc, ivl_statement_t stmt) +{ + proc->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); + return 0; +} + /* * Generate VHDL for system tasks (like $display). Not all of * these are supported. @@ -113,6 +126,8 @@ static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) if (strcmp(name, "$display") == 0) return draw_stask_display(proc, stmt); + else if (strcmp(name, "$finish") == 0) + return draw_stask_finish(proc, stmt); else { error("No VHDL translation for system task %s", name); return 0; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index ec545f3c9..076266792 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -542,6 +542,12 @@ void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const of << ";"; } +void vhdl_assert_stmt::emit(std::ofstream &of, int level) const +{ + of << "assert false "; // TODO: Allow arbitrary expression + of << " report \"" << reason_ << "\" severity failure;"; +} + vhdl_unaryop_expr::~vhdl_unaryop_expr() { delete operand_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index f6a2db031..588d2eeb7 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -251,6 +251,17 @@ public: }; +class vhdl_assert_stmt : public vhdl_seq_stmt { +public: + vhdl_assert_stmt(const char *reason) + : reason_(reason) {} + + void emit(std::ofstream &of, int level) const; +private: + std::string reason_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From a7cfdc3a876695a7ddaee217e14764a59315091d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 11 Jun 2008 14:11:37 +0100 Subject: [PATCH 065/377] Add VHDL if statement to AST types --- tgt-vhdl/process.cc | 4 +-- tgt-vhdl/stmt.cc | 75 ++++++++++++++++++++++++++--------------- tgt-vhdl/vhdl_syntax.cc | 41 ++++++++++++++++++---- tgt-vhdl/vhdl_syntax.hh | 34 +++++++++++++++++-- tgt-vhdl/vhdl_target.h | 3 +- 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 5a650aa0b..b43e0ee64 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -39,7 +39,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ent->get_arch()->add_stmt(vhdl_proc); ivl_statement_t stmt = ivl_process_stmt(proc); - int rc = draw_stmt(vhdl_proc, stmt); + int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); if (rc != 0) return rc; @@ -48,7 +48,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // the end if (ivl_process_type(proc) == IVL_PR_INITIAL) { vhdl_wait_stmt *wait = new vhdl_wait_stmt(); - vhdl_proc->add_stmt(wait); + vhdl_proc->get_container()->add_stmt(wait); } // Add a comment indicating where it came from diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index debd6ec75..a815f8d99 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -37,7 +37,8 @@ * name collision with an existing variable called * `Verilog_Display_Line' -- do something about this? */ -static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask_display(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { // Add the package requirement to the containing entity proc->get_parent()->get_parent()->requires_package("std.textio"); @@ -87,7 +88,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) write->add_expr(ref); write->add_expr(e); - proc->add_stmt(write); + container->add_stmt(write); } // WriteLine(Output, Verilog_Display_Line) @@ -98,7 +99,7 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) vhdl_var_ref *ref = new vhdl_var_ref(display_line, vhdl_type::line()); write_line->add_expr(ref); - proc->add_stmt(write_line); + container->add_stmt(write_line); return 0; } @@ -110,9 +111,10 @@ static int draw_stask_display(vhdl_process *proc, ivl_statement_t stmt) * return a failure exit code when in fact it completed * successfully. */ -static int draw_stask_finish(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask_finish(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { - proc->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); + container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); return 0; } @@ -120,14 +122,15 @@ static int draw_stask_finish(vhdl_process *proc, ivl_statement_t stmt) * Generate VHDL for system tasks (like $display). Not all of * these are supported. */ -static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) +static int draw_stask(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { const char *name = ivl_stmt_name(stmt); if (strcmp(name, "$display") == 0) - return draw_stask_display(proc, stmt); + return draw_stask_display(proc, container, stmt); else if (strcmp(name, "$finish") == 0) - return draw_stask_finish(proc, stmt); + return draw_stask_finish(proc, container, stmt); else { error("No VHDL translation for system task %s", name); return 0; @@ -138,13 +141,14 @@ static int draw_stask(vhdl_process *proc, ivl_statement_t stmt) * Generate VHDL for a block of Verilog statements. This doesn't * actually do anything, other than recursively translate the * block's statements and add them to the process. This is OK as - * `begin' and `end process' function like a Verilog block. + * the stmt_container class behaves like a Verilog block. */ -static int draw_block(vhdl_process *proc, ivl_statement_t stmt) +static int draw_block(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int count = ivl_stmt_block_count(stmt); for (int i = 0; i < count; i++) { - if (draw_stmt(proc, ivl_stmt_block_stmt(stmt, i)) != 0) + if (draw_stmt(proc, container, ivl_stmt_block_stmt(stmt, i)) != 0) return 1; } return 0; @@ -154,9 +158,10 @@ static int draw_block(vhdl_process *proc, ivl_statement_t stmt) * A no-op statement. This corresponds to a `null' statement in * VHDL. */ -static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) +static int draw_noop(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { - proc->add_stmt(new vhdl_null_stmt()); + container->add_stmt(new vhdl_null_stmt()); return 0; } @@ -165,7 +170,8 @@ static int draw_noop(vhdl_process *proc, ivl_statement_t stmt) * this are essentially the same as VHDL's non-blocking signal * assignment. */ -static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) +static int draw_nbassign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -189,7 +195,7 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - proc->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); + container->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); } else { error("Only signals as lvals supported at the moment"); @@ -203,7 +209,8 @@ static int draw_nbassign(vhdl_process *proc, ivl_statement_t stmt) * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. */ -static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) +static int draw_delay(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { uint64_t value = ivl_stmt_delay_val(stmt); @@ -216,14 +223,14 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) // the vhdl_process class vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, new vhdl_const_int(value)); - proc->add_stmt(wait); + container->add_stmt(wait); // Expand the sub-statement as well // Often this would result in a useless `null' statement which // is caught here instead ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) - draw_stmt(proc, sub_stmt); + draw_stmt(proc, container, sub_stmt); return 0; } @@ -234,7 +241,8 @@ static int draw_delay(vhdl_process *proc, ivl_statement_t stmt) * TODO: This won't yet handle the posedge to rising_edge, etc. * mapping. */ -static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) +static int draw_wait(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { @@ -271,30 +279,41 @@ static int draw_wait(vhdl_process *proc, ivl_statement_t stmt) } ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - draw_stmt(proc, sub_stmt); + draw_stmt(proc, container, sub_stmt); return 0; } +static int draw_if(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) +{ + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and - * add them to the given VHDL process. + * add them to the given VHDL process. The container is the + * location to add statements: e.g. the process body, a branch + * of an if statement, etc. */ -int draw_stmt(vhdl_process *proc, ivl_statement_t stmt) +int draw_stmt(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) { switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: - return draw_stask(proc, stmt); + return draw_stask(proc, container, stmt); case IVL_ST_BLOCK: - return draw_block(proc, stmt); + return draw_block(proc, container, stmt); case IVL_ST_NOOP: - return draw_noop(proc, stmt); + return draw_noop(proc, container, stmt); case IVL_ST_ASSIGN_NB: - return draw_nbassign(proc, stmt); + return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: - return draw_delay(proc, stmt); + return draw_delay(proc, container, stmt); case IVL_ST_WAIT: - return draw_wait(proc, stmt); + return draw_wait(proc, container, stmt); + case IVL_ST_CONDIT: + return draw_if(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 076266792..5800fff46 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -193,15 +193,9 @@ vhdl_process::vhdl_process(const char *name) vhdl_process::~vhdl_process() { - delete_children(stmts_); delete_children(decls_); } -void vhdl_process::add_stmt(vhdl_seq_stmt* stmt) -{ - stmts_.push_back(stmt); -} - void vhdl_process::add_decl(vhdl_decl* decl) { decls_.push_back(decl); @@ -244,11 +238,26 @@ void vhdl_process::emit(std::ofstream &of, int level) const of << "is"; emit_children(of, decls_, level); of << "begin"; - emit_children(of, stmts_, level); + stmts_.emit(of, level); of << "end process;"; newline(of, level); } +stmt_container::~stmt_container() +{ + delete_children(stmts_); +} + +void stmt_container::add_stmt(vhdl_seq_stmt *stmt) +{ + stmts_.push_back(stmt); +} + +void stmt_container::emit(std::ofstream &of, int level) const +{ + emit_children(of, stmts_, level); +} + vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) : comp_name_(comp_name), inst_name_(inst_name) { @@ -548,6 +557,24 @@ void vhdl_assert_stmt::emit(std::ofstream &of, int level) const of << " report \"" << reason_ << "\" severity failure;"; } +vhdl_if_stmt::~vhdl_if_stmt() +{ + delete test_; +} + +void vhdl_if_stmt::emit(std::ofstream &of, int level) const +{ + of << "if "; + test_->emit(of, level); + of << " then"; + newline(of, level); + then_part_.emit(of, level); + of << "else"; + newline(of, level); + else_part_.emit(of, level); + of << "end if;"; +} + vhdl_unaryop_expr::~vhdl_unaryop_expr() { delete operand_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 588d2eeb7..294fe3268 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -204,7 +204,20 @@ public: virtual ~vhdl_seq_stmt() {} }; -typedef std::list seq_stmt_list_t; + +/* + * A list of sequential statements. For example inside a + * process, loop, or if statement. + */ +class stmt_container { +public: + ~stmt_container(); + + void add_stmt(vhdl_seq_stmt *stmt); + void emit(std::ofstream &of, int level) const; +private: + std::list stmts_; +}; /* @@ -262,6 +275,21 @@ private: }; +class vhdl_if_stmt : public vhdl_seq_stmt { +public: + vhdl_if_stmt(vhdl_expr *test) + : test_(test) {} + ~vhdl_if_stmt(); + + stmt_container *get_then_container() { return &then_part_; } + stmt_container *get_else_container() { return &else_part_; } + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *test_; + stmt_container then_part_, else_part_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. @@ -398,12 +426,12 @@ public: virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; - void add_stmt(vhdl_seq_stmt *stmt); + stmt_container *get_container() { return &stmts_; } void add_decl(vhdl_decl *decl); void add_sensitivity(const char *name); bool have_declared_var(const std::string &name) const; private: - seq_stmt_list_t stmts_; + stmt_container stmts_; decl_list_t decls_; std::string name_; string_list_t sens_; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index b154c5f18..a0fb1f497 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -13,7 +13,8 @@ void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); -int draw_stmt(vhdl_process *proc, ivl_statement_t stmt); +int draw_stmt(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt); vhdl_expr *translate_expr(ivl_expr_t e); From 19e60b698f9e0f4dc29167657140a572e935da0e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 11 Jun 2008 14:20:05 +0100 Subject: [PATCH 066/377] Translate if statements --- tgt-vhdl/stmt.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a815f8d99..2c0393df3 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -287,6 +287,19 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, static int draw_if(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { + vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); + if (NULL == test) + return 1; + + vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); + + draw_stmt(proc, vhdif->get_then_container(), + ivl_stmt_cond_true(stmt)); + draw_stmt(proc, vhdif->get_else_container(), + ivl_stmt_cond_false(stmt)); + + container->add_stmt(vhdif); + return 0; } From 7eb41304e6b2460c59f60de60a1859e955e17048 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 10:36:38 +0100 Subject: [PATCH 067/377] Generate rising/falling edge detectors --- tgt-vhdl/stmt.cc | 76 ++++++++++++++++++++++++++++++++++++----- tgt-vhdl/vhdl_syntax.hh | 1 - tgt-vhdl/vhdl_type.cc | 5 +++ tgt-vhdl/vhdl_type.hh | 2 ++ 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 2c0393df3..e1e09eb1e 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -238,8 +238,6 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, /* * A wait statement waits for a level change on a @(..) list of * signals. - * TODO: This won't yet handle the posedge to rising_edge, etc. - * mapping. */ static int draw_wait(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) @@ -248,10 +246,9 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); - if (ivl_event_nneg(event) != 0) - error("Negative edge events not supported yet"); - if (ivl_event_npos(event) != 0) - error("Positive edge events not supported yet"); + // 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++) { @@ -268,14 +265,77 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, // 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_parent()->have_declared(signame)) + if (proc->get_parent()->have_declared(signame)) { proc->add_sensitivity(signame); + non_edges.push_back(signame); + } } else { // Ignore all other types of nexus pointer } } - } + } + + 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++) { + ivl_nexus_t nexus = ivl_event_neg(event, i); + + 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))) { + vhdl_fcall *detect + = new vhdl_fcall("falling_edge", vhdl_type::boolean()); + detect->add_expr + (new vhdl_var_ref(ivl_signal_basename(sig), + vhdl_type::std_logic())); + test->add_expr(detect); + } + } + } + + // Generate rising_edge(..) calls for each posedge event + for (int i = 0; i < npos; i++) { + ivl_nexus_t nexus = ivl_event_pos(event, i); + + 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))) { + vhdl_fcall *detect + = new vhdl_fcall("rising_edge", vhdl_type::boolean()); + detect->add_expr + (new vhdl_var_ref(ivl_signal_basename(sig), + vhdl_type::std_logic())); + test->add_expr(detect); + } + } + } + + // 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())); + } + + container->add_stmt(new vhdl_if_stmt(test)); + } + else { + // Don't bother generating an edge detector if there + // are no edge-triggered events + } } ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 294fe3268..191eb56bb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -163,7 +163,6 @@ private: vhdl_expr_list exprs_; }; - /* * A concurrent statement appears in architecture bodies but not * processes. diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 060961178..374fef0ac 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -38,6 +38,11 @@ vhdl_type *vhdl_type::line() return new vhdl_type(VHDL_TYPE_LINE); } +vhdl_type *vhdl_type::boolean() +{ + return new vhdl_type(VHDL_TYPE_BOOLEAN); +} + vhdl_type *vhdl_type::integer() { return new vhdl_type(VHDL_TYPE_INTEGER); diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 574de501b..f597690a5 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -30,6 +30,7 @@ enum vhdl_type_name_t { VHDL_TYPE_LINE, VHDL_TYPE_FILE, VHDL_TYPE_INTEGER, + VHDL_TYPE_BOOLEAN, }; /* @@ -54,6 +55,7 @@ public: static vhdl_type *line(); static vhdl_type *std_logic_vector(int msb, int lsb); static vhdl_type *integer(); + static vhdl_type *boolean(); protected: vhdl_type_name_t name_; int msb_, lsb_; From 46991aa65c3d51cb78f9c724842a804e93fd2439 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 10:47:52 +0100 Subject: [PATCH 068/377] Generate process bodies in the right place --- tgt-vhdl/expr.cc | 8 ++++++++ tgt-vhdl/stmt.cc | 14 ++++++++++---- tgt-vhdl/vhdl_syntax.cc | 2 -- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 29f1d312c..d14e3fc99 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -55,6 +55,12 @@ static vhdl_expr *translate_number(ivl_expr_t e) return new vhdl_const_bits(ivl_expr_bits(e)); } +static vhdl_expr *translate_unary(ivl_expr_t e) +{ + std::cout << "Unary opcode " << ivl_expr_opcode(e) << std::endl; + return NULL; +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -69,6 +75,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_signal(e); case IVL_EX_NUMBER: return translate_number(e); + case IVL_EX_UNARY: + return translate_unary(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e1e09eb1e..c22d20777 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -242,6 +242,8 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, static int draw_wait(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { + ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); + int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); @@ -268,6 +270,7 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, if (proc->get_parent()->have_declared(signame)) { proc->add_sensitivity(signame); non_edges.push_back(signame); + break; } } else { @@ -298,6 +301,7 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, (new vhdl_var_ref(ivl_signal_basename(sig), vhdl_type::std_logic())); test->add_expr(detect); + break; } } } @@ -318,6 +322,7 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, (new vhdl_var_ref(ivl_signal_basename(sig), vhdl_type::std_logic())); test->add_expr(detect); + break; } } } @@ -329,17 +334,18 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, (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); - container->add_stmt(new vhdl_if_stmt(test)); + draw_stmt(proc, edge_det->get_then_container(), sub_stmt); } else { // Don't bother generating an edge detector if there // are no edge-triggered events + draw_stmt(proc, container, sub_stmt); } } - - ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - draw_stmt(proc, container, sub_stmt); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 5800fff46..9387f5eef 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -567,10 +567,8 @@ void vhdl_if_stmt::emit(std::ofstream &of, int level) const of << "if "; test_->emit(of, level); of << " then"; - newline(of, level); then_part_.emit(of, level); of << "else"; - newline(of, level); else_part_.emit(of, level); of << "end if;"; } From d6f116254705f098679d82e058d028bd6b75f7e5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 10:50:46 +0100 Subject: [PATCH 069/377] Generate correct VHDL signal values --- tgt-vhdl/vhdl_helper.hh | 17 +++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index 656a35409..c1f9499ab 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -23,6 +23,7 @@ #include #include +#include template void emit_children(std::ofstream &of, @@ -54,4 +55,20 @@ void delete_children(std::list &children) children.clear(); } +static inline char vl_to_vhdl_bit(char bit) +{ + switch (bit) { + case '0': + case 'Z': + case '1': + return bit; + case 'z': + return 'Z'; + case 'x': + case 'X': + return 'U'; + } + assert(false); +} + #endif diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 9387f5eef..2145c5874 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -522,14 +522,14 @@ void vhdl_const_bits::emit(std::ofstream &of, int level) const // The bits appear to be in reverse order std::string::const_reverse_iterator it; for (it = value_.rbegin(); it != value_.rend(); ++it) - of << *it; + of << vl_to_vhdl_bit(*it); of << "\")"; } void vhdl_const_bit::emit(std::ofstream &of, int level) const { - of << "'" << bit_ << "'"; + of << "'" << vl_to_vhdl_bit(bit_) << "'"; } void vhdl_const_int::emit(std::ofstream &of, int level) const From 645ee2003faa5865cef9f4e39efae63f20f4a4d7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 10:56:28 +0100 Subject: [PATCH 070/377] Translation for unary not --- tgt-vhdl/expr.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index d14e3fc99..55ef380b3 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -57,8 +57,19 @@ static vhdl_expr *translate_number(ivl_expr_t e) static vhdl_expr *translate_unary(ivl_expr_t e) { - std::cout << "Unary opcode " << ivl_expr_opcode(e) << std::endl; - return NULL; + vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); + if (NULL == operand) + return NULL; + + switch (ivl_expr_opcode(e)) { + case '!': + return new vhdl_unaryop_expr + (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); + default: + error("No translation for unary opcode '%c'\n", + ivl_expr_opcode(e)); + return NULL; + } } /* From 8fe2211e2bc8fd21a07c823ffd2c5ebcd6219280 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 11:24:43 +0100 Subject: [PATCH 071/377] Generate `after' modifier instead of `wait' statements --- tgt-vhdl/stmt.cc | 37 ++++++++++++++++++++++++++----------- tgt-vhdl/vhdl_syntax.cc | 15 +++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 6 ++++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c22d20777..6a2076e5f 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -171,7 +171,7 @@ static int draw_noop(vhdl_process *proc, stmt_container *container, * assignment. */ static int draw_nbassign(vhdl_process *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, vhdl_expr *after = NULL) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -195,7 +195,10 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - container->add_stmt(new vhdl_nbassign_stmt(lval_ref, rhs)); + vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs); + if (after != NULL) + nbassign->set_after(after); + container->add_stmt(nbassign); } else { error("Only signals as lvals supported at the moment"); @@ -221,16 +224,28 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, // VHDL wait statement compute the value from that. // The other solution is to add them as parameters to // the vhdl_process class - vhdl_wait_stmt *wait = - new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, new vhdl_const_int(value)); - container->add_stmt(wait); - - // Expand the sub-statement as well - // Often this would result in a useless `null' statement which - // is caught here instead + vhdl_expr *time = new vhdl_const_int(value); + + // If the sub-statement is an assignment then VHDL lets + // us put the delay after it, which is more compact and + // idiomatic ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) - draw_stmt(proc, container, sub_stmt); + ivl_statement_type_t type = ivl_statement_type(sub_stmt); + if (type == IVL_ST_ASSIGN_NB) { + draw_nbassign(proc, container, sub_stmt, time); + } + else { + vhdl_wait_stmt *wait = + new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, time); + container->add_stmt(wait); + + // Expand the sub-statement as well + // Often this would result in a useless `null' statement which + // is caught here instead + if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) + draw_stmt(proc, container, sub_stmt); + + } return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2145c5874..ae8dc2595 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -484,11 +484,26 @@ void vhdl_fcall::emit(std::ofstream &of, int level) const exprs_.emit(of, level); } +vhdl_nbassign_stmt::~vhdl_nbassign_stmt() +{ + delete lhs_; + delete rhs_; + if (after_) + delete after_; +} + void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const { lhs_->emit(of, level); of << " <= "; rhs_->emit(of, level); + + if (after_) { + of << " after "; + after_->emit(of, level); + of << " ns"; + } + of << ";"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 191eb56bb..52b7aee69 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -226,12 +226,14 @@ private: class vhdl_nbassign_stmt : public vhdl_seq_stmt { public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) - : lhs_(lhs), rhs_(rhs) {} + : lhs_(lhs), rhs_(rhs), after_(NULL) {} + ~vhdl_nbassign_stmt(); + void set_after(vhdl_expr *after) { after_ = after; } void emit(std::ofstream &of, int level) const; private: vhdl_var_ref *lhs_; - vhdl_expr *rhs_; + vhdl_expr *rhs_, *after_; }; enum vhdl_wait_type_t { From 0df3eabe266642995b9b4d41e456e5752574fc2c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 11:36:21 +0100 Subject: [PATCH 072/377] Convert `if (foo) ..' to `if foo = '1' then ..' --- tgt-vhdl/vhdl_syntax.cc | 30 +++++++++++++++++++++++++----- tgt-vhdl/vhdl_syntax.hh | 4 ++-- tgt-vhdl/vhdl_type.cc | 2 ++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index ae8dc2595..2e9a1dee6 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -420,11 +420,21 @@ vhdl_expr::~vhdl_expr() */ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) { - vhdl_fcall *conv = - new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); - conv->add_expr(this); - - return conv; + if (to->get_name() == type_->get_name()) + return this; + 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()); + } + else { + vhdl_fcall *conv = + new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); + conv->add_expr(this); + + return conv; + } } void vhdl_expr_list::add_expr(vhdl_expr *e) @@ -572,6 +582,13 @@ void vhdl_assert_stmt::emit(std::ofstream &of, int level) const of << " report \"" << reason_ << "\" severity failure;"; } +vhdl_if_stmt::vhdl_if_stmt(vhdl_expr *test) +{ + // Need to ensure that the expression is Boolean + vhdl_type boolean(VHDL_TYPE_BOOLEAN); + test_ = test->cast(&boolean); +} + vhdl_if_stmt::~vhdl_if_stmt() { delete test_; @@ -640,6 +657,9 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_OR: of << " or "; break; + case VHDL_BINOP_EQ: + of << " = "; + break; } (*it)->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 52b7aee69..441c6c1bb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -56,6 +56,7 @@ private: enum vhdl_binop_t { VHDL_BINOP_AND, VHDL_BINOP_OR, + VHDL_BINOP_EQ, }; /* @@ -278,8 +279,7 @@ private: class vhdl_if_stmt : public vhdl_seq_stmt { public: - vhdl_if_stmt(vhdl_expr *test) - : test_(test) {} + vhdl_if_stmt(vhdl_expr *test); ~vhdl_if_stmt(); stmt_container *get_then_container() { return &then_part_; } diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 374fef0ac..2aed8f44c 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -68,6 +68,8 @@ std::string vhdl_type::get_string() const return std::string("File"); case VHDL_TYPE_INTEGER: return std::string("Integer"); + case VHDL_TYPE_BOOLEAN: + return std::string("Boolean"); default: return std::string("BadType"); } From b8c1f9ab6746236fb18db2fa865b39a72b05c2c9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 12 Jun 2008 20:26:23 +0100 Subject: [PATCH 073/377] A system for linking ivl_signal_t to entities --- tgt-vhdl/vhdl.cc | 54 ++++++++++++++++++++++++++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_target.h | 7 ++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index fb4009e49..023b7ecb7 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -28,10 +28,26 @@ #include #include #include +#include + +/* + * Maps a signal to the entity it is defined within. Also + * provides a mechanism for renaming signals -- i.e. when + * an output has the same name as register: valid in Verilog + * but not in VHDL, so two separate signals need to be + * defined. + */ +struct signal_defn_t { + std::string renamed; // The name of the VHDL signal + const vhdl_entity *ent; // The entity where it is defined +}; + +typedef std::map signal_defn_map_t; + static int g_errors = 0; // Total number of errors encountered - static entity_list_t g_entities; // All entities to emit +static signal_defn_map_t g_known_signals; /* @@ -73,6 +89,42 @@ void remember_entity(vhdl_entity* ent) g_entities.push_back(ent); } +/* + * Remeber the association of signal to entity. + */ +void remember_signal(ivl_signal_t sig, const vhdl_entity *ent) +{ + assert(g_known_signals.find(sig) == g_known_signals.end()); + + signal_defn_t defn = { ivl_signal_basename(sig), ent }; + g_known_signals[sig] = defn; +} + +/* + * Change the VHDL name of a Verilog signal. + */ +void rename_signal(ivl_signal_t sig, const std::string &renamed) +{ + assert(g_known_signals.find(sig) != g_known_signals.end()); + + g_known_signals[sig].renamed = renamed; +} + +const vhdl_entity *find_entity_for_signal(ivl_signal_t sig) +{ + assert(g_known_signals.find(sig) != g_known_signals.end()); + + return g_known_signals[sig].ent; +} + +const std::string &get_renamed_signal(ivl_signal_t sig) +{ + assert(g_known_signals.find(sig) != g_known_signals.end()); + + return g_known_signals[sig].renamed; +} + + extern "C" int target_design(ivl_design_t des) { ivl_scope_t *roots; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2e9a1dee6..f0248c61e 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -578,7 +578,7 @@ void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const void vhdl_assert_stmt::emit(std::ofstream &of, int level) const { - of << "assert false "; // TODO: Allow arbitrary expression + of << "assert false"; // TODO: Allow arbitrary expression of << " report \"" << reason_ << "\" severity failure;"; } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index a0fb1f497..bb29cc82d 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -21,5 +21,12 @@ vhdl_expr *translate_expr(ivl_expr_t e); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); + +void remember_signal(ivl_signal_t sig, const vhdl_entity *ent); +void rename_signal(ivl_signal_t sig, const std::string &renamed); +const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); +const std::string &get_renamed_signal(ivl_signal_t sig); + + #endif /* #ifndef INC_VHDL_TARGET_H */ From d6193c162289dbba1321a9387de645be887a57b6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 12:34:27 +0100 Subject: [PATCH 074/377] Add _Reg internal signal if output is registered --- tgt-vhdl/scope.cc | 23 +++++++++++++++++++++++ tgt-vhdl/vhdl.cc | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 87de6052c..bd5863c86 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -137,6 +137,8 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) sig_type = vhdl_type::std_logic(); else sig_type = vhdl_type::std_logic_vector(width-1, 0); + + remember_signal(sig, arch->get_parent()); const char *name = ivl_signal_basename(sig); ivl_signal_port_t mode = ivl_signal_port(sig); @@ -151,6 +153,27 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) case IVL_SIP_OUTPUT: arch->get_parent()->add_port (new vhdl_port_decl(name, sig_type, VHDL_PORT_OUT)); + + if (ivl_signal_type(sig) == IVL_SIT_REG) { + // A registered output + // In Verilog the output and reg can have the + // same name: this is not valid in VHDL + // Instead a new signal foo_Reg is created + // which represents the register + std::string newname(name); + newname += "_Reg"; + rename_signal(sig, newname.c_str()); + + vhdl_type *reg_type = new vhdl_type(*sig_type); + arch->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); + + // Create a concurrent assignment statement to + // connect the register to the output + arch->add_stmt + (new vhdl_cassign_stmt + (new vhdl_var_ref(name, NULL), + new vhdl_var_ref(newname.c_str(), NULL))); + } break; case IVL_SIP_INOUT: arch->get_parent()->add_port diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 023b7ecb7..f2c99b644 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -95,7 +95,7 @@ void remember_entity(vhdl_entity* ent) void remember_signal(ivl_signal_t sig, const vhdl_entity *ent) { assert(g_known_signals.find(sig) == g_known_signals.end()); - + signal_defn_t defn = { ivl_signal_basename(sig), ent }; g_known_signals[sig] = defn; } From 005df31a0d3fe3e262cca7ba3b8036d74f758e73 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 12:39:18 +0100 Subject: [PATCH 075/377] Use renamed signal in expressions, if there is one --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/scope.cc | 2 +- tgt-vhdl/stmt.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 55ef380b3..b3f7f1017 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -44,7 +44,7 @@ static vhdl_expr *translate_signal(ivl_expr_t e) // Assume all signals are single bits at the moment vhdl_type *type = vhdl_type::std_logic(); - return new vhdl_var_ref(ivl_signal_basename(sig), type); + return new vhdl_var_ref(get_renamed_signal(sig).c_str(), type); } /* diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index bd5863c86..f6c6c73db 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -37,7 +37,7 @@ static vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - const char *signame = ivl_signal_basename(sig); + const char *signame = get_renamed_signal(sig).c_str(); vhdl_decl *decl = arch->get_decl(signame); assert(decl); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 6a2076e5f..85773a60f 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -182,7 +182,7 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { - const char *signame = ivl_signal_basename(sig); + const char *signame = get_renamed_signal(sig).c_str(); vhdl_decl *decl = proc->get_parent()->get_decl(signame); assert(decl); From 70db096b6dde4761b9569c358cf443fe6473dc29 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 12:52:20 +0100 Subject: [PATCH 076/377] Clean up the edge detector code a bit --- tgt-vhdl/stmt.cc | 75 ++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 85773a60f..4013dafac 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -250,6 +250,35 @@ static int draw_delay(vhdl_process *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) +{ + 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))) { + const char *signame = get_renamed_signal(sig).c_str(); + + vhdl_fcall *detect + = new vhdl_fcall(type, vhdl_type::boolean()); + detect->add_expr + (new vhdl_var_ref(signame, vhdl_type::std_logic())); + test->add_expr(detect); + proc->add_sensitivity(signame); + break; + } + } +} + + /* * A wait statement waits for a level change on a @(..) list of * signals. @@ -301,47 +330,13 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, 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++) { - ivl_nexus_t nexus = ivl_event_neg(event, i); - - 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))) { - vhdl_fcall *detect - = new vhdl_fcall("falling_edge", vhdl_type::boolean()); - detect->add_expr - (new vhdl_var_ref(ivl_signal_basename(sig), - vhdl_type::std_logic())); - test->add_expr(detect); - break; - } - } - } - + 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++) { - ivl_nexus_t nexus = ivl_event_pos(event, i); - - 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))) { - vhdl_fcall *detect - = new vhdl_fcall("rising_edge", vhdl_type::boolean()); - detect->add_expr - (new vhdl_var_ref(ivl_signal_basename(sig), - vhdl_type::std_logic())); - test->add_expr(detect); - break; - } - } - } - + 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) { From 0a8fd50c4af30c449ac25937e75f6bd416b45a2f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 13:59:48 +0100 Subject: [PATCH 077/377] Find assignments that could be initializers --- tgt-vhdl/process.cc | 7 ++++++- tgt-vhdl/stmt.cc | 32 +++++++++++++++++++++++--------- tgt-vhdl/vhdl_syntax.hh | 6 ++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index b43e0ee64..ac11cefa5 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -36,7 +36,12 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // parent link won't be valid (and draw_stmt needs this // to add information to the architecture) vhdl_process *vhdl_proc = new vhdl_process(); - ent->get_arch()->add_stmt(vhdl_proc); + ent->get_arch()->add_stmt(vhdl_proc); + + // If this is an initial process, push signal initialisation + // into the declarations + if (ivl_process_type(proc) == IVL_PR_INITIAL) + vhdl_proc->set_initial(true); ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 4013dafac..1e80d11b4 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -192,13 +192,25 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, return 1; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); - // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - - vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs); - if (after != NULL) - nbassign->set_after(after); - container->add_stmt(nbassign); + // If this is an `inital' process and we haven't yet + // generated a `wait' statement then initializing the + // signal here is equivalent to initializing to in the + // declaration + // The second test ensures that we only try to initialise + // internal signals not ports + if (proc->is_initial() + && !proc->get_parent()->get_parent()->get_decl(signame)) { + std::cout << "Pushing " << signame << " init up" << std::endl; + } + else { + // The type here can be null as it is never actually needed + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); + + vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs); + if (after != NULL) + nbassign->set_after(after); + container->add_stmt(nbassign); + } } else { error("Only signals as lvals supported at the moment"); @@ -244,9 +256,12 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, // is caught here instead if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) draw_stmt(proc, container, sub_stmt); - } + // Any further assignments occur after simulation time 0 + // so they cannot be used to initialize signal declarations + proc->set_initial(false); + return 0; } @@ -278,7 +293,6 @@ static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc, } } - /* * A wait statement waits for a level change on a @(..) list of * signals. diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 441c6c1bb..27607d076 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -420,6 +420,9 @@ private: /* * Container for sequential statements. + * Verilog `initial' processes are used for variable + * initialisation whereas VHDL initialises variables in + * their declaration. */ class vhdl_process : public vhdl_conc_stmt { public: @@ -431,11 +434,14 @@ public: void add_decl(vhdl_decl *decl); void add_sensitivity(const char *name); bool have_declared_var(const std::string &name) const; + void set_initial(bool i) { initial_ = i; } + bool is_initial() const { return initial_; } private: stmt_container stmts_; decl_list_t decls_; std::string name_; string_list_t sens_; + bool initial_; }; From be3c4cf268f97b73df2a84160ebeea6493119def Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 14:10:28 +0100 Subject: [PATCH 078/377] Generate signal initial values from `initial' processes --- tgt-vhdl/stmt.cc | 5 ++--- tgt-vhdl/vhdl_syntax.cc | 21 +++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 7 +++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1e80d11b4..8d875c4dc 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -198,9 +198,8 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, // declaration // The second test ensures that we only try to initialise // internal signals not ports - if (proc->is_initial() - && !proc->get_parent()->get_parent()->get_decl(signame)) { - std::cout << "Pushing " << signame << " init up" << std::endl; + if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE) { + decl->set_initial(rhs); } else { // The type here can be null as it is never actually needed diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index f0248c61e..4d8532c38 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -371,6 +371,15 @@ vhdl_decl::~vhdl_decl() { if (type_ != NULL) delete type_; + if (initial_ != NULL) + delete initial_; +} + +void vhdl_decl::set_initial(vhdl_expr *initial) +{ + if (initial_ != NULL) + delete initial_; + initial_ = initial; } void vhdl_port_decl::emit(std::ofstream &of, int level) const @@ -396,6 +405,12 @@ void vhdl_var_decl::emit(std::ofstream &of, int level) const { of << "variable " << name_ << " : "; type_->emit(of, level); + + if (initial_) { + of << " := "; + initial_->emit(of, level); + } + of << ";"; emit_comment(of, level, true); } @@ -404,6 +419,12 @@ void vhdl_signal_decl::emit(std::ofstream &of, int level) const { of << "signal " << name_ << " : "; type_->emit(of, level); + + if (initial_) { + of << " := "; + initial_->emit(of, level); + } + of << ";"; emit_comment(of, level, true); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 27607d076..3478fbb83 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -314,15 +314,18 @@ private: */ class vhdl_decl : public vhdl_element { public: - vhdl_decl(const char *name, vhdl_type *type=NULL) - : name_(name), type_(type) {} + vhdl_decl(const char *name, vhdl_type *type = NULL, + vhdl_expr *initial = NULL) + : name_(name), type_(type), initial_(initial) {} virtual ~vhdl_decl(); const std::string &get_name() const { return name_; } const vhdl_type *get_type() const { return type_; } + void set_initial(vhdl_expr *initial); protected: std::string name_; vhdl_type *type_; + vhdl_expr *initial_; }; typedef std::list decl_list_t; From 9fbb449e06fb7ef3698b55512cbe154555f968d6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 14:17:24 +0100 Subject: [PATCH 079/377] Optimise away empty (VHDL) processes --- tgt-vhdl/process.cc | 6 +++++- tgt-vhdl/vhdl_syntax.cc | 8 ++++++++ tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index ac11cefa5..b8ae4c27d 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -51,7 +51,11 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // Initial processes are translated to VHDL processes with // no sensitivity list and and indefinite wait statement at // the end - if (ivl_process_type(proc) == IVL_PR_INITIAL) { + // However, if no statements were added to the container + // by draw_stmt, don't bother adding a wait as `emit' + // will optimise the process out of the output + if (ivl_process_type(proc) == IVL_PR_INITIAL + && !vhdl_proc->get_container()->empty()) { vhdl_wait_stmt *wait = new vhdl_wait_stmt(); vhdl_proc->get_container()->add_stmt(wait); } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 4d8532c38..ea44d2a13 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -218,6 +218,14 @@ bool vhdl_process::have_declared_var(const std::string &name) const void vhdl_process::emit(std::ofstream &of, int level) const { + // If there are no statements in the body, this process + // can't possibly do anything, so don't bother to emit it + if (stmts_.empty()) { + of << "-- Removed one empty process"; + newline(of, level); + return; + } + emit_comment(of, level); if (name_.size() > 0) of << name_ << ": "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 3478fbb83..0df1638fd 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -215,6 +215,7 @@ public: void add_stmt(vhdl_seq_stmt *stmt); void emit(std::ofstream &of, int level) const; + bool empty() const { return stmts_.empty(); } private: std::list stmts_; }; From 0ea64ad8aba40953bd41e65a197e3ed2a639f4a2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 13 Jun 2008 14:47:06 +0100 Subject: [PATCH 080/377] Correct misleading comment --- tgt-vhdl/stmt.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 8d875c4dc..e3971450d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -193,9 +193,13 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); // If this is an `inital' process and we haven't yet - // generated a `wait' statement then initializing the - // signal here is equivalent to initializing to in the - // declaration + // generated a `wait' statement then this assignment + // needs to be moved to the declaration. Otherwise the + // Verilog behaviour won't be preserved: 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->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE) { From 919c1d695ca286b053752e878e0a8a7b5f945735 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 14 Jun 2008 17:09:31 +0100 Subject: [PATCH 081/377] Adding binary + --- tgt-vhdl/expr.cc | 64 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 3 ++ tgt-vhdl/vhdl_syntax.hh | 1 + tgt-vhdl/vhdl_type.cc | 10 +++++++ tgt-vhdl/vhdl_type.hh | 6 ++++ 5 files changed, 84 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index b3f7f1017..eee314caf 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -68,6 +68,68 @@ static vhdl_expr *translate_unary(ivl_expr_t e) default: error("No translation for unary opcode '%c'\n", ivl_expr_opcode(e)); + delete operand; + return NULL; + } +} + +/* + * Translate a numeric binary operator (+, -, etc.) to + * a VHDL equivalent using the numeric_std package. + */ +static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, + vhdl_binop_t op) +{ + int lwidth = lhs->get_type()->get_width(); + int rwidth = rhs->get_type()->get_width(); + + vhdl_type ltype(VHDL_TYPE_UNSIGNED, lhs->get_type()->get_msb(), + lhs->get_type()->get_lsb()); + vhdl_type rtype(VHDL_TYPE_UNSIGNED, rhs->get_type()->get_msb(), + rhs->get_type()->get_lsb()); + + vhdl_expr *l_cast = lhs->cast(<ype); + vhdl_expr *r_cast = lhs->cast(&rtype); + + // May need to resize the left or right hand side + if (lwidth < rwidth) { + vhdl_fcall *resize = + new vhdl_fcall("resize", vhdl_type::nunsigned(rwidth)); + resize->add_expr(l_cast); + resize->add_expr(new vhdl_const_int(rwidth)); + // l_cast = resize; + } + else if (rwidth < lwidth) { + vhdl_fcall *resize = + new vhdl_fcall("resize", vhdl_type::nunsigned(lwidth)); + resize->add_expr(r_cast); + resize->add_expr(new vhdl_const_int(lwidth)); + //r_cast = resize; + } + + + return new vhdl_binop_expr(l_cast, op, r_cast, + vhdl_type::nunsigned(lwidth)); +} + +static vhdl_expr *translate_binary(ivl_expr_t e) +{ + vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); + if (NULL == lhs) + return NULL; + + vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e)); + if (NULL == rhs) + return NULL; + + switch (ivl_expr_opcode(e)) { + case '+': + return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); + default: + error("No translation for binary opcode '%c'\n", + ivl_expr_opcode(e)); + delete lhs; + delete rhs; return NULL; } } @@ -88,6 +150,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_number(e); case IVL_EX_UNARY: return translate_unary(e); + case IVL_EX_BINARY: + return translate_binary(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index ea44d2a13..e9597a55c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -689,6 +689,9 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_EQ: of << " = "; break; + case VHDL_BINOP_ADD: + of << " + "; + break; } (*it)->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 0df1638fd..cf17f8dfd 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -57,6 +57,7 @@ enum vhdl_binop_t { VHDL_BINOP_AND, VHDL_BINOP_OR, VHDL_BINOP_EQ, + VHDL_BINOP_ADD, }; /* diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 2aed8f44c..3f9abd29a 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -48,6 +48,16 @@ vhdl_type *vhdl_type::integer() return new vhdl_type(VHDL_TYPE_INTEGER); } +vhdl_type *vhdl_type::nunsigned(int width) +{ + return new vhdl_type(VHDL_TYPE_UNSIGNED, width-1, 0); +} + +vhdl_type *vhdl_type::nsigned(int width) +{ + return new vhdl_type(VHDL_TYPE_SIGNED, width-1, 0); +} + std::string vhdl_type::get_string() const { switch (name_) { diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index f597690a5..947ea4651 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -31,6 +31,8 @@ enum vhdl_type_name_t { VHDL_TYPE_FILE, VHDL_TYPE_INTEGER, VHDL_TYPE_BOOLEAN, + VHDL_TYPE_SIGNED, + VHDL_TYPE_UNSIGNED, }; /* @@ -48,12 +50,16 @@ public: vhdl_type_name_t get_name() const { return name_; } std::string get_string() const; int get_width() const { return msb_ - lsb_ + 1; } + int get_msb() const { return msb_; } + int get_lsb() const { return lsb_; } // Common types static vhdl_type *std_logic(); static vhdl_type *string(); static vhdl_type *line(); static vhdl_type *std_logic_vector(int msb, int lsb); + static vhdl_type *nunsigned(int width); + static vhdl_type *nsigned(int width); static vhdl_type *integer(); static vhdl_type *boolean(); protected: From 2fb57805ea8424fbe5a207f7373128798b924ef4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 14 Jun 2008 18:03:25 +0100 Subject: [PATCH 082/377] Use signed rather than std_logic_vector Arithmetic operators now working correctly --- tgt-vhdl/expr.cc | 23 ++++++++++------------- tgt-vhdl/scope.cc | 4 ++-- tgt-vhdl/vhdl_syntax.cc | 7 ++++--- tgt-vhdl/vhdl_type.cc | 36 +++++++++++++++++++++++++++++------- tgt-vhdl/vhdl_type.hh | 1 + 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index eee314caf..0731796c6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -79,7 +79,7 @@ static vhdl_expr *translate_unary(ivl_expr_t e) */ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) -{ +{ int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); @@ -88,28 +88,25 @@ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_type rtype(VHDL_TYPE_UNSIGNED, rhs->get_type()->get_msb(), rhs->get_type()->get_lsb()); - vhdl_expr *l_cast = lhs->cast(<ype); - vhdl_expr *r_cast = lhs->cast(&rtype); - // May need to resize the left or right hand side if (lwidth < rwidth) { vhdl_fcall *resize = - new vhdl_fcall("resize", vhdl_type::nunsigned(rwidth)); - resize->add_expr(l_cast); + new vhdl_fcall("resize", vhdl_type::nsigned(rwidth)); + resize->add_expr(lhs); resize->add_expr(new vhdl_const_int(rwidth)); - // l_cast = resize; + lhs = resize; + lwidth = rwidth; } else if (rwidth < lwidth) { vhdl_fcall *resize = - new vhdl_fcall("resize", vhdl_type::nunsigned(lwidth)); - resize->add_expr(r_cast); + new vhdl_fcall("resize", vhdl_type::nsigned(lwidth)); + resize->add_expr(rhs); resize->add_expr(new vhdl_const_int(lwidth)); - //r_cast = resize; + rhs = resize; + rwidth = lwidth; } - - return new vhdl_binop_expr(l_cast, op, r_cast, - vhdl_type::nunsigned(lwidth)); + return new vhdl_binop_expr(lhs, op, rhs, vhdl_type::nsigned(lwidth)); } static vhdl_expr *translate_binary(ivl_expr_t e) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index f6c6c73db..d1c29cd25 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -133,10 +133,10 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) int width = ivl_signal_width(sig); vhdl_type *sig_type; - if (width > 0) + if (width == 1) sig_type = vhdl_type::std_logic(); else - sig_type = vhdl_type::std_logic_vector(width-1, 0); + sig_type = vhdl_type::nsigned(width); remember_signal(sig, arch->get_parent()); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e9597a55c..ef33a79ab 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -76,6 +76,7 @@ void vhdl_entity::emit(std::ofstream &of, int level) const // might as well include it by default of << "library ieee;" << std::endl; of << "use ieee.std_logic_1164.all;" << std::endl; + of << "use ieee.numeric_std.all;" << std::endl; for (std::list::const_iterator it = uses_.begin(); it != uses_.end(); @@ -547,14 +548,14 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const } vhdl_const_bits::vhdl_const_bits(const char *value) - : vhdl_expr(vhdl_type::std_logic_vector(strlen(value)-1, 0)), + : vhdl_expr(vhdl_type::nsigned(strlen(value))), value_(value) { } 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 @@ -571,7 +572,7 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) void vhdl_const_bits::emit(std::ofstream &of, int level) const { - of << "std_logic_vector'(\""; + of << "signed'(\""; // The bits appear to be in reverse order std::string::const_reverse_iterator it; diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 3f9abd29a..6180a839e 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -58,18 +58,16 @@ vhdl_type *vhdl_type::nsigned(int width) return new vhdl_type(VHDL_TYPE_SIGNED, width-1, 0); } +/* + * This is just the name of the type, without any parameters. + */ std::string vhdl_type::get_string() const { switch (name_) { case VHDL_TYPE_STD_LOGIC: return std::string("std_logic"); case VHDL_TYPE_STD_LOGIC_VECTOR: - { - std::ostringstream ss; - ss << "std_logic_vector(" << msb_; - ss << " downto " << lsb_ << ")"; - return ss.str(); - } + return std::string("std_logic_vector"); case VHDL_TYPE_STRING: return std::string("String"); case VHDL_TYPE_LINE: @@ -80,14 +78,38 @@ std::string vhdl_type::get_string() const return std::string("Integer"); case VHDL_TYPE_BOOLEAN: return std::string("Boolean"); + case VHDL_TYPE_SIGNED: + return std::string("signed"); + case VHDL_TYPE_UNSIGNED: + return std::string("unsigned"); default: return std::string("BadType"); } } +/* + * The is the qualified name of the type. + */ +std::string vhdl_type::get_decl_string() const +{ + switch (name_) { + case VHDL_TYPE_STD_LOGIC_VECTOR: + case VHDL_TYPE_UNSIGNED: + case VHDL_TYPE_SIGNED: + { + std::ostringstream ss; + ss << get_string() << "(" << msb_; + ss << " downto " << lsb_ << ")"; + return ss.str(); + } + default: + return get_string(); + } +} + void vhdl_type::emit(std::ofstream &of, int level) const { - of << get_string(); + of << get_decl_string(); } vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 947ea4651..341c5585a 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -49,6 +49,7 @@ public: void emit(std::ofstream &of, int level) const; vhdl_type_name_t get_name() const { return name_; } std::string get_string() const; + std::string get_decl_string() const; int get_width() const { return msb_ - lsb_ + 1; } int get_msb() const { return msb_; } int get_lsb() const { return lsb_; } From 8a9486eb49ffaff691a8379eb3bf35b649f5e03e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 14 Jun 2008 18:11:10 +0100 Subject: [PATCH 083/377] Eliminate useless Resize() call --- tgt-vhdl/expr.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 0731796c6..736bc67ab 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -41,10 +41,17 @@ static vhdl_expr *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); - // Assume all signals are single bits at the moment - vhdl_type *type = vhdl_type::std_logic(); + const vhdl_entity *ent = find_entity_for_signal(sig); + assert(ent); + + const char *renamed = get_renamed_signal(sig).c_str(); - return new vhdl_var_ref(get_renamed_signal(sig).c_str(), type); + const vhdl_decl *decl = ent->get_arch()->get_decl(renamed); + assert(decl); + + vhdl_type *type = new vhdl_type(*decl->get_type()); + + return new vhdl_var_ref(renamed, type); } /* From 92c823680a2554c69d867fcb6516eb5826ac6923 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 12:13:01 +0100 Subject: [PATCH 084/377] Fix crash when `if' statement had no `else' --- tgt-vhdl/stmt.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e3971450d..36f19a671 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -388,8 +388,10 @@ static int draw_if(vhdl_process *proc, stmt_container *container, draw_stmt(proc, vhdif->get_then_container(), ivl_stmt_cond_true(stmt)); - draw_stmt(proc, vhdif->get_else_container(), - ivl_stmt_cond_false(stmt)); + + ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt); + if (cond_false_stmt) + draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt); container->add_stmt(vhdif); From 849e7cb4d5d7c71d41c5a3bcbb1741457166536d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 12:20:28 +0100 Subject: [PATCH 085/377] Add equality operator --- tgt-vhdl/expr.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 736bc67ab..7aa6d9fca 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -116,6 +116,12 @@ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, return new vhdl_binop_expr(lhs, op, rhs, vhdl_type::nsigned(lwidth)); } +static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, + vhdl_binop_t op) +{ + return new vhdl_binop_expr(lhs, op, rhs, vhdl_type::boolean()); +} + static vhdl_expr *translate_binary(ivl_expr_t e) { vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); @@ -129,6 +135,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) switch (ivl_expr_opcode(e)) { case '+': return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); + case 'e': + return translate_relation(lhs, rhs, VHDL_BINOP_EQ); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); From 7cde5f247e26b09002f92979db29ec1250bb1a37 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 12:47:41 +0100 Subject: [PATCH 086/377] Add translation for not-equals operator --- tgt-vhdl/expr.cc | 8 +++++++- tgt-vhdl/vhdl_syntax.cc | 3 +++ tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 7aa6d9fca..8e302efc4 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -119,7 +119,11 @@ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { - return new vhdl_binop_expr(lhs, op, rhs, vhdl_type::boolean()); + // Generate any necessary casts + // Arbitrarily, the RHS is casted to the type of the LHS + vhdl_expr *r_cast = rhs->cast(lhs->get_type()); + + return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean()); } static vhdl_expr *translate_binary(ivl_expr_t e) @@ -137,6 +141,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); case 'e': return translate_relation(lhs, rhs, VHDL_BINOP_EQ); + case 'N': + return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index ef33a79ab..fd9ba1805 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -690,6 +690,9 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_EQ: of << " = "; break; + case VHDL_BINOP_NEQ: + of << " /= "; + break; case VHDL_BINOP_ADD: of << " + "; break; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index cf17f8dfd..5ceb45546 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -57,6 +57,7 @@ enum vhdl_binop_t { VHDL_BINOP_AND, VHDL_BINOP_OR, VHDL_BINOP_EQ, + VHDL_BINOP_NEQ, VHDL_BINOP_ADD, }; From ce72eb4eb45ba3c454d75f555a41519f32f5b98a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 14:26:38 +0100 Subject: [PATCH 087/377] Fix Valgrind warnings --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/vhdl_syntax.cc | 11 ++++++----- tgt-vhdl/vhdl_syntax.hh | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 8e302efc4..049b6d0e3 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -59,7 +59,7 @@ static vhdl_expr *translate_signal(ivl_expr_t e) */ static vhdl_expr *translate_number(ivl_expr_t e) { - return new vhdl_const_bits(ivl_expr_bits(e)); + return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e)); } static vhdl_expr *translate_unary(ivl_expr_t e) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index fd9ba1805..a912e70b3 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -187,7 +187,7 @@ vhdl_arch *vhdl_conc_stmt::get_parent() const } vhdl_process::vhdl_process(const char *name) - : name_(name) + : name_(name), initial_(false) { } @@ -547,11 +547,12 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const of << ";"; } -vhdl_const_bits::vhdl_const_bits(const char *value) - : vhdl_expr(vhdl_type::nsigned(strlen(value))), - value_(value) +vhdl_const_bits::vhdl_const_bits(const char *value, int width) + : vhdl_expr(vhdl_type::nsigned(width)) { - + // Can't rely on value being NULL-terminated + while (width--) + value_.push_back(*value++); } vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 5ceb45546..8e576cd42 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -113,7 +113,7 @@ private: class vhdl_const_bits : public vhdl_expr { public: - vhdl_const_bits(const char *value); + vhdl_const_bits(const char *value, int width); void emit(std::ofstream &of, int level) const; const std::string &get_value() const { return value_; } vhdl_expr *cast(const vhdl_type *to); From 83a7796b7489dfc95ee7cb6eb284579d029dfdf4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 17:37:17 +0100 Subject: [PATCH 088/377] Make sure signal names conform to VHDL rules --- tgt-vhdl/scope.cc | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d1c29cd25..77d65e44e 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -140,19 +140,24 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) remember_signal(sig, arch->get_parent()); - const char *name = ivl_signal_basename(sig); + // Make sure the signal name conforms to VHDL naming rules + std::string name(ivl_signal_basename(sig)); + if (name[0] == '_') + name.insert(0, "VL"); + rename_signal(sig, name.c_str()); + ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: - arch->add_decl(new vhdl_signal_decl(name, sig_type)); + arch->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); break; case IVL_SIP_INPUT: arch->get_parent()->add_port - (new vhdl_port_decl(name, sig_type, VHDL_PORT_IN)); + (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); break; case IVL_SIP_OUTPUT: arch->get_parent()->add_port - (new vhdl_port_decl(name, sig_type, VHDL_PORT_OUT)); + (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT)); if (ivl_signal_type(sig) == IVL_SIT_REG) { // A registered output @@ -165,19 +170,19 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) rename_signal(sig, newname.c_str()); vhdl_type *reg_type = new vhdl_type(*sig_type); - arch->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); - + arch->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); + // Create a concurrent assignment statement to // connect the register to the output arch->add_stmt (new vhdl_cassign_stmt - (new vhdl_var_ref(name, NULL), + (new vhdl_var_ref(name.c_str(), NULL), new vhdl_var_ref(newname.c_str(), NULL))); } break; case IVL_SIP_INOUT: arch->get_parent()->add_port - (new vhdl_port_decl(name, sig_type, VHDL_PORT_INOUT)); + (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); break; } } From 561953e494f2b2e95c8de7083d848d0869984214 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 19:41:01 +0100 Subject: [PATCH 089/377] Minial LPM to support continuous assignments --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/lpm.cc | 58 ++++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/scope.cc | 15 ++++++++++- tgt-vhdl/vhdl_target.h | 2 ++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tgt-vhdl/lpm.cc 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); From 8d0afa632d2e2e636641d72e044fff8747768a51 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 19:49:24 +0100 Subject: [PATCH 090/377] Subtraction and multiplication LPM devices --- tgt-vhdl/lpm.cc | 19 ++++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index bc6f92207..8778dff8a 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -38,7 +38,20 @@ static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) 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); + vhdl_expr *expr = new vhdl_binop_expr(lhs, op, rhs, 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); + resize->add_expr(new vhdl_const_int(out_width)); + + expr = resize; + } arch->add_stmt(new vhdl_cassign_stmt(out, expr)); @@ -50,6 +63,10 @@ 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); + case IVL_LPM_SUB: + return draw_binop_lpm(arch, lpm, VHDL_BINOP_SUB); + case IVL_LPM_MULT: + return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return 1; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a912e70b3..3935c0bd7 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -697,6 +697,12 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_ADD: of << " + "; break; + case VHDL_BINOP_SUB: + of << " - "; + break; + case VHDL_BINOP_MULT: + of << " * "; + break; } (*it)->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 8e576cd42..50f70e5b0 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -59,6 +59,8 @@ enum vhdl_binop_t { VHDL_BINOP_EQ, VHDL_BINOP_NEQ, VHDL_BINOP_ADD, + VHDL_BINOP_SUB, + VHDL_BINOP_MULT, }; /* From ae0b09dd3a5ec7aa28627e4cc72180635baa6618 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 19:53:42 +0100 Subject: [PATCH 091/377] Don't bother emitting else part if it's empty --- tgt-vhdl/vhdl_syntax.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3935c0bd7..0af19d8b4 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -631,8 +631,10 @@ void vhdl_if_stmt::emit(std::ofstream &of, int level) const test_->emit(of, level); of << " then"; then_part_.emit(of, level); - of << "else"; - else_part_.emit(of, level); + if (!else_part_.empty()) { + of << "else"; + else_part_.emit(of, level); + } of << "end if;"; } From 1debbc310005b6511397d1cf76975970fae5f021 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 16 Jun 2008 20:06:06 +0100 Subject: [PATCH 092/377] Simplify edge_detector() a bit --- tgt-vhdl/stmt.cc | 22 +++++----------------- tgt-vhdl/vhdl_syntax.hh | 1 + 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 36f19a671..45e464f42 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -277,23 +277,11 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc, vhdl_binop_expr *test, const char *type) { - 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))) { - const char *signame = get_renamed_signal(sig).c_str(); - - vhdl_fcall *detect - = new vhdl_fcall(type, vhdl_type::boolean()); - detect->add_expr - (new vhdl_var_ref(signame, vhdl_type::std_logic())); - test->add_expr(detect); - proc->add_sensitivity(signame); - break; - } - } + vhdl_var_ref *ref = nexus_to_var_ref(proc->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()); } /* diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 50f70e5b0..3399fc8f4 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -48,6 +48,7 @@ public: : vhdl_expr(type), name_(name) {} void emit(std::ofstream &of, int level) const; + const std::string &get_name() const { return name_; } private: std::string name_; }; From 01249000c3d89d14b571fec8cb6f10cd260e242d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 17 Jun 2008 14:07:36 +0100 Subject: [PATCH 093/377] Temporarily treat blocking assignment as non-blocking --- tgt-vhdl/stmt.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 45e464f42..e40ef2002 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -402,6 +402,7 @@ int draw_stmt(vhdl_process *proc, stmt_container *container, return draw_block(proc, container, stmt); case IVL_ST_NOOP: return draw_noop(proc, container, stmt); + case IVL_ST_ASSIGN: // TODO: remove! case IVL_ST_ASSIGN_NB: return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: From af8c08e6a7e10ca3f26783ee335e5175da497b38 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 17 Jun 2008 20:16:16 +0100 Subject: [PATCH 094/377] Allow optional VHPI $finish implementation --- tgt-vhdl/stmt.cc | 15 ++++++++++++++- tgt-vhdl/vhdl.cc | 7 +++++++ tgt-vhdl/vhdl_syntax.cc | 3 ++- tgt-vhdl/vhdl_syntax.hh | 1 + tgt-vhdl/vhdl_target.h | 2 ++ tgt-vhdl/vhpi/finish.c | 6 ++++++ tgt-vhdl/vhpi/verilog_support.vhd | 15 +++++++++++++++ 7 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 tgt-vhdl/vhpi/finish.c create mode 100644 tgt-vhdl/vhpi/verilog_support.vhd diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e40ef2002..1f5c57a11 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -110,11 +110,24 @@ static int draw_stask_display(vhdl_process *proc, stmt_container *container, * the simulator. This isn't great, as the simulator will * return a failure exit code when in fact it completed * successfully. + * + * An alternative is to use the VHPI interface supported by + * some VHDL simulators and implement the $finish funcitonality + * in C. This function can be enabled with the flag + * -puse-vhpi-finish=1. */ static int draw_stask_finish(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { - container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); + const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish"); + if (strcmp(use_vhpi, "1") == 0) { + proc->get_parent()->get_parent()->requires_package("work.Verilog_Support"); + container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish")); + } + else { + container->add_stmt(new vhdl_assert_stmt("SIMULATION FINISHED")); + } + return 0; } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index f2c99b644..29ea76106 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -48,6 +48,7 @@ typedef std::map signal_defn_map_t; static int g_errors = 0; // Total number of errors encountered static entity_list_t g_entities; // All entities to emit static signal_defn_map_t g_known_signals; +static ivl_design_t g_design; /* @@ -124,6 +125,10 @@ const std::string &get_renamed_signal(ivl_signal_t sig) return g_known_signals[sig].renamed; } +ivl_design_t get_vhdl_design() +{ + return g_design; +} extern "C" int target_design(ivl_design_t des) { @@ -131,6 +136,8 @@ extern "C" int target_design(ivl_design_t des) unsigned int nroots; ivl_design_roots(des, &roots, &nroots); + g_design = des; + for (unsigned int i = 0; i < nroots; i++) draw_scope(roots[i], NULL); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 0af19d8b4..f3737b20b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -495,7 +495,8 @@ void vhdl_expr_list::emit(std::ofstream &of, int level) const void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const { of << name_; - exprs_.emit(of, level); + if (!exprs_.empty()) + exprs_.emit(of, level); of << ";"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 3399fc8f4..48beb159d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -147,6 +147,7 @@ public: ~vhdl_expr_list(); void emit(std::ofstream &of, int level) const; + bool empty() const { return exprs_.empty(); } void add_expr(vhdl_expr *e); private: std::list exprs_; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 3612d0e4f..d681afe53 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -22,6 +22,8 @@ vhdl_expr *translate_expr(ivl_expr_t e); void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); +ivl_design_t get_vhdl_design(); + 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); diff --git a/tgt-vhdl/vhpi/finish.c b/tgt-vhdl/vhpi/finish.c new file mode 100644 index 000000000..7a544da0b --- /dev/null +++ b/tgt-vhdl/vhpi/finish.c @@ -0,0 +1,6 @@ +#include + +void finish(void) +{ + exit(0); +} diff --git a/tgt-vhdl/vhpi/verilog_support.vhd b/tgt-vhdl/vhpi/verilog_support.vhd new file mode 100644 index 000000000..eb77c4c06 --- /dev/null +++ b/tgt-vhdl/vhpi/verilog_support.vhd @@ -0,0 +1,15 @@ +-- +-- VHPI support routines for VHDL output. +-- + +package Verilog_Support is + procedure finish; + attribute foreign of finish : procedure is "VHPIDIRECT finish"; +end Verilog_Support; + +package body Verilog_Support is + procedure finish is + begin + assert false severity failure; + end finish; +end Verilog_Support; From d2bebee9d9deddb954d16ed67288552ec937791f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 18 Jun 2008 12:51:11 +0100 Subject: [PATCH 095/377] Refactor before adding blocking assignment --- tgt-vhdl/process.cc | 11 +++++++++++ tgt-vhdl/stmt.cc | 39 ++++++++++++++++++++++++++++----------- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 28 ++++++++++++++++++++-------- tgt-vhdl/vhdl_target.h | 2 ++ 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index b8ae4c27d..f400a504b 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -25,6 +25,17 @@ #include #include +/* + * TODO: Explanation here. + */ +static string_list_t g_assign_vars; + +void blocking_assign_to(std::string var) +{ + std::cout << "blocking_assign_to " << var << std::endl; +} + + /* * Convert a Verilog process to VHDL and add it to the architecture * of the given entity. diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 1f5c57a11..c7e6adf59 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -178,13 +178,9 @@ static int draw_noop(vhdl_process *proc, stmt_container *container, return 0; } -/* - * A non-blocking assignment inside a process. The semantics for - * this are essentially the same as VHDL's non-blocking signal - * assignment. - */ -static int draw_nbassign(vhdl_process *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *after = NULL) +template +static int draw_generic_assign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt, vhdl_expr *after = NULL) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -222,10 +218,10 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - vhdl_nbassign_stmt *nbassign = new vhdl_nbassign_stmt(lval_ref, rhs); + T *assign = new T(lval_ref, rhs); if (after != NULL) - nbassign->set_after(after); - container->add_stmt(nbassign); + assign->set_after(after); + container->add_stmt(assign); } } else { @@ -236,6 +232,26 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, return 0; } +/* + * A non-blocking assignment inside a process. The semantics for + * this are essentially the same as VHDL's non-blocking signal + * assignment. + */ +static int draw_nbassign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt, vhdl_expr *after = NULL) +{ + return draw_generic_assign + (proc, container, stmt, after); +} + +static int draw_assign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) +{ + + + return 0; +} + /* * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. @@ -415,7 +431,8 @@ int draw_stmt(vhdl_process *proc, stmt_container *container, return draw_block(proc, container, stmt); case IVL_ST_NOOP: return draw_noop(proc, container, stmt); - case IVL_ST_ASSIGN: // TODO: remove! + case IVL_ST_ASSIGN: + return draw_assign(proc, container, stmt); case IVL_ST_ASSIGN_NB: return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index f3737b20b..3cfcf6c0c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -525,7 +525,7 @@ void vhdl_fcall::emit(std::ofstream &of, int level) const exprs_.emit(of, level); } -vhdl_nbassign_stmt::~vhdl_nbassign_stmt() +vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt() { delete lhs_; delete rhs_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 48beb159d..30399dfd2 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -227,23 +227,35 @@ private: }; +/* + * Shared between blocking and non-blocking assignment. + */ +class vhdl_abstract_assign_stmt : public vhdl_seq_stmt { +public: + vhdl_abstract_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) + : lhs_(lhs), rhs_(rhs), after_(NULL) {} + virtual ~vhdl_abstract_assign_stmt(); + + void set_after(vhdl_expr *after) { after_ = after; } +protected: + vhdl_var_ref *lhs_; + vhdl_expr *rhs_, *after_; +}; + + /* * Similar to Verilog non-blocking assignment, except the LHS * must be a signal not a variable. */ -class vhdl_nbassign_stmt : public vhdl_seq_stmt { +class vhdl_nbassign_stmt : public vhdl_abstract_assign_stmt { public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) - : lhs_(lhs), rhs_(rhs), after_(NULL) {} - ~vhdl_nbassign_stmt(); - - void set_after(vhdl_expr *after) { after_ = after; } + : vhdl_abstract_assign_stmt(lhs, rhs) {} + void emit(std::ofstream &of, int level) const; -private: - vhdl_var_ref *lhs_; - vhdl_expr *rhs_, *after_; }; + enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR_NS, // Wait for a constant number of nanoseconds diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index d681afe53..0401c33e3 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -31,6 +31,8 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed); const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); +void blocking_assign_to(std::string var); + #endif /* #ifndef INC_VHDL_TARGET_H */ From 254ccb9ccb4d6721fcb43824d0444fc904e4fc49 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 18 Jun 2008 13:06:27 +0100 Subject: [PATCH 096/377] First passing at blocking assignment --- tgt-vhdl/process.cc | 6 ++-- tgt-vhdl/stmt.cc | 63 ++++++++++++++++++++++++++++++----------- tgt-vhdl/vhdl_syntax.cc | 21 ++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 10 +++++++ tgt-vhdl/vhdl_target.h | 2 +- 5 files changed, 82 insertions(+), 20 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index f400a504b..1342f1e53 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -24,13 +24,15 @@ #include #include #include +#include /* * TODO: Explanation here. */ -static string_list_t g_assign_vars; +typedef std::set string_set_t; +static string_set_t g_assign_vars; -void blocking_assign_to(std::string var) +void blocking_assign_to(vhdl_process *proc, std::string var) { std::cout << "blocking_assign_to " << var << std::endl; } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c7e6adf59..7a8a6075c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -178,9 +178,13 @@ static int draw_noop(vhdl_process *proc, stmt_container *container, return 0; } -template -static int draw_generic_assign(vhdl_process *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *after = NULL) +/* + * A non-blocking assignment inside a process. The semantics for + * this are essentially the same as VHDL's non-blocking signal + * assignment. + */ +static int draw_nbassign(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt, vhdl_expr *after = NULL) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { @@ -218,7 +222,7 @@ static int draw_generic_assign(vhdl_process *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - T *assign = new T(lval_ref, rhs); + vhdl_nbassign_stmt *assign = new vhdl_nbassign_stmt(lval_ref, rhs); if (after != NULL) assign->set_after(after); container->add_stmt(assign); @@ -232,22 +236,47 @@ static int draw_generic_assign(vhdl_process *proc, stmt_container *container, return 0; } -/* - * A non-blocking assignment inside a process. The semantics for - * this are essentially the same as VHDL's non-blocking signal - * assignment. - */ -static int draw_nbassign(vhdl_process *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *after = NULL) -{ - return draw_generic_assign - (proc, container, stmt, after); -} - static int draw_assign(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { - + int nlvals = ivl_stmt_lvals(stmt); + if (nlvals != 1) { + error("Can only have 1 lval at the moment (found %d)", nlvals); + return 1; + } + + ivl_lval_t lval = ivl_stmt_lval(stmt, 0); + ivl_signal_t sig; + if ((sig = ivl_lval_sig(lval))) { + const std::string &signame = get_renamed_signal(sig); + + blocking_assign_to(proc, signame); + + vhdl_decl *decl = proc->get_decl(signame); + assert(decl); + + vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); + if (NULL == rhs_raw) + return 1; + vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); + + // As with non-blocking assignment, push assignments into the + // initialisation if we can + if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE) { + decl->set_initial(rhs); + } + else { + // The type here can be null as it is never actually needed + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); + + vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, rhs); + container->add_stmt(assign); + } + } + else { + error("Only signals as lvals supported at the moment"); + return 1; + } return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3cfcf6c0c..4a55dbf21 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -202,6 +202,19 @@ void vhdl_process::add_decl(vhdl_decl* decl) decls_.push_back(decl); } +vhdl_decl *vhdl_process::get_decl(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return *it; + } + + // Maybe it's a signal rather than a variable? + assert(get_parent()); + return get_parent()->get_decl(name); +} + void vhdl_process::add_sensitivity(const char *name) { sens_.push_back(name); @@ -548,6 +561,14 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const of << ";"; } +void vhdl_assign_stmt::emit(std::ofstream &of, int level) const +{ + lhs_->emit(of, level); + of << " := "; + rhs_->emit(of, level); + of << ";"; +} + vhdl_const_bits::vhdl_const_bits(const char *value, int width) : vhdl_expr(vhdl_type::nsigned(width)) { diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 30399dfd2..07a9efa1f 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -256,6 +256,15 @@ public: }; +class vhdl_assign_stmt : public vhdl_abstract_assign_stmt { +public: + vhdl_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) + : vhdl_abstract_assign_stmt(lhs, rhs) {} + + void emit(std::ofstream &of, int level) const; +}; + + enum vhdl_wait_type_t { VHDL_WAIT_INDEF, // Suspend indefinitely VHDL_WAIT_FOR_NS, // Wait for a constant number of nanoseconds @@ -456,6 +465,7 @@ public: void add_decl(vhdl_decl *decl); void add_sensitivity(const char *name); bool have_declared_var(const std::string &name) const; + vhdl_decl *get_decl(const std::string &name) const; void set_initial(bool i) { initial_ = i; } bool is_initial() const { return initial_; } private: diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 0401c33e3..785b01000 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -31,7 +31,7 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed); const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); -void blocking_assign_to(std::string var); +void blocking_assign_to(vhdl_process *proc, std::string var); #endif /* #ifndef INC_VHDL_TARGET_H */ From fb31a88c51727ccdb663e7cde01c98c498b7672a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 18 Jun 2008 13:30:19 +0100 Subject: [PATCH 097/377] Blocking assignment nearly working --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/process.cc | 31 ++++++++++++++++++++++++++++++- tgt-vhdl/stmt.cc | 9 ++++++--- tgt-vhdl/vhdl_target.h | 3 ++- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 049b6d0e3..bdc9723cc 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -46,7 +46,7 @@ static vhdl_expr *translate_signal(ivl_expr_t e) const char *renamed = get_renamed_signal(sig).c_str(); - const vhdl_decl *decl = ent->get_arch()->get_decl(renamed); + const vhdl_decl *decl = ent->get_arch()->get_decl(strip_var(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 1342f1e53..d6f310e50 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -32,11 +32,40 @@ typedef std::set string_set_t; static string_set_t g_assign_vars; -void blocking_assign_to(vhdl_process *proc, std::string var) +void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) { + std::string var(get_renamed_signal(sig)); + std::cout << "blocking_assign_to " << var << std::endl; + + 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. + + vhdl_decl *decl = proc->get_parent()->get_decl(var); + assert(decl); + vhdl_type *type = new vhdl_type(*decl->get_type()); + + var += "_Var"; + proc->add_decl(new vhdl_var_decl(var.c_str(), type)); + + rename_signal(sig, var); + g_assign_vars.insert(var); + } } +/* + * 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 diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 7a8a6075c..6d7b254bb 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -250,8 +250,6 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, if ((sig = ivl_lval_sig(lval))) { const std::string &signame = get_renamed_signal(sig); - blocking_assign_to(proc, signame); - vhdl_decl *decl = proc->get_decl(signame); assert(decl); @@ -266,8 +264,13 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, decl->set_initial(rhs); } else { + blocking_assign_to(proc, sig); + + // The signal may have been renamed by the above call + const std::string &renamed = get_renamed_signal(sig); + // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); + vhdl_var_ref *lval_ref = new vhdl_var_ref(renamed.c_str(), NULL); vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, rhs); container->add_stmt(assign); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 785b01000..befdbd2eb 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -31,7 +31,8 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed); const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); -void blocking_assign_to(vhdl_process *proc, std::string var); +void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig); +std::string strip_var(const std::string &str); #endif /* #ifndef INC_VHDL_TARGET_H */ From e0f41198d632ce371b5ea3c2af8f899b7747f675 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 18 Jun 2008 13:49:03 +0100 Subject: [PATCH 098/377] Blocking assignment working correctly --- tgt-vhdl/process.cc | 40 ++++++++++++++++++++++++++++++++++++---- tgt-vhdl/stmt.cc | 4 ++++ tgt-vhdl/vhdl_target.h | 2 +- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index d6f310e50..c5136e7fd 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -24,13 +24,13 @@ #include #include #include -#include +#include /* * TODO: Explanation here. */ -typedef std::set string_set_t; -static string_set_t g_assign_vars; +typedef std::map var_temp_set_t; +static var_temp_set_t g_assign_vars; void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) { @@ -51,10 +51,39 @@ void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) proc->add_decl(new vhdl_var_decl(var.c_str(), type)); rename_signal(sig, var); - g_assign_vars.insert(var); + g_assign_vars[var] = 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_process *proc) +{ + 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_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); + + // TODO: I'm not sure this will work properly if, e.g., the delay + // is inside a `if' statement + proc->get_container()->add_stmt(new vhdl_nbassign_stmt(lhs, rhs)); + + // Undo the renaming (since the temporary is no longer needed) + rename_signal((*it).second, stripped); + } + + g_assign_vars.clear(); +} + /* * Remove _Var from the end of a string, if it is present. */ @@ -111,6 +140,9 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ss << ivl_scope_tname(scope); vhdl_proc->set_comment(ss.str()); + // Output any remaning blocking assignments + draw_blocking_assigns(vhdl_proc); + return 0; } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 6d7b254bb..0f410d667 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -311,6 +311,10 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, draw_nbassign(proc, container, sub_stmt, time); } else { + // All blocking assignments need to be made visible + // at this point + draw_blocking_assigns(proc); + vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, time); container->add_stmt(wait); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index befdbd2eb..cfad1dc13 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -33,7 +33,7 @@ const std::string &get_renamed_signal(ivl_signal_t sig); void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig); std::string strip_var(const std::string &str); - +void draw_blocking_assigns(vhdl_process *proc); #endif /* #ifndef INC_VHDL_TARGET_H */ From be12f56856e5db5e680a31b6fa158f3eefcdfdcc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 18 Jun 2008 14:04:16 +0100 Subject: [PATCH 099/377] Document blocking assignment behaviour --- tgt-vhdl/process.cc | 72 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index c5136e7fd..2a238d7b5 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -27,31 +27,75 @@ #include /* - * TODO: Explanation here. + * 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. This + * has exactly the same (external) behaviour as the Verilog + * blocking assignment, since no external process will be able + * to observe that the assignment wasn't made immediately. + * + * 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_process *proc, ivl_signal_t sig) { std::string var(get_renamed_signal(sig)); - - std::cout << "blocking_assign_to " << var << std::endl; - + 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. - - vhdl_decl *decl = proc->get_parent()->get_decl(var); - assert(decl); - vhdl_type *type = new vhdl_type(*decl->get_type()); - - var += "_Var"; - proc->add_decl(new vhdl_var_decl(var.c_str(), type)); - - rename_signal(sig, var); - g_assign_vars[var] = sig; + if (!proc->have_declared_var(tmpname)) { + vhdl_decl *decl = proc->get_parent()->get_decl(var); + assert(decl); + vhdl_type *type = new vhdl_type(*decl->get_type()); + + proc->add_decl(new vhdl_var_decl(tmpname.c_str(), type)); + } + + rename_signal(sig, tmpname); + g_assign_vars[tmpname] = sig; } } From d7bb5658f2c24e37352941985e1c732ed103ffab Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 19 Jun 2008 12:16:19 +0100 Subject: [PATCH 100/377] Translate IVL_ST_DELAYX statements --- tgt-vhdl/stmt.cc | 23 +++++++++++++++++++---- tgt-vhdl/vhdl_syntax.cc | 19 ++++++++++++++++--- tgt-vhdl/vhdl_syntax.hh | 18 ++++++++++++++++-- tgt-vhdl/vhdl_type.cc | 5 +++++ tgt-vhdl/vhdl_type.hh | 2 ++ 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 0f410d667..9ae5d7711 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -291,8 +291,6 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, static int draw_delay(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { - uint64_t value = ivl_stmt_delay_val(stmt); - // This currently ignores the time units and precision // of the enclosing scope // A neat way to do this would be to make these values @@ -300,7 +298,23 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, // VHDL wait statement compute the value from that. // The other solution is to add them as parameters to // the vhdl_process class - vhdl_expr *time = new vhdl_const_int(value); + vhdl_expr *time; + if (ivl_statement_type(stmt) == IVL_ST_DELAY) { + uint64_t value = ivl_stmt_delay_val(stmt); + time = new vhdl_const_time(value, TIME_UNIT_NS); + } + else { + time = translate_expr(ivl_stmt_delay_expr(stmt)); + if (NULL == time) + return 1; + + vhdl_type integer(VHDL_TYPE_INTEGER); + time = time->cast(&integer); + + vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS); + time = new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, + vhdl_type::time()); + } // If the sub-statement is an assignment then VHDL lets // us put the delay after it, which is more compact and @@ -316,7 +330,7 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, draw_blocking_assigns(proc); vhdl_wait_stmt *wait = - new vhdl_wait_stmt(VHDL_WAIT_FOR_NS, time); + new vhdl_wait_stmt(VHDL_WAIT_FOR, time); container->add_stmt(wait); // Expand the sub-statement as well @@ -472,6 +486,7 @@ int draw_stmt(vhdl_process *proc, stmt_container *container, case IVL_ST_ASSIGN_NB: return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: + case IVL_ST_DELAYX: return draw_delay(proc, container, stmt); case IVL_ST_WAIT: return draw_wait(proc, container, stmt); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 4a55dbf21..787cda7ea 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -378,11 +378,10 @@ void vhdl_wait_stmt::emit(std::ofstream &of, int level) const switch (type_) { case VHDL_WAIT_INDEF: break; - case VHDL_WAIT_FOR_NS: + case VHDL_WAIT_FOR: assert(expr_); of << " for "; expr_->emit(of, level); - of << " ns"; break; } @@ -471,6 +470,12 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return new vhdl_binop_expr (this, VHDL_BINOP_EQ, one, vhdl_type::boolean()); } + 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 { vhdl_fcall *conv = new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); @@ -555,7 +560,6 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const if (after_) { of << " after "; after_->emit(of, level); - of << " ns"; } of << ";"; @@ -615,6 +619,15 @@ void vhdl_const_int::emit(std::ofstream &of, int level) const of << value_; } +void vhdl_const_time::emit(std::ofstream &of, int level) const +{ + of << value_; + switch (units_) { + case TIME_UNIT_NS: + of << " ns"; + } +} + vhdl_cassign_stmt::~vhdl_cassign_stmt() { delete lhs_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 07a9efa1f..c89e20d42 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -133,6 +133,20 @@ private: char bit_; }; +enum time_unit_t { + TIME_UNIT_NS, +}; + +class vhdl_const_time : public vhdl_expr { +public: + vhdl_const_time(int64_t value, time_unit_t units) + : vhdl_expr(vhdl_type::time()), value_(value), units_(units) {} + void emit(std::ofstream &of, int level) const; +private: + int64_t value_; + time_unit_t units_; +}; + class vhdl_const_int : public vhdl_expr { public: vhdl_const_int(int64_t value) @@ -266,8 +280,8 @@ public: enum vhdl_wait_type_t { - VHDL_WAIT_INDEF, // Suspend indefinitely - VHDL_WAIT_FOR_NS, // Wait for a constant number of nanoseconds + VHDL_WAIT_INDEF, // Suspend indefinitely + VHDL_WAIT_FOR, // Wait for a constant amount of time }; /* diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 6180a839e..4176cfce4 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -58,6 +58,11 @@ vhdl_type *vhdl_type::nsigned(int width) return new vhdl_type(VHDL_TYPE_SIGNED, width-1, 0); } +vhdl_type *vhdl_type::time() +{ + return new vhdl_type(VHDL_TYPE_TIME); +} + /* * This is just the name of the type, without any parameters. */ diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 341c5585a..e4e41d3e2 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -33,6 +33,7 @@ enum vhdl_type_name_t { VHDL_TYPE_BOOLEAN, VHDL_TYPE_SIGNED, VHDL_TYPE_UNSIGNED, + VHDL_TYPE_TIME, }; /* @@ -63,6 +64,7 @@ public: static vhdl_type *nsigned(int width); static vhdl_type *integer(); static vhdl_type *boolean(); + static vhdl_type *time(); protected: vhdl_type_name_t name_; int msb_, lsb_; From 6622b5fe3a48b4f5a43b6ca0a64e2029c3cb2a60 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 19 Jun 2008 16:08:33 +0100 Subject: [PATCH 101/377] Compare logic values for === and !== --- tgt-vhdl/expr.cc | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index bdc9723cc..3a0515d0f 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -70,6 +70,7 @@ static vhdl_expr *translate_unary(ivl_expr_t e) switch (ivl_expr_opcode(e)) { case '!': + case '~': return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); default: @@ -136,13 +137,36 @@ static vhdl_expr *translate_binary(ivl_expr_t e) if (NULL == rhs) return NULL; + // For === and !== we need to compare std_logic_vectors + // rather than signeds + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + bool vectorop = + (lhs->get_type()->get_name() == VHDL_TYPE_SIGNED + || lhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED) && + (rhs->get_type()->get_name() == VHDL_TYPE_SIGNED + || rhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED); + switch (ivl_expr_opcode(e)) { case '+': return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); case 'e': return translate_relation(lhs, rhs, VHDL_BINOP_EQ); - case 'N': + case 'E': + if (vectorop) + return translate_relation(lhs->cast(&std_logic_vector), + rhs->cast(&std_logic_vector), VHDL_BINOP_EQ); + else + return translate_relation(lhs, rhs, VHDL_BINOP_EQ); + case 'n': return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + case 'N': + if (vectorop) + return translate_relation(lhs->cast(&std_logic_vector), + rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); + else + return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + case 'o': + return translate_relation(lhs, rhs, VHDL_BINOP_OR); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); From 08d80b35cb02ec56fedc67baedde748ac6d3f075 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 19 Jun 2008 16:15:47 +0100 Subject: [PATCH 102/377] Rename signals that would be illegal VHDL names --- tgt-vhdl/scope.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 51ad1f2c3..3d0ecfa03 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -141,9 +141,20 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) remember_signal(sig, arch->get_parent()); // Make sure the signal name conforms to VHDL naming rules - std::string name(ivl_signal_basename(sig)); + std::string name(ivl_signal_basename(sig)); if (name[0] == '_') name.insert(0, "VL"); + + const char *vhdl_reserved[] = { + "in", "out", "entity", "architecture", "inout", // Etc... + NULL + }; + for (const char **p = vhdl_reserved; *p != NULL; p++) { + if (name == *p) { + name.insert(0, "VL_"); + break; + } + } rename_signal(sig, name.c_str()); ivl_signal_port_t mode = ivl_signal_port(sig); From 404c22ac8626953fdbdeb51053a5cbe383d3d396 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 20 Jun 2008 11:51:13 +0100 Subject: [PATCH 103/377] Improved implementation of $display --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/display.cc | 159 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/stmt.cc | 79 -------------------- tgt-vhdl/vhdl_target.h | 3 + 4 files changed, 163 insertions(+), 80 deletions(-) create mode 100644 tgt-vhdl/display.cc diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 0827b5f5c..1b2f15a1c 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 + stmt.o expr.o lpm.o display.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc new file mode 100644 index 000000000..998666a0e --- /dev/null +++ b/tgt-vhdl/display.cc @@ -0,0 +1,159 @@ +/* + * VHDL implementation of $display. + * + * 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 +#include +#include +#include + +static const char *DISPLAY_LINE = "Verilog_Display_Line"; + +/* + * Write a VHDL expression into the current display line. + */ +static void display_write(stmt_container *container, vhdl_expr *expr) +{ + vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); + vhdl_var_ref *ref = + new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); + write->add_expr(ref); + + // Need to add a call to Type'Image for types not + // supported by std.textio + if (expr->get_type()->get_name() != VHDL_TYPE_STRING) { + std::string name(expr->get_type()->get_string()); + name += "'Image"; + + vhdl_fcall *cast + = new vhdl_fcall(name.c_str(), vhdl_type::string()); + cast->add_expr(expr); + + write->add_expr(cast); + } + else + write->add_expr(expr); + + container->add_stmt(write); +} + +/* + * Write the value of DISPLAY_LINE to the output. + */ +static void display_line(stmt_container *container) +{ + vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); + vhdl_var_ref *output_ref = + new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE)); + write_line->add_expr(output_ref); + vhdl_var_ref *ref = + new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); + write_line->add_expr(ref); + container->add_stmt(write_line); +} + +/* + * Parse an octal escape sequence. + */ +static char parse_octal(const char *p) +{ + assert(*p && *(p+1) && *(p+2)); + assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1))); + + return (*p - '0') * 64 + + (*(p+1) - '0') * 8 + + (*(p+2) - '0') * 1; +} + +/* + * Generate VHDL for the $display system task. + * This is implemented using the functions in std.textio. Each + * parameter is written to a line variable in the process and + * then the line is written to the special variable `Output' + * (which represents the console). Subsequent $displays will + * use the same line variable. + * + * It's possible, although quite unlikely, that there will be + * name collision with an existing variable called + * `Verilog_Display_Line' -- do something about this? + */ +int draw_stask_display(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt, bool newline) +{ + // Add the package requirement to the containing entity + proc->get_parent()->get_parent()->requires_package("std.textio"); + + if (!proc->have_declared_var(DISPLAY_LINE)) { + vhdl_var_decl *line_var = + new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line()); + line_var->set_comment("For generating $display output"); + proc->add_decl(line_var); + } + + // Write the data into the line + int count = ivl_stmt_parm_count(stmt), i = 0; + while (i < count) { + // $display may have an empty parameter, in which case + // the expression will be null + // The behaviour here seems to be to output a space + ivl_expr_t net = ivl_stmt_parm(stmt, i++); + if (net) { + if (ivl_expr_type(net) == IVL_EX_STRING) { + std::ostringstream ss; + for (const char *p = ivl_expr_string(net); *p; p++) { + if (*p == '\\') { + // Octal escape + char ch = parse_octal(p+1); + if (ch == '\n') { + display_write(container, + new vhdl_const_string(ss.str().c_str())); + display_line(container); + + // Clear the stream + ss.str(""); + } + else + ss << ch; + p += 4; + } + else + ss << *p; + } + + display_write(container, new vhdl_const_string(ss.str().c_str())); + } + else { + vhdl_expr *base = translate_expr(net); + if (NULL == base) + return 1; + + display_write(container, base); + } + } + else + display_write(container, new vhdl_const_string(" ")); + } + + display_line(container); + + return 0; +} diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 9ae5d7711..ab8accd68 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -25,85 +25,6 @@ #include #include -/* - * Generate VHDL for the $display system task. - * This is implemented using the functions in std.textio. Each - * parameter is written to a line variable in the process and - * then the line is written to the special variable `Output' - * (which represents the console). Subsequent $displays will - * use the same line variable. - * - * It's possible, although quite unlikely, that there will be - * name collision with an existing variable called - * `Verilog_Display_Line' -- do something about this? - */ -static int draw_stask_display(vhdl_process *proc, stmt_container *container, - ivl_statement_t stmt) -{ - // Add the package requirement to the containing entity - proc->get_parent()->get_parent()->requires_package("std.textio"); - - const char *display_line = "Verilog_Display_Line"; - - if (!proc->have_declared_var(display_line)) { - vhdl_var_decl *line_var = - new vhdl_var_decl(display_line, vhdl_type::line()); - line_var->set_comment("For generating $display output"); - proc->add_decl(line_var); - } - - // Write the data into the line - int count = ivl_stmt_parm_count(stmt); - for (int i = 0; i < count; i++) { - // $display may have an empty parameter, in which case - // the expression will be null - // The behaviour here seems to be to output a space - ivl_expr_t net = ivl_stmt_parm(stmt, i); - vhdl_expr *e = NULL; - if (net) { - vhdl_expr *base = translate_expr(net); - if (NULL == base) - return 1; - - // Need to add a call to Type'Image for types not - // supported by std.textio - if (base->get_type()->get_name() != VHDL_TYPE_STRING) { - std::string name(base->get_type()->get_string()); - name += "'Image"; - - vhdl_fcall *cast - = new vhdl_fcall(name.c_str(), vhdl_type::string()); - cast->add_expr(base); - e = cast; - } - else - e = base; - } - else - e = new vhdl_const_string(" "); - - vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write"); - vhdl_var_ref *ref = - new vhdl_var_ref(display_line, vhdl_type::line()); - write->add_expr(ref); - write->add_expr(e); - - container->add_stmt(write); - } - - // WriteLine(Output, Verilog_Display_Line) - vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine"); - vhdl_var_ref *output_ref = - new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE)); - write_line->add_expr(output_ref); - vhdl_var_ref *ref = - new vhdl_var_ref(display_line, vhdl_type::line()); - write_line->add_expr(ref); - container->add_stmt(write_line); - - return 0; -} - /* * VHDL has no real equivalent of Verilog's $finish task. The * current solution is to use `assert false ...' to terminate diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index cfad1dc13..ee51d2a78 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -35,5 +35,8 @@ void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig); std::string strip_var(const std::string &str); void draw_blocking_assigns(vhdl_process *proc); +int draw_stask_display(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt, bool newline = true); + #endif /* #ifndef INC_VHDL_TARGET_H */ From 0f50849fbb10d7dc22656af36c39ed7812ab2c26 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 20 Jun 2008 18:26:39 +0100 Subject: [PATCH 104/377] Add call to To_Integer when printing signed/unsigned --- tgt-vhdl/display.cc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 998666a0e..a461f9017 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -38,9 +38,17 @@ static void display_write(stmt_container *container, vhdl_expr *expr) new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line()); write->add_expr(ref); - // Need to add a call to Type'Image for types not - // supported by std.textio - if (expr->get_type()->get_name() != VHDL_TYPE_STRING) { + vhdl_type_name_t type = expr->get_type()->get_name(); + if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) { + vhdl_fcall *toint = + new vhdl_fcall("To_Integer", vhdl_type::integer()); + toint->add_expr(expr); + + write->add_expr(toint); + } + else if (type != VHDL_TYPE_STRING) { + // Need to add a call to Type'Image for types not + // supported by std.textio std::string name(expr->get_type()->get_string()); name += "'Image"; From 204862ac3c0085286a3fbdd24fc26e1d8e1f882e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 20 Jun 2008 19:00:07 +0100 Subject: [PATCH 105/377] Implement $write --- tgt-vhdl/display.cc | 3 ++- tgt-vhdl/stmt.cc | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index a461f9017..e2f43bc99 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -161,7 +161,8 @@ int draw_stask_display(vhdl_process *proc, stmt_container *container, display_write(container, new vhdl_const_string(" ")); } - display_line(container); + if (newline) + display_line(container); return 0; } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index ab8accd68..ab3bad469 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -62,7 +62,9 @@ static int draw_stask(vhdl_process *proc, stmt_container *container, const char *name = ivl_stmt_name(stmt); if (strcmp(name, "$display") == 0) - return draw_stask_display(proc, container, stmt); + return draw_stask_display(proc, container, stmt, true); + else if (strcmp(name, "$write") == 0) + return draw_stask_display(proc, container, stmt, false); else if (strcmp(name, "$finish") == 0) return draw_stask_finish(proc, container, stmt); else { From 037ce08f72d91941552baa98cbc88a25b784f752 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 14:42:54 +0100 Subject: [PATCH 106/377] Fix tiny bug in $display code --- tgt-vhdl/display.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index e2f43bc99..8f9b06e4c 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -141,7 +141,7 @@ int draw_stask_display(vhdl_process *proc, stmt_container *container, } else ss << ch; - p += 4; + p += 3; } else ss << *p; From 0caf4fd9d0be8be29f59fd9a5a2f818496945016 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 15:03:36 +0100 Subject: [PATCH 107/377] Add case statement --- tgt-vhdl/expr.cc | 1 + tgt-vhdl/stmt.cc | 28 ++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 28 ++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 31 +++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 3a0515d0f..78abbf14e 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -181,6 +181,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) */ vhdl_expr *translate_expr(ivl_expr_t e) { + assert(e); ivl_expr_type_t type = ivl_expr_type(e); switch (type) { diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index ab3bad469..d0bd3ea69 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -388,6 +388,30 @@ static int draw_if(vhdl_process *proc, stmt_container *container, return 0; } +static int draw_case(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) +{ + vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); + if (NULL == test) + return 1; + + vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test); + container->add_stmt(vhdlcase); + + int nbranches = ivl_stmt_case_count(stmt); + for (int i = 0; i < nbranches; i++) { + vhdl_expr *when = translate_expr(ivl_stmt_case_expr(stmt, i)); + if (NULL == when) + return 1; + + vhdl_case_branch *branch = new vhdl_case_branch(when); + + draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); + } + + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the @@ -397,6 +421,8 @@ static int draw_if(vhdl_process *proc, stmt_container *container, int draw_stmt(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt) { + assert(stmt); + switch (ivl_statement_type(stmt)) { case IVL_ST_STASK: return draw_stask(proc, container, stmt); @@ -415,6 +441,8 @@ int draw_stmt(vhdl_process *proc, stmt_container *container, return draw_wait(proc, container, stmt); case IVL_ST_CONDIT: return draw_if(proc, container, stmt); + case IVL_ST_CASE: + return draw_case(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 787cda7ea..e9ebec260 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -748,6 +748,34 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const of << ")"; } +vhdl_case_branch::~vhdl_case_branch() +{ + delete when_; +} + +void vhdl_case_branch::emit(std::ofstream &of, int level) const +{ + of << "when "; + when_->emit(of, level); + of << " =>"; + newline(of, indent(level)); + stmts_.emit(of, indent(level)); +} + +vhdl_case_stmt::~vhdl_case_stmt() +{ + delete test_; +} + +void vhdl_case_stmt::emit(std::ofstream &of, int level) const +{ + of << "case "; + test_->emit(of, level); + of << " is"; + emit_children(of, branches_, level); + of << "end case;"; +} + diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c89e20d42..5e3552c16 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -333,6 +333,37 @@ private: }; +/* + * A single branch in a case statement consisting of an + * expression part and a statement container. + */ +class vhdl_case_branch : public vhdl_element { +public: + vhdl_case_branch(vhdl_expr *when) : when_(when) {} + ~vhdl_case_branch(); + + stmt_container *get_container() { return &stmts_; } + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *when_; + stmt_container stmts_; +}; + +typedef std::list case_branch_list_t; + +class vhdl_case_stmt : public vhdl_seq_stmt { +public: + vhdl_case_stmt(vhdl_expr *test) : test_(test) {} + ~vhdl_case_stmt(); + + void add_branch(vhdl_case_branch *b) { branches_.push_back(b); } + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *test_; + case_branch_list_t branches_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From 58f2f5007d6eee7e4a8a2b14c6b3ac153bf78ec2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 15:05:48 +0100 Subject: [PATCH 108/377] Bitwise AND --- tgt-vhdl/expr.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 78abbf14e..1e024a554 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -165,6 +165,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); else return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + case '&': // Bitwise AND + return translate_numeric(lhs, rhs, VHDL_BINOP_AND); case 'o': return translate_relation(lhs, rhs, VHDL_BINOP_OR); default: From ec23b70bb78db8f95f1e6a859b28f03ad0ff6670 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 15:13:44 +0100 Subject: [PATCH 109/377] While loops --- tgt-vhdl/stmt.cc | 17 +++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 16 ++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 13 +++++++++++++ 3 files changed, 46 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index d0bd3ea69..47ab005f1 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -412,6 +412,21 @@ static int draw_case(vhdl_process *proc, stmt_container *container, return 0; } +int draw_while(vhdl_process *proc, stmt_container *container, + ivl_statement_t stmt) +{ + vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); + if (NULL == test) + return 1; + + vhdl_while_stmt *loop = new vhdl_while_stmt(test); + container->add_stmt(loop); + + draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); + + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the @@ -443,6 +458,8 @@ int draw_stmt(vhdl_process *proc, stmt_container *container, return draw_if(proc, container, stmt); case IVL_ST_CASE: return draw_case(proc, container, stmt); + case IVL_ST_WHILE: + return draw_while(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e9ebec260..a01a47029 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -776,6 +776,22 @@ void vhdl_case_stmt::emit(std::ofstream &of, int level) const of << "end case;"; } +vhdl_while_stmt::~vhdl_while_stmt() +{ + delete test_; +} + +void vhdl_while_stmt::emit(std::ofstream &of, int level) const +{ + of << "while "; + test_->emit(of, level); + of << " loop"; + stmts_.emit(of, indent(level)); + of << "end loop;"; +} + + + diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 5e3552c16..92f3bcc32 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -364,6 +364,19 @@ private: }; +class vhdl_while_stmt : public vhdl_seq_stmt { +public: + vhdl_while_stmt(vhdl_expr *test) : test_(test) {} + ~vhdl_while_stmt(); + + stmt_container *get_container() { return &stmts_; } + void emit(std::ofstream &of, int level) const; +private: + vhdl_expr *test_; + stmt_container stmts_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From d6acb8d05924320c345c3dabb0662f38cdf78ba7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 15:16:22 +0100 Subject: [PATCH 110/377] Less than / greater than --- tgt-vhdl/expr.cc | 4 ++++ tgt-vhdl/vhdl_syntax.cc | 13 ++++++------- tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 1e024a554..937d26f83 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -169,6 +169,10 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_numeric(lhs, rhs, VHDL_BINOP_AND); case 'o': return translate_relation(lhs, rhs, VHDL_BINOP_OR); + case '<': + return translate_relation(lhs, rhs, VHDL_BINOP_LT); + case '>': + return translate_relation(lhs, rhs, VHDL_BINOP_GT); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a01a47029..700bb3d7b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -740,6 +740,12 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_MULT: of << " * "; break; + case VHDL_BINOP_LT: + of << " < "; + break; + case VHDL_BINOP_GT: + of << " > "; + break; } (*it)->emit(of, level); @@ -789,10 +795,3 @@ void vhdl_while_stmt::emit(std::ofstream &of, int level) const stmts_.emit(of, indent(level)); of << "end loop;"; } - - - - - - - diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 92f3bcc32..529bf2deb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -62,6 +62,8 @@ enum vhdl_binop_t { VHDL_BINOP_ADD, VHDL_BINOP_SUB, VHDL_BINOP_MULT, + VHDL_BINOP_LT, + VHDL_BINOP_GT, }; /* From 7cba9f3cb2e97d37864f4e7855f5a9b391649d8b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 15:19:33 +0100 Subject: [PATCH 111/377] Shift left/right --- tgt-vhdl/expr.cc | 4 ++++ tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 12 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 937d26f83..e86ef2aef 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -173,6 +173,10 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_relation(lhs, rhs, VHDL_BINOP_LT); case '>': return translate_relation(lhs, rhs, VHDL_BINOP_GT); + case 'l': + return translate_numeric(lhs, rhs, VHDL_BINOP_SL); + case 'r': + return translate_numeric(lhs, rhs, VHDL_BINOP_SR); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 700bb3d7b..0b3976259 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -746,6 +746,12 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_GT: of << " > "; break; + case VHDL_BINOP_SL: + of << " sll "; + break; + case VHDL_BINOP_SR: + of << " srl "; + break; } (*it)->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 529bf2deb..625d2a13d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -64,6 +64,8 @@ enum vhdl_binop_t { VHDL_BINOP_MULT, VHDL_BINOP_LT, VHDL_BINOP_GT, + VHDL_BINOP_SL, + VHDL_BINOP_SR, }; /* From c70fb4ba0823dc5c621bf52739116f84c9bc593e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 16:17:44 +0100 Subject: [PATCH 112/377] Simple implementation of IVL_EX_SELECT --- tgt-vhdl/expr.cc | 21 ++++++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 11 +++++++++++ tgt-vhdl/vhdl_syntax.hh | 11 +++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index e86ef2aef..a7f8e6982 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -37,7 +37,7 @@ static vhdl_expr *translate_string(ivl_expr_t e) * A reference to a signal in an expression. It's assumed that the * signal has already been defined elsewhere. */ -static vhdl_expr *translate_signal(ivl_expr_t e) +static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); @@ -149,6 +149,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) switch (ivl_expr_opcode(e)) { case '+': return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); + case '-': + return translate_numeric(lhs, rhs, VHDL_BINOP_SUB); case 'e': return translate_relation(lhs, rhs, VHDL_BINOP_EQ); case 'E': @@ -186,6 +188,21 @@ static vhdl_expr *translate_binary(ivl_expr_t e) } } +vhdl_expr *translate_select(ivl_expr_t e) +{ + vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); + if (NULL == from) + return NULL; + + // Hack: resize it to the correct size + vhdl_type *rtype = vhdl_type::nsigned(ivl_expr_width(e)); + vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); + resize->add_expr(from); + resize->add_expr(new vhdl_const_int(ivl_expr_width(e))); + + return resize; +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -205,6 +222,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_unary(e); case IVL_EX_BINARY: return translate_binary(e); + case IVL_EX_SELECT: + return translate_select(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 0b3976259..004a8e8b5 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -518,9 +518,20 @@ void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const of << ";"; } +vhdl_var_ref::~vhdl_var_ref() +{ + if (slice_) + delete slice_; +} + void vhdl_var_ref::emit(std::ofstream &of, int level) const { of << name_; + if (slice_) { + of << "("; + slice_->emit(of, level); + of << ")"; + } } void vhdl_const_string::emit(std::ofstream &of, int level) const diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 625d2a13d..12c8a1336 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -40,17 +40,20 @@ private: /* - * A normal scalar variable reference. + * A scalar or array variable reference. */ class vhdl_var_ref : public vhdl_expr { public: - vhdl_var_ref(const char *name, vhdl_type *type) - : vhdl_expr(type), name_(name) {} - + vhdl_var_ref(const char *name, vhdl_type *type, + vhdl_expr *slice = NULL) + : vhdl_expr(type), name_(name), slice_(slice) {} + ~vhdl_var_ref(); + void emit(std::ofstream &of, int level) const; const std::string &get_name() const { return name_; } private: std::string name_; + vhdl_expr *slice_; }; From 5cfe7ea0aa890e60c09ed10481e74ee138a2bf40 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 16:28:07 +0100 Subject: [PATCH 113/377] Tidy up output --- tgt-vhdl/stmt.cc | 3 ++- tgt-vhdl/vhdl_syntax.cc | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 47ab005f1..e7619b205 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -405,7 +405,8 @@ static int draw_case(vhdl_process *proc, stmt_container *container, return 1; vhdl_case_branch *branch = new vhdl_case_branch(when); - + vhdlcase->add_branch(branch); + draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 004a8e8b5..314ee5ee0 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -781,7 +781,6 @@ void vhdl_case_branch::emit(std::ofstream &of, int level) const of << "when "; when_->emit(of, level); of << " =>"; - newline(of, indent(level)); stmts_.emit(of, indent(level)); } @@ -795,7 +794,12 @@ void vhdl_case_stmt::emit(std::ofstream &of, int level) const of << "case "; test_->emit(of, level); of << " is"; - emit_children(of, branches_, level); + newline(of, indent(level)); + + case_branch_list_t::const_iterator it; + for (it = branches_.begin(); it != branches_.end(); ++it) + (*it)->emit(of, level); + of << "end case;"; } From c926454a41243db4a02ad2d225239b264f7cb6fa Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 16:33:05 +0100 Subject: [PATCH 114/377] Statements might be emitted in wrong order --- tgt-vhdl/process.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 2a238d7b5..da1a821c3 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -162,6 +162,9 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); if (rc != 0) return rc; + + // Output any remaning blocking assignments + draw_blocking_assigns(vhdl_proc); // Initial processes are translated to VHDL processes with // no sensitivity list and and indefinite wait statement at @@ -184,9 +187,6 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ss << ivl_scope_tname(scope); vhdl_proc->set_comment(ss.str()); - // Output any remaning blocking assignments - draw_blocking_assigns(vhdl_proc); - return 0; } From 75f7c9ae0cf290418b183e09cb532c3eacf44f52 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 21 Jun 2008 16:40:18 +0100 Subject: [PATCH 115/377] Only move constant assignments into initialisation --- tgt-vhdl/stmt.cc | 10 ++++++---- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 13 ++++++++----- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e7619b205..62e5f2206 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -138,7 +138,8 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, // then use the uninitialized signal value. // The second test ensures that we only try to initialise // internal signals not ports - if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE) { + if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE + && rhs->constant()) { decl->set_initial(rhs); } else { @@ -181,9 +182,10 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, return 1; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); - // As with non-blocking assignment, push assignments into the - // initialisation if we can - if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE) { + // As with non-blocking assignment, push constant assignments + // into the initialisation if we can + if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE + && rhs->constant()) { decl->set_initial(rhs); } else { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 314ee5ee0..bc1e6044f 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -585,7 +585,7 @@ void vhdl_assign_stmt::emit(std::ofstream &of, int level) const } vhdl_const_bits::vhdl_const_bits(const char *value, int width) - : vhdl_expr(vhdl_type::nsigned(width)) + : vhdl_expr(vhdl_type::nsigned(width), true) { // Can't rely on value being NULL-terminated while (width--) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 12c8a1336..66a892639 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -29,13 +29,16 @@ class vhdl_arch; class vhdl_expr : public vhdl_element { public: - vhdl_expr(vhdl_type* type) : type_(type) {} + vhdl_expr(vhdl_type* type, bool isconst=false) + : type_(type), isconst_(isconst) {} virtual ~vhdl_expr(); const vhdl_type *get_type() const { return type_; } + bool constant() const { return isconst_; } virtual vhdl_expr *cast(const vhdl_type *to); private: vhdl_type *type_; + bool isconst_; }; @@ -114,7 +117,7 @@ private: class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) - : vhdl_expr(vhdl_type::string()), value_(value) {} + : vhdl_expr(vhdl_type::string(), true), value_(value) {} void emit(std::ofstream &of, int level) const; private: @@ -134,7 +137,7 @@ private: class vhdl_const_bit : public vhdl_expr { public: vhdl_const_bit(char bit) - : vhdl_expr(vhdl_type::std_logic()), bit_(bit) {} + : vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {} void emit(std::ofstream &of, int level) const; private: char bit_; @@ -147,7 +150,7 @@ enum time_unit_t { class vhdl_const_time : public vhdl_expr { public: vhdl_const_time(int64_t value, time_unit_t units) - : vhdl_expr(vhdl_type::time()), value_(value), units_(units) {} + : vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {} void emit(std::ofstream &of, int level) const; private: int64_t value_; @@ -157,7 +160,7 @@ private: class vhdl_const_int : public vhdl_expr { public: vhdl_const_int(int64_t value) - : vhdl_expr(vhdl_type::integer()), value_(value) {} + : vhdl_expr(vhdl_type::integer(), true), value_(value) {} void emit(std::ofstream &of, int level) const; private: int64_t value_; From d5cdb91d558f14632da7248c7413d7f7eace4075 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 11:36:12 +0100 Subject: [PATCH 116/377] Handle complex expressions in case statement --- tgt-vhdl/stmt.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 62e5f2206..3ead9a100 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -396,6 +396,21 @@ static int draw_case(vhdl_process *proc, stmt_container *container, vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) return 1; + + // VHDL case expressions are required to be quite simple: variable + // references or slices. So we may need to create a temporary + // variable to hold the result of the expression evaluation + if (typeid(test) != typeid(vhdl_var_ref)) { + // TODO: Check if this is already declared + const char *tmp_name = "Verilog_Case_Ex"; + vhdl_type *test_type = new vhdl_type(*test->get_type()); + proc->add_decl(new vhdl_var_decl(tmp_name, test_type)); + + vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL); + container->add_stmt(new vhdl_assign_stmt(tmp_ref, test)); + + test = new vhdl_var_ref(tmp_name, new vhdl_type(*test_type)); + } vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test); container->add_stmt(vhdlcase); From c9ace14c4018f7351250c3d22d3e806492af6975 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 12:14:12 +0100 Subject: [PATCH 117/377] Shift operators working correctly --- tgt-vhdl/expr.cc | 15 +++++++++++++-- tgt-vhdl/vhdl_syntax.cc | 25 ++++++++++++++++++++++--- tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index a7f8e6982..bba0d484d 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -127,6 +127,17 @@ static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean()); } +static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs, + vhdl_binop_t op) +{ + // 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, op, r_cast, rtype); +} + static vhdl_expr *translate_binary(ivl_expr_t e) { vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e)); @@ -176,9 +187,9 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case '>': return translate_relation(lhs, rhs, VHDL_BINOP_GT); case 'l': - return translate_numeric(lhs, rhs, VHDL_BINOP_SL); + return translate_shift(lhs, rhs, VHDL_BINOP_SL); case 'r': - return translate_numeric(lhs, rhs, VHDL_BINOP_SR); + return translate_shift(lhs, rhs, VHDL_BINOP_SR); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index bc1e6044f..b07fb2dca 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -585,7 +585,7 @@ void vhdl_assign_stmt::emit(std::ofstream &of, int level) const } vhdl_const_bits::vhdl_const_bits(const char *value, int width) - : vhdl_expr(vhdl_type::nsigned(width), true) + : vhdl_expr(vhdl_type::nsigned(width), true), qualified_(false) { // Can't rely on value being NULL-terminated while (width--) @@ -604,20 +604,39 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) 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) { + // Might need to drop some bits (but not extend?) + assert(to->get_width() <= get_type()->get_width()); + + value_.resize(to->get_width()); + 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 return vhdl_expr::cast(to); } void vhdl_const_bits::emit(std::ofstream &of, int level) const { - of << "signed'(\""; + of << (qualified_ ? "signed'(\"" : "\""); // The bits appear to be in reverse order std::string::const_reverse_iterator it; for (it = value_.rbegin(); it != value_.rend(); ++it) of << vl_to_vhdl_bit(*it); - of << "\")"; + of << (qualified_ ? "\")" : "\""); } void vhdl_const_bit::emit(std::ofstream &of, int level) const diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 66a892639..9d4bde8d3 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -132,6 +132,7 @@ public: vhdl_expr *cast(const vhdl_type *to); private: std::string value_; + bool qualified_; }; class vhdl_const_bit : public vhdl_expr { From 991193957630dbffef9650c855d6560198c33063 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 12:21:10 +0100 Subject: [PATCH 118/377] Simplify casting code --- tgt-vhdl/expr.cc | 17 ++--------------- tgt-vhdl/vhdl_syntax.cc | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index bba0d484d..fbb4c7c65 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -90,27 +90,14 @@ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, { int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); - - vhdl_type ltype(VHDL_TYPE_UNSIGNED, lhs->get_type()->get_msb(), - lhs->get_type()->get_lsb()); - vhdl_type rtype(VHDL_TYPE_UNSIGNED, rhs->get_type()->get_msb(), - rhs->get_type()->get_lsb()); // May need to resize the left or right hand side if (lwidth < rwidth) { - vhdl_fcall *resize = - new vhdl_fcall("resize", vhdl_type::nsigned(rwidth)); - resize->add_expr(lhs); - resize->add_expr(new vhdl_const_int(rwidth)); - lhs = resize; + lhs = lhs->cast(rhs->get_type()); lwidth = rwidth; } else if (rwidth < lwidth) { - vhdl_fcall *resize = - new vhdl_fcall("resize", vhdl_type::nsigned(lwidth)); - resize->add_expr(rhs); - resize->add_expr(new vhdl_const_int(lwidth)); - rhs = resize; + rhs = rhs->cast(lhs->get_type()); rwidth = lwidth; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index b07fb2dca..a1934b794 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -462,8 +462,18 @@ vhdl_expr::~vhdl_expr() */ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) { - if (to->get_name() == type_->get_name()) - return this; + if (to->get_name() == type_->get_name()) { + if (to->get_width() == type_->get_width()) + return this; // Identical + else { + vhdl_type *rtype = vhdl_type::nsigned(to->get_width()); + vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); + resize->add_expr(this); + resize->add_expr(new vhdl_const_int(to->get_width())); + + return resize; + } + } else if (to->get_name() == VHDL_TYPE_BOOLEAN) { // '1' is true all else are false vhdl_const_bit *one = new vhdl_const_bit('1'); From d06f5c7c54283de70aa25a83ebdf94726737aa46 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 12:27:30 +0100 Subject: [PATCH 119/377] Emit loop statements with the correct indent --- tgt-vhdl/vhdl_syntax.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a1934b794..555f40aa1 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -842,6 +842,6 @@ void vhdl_while_stmt::emit(std::ofstream &of, int level) const of << "while "; test_->emit(of, level); of << " loop"; - stmts_.emit(of, indent(level)); + stmts_.emit(of, level); of << "end loop;"; } From 469036990af5f3780c93141dc0c633ef35b3dd01 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 12:30:48 +0100 Subject: [PATCH 120/377] Output blocking assignments in the right place --- tgt-vhdl/process.cc | 8 +++----- tgt-vhdl/stmt.cc | 2 +- tgt-vhdl/vhdl_target.h | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index da1a821c3..511dec64c 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -104,7 +104,7 @@ void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) * 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_process *proc) +void draw_blocking_assigns(vhdl_process *proc, stmt_container *container) { var_temp_set_t::const_iterator it; for (it = g_assign_vars.begin(); it != g_assign_vars.end(); ++it) { @@ -117,9 +117,7 @@ void draw_blocking_assigns(vhdl_process *proc) vhdl_var_ref *lhs = new vhdl_var_ref(stripped.c_str(), NULL); vhdl_expr *rhs = new vhdl_var_ref((*it).first.c_str(), type); - // TODO: I'm not sure this will work properly if, e.g., the delay - // is inside a `if' statement - proc->get_container()->add_stmt(new vhdl_nbassign_stmt(lhs, rhs)); + container->add_stmt(new vhdl_nbassign_stmt(lhs, rhs)); // Undo the renaming (since the temporary is no longer needed) rename_signal((*it).second, stripped); @@ -164,7 +162,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) return rc; // Output any remaning blocking assignments - draw_blocking_assigns(vhdl_proc); + draw_blocking_assigns(vhdl_proc, vhdl_proc->get_container()); // Initial processes are translated to VHDL processes with // no sensitivity list and and indefinite wait statement at diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 3ead9a100..52415715f 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -252,7 +252,7 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, else { // All blocking assignments need to be made visible // at this point - draw_blocking_assigns(proc); + draw_blocking_assigns(proc, container); vhdl_wait_stmt *wait = new vhdl_wait_stmt(VHDL_WAIT_FOR, time); diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index ee51d2a78..cd12460ed 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -33,7 +33,7 @@ const std::string &get_renamed_signal(ivl_signal_t sig); void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig); std::string strip_var(const std::string &str); -void draw_blocking_assigns(vhdl_process *proc); +void draw_blocking_assigns(vhdl_process *proc, stmt_container *container); int draw_stask_display(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true); From e5ef0d97bde38f237c82fc9c39b465fe2f124c64 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 13:04:28 +0100 Subject: [PATCH 121/377] Fix signed/unsigned resizing --- tgt-vhdl/expr.cc | 27 ++++++++++++--------------- tgt-vhdl/scope.cc | 2 +- tgt-vhdl/vhdl_syntax.cc | 20 ++++++++++++-------- tgt-vhdl/vhdl_syntax.hh | 1 + 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index fbb4c7c65..f91df6485 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -87,21 +87,9 @@ static vhdl_expr *translate_unary(ivl_expr_t e) */ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) -{ - int lwidth = lhs->get_type()->get_width(); - int rwidth = rhs->get_type()->get_width(); - - // May need to resize the left or right hand side - if (lwidth < rwidth) { - lhs = lhs->cast(rhs->get_type()); - lwidth = rwidth; - } - else if (rwidth < lwidth) { - rhs = rhs->cast(lhs->get_type()); - rwidth = lwidth; - } - - return new vhdl_binop_expr(lhs, op, rhs, vhdl_type::nsigned(lwidth)); +{ + vhdl_type *rtype = new vhdl_type(*lhs->get_type()); + return new vhdl_binop_expr(lhs, op, rhs, rtype); } static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, @@ -134,6 +122,15 @@ static vhdl_expr *translate_binary(ivl_expr_t e) vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e)); if (NULL == rhs) return NULL; + + int lwidth = lhs->get_type()->get_width(); + int rwidth = rhs->get_type()->get_width(); + + // May need to resize the left or right hand side + if (lwidth < rwidth) + rhs = rhs->cast(lhs->get_type()); + else if (rwidth < lwidth) + lhs = lhs->cast(rhs->get_type()); // For === and !== we need to compare std_logic_vectors // rather than signeds diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 3d0ecfa03..d06ea0a20 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -130,7 +130,7 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - + int width = ivl_signal_width(sig); vhdl_type *sig_type; if (width == 1) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 555f40aa1..823262432 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -465,14 +465,8 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) if (to->get_name() == type_->get_name()) { if (to->get_width() == type_->get_width()) return this; // Identical - else { - vhdl_type *rtype = vhdl_type::nsigned(to->get_width()); - vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); - resize->add_expr(this); - resize->add_expr(new vhdl_const_int(to->get_width())); - - return resize; - } + else + return resize(to->get_width()); } else if (to->get_name() == VHDL_TYPE_BOOLEAN) { // '1' is true all else are false @@ -495,6 +489,16 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) } } +vhdl_expr *vhdl_expr::resize(int newwidth) +{ + vhdl_type *rtype = vhdl_type::nsigned(newwidth); + 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); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9d4bde8d3..54a54fb6e 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -36,6 +36,7 @@ public: const vhdl_type *get_type() const { return type_; } bool constant() const { return isconst_; } virtual vhdl_expr *cast(const vhdl_type *to); + virtual vhdl_expr *resize(int newwidth); private: vhdl_type *type_; bool isconst_; From f81129aa6835541b560b9e2e4e942e1c69bf62fe Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 13:36:28 +0100 Subject: [PATCH 122/377] Fix some bugs with blocking assignment --- tgt-vhdl/process.cc | 7 ++++++- tgt-vhdl/stmt.cc | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 511dec64c..4d6ac6b8f 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -123,7 +123,11 @@ void draw_blocking_assigns(vhdl_process *proc, stmt_container *container) rename_signal((*it).second, stripped); } - g_assign_vars.clear(); + // 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(); } /* @@ -163,6 +167,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) // 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 diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 52415715f..6a0f562ba 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -172,7 +172,7 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { - const std::string &signame = get_renamed_signal(sig); + const std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_decl(signame); assert(decl); @@ -187,6 +187,19 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE && rhs->constant()) { decl->set_initial(rhs); + + // 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); + + vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, sig_ref); + container->add_stmt(assign); } else { blocking_assign_to(proc, sig); From 44958409f577ef44a5dd890a2af1be6cc86833a5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 13:45:24 +0100 Subject: [PATCH 123/377] A slightly smarter $display --- tgt-vhdl/display.cc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 8f9b06e4c..ad59d6c45 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -92,6 +92,14 @@ static char parse_octal(const char *p) + (*(p+2) - '0') * 1; } +static void flush_string(std::ostringstream &ss, stmt_container *container) +{ + display_write(container, new vhdl_const_string(ss.str().c_str())); + + // Clear the stream + ss.str(""); +} + /* * Generate VHDL for the $display system task. * This is implemented using the functions in std.textio. Each @@ -132,17 +140,26 @@ int draw_stask_display(vhdl_process *proc, stmt_container *container, // Octal escape char ch = parse_octal(p+1); if (ch == '\n') { - display_write(container, - new vhdl_const_string(ss.str().c_str())); + flush_string(ss, container); display_line(container); - - // Clear the stream - ss.str(""); } else ss << ch; p += 3; } + else if (*p == '%') { + flush_string(ss, container); + + p++; // Ignore the format (!) + ivl_expr_t net = ivl_stmt_parm(stmt, i++); + assert(net); + + vhdl_expr *base = translate_expr(net); + if (NULL == base) + return 1; + + display_write(container, base); + } else ss << *p; } From 449cd0a76edb41fd308a71f309eeb1850e5700ab Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 14:28:27 +0100 Subject: [PATCH 124/377] Correctly generate signed/unsigned types --- tgt-vhdl/expr.cc | 28 ++++++++++++++++++---------- tgt-vhdl/scope.cc | 4 +++- tgt-vhdl/vhdl_syntax.cc | 27 ++++++++++++++++++++++----- tgt-vhdl/vhdl_syntax.hh | 4 ++-- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index f91df6485..36dbbd2a3 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -49,6 +49,8 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) const vhdl_decl *decl = ent->get_arch()->get_decl(strip_var(renamed)); assert(decl); + std::cout << "ref: " << renamed << " width=" << decl->get_type()->get_width() << std::endl; + vhdl_type *type = new vhdl_type(*decl->get_type()); return new vhdl_var_ref(renamed, type); @@ -59,7 +61,8 @@ 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)); + 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) @@ -127,14 +130,24 @@ static vhdl_expr *translate_binary(ivl_expr_t e) int rwidth = rhs->get_type()->get_width(); // May need to resize the left or right hand side - if (lwidth < rwidth) + int opwidth; + if (lwidth < rwidth) { rhs = rhs->cast(lhs->get_type()); - else if (rwidth < lwidth) + opwidth = lwidth; + } + else if (rwidth < lwidth) { lhs = lhs->cast(rhs->get_type()); + opwidth = rwidth; + } + else + opwidth = lwidth; + + std::cout << "lwidth=" << lwidth << " rwidth=" << rwidth << std::endl; // For === and !== we need to compare std_logic_vectors // rather than signeds - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); + int msb = ivl_expr_width(e) - 1; + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, opwidth-1, 0); bool vectorop = (lhs->get_type()->get_name() == VHDL_TYPE_SIGNED || lhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED) && @@ -190,12 +203,7 @@ vhdl_expr *translate_select(ivl_expr_t e) return NULL; // Hack: resize it to the correct size - vhdl_type *rtype = vhdl_type::nsigned(ivl_expr_width(e)); - vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); - resize->add_expr(from); - resize->add_expr(new vhdl_const_int(ivl_expr_width(e))); - - return resize; + return from->resize(ivl_expr_width(e)); } /* diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d06ea0a20..743202fb7 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -135,8 +135,10 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) vhdl_type *sig_type; if (width == 1) sig_type = vhdl_type::std_logic(); - else + else if (ivl_signal_signed(sig)) sig_type = vhdl_type::nsigned(width); + else + sig_type = vhdl_type::nunsigned(width); remember_signal(sig, arch->get_parent()); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 823262432..9ef2957ca 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -462,6 +462,11 @@ vhdl_expr::~vhdl_expr() */ 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 @@ -481,10 +486,14 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return conv; } else { + vhdl_expr *tocast = this; + if (to->get_width() != type_->get_width()) + tocast = resize(to->get_width()); + vhdl_fcall *conv = new vhdl_fcall(to->get_string().c_str(), new vhdl_type(*to)); - conv->add_expr(this); - + conv->add_expr(tocast); + return conv; } } @@ -598,9 +607,14 @@ void vhdl_assign_stmt::emit(std::ofstream &of, int level) const of << ";"; } -vhdl_const_bits::vhdl_const_bits(const char *value, int width) - : vhdl_expr(vhdl_type::nsigned(width), true), qualified_(false) +vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned) + : vhdl_expr(issigned ? vhdl_type::nsigned(width) + : vhdl_type::nunsigned(width), true), + qualified_(false), + signed_(issigned) { + std::cout << (issigned ? "signed" : "unsigned") << " bits" << std::endl; + // Can't rely on value being NULL-terminated while (width--) value_.push_back(*value++); @@ -643,7 +657,10 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) void vhdl_const_bits::emit(std::ofstream &of, int level) const { - of << (qualified_ ? "signed'(\"" : "\""); + if (qualified_) + of << (signed_ ? "signed" : "unsigned") << "'(\""; + else + of << "\""; // The bits appear to be in reverse order std::string::const_reverse_iterator it; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 54a54fb6e..79a8d7177 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -127,13 +127,13 @@ private: class vhdl_const_bits : public vhdl_expr { public: - vhdl_const_bits(const char *value, int width); + vhdl_const_bits(const char *value, int width, bool issigned); void emit(std::ofstream &of, int level) const; const std::string &get_value() const { return value_; } vhdl_expr *cast(const vhdl_type *to); private: std::string value_; - bool qualified_; + bool qualified_, signed_; }; class vhdl_const_bit : public vhdl_expr { From 632a265e1443aeb848ad06931ff3ceb480e109c0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 15:00:55 +0100 Subject: [PATCH 125/377] Fix casting/resizing order bug --- tgt-vhdl/vhdl_syntax.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 9ef2957ca..3f3d6261f 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -486,15 +486,17 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return conv; } else { - vhdl_expr *tocast = this; - if (to->get_width() != type_->get_width()) - tocast = resize(to->get_width()); - + // 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(tocast); + conv->add_expr(this); - return conv; + if (to->get_width() != type_->get_width()) + return conv->resize(to->get_width()); + else + return conv; } } @@ -612,12 +614,13 @@ vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned) : vhdl_type::nunsigned(width), true), qualified_(false), signed_(issigned) -{ - std::cout << (issigned ? "signed" : "unsigned") << " bits" << std::endl; - +{ // Can't rely on value being NULL-terminated while (width--) value_.push_back(*value++); + + std::cout << (issigned ? "signed" : "unsigned") << " bits: " + << value_ << std::endl; } vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) From 88dc9b6b6327665fdcbf43c573f9cb4ea56f6eab Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 15:02:26 +0100 Subject: [PATCH 126/377] Remove debugging information from the output --- tgt-vhdl/expr.cc | 5 ----- tgt-vhdl/vhdl_syntax.cc | 11 ++++------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 36dbbd2a3..34a635201 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -49,8 +49,6 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) const vhdl_decl *decl = ent->get_arch()->get_decl(strip_var(renamed)); assert(decl); - std::cout << "ref: " << renamed << " width=" << decl->get_type()->get_width() << std::endl; - vhdl_type *type = new vhdl_type(*decl->get_type()); return new vhdl_var_ref(renamed, type); @@ -142,11 +140,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) else opwidth = lwidth; - std::cout << "lwidth=" << lwidth << " rwidth=" << rwidth << std::endl; - // For === and !== we need to compare std_logic_vectors // rather than signeds - int msb = ivl_expr_width(e) - 1; vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, opwidth-1, 0); bool vectorop = (lhs->get_type()->get_name() == VHDL_TYPE_SIGNED diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3f3d6261f..466ab7175 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -462,10 +462,10 @@ vhdl_expr::~vhdl_expr() */ 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; + //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()) @@ -618,9 +618,6 @@ vhdl_const_bits::vhdl_const_bits(const char *value, int width, bool issigned) // Can't rely on value being NULL-terminated while (width--) value_.push_back(*value++); - - std::cout << (issigned ? "signed" : "unsigned") << " bits: " - << value_ << std::endl; } vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) From f261bf7e973f863e080b82010b529115aa1b8c9e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 23 Jun 2008 15:13:10 +0100 Subject: [PATCH 127/377] Fix bug where variables could be declared twice --- tgt-vhdl/stmt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 6a0f562ba..9407a84ef 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -185,7 +185,7 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, // As with non-blocking assignment, push constant assignments // into the initialisation if we can if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE - && rhs->constant()) { + && rhs->constant() && !proc->have_declared_var(signame)) { decl->set_initial(rhs); // This signal may be used e.g. in a loop test so we need From 4188fbecee46f794be89c54f33583752a6d68d3d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 10:55:45 +0100 Subject: [PATCH 128/377] Add XOR operator and catch default case branch --- tgt-vhdl/expr.cc | 2 ++ tgt-vhdl/stmt.cc | 15 +++++++++++---- tgt-vhdl/vhdl_syntax.cc | 4 ++++ tgt-vhdl/vhdl_syntax.hh | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 34a635201..5c2fa6233 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -182,6 +182,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_shift(lhs, rhs, VHDL_BINOP_SL); case 'r': return translate_shift(lhs, rhs, VHDL_BINOP_SR); + case '^': + return translate_numeric(lhs, rhs, VHDL_BINOP_XOR); default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 9407a84ef..ff0375ac0 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -24,6 +24,7 @@ #include #include #include +#include /* * VHDL has no real equivalent of Verilog's $finish task. The @@ -430,10 +431,16 @@ static int draw_case(vhdl_process *proc, stmt_container *container, int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { - vhdl_expr *when = translate_expr(ivl_stmt_case_expr(stmt, i)); - if (NULL == when) - return 1; - + vhdl_expr *when; + ivl_expr_t net = ivl_stmt_case_expr(stmt, i); + if (net) { + when = translate_expr(net); + if (NULL == when) + return 1; + } + else + when = new vhdl_var_ref("others", NULL); + vhdl_case_branch *branch = new vhdl_case_branch(when); vhdlcase->add_branch(branch); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 466ab7175..40be6085b 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -23,6 +23,7 @@ #include #include +#include vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) @@ -813,6 +814,9 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const case VHDL_BINOP_SR: of << " srl "; break; + case VHDL_BINOP_XOR: + of << " xor "; + break; } (*it)->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 79a8d7177..c547c12b7 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -73,6 +73,7 @@ enum vhdl_binop_t { VHDL_BINOP_GT, VHDL_BINOP_SL, VHDL_BINOP_SR, + VHDL_BINOP_XOR, }; /* From cb08f02de11113c3ae33e50f23268d24611c2c20 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 10:58:21 +0100 Subject: [PATCH 129/377] Resize signed/unsigned bit vectors correctly --- tgt-vhdl/vhdl_syntax.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 40be6085b..58f928a1c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -639,10 +639,9 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) } else if (to->get_name() == VHDL_TYPE_SIGNED || to->get_name() == VHDL_TYPE_UNSIGNED) { - // Might need to drop some bits (but not extend?) - assert(to->get_width() <= get_type()->get_width()); - value_.resize(to->get_width()); + // Extend with sign bit + value_.resize(to->get_width(), value_[0]); return this; } else if (to->get_name() == VHDL_TYPE_INTEGER) { From 3866c4526e73fce8ae5f7d80643570379a854b5f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 14:58:58 +0100 Subject: [PATCH 130/377] Simplify code to emit operators --- tgt-vhdl/vhdl_syntax.cc | 44 ++++++----------------------------------- tgt-vhdl/vhdl_syntax.hh | 2 +- 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 58f928a1c..9740e5f08 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -779,44 +779,12 @@ void vhdl_binop_expr::emit(std::ofstream &of, int level) const (*it)->emit(of, level); while (++it != operands_.end()) { - switch (op_) { - case VHDL_BINOP_AND: - of << " and "; - break; - case VHDL_BINOP_OR: - of << " or "; - break; - case VHDL_BINOP_EQ: - of << " = "; - break; - case VHDL_BINOP_NEQ: - of << " /= "; - break; - case VHDL_BINOP_ADD: - of << " + "; - break; - case VHDL_BINOP_SUB: - of << " - "; - break; - case VHDL_BINOP_MULT: - of << " * "; - break; - case VHDL_BINOP_LT: - of << " < "; - break; - case VHDL_BINOP_GT: - of << " > "; - break; - case VHDL_BINOP_SL: - of << " sll "; - break; - case VHDL_BINOP_SR: - of << " srl "; - break; - case VHDL_BINOP_XOR: - of << " xor "; - break; - } + const char* ops[] = { + "and", "or", "=", "/=", "+", "-", "*", "<", + ">", "sll", "srl", "xor" + }; + + of << " " << ops[op_] << " "; (*it)->emit(of, level); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c547c12b7..41e3d61b9 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -62,7 +62,7 @@ private: enum vhdl_binop_t { - VHDL_BINOP_AND, + VHDL_BINOP_AND = 0, VHDL_BINOP_OR, VHDL_BINOP_EQ, VHDL_BINOP_NEQ, From ba36e47575942790a5b45ba8e9817ad19efb31ec Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 18:12:00 +0100 Subject: [PATCH 131/377] Add new vhdl_scope class and refactor --- tgt-vhdl/vhdl_syntax.cc | 50 +++++++++++++++++++++++++++++++---------- tgt-vhdl/vhdl_syntax.hh | 32 +++++++++++++++++++------- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 9740e5f08..485dfe425 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -25,6 +25,38 @@ #include #include +vhdl_scope::vhdl_scope() + : parent_(NULL) +{ + +} + +vhdl_scope::~vhdl_scope() +{ + delete_children(decls_); +} + +void vhdl_scope::add_decl(vhdl_decl *decl) +{ + decls_.push_back(decl); +} + +vhdl_decl *vhdl_scope::get_decl(const std::string &name) const +{ + decl_list_t::const_iterator it; + for (it = decls_.begin(); it != decls_.end(); ++it) { + if ((*it)->get_name() == name) + return *it; + } + + return parent_ ? parent_->get_decl(name) : NULL; +} + +bool vhdl_scope::have_declared(const std::string &name) const +{ + return get_decl(name) != NULL; +} + vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) : name_(name), arch_(arch), derived_from_(derived_from) @@ -35,7 +67,6 @@ vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_entity::~vhdl_entity() { delete arch_; - delete_children(ports_); } /* @@ -58,17 +89,12 @@ void vhdl_entity::requires_package(const char *spec) */ vhdl_decl *vhdl_entity::get_decl(const std::string &name) const { - decl_list_t::const_iterator it; - for (it = ports_.begin(); it != ports_.end(); ++it) { - if ((*it)->get_name() == name) - return *it; - } - return NULL; + return ports_.get_decl(name); } void vhdl_entity::add_port(vhdl_port_decl *decl) { - ports_.push_back(decl); + ports_.add_decl(decl); } void vhdl_entity::emit(std::ofstream &of, int level) const @@ -88,10 +114,10 @@ void vhdl_entity::emit(std::ofstream &of, int level) const emit_comment(of, level); of << "entity " << name_ << " is"; - if (ports_.size() > 0) { + if (!ports_.empty()) { newline(of, indent(level)); of << "port ("; - emit_children(of, ports_, indent(level), ";"); + emit_children(of, ports_.get_decls(), indent(level), ";"); of << ");"; } @@ -338,14 +364,14 @@ vhdl_component_decl::vhdl_component_decl(const char *name) /* * Create a component declaration for the given entity. */ -vhdl_component_decl *vhdl_component_decl::component_decl_for(const vhdl_entity *ent) +vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent) { assert(ent != NULL); vhdl_component_decl *decl = new vhdl_component_decl (ent->get_name().c_str()); - decl->ports_ = ent->get_ports(); + decl->ports_ = ent->get_scope()->get_decls(); return decl; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 41e3d61b9..9ccca2781 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -24,6 +24,7 @@ #include "vhdl_element.hh" #include "vhdl_type.hh" +class vhdl_scope; class vhdl_entity; class vhdl_arch; @@ -438,7 +439,7 @@ typedef std::list decl_list_t; */ class vhdl_component_decl : public vhdl_decl { public: - static vhdl_component_decl *component_decl_for(const vhdl_entity *ent); + static vhdl_component_decl *component_decl_for(vhdl_entity *ent); void emit(std::ofstream &of, int level) const; private: @@ -521,11 +522,25 @@ private: /* - * Container for sequential statements. - * Verilog `initial' processes are used for variable - * initialisation whereas VHDL initialises variables in - * their declaration. + * Contains a list of declarations in a hierarchy. */ +class vhdl_scope { +public: + vhdl_scope(); + ~vhdl_scope(); + + void add_decl(vhdl_decl *decl); + vhdl_decl *get_decl(const std::string &name) const; + bool have_declared(const std::string &name) const; + + bool empty() const { return decls_.empty(); } + const decl_list_t &get_decls() const { return decls_; } +private: + decl_list_t decls_; + vhdl_scope *parent_; +}; + + class vhdl_process : public vhdl_conc_stmt { public: vhdl_process(const char *name = ""); @@ -587,16 +602,17 @@ public: void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } vhdl_decl *get_decl(const std::string &name) const; - const decl_list_t &get_ports() const { return ports_; } const std::string &get_name() const { return name_; } void requires_package(const char *spec); - const std::string &get_derived_from() const { return derived_from_; } + const std::string &get_derived_from() const { return derived_from_; } + + vhdl_scope *get_scope() { return &ports_; } private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture std::string derived_from_; string_list_t uses_; - decl_list_t ports_; + vhdl_scope ports_; }; typedef std::list entity_list_t; From 63b1887ff27fd5bfd1c734b9590041d7e725f048 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 18:52:25 +0100 Subject: [PATCH 132/377] Refactor code to use the new vhdl_scope class --- tgt-vhdl/display.cc | 7 +-- tgt-vhdl/lpm.cc | 6 +- tgt-vhdl/process.cc | 8 +-- tgt-vhdl/scope.cc | 37 ++++++------ tgt-vhdl/stmt.cc | 14 ++--- tgt-vhdl/vhdl_syntax.cc | 126 +++++++--------------------------------- tgt-vhdl/vhdl_syntax.hh | 26 +++------ tgt-vhdl/vhdl_target.h | 3 +- 8 files changed, 64 insertions(+), 163 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index ad59d6c45..1b40c8c82 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -115,14 +115,11 @@ static void flush_string(std::ostringstream &ss, stmt_container *container) int draw_stask_display(vhdl_process *proc, stmt_container *container, ivl_statement_t stmt, bool newline) { - // Add the package requirement to the containing entity - proc->get_parent()->get_parent()->requires_package("std.textio"); - - if (!proc->have_declared_var(DISPLAY_LINE)) { + if (!proc->get_scope()->have_declared(DISPLAY_LINE)) { vhdl_var_decl *line_var = new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line()); line_var->set_comment("For generating $display output"); - proc->add_decl(line_var); + proc->get_scope()->add_decl(line_var); } // Write the data into the line diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 8778dff8a..3d67ddf93 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -25,15 +25,15 @@ 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)); + vhdl_expr *lhs = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); if (NULL == lhs) return 1; - vhdl_expr *rhs = nexus_to_var_ref(arch, ivl_lpm_data(lpm, 1)); + vhdl_expr *rhs = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 1)); if (NULL == rhs) return 1; - vhdl_var_ref *out = nexus_to_var_ref(arch, ivl_lpm_q(lpm, 0)); + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); if (NULL == out) return 1; diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 4d6ac6b8f..cc6ca855a 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -86,12 +86,12 @@ void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) // This is the first time a non-blocking assignment // has been made to this signal: create a variable // to shadow it. - if (!proc->have_declared_var(tmpname)) { - vhdl_decl *decl = proc->get_parent()->get_decl(var); + 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->add_decl(new vhdl_var_decl(tmpname.c_str(), type)); + proc->get_scope()->add_decl(new vhdl_var_decl(tmpname.c_str(), type)); } rename_signal(sig, tmpname); @@ -110,7 +110,7 @@ void draw_blocking_assigns(vhdl_process *proc, stmt_container *container) for (it = g_assign_vars.begin(); it != g_assign_vars.end(); ++it) { std::string stripped(strip_var((*it).first)); - vhdl_decl *decl = proc->get_decl(stripped); + vhdl_decl *decl = proc->get_scope()->get_decl(stripped); assert(decl); vhdl_type *type = new vhdl_type(*decl->get_type()); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 743202fb7..23dd95490 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,11 +25,12 @@ #include #include + /* - * Given a nexus and an architecture, find the first signal + * Given a nexus and an architecture scope, find the first signal * that is connected to the nexus, if there is one. */ -vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) +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++) { @@ -39,7 +40,7 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus) if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { const char *signame = get_renamed_signal(sig).c_str(); - vhdl_decl *decl = arch->get_decl(signame); + vhdl_decl *decl = arch_scope->get_decl(signame); assert(decl); vhdl_type *type = new vhdl_type(*(decl->get_type())); @@ -67,7 +68,7 @@ static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, int npins = ivl_logic_pins(log); for (int i = 1; i < npins; i++) { ivl_nexus_t input = ivl_logic_pin(log, i); - gate->add_expr(nexus_to_var_ref(arch, input)); + gate->add_expr(nexus_to_var_ref(arch->get_scope(), input)); } return gate; @@ -82,7 +83,7 @@ static vhdl_expr *input_to_expr(vhdl_arch *arch, vhdl_unaryop_t op, ivl_nexus_t input = ivl_logic_pin(log, 1); assert(input); - vhdl_expr *operand = nexus_to_var_ref(arch, input); + vhdl_expr *operand = nexus_to_var_ref(arch->get_scope(), input); return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } @@ -98,7 +99,7 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) // The output is always pin zero ivl_nexus_t output = ivl_logic_pin(log, 0); - vhdl_var_ref *lhs = nexus_to_var_ref(arch, output); + vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); vhdl_expr *rhs = NULL; switch (ivl_logic_type(log)) { @@ -123,9 +124,9 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) } /* - * Declare all signals for a scope in an architecture. + * Declare all signals and ports for a scope. */ -static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) +static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) { int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { @@ -140,7 +141,7 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) else sig_type = vhdl_type::nunsigned(width); - remember_signal(sig, arch->get_parent()); + remember_signal(sig, ent); // Make sure the signal name conforms to VHDL naming rules std::string name(ivl_signal_basename(sig)); @@ -162,14 +163,14 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: - arch->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); + ent->get_arch()->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); break; case IVL_SIP_INPUT: - arch->get_parent()->add_port + ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); break; case IVL_SIP_OUTPUT: - arch->get_parent()->add_port + ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT)); if (ivl_signal_type(sig) == IVL_SIT_REG) { @@ -183,18 +184,18 @@ static void declare_signals(vhdl_arch *arch, ivl_scope_t scope) rename_signal(sig, newname.c_str()); vhdl_type *reg_type = new vhdl_type(*sig_type); - arch->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); + ent->get_arch()->add_decl(new vhdl_signal_decl(newname.c_str(), reg_type)); // Create a concurrent assignment statement to // connect the register to the output - arch->add_stmt + ent->get_arch()->add_stmt (new vhdl_cassign_stmt (new vhdl_var_ref(name.c_str(), NULL), new vhdl_var_ref(newname.c_str(), NULL))); } break; case IVL_SIP_INOUT: - arch->get_parent()->add_port + ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); break; } @@ -231,10 +232,10 @@ 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); - + // Locate all the signals in this module and add them to // the architecture - declare_signals(arch, scope); + declare_signals(ent, scope); // Similarly, add all the primitive logic gates declare_logic(arch, scope); @@ -344,7 +345,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) assert(parent_arch != NULL); // Create a forward declaration for it - if (!parent_arch->have_declared_component(ent->get_name())) { + if (!parent_arch->have_declared(ent->get_name())) { vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); parent_arch->add_decl(comp_decl); } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index ff0375ac0..90d63c475 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -43,7 +43,7 @@ static int draw_stask_finish(vhdl_process *proc, stmt_container *container, { const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish"); if (strcmp(use_vhpi, "1") == 0) { - proc->get_parent()->get_parent()->requires_package("work.Verilog_Support"); + //get_active_entity()->requires_package("work.Verilog_Support"); container->add_stmt(new vhdl_pcall_stmt("work.Verilog_Support.Finish")); } else { @@ -121,7 +121,7 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, if ((sig = ivl_lval_sig(lval))) { const char *signame = get_renamed_signal(sig).c_str(); - vhdl_decl *decl = proc->get_parent()->get_decl(signame); + vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); @@ -175,7 +175,7 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, if ((sig = ivl_lval_sig(lval))) { const std::string signame(get_renamed_signal(sig)); - vhdl_decl *decl = proc->get_decl(signame); + vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); @@ -186,7 +186,7 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, // As with non-blocking assignment, push constant assignments // into the initialisation if we can if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE - && rhs->constant() && !proc->have_declared_var(signame)) { + && rhs->constant() && !proc->get_scope()->have_declared(signame)) { decl->set_initial(rhs); // This signal may be used e.g. in a loop test so we need @@ -295,7 +295,7 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, 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_parent(), nexus); + 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); @@ -334,7 +334,7 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, // 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_parent()->have_declared(signame)) { + if (proc->get_scope()->get_parent()->have_declared(signame)) { proc->add_sensitivity(signame); non_edges.push_back(signame); break; @@ -418,7 +418,7 @@ static int draw_case(vhdl_process *proc, stmt_container *container, // TODO: Check if this is already declared const char *tmp_name = "Verilog_Case_Ex"; vhdl_type *test_type = new vhdl_type(*test->get_type()); - proc->add_decl(new vhdl_var_decl(tmp_name, test_type)); + proc->get_scope()->add_decl(new vhdl_var_decl(tmp_name, test_type)); vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL); container->add_stmt(new vhdl_assign_stmt(tmp_ref, test)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 485dfe425..770e8db7d 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -57,11 +57,17 @@ bool vhdl_scope::have_declared(const std::string &name) const return get_decl(name) != NULL; } +vhdl_scope *vhdl_scope::get_parent() +{ + assert(parent_); + return parent_; +} + vhdl_entity::vhdl_entity(const char *name, const char *derived_from, vhdl_arch *arch) : name_(name), arch_(arch), derived_from_(derived_from) { - arch->parent_ = this; + arch->get_scope()->set_parent(&ports_); } vhdl_entity::~vhdl_entity() @@ -69,29 +75,6 @@ vhdl_entity::~vhdl_entity() delete arch_; } -/* - * Add a package to the list of `use' statements before - * the entity. - */ -void vhdl_entity::requires_package(const char *spec) -{ - std::string pname(spec); - std::list::iterator it; - for (it = uses_.begin(); it != uses_.end(); ++it) { - if (*it == pname) - return; - } - uses_.push_back(spec); -} - -/* - * Find a port declaration by name - */ -vhdl_decl *vhdl_entity::get_decl(const std::string &name) const -{ - return ports_.get_decl(name); -} - void vhdl_entity::add_port(vhdl_port_decl *decl) { ports_.add_decl(decl); @@ -104,11 +87,7 @@ void vhdl_entity::emit(std::ofstream &of, int level) const of << "library ieee;" << std::endl; of << "use ieee.std_logic_1164.all;" << std::endl; of << "use ieee.numeric_std.all;" << std::endl; - - for (std::list::const_iterator it = uses_.begin(); - it != uses_.end(); - ++it) - of << "use " << *it << ".all;" << std::endl; + of << "use std.textio.all;" << std::endl; of << std::endl; emit_comment(of, level); @@ -128,7 +107,7 @@ void vhdl_entity::emit(std::ofstream &of, int level) const } vhdl_arch::vhdl_arch(const char *entity, const char *name) - : parent_(NULL), name_(name), entity_(entity) + : name_(name), entity_(entity) { } @@ -136,24 +115,22 @@ vhdl_arch::vhdl_arch(const char *entity, const char *name) vhdl_arch::~vhdl_arch() { delete_children(stmts_); - delete_children(decls_); +} + +void vhdl_arch::add_stmt(vhdl_process *proc) +{ + proc->get_scope()->set_parent(&scope_); + stmts_.push_back(proc); } void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) { - stmt->parent_ = this; stmts_.push_back(stmt); } void vhdl_arch::add_decl(vhdl_decl *decl) { - decls_.push_back(decl); -} - -vhdl_entity *vhdl_arch::get_parent() const -{ - assert(parent_); - return parent_; + scope_.add_decl(decl); } void vhdl_arch::emit(std::ofstream &of, int level) const @@ -161,7 +138,7 @@ void vhdl_arch::emit(std::ofstream &of, int level) const emit_comment(of, level); of << "architecture " << name_ << " of " << entity_; of << " is"; - emit_children(of, decls_, level); + emit_children(of, scope_.get_decls(), level); of << "begin"; emit_children(of, stmts_, level); of << "end architecture;"; @@ -170,32 +147,7 @@ void vhdl_arch::emit(std::ofstream &of, int level) const vhdl_decl *vhdl_arch::get_decl(const std::string &name) const { - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return *it; - } - - // Maybe it's a port rather than an internal signal? - assert(parent_); - return parent_->get_decl(name); -} - -/* - * True if component `name' has already been declared in this - * architecture. This is a bit of hack, since it uses typeid - * to distinguish between components and other declarations. - */ -bool vhdl_arch::have_declared_component(const std::string &name) const -{ - std::string comp_typename(typeid(vhdl_component_decl).name()); - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if (comp_typename == typeid(**it).name() - && (*it)->get_name() == name) - return true; - } - return false; + return scope_.get_decl(name); } /* @@ -204,14 +156,9 @@ bool vhdl_arch::have_declared_component(const std::string &name) const */ bool vhdl_arch::have_declared(const std::string &name) const { - return get_decl(name) != NULL; + return scope_.have_declared(name); } -vhdl_arch *vhdl_conc_stmt::get_parent() const -{ - assert(parent_); - return parent_; -} vhdl_process::vhdl_process(const char *name) : name_(name), initial_(false) @@ -219,44 +166,11 @@ vhdl_process::vhdl_process(const char *name) } -vhdl_process::~vhdl_process() -{ - delete_children(decls_); -} - -void vhdl_process::add_decl(vhdl_decl* decl) -{ - decls_.push_back(decl); -} - -vhdl_decl *vhdl_process::get_decl(const std::string &name) const -{ - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return *it; - } - - // Maybe it's a signal rather than a variable? - assert(get_parent()); - return get_parent()->get_decl(name); -} - void vhdl_process::add_sensitivity(const char *name) { sens_.push_back(name); } -bool vhdl_process::have_declared_var(const std::string &name) const -{ - decl_list_t::const_iterator it; - for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) - return true; - } - return false; -} - void vhdl_process::emit(std::ofstream &of, int level) const { // If there are no statements in the body, this process @@ -285,7 +199,7 @@ void vhdl_process::emit(std::ofstream &of, int level) const } of << "is"; - emit_children(of, decls_, level); + emit_children(of, scope_.get_decls(), level); of << "begin"; stmts_.emit(of, level); of << "end process;"; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9ccca2781..72d9ce2d2 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -203,14 +203,8 @@ private: * processes. */ class vhdl_conc_stmt : public vhdl_element { - friend class vhdl_arch; // Can set its parent public: - vhdl_conc_stmt() : parent_(NULL) {} virtual ~vhdl_conc_stmt() {} - - vhdl_arch *get_parent() const; -private: - vhdl_arch *parent_; }; typedef std::list conc_stmt_list_t; @@ -532,9 +526,11 @@ 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(); bool empty() const { return decls_.empty(); } const decl_list_t &get_decls() const { return decls_; } + void set_parent(vhdl_scope *p) { parent_ = p; } private: decl_list_t decls_; vhdl_scope *parent_; @@ -544,19 +540,16 @@ private: class vhdl_process : public vhdl_conc_stmt { public: vhdl_process(const char *name = ""); - virtual ~vhdl_process(); void emit(std::ofstream &of, int level) const; stmt_container *get_container() { return &stmts_; } - void add_decl(vhdl_decl *decl); void add_sensitivity(const char *name); - bool have_declared_var(const std::string &name) const; - vhdl_decl *get_decl(const std::string &name) const; + vhdl_scope *get_scope() { return &scope_; } void set_initial(bool i) { initial_ = i; } bool is_initial() const { return initial_; } private: stmt_container stmts_; - decl_list_t decls_; + vhdl_scope scope_; std::string name_; string_list_t sens_; bool initial_; @@ -567,22 +560,20 @@ private: * An architecture which implements an entity. */ class vhdl_arch : public vhdl_element { - friend class vhdl_entity; // Can set its parent public: vhdl_arch(const char *entity, const char *name); virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; - bool have_declared_component(const std::string &name) const; bool have_declared(const std::string &name) const; vhdl_decl *get_decl(const std::string &name) const; void add_decl(vhdl_decl *decl); + void add_stmt(vhdl_process *proc); void add_stmt(vhdl_conc_stmt *stmt); - vhdl_entity *get_parent() const; + vhdl_scope *get_scope() { return &scope_; } private: - vhdl_entity *parent_; conc_stmt_list_t stmts_; - decl_list_t decls_; + vhdl_scope scope_; std::string name_, entity_; }; @@ -601,9 +592,7 @@ public: void emit(std::ofstream &of, int level=0) const; void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } - vhdl_decl *get_decl(const std::string &name) const; const std::string &get_name() const { return name_; } - void requires_package(const char *spec); const std::string &get_derived_from() const { return derived_from_; } vhdl_scope *get_scope() { return &ports_; } @@ -611,7 +600,6 @@ private: std::string name_; vhdl_arch *arch_; // Entity may only have a single architecture std::string derived_from_; - string_list_t uses_; vhdl_scope ports_; }; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index cd12460ed..fbabc5e30 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -23,8 +23,9 @@ void remember_entity(vhdl_entity *ent); vhdl_entity *find_entity(const std::string &tname); ivl_design_t get_vhdl_design(); +vhdl_entity *get_active_entity(); -vhdl_var_ref *nexus_to_var_ref(vhdl_arch *arch, ivl_nexus_t nexus); +vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, 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); From 75631bd8f1c99f765353ca17fa83eb4a75f357ba Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 19:06:06 +0100 Subject: [PATCH 133/377] Move is_inital code out of vhdl_process into vhdl_scope Part of tidy up before implementing functions --- tgt-vhdl/process.cc | 2 +- tgt-vhdl/stmt.cc | 15 +++++++++++---- tgt-vhdl/vhdl_syntax.cc | 15 +-------------- tgt-vhdl/vhdl_syntax.hh | 14 +++++++++----- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index cc6ca855a..5783e71b2 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -158,7 +158,7 @@ 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->set_initial(true); + vhdl_proc->get_scope()->set_initializing(true); ivl_statement_t stmt = ivl_process_stmt(proc); int rc = draw_stmt(vhdl_proc, vhdl_proc->get_container(), stmt); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 90d63c475..4eb76f421 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -129,6 +129,7 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, return 1; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); + // TODO: CORRECT THIS!!! // If this is an `inital' process and we haven't yet // generated a `wait' statement then this assignment // needs to be moved to the declaration. Otherwise the @@ -139,8 +140,10 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, // then use the uninitialized signal value. // The second test ensures that we only try to initialise // internal signals not ports - if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE + if (proc->get_scope()->initializing() + && ivl_signal_port(sig) == IVL_SIP_NONE && rhs->constant()) { + decl->set_initial(rhs); } else { @@ -185,8 +188,11 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, // As with non-blocking assignment, push constant assignments // into the initialisation if we can - if (proc->is_initial() && ivl_signal_port(sig) == IVL_SIP_NONE - && rhs->constant() && !proc->get_scope()->have_declared(signame)) { + if (proc->get_scope()->initializing() + && ivl_signal_port(sig) == IVL_SIP_NONE + && rhs->constant() + && !proc->get_scope()->have_declared(signame)) { + decl->set_initial(rhs); // This signal may be used e.g. in a loop test so we need @@ -281,7 +287,8 @@ static int draw_delay(vhdl_process *proc, stmt_container *container, // Any further assignments occur after simulation time 0 // so they cannot be used to initialize signal declarations - proc->set_initial(false); + // (if this scope is an initial process) + proc->get_scope()->set_initializing(false); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 770e8db7d..4f07eb0e8 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -26,7 +26,7 @@ #include vhdl_scope::vhdl_scope() - : parent_(NULL) + : parent_(NULL), init_(false) { } @@ -106,12 +106,6 @@ void vhdl_entity::emit(std::ofstream &of, int level) const arch_->emit(of, level); } -vhdl_arch::vhdl_arch(const char *entity, const char *name) - : name_(name), entity_(entity) -{ - -} - vhdl_arch::~vhdl_arch() { delete_children(stmts_); @@ -159,13 +153,6 @@ bool vhdl_arch::have_declared(const std::string &name) const return scope_.have_declared(name); } - -vhdl_process::vhdl_process(const char *name) - : name_(name), initial_(false) -{ - -} - void vhdl_process::add_sensitivity(const char *name) { sens_.push_back(name); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 72d9ce2d2..fffc08352 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -517,6 +517,8 @@ private: /* * Contains a list of declarations in a hierarchy. + * A scope can be `initializing' where assignments automatically + * create initial values for declarations. */ class vhdl_scope { public: @@ -531,28 +533,29 @@ public: bool empty() const { return decls_.empty(); } const decl_list_t &get_decls() const { return decls_; } void set_parent(vhdl_scope *p) { parent_ = p; } + + bool initializing() const { return init_; } + void set_initializing(bool i) { init_ = i; } private: decl_list_t decls_; vhdl_scope *parent_; + bool init_; }; class vhdl_process : public vhdl_conc_stmt { public: - vhdl_process(const char *name = ""); + vhdl_process(const char *name = "") : name_(name) {} void emit(std::ofstream &of, int level) const; stmt_container *get_container() { return &stmts_; } void add_sensitivity(const char *name); vhdl_scope *get_scope() { return &scope_; } - void set_initial(bool i) { initial_ = i; } - bool is_initial() const { return initial_; } private: stmt_container stmts_; vhdl_scope scope_; std::string name_; string_list_t sens_; - bool initial_; }; @@ -561,7 +564,8 @@ private: */ class vhdl_arch : public vhdl_element { public: - vhdl_arch(const char *entity, const char *name); + vhdl_arch(const char *entity, const char *name) + : name_(name), entity_(entity) {} virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; From e77bb0157eef1ccfad4c8954a60e221c6bfc486d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 19:39:05 +0100 Subject: [PATCH 134/377] Remove redundant methods from vhdl_arch --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/scope.cc | 10 +++++----- tgt-vhdl/vhdl_syntax.cc | 20 -------------------- tgt-vhdl/vhdl_syntax.hh | 3 --- 4 files changed, 6 insertions(+), 29 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 5c2fa6233..e861b4a7f 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -46,7 +46,7 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) const char *renamed = get_renamed_signal(sig).c_str(); - const vhdl_decl *decl = ent->get_arch()->get_decl(strip_var(renamed)); + const vhdl_decl *decl = ent->get_arch()->get_scope()->get_decl(strip_var(renamed)); assert(decl); vhdl_type *type = new vhdl_type(*decl->get_type()); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 23dd95490..2856801ff 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -163,7 +163,7 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: - ent->get_arch()->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); + ent->get_arch()->get_scope()->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); break; case IVL_SIP_INPUT: ent->get_scope()->add_decl @@ -184,7 +184,7 @@ 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()->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 @@ -276,7 +276,7 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, // Don't map a signal to itself! continue; } - else if ((decl = parent->get_arch()->get_decl(basename))) { + else if ((decl = parent->get_arch()->get_scope()->get_decl(basename))) { // It's a signal declared in the parent // Pick this one (any one will do as they're all // connected together if there's more than one) @@ -345,9 +345,9 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) assert(parent_arch != NULL); // Create a forward declaration for it - if (!parent_arch->have_declared(ent->get_name())) { + if (!parent_arch->get_scope()->have_declared(ent->get_name())) { vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); - parent_arch->add_decl(comp_decl); + parent_arch->get_scope()->add_decl(comp_decl); } // And an instantiation statement diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 770e8db7d..b8b9ca465 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -128,11 +128,6 @@ void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) stmts_.push_back(stmt); } -void vhdl_arch::add_decl(vhdl_decl *decl) -{ - scope_.add_decl(decl); -} - void vhdl_arch::emit(std::ofstream &of, int level) const { emit_comment(of, level); @@ -145,21 +140,6 @@ void vhdl_arch::emit(std::ofstream &of, int level) const blank_line(of, level); // Extra blank line after architectures; } -vhdl_decl *vhdl_arch::get_decl(const std::string &name) const -{ - return scope_.get_decl(name); -} - -/* - * True if any declaration of `name' has been added to the - * architecture. - */ -bool vhdl_arch::have_declared(const std::string &name) const -{ - return scope_.have_declared(name); -} - - vhdl_process::vhdl_process(const char *name) : name_(name), initial_(false) { diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 72d9ce2d2..5d03eca9d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -565,9 +565,6 @@ public: virtual ~vhdl_arch(); void emit(std::ofstream &of, int level=0) const; - bool have_declared(const std::string &name) const; - vhdl_decl *get_decl(const std::string &name) const; - void add_decl(vhdl_decl *decl); void add_stmt(vhdl_process *proc); void add_stmt(vhdl_conc_stmt *stmt); vhdl_scope *get_scope() { return &scope_; } From f2aca68b82d396a45666dd4bbdd33af858183469 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 19:50:57 +0100 Subject: [PATCH 135/377] Add new vhdl_procedural superclass for process/task/func --- tgt-vhdl/vhdl_syntax.hh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index d841c0a90..7bac65751 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -542,17 +542,21 @@ private: bool init_; }; +class vhdl_procedural { +public: + stmt_container *get_container() { return &stmts_; } +protected: + stmt_container stmts_; +}; -class vhdl_process : public vhdl_conc_stmt { +class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { public: vhdl_process(const char *name = "") : name_(name) {} void emit(std::ofstream &of, int level) const; - stmt_container *get_container() { return &stmts_; } void add_sensitivity(const char *name); vhdl_scope *get_scope() { return &scope_; } private: - stmt_container stmts_; vhdl_scope scope_; std::string name_; string_list_t sens_; From db992e808f24013eb64d9b7293aa6d72bd2ca1c7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 19:54:22 +0100 Subject: [PATCH 136/377] Start using vhdl_procedural instead of vhdl_process --- tgt-vhdl/display.cc | 2 +- tgt-vhdl/process.cc | 4 ++-- tgt-vhdl/vhdl_syntax.hh | 4 ++-- tgt-vhdl/vhdl_target.h | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 1b40c8c82..24e30c66e 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -112,7 +112,7 @@ static void flush_string(std::ostringstream &ss, stmt_container *container) * name collision with an existing variable called * `Verilog_Display_Line' -- do something about this? */ -int draw_stask_display(vhdl_process *proc, stmt_container *container, +int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline) { if (!proc->get_scope()->have_declared(DISPLAY_LINE)) { diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 5783e71b2..5833cb5b3 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -77,7 +77,7 @@ static var_temp_set_t g_assign_vars; /* * Called whenever a blocking assignment is made to sig. */ -void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) +void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig) { std::string var(get_renamed_signal(sig)); std::string tmpname(var + "_Var"); @@ -104,7 +104,7 @@ void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig) * 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_process *proc, stmt_container *container) +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) { diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 7bac65751..35ccf64cb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -545,8 +545,10 @@ private: class vhdl_procedural { public: stmt_container *get_container() { return &stmts_; } + vhdl_scope *get_scope() { return &scope_; } protected: stmt_container stmts_; + vhdl_scope scope_; }; class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { @@ -555,9 +557,7 @@ public: void emit(std::ofstream &of, int level) const; void add_sensitivity(const char *name); - vhdl_scope *get_scope() { return &scope_; } private: - vhdl_scope scope_; std::string name_; string_list_t sens_; }; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index fbabc5e30..710152bea 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -32,11 +32,11 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed); const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); -void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig); +void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig); std::string strip_var(const std::string &str); -void draw_blocking_assigns(vhdl_process *proc, stmt_container *container); +void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container); -int draw_stask_display(vhdl_process *proc, stmt_container *container, +int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true); #endif /* #ifndef INC_VHDL_TARGET_H */ From bf95d7756246d655d8c3c046090b87bf60bd0c34 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 20:01:06 +0100 Subject: [PATCH 137/377] Finish replacing vhdl_process with vhdl_procedural --- tgt-vhdl/stmt.cc | 28 ++++++++++++++++------------ tgt-vhdl/vhdl_syntax.hh | 2 ++ tgt-vhdl/vhdl_target.h | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 4eb76f421..791ce7545 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -38,7 +38,7 @@ * in C. This function can be enabled with the flag * -puse-vhpi-finish=1. */ -static int draw_stask_finish(vhdl_process *proc, stmt_container *container, +static int draw_stask_finish(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { const char *use_vhpi = ivl_design_flag(get_vhdl_design(), "use-vhpi-finish"); @@ -57,7 +57,7 @@ static int draw_stask_finish(vhdl_process *proc, stmt_container *container, * Generate VHDL for system tasks (like $display). Not all of * these are supported. */ -static int draw_stask(vhdl_process *proc, stmt_container *container, +static int draw_stask(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { const char *name = ivl_stmt_name(stmt); @@ -80,7 +80,7 @@ static int draw_stask(vhdl_process *proc, stmt_container *container, * block's statements and add them to the process. This is OK as * the stmt_container class behaves like a Verilog block. */ -static int draw_block(vhdl_process *proc, stmt_container *container, +static int draw_block(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { int count = ivl_stmt_block_count(stmt); @@ -95,7 +95,7 @@ static int draw_block(vhdl_process *proc, stmt_container *container, * A no-op statement. This corresponds to a `null' statement in * VHDL. */ -static int draw_noop(vhdl_process *proc, stmt_container *container, +static int draw_noop(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { container->add_stmt(new vhdl_null_stmt()); @@ -107,7 +107,7 @@ static int draw_noop(vhdl_process *proc, stmt_container *container, * this are essentially the same as VHDL's non-blocking signal * assignment. */ -static int draw_nbassign(vhdl_process *proc, stmt_container *container, +static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, vhdl_expr *after = NULL) { int nlvals = ivl_stmt_lvals(stmt); @@ -164,7 +164,7 @@ static int draw_nbassign(vhdl_process *proc, stmt_container *container, return 0; } -static int draw_assign(vhdl_process *proc, stmt_container *container, +static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { int nlvals = ivl_stmt_lvals(stmt); @@ -233,7 +233,7 @@ static int draw_assign(vhdl_process *proc, stmt_container *container, * Delay statements are equivalent to the `wait for' form of the * VHDL wait statement. */ -static int draw_delay(vhdl_process *proc, stmt_container *container, +static int draw_delay(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { // This currently ignores the time units and precision @@ -313,9 +313,13 @@ static void edge_detector(ivl_nexus_t nexus, vhdl_process *proc, * A wait statement waits for a level change on a @(..) list of * signals. */ -static int draw_wait(vhdl_process *proc, stmt_container *container, +static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_statement_t stmt) { + // 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); int nevents = ivl_stmt_nevent(stmt); @@ -390,7 +394,7 @@ static int draw_wait(vhdl_process *proc, stmt_container *container, return 0; } -static int draw_if(vhdl_process *proc, stmt_container *container, +static int draw_if(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); @@ -411,7 +415,7 @@ static int draw_if(vhdl_process *proc, stmt_container *container, return 0; } -static int draw_case(vhdl_process *proc, stmt_container *container, +static int draw_case(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); @@ -457,7 +461,7 @@ static int draw_case(vhdl_process *proc, stmt_container *container, return 0; } -int draw_while(vhdl_process *proc, stmt_container *container, +int draw_while(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); @@ -478,7 +482,7 @@ int draw_while(vhdl_process *proc, stmt_container *container, * location to add statements: e.g. the process body, a branch * of an if statement, etc. */ -int draw_stmt(vhdl_process *proc, stmt_container *container, +int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { assert(stmt); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 35ccf64cb..b328dca60 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -544,6 +544,8 @@ private: class vhdl_procedural { public: + virtual ~vhdl_procedural() {} + stmt_container *get_container() { return &stmts_; } vhdl_scope *get_scope() { return &scope_; } protected: diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 710152bea..686b560e4 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -13,7 +13,7 @@ void error(const char *fmt, ...); 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, +int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt); int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); From 899a70908ec52f638fa3b61baea46a89152e395a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 24 Jun 2008 20:13:18 +0100 Subject: [PATCH 138/377] Fix small bug with initialisation and ammend comments --- tgt-vhdl/process.cc | 5 +---- tgt-vhdl/stmt.cc | 32 +++++++++++++++++++------------- tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 5833cb5b3..73cc51e92 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -47,10 +47,7 @@ * 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. This - * has exactly the same (external) behaviour as the Verilog - * blocking assignment, since no external process will be able - * to observe that the assignment wasn't made immediately. + * back to the signals, and the temporaries are forgotten. * * For example: * diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 791ce7545..59166026d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -129,20 +129,23 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, return 1; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); - // TODO: CORRECT THIS!!! - // If this is an `inital' process and we haven't yet - // generated a `wait' statement then this assignment - // needs to be moved to the declaration. Otherwise the - // Verilog behaviour won't be preserved: 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. + // 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 - && rhs->constant()) { + && !decl->has_initial() && rhs->constant()) { decl->set_initial(rhs); } @@ -186,12 +189,15 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, return 1; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); + bool isvar = strip_var(signame) != signame; + // As with non-blocking assignment, push constant assignments - // into the initialisation if we can + // into the initialisation if we can (but only if this is + // the first time we assign to this variable). if (proc->get_scope()->initializing() && ivl_signal_port(sig) == IVL_SIP_NONE - && rhs->constant() - && !proc->get_scope()->have_declared(signame)) { + && rhs->constant() && !decl->has_initial() + && !isvar) { decl->set_initial(rhs); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index b328dca60..b4b40d21b 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -416,6 +416,7 @@ public: const std::string &get_name() const { return name_; } const vhdl_type *get_type() const { return type_; } void set_initial(vhdl_expr *initial); + bool has_initial() const { return initial_ != NULL; } protected: std::string name_; vhdl_type *type_; From c01c2bd74285df802aac74b5edda82b08fb06eae Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 12:48:46 +0100 Subject: [PATCH 139/377] Dummy code for handling function scopes --- tgt-vhdl/scope.cc | 18 ++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2856801ff..237b77d64 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -366,6 +366,21 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) return 0; } +/* + * Create a VHDL function from a Verilog function definition. + */ +int draw_function(ivl_scope_t scope, ivl_scope_t parent) +{ + assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION); + + // Find the containing entity + vhdl_entity *ent = find_entity(ivl_scope_tname(parent)); + assert(ent); + + return 1; +} + + int draw_scope(ivl_scope_t scope, void *_parent) { ivl_scope_t parent = static_cast(_parent); @@ -376,6 +391,9 @@ int draw_scope(ivl_scope_t scope, void *_parent) case IVL_SCT_MODULE: rc = draw_module(scope, parent); break; + case IVL_SCT_FUNCTION: + rc = draw_function(scope, parent); + break; default: error("No VHDL conversion for %s (at %s)", ivl_scope_tname(scope), diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index b4b40d21b..428996412 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -543,6 +543,12 @@ private: bool init_; }; + +/* + * Any sort of procedural element: process, function, or + * procedure. Roughly these map onto Verilog's processes, + * functions, and tasks. + */ class vhdl_procedural { public: virtual ~vhdl_procedural() {} @@ -554,6 +560,17 @@ protected: vhdl_scope scope_; }; + +class vhdl_function : public vhdl_decl, public vhdl_procedural { +public: + vhdl_function(const char *name, vhdl_type *ret_type) + : vhdl_decl(name, ret_type) {} + + void emit(std::ofstream &of, int level) const; +private: +}; + + class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { public: vhdl_process(const char *name = "") : name_(name) {} From a3df37b851eee3555d1fd12eb0e77baae95b3cf8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 17:29:09 +0100 Subject: [PATCH 140/377] Initial code to generate function calls Also catch a few null-pointer issues --- tgt-vhdl/expr.cc | 27 +++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index e861b4a7f..75d94147f 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -203,6 +203,31 @@ vhdl_expr *translate_select(ivl_expr_t e) return from->resize(ivl_expr_width(e)); } +vhdl_expr *translate_ufunc(ivl_expr_t e) +{ + ivl_scope_t defscope = ivl_expr_def(e); + ivl_scope_t parentscope = ivl_scope_parent(defscope); + assert(ivl_scope_type(parentscope) == IVL_SCT_MODULE); + + // A function is always declared in a module, which should have + // a corresponding entity by this point: so we can get type + // information, etc. from the declaration + vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parentscope)); + assert(parent_ent); + + const char *funcname = ivl_scope_tname(defscope); + + vhdl_decl *fdecl = + parent_ent->get_arch()->get_scope()->get_decl(funcname); + assert(fdecl); + + vhdl_type *rettype = new vhdl_type(*fdecl->get_type()); + + vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); + + return fcall; +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -224,6 +249,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_binary(e); case IVL_EX_SELECT: return translate_select(e); + case IVL_EX_UFUNC: + return translate_ufunc(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 89f15749e..921f15964 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -305,6 +305,12 @@ vhdl_decl::~vhdl_decl() delete initial_; } +const vhdl_type *vhdl_decl::get_type() const +{ + assert(type_); + return type_; +} + void vhdl_decl::set_initial(vhdl_expr *initial) { if (initial_ != NULL) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 428996412..742a38f5d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -414,7 +414,7 @@ public: virtual ~vhdl_decl(); const std::string &get_name() const { return name_; } - const vhdl_type *get_type() const { return type_; } + const vhdl_type *get_type() const; void set_initial(vhdl_expr *initial); bool has_initial() const { return initial_ != NULL; } protected: From 43c671cb5c8757145c4daf63b3af33e145950ebc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 18:00:48 +0100 Subject: [PATCH 141/377] Emit VHDL for function declarations --- tgt-vhdl/scope.cc | 9 +++++++-- tgt-vhdl/vhdl_syntax.cc | 29 +++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 22 +++++++++++++++++----- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 237b77d64..049ab1141 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -377,9 +377,14 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) vhdl_entity *ent = find_entity(ivl_scope_tname(parent)); assert(ent); - return 1; -} + const char *funcname = ivl_scope_tname(scope); + vhdl_function *func = new vhdl_function(funcname, vhdl_type::std_logic()); + + ent->get_arch()->get_scope()->add_decl(func); + + return 0; +} int draw_scope(ivl_scope_t scope, void *_parent) { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 921f15964..d8bdb95ed 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -751,3 +751,32 @@ void vhdl_while_stmt::emit(std::ofstream &of, int level) const stmts_.emit(of, level); of << "end loop;"; } + +vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) + : vhdl_decl(name, ret_type) +{ + // A function contains two scopes: + // scope_ = The paramters + // variables_ = Local variables + // A call to get_scope returns variables_ whose parent is scope_ + variables_.set_parent(&scope_); +} + +void vhdl_function::emit(std::ofstream &of, int level) const +{ + of << "function " << name_ << " ("; + emit_children(of, scope_.get_decls(), level, ","); + of << ") return "; + type_->emit(of, level); + of << " is"; + emit_children(of, variables_.get_decls(), level); + of << "begin"; + stmts_.emit(of, level); + of << "end function;"; +} + +void vhdl_param_decl::emit(std::ofstream &of, int level) const +{ + of << name_ << " : "; + type_->emit(of, level); +} diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 742a38f5d..463a637b4 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -467,6 +467,16 @@ public: }; +/* + * A parameter to a function. + */ +class vhdl_param_decl : public vhdl_decl { +public: + vhdl_param_decl(const char *name, vhdl_type *type) + : vhdl_decl(name, type) {} + void emit(std::ofstream &of, int level) const; +}; + enum vhdl_port_mode_t { VHDL_PORT_IN, VHDL_PORT_OUT, @@ -553,8 +563,8 @@ class vhdl_procedural { public: virtual ~vhdl_procedural() {} - stmt_container *get_container() { return &stmts_; } - vhdl_scope *get_scope() { return &scope_; } + virtual stmt_container *get_container() { return &stmts_; } + virtual vhdl_scope *get_scope() { return &scope_; } protected: stmt_container stmts_; vhdl_scope scope_; @@ -563,11 +573,13 @@ protected: class vhdl_function : public vhdl_decl, public vhdl_procedural { public: - vhdl_function(const char *name, vhdl_type *ret_type) - : vhdl_decl(name, ret_type) {} - + vhdl_function(const char *name, vhdl_type *ret_type); + void emit(std::ofstream &of, int level) const; + vhdl_scope *get_scope() { return &variables_; } + void add_param(vhdl_param_decl *p) { scope_.add_decl(p); } private: + vhdl_scope variables_; }; From 44aa8a6b9187347da727ff7963f5cb6f6c86b14b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 18:12:57 +0100 Subject: [PATCH 142/377] Associate signals with scopes rather than entities --- tgt-vhdl/expr.cc | 6 +++--- tgt-vhdl/scope.cc | 7 +++++-- tgt-vhdl/vhdl.cc | 12 ++++++------ tgt-vhdl/vhdl_target.h | 4 ++-- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 75d94147f..485c18206 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -41,12 +41,12 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); - const vhdl_entity *ent = find_entity_for_signal(sig); - assert(ent); + const vhdl_scope *scope = find_scope_for_signal(sig); + assert(scope); const char *renamed = get_renamed_signal(sig).c_str(); - const vhdl_decl *decl = ent->get_arch()->get_scope()->get_decl(strip_var(renamed)); + const vhdl_decl *decl = scope->get_decl(strip_var(renamed)); assert(decl); vhdl_type *type = new vhdl_type(*decl->get_type()); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 049ab1141..e07715a22 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -141,7 +141,7 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) else sig_type = vhdl_type::nunsigned(width); - remember_signal(sig, ent); + remember_signal(sig, ent->get_arch()->get_scope()); // Make sure the signal name conforms to VHDL naming rules std::string name(ivl_signal_basename(sig)); @@ -381,8 +381,11 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) vhdl_function *func = new vhdl_function(funcname, vhdl_type::std_logic()); - ent->get_arch()->get_scope()->add_decl(func); + int nports = ivl_scope_ports(scope); + std::cout << "function has " << nports << " ports" << std::endl; + + ent->get_arch()->get_scope()->add_decl(func); return 0; } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 29ea76106..670c928ae 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -38,8 +38,8 @@ * defined. */ struct signal_defn_t { - std::string renamed; // The name of the VHDL signal - const vhdl_entity *ent; // The entity where it is defined + std::string renamed; // The name of the VHDL signal + const vhdl_scope *scope; // The scope where it is defined }; typedef std::map signal_defn_map_t; @@ -93,11 +93,11 @@ void remember_entity(vhdl_entity* ent) /* * Remeber the association of signal to entity. */ -void remember_signal(ivl_signal_t sig, const vhdl_entity *ent) +void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) { assert(g_known_signals.find(sig) == g_known_signals.end()); - signal_defn_t defn = { ivl_signal_basename(sig), ent }; + signal_defn_t defn = { ivl_signal_basename(sig), scope }; g_known_signals[sig] = defn; } @@ -111,11 +111,11 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed) g_known_signals[sig].renamed = renamed; } -const vhdl_entity *find_entity_for_signal(ivl_signal_t sig) +const vhdl_scope *find_scope_for_signal(ivl_signal_t sig) { assert(g_known_signals.find(sig) != g_known_signals.end()); - return g_known_signals[sig].ent; + return g_known_signals[sig].scope; } const std::string &get_renamed_signal(ivl_signal_t sig) diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 686b560e4..4e8109a1d 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -27,9 +27,9 @@ vhdl_entity *get_active_entity(); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); -void remember_signal(ivl_signal_t sig, const vhdl_entity *ent); +void remember_signal(ivl_signal_t sig, const vhdl_scope *scope); void rename_signal(ivl_signal_t sig, const std::string &renamed); -const vhdl_entity *find_entity_for_signal(ivl_signal_t sig); +const vhdl_scope *find_scope_for_signal(ivl_signal_t sig); const std::string &get_renamed_signal(ivl_signal_t sig); void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig); From 042f7ccbcdd947b451ba9f5c7c2ea5e083f5f2b3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 18:43:50 +0100 Subject: [PATCH 143/377] Generate a return type for functions --- tgt-vhdl/scope.cc | 93 +++++++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 32 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e07715a22..faaadde83 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -123,6 +123,42 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) } } +/* + * Make sure a signal name conforms to VHDL naming rules. + */ +static std::string make_safe_name(ivl_signal_t sig) +{ + std::string name(ivl_signal_basename(sig)); + if (name[0] == '_') + name.insert(0, "VL"); + + const char *vhdl_reserved[] = { + "in", "out", "entity", "architecture", "inout", // Etc... + NULL + }; + for (const char **p = vhdl_reserved; *p != NULL; p++) { + if (name == *p) { + name.insert(0, "VL_"); + break; + } + } + 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. */ @@ -130,35 +166,13 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) { int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); - - int width = ivl_signal_width(sig); - vhdl_type *sig_type; - if (width == 1) - sig_type = vhdl_type::std_logic(); - else if (ivl_signal_signed(sig)) - sig_type = vhdl_type::nsigned(width); - else - sig_type = vhdl_type::nunsigned(width); - + ivl_signal_t sig = ivl_scope_sig(scope, i); remember_signal(sig, ent->get_arch()->get_scope()); - // Make sure the signal name conforms to VHDL naming rules - std::string name(ivl_signal_basename(sig)); - if (name[0] == '_') - name.insert(0, "VL"); - - const char *vhdl_reserved[] = { - "in", "out", "entity", "architecture", "inout", // Etc... - NULL - }; - for (const char **p = vhdl_reserved; *p != NULL; p++) { - if (name == *p) { - name.insert(0, "VL_"); - break; - } - } - rename_signal(sig, name.c_str()); + vhdl_type *sig_type = get_signal_type(sig); + + std::string name = make_safe_name(sig); + rename_signal(sig, name); ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { @@ -379,12 +393,27 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) const char *funcname = ivl_scope_tname(scope); - vhdl_function *func = new vhdl_function(funcname, vhdl_type::std_logic()); - + // This logic relies on the return value being the first port + vhdl_function *func = NULL; int nports = ivl_scope_ports(scope); - std::cout << "function has " << nports << " ports" << std::endl; - - + for (int i = 0; i < nports; i++) { + ivl_signal_t sig = ivl_scope_port(scope, i); + std::string signame = make_safe_name(sig); + + vhdl_type *sigtype = get_signal_type(sig); + if (ivl_signal_type(sig) == IVL_SIT_REG) { + func = new vhdl_function(funcname, sigtype); + + } + else { + assert(func); + } + + remember_signal(sig, func->get_scope()); + rename_signal(sig, signame); + } + + assert(func); ent->get_arch()->get_scope()->add_decl(func); return 0; } From 7773000c363596cf5776654aa075cca56a7a26ff Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 21:40:35 +0100 Subject: [PATCH 144/377] Generate function declarations --- tgt-vhdl/scope.cc | 14 ++++++++++---- tgt-vhdl/vhdl_syntax.cc | 8 ++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index faaadde83..b5a7de94d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -401,12 +401,18 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) std::string signame = make_safe_name(sig); vhdl_type *sigtype = get_signal_type(sig); - if (ivl_signal_type(sig) == IVL_SIT_REG) { + + switch (ivl_signal_port(sig)) { + case IVL_SIP_OUTPUT: + assert(func == NULL); func = new vhdl_function(funcname, sigtype); - - } - else { + break; + case IVL_SIP_INPUT: assert(func); + func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); + break; + default: + assert(false); } remember_signal(sig, func->get_scope()); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d8bdb95ed..4825b94e5 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -765,10 +765,10 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) void vhdl_function::emit(std::ofstream &of, int level) const { of << "function " << name_ << " ("; - emit_children(of, scope_.get_decls(), level, ","); - of << ") return "; - type_->emit(of, level); - of << " is"; + emit_children(of, scope_.get_decls(), level, ";"); + of << ") "; + newline(of, level); + of << "return " << type_->get_string() << " is"; emit_children(of, variables_.get_decls(), level); of << "begin"; stmts_.emit(of, level); From d997397c387726a23487c9e42a23ae03129a628e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 21:49:22 +0100 Subject: [PATCH 145/377] Generate function calls with parameters --- tgt-vhdl/expr.cc | 10 +++++++++- tgt-vhdl/scope.cc | 17 ++++++++++++----- tgt-vhdl/vhdl_syntax.cc | 2 ++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 485c18206..593c3a6ab 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -222,9 +222,17 @@ vhdl_expr *translate_ufunc(ivl_expr_t e) assert(fdecl); vhdl_type *rettype = new vhdl_type(*fdecl->get_type()); - vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); + int nparams = ivl_expr_parms(e); + for (int i = 0; i < nparams; i++) { + vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); + if (NULL == param) + return NULL; + + fcall->add_expr(param); + } + return fcall; } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b5a7de94d..a5ca5d6ff 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -404,8 +404,15 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) switch (ivl_signal_port(sig)) { case IVL_SIP_OUTPUT: - assert(func == NULL); - func = new vhdl_function(funcname, sigtype); + { + assert(func == NULL); + func = new vhdl_function(funcname, sigtype); + + // The magic variable Verilog_Result holds the return value + signame = "Verilog_Result"; + func->get_scope()->add_decl + (new vhdl_var_decl(signame.c_str(), new vhdl_type(*sigtype))); + } break; case IVL_SIP_INPUT: assert(func); @@ -417,9 +424,9 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) remember_signal(sig, func->get_scope()); rename_signal(sig, signame); - } - - assert(func); + } + + assert(func); ent->get_arch()->get_scope()->add_decl(func); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 4825b94e5..97fbc2753 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -772,6 +772,8 @@ void vhdl_function::emit(std::ofstream &of, int level) const emit_children(of, variables_.get_decls(), level); of << "begin"; stmts_.emit(of, level); + of << " return Verilog_Result;"; + newline(of, level); of << "end function;"; } From 2baf31dff8cade09621062874bc7a9ff44acce77 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 21:54:11 +0100 Subject: [PATCH 146/377] Fix bug with $display and integer literals --- tgt-vhdl/display.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 24e30c66e..c599aabc3 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -40,11 +40,8 @@ static void display_write(stmt_container *container, vhdl_expr *expr) vhdl_type_name_t type = expr->get_type()->get_name(); if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) { - vhdl_fcall *toint = - new vhdl_fcall("To_Integer", vhdl_type::integer()); - toint->add_expr(expr); - - write->add_expr(toint); + vhdl_type integer(VHDL_TYPE_INTEGER); + write->add_expr(expr->cast(&integer)); } else if (type != VHDL_TYPE_STRING) { // Need to add a call to Type'Image for types not From 500442e5c5adcc83c8ac262b8dff0dfc47d8f0eb Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 25 Jun 2008 22:15:57 +0100 Subject: [PATCH 147/377] Working function calls --- tgt-vhdl/scope.cc | 5 +++++ tgt-vhdl/stmt.cc | 32 ++++++++++++++++++++------------ tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 5 ++++- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index a5ca5d6ff..79a1e0ce2 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -425,6 +425,11 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } + + // Non-blocking assignment not allowed in functions + func->get_scope()->set_allow_signal_assignment(false); + + draw_stmt(func, func->get_container(), ivl_scope_def(scope)); assert(func); ent->get_arch()->get_scope()->add_decl(func); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 59166026d..c3bcaa183 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -116,6 +116,8 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, return 1; } + assert(proc->get_scope()->allow_signal_assignment()); + ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { @@ -201,21 +203,27 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, decl->set_initial(rhs); - // 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); + if (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); - - vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, sig_ref); - container->add_stmt(assign); + 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); + + vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, sig_ref); + container->add_stmt(assign); + } } else { - blocking_assign_to(proc, sig); + if (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 const std::string &renamed = get_renamed_signal(sig); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 97fbc2753..87629a46f 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -26,7 +26,7 @@ #include vhdl_scope::vhdl_scope() - : parent_(NULL), init_(false) + : parent_(NULL), init_(false), sig_assign_(true) { } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 463a637b4..a356cb7b9 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -547,10 +547,13 @@ public: bool initializing() const { return init_; } void set_initializing(bool i) { init_ = i; } + + void set_allow_signal_assignment(bool b) { sig_assign_ = b; } + bool allow_signal_assignment() const { return sig_assign_; } private: decl_list_t decls_; vhdl_scope *parent_; - bool init_; + bool init_, sig_assign_; }; From fd60bfd3d2220983ac3d4b169bb1c335bf852a8f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 27 Jun 2008 12:18:39 +0100 Subject: [PATCH 148/377] Rewrite function parameter finding code --- tgt-vhdl/scope.cc | 33 +++++++++++++++------------------ tgt-vhdl/vhdl_syntax.hh | 1 + 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 79a1e0ce2..5f03f20b4 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -393,38 +393,35 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) const char *funcname = ivl_scope_tname(scope); - // This logic relies on the return value being the first port - vhdl_function *func = NULL; - int nports = ivl_scope_ports(scope); - for (int i = 0; i < nports; i++) { - ivl_signal_t sig = ivl_scope_port(scope, i); - std::string signame = make_safe_name(sig); - + // The return type is worked out from the output port + vhdl_function *func = new vhdl_function(funcname, NULL); + + 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); + + std::string signame = make_safe_name(sig); switch (ivl_signal_port(sig)) { case IVL_SIP_OUTPUT: - { - assert(func == NULL); - func = new vhdl_function(funcname, sigtype); - - // The magic variable Verilog_Result holds the return value - signame = "Verilog_Result"; - func->get_scope()->add_decl - (new vhdl_var_decl(signame.c_str(), new vhdl_type(*sigtype))); - } + // The magic variable Verilog_Result holds the return value + signame = "Verilog_Result"; + func->set_type(sigtype); + func->get_scope()->add_decl + (new vhdl_var_decl(signame.c_str(), new vhdl_type(*sigtype))); break; case IVL_SIP_INPUT: - assert(func); func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); break; default: assert(false); } - + remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } + // Non-blocking assignment not allowed in functions func->get_scope()->set_allow_signal_assignment(false); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a356cb7b9..d650d2cd6 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -415,6 +415,7 @@ public: 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; } protected: From b24eb6ce88b1e12695bbd1c060a16bd38d8b4de4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 27 Jun 2008 12:21:27 +0100 Subject: [PATCH 149/377] Handle local variables in functions --- tgt-vhdl/scope.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5f03f20b4..2642648e5 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -404,18 +404,16 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) std::string signame = make_safe_name(sig); switch (ivl_signal_port(sig)) { + case IVL_SIP_INPUT: + func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); + break; case IVL_SIP_OUTPUT: // The magic variable Verilog_Result holds the return value signame = "Verilog_Result"; func->set_type(sigtype); + default: func->get_scope()->add_decl (new vhdl_var_decl(signame.c_str(), new vhdl_type(*sigtype))); - break; - case IVL_SIP_INPUT: - func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); - break; - default: - assert(false); } remember_signal(sig, func->get_scope()); From 301a25303f260eb026c2e8f1251d742c326d332e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 27 Jun 2008 12:21:53 +0100 Subject: [PATCH 150/377] Remove useless assertion --- tgt-vhdl/scope.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2642648e5..85dc3ccd3 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -426,7 +426,6 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) draw_stmt(func, func->get_container(), ivl_scope_def(scope)); - assert(func); ent->get_arch()->get_scope()->add_decl(func); return 0; } From f800298d01a0fbcf0177f4ee5c2c0cc354a429a5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 27 Jun 2008 12:29:50 +0100 Subject: [PATCH 151/377] Fix memory leak --- tgt-vhdl/scope.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 85dc3ccd3..2fbcae7a0 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -410,17 +410,16 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) case IVL_SIP_OUTPUT: // The magic variable Verilog_Result holds the return value signame = "Verilog_Result"; - func->set_type(sigtype); + func->set_type(new vhdl_type(*sigtype)); default: func->get_scope()->add_decl - (new vhdl_var_decl(signame.c_str(), new vhdl_type(*sigtype))); + (new vhdl_var_decl(signame.c_str(), sigtype)); } remember_signal(sig, func->get_scope()); rename_signal(sig, signame); } - - + // Non-blocking assignment not allowed in functions func->get_scope()->set_allow_signal_assignment(false); From 081f3974604b961809dbf19ebb94d2d22be49608 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 27 Jun 2008 14:58:03 +0100 Subject: [PATCH 152/377] Implement LPM part select --- tgt-vhdl/lpm.cc | 26 ++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 1 + 2 files changed, 27 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 3d67ddf93..00f7240e1 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -58,6 +58,30 @@ static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) return 0; } +int draw_part_select_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_expr *off = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 1)); + 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; + + // Array indexes must be integers + vhdl_type integer(VHDL_TYPE_INTEGER); + off = off->cast(&integer); + + selfrom->set_slice(off); + arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); + + return 0; +} + int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -67,6 +91,8 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_binop_lpm(arch, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); + case IVL_LPM_PART_VP: + return draw_part_select_lpm(arch, lpm); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return 1; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index d650d2cd6..16cf8109a 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -56,6 +56,7 @@ public: void emit(std::ofstream &of, int level) const; const std::string &get_name() const { return name_; } + void set_slice(vhdl_expr *s) { slice_ = s; } private: std::string name_; vhdl_expr *slice_; From b82ca281907363c23d3b3103c46fc4f3525b7121 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 30 Jun 2008 16:18:55 +0100 Subject: [PATCH 153/377] Add XOR logic type and fix part select --- tgt-vhdl/lpm.cc | 8 +++++++- tgt-vhdl/scope.cc | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 00f7240e1..6ce6d04a6 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -63,8 +63,14 @@ int draw_part_select_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_expr *off = NULL; + ivl_nexus_t base = ivl_lpm_data(lpm, 1); + if (base != NULL) + off = nexus_to_var_ref(arch->get_scope(), base); + else + off = new vhdl_const_int(ivl_lpm_base(lpm)); - vhdl_expr *off = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 1)); if (NULL == off) return 1; diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2fbcae7a0..142c2d535 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -112,6 +112,9 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) case IVL_LO_OR: rhs = inputs_to_expr(arch, VHDL_BINOP_OR, log); break; + case IVL_LO_XOR: + rhs = inputs_to_expr(arch, VHDL_BINOP_XOR, log); + break; default: error("Don't know how to translate logic type = %d", ivl_logic_type(log)); From e08e29c8b4a37587c1097f85c86402f7da5771c5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 30 Jun 2008 16:35:29 +0100 Subject: [PATCH 154/377] Add UFUNC LPM type --- tgt-vhdl/lpm.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 6ce6d04a6..50b8dfb5f 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -88,6 +88,27 @@ int draw_part_select_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return 0; } +int draw_ufunc_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +{ + vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL); + + for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) { + vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, i)); + if (NULL == ref) + return 1; + + fcall->add_expr(ref); + } + + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); + if (NULL == out) + return 1; + + arch->add_stmt(new vhdl_cassign_stmt(out, fcall)); + + return 0; +} + int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -99,6 +120,8 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); case IVL_LPM_PART_VP: return draw_part_select_lpm(arch, lpm); + case IVL_LPM_UFUNC: + return draw_ufunc_lpm(arch, lpm); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return 1; From 4e73b1b133a3716c5bd0c4e3deb5c5bd7f73be00 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 30 Jun 2008 17:47:45 +0100 Subject: [PATCH 155/377] Fix bug when resolving nexus to VHDL signal --- tgt-vhdl/scope.cc | 9 ++++++++- tgt-vhdl/vhdl.cc | 13 +++++++++---- tgt-vhdl/vhdl_target.h | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 142c2d535..615ec1aea 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -38,6 +38,9 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) 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); @@ -215,6 +218,8 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ent->get_scope()->add_decl (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); break; + default: + assert(false); } } } @@ -331,7 +336,9 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, case IVL_SIP_INOUT: map_signal(sig, parent, inst); break; - } + default: + assert(false); + } } } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 670c928ae..c3a22bedd 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -90,12 +90,17 @@ void remember_entity(vhdl_entity* ent) g_entities.push_back(ent); } +bool seen_signal_before(ivl_signal_t sig) +{ + return g_known_signals.find(sig) != g_known_signals.end(); +} + /* * Remeber the association of signal to entity. */ void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) { - assert(g_known_signals.find(sig) == g_known_signals.end()); + assert(!seen_signal_before(sig)); signal_defn_t defn = { ivl_signal_basename(sig), scope }; g_known_signals[sig] = defn; @@ -106,21 +111,21 @@ void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) */ void rename_signal(ivl_signal_t sig, const std::string &renamed) { - assert(g_known_signals.find(sig) != g_known_signals.end()); + assert(seen_signal_before(sig)); g_known_signals[sig].renamed = renamed; } const vhdl_scope *find_scope_for_signal(ivl_signal_t sig) { - assert(g_known_signals.find(sig) != g_known_signals.end()); + assert(seen_signal_before(sig)); return g_known_signals[sig].scope; } const std::string &get_renamed_signal(ivl_signal_t sig) { - assert(g_known_signals.find(sig) != g_known_signals.end()); + assert(seen_signal_before(sig)); return g_known_signals[sig].renamed; } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 4e8109a1d..1d91a77e9 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -27,6 +27,7 @@ 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); const vhdl_scope *find_scope_for_signal(ivl_signal_t sig); From 6e8474f584807efb0aa52afe453669c37ad53207 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 30 Jun 2008 17:58:15 +0100 Subject: [PATCH 156/377] Fix bug where func had to be declared before use --- tgt-vhdl/expr.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 593c3a6ab..6bd65c2f7 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -216,12 +216,13 @@ vhdl_expr *translate_ufunc(ivl_expr_t e) assert(parent_ent); const char *funcname = ivl_scope_tname(defscope); + + vhdl_type *rettype; + if (ivl_expr_signed(e)) + rettype = vhdl_type::nsigned(ivl_expr_width(e)); + else + rettype = vhdl_type::nunsigned(ivl_expr_width(e)); - vhdl_decl *fdecl = - parent_ent->get_arch()->get_scope()->get_decl(funcname); - assert(fdecl); - - vhdl_type *rettype = new vhdl_type(*fdecl->get_type()); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); int nparams = ivl_expr_parms(e); From f03dfb50ade1eaed00256652524164629ede30ca Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 10:33:46 +0100 Subject: [PATCH 157/377] Refactor nexus_to_var_ref --- tgt-vhdl/scope.cc | 74 ++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 615ec1aea..03b4e8fa7 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,18 +25,21 @@ #include #include +static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); + /* * Given a nexus and an architecture scope, find the first signal * that is connected to the nexus, if there is one. */ -vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) +static vhdl_expr *nexus_to_expr(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; + ivl_net_logic_t log; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { if (!seen_signal_before(sig)) continue; @@ -49,6 +52,9 @@ vhdl_var_ref *nexus_to_var_ref(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))) { + return translate_logic(arch_scope, log); + } else { // Ignore other types of nexus pointer } @@ -57,10 +63,17 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) assert(false); } +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)); + assert(ref); + return ref; +} + /* * Convert the inputs of a logic gate to a binary expression. */ -static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, +static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, ivl_net_logic_t log) { // Not always std_logic but this is probably OK since @@ -71,7 +84,7 @@ static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, int npins = ivl_logic_pins(log); for (int i = 1; i < npins; i++) { ivl_nexus_t input = ivl_logic_pin(log, i); - gate->add_expr(nexus_to_var_ref(arch->get_scope(), input)); + gate->add_expr(nexus_to_expr(scope, input)); } return gate; @@ -80,16 +93,34 @@ static vhdl_expr *inputs_to_expr(vhdl_arch *arch, vhdl_binop_t op, /* * Convert a gate intput to an unary expression. */ -static vhdl_expr *input_to_expr(vhdl_arch *arch, vhdl_unaryop_t op, +static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, ivl_net_logic_t log) { ivl_nexus_t input = ivl_logic_pin(log, 1); assert(input); - vhdl_expr *operand = nexus_to_var_ref(arch->get_scope(), input); + vhdl_expr *operand = nexus_to_expr(scope, input); return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } +static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) +{ + switch (ivl_logic_type(log)) { + case IVL_LO_NOT: + return input_to_expr(scope, VHDL_UNARYOP_NOT, log); + case IVL_LO_AND: + return inputs_to_expr(scope, VHDL_BINOP_AND, log); + case IVL_LO_OR: + return inputs_to_expr(scope, VHDL_BINOP_OR, log); + case IVL_LO_XOR: + return inputs_to_expr(scope, VHDL_BINOP_XOR, log); + default: + error("Don't know how to translate logic type = %d", + ivl_logic_type(log)); + return NULL; + } +} + /* * Translate all the primitive logic gates into concurrent * signal assignments. @@ -100,32 +131,15 @@ 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 = nexus_to_var_ref(arch->get_scope(), output); - - vhdl_expr *rhs = NULL; - switch (ivl_logic_type(log)) { - case IVL_LO_NOT: - rhs = input_to_expr(arch, VHDL_UNARYOP_NOT, log); - break; - case IVL_LO_AND: - rhs = inputs_to_expr(arch, VHDL_BINOP_AND, log); - break; - case IVL_LO_OR: - rhs = inputs_to_expr(arch, VHDL_BINOP_OR, log); - break; - case IVL_LO_XOR: - rhs = inputs_to_expr(arch, VHDL_BINOP_XOR, log); - break; - default: - error("Don't know how to translate logic type = %d", - ivl_logic_type(log)); - continue; + if (ivl_logic_pins(log) > 1) { + // The output is always pin zero + ivl_nexus_t output = ivl_logic_pin(log, 0); + vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); + + vhdl_expr *rhs = translate_logic(arch->get_scope(), log); + + arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); } - assert(rhs); - - arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); } } From 050aa277ae0c282b9b2c153bfc2003041c34cfe1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 10:37:22 +0100 Subject: [PATCH 158/377] Make vhdl_element::emit a little more generic --- tgt-vhdl/vhdl_element.cc | 6 ++-- tgt-vhdl/vhdl_element.hh | 8 ++--- tgt-vhdl/vhdl_helper.hh | 2 +- tgt-vhdl/vhdl_syntax.cc | 64 ++++++++++++++++++++-------------------- tgt-vhdl/vhdl_syntax.hh | 64 ++++++++++++++++++++-------------------- tgt-vhdl/vhdl_type.cc | 2 +- tgt-vhdl/vhdl_type.hh | 2 +- 7 files changed, 74 insertions(+), 74 deletions(-) diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index 5391736f7..cdbd1fcff 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -38,14 +38,14 @@ int indent(int level) /* * Emit a newline and indent to the correct level. */ -void newline(std::ofstream &of, int level) +void newline(std::ostream &of, int level) { of << std::endl; while (level--) of << ' '; } -void blank_line(std::ofstream &of, int level) +void blank_line(std::ostream &of, int level) { of << std::endl; newline(of, level); @@ -61,7 +61,7 @@ void vhdl_element::set_comment(std::string comment) * a line before the element (end_of_line is false) or at the * end of the line containing the element (end_of_line is true). */ -void vhdl_element::emit_comment(std::ofstream &of, int level, +void vhdl_element::emit_comment(std::ostream &of, int level, bool end_of_line) const { if (comment_.size() > 0) { diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index f73ea0949..4bd6b3c05 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -34,11 +34,11 @@ class vhdl_element { public: virtual ~vhdl_element() {} - virtual void emit(std::ofstream &of, int level=0) const = 0; + virtual void emit(std::ostream &of, int level=0) const = 0; void set_comment(std::string comment); protected: - void emit_comment(std::ofstream &of, int level, + void emit_comment(std::ostream &of, int level, bool end_of_line=false) const; private: std::string comment_; @@ -47,8 +47,8 @@ private: typedef std::list element_list_t; int indent(int level); -void newline(std::ofstream &of, int level); -void blank_line(std::ofstream &of, int level); +void newline(std::ostream &of, int level); +void blank_line(std::ostream &of, int level); #endif diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index c1f9499ab..a3f6f0704 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -26,7 +26,7 @@ #include template -void emit_children(std::ofstream &of, +void emit_children(std::ostream &of, const std::list &children, int level, const char *delim="") { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 87629a46f..2d4d1e984 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -80,7 +80,7 @@ void vhdl_entity::add_port(vhdl_port_decl *decl) ports_.add_decl(decl); } -void vhdl_entity::emit(std::ofstream &of, int level) const +void vhdl_entity::emit(std::ostream &of, int level) const { // Pretty much every design will use std_logic so we // might as well include it by default @@ -122,7 +122,7 @@ void vhdl_arch::add_stmt(vhdl_conc_stmt *stmt) stmts_.push_back(stmt); } -void vhdl_arch::emit(std::ofstream &of, int level) const +void vhdl_arch::emit(std::ostream &of, int level) const { emit_comment(of, level); of << "architecture " << name_ << " of " << entity_; @@ -139,7 +139,7 @@ void vhdl_process::add_sensitivity(const char *name) sens_.push_back(name); } -void vhdl_process::emit(std::ofstream &of, int level) const +void vhdl_process::emit(std::ostream &of, int level) const { // If there are no statements in the body, this process // can't possibly do anything, so don't bother to emit it @@ -184,7 +184,7 @@ void stmt_container::add_stmt(vhdl_seq_stmt *stmt) stmts_.push_back(stmt); } -void stmt_container::emit(std::ofstream &of, int level) const +void stmt_container::emit(std::ostream &of, int level) const { emit_children(of, stmts_, level); } @@ -210,7 +210,7 @@ void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr) mapping_.push_back(pmap); } -void vhdl_comp_inst::emit(std::ofstream &of, int level) const +void vhdl_comp_inst::emit(std::ostream &of, int level) const { emit_comment(of, level); of << inst_name_ << ": " << comp_name_; @@ -258,7 +258,7 @@ vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent) return decl; } -void vhdl_component_decl::emit(std::ofstream &of, int level) const +void vhdl_component_decl::emit(std::ostream &of, int level) const { emit_comment(of, level); of << "component " << name_ << " is"; @@ -280,7 +280,7 @@ vhdl_wait_stmt::~vhdl_wait_stmt() delete expr_; } -void vhdl_wait_stmt::emit(std::ofstream &of, int level) const +void vhdl_wait_stmt::emit(std::ostream &of, int level) const { of << "wait"; @@ -318,7 +318,7 @@ void vhdl_decl::set_initial(vhdl_expr *initial) initial_ = initial; } -void vhdl_port_decl::emit(std::ofstream &of, int level) const +void vhdl_port_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; @@ -337,7 +337,7 @@ void vhdl_port_decl::emit(std::ofstream &of, int level) const type_->emit(of, level); } -void vhdl_var_decl::emit(std::ofstream &of, int level) const +void vhdl_var_decl::emit(std::ostream &of, int level) const { of << "variable " << name_ << " : "; type_->emit(of, level); @@ -351,7 +351,7 @@ void vhdl_var_decl::emit(std::ofstream &of, int level) const emit_comment(of, level, true); } -void vhdl_signal_decl::emit(std::ofstream &of, int level) const +void vhdl_signal_decl::emit(std::ostream &of, int level) const { of << "signal " << name_ << " : "; type_->emit(of, level); @@ -435,7 +435,7 @@ vhdl_expr_list::~vhdl_expr_list() delete_children(exprs_); } -void vhdl_expr_list::emit(std::ofstream &of, int level) const +void vhdl_expr_list::emit(std::ostream &of, int level) const { of << "("; @@ -450,7 +450,7 @@ void vhdl_expr_list::emit(std::ofstream &of, int level) const of << ")"; } -void vhdl_pcall_stmt::emit(std::ofstream &of, int level) const +void vhdl_pcall_stmt::emit(std::ostream &of, int level) const { of << name_; if (!exprs_.empty()) @@ -464,7 +464,7 @@ vhdl_var_ref::~vhdl_var_ref() delete slice_; } -void vhdl_var_ref::emit(std::ofstream &of, int level) const +void vhdl_var_ref::emit(std::ostream &of, int level) const { of << name_; if (slice_) { @@ -474,7 +474,7 @@ void vhdl_var_ref::emit(std::ofstream &of, int level) const } } -void vhdl_const_string::emit(std::ofstream &of, int level) const +void vhdl_const_string::emit(std::ostream &of, int level) const { // In some instances a string literal can be ambiguous between // a String type and some other types (e.g. std_logic_vector) @@ -483,12 +483,12 @@ void vhdl_const_string::emit(std::ofstream &of, int level) const of << "String'(\"" << value_ << "\")"; } -void vhdl_null_stmt::emit(std::ofstream &of, int level) const +void vhdl_null_stmt::emit(std::ostream &of, int level) const { of << "null;"; } -void vhdl_fcall::emit(std::ofstream &of, int level) const +void vhdl_fcall::emit(std::ostream &of, int level) const { of << name_; exprs_.emit(of, level); @@ -502,7 +502,7 @@ vhdl_abstract_assign_stmt::~vhdl_abstract_assign_stmt() delete after_; } -void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const +void vhdl_nbassign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " <= "; @@ -516,7 +516,7 @@ void vhdl_nbassign_stmt::emit(std::ofstream &of, int level) const of << ";"; } -void vhdl_assign_stmt::emit(std::ofstream &of, int level) const +void vhdl_assign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " := "; @@ -569,7 +569,7 @@ vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) return vhdl_expr::cast(to); } -void vhdl_const_bits::emit(std::ofstream &of, int level) const +void vhdl_const_bits::emit(std::ostream &of, int level) const { if (qualified_) of << (signed_ ? "signed" : "unsigned") << "'(\""; @@ -584,17 +584,17 @@ void vhdl_const_bits::emit(std::ofstream &of, int level) const of << (qualified_ ? "\")" : "\""); } -void vhdl_const_bit::emit(std::ofstream &of, int level) const +void vhdl_const_bit::emit(std::ostream &of, int level) const { of << "'" << vl_to_vhdl_bit(bit_) << "'"; } -void vhdl_const_int::emit(std::ofstream &of, int level) const +void vhdl_const_int::emit(std::ostream &of, int level) const { of << value_; } -void vhdl_const_time::emit(std::ofstream &of, int level) const +void vhdl_const_time::emit(std::ostream &of, int level) const { of << value_; switch (units_) { @@ -609,7 +609,7 @@ vhdl_cassign_stmt::~vhdl_cassign_stmt() delete rhs_; } -void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const +void vhdl_cassign_stmt::emit(std::ostream &of, int level) const { lhs_->emit(of, level); of << " <= "; @@ -617,7 +617,7 @@ void vhdl_cassign_stmt::emit(std::ofstream &of, int level) const of << ";"; } -void vhdl_assert_stmt::emit(std::ofstream &of, int level) const +void vhdl_assert_stmt::emit(std::ostream &of, int level) const { of << "assert false"; // TODO: Allow arbitrary expression of << " report \"" << reason_ << "\" severity failure;"; @@ -635,7 +635,7 @@ vhdl_if_stmt::~vhdl_if_stmt() delete test_; } -void vhdl_if_stmt::emit(std::ofstream &of, int level) const +void vhdl_if_stmt::emit(std::ostream &of, int level) const { of << "if "; test_->emit(of, level); @@ -653,7 +653,7 @@ vhdl_unaryop_expr::~vhdl_unaryop_expr() delete operand_; } -void vhdl_unaryop_expr::emit(std::ofstream &of, int level) const +void vhdl_unaryop_expr::emit(std::ostream &of, int level) const { switch (op_) { case VHDL_UNARYOP_NOT: @@ -681,7 +681,7 @@ void vhdl_binop_expr::add_expr(vhdl_expr *e) operands_.push_back(e); } -void vhdl_binop_expr::emit(std::ofstream &of, int level) const +void vhdl_binop_expr::emit(std::ostream &of, int level) const { // Expressions are fully parenthesized to remove any // ambiguity in the output @@ -711,7 +711,7 @@ vhdl_case_branch::~vhdl_case_branch() delete when_; } -void vhdl_case_branch::emit(std::ofstream &of, int level) const +void vhdl_case_branch::emit(std::ostream &of, int level) const { of << "when "; when_->emit(of, level); @@ -724,7 +724,7 @@ vhdl_case_stmt::~vhdl_case_stmt() delete test_; } -void vhdl_case_stmt::emit(std::ofstream &of, int level) const +void vhdl_case_stmt::emit(std::ostream &of, int level) const { of << "case "; test_->emit(of, level); @@ -743,7 +743,7 @@ vhdl_while_stmt::~vhdl_while_stmt() delete test_; } -void vhdl_while_stmt::emit(std::ofstream &of, int level) const +void vhdl_while_stmt::emit(std::ostream &of, int level) const { of << "while "; test_->emit(of, level); @@ -762,7 +762,7 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) variables_.set_parent(&scope_); } -void vhdl_function::emit(std::ofstream &of, int level) const +void vhdl_function::emit(std::ostream &of, int level) const { of << "function " << name_ << " ("; emit_children(of, scope_.get_decls(), level, ";"); @@ -777,7 +777,7 @@ void vhdl_function::emit(std::ofstream &of, int level) const of << "end function;"; } -void vhdl_param_decl::emit(std::ofstream &of, int level) const +void vhdl_param_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; type_->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 16cf8109a..2487840ed 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -54,7 +54,7 @@ public: : vhdl_expr(type), name_(name), slice_(slice) {} ~vhdl_var_ref(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } void set_slice(vhdl_expr *s) { slice_ = s; } private: @@ -93,7 +93,7 @@ public: ~vhdl_binop_expr(); void add_expr(vhdl_expr *e); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: std::list operands_; vhdl_binop_t op_; @@ -111,7 +111,7 @@ public: : vhdl_expr(type), op_(op), operand_(operand) {} ~vhdl_unaryop_expr(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_unaryop_t op_; vhdl_expr *operand_; @@ -123,7 +123,7 @@ public: vhdl_const_string(const char *value) : vhdl_expr(vhdl_type::string(), true), value_(value) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: std::string value_; }; @@ -131,7 +131,7 @@ private: class vhdl_const_bits : public vhdl_expr { public: vhdl_const_bits(const char *value, int width, bool issigned); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; const std::string &get_value() const { return value_; } vhdl_expr *cast(const vhdl_type *to); private: @@ -143,7 +143,7 @@ class vhdl_const_bit : public vhdl_expr { public: vhdl_const_bit(char bit) : vhdl_expr(vhdl_type::std_logic(), true), bit_(bit) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: char bit_; }; @@ -156,7 +156,7 @@ class vhdl_const_time : public vhdl_expr { public: vhdl_const_time(int64_t value, time_unit_t units) : vhdl_expr(vhdl_type::time(), true), value_(value), units_(units) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: int64_t value_; time_unit_t units_; @@ -166,7 +166,7 @@ class vhdl_const_int : public vhdl_expr { public: vhdl_const_int(int64_t value) : vhdl_expr(vhdl_type::integer(), true), value_(value) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: int64_t value_; }; @@ -175,7 +175,7 @@ class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; bool empty() const { return exprs_.empty(); } void add_expr(vhdl_expr *e); private: @@ -193,7 +193,7 @@ public: ~vhdl_fcall() {} void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: std::string name_; vhdl_expr_list exprs_; @@ -219,7 +219,7 @@ public: : lhs_(lhs), rhs_(rhs) {} ~vhdl_cassign_stmt(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_var_ref *lhs_; vhdl_expr *rhs_; @@ -243,7 +243,7 @@ public: ~stmt_container(); void add_stmt(vhdl_seq_stmt *stmt); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; bool empty() const { return stmts_.empty(); } private: std::list stmts_; @@ -275,7 +275,7 @@ public: vhdl_nbassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : vhdl_abstract_assign_stmt(lhs, rhs) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; @@ -284,7 +284,7 @@ public: vhdl_assign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) : vhdl_abstract_assign_stmt(lhs, rhs) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; @@ -304,7 +304,7 @@ public: : type_(type), expr_(expr) {} ~vhdl_wait_stmt(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_wait_type_t type_; vhdl_expr *expr_; @@ -313,7 +313,7 @@ private: class vhdl_null_stmt : public vhdl_seq_stmt { public: - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; @@ -322,7 +322,7 @@ public: vhdl_assert_stmt(const char *reason) : reason_(reason) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: std::string reason_; }; @@ -335,7 +335,7 @@ public: stmt_container *get_then_container() { return &then_part_; } stmt_container *get_else_container() { return &else_part_; } - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; stmt_container then_part_, else_part_; @@ -352,7 +352,7 @@ public: ~vhdl_case_branch(); stmt_container *get_container() { return &stmts_; } - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_expr *when_; stmt_container stmts_; @@ -366,7 +366,7 @@ public: ~vhdl_case_stmt(); void add_branch(vhdl_case_branch *b) { branches_.push_back(b); } - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; case_branch_list_t branches_; @@ -379,7 +379,7 @@ public: ~vhdl_while_stmt(); stmt_container *get_container() { return &stmts_; } - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; stmt_container stmts_; @@ -394,7 +394,7 @@ class vhdl_pcall_stmt : public vhdl_seq_stmt { public: vhdl_pcall_stmt(const char *name) : name_(name) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; void add_expr(vhdl_expr *e) { exprs_.add_expr(e); } private: std::string name_; @@ -438,7 +438,7 @@ class vhdl_component_decl : public vhdl_decl { public: static vhdl_component_decl *component_decl_for(vhdl_entity *ent); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_component_decl(const char *name); @@ -454,7 +454,7 @@ class vhdl_var_decl : public vhdl_decl { public: vhdl_var_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; @@ -465,7 +465,7 @@ class vhdl_signal_decl : public vhdl_decl { public: vhdl_signal_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} - virtual void emit(std::ofstream &of, int level) const; + virtual void emit(std::ostream &of, int level) const; }; @@ -476,7 +476,7 @@ class vhdl_param_decl : public vhdl_decl { public: vhdl_param_decl(const char *name, vhdl_type *type) : vhdl_decl(name, type) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; }; enum vhdl_port_mode_t { @@ -496,7 +496,7 @@ public: vhdl_port_mode_t mode) : vhdl_decl(name, type), mode_(mode) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; private: vhdl_port_mode_t mode_; }; @@ -520,7 +520,7 @@ public: vhdl_comp_inst(const char *inst_name, const char *comp_name); ~vhdl_comp_inst(); - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; void map_port(const char *name, vhdl_expr *expr); private: std::string comp_name_, inst_name_; @@ -580,7 +580,7 @@ class vhdl_function : public vhdl_decl, public vhdl_procedural { public: vhdl_function(const char *name, vhdl_type *ret_type); - void emit(std::ofstream &of, int level) const; + 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: @@ -592,7 +592,7 @@ class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { public: vhdl_process(const char *name = "") : name_(name) {} - void emit(std::ofstream &of, int level) const; + void emit(std::ostream &of, int level) const; void add_sensitivity(const char *name); private: std::string name_; @@ -609,7 +609,7 @@ public: : name_(name), entity_(entity) {} virtual ~vhdl_arch(); - void emit(std::ofstream &of, int level=0) const; + void emit(std::ostream &of, int level=0) const; void add_stmt(vhdl_process *proc); void add_stmt(vhdl_conc_stmt *stmt); vhdl_scope *get_scope() { return &scope_; } @@ -631,7 +631,7 @@ public: vhdl_arch *arch); virtual ~vhdl_entity(); - void emit(std::ofstream &of, int level=0) const; + void emit(std::ostream &of, int level=0) const; void add_port(vhdl_port_decl *decl); vhdl_arch *get_arch() const { return arch_; } const std::string &get_name() const { return name_; } diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 4176cfce4..77b3a7b0f 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -112,7 +112,7 @@ std::string vhdl_type::get_decl_string() const } } -void vhdl_type::emit(std::ofstream &of, int level) const +void vhdl_type::emit(std::ostream &of, int level) const { of << get_decl_string(); } diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index e4e41d3e2..b0e0c6f3b 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -47,7 +47,7 @@ public: : name_(name), msb_(msb), lsb_(lsb) {} virtual ~vhdl_type() {} - void emit(std::ofstream &of, int level) const; + 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; From ef89a760d67a40c5463b54623ad371311509f459 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 10:44:20 +0100 Subject: [PATCH 159/377] Add vhdl_element::print method for debugging --- tgt-vhdl/scope.cc | 8 ++++++-- tgt-vhdl/vhdl_element.cc | 6 ++++++ tgt-vhdl/vhdl_element.hh | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 03b4e8fa7..c4b9b9eb8 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -64,8 +64,12 @@ 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(nexus_to_expr(arch_scope, nexus)); +{ + vhdl_expr *e = nexus_to_expr(arch_scope, nexus); + + e->print(); + + vhdl_var_ref *ref = dynamic_cast(e); assert(ref); return ref; } diff --git a/tgt-vhdl/vhdl_element.cc b/tgt-vhdl/vhdl_element.cc index cdbd1fcff..e631319fc 100644 --- a/tgt-vhdl/vhdl_element.cc +++ b/tgt-vhdl/vhdl_element.cc @@ -72,3 +72,9 @@ void vhdl_element::emit_comment(std::ostream &of, int level, newline(of, level); } } + +void vhdl_element::print() const +{ + emit(std::cout, 0); + std::cout << std::endl; +} diff --git a/tgt-vhdl/vhdl_element.hh b/tgt-vhdl/vhdl_element.hh index 4bd6b3c05..abccdfdb2 100644 --- a/tgt-vhdl/vhdl_element.hh +++ b/tgt-vhdl/vhdl_element.hh @@ -35,6 +35,7 @@ public: virtual ~vhdl_element() {} virtual void emit(std::ostream &of, int level=0) const = 0; + void print() const; void set_comment(std::string comment); protected: From 624943b3ca2ade7f866ce593261d5722f356b88d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 10:59:31 +0100 Subject: [PATCH 160/377] Simplify port map generation code --- tgt-vhdl/scope.cc | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index c4b9b9eb8..70cf45611 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -41,13 +41,16 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus) ivl_signal_t sig; ivl_net_logic_t log; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { + std::cout << ivl_signal_name(sig) << std::endl; + if (!seen_signal_before(sig)) continue; const char *signame = get_renamed_signal(sig).c_str(); vhdl_decl *decl = arch_scope->get_decl(signame); - assert(decl); + if (NULL == decl) + continue; // Not in this scope vhdl_type *type = new vhdl_type(*(decl->get_type())); return new vhdl_var_ref(signame, type); @@ -135,15 +138,18 @@ 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); - if (ivl_logic_pins(log) > 1) { - // The output is always pin zero - ivl_nexus_t output = ivl_logic_pin(log, 0); - vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); - - vhdl_expr *rhs = translate_logic(arch->get_scope(), log); - - arch->add_stmt(new vhdl_cassign_stmt(lhs, rhs)); - } + std::cout << ivl_logic_pins(log) << std::endl; + + // 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)); } } @@ -303,8 +309,13 @@ 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); + inst->map_port(ivl_signal_basename(to), to_e); + + return; - int nptrs = ivl_nexus_ptrs(nexus); + /* int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { ivl_signal_t sig; vhdl_decl *decl; @@ -327,7 +338,7 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, return; } } - } + }*/ error("Failed to find signal to connect to port %s", ivl_signal_basename(to)); From edfae1abfbd5bec2fa73a607bb39ed09250bf407 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 11:02:49 +0100 Subject: [PATCH 161/377] PV LPM part select type --- tgt-vhdl/lpm.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 50b8dfb5f..6fdec04bb 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -118,6 +118,7 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_binop_lpm(arch, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); + case IVL_LPM_PART_PV: case IVL_LPM_PART_VP: return draw_part_select_lpm(arch, lpm); case IVL_LPM_UFUNC: From 596c93ce7e3232b0892f92d8130631964b911cc2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 11:05:24 +0100 Subject: [PATCH 162/377] Rename instance if it has the same name as the type --- tgt-vhdl/scope.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 70cf45611..513bd095a 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -404,9 +404,14 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) } // And an instantiation statement - const char *inst_name = ivl_scope_basename(scope); + std::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"; + } + vhdl_comp_inst *inst = - new vhdl_comp_inst(inst_name, ent->get_name().c_str()); + new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); port_map(scope, parent_ent, inst); parent_arch->add_stmt(inst); From 37756b8d06217e5cd112ec6d3c81b97641322004 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 11:13:02 +0100 Subject: [PATCH 163/377] Avoid mapping a signal to itself --- tgt-vhdl/scope.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 513bd095a..b33f14c1f 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -30,9 +30,11 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); /* * Given a nexus and an architecture scope, find the first signal - * that is connected to the nexus, if there is one. + * that is connected to the nexus, if there is one. Never return + * a reference to 'ignore' if it is found in the nexus. */ -static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus) +static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, + ivl_signal_t ignore = NULL) { int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { @@ -43,7 +45,7 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus) if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { std::cout << ivl_signal_name(sig) << std::endl; - if (!seen_signal_before(sig)) + if (!seen_signal_before(sig) || sig == ignore) continue; const char *signame = get_renamed_signal(sig).c_str(); @@ -310,7 +312,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); + vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(), nexus, to); + std::cout << "map " << ivl_signal_basename(to) << std::endl; inst->map_port(ivl_signal_basename(to), to_e); return; From 930e04f6c77a8b2a7cbf656d2f900ee6a8645b55 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 11:28:02 +0100 Subject: [PATCH 164/377] Ensure port map expressions are globally static --- tgt-vhdl/scope.cc | 32 ++++++++++++++++++++++++++++++-- tgt-vhdl/vhdl_syntax.hh | 3 +++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b33f14c1f..0b7bce50d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -313,9 +313,37 @@ 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, to); - std::cout << "map " << ivl_signal_basename(to) << std::endl; - inst->map_port(ivl_signal_basename(to), to_e); + // The expressions in a VHDL port map must be 'globally static' + // i.e. they can't be arbitrary expressions + // To handle this, only vhdl_var_refs are mapped automatically + // Otherwise a temporary variable is created to store the + // result of the expression and that is mapped to the port + // This is actually a bit stricter than necessary: but turns out + // to be much easier to implement + const char *basename = ivl_signal_basename(to); + vhdl_var_ref *to_ref; + if ((to_ref = dynamic_cast(to_e))) { + inst->map_port(basename, to_ref); + } + else { + // Not a static expression + std::string tmpname(inst->get_inst_name().c_str()); + tmpname += "_"; + tmpname += basename; + tmpname += "_Expr"; + + vhdl_type *tmptype = new vhdl_type(*to_e->get_type()); + parent->get_arch()->get_scope()->add_decl + (new vhdl_signal_decl(tmpname.c_str(), tmptype)); + + vhdl_var_ref *tmp_ref1 = new vhdl_var_ref(tmpname.c_str(), NULL); + parent->get_arch()->add_stmt(new vhdl_cassign_stmt(tmp_ref1, to_e)); + + vhdl_var_ref *tmp_ref2 = new vhdl_var_ref(*tmp_ref1); + inst->map_port(basename, tmp_ref2); + } + return; /* int nptrs = ivl_nexus_ptrs(nexus); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 2487840ed..c87eea284 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -522,6 +522,9 @@ public: void emit(std::ostream &of, int level) const; void map_port(const char *name, vhdl_expr *expr); + + const std::string &get_comp_name() const { return comp_name_; } + const std::string &get_inst_name() const { return inst_name_; } private: std::string comp_name_, inst_name_; port_map_list_t mapping_; From 35c66744dbcdaf1d25aedfe07a0fdd15946e82cc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 1 Jul 2008 11:31:00 +0100 Subject: [PATCH 165/377] Cleanup and remove debug output --- tgt-vhdl/scope.cc | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 0b7bce50d..a0ccd5526 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -43,8 +43,6 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_signal_t sig; ivl_net_logic_t log; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - std::cout << ivl_signal_name(sig) << std::endl; - if (!seen_signal_before(sig) || sig == ignore) continue; @@ -71,9 +69,6 @@ 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_expr *e = nexus_to_expr(arch_scope, nexus); - - e->print(); - vhdl_var_ref *ref = dynamic_cast(e); assert(ref); return ref; @@ -140,8 +135,6 @@ 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); - std::cout << ivl_logic_pins(log) << std::endl; - // The output is always pin zero ivl_nexus_t output = ivl_logic_pin(log, 0); vhdl_var_ref *lhs = @@ -343,36 +336,6 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, vhdl_var_ref *tmp_ref2 = new vhdl_var_ref(*tmp_ref1); inst->map_port(basename, tmp_ref2); } - - return; - - /* int nptrs = ivl_nexus_ptrs(nexus); - for (int i = 0; i < nptrs; i++) { - ivl_signal_t sig; - vhdl_decl *decl; - - ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nexus, i); - if ((sig = ivl_nexus_ptr_sig(ptr)) != NULL) { - const char *basename = ivl_signal_basename(sig); - if (sig == to) { - // Don't map a signal to itself! - continue; - } - else if ((decl = parent->get_arch()->get_scope()->get_decl(basename))) { - // It's a signal declared in the parent - // Pick this one (any one will do as they're all - // connected together if there's more than one) - vhdl_var_ref *ref = - new vhdl_var_ref(basename, vhdl_type::std_logic()); - inst->map_port(ivl_signal_basename(to), ref); - - return; - } - } - }*/ - - error("Failed to find signal to connect to port %s", - ivl_signal_basename(to)); } /* From 4fac825457da9e7b34a475a1efdaa57fe2af557a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 14:45:54 +0100 Subject: [PATCH 166/377] Add PV part select type --- tgt-vhdl/lpm.cc | 54 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 6fdec04bb..0d06d9057 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -58,19 +58,30 @@ static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) return 0; } -int draw_part_select_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +/* + * Return the base of a part select. + */ +static vhdl_expr *part_select_base(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_expr *off = NULL; + vhdl_expr *off; ivl_nexus_t base = ivl_lpm_data(lpm, 1); if (base != NULL) off = nexus_to_var_ref(arch->get_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 int draw_part_select_vp_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_expr *off = part_select_base(arch, lpm);; if (NULL == off) return 1; @@ -78,17 +89,31 @@ int draw_part_select_lpm(vhdl_arch *arch, ivl_lpm_t lpm) if (NULL == out) return 1; - // Array indexes must be integers - vhdl_type integer(VHDL_TYPE_INTEGER); - off = off->cast(&integer); - selfrom->set_slice(off); arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); - return 0; } -int draw_ufunc_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +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_expr *off = part_select_base(arch, 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); + arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); + return 0; +} + +static int draw_ufunc_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL); @@ -119,8 +144,9 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) case IVL_LPM_MULT: return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); case IVL_LPM_PART_PV: + return draw_part_select_pv_lpm(arch, lpm); case IVL_LPM_PART_VP: - return draw_part_select_lpm(arch, lpm); + return draw_part_select_vp_lpm(arch, lpm); case IVL_LPM_UFUNC: return draw_ufunc_lpm(arch, lpm); default: From 7e999c54962af151e139f4cfc619e1231679e699 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 15:13:12 +0100 Subject: [PATCH 167/377] Fix continuous assignment of constants E.g. in assign p = 1 the RHS signal in the generated LPM now has a correct intial value (and it will never be written to elsewhere) --- tgt-vhdl/scope.cc | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index a0ccd5526..816f3db1e 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -27,6 +27,32 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); +/* + * Given a nexus find a constant value in it that can be used + * as an initial signal value. + */ +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; +} /* * Given a nexus and an architecture scope, find the first signal @@ -202,7 +228,18 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) ivl_signal_port_t mode = ivl_signal_port(sig); switch (mode) { case IVL_SIP_NONE: - ent->get_arch()->get_scope()->add_decl(new vhdl_signal_decl(name.c_str(), sig_type)); + { + vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); + + // 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)); + if (init != NULL) + decl->set_initial(init); + + ent->get_arch()->get_scope()->add_decl(decl); + } break; case IVL_SIP_INPUT: ent->get_scope()->add_decl @@ -249,8 +286,10 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) 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)); + for (int i = 0; i < nlpms; i++) { + if (draw_lpm(arch, ivl_scope_lpm(scope, i)) != 0) + error("Failed to translate LPM"); + } } /* From fb08164cbc5546482cf020e3534d988f5b19e618 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 15:20:43 +0100 Subject: [PATCH 168/377] List some more illegal VHDL names --- tgt-vhdl/scope.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 816f3db1e..c87a9773c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -184,7 +184,8 @@ static std::string make_safe_name(ivl_signal_t sig) name.insert(0, "VL"); const char *vhdl_reserved[] = { - "in", "out", "entity", "architecture", "inout", // Etc... + "in", "out", "entity", "architecture", "inout", "array", + "is", "not", "and", "or", "bus", // Etc... NULL }; for (const char **p = vhdl_reserved; *p != NULL; p++) { From dbbadbc309204c3a7c4875efd356913cb9154ca9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 16:13:02 +0100 Subject: [PATCH 169/377] Make sure the renamed signal is used in the sensitivity list --- tgt-vhdl/scope.cc | 2 +- tgt-vhdl/stmt.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index c87a9773c..fa3c4071a 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -185,7 +185,7 @@ static std::string make_safe_name(ivl_signal_t sig) const char *vhdl_reserved[] = { "in", "out", "entity", "architecture", "inout", "array", - "is", "not", "and", "or", "bus", // Etc... + "is", "not", "and", "or", "bus", "bit", // Etc... NULL }; for (const char **p = vhdl_reserved; *p != NULL; p++) { diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c3bcaa183..d01f4ec75 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -354,13 +354,13 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - const char *signame = ivl_signal_basename(sig); + 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); + proc->add_sensitivity(signame.c_str()); non_edges.push_back(signame); break; } From 6868127ba3689cef5b7614b4f63d7824d4714f63 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 16:14:17 +0100 Subject: [PATCH 170/377] Make sure case expression has the correct type --- tgt-vhdl/stmt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index d01f4ec75..c03f0a11d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -459,7 +459,7 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, vhdl_expr *when; ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { - when = translate_expr(net); + when = translate_expr(net)->cast(test->get_type()); if (NULL == when) return 1; } From a5264e99955cda1199cb0a854e28be0c4e7b0f23 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 16:17:56 +0100 Subject: [PATCH 171/377] Make sure all choices are covered in case statement --- tgt-vhdl/stmt.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c03f0a11d..baf9fa727 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -453,6 +453,11 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test); container->add_stmt(vhdlcase); + + // VHDL is more strict than Verilog about covering every + // possible case. So make sure we add an 'others' branch + // if there isn't a default one. + bool have_others = false; int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { @@ -463,14 +468,23 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, if (NULL == when) return 1; } - else - when = new vhdl_var_ref("others", NULL); + else { + when = new vhdl_var_ref("others", NULL); + have_others = true; + } vhdl_case_branch *branch = new vhdl_case_branch(when); vhdlcase->add_branch(branch); draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); } + + if (!have_others) { + vhdl_case_branch *others = + new vhdl_case_branch(new vhdl_var_ref("others", NULL)); + others->get_container()->add_stmt(new vhdl_null_stmt()); + vhdlcase->add_branch(others); + } return 0; } From 1736cd9bc82ac74d36c3a4893bee9e4b961384e5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 16:27:36 +0100 Subject: [PATCH 172/377] Fix uneccessarily complicated generated case statement No need to generate separate case test variable if the test in the VL source is a simple variable reference. --- tgt-vhdl/stmt.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index baf9fa727..456f36be8 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -439,7 +439,7 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, // VHDL case expressions are required to be quite simple: variable // references or slices. So we may need to create a temporary // variable to hold the result of the expression evaluation - if (typeid(test) != typeid(vhdl_var_ref)) { + if (typeid(*test) != typeid(vhdl_var_ref)) { // TODO: Check if this is already declared const char *tmp_name = "Verilog_Case_Ex"; vhdl_type *test_type = new vhdl_type(*test->get_type()); From 19cbab78b2c82b7d41d6e6a8bfc20305bb02d449 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 3 Jul 2008 20:04:47 +0100 Subject: [PATCH 173/377] Tidy up code to generate default branch of case --- tgt-vhdl/stmt.cc | 23 ++++++++++------------- tgt-vhdl/vhdl_syntax.cc | 5 +++++ tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 456f36be8..2589fc0c3 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -461,30 +461,27 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { - vhdl_expr *when; + stmt_container *container; ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { - when = translate_expr(net)->cast(test->get_type()); + vhdl_expr *when = translate_expr(net)->cast(test->get_type()); if (NULL == when) return 1; + + vhdl_case_branch *branch = new vhdl_case_branch(when); + vhdlcase->add_branch(branch); + container = branch->get_container(); } else { - when = new vhdl_var_ref("others", NULL); + container = vhdlcase->get_others_container(); have_others = true; } - vhdl_case_branch *branch = new vhdl_case_branch(when); - vhdlcase->add_branch(branch); - - draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); + draw_stmt(proc, container, ivl_stmt_case_stmt(stmt, i)); } - if (!have_others) { - vhdl_case_branch *others = - new vhdl_case_branch(new vhdl_var_ref("others", NULL)); - others->get_container()->add_stmt(new vhdl_null_stmt()); - vhdlcase->add_branch(others); - } + if (!have_others) + vhdlcase->get_others_container()->add_stmt(new vhdl_null_stmt()); return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2d4d1e984..036c6e889 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -734,6 +734,11 @@ void vhdl_case_stmt::emit(std::ostream &of, int level) const case_branch_list_t::const_iterator it; for (it = branches_.begin(); it != branches_.end(); ++it) (*it)->emit(of, level); + + if (!others_.empty()) { + of << "when others =>"; + others_.emit(of, indent(level)); + } of << "end case;"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c87eea284..53ee27d94 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -367,9 +367,11 @@ public: void add_branch(vhdl_case_branch *b) { branches_.push_back(b); } void emit(std::ostream &of, int level) const; + stmt_container *get_others_container() { return &others_; } private: vhdl_expr *test_; case_branch_list_t branches_; + stmt_container others_; }; From c54b36c902072d1f2bf7dc825bb3a075ceac9da3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:10:20 +0100 Subject: [PATCH 174/377] Add logical AND operator --- tgt-vhdl/expr.cc | 2 ++ tgt-vhdl/stmt.cc | 23 +++++++++++++---------- tgt-vhdl/vhdl_syntax.cc | 5 ----- tgt-vhdl/vhdl_syntax.hh | 2 -- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 6bd65c2f7..43901518e 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -172,6 +172,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); case '&': // Bitwise AND return translate_numeric(lhs, rhs, VHDL_BINOP_AND); + case 'a': // Logical AND + return translate_relation(lhs, rhs, VHDL_BINOP_AND); case 'o': return translate_relation(lhs, rhs, VHDL_BINOP_OR); case '<': diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 2589fc0c3..456f36be8 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -461,27 +461,30 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, int nbranches = ivl_stmt_case_count(stmt); for (int i = 0; i < nbranches; i++) { - stmt_container *container; + vhdl_expr *when; ivl_expr_t net = ivl_stmt_case_expr(stmt, i); if (net) { - vhdl_expr *when = translate_expr(net)->cast(test->get_type()); + when = translate_expr(net)->cast(test->get_type()); if (NULL == when) return 1; - - vhdl_case_branch *branch = new vhdl_case_branch(when); - vhdlcase->add_branch(branch); - container = branch->get_container(); } else { - container = vhdlcase->get_others_container(); + when = new vhdl_var_ref("others", NULL); have_others = true; } - draw_stmt(proc, container, ivl_stmt_case_stmt(stmt, i)); + vhdl_case_branch *branch = new vhdl_case_branch(when); + vhdlcase->add_branch(branch); + + draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); } - if (!have_others) - vhdlcase->get_others_container()->add_stmt(new vhdl_null_stmt()); + if (!have_others) { + vhdl_case_branch *others = + new vhdl_case_branch(new vhdl_var_ref("others", NULL)); + others->get_container()->add_stmt(new vhdl_null_stmt()); + vhdlcase->add_branch(others); + } return 0; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 036c6e889..2d4d1e984 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -734,11 +734,6 @@ void vhdl_case_stmt::emit(std::ostream &of, int level) const case_branch_list_t::const_iterator it; for (it = branches_.begin(); it != branches_.end(); ++it) (*it)->emit(of, level); - - if (!others_.empty()) { - of << "when others =>"; - others_.emit(of, indent(level)); - } of << "end case;"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 53ee27d94..c87eea284 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -367,11 +367,9 @@ public: void add_branch(vhdl_case_branch *b) { branches_.push_back(b); } void emit(std::ostream &of, int level) const; - stmt_container *get_others_container() { return &others_; } private: vhdl_expr *test_; case_branch_list_t branches_; - stmt_container others_; }; From 409fc4dc19f6eec021b564e61c92c58e78c96480 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:15:34 +0100 Subject: [PATCH 175/377] Check if case expression variable is already defined Verilog_Case_Ex is used as a temporary to store the result of any non-static case expression. This fixes a bug where it would be declared multiple times if there were multiple case statements in a block. --- tgt-vhdl/stmt.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 456f36be8..f60e844bb 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -440,15 +440,18 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, // references or slices. So we may need to create a temporary // variable to hold the result of the expression evaluation if (typeid(*test) != typeid(vhdl_var_ref)) { - // TODO: Check if this is already declared const char *tmp_name = "Verilog_Case_Ex"; vhdl_type *test_type = new vhdl_type(*test->get_type()); - proc->get_scope()->add_decl(new vhdl_var_decl(tmp_name, test_type)); + + if (!proc->get_scope()->have_declared(tmp_name)) { + proc->get_scope()->add_decl + (new vhdl_var_decl(tmp_name, new vhdl_type(*test_type))); + } vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_name, NULL); container->add_stmt(new vhdl_assign_stmt(tmp_ref, test)); - test = new vhdl_var_ref(tmp_name, new vhdl_type(*test_type)); + test = new vhdl_var_ref(tmp_name, test_type); } vhdl_case_stmt *vhdlcase = new vhdl_case_stmt(test); From 88816e150a83d7680f46982ac0924eabfbc58932 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:17:24 +0100 Subject: [PATCH 176/377] Properly parenthesise unary operators --- tgt-vhdl/vhdl_syntax.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2d4d1e984..abf274ec1 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -655,12 +655,14 @@ vhdl_unaryop_expr::~vhdl_unaryop_expr() void vhdl_unaryop_expr::emit(std::ostream &of, int level) const { + of << "("; switch (op_) { case VHDL_UNARYOP_NOT: of << "not "; break; } operand_->emit(of, level); + of << ")"; } vhdl_binop_expr::vhdl_binop_expr(vhdl_expr *left, vhdl_binop_t op, From 96d32b29c9e9542faa1164f1d54a99ceb0c75393 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:23:32 +0100 Subject: [PATCH 177/377] Translate logical expressions correctly. For logical AND/OR in VHDL both operands must be of the same type (Boolean) --- tgt-vhdl/expr.cc | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 43901518e..96e76a6a2 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -103,6 +103,17 @@ static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs, return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean()); } +/* + * Like translate_relation but both operands must be Boolean. + */ +static vhdl_expr *translate_logical(vhdl_expr *lhs, vhdl_expr *rhs, + vhdl_binop_t op) +{ + vhdl_type boolean(VHDL_TYPE_BOOLEAN); + + return translate_relation(lhs->cast(&boolean), rhs->cast(&boolean), op); +} + static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { @@ -173,9 +184,9 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case '&': // Bitwise AND return translate_numeric(lhs, rhs, VHDL_BINOP_AND); case 'a': // Logical AND - return translate_relation(lhs, rhs, VHDL_BINOP_AND); - case 'o': - return translate_relation(lhs, rhs, VHDL_BINOP_OR); + return translate_logical(lhs, rhs, VHDL_BINOP_AND); + case 'o': // Logical OR + return translate_logical(lhs, rhs, VHDL_BINOP_OR); case '<': return translate_relation(lhs, rhs, VHDL_BINOP_LT); case '>': From 1410c339de9e0a6fbb8840a96a09b63e0bcd8d6d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:36:11 +0100 Subject: [PATCH 178/377] Make sure any calls to numeric_std Resize have correct type The signed/unsigned-ness of an expression needs to be preserved over any call to Resize. Also add a sanity check to make sure non-vector types are not resized. --- tgt-vhdl/vhdl_syntax.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index abf274ec1..764898033 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -417,7 +417,15 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) vhdl_expr *vhdl_expr::resize(int newwidth) { - vhdl_type *rtype = vhdl_type::nsigned(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 + assert(false); // 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)); From 19871efd5a1835e0d01f03682525467061214d16 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 11:58:33 +0100 Subject: [PATCH 179/377] Fix bug where sensitivity might reference undefined signals --- tgt-vhdl/stmt.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index f60e844bb..922e2d4b2 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -335,7 +335,10 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, 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 int nevents = ivl_stmt_nevent(stmt); for (int i = 0; i < nevents; i++) { ivl_event_t event = ivl_stmt_events(stmt, i); @@ -354,6 +357,9 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, 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 From 3d0a2b55ce5c0a4372700b0ce32dee25cbf99cb1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 12:03:37 +0100 Subject: [PATCH 180/377] Avoid declaring same function multiple times If it appears in multiple places in the hierarchy --- tgt-vhdl/scope.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index fa3c4071a..0d6b8dd88 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -471,6 +471,13 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) const char *funcname = ivl_scope_tname(scope); + // Has this function been declared already? + // (draw_function will be invoked multiple times for + // the same function if it appears multiple times in + // the design hierarchy) + if (ent->get_arch()->get_scope()->have_declared(funcname)) + return 0; + // The return type is worked out from the output port vhdl_function *func = new vhdl_function(funcname, NULL); From a298b03735cdae16084d22549aa6f50d256897af Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 12:05:49 +0100 Subject: [PATCH 181/377] Add bitwise OR --- tgt-vhdl/expr.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 96e76a6a2..8e07a8296 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -185,6 +185,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_numeric(lhs, rhs, VHDL_BINOP_AND); case 'a': // Logical AND return translate_logical(lhs, rhs, VHDL_BINOP_AND); + case '|': // Bitwise OR + return translate_numeric(lhs, rhs, VHDL_BINOP_OR); case 'o': // Logical OR return translate_logical(lhs, rhs, VHDL_BINOP_OR); case '<': From 5aeff6d47dff364d253e7880ff0b385d42b68805 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 20:07:38 +0100 Subject: [PATCH 182/377] Merge blocking and non-blocking assignment code --- tgt-vhdl/expr.cc | 13 ++++- tgt-vhdl/stmt.cc | 132 ++++++++++++++++++++--------------------------- 2 files changed, 67 insertions(+), 78 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 8e07a8296..07cd703cb 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -208,7 +208,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) } } -vhdl_expr *translate_select(ivl_expr_t e) +static vhdl_expr *translate_select(ivl_expr_t e) { vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); if (NULL == from) @@ -218,7 +218,7 @@ vhdl_expr *translate_select(ivl_expr_t e) return from->resize(ivl_expr_width(e)); } -vhdl_expr *translate_ufunc(ivl_expr_t e) +static vhdl_expr *translate_ufunc(ivl_expr_t e) { ivl_scope_t defscope = ivl_expr_def(e); ivl_scope_t parentscope = ivl_scope_parent(defscope); @@ -252,6 +252,13 @@ vhdl_expr *translate_ufunc(ivl_expr_t e) return fcall; } +static vhdl_expr *translate_ternary(ivl_expr_t e) +{ + error("Ternary expression only supported as RHS of assignment"); + + return NULL; +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -275,6 +282,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_select(e); case IVL_EX_UFUNC: return translate_ufunc(e); + case IVL_EX_TERNARY: + return translate_ternary(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 922e2d4b2..18512bc3b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -102,34 +102,30 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } -/* - * A non-blocking assignment inside a process. The semantics for - * this are essentially the same as VHDL's non-blocking signal - * assignment. - */ -static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *after = NULL) +template +static T *make_assignment(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt, bool blocking) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { error("Can only have 1 lval at the moment (found %d)", nlvals); - return 1; + return NULL; } - assert(proc->get_scope()->allow_signal_assignment()); - ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { - const char *signame = get_renamed_signal(sig).c_str(); + std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); if (NULL == rhs_raw) - return 1; + return NULL; vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); + + bool isvar = strip_var(signame) != signame; // Where possible, move constant assignments into the // declaration as initializers. This optimisation is only @@ -147,63 +143,12 @@ static int draw_nbassign(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->set_initial(rhs); - } - else { - // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame, NULL); - - vhdl_nbassign_stmt *assign = new vhdl_nbassign_stmt(lval_ref, rhs); - if (after != NULL) - assign->set_after(after); - container->add_stmt(assign); - } - } - else { - error("Only signals as lvals supported at the moment"); - return 1; - } - - return 0; -} - -static int draw_assign(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) -{ - int nlvals = ivl_stmt_lvals(stmt); - if (nlvals != 1) { - error("Can only have 1 lval at the moment (found %d)", nlvals); - return 1; - } - - ivl_lval_t lval = ivl_stmt_lval(stmt, 0); - ivl_signal_t sig; - if ((sig = ivl_lval_sig(lval))) { - const std::string signame(get_renamed_signal(sig)); - - vhdl_decl *decl = proc->get_scope()->get_decl(signame); - assert(decl); - - vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); - if (NULL == rhs_raw) - return 1; - vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); - - bool isvar = strip_var(signame) != signame; - - // As with non-blocking assignment, push constant assignments - // into the initialisation if we can (but only if this is - // the first time we assign to this variable). - if (proc->get_scope()->initializing() - && ivl_signal_port(sig) == IVL_SIP_NONE - && rhs->constant() && !decl->has_initial() + && !decl->has_initial() && rhs->constant() && !isvar) { decl->set_initial(rhs); - - if (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); @@ -214,32 +159,67 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, 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); - vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, sig_ref); - container->add_stmt(assign); + return new T(lval_ref, sig_ref); } + else + return NULL; // No statement need be emitted } else { - if (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 - const std::string &renamed = get_renamed_signal(sig); + // The signal may have been renamed by the above call + signame = get_renamed_signal(sig); + } // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(renamed.c_str(), NULL); + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); - vhdl_assign_stmt *assign = new vhdl_assign_stmt(lval_ref, rhs); - container->add_stmt(assign); + return new T(lval_ref, rhs); } } else { error("Only signals as lvals supported at the moment"); - return 1; + return NULL; } +} + +/* + * A non-blocking assignment inside a process. The semantics for + * this are essentially the same as VHDL's non-blocking signal + * assignment. + */ +static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt, vhdl_expr *after = NULL) +{ + assert(proc->get_scope()->allow_signal_assignment()); + + 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(a); + } + + return 0; +} + +static int draw_assign(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt) +{ + vhdl_assign_stmt *a = + make_assignment(proc, container, stmt, true); + + if (a != NULL) { + // Assignment is a statement and not moved into the initialisation + container->add_stmt(a); + } + return 0; } From 18071562ba3fef997eb15856e21d8e4e12f5bd22 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 4 Jul 2008 21:55:51 +0100 Subject: [PATCH 183/377] Partially implement ternary expressions This handles the case where the expression appears as the right hand side of an assignment. The expression is converted into a regular if statement. --- tgt-vhdl/stmt.cc | 172 ++++++++++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 68 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 18512bc3b..183d84bca 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -102,6 +102,89 @@ 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) +{ + std::string signame(get_renamed_signal(sig)); + + vhdl_decl *decl = proc->get_scope()->get_decl(signame); + assert(decl); + + rhs = rhs->cast(decl->get_type()); + + bool isvar = strip_var(signame) != 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. + + // 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(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); + + T *a = new T(lval_ref, sig_ref); + container->add_stmt(a); + + 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 + blocking_assign_to(proc, sig); + + // The signal may have been renamed by the above call + signame = get_renamed_signal(sig); + } + + // The type here can be null as it is never actually needed + vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); + + T *a = new T(lval_ref, rhs); + container->add_stmt(a); + + return a; + } +} + +/* + * Generate an assignment of type T for the Verilog statement stmt. + */ template static T *make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool blocking) @@ -115,70 +198,31 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { - std::string signame(get_renamed_signal(sig)); + ivl_expr_t rval = ivl_stmt_rval(stmt); + 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_decl *decl = proc->get_scope()->get_decl(signame); - assert(decl); + if (!test || !true_part || !false_part) + return NULL; - vhdl_expr *rhs_raw = translate_expr(ivl_stmt_rval(stmt)); - if (NULL == rhs_raw) + vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); + make_vhdl_assignment(proc, vhdif->get_then_container(), sig, + true_part, blocking); + make_vhdl_assignment(proc, vhdif->get_else_container(), sig, + false_part, blocking); + + container->add_stmt(vhdif); return NULL; - vhdl_expr *rhs = rhs_raw->cast(decl->get_type()); - - bool isvar = strip_var(signame) != 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. - - // 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() - && !isvar) { - - decl->set_initial(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); - - return new T(lval_ref, sig_ref); - } - 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 - blocking_assign_to(proc, sig); - // The signal may have been renamed by the above call - signame = get_renamed_signal(sig); - } - - // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); - - return new T(lval_ref, rhs); - } + vhdl_expr *rhs = translate_expr(rval); + if (NULL == rhs) + return NULL; + + return make_vhdl_assignment(proc, container, sig, rhs, blocking); } else { error("Only signals as lvals supported at the moment"); @@ -203,7 +247,6 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, // Assignment is a statement and not moved into the initialisation if (after != NULL) a->set_after(after); - container->add_stmt(a); } return 0; @@ -212,14 +255,7 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, static int draw_assign(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) { - vhdl_assign_stmt *a = - make_assignment(proc, container, stmt, true); - - if (a != NULL) { - // Assignment is a statement and not moved into the initialisation - container->add_stmt(a); - } - + make_assignment(proc, container, stmt, true); return 0; } From 85d2cc78d6c0a11c3d3b036c2d9eb87da3502687 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 6 Jul 2008 17:56:48 +0100 Subject: [PATCH 184/377] Finish ternary operator expansion --- tgt-vhdl/stmt.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 183d84bca..fb6d214fb 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -217,12 +217,13 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, container->add_stmt(vhdif); return NULL; } - - vhdl_expr *rhs = translate_expr(rval); - if (NULL == rhs) - return NULL; - - return make_vhdl_assignment(proc, container, sig, rhs, blocking); + else { + vhdl_expr *rhs = translate_expr(rval); + if (NULL == rhs) + return NULL; + + return make_vhdl_assignment(proc, container, sig, rhs, blocking); + } } else { error("Only signals as lvals supported at the moment"); From c33600bcc38d936b9e2ae857ad90113cd4e6f951 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 6 Jul 2008 18:21:34 +0100 Subject: [PATCH 185/377] Add concatenation operator --- tgt-vhdl/expr.cc | 51 ++++++++++++++++++++++++++++------------- tgt-vhdl/scope.cc | 10 ++++---- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 1 + 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 07cd703cb..447857bf6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -218,6 +218,29 @@ static vhdl_expr *translate_select(ivl_expr_t e) return from->resize(ivl_expr_width(e)); } +static vhdl_type *expr_to_vhdl_type(ivl_expr_t e) +{ + if (ivl_expr_signed(e)) + return vhdl_type::nsigned(ivl_expr_width(e)); + else + return vhdl_type::nunsigned(ivl_expr_width(e)); +} + +template +static T *translate_parms(T *t, ivl_expr_t e) +{ + int nparams = ivl_expr_parms(e); + for (int i = 0; i < nparams; i++) { + vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); + if (NULL == param) + return NULL; + + t->add_expr(param); + } + + return t; +} + static vhdl_expr *translate_ufunc(ivl_expr_t e) { ivl_scope_t defscope = ivl_expr_def(e); @@ -232,24 +255,10 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) const char *funcname = ivl_scope_tname(defscope); - vhdl_type *rettype; - if (ivl_expr_signed(e)) - rettype = vhdl_type::nsigned(ivl_expr_width(e)); - else - rettype = vhdl_type::nunsigned(ivl_expr_width(e)); - + vhdl_type *rettype = expr_to_vhdl_type(e); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); - int nparams = ivl_expr_parms(e); - for (int i = 0; i < nparams; i++) { - vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); - if (NULL == param) - return NULL; - - fcall->add_expr(param); - } - - return fcall; + return translate_parms(fcall, e); } static vhdl_expr *translate_ternary(ivl_expr_t e) @@ -259,6 +268,14 @@ static vhdl_expr *translate_ternary(ivl_expr_t e) return NULL; } +static vhdl_expr *translate_concat(ivl_expr_t e) +{ + vhdl_type *rtype = expr_to_vhdl_type(e); + vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype); + + return translate_parms(concat, e); +} + /* * Generate a VHDL expression from a Verilog expression. */ @@ -284,6 +301,8 @@ vhdl_expr *translate_expr(ivl_expr_t e) return translate_ufunc(e); case IVL_EX_TERNARY: return translate_ternary(e); + case IVL_EX_CONCAT: + return translate_concat(e); default: error("No VHDL translation for expression at %s:%d (type = %d)", ivl_expr_file(e), ivl_expr_lineno(e), type); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 0d6b8dd88..da0375d95 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -185,7 +185,7 @@ static std::string make_safe_name(ivl_signal_t sig) const char *vhdl_reserved[] = { "in", "out", "entity", "architecture", "inout", "array", - "is", "not", "and", "or", "bus", "bit", // Etc... + "is", "not", "and", "or", "bus", "bit", "line", // Etc... NULL }; for (const char **p = vhdl_reserved; *p != NULL; p++) { @@ -354,16 +354,16 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, // result of the expression and that is mapped to the port // This is actually a bit stricter than necessary: but turns out // to be much easier to implement - const char *basename = ivl_signal_basename(to); + std::string name = make_safe_name(to); vhdl_var_ref *to_ref; if ((to_ref = dynamic_cast(to_e))) { - inst->map_port(basename, to_ref); + inst->map_port(name.c_str(), to_ref); } else { // Not a static expression std::string tmpname(inst->get_inst_name().c_str()); tmpname += "_"; - tmpname += basename; + tmpname += name; tmpname += "_Expr"; vhdl_type *tmptype = new vhdl_type(*to_e->get_type()); @@ -374,7 +374,7 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, parent->get_arch()->add_stmt(new vhdl_cassign_stmt(tmp_ref1, to_e)); vhdl_var_ref *tmp_ref2 = new vhdl_var_ref(*tmp_ref1); - inst->map_port(basename, tmp_ref2); + inst->map_port(name.c_str(), tmp_ref2); } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 764898033..d4773fa97 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -705,7 +705,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const while (++it != operands_.end()) { const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", - ">", "sll", "srl", "xor" + ">", "sll", "srl", "xor", "&" }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c87eea284..c45351d18 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -76,6 +76,7 @@ enum vhdl_binop_t { VHDL_BINOP_SL, VHDL_BINOP_SR, VHDL_BINOP_XOR, + VHDL_BINOP_CONCAT, }; /* From ebaa4c7d5db29cc80372868c2dbcf13ec0bdaa50 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 11:00:27 +0100 Subject: [PATCH 186/377] Implement assignment to part select properly Previously the base of the lval was ignored, this ensures the correct assignment is generated. --- tgt-vhdl/expr.cc | 20 ++++++++++++++++---- tgt-vhdl/stmt.cc | 31 ++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 447857bf6..996bbe573 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -212,10 +212,22 @@ static vhdl_expr *translate_select(ivl_expr_t e) { vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); if (NULL == from) - return NULL; - - // Hack: resize it to the correct size - return from->resize(ivl_expr_width(e)); + return NULL; + + ivl_expr_t o2 = ivl_expr_oper2(e); + if (o2) { + vhdl_expr *off = translate_expr(ivl_expr_oper2(e)); + if (NULL == off) + return NULL; + + vhdl_var_ref *ref = dynamic_cast(from); + assert(ref); + + ref->set_slice(off); + return ref; + } + else + return from; } static vhdl_type *expr_to_vhdl_type(ivl_expr_t e) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fb6d214fb..f956a48bf 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -110,14 +110,22 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, */ template static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_signal_t sig, vhdl_expr *rhs, bool blocking) + ivl_signal_t sig, vhdl_expr *rhs, bool blocking, + vhdl_expr *base = NULL) { std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); - rhs = rhs->cast(decl->get_type()); + // TODO: Fix casting when there is a part select + if (base == NULL) + rhs = rhs->cast(decl->get_type()); + + if (base) { + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); + } bool isvar = strip_var(signame) != signame; @@ -154,6 +162,9 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, 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); + T *a = new T(lval_ref, sig_ref); container->add_stmt(a); @@ -174,6 +185,8 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); + if (base) + lval_ref->set_slice(base); T *a = new T(lval_ref, rhs); container->add_stmt(a); @@ -198,6 +211,14 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { + + vhdl_expr *base = NULL; + ivl_expr_t e_off = ivl_lval_part_off(lval); + if (e_off) { + if ((base = translate_expr(e_off)) == NULL) + return NULL; + } + ivl_expr_t rval = ivl_stmt_rval(stmt); if (ivl_expr_type(rval) == IVL_EX_TERNARY) { // Expand ternary expressions into an if statement @@ -210,9 +231,9 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); make_vhdl_assignment(proc, vhdif->get_then_container(), sig, - true_part, blocking); + true_part, blocking, base); make_vhdl_assignment(proc, vhdif->get_else_container(), sig, - false_part, blocking); + false_part, blocking, base); container->add_stmt(vhdif); return NULL; @@ -222,7 +243,7 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, if (NULL == rhs) return NULL; - return make_vhdl_assignment(proc, container, sig, rhs, blocking); + return make_vhdl_assignment(proc, container, sig, rhs, blocking, base); } } else { From bdf5ee7ab732f36435740f8d8de80f5eb87d3ea9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 14:48:57 +0100 Subject: [PATCH 187/377] Concat LPM --- tgt-vhdl/expr.cc | 20 ++++---------------- tgt-vhdl/lpm.cc | 2 ++ tgt-vhdl/stmt.cc | 31 +++++-------------------------- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 996bbe573..447857bf6 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -212,22 +212,10 @@ static vhdl_expr *translate_select(ivl_expr_t e) { vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); if (NULL == from) - return NULL; - - ivl_expr_t o2 = ivl_expr_oper2(e); - if (o2) { - vhdl_expr *off = translate_expr(ivl_expr_oper2(e)); - if (NULL == off) - return NULL; - - vhdl_var_ref *ref = dynamic_cast(from); - assert(ref); - - ref->set_slice(off); - return ref; - } - else - return from; + return NULL; + + // Hack: resize it to the correct size + return from->resize(ivl_expr_width(e)); } static vhdl_type *expr_to_vhdl_type(ivl_expr_t e) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 0d06d9057..5f683757b 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -143,6 +143,8 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_binop_lpm(arch, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); + case IVL_LPM_CONCAT: + return draw_binop_lpm(arch, lpm, VHDL_BINOP_CONCAT); case IVL_LPM_PART_PV: return draw_part_select_pv_lpm(arch, lpm); case IVL_LPM_PART_VP: diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index f956a48bf..fb6d214fb 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -110,22 +110,14 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, */ 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) + ivl_signal_t sig, vhdl_expr *rhs, bool blocking) { std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); - // TODO: Fix casting when there is a part select - if (base == NULL) - rhs = rhs->cast(decl->get_type()); - - if (base) { - vhdl_type integer(VHDL_TYPE_INTEGER); - base = base->cast(&integer); - } + rhs = rhs->cast(decl->get_type()); bool isvar = strip_var(signame) != signame; @@ -162,9 +154,6 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, 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); - T *a = new T(lval_ref, sig_ref); container->add_stmt(a); @@ -185,8 +174,6 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); - if (base) - lval_ref->set_slice(base); T *a = new T(lval_ref, rhs); container->add_stmt(a); @@ -211,14 +198,6 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { - - vhdl_expr *base = NULL; - ivl_expr_t e_off = ivl_lval_part_off(lval); - if (e_off) { - if ((base = translate_expr(e_off)) == NULL) - return NULL; - } - ivl_expr_t rval = ivl_stmt_rval(stmt); if (ivl_expr_type(rval) == IVL_EX_TERNARY) { // Expand ternary expressions into an if statement @@ -231,9 +210,9 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); make_vhdl_assignment(proc, vhdif->get_then_container(), sig, - true_part, blocking, base); + true_part, blocking); make_vhdl_assignment(proc, vhdif->get_else_container(), sig, - false_part, blocking, base); + false_part, blocking); container->add_stmt(vhdif); return NULL; @@ -243,7 +222,7 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, if (NULL == rhs) return NULL; - return make_vhdl_assignment(proc, container, sig, rhs, blocking, base); + return make_vhdl_assignment(proc, container, sig, rhs, blocking); } } else { From dadd145d09e344fabcf79e8d53687784377e7907 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 15:04:28 +0100 Subject: [PATCH 188/377] Add message for unsupported LPM nexus pointer --- tgt-vhdl/scope.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index da0375d95..802e94aa4 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -68,6 +68,7 @@ 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))) { if (!seen_signal_before(sig) || sig == ignore) continue; @@ -84,6 +85,9 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, else if ((log = ivl_nexus_ptr_log(nexus_ptr))) { return translate_logic(arch_scope, log); } + else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { + error("LPM in nexus not implemented yet"); + } else { // Ignore other types of nexus pointer } From 4db5b9d7ed6fa3addde495c97e419e624cb254d0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 15:23:57 +0100 Subject: [PATCH 189/377] Add unary OR/NOR These are currently implemented with reference to an external Reduce_OR function --- tgt-vhdl/expr.cc | 15 +++++++++++++-- tgt-vhdl/scope.cc | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 447857bf6..602dbb187 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -68,12 +68,23 @@ static vhdl_expr *translate_unary(ivl_expr_t e) vhdl_expr *operand = translate_expr(ivl_expr_oper1(e)); if (NULL == operand) return NULL; - - switch (ivl_expr_opcode(e)) { + + char opcode = ivl_expr_opcode(e); + switch (opcode) { case '!': case '~': return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); + case 'N': // NOR + case '|': + { + vhdl_fcall *f = new vhdl_fcall("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()); + else + return f; + } default: error("No translation for unary opcode '%c'\n", ivl_expr_opcode(e)); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 802e94aa4..da356654d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -164,7 +164,7 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) int nlogs = ivl_scope_logs(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 = From 7f955cc07040e5dccdf8a3c7177309c1420a69bd Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 15:36:13 +0100 Subject: [PATCH 190/377] Move the VHDL support package --- tgt-vhdl/verilog_support.vhd | 41 +++++++++++++++++++++++++++++++ tgt-vhdl/vhpi/verilog_support.vhd | 15 ----------- 2 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 tgt-vhdl/verilog_support.vhd delete mode 100644 tgt-vhdl/vhpi/verilog_support.vhd diff --git a/tgt-vhdl/verilog_support.vhd b/tgt-vhdl/verilog_support.vhd new file mode 100644 index 000000000..253d9c21a --- /dev/null +++ b/tgt-vhdl/verilog_support.vhd @@ -0,0 +1,41 @@ +-- +-- Support routines for Icarus Verilog VHDL output +-- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package Verilog_Support is + + -- This routine implements $finish by terminating the simulation + -- It is implemented via the VHPI interface + procedure finish; + attribute foreign of finish : procedure is "VHPIDIRECT finish"; + + -- Routines to implement Verilog reduction operators + function Reduce_OR(X : unsigned) return std_logic; + + +end Verilog_Support; + +package body Verilog_Support is + + -- This is a dummy body to provide a default implementation + -- if VHPI is not supported + procedure finish is + begin + assert false severity failure; + end finish; + + function Reduce_OR(X : unsigned) return std_logic is + begin + for I in X'range loop + if X(I) /= '1' then + return '0'; + end if; + end loop; + return '1'; + end function; + +end Verilog_Support; diff --git a/tgt-vhdl/vhpi/verilog_support.vhd b/tgt-vhdl/vhpi/verilog_support.vhd deleted file mode 100644 index eb77c4c06..000000000 --- a/tgt-vhdl/vhpi/verilog_support.vhd +++ /dev/null @@ -1,15 +0,0 @@ --- --- VHPI support routines for VHDL output. --- - -package Verilog_Support is - procedure finish; - attribute foreign of finish : procedure is "VHPIDIRECT finish"; -end Verilog_Support; - -package body Verilog_Support is - procedure finish is - begin - assert false severity failure; - end finish; -end Verilog_Support; From 89cdbf63be22363dfadeb49518f7080ac85f8b78 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 15:45:20 +0100 Subject: [PATCH 191/377] Reduction LPM types --- tgt-vhdl/lpm.cc | 37 ++++++++++++++++++++++++++++++++++++ tgt-vhdl/verilog_support.vhd | 6 +++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 5f683757b..12288e725 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -134,6 +134,31 @@ static int draw_ufunc_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return 0; } +static int draw_reduction_lpm(vhdl_arch *arch, ivl_lpm_t lpm, const char *rfunc, + bool invert) +{ + vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic()); + + vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); + if (NULL == ref) + return 1; + + fcall->add_expr(ref); + + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); + if (NULL == out) + return 1; + + if (invert) + arch->add_stmt + (new vhdl_cassign_stmt + (out, new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic()))); + else + arch->add_stmt(new vhdl_cassign_stmt(out, fcall)); + + return 0; +} + int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -151,6 +176,18 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_part_select_vp_lpm(arch, lpm); case IVL_LPM_UFUNC: return draw_ufunc_lpm(arch, lpm); + case IVL_LPM_RE_AND: + return draw_reduction_lpm(arch, lpm, "Reduce_AND", false); + case IVL_LPM_RE_NAND: + return draw_reduction_lpm(arch, lpm, "Reduce_AND", true); + case IVL_LPM_RE_NOR: + return draw_reduction_lpm(arch, lpm, "Reduce_OR", true); + case IVL_LPM_RE_OR: + return draw_reduction_lpm(arch, lpm, "Reduce_OR", false); + case IVL_LPM_RE_XOR: + return draw_reduction_lpm(arch, lpm, "Reduce_XOR", false); + case IVL_LPM_RE_XNOR: + return draw_reduction_lpm(arch, lpm, "Reduce_XNOR", false); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return 1; diff --git a/tgt-vhdl/verilog_support.vhd b/tgt-vhdl/verilog_support.vhd index 253d9c21a..b1c4f7e32 100644 --- a/tgt-vhdl/verilog_support.vhd +++ b/tgt-vhdl/verilog_support.vhd @@ -31,11 +31,11 @@ package body Verilog_Support is function Reduce_OR(X : unsigned) return std_logic is begin for I in X'range loop - if X(I) /= '1' then - return '0'; + if X(I) = '1' then + return '1'; end if; end loop; - return '1'; + return '0'; end function; end Verilog_Support; From 37fe6e4219c8311028a4f7654586efc7ffb0f7dd Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 15:49:51 +0100 Subject: [PATCH 192/377] Dummy implementation of IVL_LO_BUF* --- tgt-vhdl/scope.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index da356654d..c9f992f08 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -148,6 +148,9 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) return inputs_to_expr(scope, VHDL_BINOP_OR, log); case IVL_LO_XOR: return inputs_to_expr(scope, VHDL_BINOP_XOR, log); + case IVL_LO_BUF: + case IVL_LO_BUFZ: + return nexus_to_expr(scope, ivl_logic_pin(log, 1)); default: error("Don't know how to translate logic type = %d", ivl_logic_type(log)); From b0de1a8d7eddb12f9563170d4fe581ecf1cb0ee6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 16:11:45 +0100 Subject: [PATCH 193/377] Implement part select for LHS of assignment --- tgt-vhdl/stmt.cc | 33 ++++++++++++++++++++++++++++----- tgt-vhdl/vhdl_syntax.cc | 4 ++++ tgt-vhdl/vhdl_syntax.hh | 3 ++- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fb6d214fb..b7f9ad68d 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -110,14 +110,22 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, */ template static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_signal_t sig, vhdl_expr *rhs, bool blocking) + ivl_signal_t sig, vhdl_expr *rhs, bool blocking, + vhdl_expr *base = NULL, unsigned lval_width = 0) { std::string signame(get_renamed_signal(sig)); vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); - rhs = rhs->cast(decl->get_type()); + // TODO: Fix casting when there is a part select + if (base == NULL) + rhs = rhs->cast(decl->get_type()); + + if (base) { + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); + } bool isvar = strip_var(signame) != signame; @@ -154,6 +162,9 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, 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); @@ -174,6 +185,8 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, // The type here can be null as it is never actually needed vhdl_var_ref *lval_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, rhs); container->add_stmt(a); @@ -198,6 +211,16 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t sig; if ((sig = ivl_lval_sig(lval))) { + + vhdl_expr *base = NULL; + ivl_expr_t e_off = ivl_lval_part_off(lval); + if (e_off) { + if ((base = translate_expr(e_off)) == NULL) + return NULL; + } + + unsigned lval_width = ivl_lval_width(lval); + ivl_expr_t rval = ivl_stmt_rval(stmt); if (ivl_expr_type(rval) == IVL_EX_TERNARY) { // Expand ternary expressions into an if statement @@ -210,9 +233,9 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); make_vhdl_assignment(proc, vhdif->get_then_container(), sig, - true_part, blocking); + true_part, blocking, base, lval_width); make_vhdl_assignment(proc, vhdif->get_else_container(), sig, - false_part, blocking); + false_part, blocking, base, lval_width); container->add_stmt(vhdif); return NULL; @@ -222,7 +245,7 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, if (NULL == rhs) return NULL; - return make_vhdl_assignment(proc, container, sig, rhs, blocking); + return make_vhdl_assignment(proc, container, sig, rhs, blocking, base, lval_width); } } else { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d4773fa97..aa5d18eb7 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -477,6 +477,10 @@ void vhdl_var_ref::emit(std::ostream &of, int level) const of << name_; if (slice_) { of << "("; + if (slice_width_ > 0) { + slice_->emit(of, level); + of << " + " << slice_width_ << " downto "; + } slice_->emit(of, level); of << ")"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c45351d18..0e3968327 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -56,10 +56,11 @@ public: void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } - void set_slice(vhdl_expr *s) { slice_ = s; } + void set_slice(vhdl_expr *s, int w=0) { slice_ = s; slice_width_ = w; } private: std::string name_; vhdl_expr *slice_; + unsigned slice_width_; }; From 6b73cc39a54526a471b97c4b0fcc62a679fdaf5c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 16:17:54 +0100 Subject: [PATCH 194/377] Add Active_High support func and fix LPM part select --- tgt-vhdl/lpm.cc | 4 ++-- tgt-vhdl/verilog_support.vhd | 15 +++++++++++++-- tgt-vhdl/vhdl_syntax.cc | 10 ++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 12288e725..d0e20217d 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -89,7 +89,7 @@ static int draw_part_select_vp_lpm(vhdl_arch *arch, ivl_lpm_t lpm) if (NULL == out) return 1; - selfrom->set_slice(off); + selfrom->set_slice(off, ivl_lpm_width(lpm) - 1); arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); return 0; } @@ -108,7 +108,7 @@ static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) if (NULL == out) return 1; - out->set_slice(off); + out->set_slice(off, ivl_lpm_width(lpm) - 1); arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); return 0; } diff --git a/tgt-vhdl/verilog_support.vhd b/tgt-vhdl/verilog_support.vhd index b1c4f7e32..34ec5df20 100644 --- a/tgt-vhdl/verilog_support.vhd +++ b/tgt-vhdl/verilog_support.vhd @@ -15,7 +15,9 @@ package Verilog_Support is -- Routines to implement Verilog reduction operators function Reduce_OR(X : unsigned) return std_logic; - + + -- Convert Boolean to std_logic + function Active_High(B : Boolean) return std_logic; end Verilog_Support; @@ -36,6 +38,15 @@ package body Verilog_Support is end if; end loop; return '0'; - end function; + end function; + + function Active_High(B : Boolean) return std_logic is + begin + if B then + return '1'; + else + return '0'; + end if; + end function; end Verilog_Support; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index aa5d18eb7..df07bff65 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -400,6 +400,16 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) 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 From 3987e0753d588f45686188b5a9d40ce263c45830 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 16:31:27 +0100 Subject: [PATCH 195/377] Fix case where booleans are compared against vectors --- tgt-vhdl/expr.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 602dbb187..7a5752420 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -100,6 +100,14 @@ static vhdl_expr *translate_unary(ivl_expr_t e) static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, vhdl_binop_t op) { + // May need to make either side Boolean for operators + // to work + vhdl_type boolean(VHDL_TYPE_BOOLEAN); + if (lhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN) + rhs = rhs->cast(&boolean); + else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN) + lhs = lhs->cast(&boolean); + vhdl_type *rtype = new vhdl_type(*lhs->get_type()); return new vhdl_binop_expr(lhs, op, rhs, rtype); } @@ -145,7 +153,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e)); if (NULL == rhs) return NULL; - + int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); From 03486645126bf8b28745551fb78f1267e49459a6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 16:35:39 +0100 Subject: [PATCH 196/377] Correctly determine VHDL type of LHS of part select --- tgt-vhdl/stmt.cc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index b7f9ad68d..559fa0ac8 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -118,13 +118,25 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, vhdl_decl *decl = proc->get_scope()->get_decl(signame); assert(decl); - // TODO: Fix casting when there is a part select if (base == NULL) rhs = rhs->cast(decl->get_type()); - - if (base) { + 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(); + assert(tname == VHDL_TYPE_SIGNED || tname == VHDL_TYPE_UNSIGNED); + + if (lval_width == 1) { + vhdl_type t(VHDL_TYPE_STD_LOGIC); + rhs = rhs->cast(&t); + } + else { + vhdl_type t(tname, lval_width); + rhs = rhs->cast(&t); + } } bool isvar = strip_var(signame) != signame; From 47db80315c1d627f21e3a637930ea791a35803a2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 19:27:52 +0100 Subject: [PATCH 197/377] Add sign extension LPM --- tgt-vhdl/expr.cc | 2 ++ tgt-vhdl/lpm.cc | 19 +++++++++++++++++++ tgt-vhdl/scope.cc | 8 +++++++- tgt-vhdl/vhdl.cc | 2 ++ 4 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 7a5752420..2685bbfb9 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -184,6 +184,8 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); case '-': return translate_numeric(lhs, rhs, VHDL_BINOP_SUB); + case '*': + return translate_numeric(lhs, rhs, VHDL_BINOP_MULT); case 'e': return translate_relation(lhs, rhs, VHDL_BINOP_EQ); case 'E': diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index d0e20217d..a9ae1b4cc 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -159,6 +159,23 @@ static int draw_reduction_lpm(vhdl_arch *arch, ivl_lpm_t lpm, const char *rfunc, return 0; } +static int draw_sign_extend_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +{ + vhdl_expr *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); + if (NULL == ref) + return 1; + + ref = ref->resize(ivl_lpm_width(lpm)); + + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); + if (NULL == out) + return 1; + + arch->add_stmt(new vhdl_cassign_stmt(out, ref)); + + return 0; +} + int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -188,6 +205,8 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return draw_reduction_lpm(arch, lpm, "Reduce_XOR", false); case IVL_LPM_RE_XNOR: return draw_reduction_lpm(arch, lpm, "Reduce_XNOR", false); + case IVL_LPM_SIGN_EXT: + return draw_sign_extend_lpm(arch, lpm); 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 c9f992f08..66c4040c4 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -26,6 +26,7 @@ #include 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 @@ -62,6 +63,8 @@ static vhdl_expr *nexus_to_const(ivl_nexus_t nexus) static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_signal_t ignore = NULL) { + std::cout << "nexus_to_expr " << ivl_nexus_name(nexus) << std::endl; + int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); @@ -86,7 +89,10 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, return translate_logic(arch_scope, log); } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - error("LPM in nexus not implemented yet"); + std::string basename("VL_"); + basename += ivl_lpm_basename(lpm); + + return new vhdl_var_ref(basename.c_str(), vhdl_type::std_logic()); } else { // Ignore other types of nexus pointer diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index c3a22bedd..4ef96119a 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -101,6 +101,8 @@ bool seen_signal_before(ivl_signal_t sig) void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) { assert(!seen_signal_before(sig)); + + std::cout << "remember_signal " << ivl_signal_name(sig) << std::endl; signal_defn_t defn = { ivl_signal_basename(sig), scope }; g_known_signals[sig] = defn; From 2bb645e0bcf254b19176281db972cdf469171c7a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 19:46:18 +0100 Subject: [PATCH 198/377] Refactor LPM code to allow lpm->expr function --- tgt-vhdl/lpm.cc | 172 ++++++++++++++++++++++-------------------------- 1 file changed, 80 insertions(+), 92 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index a9ae1b4cc..98396f609 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -23,19 +23,19 @@ #include #include -static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) +static vhdl_expr *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { - vhdl_expr *lhs = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); + vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == lhs) - return 1; + return NULL; - vhdl_expr *rhs = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 1)); + vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1)); if (NULL == rhs) - return 1; + return NULL; - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); + vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); if (NULL == out) - return 1; + return NULL; vhdl_type *result_type = new vhdl_type(*lhs->get_type()); vhdl_expr *expr = new vhdl_binop_expr(lhs, op, rhs, result_type); @@ -53,20 +53,18 @@ static int draw_binop_lpm(vhdl_arch *arch, ivl_lpm_t lpm, vhdl_binop_t op) expr = resize; } - arch->add_stmt(new vhdl_cassign_stmt(out, expr)); - - return 0; + return expr; } /* * Return the base of a part select. */ -static vhdl_expr *part_select_base(vhdl_arch *arch, ivl_lpm_t lpm) +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(arch->get_scope(), base); + off = nexus_to_var_ref(scope, base); else off = new vhdl_const_int(ivl_lpm_base(lpm)); @@ -75,23 +73,18 @@ static vhdl_expr *part_select_base(vhdl_arch *arch, ivl_lpm_t lpm) return off->cast(&integer); } -static int draw_part_select_vp_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm) { - vhdl_var_ref *selfrom = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); + vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) - return 1; + return NULL; - vhdl_expr *off = part_select_base(arch, lpm);; + vhdl_expr *off = part_select_base(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; + return NULL; selfrom->set_slice(off, ivl_lpm_width(lpm) - 1); - arch->add_stmt(new vhdl_cassign_stmt(out, selfrom)); - return 0; + return selfrom; } static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) @@ -100,7 +93,7 @@ static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) if (NULL == selfrom) return 1; - vhdl_expr *off = part_select_base(arch, lpm);; + vhdl_expr *off = part_select_base(arch->get_scope(), lpm);; if (NULL == off) return 1; @@ -113,103 +106,98 @@ static int draw_part_select_pv_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return 0; } -static int draw_ufunc_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +static vhdl_expr *draw_ufunc_lpm(vhdl_scope *scope, ivl_lpm_t lpm) { vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL); for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) { - vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, i)); + vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i)); if (NULL == ref) - return 1; + return NULL; fcall->add_expr(ref); } - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (NULL == out) - return 1; - - arch->add_stmt(new vhdl_cassign_stmt(out, fcall)); - - return 0; + return fcall; } -static int draw_reduction_lpm(vhdl_arch *arch, ivl_lpm_t lpm, const char *rfunc, - bool invert) +static vhdl_expr *draw_reduction_lpm(vhdl_scope *scope, ivl_lpm_t lpm, + const char *rfunc, bool invert) { vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic()); - vhdl_var_ref *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); + vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == ref) - return 1; + return NULL; fcall->add_expr(ref); - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (NULL == out) - return 1; - if (invert) - arch->add_stmt - (new vhdl_cassign_stmt - (out, new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic()))); + return new vhdl_unaryop_expr + (VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic()); else - arch->add_stmt(new vhdl_cassign_stmt(out, fcall)); - - return 0; + return fcall; } -static int draw_sign_extend_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm) { - vhdl_expr *ref = nexus_to_var_ref(arch->get_scope(), ivl_lpm_data(lpm, 0)); - if (NULL == ref) - return 1; + vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); + if (ref) + return ref->resize(ivl_lpm_width(lpm)); + else + return NULL; +} - ref = ref->resize(ivl_lpm_width(lpm)); - - vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (NULL == out) - return 1; - - arch->add_stmt(new vhdl_cassign_stmt(out, ref)); - - return 0; +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); + case IVL_LPM_SUB: + return draw_binop_lpm(scope, lpm, VHDL_BINOP_SUB); + case IVL_LPM_MULT: + return draw_binop_lpm(scope, lpm, VHDL_BINOP_MULT); + case IVL_LPM_CONCAT: + return draw_binop_lpm(scope, lpm, VHDL_BINOP_CONCAT); + case IVL_LPM_PART_VP: + return draw_part_select_vp_lpm(scope, lpm); + case IVL_LPM_UFUNC: + return draw_ufunc_lpm(scope, lpm); + case IVL_LPM_RE_AND: + return draw_reduction_lpm(scope, lpm, "Reduce_AND", false); + case IVL_LPM_RE_NAND: + return draw_reduction_lpm(scope, lpm, "Reduce_AND", true); + case IVL_LPM_RE_NOR: + return draw_reduction_lpm(scope, lpm, "Reduce_OR", true); + case IVL_LPM_RE_OR: + return draw_reduction_lpm(scope, lpm, "Reduce_OR", false); + case IVL_LPM_RE_XOR: + return draw_reduction_lpm(scope, lpm, "Reduce_XOR", false); + case IVL_LPM_RE_XNOR: + return draw_reduction_lpm(scope, lpm, "Reduce_XNOR", false); + case IVL_LPM_SIGN_EXT: + return draw_sign_extend_lpm(scope, lpm); + default: + error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); + return NULL; + } } 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); - case IVL_LPM_SUB: - return draw_binop_lpm(arch, lpm, VHDL_BINOP_SUB); - case IVL_LPM_MULT: - return draw_binop_lpm(arch, lpm, VHDL_BINOP_MULT); - case IVL_LPM_CONCAT: - return draw_binop_lpm(arch, lpm, VHDL_BINOP_CONCAT); - case IVL_LPM_PART_PV: + if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) return draw_part_select_pv_lpm(arch, lpm); - case IVL_LPM_PART_VP: - return draw_part_select_vp_lpm(arch, lpm); - case IVL_LPM_UFUNC: - return draw_ufunc_lpm(arch, lpm); - case IVL_LPM_RE_AND: - return draw_reduction_lpm(arch, lpm, "Reduce_AND", false); - case IVL_LPM_RE_NAND: - return draw_reduction_lpm(arch, lpm, "Reduce_AND", true); - case IVL_LPM_RE_NOR: - return draw_reduction_lpm(arch, lpm, "Reduce_OR", true); - case IVL_LPM_RE_OR: - return draw_reduction_lpm(arch, lpm, "Reduce_OR", false); - case IVL_LPM_RE_XOR: - return draw_reduction_lpm(arch, lpm, "Reduce_XOR", false); - case IVL_LPM_RE_XNOR: - return draw_reduction_lpm(arch, lpm, "Reduce_XNOR", false); - case IVL_LPM_SIGN_EXT: - return draw_sign_extend_lpm(arch, lpm); - default: - error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); - return 1; + 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 (NULL == out) + return 1; + + arch->add_stmt(new vhdl_cassign_stmt(out, f)); + return 0; } } From 860a74ddd870863144a85370e6c35b7d5a22f29a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 20:41:29 +0100 Subject: [PATCH 199/377] Allow LPMs in port maps --- tgt-vhdl/lpm.cc | 13 ++++++------- tgt-vhdl/scope.cc | 37 +++++++++++++++++++++++++++++-------- tgt-vhdl/vhdl_target.h | 1 + 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 98396f609..48af05b0b 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -33,10 +33,6 @@ static vhdl_expr *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t if (NULL == rhs) return NULL; - vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); - if (NULL == out) - return NULL; - vhdl_type *result_type = new vhdl_type(*lhs->get_type()); vhdl_expr *expr = new vhdl_binop_expr(lhs, op, rhs, result_type); @@ -75,6 +71,8 @@ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm) { + std::cout << "Part select vp" << std::endl; + vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) return NULL; @@ -150,6 +148,8 @@ static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm) vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { + std::cout << "LPM type " << ivl_lpm_type(lpm) << std::endl; + switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: return draw_binop_lpm(scope, lpm, VHDL_BINOP_ADD); @@ -193,10 +193,9 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) return 1; vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); - if (NULL == out) - return 1; + if (out) + arch->add_stmt(new vhdl_cassign_stmt(out, f)); - arch->add_stmt(new vhdl_cassign_stmt(out, f)); return 0; } } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 66c4040c4..ca2e3f5bf 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -89,10 +89,10 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, return translate_logic(arch_scope, log); } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - std::string basename("VL_"); - basename += ivl_lpm_basename(lpm); - - return new vhdl_var_ref(basename.c_str(), vhdl_type::std_logic()); + std::cout << "LPM to expr" << std::endl; + vhdl_expr *e = lpm_to_expr(arch_scope, lpm); + if (e) + return e; } else { // Ignore other types of nexus pointer @@ -104,10 +104,30 @@ 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_expr *e = nexus_to_expr(arch_scope, nexus); - vhdl_var_ref *ref = dynamic_cast(e); - assert(ref); - return ref; + 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 { + // Ignore other types of nexus pointer + } + } + + return NULL; } /* @@ -359,6 +379,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, to); + assert(to_e); // The expressions in a VHDL port map must be 'globally static' // i.e. they can't be arbitrary expressions diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 1d91a77e9..c70870ca2 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -17,6 +17,7 @@ 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); void remember_entity(vhdl_entity *ent); From 4777966b4c2b314174453e2afb21113a978f6ce4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 21:19:59 +0100 Subject: [PATCH 200/377] Bit select bug fixes --- tgt-vhdl/expr.cc | 25 ++++++++++++++++++++----- tgt-vhdl/stmt.cc | 7 ++++--- tgt-vhdl/vhdl.cc | 2 -- tgt-vhdl/vhdl_syntax.cc | 21 ++++++++++++++++++++- tgt-vhdl/vhdl_syntax.hh | 6 ++++-- 5 files changed, 48 insertions(+), 13 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 2685bbfb9..4910310d0 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -212,8 +212,12 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return translate_logical(lhs, rhs, VHDL_BINOP_OR); case '<': return translate_relation(lhs, rhs, VHDL_BINOP_LT); + case 'L': + return translate_relation(lhs, rhs, VHDL_BINOP_LEQ); case '>': return translate_relation(lhs, rhs, VHDL_BINOP_GT); + case 'G': + return translate_relation(lhs, rhs, VHDL_BINOP_GEQ); case 'l': return translate_shift(lhs, rhs, VHDL_BINOP_SL); case 'r': @@ -231,12 +235,23 @@ static vhdl_expr *translate_binary(ivl_expr_t e) static vhdl_expr *translate_select(ivl_expr_t e) { - vhdl_expr *from = translate_expr(ivl_expr_oper1(e)); + vhdl_var_ref *from = + dynamic_cast(translate_expr(ivl_expr_oper1(e))); if (NULL == from) - return NULL; - - // Hack: resize it to the correct size - return from->resize(ivl_expr_width(e)); + return NULL; + + ivl_expr_t o2 = ivl_expr_oper2(e); + if (o2) { + vhdl_expr *base = translate_expr(ivl_expr_oper2(e)); + if (NULL == base) + return NULL; + + vhdl_type integer(VHDL_TYPE_INTEGER); + from->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); + return from; + } + else + return from->resize(ivl_expr_width(e)); } static vhdl_type *expr_to_vhdl_type(ivl_expr_t e) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 559fa0ac8..302833b75 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -194,9 +194,10 @@ static T *make_vhdl_assignment(vhdl_procedural *proc, stmt_container *container, // The signal may have been renamed by the above call signame = get_renamed_signal(sig); } - - // The type here can be null as it is never actually needed - vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), NULL); + + 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); diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 4ef96119a..c8563c488 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -102,8 +102,6 @@ void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) { assert(!seen_signal_before(sig)); - std::cout << "remember_signal " << ivl_signal_name(sig) << std::endl; - signal_defn_t defn = { ivl_signal_basename(sig), scope }; g_known_signals[sig] = defn; } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index df07bff65..a937135d0 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -482,6 +482,25 @@ vhdl_var_ref::~vhdl_var_ref() delete slice_; } +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; + + 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_; @@ -719,7 +738,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const while (++it != operands_.end()) { const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", - ">", "sll", "srl", "xor", "&" + ">", "<=", ">=", "sll", "srl", "xor", "&" }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 0e3968327..89b26d217 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -38,7 +38,7 @@ public: bool constant() const { return isconst_; } virtual vhdl_expr *cast(const vhdl_type *to); virtual vhdl_expr *resize(int newwidth); -private: +protected: vhdl_type *type_; bool isconst_; }; @@ -56,7 +56,7 @@ public: void emit(std::ostream &of, int level) const; const std::string &get_name() const { return name_; } - void set_slice(vhdl_expr *s, int w=0) { slice_ = s; slice_width_ = w; } + void set_slice(vhdl_expr *s, int w=0); private: std::string name_; vhdl_expr *slice_; @@ -74,6 +74,8 @@ enum vhdl_binop_t { VHDL_BINOP_MULT, VHDL_BINOP_LT, VHDL_BINOP_GT, + VHDL_BINOP_LEQ, + VHDL_BINOP_GEQ, VHDL_BINOP_SL, VHDL_BINOP_SR, VHDL_BINOP_XOR, From a0dbb1aa5dfa5b73116b245441c580f75460918a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 7 Jul 2008 21:45:27 +0100 Subject: [PATCH 201/377] Fix more bugs in part selects --- tgt-vhdl/lpm.cc | 47 ++++++++++++++++++++++++++++++------------- tgt-vhdl/vhdl_type.cc | 10 +++++++++ tgt-vhdl/vhdl_type.hh | 2 ++ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 48af05b0b..239f9d7be 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -23,19 +23,38 @@ #include #include +static vhdl_expr *draw_concat_lpm(vhdl_scope *scope, ivl_lpm_t lpm) +{ + vhdl_type *result_type = + vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); + vhdl_binop_expr *expr = + new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type); + + for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; 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 *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op) { - vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); - if (NULL == lhs) - return NULL; - - vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1)); - if (NULL == rhs) - return NULL; - - vhdl_type *result_type = new vhdl_type(*lhs->get_type()); - vhdl_expr *expr = new vhdl_binop_expr(lhs, op, rhs, result_type); + vhdl_type *result_type = + vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0); + vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type); + + 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); + } + if (op == VHDL_BINOP_MULT) { // Need to resize the output to the desired size, // as this does not happen automatically in VHDL @@ -46,10 +65,10 @@ static vhdl_expr *draw_binop_lpm(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t resize->add_expr(expr); resize->add_expr(new vhdl_const_int(out_width)); - expr = resize; + return resize; } - - return expr; + else + return expr; } /* @@ -158,7 +177,7 @@ vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) case IVL_LPM_MULT: return draw_binop_lpm(scope, lpm, VHDL_BINOP_MULT); case IVL_LPM_CONCAT: - return draw_binop_lpm(scope, lpm, VHDL_BINOP_CONCAT); + return draw_concat_lpm(scope, lpm); case IVL_LPM_PART_VP: return draw_part_select_vp_lpm(scope, lpm); case IVL_LPM_UFUNC: diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 77b3a7b0f..18db0dc28 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -121,3 +121,13 @@ vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) { return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); } + +vhdl_type *vhdl_type::type_for(int width, bool issigned) +{ + if (width == 0) + return vhdl_type::std_logic(); + else if (issigned) + return vhdl_type::nsigned(width); + else + return vhdl_type::nunsigned(width); +} diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index b0e0c6f3b..0c52814d6 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -65,6 +65,8 @@ public: static vhdl_type *integer(); static vhdl_type *boolean(); static vhdl_type *time(); + + static vhdl_type *type_for(int width, bool issigned); protected: vhdl_type_name_t name_; int msb_, lsb_; From bd5cc96956d92aa0835b705750157c2febe1f0fc Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 8 Jul 2008 00:20:31 +0100 Subject: [PATCH 202/377] Correct vector sizes for bit select --- tgt-vhdl/expr.cc | 25 +++++++++++++------------ tgt-vhdl/lpm.cc | 4 ---- tgt-vhdl/scope.cc | 6 ++---- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_type.cc | 16 ++++++++-------- tgt-vhdl/vhdl_type.hh | 6 +++--- 6 files changed, 27 insertions(+), 32 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 4910310d0..344a717be 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -157,28 +157,29 @@ static vhdl_expr *translate_binary(ivl_expr_t e) int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); + std::cout << "opwidth = " << ivl_expr_width(e) + << " lwidth = " << lwidth + << " rwidth = " << rwidth << std::endl; + // May need to resize the left or right hand side - int opwidth; - if (lwidth < rwidth) { - rhs = rhs->cast(lhs->get_type()); - opwidth = lwidth; + /*if (lwidth < rwidth) { + lhs = lhs->cast(rhs->get_type()); } else if (rwidth < lwidth) { - lhs = lhs->cast(rhs->get_type()); - opwidth = rwidth; - } - else - opwidth = lwidth; + rhs = rhs->cast(lhs->get_type()); + }*/ + int result_width = ivl_expr_width(e); + // For === and !== we need to compare std_logic_vectors // rather than signeds - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, opwidth-1, 0); + vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0); bool vectorop = (lhs->get_type()->get_name() == VHDL_TYPE_SIGNED || lhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED) && (rhs->get_type()->get_name() == VHDL_TYPE_SIGNED || rhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED); - + switch (ivl_expr_opcode(e)) { case '+': return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); @@ -244,7 +245,7 @@ static vhdl_expr *translate_select(ivl_expr_t e) if (o2) { vhdl_expr *base = translate_expr(ivl_expr_oper2(e)); if (NULL == base) - return NULL; + return NULL; vhdl_type integer(VHDL_TYPE_INTEGER); from->set_slice(base->cast(&integer), ivl_expr_width(e) - 1); diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 239f9d7be..b6e6ae874 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -90,8 +90,6 @@ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) static vhdl_expr *draw_part_select_vp_lpm(vhdl_scope *scope, ivl_lpm_t lpm) { - std::cout << "Part select vp" << std::endl; - vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); if (NULL == selfrom) return NULL; @@ -167,8 +165,6 @@ static vhdl_expr *draw_sign_extend_lpm(vhdl_scope *scope, ivl_lpm_t lpm) vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { - std::cout << "LPM type " << ivl_lpm_type(lpm) << std::endl; - switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: return draw_binop_lpm(scope, lpm, VHDL_BINOP_ADD); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index ca2e3f5bf..a798efbd9 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -63,8 +63,6 @@ static vhdl_expr *nexus_to_const(ivl_nexus_t nexus) static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, ivl_signal_t ignore = NULL) { - std::cout << "nexus_to_expr " << ivl_nexus_name(nexus) << std::endl; - int nptrs = ivl_nexus_ptrs(nexus); for (int i = 0; i < nptrs; i++) { ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); @@ -89,7 +87,6 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus, return translate_logic(arch_scope, log); } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - std::cout << "LPM to expr" << std::endl; vhdl_expr *e = lpm_to_expr(arch_scope, lpm); if (e) return e; @@ -254,7 +251,8 @@ 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()); - vhdl_type *sig_type = get_signal_type(sig); + vhdl_type *sig_type = + vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); std::string name = make_safe_name(sig); rename_signal(sig, name); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a937135d0..d509ebc00 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -434,7 +434,7 @@ vhdl_expr *vhdl_expr::resize(int newwidth) else if (type_->get_name() == VHDL_TYPE_UNSIGNED) rtype = vhdl_type::nunsigned(newwidth); else - assert(false); // Doesn't make sense to resize non-vector type + return this; // Doesn't make sense to resize non-vector type vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); resize->add_expr(this); diff --git a/tgt-vhdl/vhdl_type.cc b/tgt-vhdl/vhdl_type.cc index 18db0dc28..b431b02f1 100644 --- a/tgt-vhdl/vhdl_type.cc +++ b/tgt-vhdl/vhdl_type.cc @@ -48,14 +48,14 @@ vhdl_type *vhdl_type::integer() return new vhdl_type(VHDL_TYPE_INTEGER); } -vhdl_type *vhdl_type::nunsigned(int width) +vhdl_type *vhdl_type::nunsigned(int width, int lsb) { - return new vhdl_type(VHDL_TYPE_UNSIGNED, width-1, 0); + return new vhdl_type(VHDL_TYPE_UNSIGNED, width-1+lsb, lsb); } -vhdl_type *vhdl_type::nsigned(int width) +vhdl_type *vhdl_type::nsigned(int width, int lsb) { - return new vhdl_type(VHDL_TYPE_SIGNED, width-1, 0); + return new vhdl_type(VHDL_TYPE_SIGNED, width-1+lsb, lsb); } vhdl_type *vhdl_type::time() @@ -122,12 +122,12 @@ vhdl_type *vhdl_type::std_logic_vector(int msb, int lsb) return new vhdl_type(VHDL_TYPE_STD_LOGIC_VECTOR, msb, lsb); } -vhdl_type *vhdl_type::type_for(int width, bool issigned) +vhdl_type *vhdl_type::type_for(int width, bool issigned, int lsb) { - if (width == 0) + if (width == 1) return vhdl_type::std_logic(); else if (issigned) - return vhdl_type::nsigned(width); + return vhdl_type::nsigned(width, lsb); else - return vhdl_type::nunsigned(width); + return vhdl_type::nunsigned(width, lsb); } diff --git a/tgt-vhdl/vhdl_type.hh b/tgt-vhdl/vhdl_type.hh index 0c52814d6..7b5878478 100644 --- a/tgt-vhdl/vhdl_type.hh +++ b/tgt-vhdl/vhdl_type.hh @@ -60,13 +60,13 @@ public: static vhdl_type *string(); static vhdl_type *line(); static vhdl_type *std_logic_vector(int msb, int lsb); - static vhdl_type *nunsigned(int width); - static vhdl_type *nsigned(int width); + static vhdl_type *nunsigned(int width, int lsb=0); + static vhdl_type *nsigned(int width, int lsb=0); static vhdl_type *integer(); static vhdl_type *boolean(); static vhdl_type *time(); - static vhdl_type *type_for(int width, bool issigned); + static vhdl_type *type_for(int width, bool issigned, int lsb=0); protected: vhdl_type_name_t name_; int msb_, lsb_; From 1cd7689d03d7f41ee07a9c627ccda963b77b2808 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 8 Jul 2008 12:58:50 +0100 Subject: [PATCH 203/377] Fix casting with signed/unsigned expressions Previously the code generator tried to infer the VHDL types. Now it takes a much more dumb approach and forces the VHDL type to be the same as the ivl type (derived from ivl_expr_signed and ivl_expr_width) in the expression tree. This works much better :-) --- tgt-vhdl/expr.cc | 157 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 37 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 344a717be..a689c8c18 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -69,6 +69,39 @@ static vhdl_expr *translate_unary(ivl_expr_t e) if (NULL == operand) return NULL; + bool should_be_signed = ivl_expr_signed(e) != 0; + + if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { + //operand->print(); + //std::cout << "^ should be signed but is not" << std::endl; + + int msb = operand->get_type()->get_msb(); + int lsb = operand->get_type()->get_lsb(); + vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); + + operand = operand->cast(&u); + } + 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; + + int msb = operand->get_type()->get_msb(); + int lsb = operand->get_type()->get_lsb(); + vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb); + + operand = operand->cast(&u); + } + + // Need to ensure that the operand is interpreted as unsigned to get VHDL + // to emulate Verilog behaviour + if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED) { + int msb = operand->get_type()->get_msb(); + int lsb = operand->get_type()->get_lsb(); + vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb); + + operand = operand->cast(&u); + } + char opcode = ivl_expr_opcode(e); switch (opcode) { case '!': @@ -156,75 +189,89 @@ static vhdl_expr *translate_binary(ivl_expr_t e) int lwidth = lhs->get_type()->get_width(); int rwidth = rhs->get_type()->get_width(); - - std::cout << "opwidth = " << ivl_expr_width(e) - << " lwidth = " << lwidth - << " rwidth = " << rwidth << std::endl; - - // May need to resize the left or right hand side - /*if (lwidth < rwidth) { - lhs = lhs->cast(rhs->get_type()); - } - else if (rwidth < lwidth) { - rhs = rhs->cast(lhs->get_type()); - }*/ - int result_width = ivl_expr_width(e); // For === and !== we need to compare std_logic_vectors // rather than signeds vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0); + vhdl_type_name_t ltype = lhs->get_type()->get_name(); + vhdl_type_name_t rtype = rhs->get_type()->get_name(); bool vectorop = - (lhs->get_type()->get_name() == VHDL_TYPE_SIGNED - || lhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED) && - (rhs->get_type()->get_name() == VHDL_TYPE_SIGNED - || rhs->get_type()->get_name() == VHDL_TYPE_UNSIGNED); + (ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) && + (rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED); + // May need to resize the left or right hand side + if (vectorop) { + if (lwidth < rwidth) + lhs = lhs->resize(rwidth); + else if (rwidth < lwidth) + rhs = rhs->resize(lwidth); + } + + vhdl_expr *result; switch (ivl_expr_opcode(e)) { case '+': - return translate_numeric(lhs, rhs, VHDL_BINOP_ADD); + result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD); + break; case '-': - return translate_numeric(lhs, rhs, VHDL_BINOP_SUB); + result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB); + break; case '*': - return translate_numeric(lhs, rhs, VHDL_BINOP_MULT); + result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT); + break; case 'e': - return translate_relation(lhs, rhs, VHDL_BINOP_EQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); + break; case 'E': if (vectorop) - return translate_relation(lhs->cast(&std_logic_vector), + result = translate_relation(lhs->cast(&std_logic_vector), rhs->cast(&std_logic_vector), VHDL_BINOP_EQ); else - return translate_relation(lhs, rhs, VHDL_BINOP_EQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); + break; case 'n': - return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + break; case 'N': if (vectorop) - return translate_relation(lhs->cast(&std_logic_vector), + result = translate_relation(lhs->cast(&std_logic_vector), rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); else - return translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ); + break; case '&': // Bitwise AND - return translate_numeric(lhs, rhs, VHDL_BINOP_AND); + result = translate_numeric(lhs, rhs, VHDL_BINOP_AND); + break; case 'a': // Logical AND - return translate_logical(lhs, rhs, VHDL_BINOP_AND); + result = translate_logical(lhs, rhs, VHDL_BINOP_AND); + break; case '|': // Bitwise OR - return translate_numeric(lhs, rhs, VHDL_BINOP_OR); + result = translate_numeric(lhs, rhs, VHDL_BINOP_OR); + break; case 'o': // Logical OR - return translate_logical(lhs, rhs, VHDL_BINOP_OR); + result = translate_logical(lhs, rhs, VHDL_BINOP_OR); + break; case '<': - return translate_relation(lhs, rhs, VHDL_BINOP_LT); + result = translate_relation(lhs, rhs, VHDL_BINOP_LT); + break; case 'L': - return translate_relation(lhs, rhs, VHDL_BINOP_LEQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ); + break; case '>': - return translate_relation(lhs, rhs, VHDL_BINOP_GT); + result = translate_relation(lhs, rhs, VHDL_BINOP_GT); + break; case 'G': - return translate_relation(lhs, rhs, VHDL_BINOP_GEQ); + result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ); + break; case 'l': - return translate_shift(lhs, rhs, VHDL_BINOP_SL); + result = translate_shift(lhs, rhs, VHDL_BINOP_SL); + break; case 'r': - return translate_shift(lhs, rhs, VHDL_BINOP_SR); + result = translate_shift(lhs, rhs, VHDL_BINOP_SR); + break; case '^': - return translate_numeric(lhs, rhs, VHDL_BINOP_XOR); + result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR); + break; default: error("No translation for binary opcode '%c'\n", ivl_expr_opcode(e)); @@ -232,6 +279,42 @@ static vhdl_expr *translate_binary(ivl_expr_t e) delete rhs; return NULL; } + + if (NULL == result) + return NULL; + + if (vectorop) { + bool should_be_signed = ivl_expr_signed(e) != 0; + + if (result->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { + //result->print(); + //std::cout << "^ should be signed but is not" << std::endl; + + int msb = result->get_type()->get_msb(); + int lsb = result->get_type()->get_lsb(); + vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); + + result = result->cast(&u); + } + 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; + + int msb = result->get_type()->get_msb(); + int lsb = result->get_type()->get_lsb(); + vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); + + result = result->cast(&u); + } + + int actual_width = result->get_type()->get_width(); + if (actual_width != result_width) { + //result->print(); + //std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl; + } + } + + return result; } static vhdl_expr *translate_select(ivl_expr_t e) From 55747bf79dec191a7ecfc3783acf49e70384df2d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 8 Jul 2008 13:07:11 +0100 Subject: [PATCH 204/377] Refactor signdness changing code into a single function This is the code that generated calls to signed/unsigned in the VHDL output. --- tgt-vhdl/expr.cc | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index a689c8c18..fadc0d3d4 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -23,6 +23,18 @@ #include #include +/* + * Change the signdness of a vector. + */ +static vhdl_expr *change_signdness(vhdl_expr *e, bool issigned) +{ + int msb = e->get_type()->get_msb(); + int lsb = e->get_type()->get_lsb(); + vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb); + + return e->cast(&u); +} + /* * Convert a constant Verilog string to a constant VHDL string. */ @@ -74,34 +86,16 @@ static vhdl_expr *translate_unary(ivl_expr_t e) if (operand->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { //operand->print(); //std::cout << "^ should be signed but is not" << std::endl; - - int msb = operand->get_type()->get_msb(); - int lsb = operand->get_type()->get_lsb(); - vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); - operand = operand->cast(&u); + operand = change_signdness(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; - - int msb = operand->get_type()->get_msb(); - int lsb = operand->get_type()->get_lsb(); - vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb); - operand = operand->cast(&u); + operand = change_signdness(operand, false); } - // Need to ensure that the operand is interpreted as unsigned to get VHDL - // to emulate Verilog behaviour - if (operand->get_type()->get_name() == VHDL_TYPE_SIGNED) { - int msb = operand->get_type()->get_msb(); - int lsb = operand->get_type()->get_lsb(); - vhdl_type u(VHDL_TYPE_UNSIGNED, msb, lsb); - - operand = operand->cast(&u); - } - char opcode = ivl_expr_opcode(e); switch (opcode) { case '!': @@ -290,21 +284,13 @@ static vhdl_expr *translate_binary(ivl_expr_t e) //result->print(); //std::cout << "^ should be signed but is not" << std::endl; - int msb = result->get_type()->get_msb(); - int lsb = result->get_type()->get_lsb(); - vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); - - result = result->cast(&u); + result = change_signdness(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; - int msb = result->get_type()->get_msb(); - int lsb = result->get_type()->get_lsb(); - vhdl_type u(VHDL_TYPE_SIGNED, msb, lsb); - - result = result->cast(&u); + result = change_signdness(result, false); } int actual_width = result->get_type()->get_width(); From aa951af2b741eb8e6f8a3c6947b7ae721a2b14c3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 10 Jul 2008 19:27:17 +0100 Subject: [PATCH 205/377] 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 206/377] 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 207/377] 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 208/377] 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 209/377] 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 210/377] 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 211/377] 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 212/377] 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 213/377] 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 214/377] 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 215/377] 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 216/377] 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 217/377] 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 218/377] 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 219/377] 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 220/377] 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 221/377] 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 222/377] 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 223/377] 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 224/377] 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 225/377] 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 226/377] 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 227/377] 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 228/377] 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 229/377] 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 230/377] 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 231/377] 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 232/377] 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 233/377] 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 234/377] 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 235/377] 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 236/377] 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 237/377] 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 238/377] 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 239/377] 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 240/377] 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 241/377] 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 242/377] 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 243/377] 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 244/377] 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 245/377] 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 246/377] 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 247/377] 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 248/377] 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 249/377] 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 250/377] 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 251/377] 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 252/377] 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 253/377] 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 254/377] 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 255/377] 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 256/377] 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 257/377] 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 258/377] 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 259/377] 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 260/377] 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 261/377] 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 { From 2f4f075005c5b82c004f34f4bf9cff4d1b5c5c06 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 21 Jul 2008 15:20:40 +0100 Subject: [PATCH 262/377] Typo --- tgt-vhdl/vhdl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index c8563c488..a6d2b61c8 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -31,7 +31,7 @@ #include /* - * Maps a signal to the entity it is defined within. Also + * Maps a signal to the scope it is defined within. Also * provides a mechanism for renaming signals -- i.e. when * an output has the same name as register: valid in Verilog * but not in VHDL, so two separate signals need to be From a5db0297b0d17c4ecaaa6db5c062f507f7673c79 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 22 Jul 2008 15:44:29 +0100 Subject: [PATCH 263/377] Unary minus --- tgt-vhdl/expr.cc | 3 +++ tgt-vhdl/vhdl_syntax.cc | 3 +++ tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 7 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index f64ac4ac6..9e383dfc9 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -149,6 +149,9 @@ static vhdl_expr *translate_unary(ivl_expr_t e) case '~': return new vhdl_unaryop_expr (VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type())); + case '-': + return new vhdl_unaryop_expr + (VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type())); case 'N': // NOR return translate_reduction(SF_REDUCE_OR, true, operand); case '|': diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3cc70853a..a14f11e6d 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -657,6 +657,9 @@ void vhdl_unaryop_expr::emit(std::ostream &of, int level) const case VHDL_UNARYOP_NOT: of << "not "; break; + case VHDL_UNARYOP_NEG: + of << "-"; + break; } operand_->emit(of, level); of << ")"; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index fcf06286a..c6a2c727f 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -107,6 +107,7 @@ private: enum vhdl_unaryop_t { VHDL_UNARYOP_NOT, + VHDL_UNARYOP_NEG, }; class vhdl_unaryop_expr : public vhdl_expr { From 30fdadc5252f1d9746ac76177af9959bacd4ef58 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 23 Jul 2008 13:40:42 +0100 Subject: [PATCH 264/377] Support delays in logic devices --- tgt-vhdl/scope.cc | 21 +++++++++++++++++++-- tgt-vhdl/vhdl_syntax.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.hh | 5 +++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index ac1202fff..69808076b 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -242,9 +242,26 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) 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)); + vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); + + ivl_expr_t delay = ivl_logic_delay(log, 1); + vhdl_expr *after; + if (delay && (after = translate_expr(delay))) { + // 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()); + + ass->set_after(after); + } + + arch->add_stmt(ass); } } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index a14f11e6d..2f5e9f56f 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -611,6 +611,12 @@ void vhdl_cassign_stmt::emit(std::ostream &of, int level) const of << "else "; } rhs_->emit(of, level); + + if (after_) { + of << " after "; + after_->emit(of, level); + } + of << ";"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c6a2c727f..f7acf9762 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -227,14 +227,15 @@ typedef std::list conc_stmt_list_t; class vhdl_cassign_stmt : public vhdl_conc_stmt { public: vhdl_cassign_stmt(vhdl_var_ref *lhs, vhdl_expr *rhs) - : lhs_(lhs), rhs_(rhs) {} + : lhs_(lhs), rhs_(rhs), after_(NULL) {} ~vhdl_cassign_stmt(); void emit(std::ostream &of, int level) const; void add_condition(vhdl_expr *value, vhdl_expr *cond); + void set_after(vhdl_expr *a) { after_ = a; } private: vhdl_var_ref *lhs_; - vhdl_expr *rhs_; + vhdl_expr *rhs_, *after_; struct when_part_t { vhdl_expr *value, *cond; From 1409207defa5cbdd0fd10765ab0c639e7320ec2b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 23 Jul 2008 14:31:41 +0100 Subject: [PATCH 265/377] Correctly indent case statements --- tgt-vhdl/support.cc | 4 ++-- tgt-vhdl/vhdl_helper.hh | 6 ++++-- tgt-vhdl/vhdl_syntax.cc | 14 ++++++++++---- tgt-vhdl/vhdl_syntax.hh | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 159618739..4c396407f 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -86,9 +86,9 @@ void support_function::emit(std::ostream &of, int level) const 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)) + << "return '1';" << nl_string(indent(level)) << "else" << nl_string(indent(indent(level))) - << "return '0'" << nl_string(indent(level)) + << "return '0';" << nl_string(indent(level)) << "end if;" << nl_string(level); break; case SF_REDUCE_OR: diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index a3f6f0704..d003ff1ef 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -28,7 +28,8 @@ template void emit_children(std::ostream &of, const std::list &children, - int level, const char *delim="") + int level, const char *delim = "", + bool trailing_newline = true) { // Don't indent if there are no children if (children.size() == 0) @@ -42,7 +43,8 @@ void emit_children(std::ostream &of, if (--sz > 0) of << delim; } - newline(of, level); + if (trailing_newline) + newline(of, level); } } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2f5e9f56f..9637d1fe1 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -192,9 +192,9 @@ void stmt_container::add_stmt(vhdl_seq_stmt *stmt) stmts_.push_back(stmt); } -void stmt_container::emit(std::ostream &of, int level) const +void stmt_container::emit(std::ostream &of, int level, bool newline) const { - emit_children(of, stmts_, level); + emit_children(of, stmts_, level, "", newline); } vhdl_comp_inst::vhdl_comp_inst(const char *inst_name, const char *comp_name) @@ -724,7 +724,7 @@ void vhdl_case_branch::emit(std::ostream &of, int level) const of << "when "; when_->emit(of, level); of << " =>"; - stmts_.emit(of, indent(level)); + stmts_.emit(of, indent(level), false); } vhdl_case_stmt::~vhdl_case_stmt() @@ -740,8 +740,14 @@ void vhdl_case_stmt::emit(std::ostream &of, int level) const newline(of, indent(level)); case_branch_list_t::const_iterator it; - for (it = branches_.begin(); it != branches_.end(); ++it) + int n = branches_.size(); + for (it = branches_.begin(); it != branches_.end(); ++it) { (*it)->emit(of, level); + if (--n > 0) + newline(of, indent(level)); + else + newline(of, level); + } of << "end case;"; } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index f7acf9762..f54eb4f64 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -261,7 +261,7 @@ public: ~stmt_container(); void add_stmt(vhdl_seq_stmt *stmt); - void emit(std::ostream &of, int level) const; + void emit(std::ostream &of, int level, bool newline=true) const; bool empty() const { return stmts_.empty(); } private: std::list stmts_; From e4c2400eb20673f700a7d8da3bb5ada3392fa250 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 23 Jul 2008 16:18:49 +0100 Subject: [PATCH 266/377] Refactor the expression->time code into a single function --- tgt-vhdl/expr.cc | 18 ++++++++++++++++++ tgt-vhdl/scope.cc | 15 ++------------- tgt-vhdl/stmt.cc | 24 +++--------------------- tgt-vhdl/vhdl_target.h | 1 + 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 9e383dfc9..f0aec0019 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -484,3 +484,21 @@ vhdl_expr *translate_expr(ivl_expr_t e) return NULL; } } + +/* + * Translate an expression into a time. This is achieved simply + * by multiplying the expression by 1ns. + */ +vhdl_expr *translate_time_expr(ivl_expr_t e) +{ + vhdl_expr *time = translate_expr(e); + if (NULL == time) + return NULL; + + vhdl_type integer(VHDL_TYPE_INTEGER); + time = time->cast(&integer); + + vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS); + return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, + vhdl_type::time()); +} diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 69808076b..826def5ad 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -247,19 +247,8 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); ivl_expr_t delay = ivl_logic_delay(log, 1); - vhdl_expr *after; - if (delay && (after = translate_expr(delay))) { - // 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()); - - ass->set_after(after); - } + if (delay) + ass->set_after(translate_time_expr(delay)); arch->add_stmt(ass); } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 87efac0e2..68e9e20ec 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -269,19 +269,8 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, 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 (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) + after = translate_time_expr(i_delay); if (after != NULL) a->set_after(after); @@ -349,16 +338,9 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, time = new vhdl_const_time(value, TIME_UNIT_NS); } else { - time = translate_expr(ivl_stmt_delay_expr(stmt)); + time = translate_time_expr(ivl_stmt_delay_expr(stmt)); if (NULL == time) return 1; - - vhdl_type integer(VHDL_TYPE_INTEGER); - time = time->cast(&integer); - - vhdl_expr *ns1 = new vhdl_const_time(1, TIME_UNIT_NS); - time = new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1, - vhdl_type::time()); } // If the sub-statement is an assignment then VHDL lets diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 20584eecf..62e784845 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -22,6 +22,7 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); vhdl_expr *translate_expr(ivl_expr_t e); +vhdl_expr *translate_time_expr(ivl_expr_t e); vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm); void remember_entity(vhdl_entity *ent); From 8bee5b11082339b5b4eb63760ab6377dfe6e0c54 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 24 Jul 2008 14:30:10 +0100 Subject: [PATCH 267/377] Add `forever' statement type --- tgt-vhdl/stmt.cc | 13 +++++++++++++ tgt-vhdl/vhdl_syntax.cc | 7 +++++++ tgt-vhdl/vhdl_syntax.hh | 9 +++++++++ 3 files changed, 29 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 68e9e20ec..a1d152f5b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -559,6 +559,17 @@ int draw_while(vhdl_procedural *proc, stmt_container *container, return 0; } +int draw_forever(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt) +{ + vhdl_loop_stmt *loop = new vhdl_loop_stmt; + container->add_stmt(loop); + + draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); + + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the @@ -593,6 +604,8 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, return draw_case(proc, container, stmt); case IVL_ST_WHILE: return draw_while(proc, container, stmt); + case IVL_ST_FOREVER: + return draw_forever(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 9637d1fe1..0fe655b1e 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -766,6 +766,13 @@ void vhdl_while_stmt::emit(std::ostream &of, int level) const of << "end loop;"; } +void vhdl_loop_stmt::emit(std::ostream &of, int level) const +{ + of << "loop"; + stmts_.emit(of, level); + of << "end loop;"; +} + vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) : vhdl_decl(name, ret_type) { diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index f54eb4f64..06a7d4125 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -408,6 +408,15 @@ private: }; +class vhdl_loop_stmt : public vhdl_seq_stmt { +public: + stmt_container *get_container() { return &stmts_; } + void emit(std::ostream &of, int level) const; +private: + stmt_container stmts_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From 39c9c54760af6964738ab757815ec11ede0584df Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 24 Jul 2008 14:52:06 +0100 Subject: [PATCH 268/377] Add repeat statement --- tgt-vhdl/stmt.cc | 22 ++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 16 ++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 15 +++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a1d152f5b..187134854 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -570,6 +570,26 @@ int draw_forever(vhdl_procedural *proc, stmt_container *container, return 0; } +int draw_repeat(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt) +{ + vhdl_expr *times = translate_expr(ivl_stmt_cond_expr(stmt)); + if (NULL == times) + return 1; + + vhdl_type integer(VHDL_TYPE_INTEGER); + times = times->cast(&integer); + + const char *it_name = "Verilog_Repeat"; + vhdl_for_stmt *loop = + new vhdl_for_stmt(it_name, new vhdl_const_int(1), times); + container->add_stmt(loop); + + draw_stmt(proc, loop->get_container(), ivl_stmt_sub_stmt(stmt)); + + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the @@ -606,6 +626,8 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, return draw_while(proc, container, stmt); case IVL_ST_FOREVER: return draw_forever(proc, container, stmt); + case IVL_ST_REPEAT: + return draw_repeat(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 0fe655b1e..07a26f5d3 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -773,6 +773,22 @@ void vhdl_loop_stmt::emit(std::ostream &of, int level) const of << "end loop;"; } +vhdl_for_stmt::~vhdl_for_stmt() +{ + delete from_; + delete to_; +} + +void vhdl_for_stmt::emit(std::ostream &of, int level) const +{ + of << "for " << lname_ << " in "; + from_->emit(of, level); + of << " to "; + to_->emit(of, level); + of << " "; + loop_.emit(of, level); +} + vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) : vhdl_decl(name, ret_type) { diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 06a7d4125..50c3d305d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -417,6 +417,21 @@ private: }; +class vhdl_for_stmt : public vhdl_seq_stmt { +public: + vhdl_for_stmt(const char *lname, vhdl_expr *from, vhdl_expr *to) + : lname_(lname), from_(from), to_(to) {} + ~vhdl_for_stmt(); + + stmt_container *get_container() { return loop_.get_container(); } + void emit(std::ostream &of, int level) const; +private: + vhdl_loop_stmt loop_; + const char *lname_; + vhdl_expr *from_, *to_; +}; + + /* * A procedure call. Which is a statement, unlike a function * call which is an expression. From d3296d48955540c9d2b651e84dc3557730c2619f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 24 Jul 2008 15:22:25 +0100 Subject: [PATCH 269/377] Refactor while/for loop code to use common base --- tgt-vhdl/vhdl_syntax.cc | 7 +++---- tgt-vhdl/vhdl_syntax.hh | 28 +++++++++++++--------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 07a26f5d3..aa3b419d8 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -761,9 +761,8 @@ void vhdl_while_stmt::emit(std::ostream &of, int level) const { of << "while "; test_->emit(of, level); - of << " loop"; - stmts_.emit(of, level); - of << "end loop;"; + of << " "; + vhdl_loop_stmt::emit(of, level); } void vhdl_loop_stmt::emit(std::ostream &of, int level) const @@ -786,7 +785,7 @@ void vhdl_for_stmt::emit(std::ostream &of, int level) const of << " to "; to_->emit(of, level); of << " "; - loop_.emit(of, level); + vhdl_loop_stmt::emit(of, level); } vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 50c3d305d..551e4636f 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -395,38 +395,36 @@ private: }; -class vhdl_while_stmt : public vhdl_seq_stmt { +class vhdl_loop_stmt : public vhdl_seq_stmt { +public: + virtual ~vhdl_loop_stmt() {} + + stmt_container *get_container() { return &stmts_; } + void emit(std::ostream &of, int level) const; +private: + stmt_container stmts_; +}; + + +class vhdl_while_stmt : public vhdl_loop_stmt { public: vhdl_while_stmt(vhdl_expr *test) : test_(test) {} ~vhdl_while_stmt(); - stmt_container *get_container() { return &stmts_; } void emit(std::ostream &of, int level) const; private: vhdl_expr *test_; - stmt_container stmts_; }; -class vhdl_loop_stmt : public vhdl_seq_stmt { -public: - stmt_container *get_container() { return &stmts_; } - void emit(std::ostream &of, int level) const; -private: - stmt_container stmts_; -}; - - -class vhdl_for_stmt : public vhdl_seq_stmt { +class vhdl_for_stmt : public vhdl_loop_stmt { public: vhdl_for_stmt(const char *lname, vhdl_expr *from, vhdl_expr *to) : lname_(lname), from_(from), to_(to) {} ~vhdl_for_stmt(); - stmt_container *get_container() { return loop_.get_container(); } void emit(std::ostream &of, int level) const; private: - vhdl_loop_stmt loop_; const char *lname_; vhdl_expr *from_, *to_; }; From 5a098197296d76da869df106e0c6f9c96561abea Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 24 Jul 2008 16:00:12 +0100 Subject: [PATCH 270/377] Catch case of select expression on non-variable --- tgt-vhdl/display.cc | 2 +- tgt-vhdl/expr.cc | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index c599aabc3..e70f1bce5 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -162,7 +162,7 @@ int draw_stask_display(vhdl_procedural *proc, stmt_container *container, } else { vhdl_expr *base = translate_expr(net); - if (NULL == base) + if (NULL == base) return 1; display_write(container, base); diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index f0aec0019..007abb203 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -355,8 +355,10 @@ static vhdl_expr *translate_select(ivl_expr_t e) { vhdl_var_ref *from = dynamic_cast(translate_expr(ivl_expr_oper1(e))); - if (NULL == from) + if (NULL == from) { + error("Can only select from variable reference"); return NULL; + } ivl_expr_t o2 = ivl_expr_oper2(e); if (o2) { @@ -454,7 +456,7 @@ vhdl_expr *translate_expr(ivl_expr_t e) { assert(e); ivl_expr_type_t type = ivl_expr_type(e); - + switch (type) { case IVL_EX_STRING: return translate_string(e); From 8b32096e2a32819a82751201fdc255bc4c3fd88f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 27 Jul 2008 18:39:16 +0100 Subject: [PATCH 271/377] Convert std_logic to Boolean in loop tests --- tgt-vhdl/cast.cc | 2 ++ tgt-vhdl/stmt.cc | 5 +++++ tgt-vhdl/vhdl_syntax.cc | 5 +++++ tgt-vhdl/vhdl_syntax.hh | 9 +++++++++ 4 files changed, 21 insertions(+) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 7d83a67f4..a3d571b53 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -168,6 +168,8 @@ 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 if (to->get_name() == VHDL_TYPE_BOOLEAN) + return new vhdl_const_bool(bit_ == '1'); else return vhdl_expr::cast(to); } diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 187134854..998eaea90 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -551,6 +551,11 @@ int draw_while(vhdl_procedural *proc, stmt_container *container, if (NULL == test) return 1; + // The test must be a Boolean (and std_logic and (un)signed types + // must be explicitly cast unlike in Verilog) + vhdl_type boolean(VHDL_TYPE_BOOLEAN); + test = test->cast(&boolean); + vhdl_while_stmt *loop = new vhdl_while_stmt(test); container->add_stmt(loop); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index aa3b419d8..3b3099518 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -567,6 +567,11 @@ void vhdl_const_int::emit(std::ostream &of, int level) const of << value_; } +void vhdl_const_bool::emit(std::ostream &of, int level) const +{ + of << (value_ ? "True" : "False"); +} + void vhdl_const_time::emit(std::ostream &of, int level) const { of << value_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 551e4636f..538842052 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -180,6 +180,15 @@ private: int64_t value_; }; +class vhdl_const_bool : public vhdl_expr { +public: + vhdl_const_bool(bool value) + : vhdl_expr(vhdl_type::boolean(), true), value_(value) {} + void emit(std::ostream &of, int level) const; +private: + bool value_; +}; + class vhdl_expr_list : public vhdl_element { public: ~vhdl_expr_list(); From b9cecbef6420acbea600a91b18c1f99dbfc2933c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 27 Jul 2008 19:05:49 +0100 Subject: [PATCH 272/377] Make sure LPM comparison result is std_logic not Boolean --- tgt-vhdl/lpm.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 3221b85c6..e3370b263 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -130,7 +130,9 @@ static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t expr->add_expr(e); } - return expr; + // Need to make sure output is std_logic rather than Boolean + vhdl_type std_logic(VHDL_TYPE_STD_LOGIC); + return expr->cast(&std_logic); } static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) From 03e306c8056594972ef14cb5518eaf0168e5ecd9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 27 Jul 2008 15:02:09 -0400 Subject: [PATCH 273/377] Infrastructure for parsing analog process statements. Organize the parsing infrastructure for parsing analog processes, including holding them in scopes, and collecting analog statements. --- AStatement.cc | 38 +++++++++++++++++++++++++ AStatement.h | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ Makefile.in | 5 ++-- PScope.h | 8 ++++-- parse.y | 6 +++- pform.cc | 11 ++++++++ pform.h | 9 ++++++ pform_analog.cc | 40 ++++++++++++++++++++++++++ pform_dump.cc | 46 ++++++++++++++++++++++++++++++ 9 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 AStatement.cc create mode 100644 AStatement.h create mode 100644 pform_analog.cc diff --git a/AStatement.cc b/AStatement.cc new file mode 100644 index 000000000..4d59dffc2 --- /dev/null +++ b/AStatement.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "config.h" + +# include "AStatement.h" + +AStatement::~AStatement() +{ +} + +AContrib::AContrib() +{ +} + +AContrib::~AContrib() +{ +} + +AProcess::~AProcess() +{ +} diff --git a/AStatement.h b/AStatement.h new file mode 100644 index 000000000..fb00fc6ce --- /dev/null +++ b/AStatement.h @@ -0,0 +1,74 @@ +#ifndef __AStatement_H +#define __AStatement_H +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include +# include "StringHeap.h" +# include "LineInfo.h" + +class PExpr; + +class AStatement : public LineInfo { + + public: + AStatement() { } + virtual ~AStatement() =0; + + virtual void dump(ostream&out, unsigned ind) const; + + private: // not implemented + AStatement(const AStatement&); + AStatement& operator= (const AStatement&); +}; + +class AContrib : public AStatement { + + public: + AContrib(); + ~AContrib(); + + private: +}; + +class AProcess : public LineInfo { + + public: + enum Type { PR_INITIAL, PR_ALWAYS }; + + AProcess(Type t, AStatement*st) + : type_(t), statement_(st) { } + + ~AProcess(); + + map attributes; + + // Dump the analog process + void dump(ostream&out, unsigned ind) const; + + private: + Type type_; + AStatement*statement_; + + private: // not implemented + AProcess(const AProcess&); + AProcess& operator= (const AProcess&); +}; + +#endif diff --git a/Makefile.in b/Makefile.in index a5be31f9b..a45841892 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,12 +107,13 @@ load_module.o netlist.o netmisc.o net_assign.o \ net_design.o net_event.o net_expr.o net_force.o net_func.o \ net_link.o net_modulo.o net_nex_input.o net_nex_output.o \ net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \ -parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \ +parse.o parse_misc.o pform.o pform_analog.o pform_disciplines.o \ +pform_dump.o pform_types.o \ set_width.o symbol_search.o sync.o sys_funcs.o \ verinum.o verireal.o target.o targets.o \ Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \ PExpr.o PGate.o PGenerate.o PScope.o PSpec.o \ -PTask.o PUdp.o PFunction.o PWire.o Statement.o StringHeap.o \ +PTask.o PUdp.o PFunction.o PWire.o Statement.o AStatement.o StringHeap.o \ $(FF) $(TT) Makefile: Makefile.in config.h.in config.status diff --git a/PScope.h b/PScope.h index d65244a03..545b502f3 100644 --- a/PScope.h +++ b/PScope.h @@ -24,6 +24,7 @@ # include class PEvent; +class AProcess; class PProcess; class PWire; @@ -50,6 +51,10 @@ class LexicalScope { mapwires; PWire* wires_find(perm_string name); + // Behaviors (processes) in this scope + list behaviors; + list analog_behaviors; + private: }; @@ -74,9 +79,6 @@ class PScope : public LexicalScope { // Named events in the scope. mapevents; - // Behaviors (processes) in this scope - list behaviors; - protected: void dump_wires_(ostream&out, unsigned indent) const; diff --git a/parse.y b/parse.y index f63ee1d9b..0bea41113 100644 --- a/parse.y +++ b/parse.y @@ -180,6 +180,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) PEventStatement*event_statement; Statement*statement; svector*statement_list; + AStatement*astatement; PTaskFuncArg function_type; @@ -302,6 +303,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %type statement statement_or_null %type statement_list +%type analog_statement + %type spec_polarity %type specify_path_identifiers @@ -2078,6 +2081,7 @@ module_item } | attribute_list_opt K_analog analog_statement + { pform_make_analog_behavior(@2, AProcess::PR_ALWAYS, $3); } /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the @@ -3724,7 +3728,7 @@ statement_or_null analog_statement : branch_probe_expression K_CONTRIBUTE expression ';' - { yyerror(@1, "sorry: Analog contribution statements not supported."); } + { $$ = pform_contribution_statement(@2); } ; /* Task items are, other than the statement, task port items and diff --git a/pform.cc b/pform.cc index 6b3612a06..9e9d84a87 100644 --- a/pform.cc +++ b/pform.cc @@ -192,6 +192,17 @@ static void pform_put_behavior_in_scope(PProcess*pp) lexical_scope->behaviors.push_back(pp); } +void pform_put_behavior_in_scope(AProcess*pp) +{ + if (pform_cur_generate) + if (pform_cur_generate->lexical_scope) + pform_cur_generate->lexical_scope->analog_behaviors.push_back(pp); + else + pform_cur_generate->analog_behaviors.push_back(pp); + else + lexical_scope->analog_behaviors.push_back(pp); +} + void pform_set_default_nettype(NetNet::Type type, const char*file, unsigned lineno) { diff --git a/pform.h b/pform.h index a94be9f96..c3a5f7652 100644 --- a/pform.h +++ b/pform.h @@ -24,6 +24,7 @@ # include "named.h" # include "Module.h" # include "Statement.h" +# include "AStatement.h" # include "PGate.h" # include "PExpr.h" # include "PTask.h" @@ -179,6 +180,7 @@ extern PTask*pform_push_task_scope(char*name); extern PFunction*pform_push_function_scope(char*name); extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); +extern void pform_put_behavior_in_scope(AProcess*proc); extern verinum* pform_verinum_with_size(verinum*s, verinum*val, const char*file, unsigned lineno); @@ -389,4 +391,11 @@ extern void pform_attach_discipline(const struct vlltype&loc, extern void pform_dump(ostream&out, const nature_t*); extern void pform_dump(ostream&out, const discipline_t*); +/* ** pform_analog.cc +*/ +extern void pform_make_analog_behavior(const struct vlltype&loc, + AProcess::Type type, AStatement*st); + +extern AStatement*pform_contribution_statement(const struct vlltype&loc); + #endif diff --git a/pform_analog.cc b/pform_analog.cc new file mode 100644 index 000000000..44c080458 --- /dev/null +++ b/pform_analog.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "config.h" +# include "compiler.h" +# include "pform.h" +# include "parse_misc.h" +# include "AStatement.h" + +AStatement* pform_contribution_statement(const struct vlltype&loc) +{ + AContrib*tmp = new AContrib; + FILE_NAME(tmp, loc); + return tmp; +} + +void pform_make_analog_behavior(const struct vlltype&loc, AProcess::Type pt, + AStatement*statement) +{ + AProcess*proc = new AProcess(pt, statement); + FILE_NAME(proc, loc); + + pform_put_behavior_in_scope(proc); +} diff --git a/pform_dump.cc b/pform_dump.cc index ba6e60912..7ea9b37b1 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -531,6 +531,16 @@ void Statement::dump(ostream&out, unsigned ind) const << " */ ;" << endl; } +void AStatement::dump(ostream&out, unsigned ind) const +{ + /* I give up. I don't know what type this statement is, + so just print the C++ typeid and let the user figure + it out. */ + out << setw(ind) << ""; + out << "/* " << get_fileline() << ": " << typeid(*this).name() + << " */ ;" << endl; +} + void PAssign::dump(ostream&out, unsigned ind) const { out << setw(ind) << ""; @@ -840,6 +850,32 @@ void PProcess::dump(ostream&out, unsigned ind) const statement_->dump(out, ind+2); } +void AProcess::dump(ostream&out, unsigned ind) const +{ + switch (type_) { + case AProcess::PR_INITIAL: + out << setw(ind) << "" << "analog initial"; + break; + case AProcess::PR_ALWAYS: + out << setw(ind) << "" << "analog"; + break; + } + + out << " /* " << get_fileline() << " */" << endl; + + for (map::const_iterator idx = attributes.begin() + ; idx != attributes.end() ; idx++ ) { + + out << setw(ind+2) << "" << "(* " << (*idx).first; + if ((*idx).second) { + out << " = " << *(*idx).second; + } + out << " *)" << endl; + } + + statement_->dump(out, ind+2); +} + void PSpecPath::dump(std::ostream&out, unsigned ind) const { out << setw(ind) << "" << "specify path "; @@ -937,6 +973,11 @@ void PGenerate::dump(ostream&out, unsigned indent) const (*idx)->dump(out, indent+2); } + for (list::const_iterator idx = analog_behaviors.begin() + ; idx != analog_behaviors.end() ; idx++) { + (*idx)->dump(out, indent+2); + } + for (list::const_iterator idx = generate_schemes.begin() ; idx != generate_schemes.end() ; idx++) { (*idx)->dump(out, indent+2); @@ -1122,6 +1163,11 @@ void Module::dump(ostream&out) const (*behav)->dump(out, 4); } + for (list::const_iterator idx = analog_behaviors.begin() + ; idx != analog_behaviors.end() ; idx++) { + (*idx)->dump(out, 4); + } + for (list::const_iterator spec = specify_paths.begin() ; spec != specify_paths.end() ; spec ++ ) { From 25a27f9dd9f30abc3a8477ba9034249cc2822732 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 27 Jul 2008 17:22:19 -0400 Subject: [PATCH 274/377] Parse contribution statements as far as pform. Contribution statements have an l-value and r-value. Parse those expressions into pform so that elaboration has something to work with. In this process, this patch also changes the PECallFunction class to use the vector template instead of the svector template. The latter doesn't add anything over the STL vector template, so this is a start of working the svector out. --- AStatement.cc | 5 ++++- AStatement.h | 16 +++++++++++++- PExpr.cc | 15 ++++++++++++-- PExpr.h | 11 +++++++--- elab_expr.cc | 12 +++++------ elab_net.cc | 8 +++---- net_func.cc | 2 +- parse.y | 5 ++++- pform.h | 8 ++++++- pform_analog.cc | 33 +++++++++++++++++++++++++++-- pform_dump.cc | 12 +++++++++-- svector.h | 55 ++++++++++++++----------------------------------- 12 files changed, 118 insertions(+), 64 deletions(-) diff --git a/AStatement.cc b/AStatement.cc index 4d59dffc2..a3617d6bf 100644 --- a/AStatement.cc +++ b/AStatement.cc @@ -25,12 +25,15 @@ AStatement::~AStatement() { } -AContrib::AContrib() +AContrib::AContrib(PExpr*lv, PExpr*rv) +: lval_(lv), rval_(rv) { } AContrib::~AContrib() { + delete lval_; + delete rval_; } AProcess::~AProcess() diff --git a/AStatement.h b/AStatement.h index fb00fc6ce..a1b2085ef 100644 --- a/AStatement.h +++ b/AStatement.h @@ -38,15 +38,29 @@ class AStatement : public LineInfo { AStatement& operator= (const AStatement&); }; +/* + * A contribution statement is like an assignment: there is an l-value + * expression and an r-value expression. The l-value is a branch probe + * expression. + */ class AContrib : public AStatement { public: - AContrib(); + AContrib(PExpr*lval, PExpr*rval); ~AContrib(); + virtual void dump(ostream&out, unsigned ind) const; + private: + PExpr*lval_; + PExpr*rval_; }; +/* + * An analog process is not a statement, but contains an analog + * statement. The process is where we attach process characteristics + * such as initial vs. always, attributes.... + */ class AProcess : public LineInfo { public: diff --git a/PExpr.cc b/PExpr.cc index 96428204f..ad2efbeda 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -90,7 +90,7 @@ PEBShift::~PEBShift() { } -PECallFunction::PECallFunction(const pform_name_t&n, const svector &parms) +PECallFunction::PECallFunction(const pform_name_t&n, const vector &parms) : path_(n), parms_(parms) { } @@ -103,7 +103,7 @@ static pform_name_t pn_from_ps(perm_string n) return tmp; } -PECallFunction::PECallFunction(perm_string n, const svector&parms) +PECallFunction::PECallFunction(perm_string n, const vector&parms) : path_(pn_from_ps(n)), parms_(parms) { } @@ -113,6 +113,17 @@ PECallFunction::PECallFunction(perm_string n) { } +// NOTE: Anachronism. Try to work all use of svector out. +PECallFunction::PECallFunction(const pform_name_t&n, const svector &parms) +: path_(n), parms_(vector_from_svector(parms)) +{ +} + +PECallFunction::PECallFunction(perm_string n, const svector&parms) +: path_(pn_from_ps(n)), parms_(vector_from_svector(parms)) +{ +} + PECallFunction::~PECallFunction() { } diff --git a/PExpr.h b/PExpr.h index 08dccdd29..7450e3e03 100644 --- a/PExpr.h +++ b/PExpr.h @@ -697,10 +697,15 @@ class PETernary : public PExpr { */ class PECallFunction : public PExpr { public: - explicit PECallFunction(const pform_name_t&n, const svector &parms); + explicit PECallFunction(const pform_name_t&n, const vector &parms); // Call of system function (name is not hierarchical) - explicit PECallFunction(perm_string n, const svector &parms); + explicit PECallFunction(perm_string n, const vector &parms); explicit PECallFunction(perm_string n); + + // svector versions. Should be removed! + explicit PECallFunction(const pform_name_t&n, const svector &parms); + explicit PECallFunction(perm_string n, const svector &parms); + ~PECallFunction(); virtual void dump(ostream &) const; @@ -721,7 +726,7 @@ class PECallFunction : public PExpr { private: pform_name_t path_; - svector parms_; + vector parms_; bool check_call_matches_definition_(Design*des, NetScope*dscope) const; diff --git a/elab_expr.cc b/elab_expr.cc index 2939b91d9..6f8470dbf 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -449,7 +449,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w and makes it into a signed expression. No bits are changed, it just changes the interpretation. */ if (strcmp(peek_tail_name(path_), "$signed") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $signed() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -463,7 +463,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w } /* add $unsigned to match $signed */ if (strcmp(peek_tail_name(path_), "$unsigned") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $unsigned() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -486,7 +486,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w deleted. */ if ((strcmp(peek_tail_name(path_), "$sizeof") == 0) || (strcmp(peek_tail_name(path_), "$bits") == 0)) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $bits() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -522,7 +522,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w otherwise. The subexpression is elaborated but not evaluated. */ if (strcmp(peek_tail_name(path_), "$is_signed") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $is_signed() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -558,7 +558,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w Functions cannot really take empty parameters, but the case ``func()'' is the same as no parameters at all. So catch that special case here. */ - unsigned nparms = parms_.count(); + unsigned nparms = parms_.size(); if ((nparms == 1) && (parms_[0] == 0)) nparms = 0; @@ -622,7 +622,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, if (! check_call_matches_definition_(des, dscope)) return 0; - unsigned parms_count = parms_.count(); + unsigned parms_count = parms_.size(); if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; diff --git a/elab_net.cc b/elab_net.cc index f00936882..09c040de0 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1466,7 +1466,7 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, forces it to be a signed result. Otherwise, it is as if the $signed did not exist. */ if (strcmp(name, "$signed") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $signed() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -1482,7 +1482,7 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, /* handle $unsigned like $signed */ if (strcmp(name, "$unsigned") == 0) { - if ((parms_.count() != 1) || (parms_[0] == 0)) { + if ((parms_.size() != 1) || (parms_[0] == 0)) { cerr << get_fileline() << ": error: The $unsigned() function " << "takes exactly one(1) argument." << endl; des->errors += 1; @@ -1514,7 +1514,7 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, } NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(), - def, 1+parms_.count()); + def, 1+parms_.size()); net->set_line(*this); net->rise_time(rise); net->fall_time(fall); @@ -1531,7 +1531,7 @@ NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, connect(net->pin(0), osig->pin(0)); unsigned errors = 0; - for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { + for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0, 0, 0, 0, Link::STRONG, Link::STRONG); diff --git a/net_func.cc b/net_func.cc index 5a4d4e5bb..564d16258 100644 --- a/net_func.cc +++ b/net_func.cc @@ -104,7 +104,7 @@ bool PECallFunction::check_call_matches_definition_(Design*des, NetScope*dscope) 1 nil pointer. This is how the parser tells me of no parameter. In other words, ``func()'' is 1 nil parameter. */ - unsigned parms_count = parms_.count(); + unsigned parms_count = parms_.size(); if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; diff --git a/parse.y b/parse.y index 0bea41113..af4c89bd6 100644 --- a/parse.y +++ b/parse.y @@ -283,6 +283,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %type hierarchy_identifier %type expression expr_primary expr_mintypmax %type lpvalue +%type branch_probe_expression %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper @@ -854,7 +855,9 @@ event_expression function name really is a nature attribute identifier. */ branch_probe_expression : IDENTIFIER '(' IDENTIFIER ',' IDENTIFIER ')' + { $$ = pform_make_branch_probe_expression(@1, $1, $3, $5); } | IDENTIFIER '(' IDENTIFIER ')' + { $$ = pform_make_branch_probe_expression(@1, $1, $3); } ; expression @@ -3728,7 +3731,7 @@ statement_or_null analog_statement : branch_probe_expression K_CONTRIBUTE expression ';' - { $$ = pform_contribution_statement(@2); } + { $$ = pform_contribution_statement(@2, $1, $3); } ; /* Task items are, other than the statement, task port items and diff --git a/pform.h b/pform.h index c3a5f7652..c5040585c 100644 --- a/pform.h +++ b/pform.h @@ -396,6 +396,12 @@ extern void pform_dump(ostream&out, const discipline_t*); extern void pform_make_analog_behavior(const struct vlltype&loc, AProcess::Type type, AStatement*st); -extern AStatement*pform_contribution_statement(const struct vlltype&loc); +extern AStatement*pform_contribution_statement(const struct vlltype&loc, + PExpr*lval, PExpr*rval); +extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, + char*name, char*n1, char*n2); + +extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, + char*name, char*branch); #endif diff --git a/pform_analog.cc b/pform_analog.cc index 44c080458..55408452b 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -23,9 +23,10 @@ # include "parse_misc.h" # include "AStatement.h" -AStatement* pform_contribution_statement(const struct vlltype&loc) +AStatement* pform_contribution_statement(const struct vlltype&loc, + PExpr*lval, PExpr*rval) { - AContrib*tmp = new AContrib; + AContrib*tmp = new AContrib(lval, rval); FILE_NAME(tmp, loc); return tmp; } @@ -38,3 +39,31 @@ void pform_make_analog_behavior(const struct vlltype&loc, AProcess::Type pt, pform_put_behavior_in_scope(proc); } + +PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, + char*name, char*n1, char*n2) +{ + vector parms (2); + parms[0] = new PEIdent(lex_strings.make(n1)); + FILE_NAME(parms[0], loc); + + parms[1] = new PEIdent(lex_strings.make(n2)); + FILE_NAME(parms[1], loc); + + PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); + FILE_NAME(res, loc); + return res; +} + +PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, + char*name, char*branch_name) +{ + vector parms (1); + parms[0] = new PEIdent(lex_strings.make(branch_name)); + FILE_NAME(parms[0], loc); + + PECallFunction*res = new PECallFunction(lex_strings.make(name), parms); + FILE_NAME(res, loc); + + return res; +} diff --git a/pform_dump.cc b/pform_dump.cc index 7ea9b37b1..4726aa3df 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -180,9 +180,9 @@ void PECallFunction::dump(ostream &out) const { out << path_ << "("; - if (parms_.count() > 0) { + if (parms_.size() > 0) { if (parms_[0]) parms_[0]->dump(out); - for (unsigned idx = 1; idx < parms_.count(); ++idx) { + for (unsigned idx = 1; idx < parms_.size(); ++idx) { out << ", "; if (parms_[idx]) parms_[idx]->dump(out); } @@ -541,6 +541,14 @@ void AStatement::dump(ostream&out, unsigned ind) const << " */ ;" << endl; } +void AContrib::dump(ostream&out, unsigned ind) const +{ + out << setw(ind) << ""; + out << *lval_ << " <+ " << *rval_ + << "; /* " << get_fileline() << " */" + << endl; +} + void PAssign::dump(ostream&out, unsigned ind) const { out << setw(ind) << ""; diff --git a/svector.h b/svector.h index 09181966d..c0f262e4c 100644 --- a/svector.h +++ b/svector.h @@ -1,7 +1,7 @@ #ifndef __svector_H #define __svector_H /* - * Copyright (c) 1999 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -20,12 +20,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: svector.h,v 1.11 2007/03/22 16:08:17 steve Exp $" -#endif # include "config.h" # include +# include # include /* @@ -106,41 +104,18 @@ template <> inline svector::svector(unsigned size) { } - /* - * $Log: svector.h,v $ - * Revision 1.11 2007/03/22 16:08:17 steve - * Spelling fixes from Larry - * - * Revision 1.10 2005/06/14 19:13:43 steve - * gcc3/4 compile errors. - * - * Revision 1.9 2003/07/23 02:35:44 steve - * Inline the svector constructor. - * - * Revision 1.8 2003/07/16 00:54:07 steve - * Needs the config.h header. - * - * Revision 1.7 2003/07/15 05:07:13 steve - * Move PUdp constructor into compiled file. - * - * Revision 1.6 2002/08/12 01:35:00 steve - * conditional ident string using autoconfig. - * - * Revision 1.5 2000/02/23 02:56:55 steve - * Macintosh compilers do not support ident. - * - * Revision 1.4 1999/06/15 03:44:53 steve - * Get rid of the STL vector template. - * - * Revision 1.3 1999/05/06 04:37:17 steve - * Get rid of list types. - * - * Revision 1.2 1999/05/01 02:57:53 steve - * Handle much more complex event expressions. - * - * Revision 1.1 1999/04/29 02:16:26 steve - * Parse OR of event expressions. - * - */ +* This is a convenience function that converts an svector to a +* vector. This is to ease the transition from svector to vector so +* that the svector class can be gradually removed. +*/ +template inline std::vector vector_from_svector(const svector&that) +{ + std::vector res (that.count()); + for (unsigned idx = 0 ; idx < that.count() ; idx += 1) + res[idx] = that[idx]; + + return res; +} + #endif From 78028a3310b7539b23f5b389936628e973c13b8e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 12:59:10 +0100 Subject: [PATCH 275/377] Fully support ternary expressions --- tgt-vhdl/expr.cc | 30 ++++++++++++++++++++++++++++-- tgt-vhdl/support.cc | 31 ++++++++++++++++++++++++++++++- tgt-vhdl/support.hh | 7 ++++++- 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 007abb203..0632e53f5 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -419,9 +419,35 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) static vhdl_expr *translate_ternary(ivl_expr_t e) { - error("Ternary expression only supported as RHS of assignment"); + support_function_t sf; + int width = ivl_expr_width(e); + bool issigned = ivl_expr_signed(e) != 0; + if (width == 1) + sf = SF_TERNARY_LOGIC; + else if (issigned) + sf = SF_TERNARY_SIGNED; + else + sf = SF_TERNARY_UNSIGNED; - return NULL; + require_support_function(sf); + + vhdl_expr *test = translate_expr(ivl_expr_oper1(e)); + vhdl_expr *true_part = translate_expr(ivl_expr_oper2(e)); + vhdl_expr *false_part = translate_expr(ivl_expr_oper3(e)); + if (!test || !true_part || !false_part) + return NULL; + + vhdl_type boolean(VHDL_TYPE_BOOLEAN); + test = test->cast(&boolean); + + vhdl_fcall *fcall = + new vhdl_fcall(support_function::function_name(sf), + vhdl_type::type_for(width, issigned)); + fcall->add_expr(test); + fcall->add_expr(true_part); + fcall->add_expr(false_part); + + return fcall; } static vhdl_expr *translate_concat(ivl_expr_t e) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 4c396407f..5e26f159a 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -46,6 +46,12 @@ const char *support_function::function_name(support_function_t type) return "Reduce_AND"; case SF_REDUCE_XOR: return "Reduce_XOR"; + case SF_TERNARY_LOGIC: + return "Ternary_Logic"; + case SF_TERNARY_UNSIGNED: + return "Ternary_Unsigned"; + case SF_TERNARY_SIGNED: + return "Ternary_Signed"; default: assert(false); } @@ -61,12 +67,20 @@ vhdl_type *support_function::function_type(support_function_t type) case SF_REDUCE_OR: case SF_REDUCE_AND: case SF_REDUCE_XOR: + case SF_TERNARY_LOGIC: return vhdl_type::std_logic(); default: assert(false); } } +void support_function::emit_ternary(std::ostream &of, int level) const +{ + of << "begin" << nl_string(indent(level)) + << "if T then return X; else return Y; end if;" + << nl_string(level); +} + void support_function::emit(std::ostream &of, int level) const { of << "function " << function_name(type_); @@ -80,7 +94,7 @@ void support_function::emit(std::ostream &of, int level) const case SF_SIGNED_TO_BOOLEAN: of << "(X : signed) return Boolean is" << nl_string(level) << "begin" << nl_string(indent(level)) - << "return X /= To_Signed(0, X'Length);" << nl_string (level); + << "return X /= To_Signed(0, X'Length);" << nl_string(level); break; case SF_BOOLEAN_TO_LOGIC: of << "(B : Boolean) return std_logic is" << nl_string(level) @@ -121,6 +135,21 @@ void support_function::emit(std::ostream &of, int level) const << "end loop;" << nl_string(indent(level)) << "return R;" << nl_string(level); break; + case SF_TERNARY_LOGIC: + of << "(T : Boolean; X, Y : std_logic) return std_logic is" + << nl_string(level); + emit_ternary(of, level); + break; + case SF_TERNARY_SIGNED: + of << "(T : Boolean; X, Y : signed) return signed is" + << nl_string(level); + emit_ternary(of, level); + break; + case SF_TERNARY_UNSIGNED: + of << "(T : Boolean; X, Y : signed) return unsigned is" + << nl_string(level); + emit_ternary(of, level); + break; default: assert(false); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index a5e247c94..80d6cfaff 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -24,12 +24,15 @@ #include "vhdl_syntax.hh" enum support_function_t { - SF_UNSIGNED_TO_BOOLEAN, + SF_UNSIGNED_TO_BOOLEAN = 0, SF_SIGNED_TO_BOOLEAN, SF_BOOLEAN_TO_LOGIC, SF_REDUCE_OR, SF_REDUCE_AND, SF_REDUCE_XOR, + SF_TERNARY_LOGIC, + SF_TERNARY_UNSIGNED, + SF_TERNARY_SIGNED, }; class support_function : public vhdl_function { @@ -42,6 +45,8 @@ public: static vhdl_type *function_type(support_function_t type); private: + void emit_ternary(std::ostream &of, int level) const; + support_function_t type_; }; From 3e28a1067688a1dd82abbfceb16a573f2f6e57a8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 13:02:04 +0100 Subject: [PATCH 276/377] Compress support function names a bit --- tgt-vhdl/support.cc | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 5e26f159a..0abee9fdd 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -33,28 +33,12 @@ void require_support_function(support_function_t f) const char *support_function::function_name(support_function_t type) { - 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"; - case SF_REDUCE_OR: - return "Reduce_OR"; - case SF_REDUCE_AND: - return "Reduce_AND"; - case SF_REDUCE_XOR: - return "Reduce_XOR"; - case SF_TERNARY_LOGIC: - return "Ternary_Logic"; - case SF_TERNARY_UNSIGNED: - return "Ternary_Unsigned"; - case SF_TERNARY_SIGNED: - return "Ternary_Signed"; - default: - assert(false); - } + const char *names[] = + { "Unsigned_To_Boolean", "Signed_To_Boolean", "Boolean_To_Logic", + "Reduce_OR", "Reduce_AND", "Reduce_XOR", "Ternary_Logic", + "Ternary_Unsigned", "Ternary_Signed", NULL }; + + return names[type]; } vhdl_type *support_function::function_type(support_function_t type) From 1d4914c59028e8533f62e54a1972629b1b0ae86d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 13:04:30 +0100 Subject: [PATCH 277/377] Undo last commit --- tgt-vhdl/support.cc | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 5e26f159a..08165b41a 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -34,24 +34,15 @@ void require_support_function(support_function_t f) const char *support_function::function_name(support_function_t type) { 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"; - case SF_REDUCE_OR: - return "Reduce_OR"; - case SF_REDUCE_AND: - return "Reduce_AND"; - case SF_REDUCE_XOR: - return "Reduce_XOR"; - case SF_TERNARY_LOGIC: - return "Ternary_Logic"; - case SF_TERNARY_UNSIGNED: - return "Ternary_Unsigned"; - case SF_TERNARY_SIGNED: - return "Ternary_Signed"; + 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"; + case SF_REDUCE_OR: return "Reduce_OR"; + case SF_REDUCE_AND: return "Reduce_AND"; + case SF_REDUCE_XOR: return "Reduce_XOR"; + case SF_TERNARY_LOGIC: return "Ternary_Logic"; + case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned"; + case SF_TERNARY_SIGNED: return "Ternary_Signed"; default: assert(false); } From 506a0ba7d648d66cd81d2f05552904aba65dc1e4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 21:46:19 +0100 Subject: [PATCH 278/377] Support repeat in concatenation --- tgt-vhdl/expr.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 0632e53f5..90d8891ca 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -455,7 +455,11 @@ static vhdl_expr *translate_concat(ivl_expr_t e) vhdl_type *rtype = expr_to_vhdl_type(e); vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype); - return translate_parms(concat, e); + int nrepeat = ivl_expr_repeat(e); + while (nrepeat--) + translate_parms(concat, e); + + return concat; } vhdl_expr *translate_sfunc_time(ivl_expr_t e) From f88415b1d79fd643a3ce8833fc2dcdd94d8a5c95 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 22:46:39 +0100 Subject: [PATCH 279/377] Conversion of std_logic to integer --- tgt-vhdl/cast.cc | 10 +++++++++- tgt-vhdl/support.cc | 9 +++++++++ tgt-vhdl/support.hh | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index a3d571b53..167efc4d2 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -70,7 +70,15 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) } } else if (to->get_name() == VHDL_TYPE_INTEGER) { - vhdl_fcall *conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); + vhdl_fcall *conv; + if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { + require_support_function(SF_LOGIC_TO_INTEGER); + conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER), + vhdl_type::integer()); + } + else + conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); + conv->add_expr(this); return conv; diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 08165b41a..1c4e3e862 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -43,6 +43,7 @@ const char *support_function::function_name(support_function_t type) case SF_TERNARY_LOGIC: return "Ternary_Logic"; case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned"; case SF_TERNARY_SIGNED: return "Ternary_Signed"; + case SF_LOGIC_TO_INTEGER: return "Logic_To_Integer"; default: assert(false); } @@ -60,6 +61,8 @@ vhdl_type *support_function::function_type(support_function_t type) case SF_REDUCE_XOR: case SF_TERNARY_LOGIC: return vhdl_type::std_logic(); + case SF_LOGIC_TO_INTEGER: + return vhdl_type::integer(); default: assert(false); } @@ -141,6 +144,12 @@ void support_function::emit(std::ostream &of, int level) const << nl_string(level); emit_ternary(of, level); break; + case SF_LOGIC_TO_INTEGER: + of << "(X : std_logic) return integer is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "if X = '1' then return 1; else return 0; end if;" + << nl_string(level); + break; default: assert(false); } diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index 80d6cfaff..2cbee0c7b 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -33,6 +33,7 @@ enum support_function_t { SF_TERNARY_LOGIC, SF_TERNARY_UNSIGNED, SF_TERNARY_SIGNED, + SF_LOGIC_TO_INTEGER, }; class support_function : public vhdl_function { From 7a2e9c02cd0de0e70d9f1bffd33b07130d3df003 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 28 Jul 2008 22:48:21 +0100 Subject: [PATCH 280/377] Simplify support function emitting code --- tgt-vhdl/support.cc | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 1c4e3e862..7b0de5d76 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -70,9 +70,8 @@ vhdl_type *support_function::function_type(support_function_t type) void support_function::emit_ternary(std::ostream &of, int level) const { - of << "begin" << nl_string(indent(level)) - << "if T then return X; else return Y; end if;" - << nl_string(level); + of << nl_string(level) << "begin" << nl_string(indent(level)) + << "if T then return X; else return Y; end if;"; } void support_function::emit(std::ostream &of, int level) const @@ -83,12 +82,12 @@ void support_function::emit(std::ostream &of, int level) const case SF_UNSIGNED_TO_BOOLEAN: of << "(X : unsigned) return Boolean is" << nl_string(level) << "begin" << nl_string(indent(level)) - << "return X /= To_Unsigned(0, X'Length);" << nl_string(level); + << "return X /= To_Unsigned(0, X'Length);"; break; case SF_SIGNED_TO_BOOLEAN: of << "(X : signed) return Boolean is" << nl_string(level) << "begin" << nl_string(indent(level)) - << "return X /= To_Signed(0, X'Length);" << nl_string(level); + << "return X /= To_Signed(0, X'Length);"; break; case SF_BOOLEAN_TO_LOGIC: of << "(B : Boolean) return std_logic is" << nl_string(level) @@ -97,7 +96,7 @@ void support_function::emit(std::ostream &of, int level) const << "return '1';" << nl_string(indent(level)) << "else" << nl_string(indent(indent(level))) << "return '0';" << nl_string(indent(level)) - << "end if;" << nl_string(level); + << "end if;"; break; case SF_REDUCE_OR: of << "(X : std_logic_vector) return std_logic is" << nl_string(level) @@ -107,7 +106,7 @@ void support_function::emit(std::ostream &of, int level) const << "return '1';" << nl_string(indent(indent(level))) << "end if;" << nl_string(indent(level)) << "end loop;" << nl_string(indent(level)) - << "return '0';" << nl_string(level); + << "return '0';"; break; case SF_REDUCE_AND: of << "(X : std_logic_vector) return std_logic is" << nl_string(level) @@ -117,7 +116,7 @@ void support_function::emit(std::ostream &of, int level) const << "return '0';" << nl_string(indent(indent(level))) << "end if;" << nl_string(indent(level)) << "end loop;" << nl_string(indent(level)) - << "return '1';" << nl_string(level); + << "return '1';"; break; case SF_REDUCE_XOR: of << "(X : std_logic_vector) return std_logic is" @@ -127,32 +126,28 @@ void support_function::emit(std::ostream &of, int level) const << "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); + << "return R;"; break; case SF_TERNARY_LOGIC: - of << "(T : Boolean; X, Y : std_logic) return std_logic is" - << nl_string(level); + of << "(T : Boolean; X, Y : std_logic) return std_logic is"; emit_ternary(of, level); break; case SF_TERNARY_SIGNED: - of << "(T : Boolean; X, Y : signed) return signed is" - << nl_string(level); + of << "(T : Boolean; X, Y : signed) return signed is"; emit_ternary(of, level); break; case SF_TERNARY_UNSIGNED: - of << "(T : Boolean; X, Y : signed) return unsigned is" - << nl_string(level); + of << "(T : Boolean; X, Y : signed) return unsigned is"; emit_ternary(of, level); break; case SF_LOGIC_TO_INTEGER: of << "(X : std_logic) return integer is" << nl_string(level) << "begin" << nl_string(indent(level)) - << "if X = '1' then return 1; else return 0; end if;" - << nl_string(level); + << "if X = '1' then return 1; else return 0; end if;"; break; default: assert(false); } - of << "end function;" << nl_string(level); + of << nl_string(level) << "end function;" << nl_string(level); } From 65c2ceb89d11e0942bd354517fe39e23da54194f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 11:01:02 +0100 Subject: [PATCH 281/377] Build entity hierarchy in separate stages --- tgt-vhdl/scope.cc | 144 ++++++++++++++++++++++++++++------------------ tgt-vhdl/vhdl.cc | 2 +- 2 files changed, 89 insertions(+), 57 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 826def5ad..7a1ae8cac 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -408,50 +408,6 @@ static void declare_lpm(vhdl_arch *arch, ivl_scope_t scope) } } -/* - * Create a VHDL entity for scopes of type IVL_SCT_MODULE. - */ -static vhdl_entity *create_entity_for(ivl_scope_t scope) -{ - assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - - // The type name will become the entity name - const char *tname = ivl_scope_tname(scope); - - // Remember the scope name this entity was derived from so - // the correct processes can be added later - const char *derived_from = ivl_scope_name(scope); - - // Verilog does not have the entity/architecture distinction - // so we always create a pair and associate the architecture - // with the entity for convenience (this also means that we - // 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 - declare_signals(ent, 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; - ss << "Generated from Verilog module " << ivl_scope_tname(scope); - - arch->set_comment(ss.str()); - ent->set_comment(ss.str()); - - remember_entity(ent); - return ent; -} - /* * Map two signals together in an instantiation. * The signals are joined by a nexus. @@ -569,6 +525,7 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, /* * Instantiate an entity in the hierarchy, and possibly create * that entity if it hasn't been encountered yet. + * DEPRECATE */ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) { @@ -576,8 +533,8 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) // Maybe we need to create this entity first? vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); - if (NULL == ent) - ent = create_entity_for(scope); + /* if (NULL == ent) + ent = create_entity_for(scope);*/ assert(ent); set_active_entity(ent); @@ -633,7 +590,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) /* * Create a VHDL function from a Verilog function definition. */ -int draw_function(ivl_scope_t scope, ivl_scope_t parent) +static int draw_function(ivl_scope_t scope, ivl_scope_t parent) { assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION); @@ -688,31 +645,106 @@ int draw_function(ivl_scope_t scope, ivl_scope_t parent) return 0; } -int draw_scope(ivl_scope_t scope, void *_parent) +/* + * Create an empty VHDL entity for a Verilog module. + */ +static void create_skeleton_entity_for(ivl_scope_t scope) { - ivl_scope_t parent = static_cast(_parent); + assert(ivl_scope_type(scope) == IVL_SCT_MODULE); + + // The type name will become the entity name + const char *tname = ivl_scope_tname(scope); + + // Remember the scope name this entity was derived from so + // the correct processes can be added later + const char *derived_from = ivl_scope_name(scope); + + // Verilog does not have the entity/architecture distinction + // so we always create a pair and associate the architecture + // with the entity for convenience (this also means that we + // 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); + + // Build a comment to add to the entity/architecture + std::ostringstream ss; + ss << "Generated from Verilog module " << ivl_scope_tname(scope); + + arch->set_comment(ss.str()); + ent->set_comment(ss.str()); + + remember_entity(ent); +} + +/* + * A first pass through the hierarchy: create VHDL entities for + * each unique Verilog module type. + */ +static int draw_skeleton_scope(ivl_scope_t scope, void *_parent) +{ + //ivl_scope_t parent = static_cast(_parent); ivl_scope_type_t type = ivl_scope_type(scope); - int rc = 0; switch (type) { case IVL_SCT_MODULE: - rc = draw_module(scope, parent); + // Create this entity if it doesn't already exist + if (find_entity(ivl_scope_tname(scope)) == NULL) { + create_skeleton_entity_for(scope); + cout << "Created skeleton entity for " << ivl_scope_tname(scope) << endl; + } break; case IVL_SCT_FUNCTION: - rc = draw_function(scope, parent); - break; default: error("No VHDL conversion for %s (at %s)", ivl_scope_tname(scope), ivl_scope_name(scope)); break; } - if (rc != 0) - return rc; - rc = ivl_scope_children(scope, draw_scope, scope); + return ivl_scope_children(scope, draw_skeleton_scope, scope); +} + +static int draw_all_signals(ivl_scope_t scope, void *_parent) +{ + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + assert(ent); + + if (ent->get_derived_from() == ivl_scope_name(scope)) + declare_signals(ent, scope); + } + + return ivl_scope_children(scope, draw_all_signals, scope); +} + +static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) +{ + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + assert(ent); + + if (ent->get_derived_from() == ivl_scope_name(scope)) { + declare_logic(ent->get_arch(), scope); + declare_lpm(ent->get_arch(), scope); + } + } + + return ivl_scope_children(scope, draw_all_logic_and_lpm, scope); +} + +int draw_scope(ivl_scope_t scope, void *_parent) +{ + int rc = draw_skeleton_scope(scope, _parent); if (rc != 0) return rc; + + rc = draw_all_signals(scope, _parent); + if (rc != 0) + return rc; + + rc = draw_all_logic_and_lpm(scope, _parent); + if (rc != 0) + return rc; return 0; } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 35c30e4f9..ecc6bffc4 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -158,7 +158,7 @@ extern "C" int target_design(ivl_design_t des) for (unsigned int i = 0; i < nroots; i++) draw_scope(roots[i], NULL); - ivl_design_process(des, draw_process, NULL); + //ivl_design_process(des, draw_process, NULL); // Write the generated elements to the output file // only if there are no errors From 8a5f129e567cbfddbf033f4756aea1ca2233c269 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 12:00:26 +0100 Subject: [PATCH 282/377] Draw nexus in multiple passes --- tgt-vhdl/scope.cc | 151 ++++++++++++++++++++++++++++++++++------ tgt-vhdl/vhdl.cc | 6 +- tgt-vhdl/vhdl_syntax.cc | 10 +++ tgt-vhdl/vhdl_syntax.hh | 1 + tgt-vhdl/vhdl_target.h | 4 +- 5 files changed, 147 insertions(+), 25 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 7a1ae8cac..1b170f7be 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -59,7 +59,7 @@ enum 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, +/*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); @@ -112,17 +112,132 @@ static vhdl_expr *nexus_to_expr(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 *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) { return dynamic_cast (nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF)); + }*/ + +/* + * This structure is stored in the private part of each nexus. + * It stores a signal for each VHDL scope which is connected to + * that nexus. It's stored as a list so we can use contained_within + * to allow several nested scopes to reference the same signal. + */ +struct nexus_private_t { + struct scope_signal_map_t { + vhdl_scope *scope; + ivl_signal_t sig; + }; + + list signals; +}; + +/* + * Remember that sig is the representative of this nexus in scope. + */ +static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, + ivl_signal_t sig) +{ + nexus_private_t::scope_signal_map_t sigmap = { scope, sig }; + priv->signals.push_back(sigmap); } +/* + * Find a signal that is connected to this nexus that is visible + * in this scope. + */ +static ivl_signal_t visible_nexus_signal(nexus_private_t *priv, vhdl_scope *scope) +{ + list::iterator it; + for (it = priv->signals.begin(); it != priv->signals.end(); ++it) { + if (scope->contained_within((*it).scope)) + return (*it).sig; + } + return NULL; +} + +/* + * Generates VHDL code to fully represent a nexus. + */ +void draw_nexus(ivl_nexus_t nexus) +{ + nexus_private_t *priv = new nexus_private_t; + + int nptrs = ivl_nexus_ptrs(nexus); + + // First pass through connect all the signals up + 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))) { + cout << "signal " << ivl_signal_basename(sig) << endl; + + vhdl_scope *scope = find_scope_for_signal(sig); + + ivl_signal_t linked; + if ((linked = visible_nexus_signal(priv, scope))) { + cout << "...should be linked to " << ivl_signal_name(linked) << endl; + assert(false); + } + else { + cout << "...represents this nexus in scope " << hex << scope << endl; + link_scope_to_nexus_signal(priv, scope, sig); + } + } + } + + // Second pass through make sure logic/LPMs have signal + // inputs and outputs + for (int i = 0; i < nptrs; i++) { + ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); + + ivl_net_logic_t log; + ivl_lpm_t lpm; + ivl_net_const_t con; + if ((log = ivl_nexus_ptr_log(nexus_ptr))) { + /* + ivl_signal_t linked; + if ((linked = visible_nexus_signal(*/ + } + else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { + assert(false); + } + } + + // Save the private data in the nexus + ivl_nexus_set_private(nexus, priv); +} + +/* + * Translate a nexus to a variable reference. Given a nexus and a + * scope, this function returns a reference to a signal that is + * connected to the nexus and within the given scope. This signal + * might not exist in the original Verilog source (even as a + * compiler-generated temporary). If this nexus hasn't been + * encountered before, the necessary code to connect up the nexus + * will be generated. + */ + vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) + { + cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; + + if (ivl_nexus_get_private(nexus) == NULL) { + cout << "first time we've seen this nexus" << endl; + + draw_nexus(nexus); + } + + assert(false); + } + + /* * Convert the inputs of a logic gate to a binary expression. */ @@ -137,7 +252,7 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, int npins = ivl_logic_pins(log); for (int i = 1; i < npins; i++) { ivl_nexus_t input = ivl_logic_pin(log, i); - gate->add_expr(nexus_to_expr(scope, input)); + gate->add_expr(nexus_to_var_ref(scope, input)); } return gate; @@ -152,7 +267,7 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, ivl_nexus_t input = ivl_logic_pin(log, 1); assert(input); - vhdl_expr *operand = nexus_to_expr(scope, input); + vhdl_expr *operand = nexus_to_var_ref(scope, input); return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic()); } @@ -162,10 +277,10 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) 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)); + vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); assert(val); - vhdl_expr *sel = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 2)); + vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2)); assert(val); vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1'); @@ -205,7 +320,7 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) return inputs_to_expr(scope, VHDL_BINOP_XOR, log); case IVL_LO_BUF: case IVL_LO_BUFZ: - return nexus_to_expr(scope, ivl_logic_pin(log, 1)); + return nexus_to_var_ref(scope, ivl_logic_pin(log, 1)); case IVL_LO_PULLUP: return new vhdl_const_bit('1'); case IVL_LO_PULLDOWN: @@ -238,10 +353,7 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) { // 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_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output); vhdl_expr *rhs = translate_logic(arch->get_scope(), log); vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); @@ -331,11 +443,10 @@ 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_expr(ent->get_scope(), ivl_signal_nex(sig, 0), - NEXUS_TO_CONST); + /*vhdl_expr *init = + nexus_to_var_ref(ent->get_scope(), ivl_signal_nex(sig, 0)); if (init != NULL) - decl->set_initial(init); + decl->set_initial(init);*/ ent->get_arch()->get_scope()->add_decl(decl); } @@ -352,13 +463,13 @@ 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 = + /*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)); - } + }*/ ent->get_scope()->add_decl(decl); } @@ -418,8 +529,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, NEXUS_TO_ANY); + vhdl_expr *to_e = nexus_to_var_ref(parent->get_arch()->get_scope(), + nexus); assert(to_e); // The expressions in a VHDL port map must be 'globally static' diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index ecc6bffc4..a8571d9fc 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -39,7 +39,7 @@ */ struct signal_defn_t { std::string renamed; // The name of the VHDL signal - const vhdl_scope *scope; // The scope where it is defined + vhdl_scope *scope; // The scope where it is defined }; typedef std::map signal_defn_map_t; @@ -98,7 +98,7 @@ bool seen_signal_before(ivl_signal_t sig) /* * Remeber the association of signal to entity. */ -void remember_signal(ivl_signal_t sig, const vhdl_scope *scope) +void remember_signal(ivl_signal_t sig, vhdl_scope *scope) { assert(!seen_signal_before(sig)); @@ -116,7 +116,7 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed) g_known_signals[sig].renamed = renamed; } -const vhdl_scope *find_scope_for_signal(ivl_signal_t sig) +vhdl_scope *find_scope_for_signal(ivl_signal_t sig) { assert(seen_signal_before(sig)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 3b3099518..7378cf4ce 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -64,6 +64,16 @@ bool vhdl_scope::have_declared(const std::string &name) const return get_decl(name) != NULL; } +bool vhdl_scope::contained_within(const vhdl_scope *other) const +{ + if (this == other) + return true; + else if (NULL == parent_) + return false; + else + return parent_->contained_within(other); +} + vhdl_scope *vhdl_scope::get_parent() const { assert(parent_); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 538842052..0595e97cb 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -608,6 +608,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; + bool contained_within(const vhdl_scope *other) const; vhdl_scope *get_parent() const; bool empty() const { return decls_.empty(); } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 62e784845..b42bad48a 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -35,9 +35,9 @@ void set_active_entity(vhdl_entity *ent); 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 remember_signal(ivl_signal_t sig, vhdl_scope *scope); void rename_signal(ivl_signal_t sig, const string &renamed); -const vhdl_scope *find_scope_for_signal(ivl_signal_t sig); +vhdl_scope *find_scope_for_signal(ivl_signal_t sig); const string &get_renamed_signal(ivl_signal_t sig); ivl_signal_t find_signal_named(const string &name, const vhdl_scope *scope); From 1a45e9164fda063ccdfca458f96c509558792be9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 12:04:40 +0100 Subject: [PATCH 283/377] Find signal a logic device is connected to --- tgt-vhdl/scope.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 1b170f7be..e1d083b14 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -202,9 +202,20 @@ void draw_nexus(ivl_nexus_t nexus) ivl_lpm_t lpm; ivl_net_const_t con; if ((log = ivl_nexus_ptr_log(nexus_ptr))) { - /* + ivl_scope_t log_scope = ivl_logic_scope(log); + vhdl_scope *vhdl_scope = + find_entity(ivl_scope_tname(log_scope))->get_arch()->get_scope(); + + cout << "logic " << ivl_logic_basename(log) << endl; + ivl_signal_t linked; - if ((linked = visible_nexus_signal(*/ + if ((linked = visible_nexus_signal(priv, vhdl_scope))) { + cout << "...linked to signal " << ivl_signal_name(linked) << endl; + } + else { + cout << "...has no signal!" << endl; + assert(false); + } } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { assert(false); From c0c838f1bce3ffc2c19117fa3d69b554e9b9effa Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 12:11:44 +0100 Subject: [PATCH 284/377] Logic devices now working again --- tgt-vhdl/scope.cc | 17 ++++++++++++++++- tgt-vhdl/vhdl.cc | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index e1d083b14..ff1dc027c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -244,8 +244,23 @@ void draw_nexus(ivl_nexus_t nexus) draw_nexus(nexus); } + + nexus_private_t *priv = + static_cast(ivl_nexus_get_private(nexus)); + assert(priv); + + ivl_signal_t sig = visible_nexus_signal(priv, scope); + assert(sig); + + const string &renamed = get_renamed_signal(sig); + + cout << "--> signal " << renamed << endl; + + vhdl_decl *decl = scope->get_decl(renamed); + assert(decl); - assert(false); + vhdl_type *type = new vhdl_type(*(decl->get_type())); + return new vhdl_var_ref(renamed.c_str(), type); } diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index a8571d9fc..621fd593b 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -158,7 +158,7 @@ extern "C" int target_design(ivl_design_t des) for (unsigned int i = 0; i < nroots; i++) draw_scope(roots[i], NULL); - //ivl_design_process(des, draw_process, NULL); + ivl_design_process(des, draw_process, NULL); // Write the generated elements to the output file // only if there are no errors From c6f6ea7358919fd427ae44aaa5c5dc2999d2ff0c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 12:21:19 +0100 Subject: [PATCH 285/377] Instantiation working again --- tgt-vhdl/scope.cc | 83 ++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index ff1dc027c..338da18a6 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -684,37 +684,7 @@ static int draw_module(ivl_scope_t scope, ivl_scope_t parent) // example of this module in the hieararchy if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { - vhdl_arch *parent_arch = parent_ent->get_arch(); - assert(parent_arch != NULL); - // Create a forward declaration for it - if (!parent_arch->get_scope()->have_declared(ent->get_name())) { - vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); - parent_arch->get_scope()->add_decl(comp_decl); - } - - // And an instantiation statement - 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()); - port_map(scope, parent_ent, inst); - - parent_arch->add_stmt(inst); } else { // Ignore this instantiation (already accounted for) @@ -869,6 +839,55 @@ static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) return ivl_scope_children(scope, draw_all_logic_and_lpm, scope); } +static int draw_hierarchy(ivl_scope_t scope, void *_parent) +{ + if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) { + ivl_scope_t parent = static_cast(_parent); + + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + assert(ent); + + vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); + assert(parent_ent); + + if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { + vhdl_arch *parent_arch = parent_ent->get_arch(); + assert(parent_arch != NULL); + + // Create a forward declaration for it + if (!parent_arch->get_scope()->have_declared(ent->get_name())) { + vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); + parent_arch->get_scope()->add_decl(comp_decl); + } + + // And an instantiation statement + 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()); + //port_map(scope, parent_ent, inst); + + parent_arch->add_stmt(inst); + } + } + + return ivl_scope_children(scope, draw_hierarchy, scope); +} + int draw_scope(ivl_scope_t scope, void *_parent) { int rc = draw_skeleton_scope(scope, _parent); @@ -882,6 +901,10 @@ int draw_scope(ivl_scope_t scope, void *_parent) rc = draw_all_logic_and_lpm(scope, _parent); if (rc != 0) return rc; + + rc = draw_hierarchy(scope, _parent); + if (rc != 0) + return rc; return 0; } From c26b7ce67597740ead390d7c59cadffcbb05c646 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 13:02:55 +0100 Subject: [PATCH 286/377] Port maps --- tgt-vhdl/scope.cc | 149 +++++++++++++--------------------------------- 1 file changed, 43 insertions(+), 106 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 338da18a6..69861211b 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -555,80 +555,52 @@ 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_var_ref(parent->get_arch()->get_scope(), - nexus); - assert(to_e); + vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus); - // The expressions in a VHDL port map must be 'globally static' - // i.e. they can't be arbitrary expressions - // To handle this, only vhdl_var_refs are mapped automatically - // Otherwise a temporary variable is created to store the - // result of the expression and that is mapped to the port - // This is actually a bit stricter than necessary: but turns out - // to be much easier to implement - std::string name = make_safe_name(to); - vhdl_var_ref *to_ref; - if ((to_ref = dynamic_cast(to_e))) { - // 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) { + string name = make_safe_name(to); + + // 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(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 + string shadow_name(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 + (ref, new vhdl_var_ref(shadow_name.c_str(), NULL))); - // 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); - } + // Make sure any future references to this signal read the + // shadow not the output + ivl_signal_t sig = find_signal_named(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 a static expression - std::string tmpname(inst->get_inst_name().c_str()); - tmpname += "_"; - tmpname += name; - tmpname += "_Expr"; - - vhdl_type *tmptype = new vhdl_type(*to_e->get_type()); - parent->get_arch()->get_scope()->add_decl - (new vhdl_signal_decl(tmpname.c_str(), tmptype)); - - vhdl_var_ref *tmp_ref1 = new vhdl_var_ref(tmpname.c_str(), NULL); - parent->get_arch()->add_stmt(new vhdl_cassign_stmt(tmp_ref1, to_e)); - - vhdl_var_ref *tmp_ref2 = new vhdl_var_ref(*tmp_ref1); - inst->map_port(name.c_str(), tmp_ref2); + // Not an output port declaration therefore we can + // definitely read it + inst->map_port(name.c_str(), ref); } } @@ -659,41 +631,6 @@ static void port_map(ivl_scope_t scope, vhdl_entity *parent, } } -/* - * Instantiate an entity in the hierarchy, and possibly create - * that entity if it hasn't been encountered yet. - * DEPRECATE - */ -static int draw_module(ivl_scope_t scope, ivl_scope_t parent) -{ - assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - - // Maybe we need to create this entity first? - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); - /* if (NULL == ent) - ent = create_entity_for(scope);*/ - assert(ent); - set_active_entity(ent); - - // Is this module instantiated inside another? - if (parent != NULL) { - vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); - assert(parent_ent != NULL); - - // Make sure we only collect instantiations from *one* - // example of this module in the hieararchy - if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { - - - } - else { - // Ignore this instantiation (already accounted for) - } - } - - return 0; -} - /* * Create a VHDL function from a Verilog function definition. */ @@ -879,7 +816,7 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); - //port_map(scope, parent_ent, inst); + port_map(scope, parent_ent, inst); parent_arch->add_stmt(inst); } From 39717989a8bdba8acbb90d0498a78a05e1e0f484 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 13:04:29 +0100 Subject: [PATCH 287/377] Call set_active_entity in the right places --- tgt-vhdl/process.cc | 1 + tgt-vhdl/scope.cc | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 5276feed6..1c19e776c 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -71,6 +71,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) ss << ivl_scope_tname(scope); vhdl_proc->set_comment(ss.str()); + set_active_entity(NULL); return 0; } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 69861211b..6dbe66be9 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -768,8 +768,12 @@ static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) assert(ent); if (ent->get_derived_from() == ivl_scope_name(scope)) { - declare_logic(ent->get_arch(), scope); - declare_lpm(ent->get_arch(), scope); + set_active_entity(ent); + { + declare_logic(ent->get_arch(), scope); + declare_lpm(ent->get_arch(), scope); + } + set_active_entity(NULL); } } From 680c6f0503d2c9ba5078a9c157857839d2d91abd Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 13:06:21 +0100 Subject: [PATCH 288/377] Make sure LPMs have valid inputs/outputs --- tgt-vhdl/scope.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 6dbe66be9..737371b22 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -218,7 +218,20 @@ void draw_nexus(ivl_nexus_t nexus) } } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - assert(false); + ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); + vhdl_scope *vhdl_scope = + find_entity(ivl_scope_tname(lpm_scope))->get_arch()->get_scope(); + + cout << "LPM " << ivl_lpm_basename(lpm) << endl; + + ivl_signal_t linked; + if ((linked = visible_nexus_signal(priv, vhdl_scope))) { + cout << "...linked to signal " << ivl_signal_name(linked) << endl; + } + else { + cout << "...has no signal!" << endl; + assert(false); + } } } From d94dac28a8544798b6ba8def09eea379123976fe Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 13:08:13 +0100 Subject: [PATCH 289/377] Remove redundant lpm_output --- tgt-vhdl/lpm.cc | 39 ++++++++------------------------------- tgt-vhdl/vhdl_target.h | 1 - 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index e3370b263..b3d92b466 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -40,36 +40,6 @@ static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm) 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 = @@ -295,7 +265,14 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) if (NULL == f) return 0; - vhdl_var_ref *out = lpm_output(arch->get_scope(), lpm); + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); + if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) { + vhdl_expr *off = part_select_base(arch->get_scope(), lpm); + assert(off); + + out->set_slice(off, ivl_lpm_width(lpm) - 1); + } + arch->add_stmt(new vhdl_cassign_stmt(out, f)); return 0; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index b42bad48a..bd786a3ca 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -23,7 +23,6 @@ int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); vhdl_expr *translate_expr(ivl_expr_t e); vhdl_expr *translate_time_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 f8034d69efc9aea6a741b359352b38bac7c6dce9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 13:30:54 +0100 Subject: [PATCH 290/377] Fix constants in nexuses --- tgt-vhdl/expr.cc | 6 ++++ tgt-vhdl/scope.cc | 79 +++++++++++++++++++++++++----------------- tgt-vhdl/vhdl_target.h | 1 + 3 files changed, 55 insertions(+), 31 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 90d8891ca..657492d45 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -56,6 +56,12 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); + // Make sure the nexus code is generated + for (unsigned i = ivl_signal_array_base(sig); + i < ivl_signal_array_count(sig); + i++) + seen_nexus(ivl_signal_nex(sig, i)); + const vhdl_scope *scope = find_scope_for_signal(sig); assert(scope); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 737371b22..50f4a1d41 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -201,6 +201,7 @@ void draw_nexus(ivl_nexus_t nexus) ivl_net_logic_t log; ivl_lpm_t lpm; ivl_net_const_t con; + ivl_signal_t linked; if ((log = ivl_nexus_ptr_log(nexus_ptr))) { ivl_scope_t log_scope = ivl_logic_scope(log); vhdl_scope *vhdl_scope = @@ -208,7 +209,6 @@ void draw_nexus(ivl_nexus_t nexus) cout << "logic " << ivl_logic_basename(log) << endl; - ivl_signal_t linked; if ((linked = visible_nexus_signal(priv, vhdl_scope))) { cout << "...linked to signal " << ivl_signal_name(linked) << endl; } @@ -224,7 +224,6 @@ void draw_nexus(ivl_nexus_t nexus) cout << "LPM " << ivl_lpm_basename(lpm) << endl; - ivl_signal_t linked; if ((linked = visible_nexus_signal(priv, vhdl_scope))) { cout << "...linked to signal " << ivl_signal_name(linked) << endl; } @@ -233,11 +232,54 @@ void draw_nexus(ivl_nexus_t nexus) assert(false); } } + else if ((con = ivl_nexus_ptr_con(nexus_ptr))) { + cout << "CONSTANT" << endl; + + list::iterator it; + for (it = priv->signals.begin(); it != priv->signals.end(); ++it) { + cout << "...linked to signal " << ivl_signal_name((*it).sig) << endl; + + // Make this the initial value of the signal + const string &renamed = get_renamed_signal((*it).sig); + vhdl_decl *decl = + find_scope_for_signal((*it).sig)->get_decl(renamed); + assert(decl); + + if (!decl->has_initial()) { + if (ivl_const_width(con) == 1) + decl->set_initial + (new vhdl_const_bit(ivl_const_bits(con)[0])); + else + decl->set_initial + (new vhdl_const_bits(ivl_const_bits(con), + ivl_const_width(con), + ivl_const_signed(con) != 0)); + } + else { + error("signal %s has two constant drivers!?", renamed.c_str()); + assert(false); + } + } + } } - + // Save the private data in the nexus ivl_nexus_set_private(nexus, priv); } + +/* + * Ensure that a nexus has been initialised. I.e. all the necessary + * statements, declarations, etc. have been generated. + */ +void seen_nexus(ivl_nexus_t nexus) +{ + if (ivl_nexus_get_private(nexus) == NULL) { + cout << "first time we've seen nexus " + << ivl_nexus_name(nexus) << endl; + + draw_nexus(nexus); + } +} /* * Translate a nexus to a variable reference. Given a nexus and a @@ -252,12 +294,8 @@ void draw_nexus(ivl_nexus_t nexus) { cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; - if (ivl_nexus_get_private(nexus) == NULL) { - cout << "first time we've seen this nexus" << endl; - - draw_nexus(nexus); - } - + seen_nexus(nexus); + nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); assert(priv); @@ -478,15 +516,6 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) case IVL_SIP_NONE: { vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); - - // 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_var_ref(ent->get_scope(), ivl_signal_nex(sig, 0)); - if (init != NULL) - decl->set_initial(init);*/ - ent->get_arch()->get_scope()->add_decl(decl); } break; @@ -497,19 +526,7 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) case IVL_SIP_OUTPUT: { 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_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)); - }*/ - + new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); ent->get_scope()->add_decl(decl); } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index bd786a3ca..6a8fcf99b 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -32,6 +32,7 @@ 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); +void seen_nexus(ivl_nexus_t nexus); bool seen_signal_before(ivl_signal_t sig); void remember_signal(ivl_signal_t sig, vhdl_scope *scope); From a842b327c726494d23916983ff10689929e5fd30 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 14:02:05 +0100 Subject: [PATCH 291/377] Generate constant drivers as concurrent assignments --- tgt-vhdl/expr.cc | 6 ---- tgt-vhdl/scope.cc | 89 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 657492d45..df604099d 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -55,12 +55,6 @@ static vhdl_expr *translate_string(ivl_expr_t e) static vhdl_var_ref *translate_signal(ivl_expr_t e) { ivl_signal_t sig = ivl_expr_signal(e); - - // Make sure the nexus code is generated - for (unsigned i = ivl_signal_array_base(sig); - i < ivl_signal_array_count(sig); - i++) - seen_nexus(ivl_signal_nex(sig, i)); const vhdl_scope *scope = find_scope_for_signal(sig); assert(scope); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 50f4a1d41..5f4c7ddce 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -136,6 +136,7 @@ struct nexus_private_t { }; list signals; + vhdl_expr *const_driver; }; /* @@ -168,6 +169,7 @@ static ivl_signal_t visible_nexus_signal(nexus_private_t *priv, vhdl_scope *scop void draw_nexus(ivl_nexus_t nexus) { nexus_private_t *priv = new nexus_private_t; + priv->const_driver = NULL; int nptrs = ivl_nexus_ptrs(nexus); @@ -234,32 +236,13 @@ void draw_nexus(ivl_nexus_t nexus) } else if ((con = ivl_nexus_ptr_con(nexus_ptr))) { cout << "CONSTANT" << endl; - - list::iterator it; - for (it = priv->signals.begin(); it != priv->signals.end(); ++it) { - cout << "...linked to signal " << ivl_signal_name((*it).sig) << endl; - - // Make this the initial value of the signal - const string &renamed = get_renamed_signal((*it).sig); - vhdl_decl *decl = - find_scope_for_signal((*it).sig)->get_decl(renamed); - assert(decl); - - if (!decl->has_initial()) { - if (ivl_const_width(con) == 1) - decl->set_initial - (new vhdl_const_bit(ivl_const_bits(con)[0])); - else - decl->set_initial - (new vhdl_const_bits(ivl_const_bits(con), - ivl_const_width(con), - ivl_const_signed(con) != 0)); - } - else { - error("signal %s has two constant drivers!?", renamed.c_str()); - assert(false); - } - } + + if (ivl_const_width(con) == 1) + priv->const_driver = new vhdl_const_bit(ivl_const_bits(con)[0]); + else + priv->const_driver = + new vhdl_const_bits(ivl_const_bits(con), ivl_const_width(con), + ivl_const_signed(con) != 0); } } @@ -791,6 +774,56 @@ static int draw_all_signals(ivl_scope_t scope, void *_parent) return ivl_scope_children(scope, draw_all_signals, scope); } +/* + * Make concurrent assignments for constants in nets. This works + * bottom-up so that the driver is in the lowest instance it can. + * This also has the side effect of generating all the necessary + * nexus code. + */ +static int draw_constant_drivers(ivl_scope_t scope, void *_parent) +{ + ivl_scope_children(scope, draw_constant_drivers, scope); + + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { + vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + assert(ent); + + if (ent->get_derived_from() == ivl_scope_name(scope)) { + int nsigs = ivl_scope_sigs(scope); + for (int i = 0; i < nsigs; i++) { + ivl_signal_t sig = ivl_scope_sig(scope, i); + + for (unsigned i = ivl_signal_array_base(sig); + i < ivl_signal_array_count(sig); + i++) { + // Make sure the nexus code is generated + ivl_nexus_t nex = ivl_signal_nex(sig, i); + seen_nexus(nex); + + assert(i == 0); // TODO: Make work for more words + nexus_private_t *priv = + static_cast(ivl_nexus_get_private(nex)); + assert(priv); + + if (priv->const_driver) { + cout << "NEEDS CONST DRIVER!" << endl; + cout << "(in scope " << ivl_scope_name(scope) << endl; + + vhdl_var_ref *ref = + nexus_to_var_ref(ent->get_arch()->get_scope(), nex); + + ent->get_arch()->add_stmt + (new vhdl_cassign_stmt(ref, priv->const_driver)); + priv->const_driver = NULL; + } + } + } + } + } + + return 0; +} + static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE) { @@ -876,6 +909,10 @@ int draw_scope(ivl_scope_t scope, void *_parent) rc = draw_hierarchy(scope, _parent); if (rc != 0) return rc; + + rc = draw_constant_drivers(scope, _parent); + if (rc != 0) + return rc; return 0; } From 48c1a7982c4f03f91d7a4557bd5a03c3192417e8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 14:24:04 +0100 Subject: [PATCH 292/377] Make seen_nexus private --- tgt-vhdl/scope.cc | 2 +- tgt-vhdl/vhdl_target.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5f4c7ddce..8f611f84b 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -254,7 +254,7 @@ void draw_nexus(ivl_nexus_t nexus) * Ensure that a nexus has been initialised. I.e. all the necessary * statements, declarations, etc. have been generated. */ -void seen_nexus(ivl_nexus_t nexus) +static void seen_nexus(ivl_nexus_t nexus) { if (ivl_nexus_get_private(nexus) == NULL) { cout << "first time we've seen nexus " diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 6a8fcf99b..bd786a3ca 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -32,7 +32,6 @@ 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); -void seen_nexus(ivl_nexus_t nexus); bool seen_signal_before(ivl_signal_t sig); void remember_signal(ivl_signal_t sig, vhdl_scope *scope); From e037ffd952816f6b31165aede55bf09f3aaaa9b8 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 15:09:58 +0100 Subject: [PATCH 293/377] Create temporaries for LPM outputs --- tgt-vhdl/scope.cc | 104 +++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 37 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 8f611f84b..b1233875c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -123,19 +123,26 @@ enum vhdl_nexus_obj_t { (nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF)); }*/ + +/* + * TODO: COMMENT + */ +struct scope_nexus_t { + vhdl_scope *scope; + ivl_signal_t sig; // A real signal + string tmpname; // A new temporary signal +}; + + /* * This structure is stored in the private part of each nexus. - * It stores a signal for each VHDL scope which is connected to - * that nexus. It's stored as a list so we can use contained_within - * to allow several nested scopes to reference the same signal. + * It stores a scope_nexus_t for each VHDL scope which is + * connected to that nexus. It's stored as a list so we can use + * contained_within to allow several nested scopes to reference + * the same signal. */ struct nexus_private_t { - struct scope_signal_map_t { - vhdl_scope *scope; - ivl_signal_t sig; - }; - - list signals; + list signals; vhdl_expr *const_driver; }; @@ -145,24 +152,44 @@ struct nexus_private_t { static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, ivl_signal_t sig) { - nexus_private_t::scope_signal_map_t sigmap = { scope, sig }; + scope_nexus_t sigmap = { scope, sig, "" }; priv->signals.push_back(sigmap); } /* - * Find a signal that is connected to this nexus that is visible - * in this scope. + * Make a temporary the representative of this nexus in scope. */ -static ivl_signal_t visible_nexus_signal(nexus_private_t *priv, vhdl_scope *scope) +static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope, + const string &name) { - list::iterator it; + scope_nexus_t sigmap = { scope, NULL, name }; + priv->signals.push_back(sigmap); +} + +/* + * Returns the scope_nexus_t of this nexus visible within scope. + */ +static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope) +{ + list::iterator it; for (it = priv->signals.begin(); it != priv->signals.end(); ++it) { if (scope->contained_within((*it).scope)) - return (*it).sig; + return &*it; } return NULL; } +/* + * Finds the name of the nexus signal within this scope. + */ +static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope) +{ + scope_nexus_t *sn = visible_nexus(priv, scope); + assert(sn); + + return sn->sig ? get_renamed_signal(sn->sig) : sn->tmpname; +} + /* * Generates VHDL code to fully represent a nexus. */ @@ -183,9 +210,9 @@ void draw_nexus(ivl_nexus_t nexus) vhdl_scope *scope = find_scope_for_signal(sig); - ivl_signal_t linked; - if ((linked = visible_nexus_signal(priv, scope))) { - cout << "...should be linked to " << ivl_signal_name(linked) << endl; + if (visible_nexus(priv, scope)) { + cout << "...should be linked to " + << visible_nexus_signal_name(priv, scope) << endl; assert(false); } else { @@ -203,16 +230,16 @@ void draw_nexus(ivl_nexus_t nexus) ivl_net_logic_t log; ivl_lpm_t lpm; ivl_net_const_t con; - ivl_signal_t linked; if ((log = ivl_nexus_ptr_log(nexus_ptr))) { ivl_scope_t log_scope = ivl_logic_scope(log); vhdl_scope *vhdl_scope = find_entity(ivl_scope_tname(log_scope))->get_arch()->get_scope(); cout << "logic " << ivl_logic_basename(log) << endl; - - if ((linked = visible_nexus_signal(priv, vhdl_scope))) { - cout << "...linked to signal " << ivl_signal_name(linked) << endl; + + if (visible_nexus(priv, vhdl_scope)) { + cout << "...linked to signal " + << visible_nexus_signal_name(priv, vhdl_scope) << endl; } else { cout << "...has no signal!" << endl; @@ -226,12 +253,20 @@ void draw_nexus(ivl_nexus_t nexus) cout << "LPM " << ivl_lpm_basename(lpm) << endl; - if ((linked = visible_nexus_signal(priv, vhdl_scope))) { - cout << "...linked to signal " << ivl_signal_name(linked) << endl; + if (visible_nexus(priv, vhdl_scope)) { + cout << "...linked to signal " + << visible_nexus_signal_name(priv, vhdl_scope) << endl; } else { - cout << "...has no signal!" << endl; - assert(false); + // Create a temporary signal to connect the nexus + // TODO: we could avoid this for IVL_LPM_PART_PV + vhdl_type *type = vhdl_type::type_for(ivl_lpm_width(lpm), + ivl_lpm_signed(lpm) != 0); + ostringstream ss; + ss << "LPM" << ivl_lpm_basename(lpm); + vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); + + link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } } else if ((con = ivl_nexus_ptr_con(nexus_ptr))) { @@ -278,23 +313,18 @@ static void seen_nexus(ivl_nexus_t nexus) cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; seen_nexus(nexus); - + nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); - assert(priv); - - ivl_signal_t sig = visible_nexus_signal(priv, scope); - assert(sig); - - const string &renamed = get_renamed_signal(sig); - + string renamed(visible_nexus_signal_name(priv, scope)); + cout << "--> signal " << renamed << endl; - + vhdl_decl *decl = scope->get_decl(renamed); assert(decl); - + vhdl_type *type = new vhdl_type(*(decl->get_type())); - return new vhdl_var_ref(renamed.c_str(), type); + return new vhdl_var_ref(renamed.c_str(), type); } From 25602e487d38b5323299a1c490e12c8405650823 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 15:12:51 +0100 Subject: [PATCH 294/377] Comment --- tgt-vhdl/scope.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b1233875c..5246d902d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -125,7 +125,11 @@ enum vhdl_nexus_obj_t { /* - * TODO: COMMENT + * This represents the portion of a nexus that is visible within + * a VHDL scope. If that nexus portion does not contain a signal, + * then `tmpname' gives the name of the temporary that will be + * used when this nexus is used in `scope' (e.g. for LPMs that + * appear in instantiations). */ struct scope_nexus_t { vhdl_scope *scope; From 5ec2c37e7e808a5869b3d52fd4470f370fca001d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 15:29:49 +0100 Subject: [PATCH 295/377] Get functions working again --- tgt-vhdl/scope.cc | 50 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5246d902d..d94232324 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -691,12 +691,7 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) const char *funcname = ivl_scope_tname(scope); - // Has this function been declared already? - // (draw_function will be invoked multiple times for - // the same function if it appears multiple times in - // the design hierarchy) - if (ent->get_arch()->get_scope()->have_declared(funcname)) - return 0; + assert(!ent->get_arch()->get_scope()->have_declared(funcname)); // The return type is worked out from the output port vhdl_function *func = new vhdl_function(funcname, NULL); @@ -729,8 +724,12 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) // Non-blocking assignment not allowed in functions func->get_scope()->set_allow_signal_assignment(false); - - draw_stmt(func, func->get_container(), ivl_scope_def(scope)); + + set_active_entity(ent); + { + draw_stmt(func, func->get_container(), ivl_scope_def(scope)); + } + set_active_entity(NULL); ent->get_arch()->get_scope()->add_decl(func); return 0; @@ -773,23 +772,12 @@ static void create_skeleton_entity_for(ivl_scope_t scope) */ static int draw_skeleton_scope(ivl_scope_t scope, void *_parent) { - //ivl_scope_t parent = static_cast(_parent); - - ivl_scope_type_t type = ivl_scope_type(scope); - switch (type) { - case IVL_SCT_MODULE: + if (ivl_scope_type(scope) == IVL_SCT_MODULE) { // Create this entity if it doesn't already exist if (find_entity(ivl_scope_tname(scope)) == NULL) { create_skeleton_entity_for(scope); cout << "Created skeleton entity for " << ivl_scope_tname(scope) << endl; } - break; - case IVL_SCT_FUNCTION: - default: - error("No VHDL conversion for %s (at %s)", - ivl_scope_tname(scope), - ivl_scope_name(scope)); - break; } return ivl_scope_children(scope, draw_skeleton_scope, scope); @@ -808,6 +796,24 @@ static int draw_all_signals(ivl_scope_t scope, void *_parent) return ivl_scope_children(scope, draw_all_signals, scope); } +/* + * Draw all tasks and functions in the hierarchy. + */ +static int draw_functions(ivl_scope_t scope, void *_parent) +{ + ivl_scope_t parent = static_cast(_parent); + if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) { + vhdl_entity *ent = find_entity(ivl_scope_tname(parent)); + assert(ent); + + if (ent->get_derived_from() == ivl_scope_name(parent)) + if (draw_function(scope, parent) != 0) + return 1; + } + + return ivl_scope_children(scope, draw_functions, scope); +} + /* * Make concurrent assignments for constants in nets. This works * bottom-up so that the driver is in the lowest instance it can. @@ -944,6 +950,10 @@ int draw_scope(ivl_scope_t scope, void *_parent) if (rc != 0) return rc; + rc = draw_functions(scope, _parent); + if (rc != 0) + return rc; + rc = draw_constant_drivers(scope, _parent); if (rc != 0) return rc; From c9454b346ea043b78d18ab1e0d3725af1c684fd5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 19:04:41 +0100 Subject: [PATCH 296/377] Fix module3.12B --- tgt-vhdl/scope.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d94232324..2bec7d411 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -211,6 +211,11 @@ void draw_nexus(ivl_nexus_t nexus) ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { cout << "signal " << ivl_signal_basename(sig) << endl; + + if (!seen_signal_before(sig)) { + remember_signal(sig, NULL); + continue; + } vhdl_scope *scope = find_scope_for_signal(sig); @@ -601,6 +606,17 @@ 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); + seen_nexus(nexus); + + vhdl_scope *arch_scope = parent->get_arch()->get_scope(); + + nexus_private_t *priv = + static_cast(ivl_nexus_get_private(nexus)); + assert(priv); + if (!visible_nexus(priv, arch_scope)) { + // This nexus isn't attached to anything in the parent + return; + } vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus); From 744fbed7834497509af8327ef7112d4dea9d79fe Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 19:33:40 +0100 Subject: [PATCH 297/377] Finish re-writing nexus code --- tgt-vhdl/expr.cc | 2 +- tgt-vhdl/process.cc | 12 +- tgt-vhdl/scope.cc | 293 ++++++++++++++--------------------------- tgt-vhdl/vhdl.cc | 22 +++- tgt-vhdl/vhdl_target.h | 2 +- 5 files changed, 115 insertions(+), 216 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index df604099d..7ad67c3ee 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -406,7 +406,7 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) // A function is always declared in a module, which should have // a corresponding entity by this point: so we can get type // information, etc. from the declaration - vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parentscope)); + vhdl_entity *parent_ent = find_entity(ivl_scope_name(parentscope)); assert(parent_ent); const char *funcname = ivl_scope_tname(defscope); diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 1c19e776c..9e5b83207 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -83,16 +83,8 @@ int draw_process(ivl_process_t proc, void *cd) // A process should occur in a module scope, therefore it // should have already been assigned a VHDL entity assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + vhdl_entity *ent = find_entity(ivl_scope_name(scope)); assert(ent != NULL); - // If the scope this process belongs to is the same as the - // VHDL entity was generated from, then create a VHDL process - // from this Verilog process. This ensures that each process - // is translated at most once, no matter how many times it - // appears in the hierarchy. - if (ent->get_derived_from() == scope_name) - return generate_vhdl_process(ent, proc); - else - return 0; + return generate_vhdl_process(ent, proc); } diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2bec7d411..dd984dec1 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -40,90 +40,6 @@ void set_active_entity(vhdl_entity *ent) g_active_entity = ent; } - -/* - * The types of VHDL object a nexus can be converted into. - */ -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, 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) -{ - 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; - ivl_net_logic_t log; - ivl_lpm_t lpm; - 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) || - (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); - vhdl_type *type = new vhdl_type(*(decl->get_type())); - return new vhdl_var_ref(signame, type); - } - else if ((allowed & NEXUS_TO_OTHER) && - (log = ivl_nexus_ptr_log(nexus_ptr))) { - return translate_logic(arch_scope, log); - } - else if ((allowed & NEXUS_TO_OTHER) && - (lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { - return lpm_output(arch_scope, lpm); - } - 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); - } - 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 { - // Ignore other types of nexus pointer - } - } - - return NULL; - }*/ - -/* - * Guarantees the result will never be NULL. - */ - /*vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus) -{ - return dynamic_cast - (nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF)); - }*/ - - /* * This represents the portion of a nexus that is visible within * a VHDL scope. If that nexus portion does not contain a signal, @@ -137,7 +53,6 @@ struct scope_nexus_t { string tmpname; // A new temporary signal }; - /* * This structure is stored in the private part of each nexus. * It stores a scope_nexus_t for each VHDL scope which is @@ -211,11 +126,6 @@ void draw_nexus(ivl_nexus_t nexus) ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { cout << "signal " << ivl_signal_basename(sig) << endl; - - if (!seen_signal_before(sig)) { - remember_signal(sig, NULL); - continue; - } vhdl_scope *scope = find_scope_for_signal(sig); @@ -242,7 +152,7 @@ void draw_nexus(ivl_nexus_t nexus) if ((log = ivl_nexus_ptr_log(nexus_ptr))) { ivl_scope_t log_scope = ivl_logic_scope(log); vhdl_scope *vhdl_scope = - find_entity(ivl_scope_tname(log_scope))->get_arch()->get_scope(); + find_entity(ivl_scope_name(log_scope))->get_arch()->get_scope(); cout << "logic " << ivl_logic_basename(log) << endl; @@ -258,7 +168,7 @@ void draw_nexus(ivl_nexus_t nexus) else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); vhdl_scope *vhdl_scope = - find_entity(ivl_scope_tname(lpm_scope))->get_arch()->get_scope(); + find_entity(ivl_scope_name(lpm_scope))->get_arch()->get_scope(); cout << "LPM " << ivl_lpm_basename(lpm) << endl; @@ -317,26 +227,25 @@ static void seen_nexus(ivl_nexus_t nexus) * encountered before, the necessary code to connect up the nexus * will be generated. */ - vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) - { - cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; - - seen_nexus(nexus); - - nexus_private_t *priv = - static_cast(ivl_nexus_get_private(nexus)); - string renamed(visible_nexus_signal_name(priv, scope)); - - cout << "--> signal " << renamed << endl; - - vhdl_decl *decl = scope->get_decl(renamed); - assert(decl); - - vhdl_type *type = new vhdl_type(*(decl->get_type())); - return new vhdl_var_ref(renamed.c_str(), type); - } +vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) +{ + cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; + + seen_nexus(nexus); + + nexus_private_t *priv = + static_cast(ivl_nexus_get_private(nexus)); + string renamed(visible_nexus_signal_name(priv, scope)); + + cout << "--> signal " << renamed << endl; + + vhdl_decl *decl = scope->get_decl(renamed); + assert(decl); + + vhdl_type *type = new vhdl_type(*(decl->get_type())); + return new vhdl_var_ref(renamed.c_str(), type); +} - /* * Convert the inputs of a logic gate to a binary expression. */ @@ -470,9 +379,9 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) /* * Make sure a signal name conforms to VHDL naming rules. */ -static std::string make_safe_name(ivl_signal_t sig) +static string make_safe_name(ivl_signal_t sig) { - std::string name(ivl_signal_basename(sig)); + string name(ivl_signal_basename(sig)); if (name[0] == '_') name.insert(0, "VL"); @@ -702,7 +611,7 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) assert(ivl_scope_type(scope) == IVL_SCT_FUNCTION); // Find the containing entity - vhdl_entity *ent = find_entity(ivl_scope_tname(parent)); + vhdl_entity *ent = find_entity(ivl_scope_name(parent)); assert(ent); const char *funcname = ivl_scope_tname(scope); @@ -773,7 +682,7 @@ static void create_skeleton_entity_for(ivl_scope_t scope) vhdl_entity *ent = new vhdl_entity(tname, derived_from, arch); // Build a comment to add to the entity/architecture - std::ostringstream ss; + ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope); arch->set_comment(ss.str()); @@ -789,11 +698,9 @@ static void create_skeleton_entity_for(ivl_scope_t scope) static int draw_skeleton_scope(ivl_scope_t scope, void *_parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE) { - // Create this entity if it doesn't already exist - if (find_entity(ivl_scope_tname(scope)) == NULL) { - create_skeleton_entity_for(scope); - cout << "Created skeleton entity for " << ivl_scope_tname(scope) << endl; - } + create_skeleton_entity_for(scope); + cout << "Created skeleton entity for " << ivl_scope_tname(scope) + << " from instance " << ivl_scope_name(scope) << endl; } return ivl_scope_children(scope, draw_skeleton_scope, scope); @@ -802,11 +709,10 @@ static int draw_skeleton_scope(ivl_scope_t scope, void *_parent) static int draw_all_signals(ivl_scope_t scope, void *_parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE) { - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + vhdl_entity *ent = find_entity(ivl_scope_name(scope)); assert(ent); - if (ent->get_derived_from() == ivl_scope_name(scope)) - declare_signals(ent, scope); + declare_signals(ent, scope); } return ivl_scope_children(scope, draw_all_signals, scope); @@ -819,12 +725,11 @@ static int draw_functions(ivl_scope_t scope, void *_parent) { ivl_scope_t parent = static_cast(_parent); if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) { - vhdl_entity *ent = find_entity(ivl_scope_tname(parent)); + vhdl_entity *ent = find_entity(ivl_scope_name(parent)); assert(ent); - - if (ent->get_derived_from() == ivl_scope_name(parent)) - if (draw_function(scope, parent) != 0) - return 1; + + if (draw_function(scope, parent) != 0) + return 1; } return ivl_scope_children(scope, draw_functions, scope); @@ -841,37 +746,35 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) ivl_scope_children(scope, draw_constant_drivers, scope); if (ivl_scope_type(scope) == IVL_SCT_MODULE) { - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + vhdl_entity *ent = find_entity(ivl_scope_name(scope)); assert(ent); - if (ent->get_derived_from() == ivl_scope_name(scope)) { - int nsigs = ivl_scope_sigs(scope); - for (int i = 0; i < nsigs; i++) { - ivl_signal_t sig = ivl_scope_sig(scope, i); + int nsigs = ivl_scope_sigs(scope); + for (int i = 0; i < nsigs; i++) { + ivl_signal_t sig = ivl_scope_sig(scope, i); + + for (unsigned i = ivl_signal_array_base(sig); + i < ivl_signal_array_count(sig); + i++) { + // Make sure the nexus code is generated + ivl_nexus_t nex = ivl_signal_nex(sig, i); + seen_nexus(nex); + + assert(i == 0); // TODO: Make work for more words + nexus_private_t *priv = + static_cast(ivl_nexus_get_private(nex)); + assert(priv); - for (unsigned i = ivl_signal_array_base(sig); - i < ivl_signal_array_count(sig); - i++) { - // Make sure the nexus code is generated - ivl_nexus_t nex = ivl_signal_nex(sig, i); - seen_nexus(nex); - - assert(i == 0); // TODO: Make work for more words - nexus_private_t *priv = - static_cast(ivl_nexus_get_private(nex)); - assert(priv); - - if (priv->const_driver) { - cout << "NEEDS CONST DRIVER!" << endl; - cout << "(in scope " << ivl_scope_name(scope) << endl; - - vhdl_var_ref *ref = - nexus_to_var_ref(ent->get_arch()->get_scope(), nex); - - ent->get_arch()->add_stmt - (new vhdl_cassign_stmt(ref, priv->const_driver)); - priv->const_driver = NULL; - } + if (priv->const_driver) { + cout << "NEEDS CONST DRIVER!" << endl; + cout << "(in scope " << ivl_scope_name(scope) << endl; + + vhdl_var_ref *ref = + nexus_to_var_ref(ent->get_arch()->get_scope(), nex); + + ent->get_arch()->add_stmt + (new vhdl_cassign_stmt(ref, priv->const_driver)); + priv->const_driver = NULL; } } } @@ -883,17 +786,15 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) static int draw_all_logic_and_lpm(ivl_scope_t scope, void *_parent) { if (ivl_scope_type(scope) == IVL_SCT_MODULE) { - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + vhdl_entity *ent = find_entity(ivl_scope_name(scope)); assert(ent); - if (ent->get_derived_from() == ivl_scope_name(scope)) { - set_active_entity(ent); - { - declare_logic(ent->get_arch(), scope); - declare_lpm(ent->get_arch(), scope); - } - set_active_entity(NULL); + set_active_entity(ent); + { + declare_logic(ent->get_arch(), scope); + declare_lpm(ent->get_arch(), scope); } + set_active_entity(NULL); } return ivl_scope_children(scope, draw_all_logic_and_lpm, scope); @@ -904,45 +805,43 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) if (ivl_scope_type(scope) == IVL_SCT_MODULE && _parent) { ivl_scope_t parent = static_cast(_parent); - vhdl_entity *ent = find_entity(ivl_scope_tname(scope)); + vhdl_entity *ent = find_entity(ivl_scope_name(scope)); assert(ent); - vhdl_entity *parent_ent = find_entity(ivl_scope_tname(parent)); + vhdl_entity *parent_ent = find_entity(ivl_scope_name(parent)); assert(parent_ent); - if (parent_ent->get_derived_from() == ivl_scope_name(parent)) { - vhdl_arch *parent_arch = parent_ent->get_arch(); - assert(parent_arch != NULL); + vhdl_arch *parent_arch = parent_ent->get_arch(); + assert(parent_arch != NULL); - // Create a forward declaration for it - if (!parent_arch->get_scope()->have_declared(ent->get_name())) { - vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); - parent_arch->get_scope()->add_decl(comp_decl); - } - - // And an instantiation statement - 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()); - port_map(scope, parent_ent, inst); - - parent_arch->add_stmt(inst); + // Create a forward declaration for it + if (!parent_arch->get_scope()->have_declared(ent->get_name())) { + vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); + parent_arch->get_scope()->add_decl(comp_decl); } + + // And an instantiation statement + 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()); + port_map(scope, parent_ent, inst); + + parent_arch->add_stmt(inst); } return ivl_scope_children(scope, draw_hierarchy, scope); diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 621fd593b..a82f583d3 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -29,6 +29,7 @@ #include #include #include +#include /* * Maps a signal to the scope it is defined within. Also @@ -68,13 +69,13 @@ void error(const char *fmt, ...) } /* - * Find an entity given a type name. + * Find an entity given a scope name. */ -vhdl_entity *find_entity(const std::string &tname) +vhdl_entity *find_entity(const std::string &sname) { entity_list_t::const_iterator it; for (it = g_entities.begin(); it != g_entities.end(); ++it) { - if ((*it)->get_name() == tname) + if ((*it)->get_derived_from() == sname) return *it; } return NULL; @@ -86,7 +87,7 @@ vhdl_entity *find_entity(const std::string &tname) */ void remember_entity(vhdl_entity* ent) { - assert(find_entity(ent->get_name()) == NULL); + assert(find_entity(ent->get_derived_from()) == NULL); g_entities.push_back(ent); } @@ -164,12 +165,19 @@ extern "C" int target_design(ivl_design_t des) // only if there are no errors if (0 == g_errors) { const char *ofname = ivl_design_flag(des, "-o"); - std::ofstream outfile(ofname); + ofstream outfile(ofname); + + // Make sure we only emit one example of each type of entity + set seen_entities; for (entity_list_t::iterator it = g_entities.begin(); it != g_entities.end(); - ++it) - (*it)->emit(outfile); + ++it) { + if (seen_entities.find((*it)->get_name()) == seen_entities.end()) { + (*it)->emit(outfile); + seen_entities.insert((*it)->get_name()); + } + } outfile.close(); } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index bd786a3ca..430961cbf 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -25,7 +25,7 @@ vhdl_expr *translate_expr(ivl_expr_t e); vhdl_expr *translate_time_expr(ivl_expr_t e); void remember_entity(vhdl_entity *ent); -vhdl_entity *find_entity(const string &tname); +vhdl_entity *find_entity(const string &sname); ivl_design_t get_vhdl_design(); vhdl_entity *get_active_entity(); From 3bcd42dc8f1a5769272e591a903a987ac01302b4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 19:39:20 +0100 Subject: [PATCH 298/377] Fix case where logic device has no valid output --- tgt-vhdl/scope.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index dd984dec1..158ad0091 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -162,7 +162,16 @@ void draw_nexus(ivl_nexus_t nexus) } else { cout << "...has no signal!" << endl; - assert(false); + + // Create a temporary signal to connect it to the nexus + vhdl_type *type = + vhdl_type::type_for(ivl_logic_width(log), false); + + ostringstream ss; + ss << "LO" << ivl_logic_basename(log); + vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); + + link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } } else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) { From eaf1cc9120afaebfeca2b199b9c83f453b278172 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 19:47:17 +0100 Subject: [PATCH 299/377] Fix assertion failure with arrayed signals --- tgt-vhdl/scope.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 158ad0091..80ff7b6e6 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -769,12 +769,13 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) ivl_nexus_t nex = ivl_signal_nex(sig, i); seen_nexus(nex); - assert(i == 0); // TODO: Make work for more words nexus_private_t *priv = static_cast(ivl_nexus_get_private(nex)); assert(priv); if (priv->const_driver) { + assert(i == 0); // TODO: Make work for more words + cout << "NEEDS CONST DRIVER!" << endl; cout << "(in scope " << ivl_scope_name(scope) << endl; From 9a5b7bb0b0a83c46c87dc61fe96a39016108d812 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 21:03:00 +0100 Subject: [PATCH 300/377] Connect signals together if joined in a nexus --- tgt-vhdl/scope.cc | 92 ++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 37 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 80ff7b6e6..f60dd301a 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -45,12 +45,14 @@ void set_active_entity(vhdl_entity *ent) * a VHDL scope. If that nexus portion does not contain a signal, * then `tmpname' gives the name of the temporary that will be * used when this nexus is used in `scope' (e.g. for LPMs that - * appear in instantiations). + * appear in instantiations). The list `connect' lists all the + * signals that should be joined together to re-create the net. */ struct scope_nexus_t { vhdl_scope *scope; - ivl_signal_t sig; // A real signal - string tmpname; // A new temporary signal + ivl_signal_t sig; // A real signal + string tmpname; // A new temporary signal + list connect; // Other signals to wire together }; /* @@ -65,26 +67,6 @@ struct nexus_private_t { vhdl_expr *const_driver; }; -/* - * Remember that sig is the representative of this nexus in scope. - */ -static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, - ivl_signal_t sig) -{ - scope_nexus_t sigmap = { scope, sig, "" }; - priv->signals.push_back(sigmap); -} - -/* - * Make a temporary the representative of this nexus in scope. - */ -static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope, - const string &name) -{ - scope_nexus_t sigmap = { scope, NULL, name }; - priv->signals.push_back(sigmap); -} - /* * Returns the scope_nexus_t of this nexus visible within scope. */ @@ -98,6 +80,38 @@ static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope) return NULL; } +/* + * Remember that a signal in `scope' is part of this nexus. The + * first signal passed to this function for a scope will be used + * as the canonical representation of this nexus when we need to + * convert it to a variable reference (e.g. in a LPM input/output). + */ +static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, + ivl_signal_t sig) +{ + scope_nexus_t *sn; + if ((sn = visible_nexus(priv, scope))) { + assert(sn->tmpname == ""); + + cout << "need to tie up " << get_renamed_signal(sig) << endl; + sn->connect.push_back(sig); + } + else { + scope_nexus_t new_sn = { scope, sig, "" }; + priv->signals.push_back(new_sn); + } +} + +/* + * Make a temporary the representative of this nexus in scope. + */ +static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope, + const string &name) +{ + scope_nexus_t new_sn = { scope, NULL, name }; + priv->signals.push_back(new_sn); +} + /* * Finds the name of the nexus signal within this scope. */ @@ -128,16 +142,7 @@ void draw_nexus(ivl_nexus_t nexus) cout << "signal " << ivl_signal_basename(sig) << endl; vhdl_scope *scope = find_scope_for_signal(sig); - - if (visible_nexus(priv, scope)) { - cout << "...should be linked to " - << visible_nexus_signal_name(priv, scope) << endl; - assert(false); - } - else { - cout << "...represents this nexus in scope " << hex << scope << endl; - link_scope_to_nexus_signal(priv, scope, sig); - } + link_scope_to_nexus_signal(priv, scope, sig); } } @@ -637,7 +642,7 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - std::string signame = make_safe_name(sig); + string signame(make_safe_name(sig)); switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: @@ -773,19 +778,32 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) static_cast(ivl_nexus_get_private(nex)); assert(priv); + vhdl_scope *arch_scope = ent->get_arch()->get_scope(); + if (priv->const_driver) { assert(i == 0); // TODO: Make work for more words cout << "NEEDS CONST DRIVER!" << endl; cout << "(in scope " << ivl_scope_name(scope) << endl; - - vhdl_var_ref *ref = - nexus_to_var_ref(ent->get_arch()->get_scope(), nex); + + vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex); ent->get_arch()->add_stmt (new vhdl_cassign_stmt(ref, priv->const_driver)); priv->const_driver = NULL; } + + scope_nexus_t *sn = visible_nexus(priv, arch_scope); + for (list::const_iterator it = sn->connect.begin(); + it != sn->connect.end(); + ++it) { + vhdl_var_ref *rref = + new vhdl_var_ref(get_renamed_signal(sn->sig).c_str(), NULL); + vhdl_var_ref *lref = + new vhdl_var_ref(get_renamed_signal(*it).c_str(), NULL); + ent->get_arch()->add_stmt(new vhdl_cassign_stmt(lref, rref)); + } + sn->connect.clear(); } } } From 9f6f711f8d5d2ce1c6983a03076aecd08ca05736 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 21:08:50 +0100 Subject: [PATCH 301/377] Remove unused variable --- tgt-vhdl/process.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 9e5b83207..432278ce5 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -78,7 +78,6 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) int draw_process(ivl_process_t proc, void *cd) { ivl_scope_t scope = ivl_process_scope(proc); - const char *scope_name = ivl_scope_name(scope); // A process should occur in a module scope, therefore it // should have already been assigned a VHDL entity From e5b8abfb23c63cbada5690ba76f3f0dbd65bd6e0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 29 Jul 2008 21:15:51 +0100 Subject: [PATCH 302/377] Remove debugging output --- tgt-vhdl/scope.cc | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index f60dd301a..36e45f90c 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -26,7 +26,7 @@ #include static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); -static std::string make_safe_name(ivl_signal_t sig); +static string make_safe_name(ivl_signal_t sig); static vhdl_entity *g_active_entity = NULL; @@ -93,7 +93,6 @@ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, if ((sn = visible_nexus(priv, scope))) { assert(sn->tmpname == ""); - cout << "need to tie up " << get_renamed_signal(sig) << endl; sn->connect.push_back(sig); } else { @@ -138,9 +137,7 @@ void draw_nexus(ivl_nexus_t nexus) ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i); ivl_signal_t sig; - if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { - cout << "signal " << ivl_signal_basename(sig) << endl; - + if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { vhdl_scope *scope = find_scope_for_signal(sig); link_scope_to_nexus_signal(priv, scope, sig); } @@ -159,15 +156,10 @@ void draw_nexus(ivl_nexus_t nexus) vhdl_scope *vhdl_scope = find_entity(ivl_scope_name(log_scope))->get_arch()->get_scope(); - cout << "logic " << ivl_logic_basename(log) << endl; - if (visible_nexus(priv, vhdl_scope)) { - cout << "...linked to signal " - << visible_nexus_signal_name(priv, vhdl_scope) << endl; + // Already seen this signal in vhdl_scope } else { - cout << "...has no signal!" << endl; - // Create a temporary signal to connect it to the nexus vhdl_type *type = vhdl_type::type_for(ivl_logic_width(log), false); @@ -184,11 +176,8 @@ void draw_nexus(ivl_nexus_t nexus) vhdl_scope *vhdl_scope = find_entity(ivl_scope_name(lpm_scope))->get_arch()->get_scope(); - cout << "LPM " << ivl_lpm_basename(lpm) << endl; - if (visible_nexus(priv, vhdl_scope)) { - cout << "...linked to signal " - << visible_nexus_signal_name(priv, vhdl_scope) << endl; + // Already seen this signal in vhdl_scope } else { // Create a temporary signal to connect the nexus @@ -203,8 +192,6 @@ void draw_nexus(ivl_nexus_t nexus) } } else if ((con = ivl_nexus_ptr_con(nexus_ptr))) { - cout << "CONSTANT" << endl; - if (ivl_const_width(con) == 1) priv->const_driver = new vhdl_const_bit(ivl_const_bits(con)[0]); else @@ -224,12 +211,8 @@ void draw_nexus(ivl_nexus_t nexus) */ static void seen_nexus(ivl_nexus_t nexus) { - if (ivl_nexus_get_private(nexus) == NULL) { - cout << "first time we've seen nexus " - << ivl_nexus_name(nexus) << endl; - + if (ivl_nexus_get_private(nexus) == NULL) draw_nexus(nexus); - } } /* @@ -243,16 +226,12 @@ static void seen_nexus(ivl_nexus_t nexus) */ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) { - cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl; - seen_nexus(nexus); nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); string renamed(visible_nexus_signal_name(priv, scope)); - cout << "--> signal " << renamed << endl; - vhdl_decl *decl = scope->get_decl(renamed); assert(decl); @@ -711,12 +690,9 @@ static void create_skeleton_entity_for(ivl_scope_t scope) */ static int draw_skeleton_scope(ivl_scope_t scope, void *_parent) { - if (ivl_scope_type(scope) == IVL_SCT_MODULE) { + if (ivl_scope_type(scope) == IVL_SCT_MODULE) create_skeleton_entity_for(scope); - cout << "Created skeleton entity for " << ivl_scope_tname(scope) - << " from instance " << ivl_scope_name(scope) << endl; - } - + return ivl_scope_children(scope, draw_skeleton_scope, scope); } @@ -783,9 +759,6 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) if (priv->const_driver) { assert(i == 0); // TODO: Make work for more words - cout << "NEEDS CONST DRIVER!" << endl; - cout << "(in scope " << ivl_scope_name(scope) << endl; - vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex); ent->get_arch()->add_stmt From baa2363e85ce75a57bb5e594064126c0fbe9e5d0 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 30 Jul 2008 10:13:08 +0100 Subject: [PATCH 303/377] Split logic device code into separate file --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/logic.cc | 146 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/scope.cc | 124 +--------------------------------- tgt-vhdl/vhdl_target.h | 1 + 4 files changed, 150 insertions(+), 123 deletions(-) create mode 100644 tgt-vhdl/logic.cc diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 36727ce67..bbd0cfeaf 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 cast.o + stmt.o expr.o lpm.o display.o support.o cast.o logic.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc new file mode 100644 index 000000000..4edd12bb3 --- /dev/null +++ b/tgt-vhdl/logic.cc @@ -0,0 +1,146 @@ +/* + * VHDL code generation for logic 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 "vhdl_element.hh" + +#include + + +/* + * Convert the inputs of a logic gate to a binary expression. + */ +static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, + ivl_net_logic_t log) +{ + // Not always std_logic but this is probably OK since + // the program has already been type checked + vhdl_binop_expr *gate = + new vhdl_binop_expr(op, vhdl_type::std_logic()); + + int npins = ivl_logic_pins(log); + for (int i = 1; i < npins; i++) { + ivl_nexus_t input = ivl_logic_pin(log, i); + gate->add_expr(nexus_to_var_ref(scope, input)); + } + + return gate; +} + +/* + * Convert a gate intput to an unary expression. + */ +static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, + ivl_net_logic_t log) +{ + ivl_nexus_t input = ivl_logic_pin(log, 1); + assert(input); + + vhdl_expr *operand = nexus_to_var_ref(scope, input); + 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_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); + assert(val); + + vhdl_expr *sel = nexus_to_var_ref(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); + + 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); + + arch->add_stmt(cass); +} + +static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) +{ + switch (ivl_logic_type(log)) { + case IVL_LO_NOT: + return input_to_expr(scope, VHDL_UNARYOP_NOT, log); + case IVL_LO_AND: + return inputs_to_expr(scope, VHDL_BINOP_AND, log); + case IVL_LO_OR: + return inputs_to_expr(scope, VHDL_BINOP_OR, log); + case IVL_LO_XOR: + return inputs_to_expr(scope, VHDL_BINOP_XOR, log); + case IVL_LO_BUF: + case IVL_LO_BUFZ: + return nexus_to_var_ref(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 to expression", + ivl_logic_type(log)); + return NULL; + } +} + +void draw_logic(vhdl_arch *arch, ivl_net_logic_t log) +{ + 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 = nexus_to_var_ref(arch->get_scope(), output); + + vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log); + vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); + + ivl_expr_t delay = ivl_logic_delay(log, 1); + if (delay) + ass->set_after(translate_time_expr(delay)); + + arch->add_stmt(ass); + } + } +} diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 36e45f90c..5020d813d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -25,7 +25,6 @@ #include #include -static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log); static string make_safe_name(ivl_signal_t sig); static vhdl_entity *g_active_entity = NULL; @@ -238,100 +237,6 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) vhdl_type *type = new vhdl_type(*(decl->get_type())); return new vhdl_var_ref(renamed.c_str(), type); } - -/* - * Convert the inputs of a logic gate to a binary expression. - */ -static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, - ivl_net_logic_t log) -{ - // Not always std_logic but this is probably OK since - // the program has already been type checked - vhdl_binop_expr *gate = - new vhdl_binop_expr(op, vhdl_type::std_logic()); - - int npins = ivl_logic_pins(log); - for (int i = 1; i < npins; i++) { - ivl_nexus_t input = ivl_logic_pin(log, i); - gate->add_expr(nexus_to_var_ref(scope, input)); - } - - return gate; -} - -/* - * Convert a gate intput to an unary expression. - */ -static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, - ivl_net_logic_t log) -{ - ivl_nexus_t input = ivl_logic_pin(log, 1); - assert(input); - - vhdl_expr *operand = nexus_to_var_ref(scope, input); - 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_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); - assert(val); - - vhdl_expr *sel = nexus_to_var_ref(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); - - 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); - - arch->add_stmt(cass); -} - -static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) -{ - switch (ivl_logic_type(log)) { - case IVL_LO_NOT: - return input_to_expr(scope, VHDL_UNARYOP_NOT, log); - case IVL_LO_AND: - return inputs_to_expr(scope, VHDL_BINOP_AND, log); - case IVL_LO_OR: - return inputs_to_expr(scope, VHDL_BINOP_OR, log); - case IVL_LO_XOR: - return inputs_to_expr(scope, VHDL_BINOP_XOR, log); - case IVL_LO_BUF: - case IVL_LO_BUFZ: - return nexus_to_var_ref(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 to expression", - ivl_logic_type(log)); - return NULL; - } -} /* * Translate all the primitive logic gates into concurrent @@ -340,33 +245,8 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log) static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) { int nlogs = ivl_scope_logs(scope); - for (int i = 0; i < nlogs; i++) { - ivl_net_logic_t log = ivl_scope_log(scope, i); - - 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 = nexus_to_var_ref(arch->get_scope(), output); - - vhdl_expr *rhs = translate_logic(arch->get_scope(), log); - vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs); - - ivl_expr_t delay = ivl_logic_delay(log, 1); - if (delay) - ass->set_after(translate_time_expr(delay)); - - arch->add_stmt(ass); - } - } - } + for (int i = 0; i < nlogs; i++) + draw_logic(arch, ivl_scope_log(scope, i)); } /* diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 430961cbf..a86b154e4 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -20,6 +20,7 @@ int draw_process(ivl_process_t net, void *cd); int draw_stmt(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt); int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); +void draw_logic(vhdl_arch *arch, ivl_net_logic_t log); vhdl_expr *translate_expr(ivl_expr_t e); vhdl_expr *translate_time_expr(ivl_expr_t e); From 9f04641fc780e4856fc0faa8ec977970e1b70b88 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 30 Jul 2008 18:01:41 -0700 Subject: [PATCH 304/377] Detect and elaborate AMS access functions. Detect function call expressions that turn out to be calls to the access function of a nature. Elaborate the access function and stub the emit code. This gets the access function just short of the code generator. --- PExpr.h | 1 + design_dump.cc | 7 +++++++ discipline.h | 2 ++ dup_expr.cc | 9 +++++++++ elab_expr.cc | 31 +++++++++++++++++++++++++++++-- emit.cc | 8 ++++++-- net_expr.cc | 14 ++++++++++++++ net_nex_input.cc | 5 +++++ netlist.h | 21 +++++++++++++++++++++ pform_disciplines.cc | 18 +++++++++++++++++- t-dll-expr.cc | 9 +++++++++ t-dll-proc.cc | 20 ++++++++++++++------ t-dll.h | 3 ++- target.cc | 9 ++++++++- target.h | 3 ++- tgt-stub/expression.c | 17 +++++++++++++++-- 16 files changed, 161 insertions(+), 16 deletions(-) diff --git a/PExpr.h b/PExpr.h index 7450e3e03..01ffa23e3 100644 --- a/PExpr.h +++ b/PExpr.h @@ -731,6 +731,7 @@ class PECallFunction : public PExpr { bool check_call_matches_definition_(Design*des, NetScope*dscope) const; NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; + NetExpr* elaborate_access_func_(Design*des, NetScope*scope, int expr_wid) const; NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope, unsigned width, const NetExpr* rise, diff --git a/design_dump.cc b/design_dump.cc index ca8e71d8e..98378628f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -27,6 +27,7 @@ # include # include "netlist.h" # include "compiler.h" +# include "discipline.h" # include "ivl_assert.h" static ostream& operator<< (ostream&o, NetBlock::Type t) @@ -1182,6 +1183,12 @@ void NetExpr::dump(ostream&o) const o << "(?" << typeid(*this).name() << "?)"; } +void NetEAccess::dump(ostream&o) const +{ + o << nature_->name() << "." << nature_->access() << "("; + o << ")"; +} + void NetEBinary::dump(ostream&o) const { if (op_ == 'm' || op_ == 'M') { diff --git a/discipline.h b/discipline.h index 30932d49d..a79e538d2 100644 --- a/discipline.h +++ b/discipline.h @@ -71,5 +71,7 @@ class discipline_t : public LineInfo { extern map natures; extern map disciplines; + // Map access function name to the nature that it accesses. +extern map access_function_nature; #endif diff --git a/dup_expr.cc b/dup_expr.cc index 7a8ec8a76..96a721543 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -21,6 +21,15 @@ # include "netlist.h" # include +# include "ivl_assert.h" + +NetEAccess* NetEAccess::dup_expr() const +{ + NetEAccess*tmp = new NetEAccess(nature_); + ivl_assert(*this, tmp); + tmp->set_line(*this); + return tmp; +} NetEBComp* NetEBComp::dup_expr() const { diff --git a/elab_expr.cc b/elab_expr.cc index 6f8470dbf..9f3cc228b 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -25,6 +25,7 @@ # include "pform.h" # include "netlist.h" +# include "discipline.h" # include "netmisc.h" # include "util.h" # include "ivl_assert.h" @@ -601,6 +602,26 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w return fun; } +NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, + int expr_wid) const +{ + // Hierarchical names cannot be access functions. + if (path_.size() != 1) + return 0; + + perm_string access_name = peek_tail_name(path_); + nature_t*nature = access_function_nature[access_name]; + + // If the name doesn't match any access functions, then give up. + if (nature == 0) + return 0; + + NetEAccess*tmp = new NetEAccess(nature); + tmp->set_line(*this); + + return tmp; +} + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { @@ -609,15 +630,21 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, NetFuncDef*def = des->find_function(scope, path_); if (def == 0) { + // Not a user defined function. Maybe it is an access + // function for a nature? If so then elaborate it that way. + NetExpr*tmp = elaborate_access_func_(des, scope, expr_wid); + if (tmp != 0) + return tmp; + cerr << get_fileline() << ": error: No function " << path_ << " in this context (" << scope_path(scope) << ")." << endl; des->errors += 1; return 0; } - assert(def); + ivl_assert(*this, def); NetScope*dscope = def->scope(); - assert(dscope); + ivl_assert(*this, dscope); if (! check_call_matches_definition_(des, dscope)) return 0; diff --git a/emit.cc b/emit.cc index 4e2b652b6..785520a12 100644 --- a/emit.cc +++ b/emit.cc @@ -198,8 +198,7 @@ bool NetProc::emit_proc(struct target_t*tgt) const bool NetAssign::emit_proc(struct target_t*tgt) const { - tgt->proc_assign(this); - return true; + return tgt->proc_assign(this); } bool NetAssignNB::emit_proc(struct target_t*tgt) const @@ -461,6 +460,11 @@ int Design::emit(struct target_t*tgt) const return rc; } +void NetEAccess::expr_scan(struct expr_scan_t*tgt) const +{ + tgt->expr_access_func(this); +} + void NetEBinary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_binary(this); diff --git a/net_expr.cc b/net_expr.cc index 92594ea3d..4d3818099 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -588,3 +588,17 @@ ivl_variable_type_t NetESFunc::expr_type() const { return type_; } + +NetEAccess::NetEAccess(nature_t*nat) +: nature_(nat) +{ +} + +NetEAccess::~NetEAccess() +{ +} + +ivl_variable_type_t NetEAccess::expr_type() const +{ + return IVL_VT_REAL; +} diff --git a/net_nex_input.cc b/net_nex_input.cc index 2a68c2a8b..622621b05 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -62,6 +62,11 @@ NexusSet* NetEConcat::nex_input(bool rem_out) return result; } +NexusSet* NetEAccess::nex_input(bool rem_out) +{ + return new NexusSet; +} + /* * A constant has not inputs, so always return an empty set. */ diff --git a/netlist.h b/netlist.h index d6e01bab2..d3af7febd 100644 --- a/netlist.h +++ b/netlist.h @@ -68,6 +68,7 @@ class NetTaskDef; class NetEvTrig; class NetEvWait; +class nature_t; struct target; struct functor_t; @@ -2873,6 +2874,26 @@ class NetEUFunc : public NetExpr { NetEUFunc& operator= (const NetEUFunc&); }; +/* + * A call to a nature access function for a branch. + */ +class NetEAccess : public NetExpr { + + public: + explicit NetEAccess(nature_t*nat); + ~NetEAccess(); + + virtual ivl_variable_type_t expr_type() const; + virtual void dump(ostream&) const; + + virtual void expr_scan(struct expr_scan_t*) const; + virtual NetEAccess*dup_expr() const; + virtual NexusSet* nex_input(bool rem_out = true); + + private: + nature_t*nature_; +}; + /* * A call to a user defined task is elaborated into this object. This * contains a pointer to the elaborated task definition, but is a diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 82f78708b..cca4cc0ac 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -25,6 +25,7 @@ map natures; map disciplines; +map access_function_nature; static perm_string nature_name = perm_string::perm_string(); static perm_string nature_access = perm_string::perm_string(); @@ -62,9 +63,24 @@ void pform_end_nature(const struct vlltype&loc) } nature_t*tmp = new nature_t(nature_name, nature_access); + FILE_NAME(tmp, loc); + natures[nature_name] = tmp; - FILE_NAME(tmp, loc); + // Make sure the access function is not used by multiple + // different natures. + if (nature_t*dup_access_nat = access_function_nature[nature_access]) { + cerr << tmp->get_fileline() << ": error: " + << "Access function name " << nature_access + << " is already used by nature " << dup_access_nat->name() + << " declared at " << dup_access_nat->get_fileline() + << "." << endl; + error_count += 1; + } + + // Map the access functio back to the nature so that + // expressions that use the access function can find it. + access_function_nature[nature_access] = tmp; nature_name = perm_string::perm_string(); nature_access = perm_string::perm_string(); diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 958e5d0f2..51f9d4ea9 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -149,6 +149,15 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val) return expr; } +void dll_target::expr_access_func(const NetEAccess*net) +{ + assert(expr_ == 0); + + cerr << net->get_fileline() << ": internal error: " + << "Nature access functions not implemented yet." << endl; + +} + void dll_target::expr_binary(const NetEBinary*net) { assert(expr_ == 0); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 5d843e9d4..c75034e1e 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -37,6 +37,8 @@ bool dll_target::process(const NetProcTop*net) { + bool rc_flag = true; + ivl_process_t obj = (struct ivl_process_s*) calloc(1, sizeof(struct ivl_process_s)); @@ -70,7 +72,7 @@ bool dll_target::process(const NetProcTop*net) assert(stmt_cur_ == 0); stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_); assert(stmt_cur_); - net->statement()->emit_proc(this); + rc_flag = net->statement()->emit_proc(this) && rc_flag; assert(stmt_cur_); obj->stmt_ = stmt_cur_; @@ -80,7 +82,7 @@ bool dll_target::process(const NetProcTop*net) obj->next_ = des_.threads_; des_.threads_ = obj; - return true; + return rc_flag; } void dll_target::task_def(const NetScope*net) @@ -190,7 +192,7 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net) /* */ -void dll_target::proc_assign(const NetAssign*net) +bool dll_target::proc_assign(const NetAssign*net) { assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); @@ -214,6 +216,8 @@ void dll_target::proc_assign(const NetAssign*net) stmt_cur_->u_.assign_.delay = expr_; expr_ = 0; } + + return true; } @@ -399,6 +403,8 @@ bool dll_target::proc_cassign(const NetCAssign*net) bool dll_target::proc_condit(const NetCondit*net) { + bool rc_flag = true; + assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); FILE_NAME(stmt_cur_, net); @@ -410,18 +416,20 @@ bool dll_target::proc_condit(const NetCondit*net) assert(expr_ == 0); net->expr()->expr_scan(this); stmt_cur_->u_.condit_.cond_ = expr_; + if (expr_ == 0) + rc_flag = false; expr_ = 0; ivl_statement_t save_cur_ = stmt_cur_; stmt_cur_ = save_cur_->u_.condit_.stmt_+0; - bool flag = net->emit_recurse_if(this); + rc_flag = net->emit_recurse_if(this) && rc_flag; stmt_cur_ = save_cur_->u_.condit_.stmt_+1; - flag = flag && net->emit_recurse_else(this); + rc_flag = net->emit_recurse_else(this) && rc_flag; stmt_cur_ = save_cur_; - return flag; + return rc_flag; } bool dll_target::proc_deassign(const NetDeassign*net) diff --git a/t-dll.h b/t-dll.h index 5bc4c3fb4..98acadff7 100644 --- a/t-dll.h +++ b/t-dll.h @@ -111,7 +111,7 @@ struct dll_target : public target_t, public expr_scan_t { /* These methods and members are used for forming the statements of a thread. */ struct ivl_statement_s*stmt_cur_; - void proc_assign(const NetAssign*); + bool proc_assign(const NetAssign*); void proc_assign_nb(const NetAssignNB*); bool proc_block(const NetBlock*); void proc_case(const NetCase*); @@ -134,6 +134,7 @@ struct dll_target : public target_t, public expr_scan_t { void task_def(const NetScope*); struct ivl_expr_s*expr_; + void expr_access_func(const NetEAccess*); void expr_binary(const NetEBinary*); void expr_concat(const NetEConcat*); void expr_const(const NetEConst*); diff --git a/target.cc b/target.cc index 10e900027..fef82cedb 100644 --- a/target.cc +++ b/target.cc @@ -243,10 +243,11 @@ bool target_t::process(const NetProcTop*top) return top->statement()->emit_proc(this); } -void target_t::proc_assign(const NetAssign*) +bool target_t::proc_assign(const NetAssign*) { cerr << "target (" << typeid(*this).name() << "): " "Unhandled procedural assignment." << endl; + return false; } void target_t::proc_assign_nb(const NetAssignNB*) @@ -377,6 +378,12 @@ expr_scan_t::~expr_scan_t() { } +void expr_scan_t::expr_access_func(const NetEAccess*) +{ + cerr << "expr_scan_t (" << typeid(*this).name() << "): " + "unhandled expr_access_func." << endl; +} + void expr_scan_t::expr_const(const NetEConst*) { cerr << "expr_scan_t (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index 03fba0886..bed4815e6 100644 --- a/target.h +++ b/target.h @@ -105,7 +105,7 @@ struct target_t { virtual bool process(const NetProcTop*); /* Various kinds of process nodes are dispatched through these. */ - virtual void proc_assign(const NetAssign*); + virtual bool proc_assign(const NetAssign*); virtual void proc_assign_nb(const NetAssignNB*); virtual bool proc_block(const NetBlock*); virtual void proc_case(const NetCase*); @@ -133,6 +133,7 @@ struct target_t { of expressions. */ struct expr_scan_t { virtual ~expr_scan_t(); + virtual void expr_access_func(const NetEAccess*); virtual void expr_const(const NetEConst*); virtual void expr_param(const NetEConstParam*); virtual void expr_rparam(const NetECRealParam*); diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 823d359a6..791b14b75 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -49,10 +49,23 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind) const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*vt = vt_type_string(net); + ivl_expr_t oper1 = ivl_expr_oper1(net); + ivl_expr_t oper2 = ivl_expr_oper2(net); + fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "", ivl_expr_opcode(net), width, sign, vt); - show_expression(ivl_expr_oper1(net), ind+3); - show_expression(ivl_expr_oper2(net), ind+3); + if (oper1) { + show_expression(oper1, ind+3); + } else { + fprintf(out, "%*sERROR: Missing operand 1\n", ind+3, ""); + stub_errors += 1; + } + if (oper2) { + show_expression(oper2, ind+3); + } else { + fprintf(out, "%*sERROR: Missing operand 2\n", ind+3, ""); + stub_errors += 1; + } switch (ivl_expr_opcode(net)) { From 221c63b76616cc4aa6699cef7c851b65f2adcfba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 30 Jul 2008 18:02:07 -0700 Subject: [PATCH 305/377] Add some simple error checking. --- t-dll-api.cc | 1 + tgt-stub/statement.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/t-dll-api.cc b/t-dll-api.cc index cf3c9b83c..d36bd56f7 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -354,6 +354,7 @@ extern "C" ivl_expr_t ivl_expr_oper3(ivl_expr_t net) extern "C" ivl_parameter_t ivl_expr_parameter(ivl_expr_t net) { + assert(net); switch (net->type_) { case IVL_EX_NUMBER: return net->u_.number_.parameter; diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index efdb7094d..bf560cf5f 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -264,7 +264,12 @@ void show_statement(ivl_statement_t net, unsigned ind) ivl_statement_t f = ivl_stmt_cond_false(net); fprintf(out, "%*sif (...)\n", ind, ""); - show_expression(ex, ind+4); + if (ex) { + show_expression(ex, ind+4); + } else { + fprintf(out, "%*sERROR: Condition expression is NIL;\n", ind+4, ""); + stub_errors += 1; + } if (t) show_statement(t, ind+4); else From db339b8fc3b3be83420a98b7304458ee6b6d01aa Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 31 Jul 2008 20:59:20 +0100 Subject: [PATCH 306/377] Stub for UDP logic devices --- tgt-vhdl/logic.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 4edd12bb3..458718623 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -93,6 +93,11 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) arch->add_stmt(cass); } +static void udp_logic(vhdl_arch *arch, ivl_udp_t udp) +{ + +} + static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) { switch (ivl_logic_type(log)) { @@ -127,6 +132,9 @@ void draw_logic(vhdl_arch *arch, ivl_net_logic_t log) case IVL_LO_BUFIF1: bufif_logic(arch, log, false); break; + case IVL_LO_UDP: + udp_logic(arch, ivl_logic_udp(log)); + break; default: { // The output is always pin zero From 7b0f675785ba3d67078083661dab69fb598f67d1 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 31 Jul 2008 21:08:59 +0100 Subject: [PATCH 307/377] Add check for sequential UDPs --- tgt-vhdl/logic.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 458718623..efffea133 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -22,6 +22,7 @@ #include "vhdl_element.hh" #include +#include /* @@ -93,9 +94,19 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) arch->add_stmt(cass); } -static void udp_logic(vhdl_arch *arch, ivl_udp_t udp) +static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { + ivl_udp_t udp = ivl_logic_udp(log); + + cout << "UDP " << ivl_udp_name(udp) << " nin=" + << ivl_udp_nin(udp) << " rows=" + << ivl_udp_rows(udp) << endl; + if (ivl_udp_sequ(udp)) { + error("Sequential UDP devices not supported yet"); + return; + } + } static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) @@ -133,7 +144,7 @@ void draw_logic(vhdl_arch *arch, ivl_net_logic_t log) bufif_logic(arch, log, false); break; case IVL_LO_UDP: - udp_logic(arch, ivl_logic_udp(log)); + udp_logic(arch, log); break; default: { From d21277f1b93e55e91ec8914ceaf22e7c4e1c3e8a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 31 Jul 2008 21:17:49 +0100 Subject: [PATCH 308/377] Tidy up whitespace in output --- tgt-vhdl/vhdl_syntax.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 7378cf4ce..e31f755a1 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -278,6 +278,7 @@ vhdl_component_decl *vhdl_component_decl::component_decl_for(vhdl_entity *ent) void vhdl_component_decl::emit(std::ostream &of, int level) const { + newline(of, level); emit_comment(of, level); of << "component " << name_ << " is"; @@ -815,6 +816,7 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) void vhdl_function::emit(std::ostream &of, int level) const { + newline(of, level); of << "function " << name_ << " ("; emit_children(of, scope_.get_decls(), level, ";"); of << ") "; @@ -826,7 +828,6 @@ 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 09f3eb4a364a28a0c6bc651f660e1bd09ebe371d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Aug 2008 16:27:55 +0100 Subject: [PATCH 309/377] Don't bother calling reduction function if argument is std_logic --- tgt-vhdl/expr.cc | 26 +++++++++++++++++--------- tgt-vhdl/lpm.cc | 25 ++++++++++++++++--------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 7ad67c3ee..c57f951a1 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -106,18 +106,26 @@ static vhdl_expr *translate_ulong(ivl_expr_t 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)); + vhdl_expr *result; + if (operand->get_type()->get_name() == VHDL_TYPE_STD_LOGIC) + result = operand; + else { + 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)); + + result = fcall; + } + if (neg) - return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, fcall, + return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, result, vhdl_type::std_logic()); else - return fcall; + return result; } static vhdl_expr *translate_unary(ivl_expr_t e) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index b3d92b466..c13cf2cbc 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -144,22 +144,29 @@ 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, support_function_t f, bool invert) { - 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; - vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR); - fcall->add_expr(ref->cast(&std_logic_vector)); - + vhdl_expr *result; + if (ref->get_type()->get_name() == VHDL_TYPE_STD_LOGIC) + result = ref; + else { + 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(ref->cast(&std_logic_vector)); + + result = fcall; + } + if (invert) return new vhdl_unaryop_expr - (VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic()); + (VHDL_UNARYOP_NOT, result, vhdl_type::std_logic()); else - return fcall; + return result; } static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) From 3f73c9bb54253536b4dcbc53e1494e28aa80601c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Aug 2008 16:35:47 +0100 Subject: [PATCH 310/377] Make sure argument to unary - is signed --- tgt-vhdl/expr.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index c57f951a1..8de363b86 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -158,6 +158,7 @@ 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 '-': + operand = change_signedness(operand, true); return new vhdl_unaryop_expr (VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type())); case 'N': // NOR From a26d91557b2dc7af64a39c0ce530b95551ea2286 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Aug 2008 17:42:26 +0100 Subject: [PATCH 311/377] Add binary NAND and NOR operators --- tgt-vhdl/expr.cc | 6 ++++++ tgt-vhdl/vhdl_syntax.cc | 3 ++- tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 8de363b86..c1d57fc12 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -296,6 +296,12 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case 'a': // Logical AND result = translate_logical(lhs, rhs, VHDL_BINOP_AND); break; + case 'A': // Bitwise NAND + result = translate_numeric(lhs, rhs, VHDL_BINOP_NAND); + break; + case 'O': // Bitwise NOR + result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR); + break; case '|': // Bitwise OR result = translate_numeric(lhs, rhs, VHDL_BINOP_OR); break; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e31f755a1..0bd3180c0 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -719,7 +719,8 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const while (++it != operands_.end()) { const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", - ">", "<=", ">=", "sll", "srl", "xor", "&" + ">", "<=", ">=", "sll", "srl", "xor", "&", + "nand", "nor", NULL }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 0595e97cb..9a3effaa6 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -81,6 +81,8 @@ enum vhdl_binop_t { VHDL_BINOP_SR, VHDL_BINOP_XOR, VHDL_BINOP_CONCAT, + VHDL_BINOP_NAND, + VHDL_BINOP_NOR, }; /* From e0834f7f385b69d67a6d3d9bc05f41257bdf4977 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Aug 2008 17:46:04 +0100 Subject: [PATCH 312/377] Add NAND and NOR logic devices --- tgt-vhdl/logic.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index efffea133..816178383 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -118,6 +118,10 @@ static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) return inputs_to_expr(scope, VHDL_BINOP_AND, log); case IVL_LO_OR: return inputs_to_expr(scope, VHDL_BINOP_OR, log); + case IVL_LO_NAND: + return inputs_to_expr(scope, VHDL_BINOP_NAND, log); + case IVL_LO_NOR: + return inputs_to_expr(scope, VHDL_BINOP_NOR, log); case IVL_LO_XOR: return inputs_to_expr(scope, VHDL_BINOP_XOR, log); case IVL_LO_BUF: From bb80b432e6beabc44fa6aad2735348b2f3b8dda6 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 1 Aug 2008 21:21:42 +0100 Subject: [PATCH 313/377] Add comments file/line number comments Added to entities, architectures, and processes --- tgt-vhdl/process.cc | 6 ++++-- tgt-vhdl/scope.cc | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 432278ce5..b7c2e8fd4 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -67,8 +67,10 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) const char *type = ivl_process_type(proc) == IVL_PR_INITIAL ? "initial" : "always"; std::ostringstream ss; - ss << "Generated from " << type << " process in "; - ss << ivl_scope_tname(scope); + ss << "Generated from " << type << " process in " + << ivl_scope_tname(scope) << " (" + << ivl_scope_file(scope) << " line " + << ivl_scope_lineno(scope) << ")"; vhdl_proc->set_comment(ss.str()); set_active_entity(NULL); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 5020d813d..6decb334e 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -556,7 +556,9 @@ static void create_skeleton_entity_for(ivl_scope_t scope) // Build a comment to add to the entity/architecture ostringstream ss; - ss << "Generated from Verilog module " << ivl_scope_tname(scope); + ss << "Generated from Verilog module " << ivl_scope_tname(scope) + << " (" << ivl_scope_file(scope) << " line " + << ivl_scope_lineno(scope) << ")"; arch->set_comment(ss.str()); ent->set_comment(ss.str()); From 5d0df8d880ebaaff8fe4f8eba47a09e173d85984 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 10:42:00 +0100 Subject: [PATCH 314/377] Change format of line file/line numbers --- tgt-vhdl/process.cc | 2 +- tgt-vhdl/scope.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index b7c2e8fd4..2e1517eef 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -69,7 +69,7 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) std::ostringstream ss; ss << "Generated from " << type << " process in " << ivl_scope_tname(scope) << " (" - << ivl_scope_file(scope) << " line " + << ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope) << ")"; vhdl_proc->set_comment(ss.str()); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 6decb334e..cfd74f611 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -557,7 +557,7 @@ static void create_skeleton_entity_for(ivl_scope_t scope) // Build a comment to add to the entity/architecture ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope) - << " (" << ivl_scope_file(scope) << " line " + << " (" << ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope) << ")"; arch->set_comment(ss.str()); From a60216ec15cf9117713913596332cbcc0f696e38 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 10:44:03 +0100 Subject: [PATCH 315/377] Use ivl_process_* functions for file/line number information --- tgt-vhdl/process.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 2e1517eef..cc2d9b649 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -69,8 +69,8 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc) std::ostringstream ss; ss << "Generated from " << type << " process in " << ivl_scope_tname(scope) << " (" - << ivl_scope_file(scope) << ":" - << ivl_scope_lineno(scope) << ")"; + << ivl_process_file(proc) << ":" + << ivl_process_lineno(proc) << ")"; vhdl_proc->set_comment(ss.str()); set_active_entity(NULL); From 752a90dc2f08839e09239ba40aa44a7a8bdcbb6f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 10:45:38 +0100 Subject: [PATCH 316/377] Insert blank line before VHDL process in output --- tgt-vhdl/vhdl_syntax.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 0bd3180c0..45595deba 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -166,7 +166,8 @@ void vhdl_process::emit(std::ostream &of, int level) const newline(of, level); return; } - + + newline(of, level); emit_comment(of, level); if (name_.size() > 0) of << name_ << ": "; @@ -189,7 +190,6 @@ void vhdl_process::emit(std::ostream &of, int level) const of << "begin"; stmts_.emit(of, level); of << "end process;"; - newline(of, level); } stmt_container::~stmt_container() From 9448c5939c24116dd4e80ea5764300c62eb23f0f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 15:46:36 +0100 Subject: [PATCH 317/377] Always user Ternary_* support functions for ternary assignments Previously the code generator expanded ternary assignments to and `if' statement. This patch replaces that with a single assignment and a call to a Ternary_* support function. This will make it much easier to support multiple lvals later. --- tgt-vhdl/stmt.cc | 136 ++++++++++++++++---------------------------- tgt-vhdl/support.cc | 10 +++- 2 files changed, 56 insertions(+), 90 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 998eaea90..fecda790c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -186,97 +186,59 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container, unsigned lval_width = ivl_lval_width(lval); ivl_expr_t rval = ivl_stmt_rval(stmt); - 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 = - make_assign_rhs(sig, proc->get_scope(), - ivl_expr_oper2(rval), base, lval_width); - vhdl_expr *false_part = - make_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); - - // 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); + vhdl_expr *rhs = + make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); + if (NULL == rhs) return NULL; - } - else { - vhdl_expr *rhs = - make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); - if (NULL == rhs) + + 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. + + // 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() + && 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 + // 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; - - 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. - - // 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() - && 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 - // 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); - - ivl_expr_t i_delay; - if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) - after = translate_time_expr(i_delay); - - if (after != NULL) - a->set_after(after); - - return a; } + + 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); + + ivl_expr_t i_delay; + if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) + after = translate_time_expr(i_delay); + + if (after != NULL) + a->set_after(after); + + return a; } else { error("Only signals as lvals supported at the moment"); diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index 7b0de5d76..e9592fa06 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -61,6 +61,10 @@ vhdl_type *support_function::function_type(support_function_t type) case SF_REDUCE_XOR: case SF_TERNARY_LOGIC: return vhdl_type::std_logic(); + case SF_TERNARY_SIGNED: + return new vhdl_type(VHDL_TYPE_SIGNED); + case SF_TERNARY_UNSIGNED: + return new vhdl_type(VHDL_TYPE_UNSIGNED); case SF_LOGIC_TO_INTEGER: return vhdl_type::integer(); default: @@ -76,7 +80,7 @@ void support_function::emit_ternary(std::ostream &of, int level) const void support_function::emit(std::ostream &of, int level) const { - of << "function " << function_name(type_); + of << nl_string(level) << "function " << function_name(type_); switch (type_) { case SF_UNSIGNED_TO_BOOLEAN: @@ -137,7 +141,7 @@ void support_function::emit(std::ostream &of, int level) const emit_ternary(of, level); break; case SF_TERNARY_UNSIGNED: - of << "(T : Boolean; X, Y : signed) return unsigned is"; + of << "(T : Boolean; X, Y : unsigned) return unsigned is"; emit_ternary(of, level); break; case SF_LOGIC_TO_INTEGER: @@ -149,5 +153,5 @@ void support_function::emit(std::ostream &of, int level) const assert(false); } - of << nl_string(level) << "end function;" << nl_string(level); + of << nl_string(level) << "end function;"; } From fad8abee343659d0b5c11a6c1c68ef3325d36ee4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 16:38:44 +0100 Subject: [PATCH 318/377] Start refactoring make_assignment for multiple lvals This patch lifts the RHS generating code out of the lval-specific code and sticks a loop around the lvals. --- tgt-vhdl/stmt.cc | 152 ++++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 75 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fecda790c..dfed1efca 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -158,91 +158,93 @@ static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, * Generate an assignment of type T for the Verilog statement stmt. */ template -static T *make_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, bool blocking, vhdl_expr *after) +void make_assignment(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt, bool blocking, vhdl_expr *after) { int nlvals = ivl_stmt_lvals(stmt); if (nlvals != 1) { error("Can only have 1 lval at the moment (found %d)", nlvals); - return NULL; + return; } - ivl_lval_t lval = ivl_stmt_lval(stmt, 0); - ivl_signal_t sig; - if ((sig = ivl_lval_sig(lval))) { + vhdl_expr *rhs = translate_expr(ivl_stmt_rval(stmt)); + // make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); + if (NULL == rhs) + return; - 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; + for (int i = 0; i < nlvals; i++) { + ivl_lval_t lval = ivl_stmt_lval(stmt, 0); + ivl_signal_t sig; + if ((sig = ivl_lval_sig(lval))) { - vhdl_type integer(VHDL_TYPE_INTEGER); - base = base->cast(&integer); - } - - unsigned lval_width = ivl_lval_width(lval); - - ivl_expr_t rval = ivl_stmt_rval(stmt); - vhdl_expr *rhs = - make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); - if (NULL == rhs) - return NULL; - - 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. - - // 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() - && 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 - // 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_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; + + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); } + + unsigned lval_width = ivl_lval_width(lval); + + 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. + + // 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() + && decl->get_type()->get_name() != VHDL_TYPE_ARRAY + && nlvals == 1) { + + // 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; + } + } + + 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); + + ivl_expr_t i_delay; + if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) + after = translate_time_expr(i_delay); + + if (after != NULL) + a->set_after(after); + + return; + } + else { + error("Only signals as lvals supported at the moment"); + return; } - - 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); - - ivl_expr_t i_delay; - if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) - after = translate_time_expr(i_delay); - - if (after != NULL) - a->set_after(after); - - return a; - } - else { - error("Only signals as lvals supported at the moment"); - return NULL; } } From c706c94e384d0a1e274259c23e206c565f4c4e29 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 18:20:18 +0100 Subject: [PATCH 319/377] Generate a vhdl_var_ref for every assignment lval This completes the refactoring of make_assignment necessary to implement multiple lvals. --- tgt-vhdl/stmt.cc | 202 +++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 114 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index dfed1efca..924579e86 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -92,8 +92,7 @@ static int draw_block(vhdl_procedural *proc, stmt_container *container, } /* - * A no-op statement. This corresponds to a `null' statement in - * VHDL. + * A no-op statement. This corresponds to a `null' statement in VHDL. */ static int draw_noop(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt) @@ -102,40 +101,6 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } -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)); - - vhdl_decl *decl = scope->get_decl(signame); - assert(decl); - - vhdl_expr *rhs = translate_expr(e); - if (rhs == NULL) - return rhs; - - 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 - vhdl_type_name_t tname = decl->get_type()->get_name(); - assert(tname == VHDL_TYPE_SIGNED || tname == VHDL_TYPE_UNSIGNED); - - if (lval_width == 1) { - vhdl_type t(VHDL_TYPE_STD_LOGIC); - return rhs->cast(&t); - } - else { - vhdl_type t(tname, lval_width - 1); - return rhs->cast(&t); - } - } -} - static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, vhdl_expr *base, int lval_width) { @@ -154,6 +119,41 @@ static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, return lval_ref; } +static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc, + list &lvals) +{ + int nlvals = ivl_stmt_lvals(stmt); + for (int i = 0; i < nlvals; i++) { + ivl_lval_t lval = ivl_stmt_lval(stmt, i); + + ivl_signal_t sig = ivl_lval_sig(lval); + if (!sig) { + error("Only signals as lvals supported at the moment"); + return false; + } + + 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 false; + + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); + } + + unsigned lval_width = ivl_lval_width(lval); + + string signame(get_renamed_signal(sig)); + + lvals.push_back(make_assign_lhs(sig, proc->get_scope(), base, lval_width)); + } + + return true; +} + /* * Generate an assignment of type T for the Verilog statement stmt. */ @@ -161,90 +161,64 @@ template void make_assignment(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool blocking, vhdl_expr *after) { - int nlvals = ivl_stmt_lvals(stmt); - if (nlvals != 1) { - error("Can only have 1 lval at the moment (found %d)", nlvals); - return; - } - - vhdl_expr *rhs = translate_expr(ivl_stmt_rval(stmt)); - // make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width); - if (NULL == rhs) + list lvals; + if (!assignment_lvals(stmt, proc, lvals)) return; - for (int i = 0; i < nlvals; i++) { + vhdl_expr *rhs; + if ((rhs = translate_expr(ivl_stmt_rval(stmt))) == NULL) + return; + + if (lvals.size() == 1) { + vhdl_var_ref *lhs = lvals.front(); + rhs = rhs->cast(lhs->get_type()); + + // 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 ivl_lval_t lval = ivl_stmt_lval(stmt, 0); - ivl_signal_t sig; - if ((sig = ivl_lval_sig(lval))) { - - 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; + vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name()); + if (proc->get_scope()->initializing() + && ivl_signal_port(ivl_lval_sig(lval)) == IVL_SIP_NONE + && !decl->has_initial() + && rhs->constant() + && decl->get_type()->get_name() != VHDL_TYPE_ARRAY) { - vhdl_type integer(VHDL_TYPE_INTEGER); - base = base->cast(&integer); + // 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); + delete lhs; + return; } - - unsigned lval_width = ivl_lval_width(lval); - - 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. - - // 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() - && decl->get_type()->get_name() != VHDL_TYPE_ARRAY - && nlvals == 1) { - - // 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; - } - } - - 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); - - ivl_expr_t i_delay; - if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) - after = translate_time_expr(i_delay); - - if (after != NULL) - a->set_after(after); - - return; - } - else { - error("Only signals as lvals supported at the moment"); - return; } + + T *a = new T(lhs, rhs); + container->add_stmt(a); + + ivl_expr_t i_delay; + if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) + after = translate_time_expr(i_delay); + + if (after != NULL) + a->set_after(after); + } + else { + assert(false); } } From c1b5424ca6f3192c8845817cf56051764f6d7812 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 2 Aug 2008 18:40:24 +0100 Subject: [PATCH 320/377] Implement assignment with multiple lvals Multiple lvals are implemented by first assigning the complete RHS to a temporary, and then assigning each lval in turn as bit-selects of the temporary --- tgt-vhdl/stmt.cc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 924579e86..6d00c1e12 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -218,7 +218,36 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, a->set_after(after); } else { - assert(false); + // Multiple lvals are implemented by first assigning the complete + // RHS to a temporary, and then assigning each lval in turn as + // bit-selects of the temporary + + static int tmp_count = 0; + ostringstream ss; + ss << "Verilog_Assign_Tmp_" << tmp_count++; + string tmpname = ss.str(); + + proc->get_scope()->add_decl + (new vhdl_var_decl(tmpname.c_str(), new vhdl_type(*rhs->get_type()))); + + vhdl_var_ref *tmp_ref = + new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type())); + container->add_stmt(new vhdl_assign_stmt(tmp_ref, rhs)); + + list::iterator it; + int width_so_far = 0; + for (it = lvals.begin(); it != lvals.end(); ++it) { + vhdl_var_ref *tmp_rhs = + new vhdl_var_ref(tmpname.c_str(), new vhdl_type(*rhs->get_type())); + + int lval_width = (*it)->get_type()->get_width(); + vhdl_expr *slice_base = new vhdl_const_int(width_so_far); + tmp_rhs->set_slice(slice_base, lval_width - 1); + + container->add_stmt(new T(*it, tmp_rhs)); + + width_so_far += lval_width; + } } } From c8cbac58f5820cc28cb7bf5666bdeb6f69b585aa Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 10:50:31 +0100 Subject: [PATCH 321/377] Add forward declarations for functions This patch adds a forward declaration for every user funciton. This fixes VHDL compile problems if a function calls another before it has been declared. --- tgt-vhdl/scope.cc | 5 +++++ tgt-vhdl/vhdl_syntax.cc | 15 +++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 12 ++++++++++++ 3 files changed, 32 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index cfd74f611..d3c3d9ea7 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -528,6 +528,11 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) draw_stmt(func, func->get_container(), ivl_scope_def(scope)); } set_active_entity(NULL); + + // Add a forward declaration too in case it is called by + // another function that has already been added + ent->get_arch()->get_scope()->add_forward_decl + (new vhdl_forward_fdecl(func)); ent->get_arch()->get_scope()->add_decl(func); return 0; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 45595deba..dd9a365bb 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -48,6 +48,11 @@ void vhdl_scope::add_decl(vhdl_decl *decl) decls_.push_back(decl); } +void vhdl_scope::add_forward_decl(vhdl_decl *decl) +{ + decls_.push_front(decl); +} + vhdl_decl *vhdl_scope::get_decl(const std::string &name) const { decl_list_t::const_iterator it; @@ -831,6 +836,16 @@ void vhdl_function::emit(std::ostream &of, int level) const of << "end function;"; } +void vhdl_forward_fdecl::emit(std::ostream &of, int level) const +{ + of << "function " << f_->get_name() << " ("; + emit_children(of, f_->scope_.get_decls(), level, ";"); + of << ") "; + newline(of, level); + of << "return " << f_->type_->get_string() << ";"; + newline(of, level); +} + void vhdl_param_decl::emit(std::ostream &of, int level) const { of << name_ << " : "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9a3effaa6..c8cbf8c07 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -608,6 +608,7 @@ public: ~vhdl_scope(); void add_decl(vhdl_decl *decl); + void add_forward_decl(vhdl_decl *decl); vhdl_decl *get_decl(const std::string &name) const; bool have_declared(const std::string &name) const; bool contained_within(const vhdl_scope *other) const; @@ -647,6 +648,7 @@ protected: class vhdl_function : public vhdl_decl, public vhdl_procedural { + friend class vhdl_forward_fdecl; public: vhdl_function(const char *name, vhdl_type *ret_type); @@ -657,6 +659,16 @@ private: vhdl_scope variables_; }; +class vhdl_forward_fdecl : public vhdl_decl { +public: + vhdl_forward_fdecl(const vhdl_function *f) + : vhdl_decl((f->get_name() + "_Forward").c_str()), f_(f) {} + + void emit(std::ostream &of, int level) const; +private: + const vhdl_function *f_; +}; + class vhdl_process : public vhdl_conc_stmt, public vhdl_procedural { public: From 45dfa28dbaf6b70f9704e23407f56d774d53c62d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 11:41:26 +0100 Subject: [PATCH 322/377] Remember signal pin a nexus was attached to Also modify nexus_to_var_ref to set the correct array offset when the signal is an array (the offset comes from the pin). --- tgt-vhdl/lpm.cc | 2 +- tgt-vhdl/scope.cc | 28 +++++++++++++++++++--------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index c13cf2cbc..9ddbd5257 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -185,7 +185,7 @@ static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return NULL; const char *renamed = get_renamed_signal(array).c_str(); - + vhdl_decl *adecl = scope->get_decl(renamed); assert(adecl); diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d3c3d9ea7..530b8a147 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -50,6 +50,7 @@ void set_active_entity(vhdl_entity *ent) struct scope_nexus_t { vhdl_scope *scope; ivl_signal_t sig; // A real signal + unsigned pin; // The pin this signal is connected to string tmpname; // A new temporary signal list connect; // Other signals to wire together }; @@ -86,8 +87,8 @@ static scope_nexus_t *visible_nexus(nexus_private_t *priv, vhdl_scope *scope) * convert it to a variable reference (e.g. in a LPM input/output). */ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, - ivl_signal_t sig) -{ + ivl_signal_t sig, unsigned pin) +{ scope_nexus_t *sn; if ((sn = visible_nexus(priv, scope))) { assert(sn->tmpname == ""); @@ -95,7 +96,7 @@ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, sn->connect.push_back(sig); } else { - scope_nexus_t new_sn = { scope, sig, "" }; + scope_nexus_t new_sn = { scope, sig, pin, "" }; priv->signals.push_back(new_sn); } } @@ -106,18 +107,20 @@ static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope, static void link_scope_to_nexus_tmp(nexus_private_t *priv, vhdl_scope *scope, const string &name) { - scope_nexus_t new_sn = { scope, NULL, name }; + scope_nexus_t new_sn = { scope, NULL, 0, name }; priv->signals.push_back(new_sn); } /* * Finds the name of the nexus signal within this scope. */ -static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope) +static string visible_nexus_signal_name(nexus_private_t *priv, vhdl_scope *scope, + unsigned *pin) { scope_nexus_t *sn = visible_nexus(priv, scope); assert(sn); + *pin = sn->pin; return sn->sig ? get_renamed_signal(sn->sig) : sn->tmpname; } @@ -138,7 +141,8 @@ void draw_nexus(ivl_nexus_t nexus) ivl_signal_t sig; if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) { vhdl_scope *scope = find_scope_for_signal(sig); - link_scope_to_nexus_signal(priv, scope, sig); + unsigned pin = ivl_nexus_ptr_pin(nexus_ptr); + link_scope_to_nexus_signal(priv, scope, sig, pin); } } @@ -229,13 +233,19 @@ vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus) nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); - string renamed(visible_nexus_signal_name(priv, scope)); + unsigned pin; + string renamed(visible_nexus_signal_name(priv, scope, &pin)); vhdl_decl *decl = scope->get_decl(renamed); assert(decl); - + vhdl_type *type = new vhdl_type(*(decl->get_type())); - return new vhdl_var_ref(renamed.c_str(), type); + vhdl_var_ref *ref = new vhdl_var_ref(renamed.c_str(), type); + + if (decl->get_type()->get_name() == VHDL_TYPE_ARRAY) + ref->set_slice(new vhdl_const_int(pin), 0); + + return ref; } /* From 0e2628a3fb6b3f2c174d2a7d3d8dd35f7526c107 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 12:46:50 +0100 Subject: [PATCH 323/377] Minimal implementation of IVL_LPM_MUX This handles the (common) case of the select being only 1 bit wide. Implemented as a concurrent assignment with a `when' clause. --- tgt-vhdl/lpm.cc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 9ddbd5257..fde076681 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -266,11 +266,42 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) } } +static int draw_mux_lpm(vhdl_arch *arch, ivl_lpm_t lpm) +{ + int nselects = ivl_lpm_selects(lpm); + + if (nselects > 1) { + error("Only 1 LPM select bit supported at the moment"); + return 1; + } + + vhdl_scope *scope = arch->get_scope(); + + vhdl_expr *s0 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); + vhdl_expr *s1 = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1)); + + vhdl_expr *sel = nexus_to_var_ref(scope, ivl_lpm_select(lpm)); + vhdl_expr *b1 = new vhdl_const_bit('1'); + vhdl_expr *t1 = + new vhdl_binop_expr(sel, VHDL_BINOP_EQ, b1, vhdl_type::boolean()); + + vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0)); + + vhdl_cassign_stmt *s = new vhdl_cassign_stmt(out, s0); + s->add_condition(s1, t1); + + arch->add_stmt(s); + return 0; +} + int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm) { + if (ivl_lpm_type(lpm) == IVL_LPM_MUX) + return draw_mux_lpm(arch, lpm); + vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm); if (NULL == f) - return 0; + return 1; vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), ivl_lpm_q(lpm, 0)); if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) { From c2f622327f3bfbd0e3d78b7cfd09cb22f01dce7a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 14:34:41 +0100 Subject: [PATCH 324/377] Use ivl_scope_def_* for definition file/line numbers --- 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 530b8a147..c5a381fa1 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -572,8 +572,8 @@ static void create_skeleton_entity_for(ivl_scope_t scope) // Build a comment to add to the entity/architecture ostringstream ss; ss << "Generated from Verilog module " << ivl_scope_tname(scope) - << " (" << ivl_scope_file(scope) << ":" - << ivl_scope_lineno(scope) << ")"; + << " (" << ivl_scope_def_file(scope) << ":" + << ivl_scope_def_lineno(scope) << ")"; arch->set_comment(ss.str()); ent->set_comment(ss.str()); From 10a5ca199dd2da8fedb2ac0fa51ced67c3802e12 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 14:38:08 +0100 Subject: [PATCH 325/377] Add file / line number comments to instantiations --- 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 c5a381fa1..3cdaeb0eb 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -737,7 +737,12 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); - port_map(scope, parent_ent, inst); + port_map(scope, parent_ent, inst); + + ostringstream ss; + ss << "Generated from instantiation at " + << ivl_scope_file(scope) << ":" << ivl_scope_lineno(scope); + inst->set_comment(ss.str().c_str()); parent_arch->add_stmt(inst); } From 49a2693357f3b8b8afab6d7a751b457c6e9593db Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 14:46:57 +0100 Subject: [PATCH 326/377] Add file / line number information to functions --- tgt-vhdl/scope.cc | 5 +++++ tgt-vhdl/vhdl_syntax.cc | 1 + 2 files changed, 6 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 3cdaeb0eb..55ff84e73 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -543,6 +543,11 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) // another function that has already been added ent->get_arch()->get_scope()->add_forward_decl (new vhdl_forward_fdecl(func)); + + ostringstream ss; + ss << "Generated from function " << funcname << " at " + << ivl_scope_def_file(scope) << ":" << ivl_scope_def_lineno(scope); + func->set_comment(ss.str().c_str()); ent->get_arch()->get_scope()->add_decl(func); return 0; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index dd9a365bb..d3b6ae306 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -823,6 +823,7 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) void vhdl_function::emit(std::ostream &of, int level) const { newline(of, level); + emit_comment(of, level); of << "function " << name_ << " ("; emit_children(of, scope_.get_decls(), level, ";"); of << ") "; From 9565ea10343b79a07d531b70d3b20f45f43fbd26 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 14:50:13 +0100 Subject: [PATCH 327/377] Add some whitespace above component instantiations --- tgt-vhdl/vhdl_syntax.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d3b6ae306..f8932d2f0 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -235,6 +235,7 @@ void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr) void vhdl_comp_inst::emit(std::ostream &of, int level) const { + newline(of, level); emit_comment(of, level); of << inst_name_ << ": " << comp_name_; @@ -257,7 +258,6 @@ void vhdl_comp_inst::emit(std::ostream &of, int level) const } of << ";"; - newline(of, level); } vhdl_component_decl::vhdl_component_decl(const char *name) From 72019959a8d6da5ac93a24d85d17123ab79ab8d9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 3 Aug 2008 15:47:32 +0100 Subject: [PATCH 328/377] Translate some ternary expressions to if statements This re-implements some earlier functionality where ternary expressions on an assignment RHS are translated to an if statement. --- tgt-vhdl/stmt.cc | 152 +++++++++++++++++++++++++--------------- tgt-vhdl/vhdl_syntax.hh | 3 +- 2 files changed, 99 insertions(+), 56 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 6d00c1e12..981a6b92c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -101,9 +101,28 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container, return 0; } -static vhdl_var_ref *make_assign_lhs(ivl_signal_t sig, vhdl_scope *scope, - vhdl_expr *base, int lval_width) +static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) { + ivl_signal_t sig = ivl_lval_sig(lval); + if (!sig) { + error("Only signals as lvals supported at the moment"); + return NULL; + } + + 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; + + vhdl_type integer(VHDL_TYPE_INTEGER); + base = base->cast(&integer); + } + + unsigned lval_width = ivl_lval_width(lval); + string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); @@ -125,31 +144,12 @@ static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc, int nlvals = ivl_stmt_lvals(stmt); for (int i = 0; i < nlvals; i++) { ivl_lval_t lval = ivl_stmt_lval(stmt, i); - - ivl_signal_t sig = ivl_lval_sig(lval); - if (!sig) { - error("Only signals as lvals supported at the moment"); + vhdl_var_ref *lhs = make_assign_lhs(lval, proc->get_scope()); + if (NULL == lhs) return false; - } - 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 false; - - vhdl_type integer(VHDL_TYPE_INTEGER); - base = base->cast(&integer); - } - - unsigned lval_width = ivl_lval_width(lval); - - string signame(get_renamed_signal(sig)); - - lvals.push_back(make_assign_lhs(sig, proc->get_scope(), base, lval_width)); - } + lvals.push_back(lhs); + } return true; } @@ -159,19 +159,65 @@ static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc, */ template void make_assignment(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, bool blocking, vhdl_expr *after) + ivl_statement_t stmt, bool blocking) { list lvals; if (!assignment_lvals(stmt, proc, lvals)) return; - vhdl_expr *rhs; - if ((rhs = translate_expr(ivl_stmt_rval(stmt))) == NULL) + vhdl_expr *rhs, *rhs2 = NULL; + ivl_expr_t rval = ivl_stmt_rval(stmt); + if (ivl_expr_type(rval) == IVL_EX_TERNARY) { + rhs = translate_expr(ivl_expr_oper2(rval)); + rhs2 = translate_expr(ivl_expr_oper3(rval)); + } + else + rhs = translate_expr(rval); + if (rhs == NULL) return; if (lvals.size() == 1) { vhdl_var_ref *lhs = lvals.front(); rhs = rhs->cast(lhs->get_type()); + + ivl_expr_t i_delay; + vhdl_expr *after = NULL; + if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) + after = translate_time_expr(i_delay); + + // A small optimisation is to expand ternary RHSs into an + // if statement (eliminates a function call and produces + // more idiomatic code) + if (ivl_expr_type(rval) == IVL_EX_TERNARY) { + rhs2 = rhs2->cast(lhs->get_type()); + vhdl_var_ref *lhs2 = + make_assign_lhs(ivl_stmt_lval(stmt, 0), proc->get_scope()); + + vhdl_expr *test = translate_expr(ivl_expr_oper1(rval)); + if (NULL == test) + return; + + vhdl_if_stmt *vhdif = new vhdl_if_stmt(test); + + // True part + { + T *a = new T(lhs, rhs); + if (after) + a->set_after(after); + vhdif->get_then_container()->add_stmt(a); + } + + // False part + { + T *a = new T(lhs2, rhs2); + if (after) + a->set_after(translate_time_expr(i_delay)); + vhdif->get_else_container()->add_stmt(a); + } + + container->add_stmt(vhdif); + return; + } // Where possible, move constant assignments into the // declaration as initializers. This optimisation is only @@ -209,11 +255,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, T *a = new T(lhs, rhs); container->add_stmt(a); - - ivl_expr_t i_delay; - if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt))) - after = translate_time_expr(i_delay); - + if (after != NULL) a->set_after(after); } @@ -243,8 +285,17 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, int lval_width = (*it)->get_type()->get_width(); vhdl_expr *slice_base = new vhdl_const_int(width_so_far); tmp_rhs->set_slice(slice_base, lval_width - 1); + + ivl_expr_t i_delay; + vhdl_expr *after = NULL; + if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL) + after = translate_time_expr(i_delay); - container->add_stmt(new T(*it, tmp_rhs)); + T *a = new T(*it, tmp_rhs); + if (after) + a->set_after(after); + + container->add_stmt(a); width_so_far += lval_width; } @@ -257,11 +308,11 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, * assignment. */ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt, vhdl_expr *after = NULL) + ivl_statement_t stmt) { assert(proc->get_scope()->allow_signal_assignment()); - make_assignment(proc, container, stmt, false, after); + make_assignment(proc, container, stmt, false); return 0; } @@ -274,13 +325,13 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, // followed by a zero-time wait // This follows the Verilog semantics fairly closely. - make_assignment(proc, container, stmt, false, NULL); + make_assignment(proc, container, stmt, false); container->add_stmt (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); } else - make_assignment(proc, container, stmt, true, NULL); + make_assignment(proc, container, stmt, true); return 0; } @@ -310,25 +361,16 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container, return 1; } - // If the sub-statement is an assignment then VHDL lets - // us put the delay after it, which is more compact and - // idiomatic ivl_statement_t sub_stmt = ivl_stmt_sub_stmt(stmt); - ivl_statement_type_t type = ivl_statement_type(sub_stmt); - if (type == IVL_ST_ASSIGN_NB) { - draw_nbassign(proc, container, sub_stmt, time); - } - else { - vhdl_wait_stmt *wait = - new vhdl_wait_stmt(VHDL_WAIT_FOR, time); - container->add_stmt(wait); + vhdl_wait_stmt *wait = + new vhdl_wait_stmt(VHDL_WAIT_FOR, time); + container->add_stmt(wait); - // Expand the sub-statement as well - // Often this would result in a useless `null' statement which - // is caught here instead - if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) - draw_stmt(proc, container, sub_stmt); - } + // Expand the sub-statement as well + // Often this would result in a useless `null' statement which + // is caught here instead + if (ivl_statement_type(sub_stmt) != IVL_ST_NOOP) + draw_stmt(proc, container, sub_stmt); // Any further assignments occur after simulation time 0 // so they cannot be used to initialize signal declarations diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c8cbf8c07..e09d6ab63 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -246,7 +246,8 @@ public: void set_after(vhdl_expr *a) { after_ = a; } private: vhdl_var_ref *lhs_; - vhdl_expr *rhs_, *after_; + vhdl_expr *rhs_; + vhdl_expr *after_; struct when_part_t { vhdl_expr *value, *cond; From b292a5fc0526e7b5afc10a4ae992f05f1261712e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 4 Aug 2008 20:54:05 -0700 Subject: [PATCH 329/377] Create a branch object to be the argument to the access function. The NetBranch object is connected, but not like an object, so the NetPins object base class is factored out from NetObj to handle the connectivity, and the NetBranch class uses the NetPins to connect a branch. Also, account for the fact that nets with a discipline are by default real-valued. --- cprop.cc | 4 +-- design_dump.cc | 12 +++++++- dup_expr.cc | 2 +- elab_expr.cc | 31 ++++++++++++++++++- elab_sig.cc | 4 +++ ivl_target.h | 1 + link_const.cc | 5 +-- net_event.cc | 2 +- net_expr.cc | 4 +-- net_link.cc | 15 +++++---- net_tran.cc | 8 +++-- netlist.cc | 71 +++++++++++++++++++++++++++++++------------ netlist.h | 69 +++++++++++++++++++++++++++++++---------- pform_disciplines.cc | 1 + t-dll-expr.cc | 12 +++++--- tgt-stub/expression.c | 15 +++++++++ 16 files changed, 199 insertions(+), 57 deletions(-) diff --git a/cprop.cc b/cprop.cc index 9345b9ea8..56e3a7bf7 100644 --- a/cprop.cc +++ b/cprop.cc @@ -897,7 +897,7 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - NetObj*cur; + NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); @@ -923,7 +923,7 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - NetObj*cur; + NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); diff --git a/design_dump.cc b/design_dump.cc index 98378628f..17c0af847 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -188,6 +188,10 @@ void NetNet::dump_net(ostream&o, unsigned ind) const o << " inout"; break; } + + if (discipline_t*dis = get_discipline()) + o << " discipline=" << dis->name(); + o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); @@ -237,7 +241,7 @@ void NetNode::dump_node(ostream&o, unsigned ind) const /* This is the generic dumping of all the signals connected to each pin of the object. The "this" object is not printed, only the signals connected to this. */ -void NetObj::dump_node_pins(ostream&o, unsigned ind) const +void NetPins::dump_node_pins(ostream&o, unsigned ind) const { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { o << setw(ind) << "" << idx << " " << pin(idx).get_name() @@ -1186,6 +1190,12 @@ void NetExpr::dump(ostream&o) const void NetEAccess::dump(ostream&o) const { o << nature_->name() << "." << nature_->access() << "("; + assert(branch_); + if (branch_->pin(0).is_linked()) + o << branch_->pin(0).nexus()->name(); + o << ", "; + if (branch_->pin(1).is_linked()) + o << branch_->pin(1).nexus()->name(); o << ")"; } diff --git a/dup_expr.cc b/dup_expr.cc index 96a721543..ad4bb7b0a 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -25,7 +25,7 @@ NetEAccess* NetEAccess::dup_expr() const { - NetEAccess*tmp = new NetEAccess(nature_); + NetEAccess*tmp = new NetEAccess(branch_, nature_); ivl_assert(*this, tmp); tmp->set_line(*this); return tmp; diff --git a/elab_expr.cc b/elab_expr.cc index 9f3cc228b..b4160e5d8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -616,7 +616,36 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, if (nature == 0) return 0; - NetEAccess*tmp = new NetEAccess(nature); + // An access function must have 1 or 2 arguments. + ivl_assert(*this, parms_.size()==2 || parms_.size()==1); + + NetBranch*branch = 0; + + if (parms_.size() == 1) { + PExpr*arg1 = parms_[0]; + PEIdent*arg_ident = dynamic_cast (arg1); + ivl_assert(*this, arg_ident); + + const pform_name_t&path = arg_ident->path(); + ivl_assert(*this, path.size()==1); + perm_string name = peek_tail_name(path); + + NetNet*sig = scope->find_signal(name); + ivl_assert(*this, sig); + + discipline_t*dis = sig->get_discipline(); + ivl_assert(*this, dis); + ivl_assert(*this, nature == dis->potential() || nature == dis->flow()); + + branch = new NetBranch(dis); + branch->set_line(*this); + connect(branch->pin(0), sig->pin(0)); + + } else { + ivl_assert(*this, 0); + } + + NetEAccess*tmp = new NetEAccess(branch, nature); tmp->set_line(*this); return tmp; diff --git a/elab_sig.cc b/elab_sig.cc index 8faa7f2c9..c01fdd81e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1029,6 +1029,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig->set_signed(get_signed()); sig->set_isint(get_isint()); + if (discipline_t*dis = get_discipline()) { + sig->set_discipline(dis); + } + if (pull) connect(sig->pin(0), pull->pin(0)); diff --git a/ivl_target.h b/ivl_target.h index 7535bd0d4..c019acf04 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -193,6 +193,7 @@ typedef enum ivl_drive_e { typedef enum ivl_expr_type_e { IVL_EX_NONE = 0, IVL_EX_ARRAY = 18, + IVL_EX_BACCESS= 19, IVL_EX_BINARY = 2, IVL_EX_CONCAT = 3, IVL_EX_EVENT = 17, diff --git a/link_const.cc b/link_const.cc index 60b68afa6..212fbf9e7 100644 --- a/link_const.cc +++ b/link_const.cc @@ -60,8 +60,9 @@ bool Nexus::drivers_constant() const if (cur_dir == Link::PASSIVE) { - const NetObj*obj = cur->get_obj(); - if (obj->scope()->parent() != 0) + const NetPins*obj = cur->get_obj(); + const NetObj*as_obj = dynamic_cast(obj); + if (as_obj == 0 || as_obj->scope()->parent() != 0) continue; sig = dynamic_cast(cur->get_obj()); diff --git a/net_event.cc b/net_event.cc index a214cdd48..3535e7ea9 100644 --- a/net_event.cc +++ b/net_event.cc @@ -299,7 +299,7 @@ void NetEvProbe::find_similar_probes(list&plist) Nexus*nex = pin(0).nexus(); for (Link*lcur = nex->first_nlink(); lcur; lcur = lcur->next_nlink()) { - NetObj*obj = lcur->get_obj(); + NetPins*obj = lcur->get_obj(); if (obj->pin_count() != pin_count()) continue; diff --git a/net_expr.cc b/net_expr.cc index 4d3818099..e749cdca1 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -589,8 +589,8 @@ ivl_variable_type_t NetESFunc::expr_type() const return type_; } -NetEAccess::NetEAccess(nature_t*nat) -: nature_(nat) +NetEAccess::NetEAccess(NetBranch*br, nature_t*nat) +: branch_(br), nature_(nat) { } diff --git a/net_link.cc b/net_link.cc index 228add8c0..9b892a152 100644 --- a/net_link.cc +++ b/net_link.cc @@ -134,13 +134,13 @@ verinum::V Link::get_init() const } -void Link::cur_link(NetObj*&net, unsigned &pin) +void Link::cur_link(NetPins*&net, unsigned &pin) { net = node_; pin = pin_; } -void Link::cur_link(const NetObj*&net, unsigned &pin) const +void Link::cur_link(const NetPins*&net, unsigned &pin) const { net = node_; pin = pin_; @@ -186,12 +186,12 @@ const Link* Link::next_nlink() const return next_; } -const NetObj*Link::get_obj() const +const NetPins*Link::get_obj() const { return node_; } -NetObj*Link::get_obj() +NetPins*Link::get_obj() { return node_; } @@ -253,7 +253,10 @@ void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay) if (cur->get_dir() != Link::OUTPUT) continue; - NetObj*obj = cur->get_obj(); + NetObj*obj = dynamic_cast(cur->get_obj()); + if (obj == 0) + continue; + obj->rise_time(rise); obj->fall_time(fall); obj->decay_time(decay); @@ -397,7 +400,7 @@ const char* Nexus::name() const if (sig == 0) { const Link*lnk = first_nlink(); - const NetObj*obj = lnk->get_obj(); + const NetObj*obj = dynamic_cast(lnk->get_obj()); pin = lnk->get_pin(); cerr << "internal error: No signal for nexus of " << obj->name() << " pin " << pin << "(" << diff --git a/net_tran.cc b/net_tran.cc index b28a28753..42b726307 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -100,8 +100,12 @@ void join_island(NetObj*obj) Nexus*nex = obj->pin(idx).nexus(); for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { unsigned pin; - NetObj*tmp; - cur->cur_link(tmp, pin); + NetPins*tmp_pins; + cur->cur_link(tmp_pins, pin); + + NetObj*tmp = dynamic_cast (tmp_pins); + if (tmp == 0) + continue; // Skip self. if (tmp == obj) diff --git a/netlist.cc b/netlist.cc index 51cf898f6..ece7adf45 100644 --- a/netlist.cc +++ b/netlist.cc @@ -91,7 +91,7 @@ unsigned count_inputs(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (cur->pin(cpin).get_dir() == Link::INPUT) @@ -108,7 +108,7 @@ unsigned count_outputs(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (cur->pin(cpin).get_dir() == Link::OUTPUT) @@ -125,7 +125,7 @@ unsigned count_signals(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (dynamic_cast(cur)) @@ -142,7 +142,7 @@ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx) for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); @@ -171,8 +171,8 @@ Link* find_next_output(Link*lnk) return 0; } -NetObj::NetObj(NetScope*s, perm_string n, unsigned np) -: scope_(s), name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0) +NetPins::NetPins(unsigned npins) +: npins_(npins) { pins_ = new Link[npins_]; for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { @@ -181,22 +181,12 @@ NetObj::NetObj(NetScope*s, perm_string n, unsigned np) } } -NetObj::~NetObj() +NetPins::~NetPins() { delete[]pins_; } -NetScope* NetObj::scope() -{ - return scope_; -} - -const NetScope* NetObj::scope() const -{ - return scope_; -} - -Link& NetObj::pin(unsigned idx) +Link& NetPins::pin(unsigned idx) { if (idx >= npins_) { cerr << get_fileline() << ": internal error: pin("<del_node(this); } +NetBranch::NetBranch(discipline_t*dis) +: NetPins(2), discipline_(dis) +{ + pin(0).set_name(perm_string::literal("A"), 0); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_name(perm_string::literal("B"), 0); + pin(1).set_dir(Link::PASSIVE); +} + +NetBranch::~NetBranch() +{ +} + NetBus::NetBus(NetScope*s, unsigned pin_count) : NetObj(s, perm_string::literal(""), pin_count) { @@ -622,6 +644,17 @@ void NetNet::set_isint(bool flag) isint_ = flag; } +discipline_t* NetNet::get_discipline() const +{ + return discipline_; +} + +void NetNet::set_discipline(discipline_t*dis) +{ + ivl_assert(*this, discipline_ == 0); + discipline_ = dis; +} + long NetNet::lsb() const { return lsb_; diff --git a/netlist.h b/netlist.h index d3af7febd..6a3488b46 100644 --- a/netlist.h +++ b/netlist.h @@ -69,6 +69,7 @@ class NetEvTrig; class NetEvWait; class nature_t; +class discipline_t; struct target; struct functor_t; @@ -77,6 +78,24 @@ ostream& operator << (ostream&o, ivl_variable_type_t val); extern void join_island(NetObj*obj); +class NetPins : public LineInfo { + + public: + explicit NetPins(unsigned npins); + virtual ~NetPins(); + + unsigned pin_count() const { return npins_; } + + Link&pin(unsigned idx); + const Link&pin(unsigned idx) const; + + void dump_node_pins(ostream&, unsigned) const; + + private: + Link*pins_; + const unsigned npins_; +}; + /* ========= * A NetObj is anything that has any kind of behavior in the * netlist. Nodes can be gates, registers, etc. and are linked @@ -97,7 +116,7 @@ extern void join_island(NetObj*obj); * interpretation of the rise/fall/decay times is typically left to * the target to properly interpret. */ -class NetObj : public Attrib, public virtual LineInfo { +class NetObj : public NetPins, public Attrib { public: public: @@ -111,8 +130,6 @@ class NetObj : public Attrib, public virtual LineInfo { perm_string name() const { return name_; } - unsigned pin_count() const { return npins_; } - const NetExpr* rise_time() const { return delay1_; } const NetExpr* fall_time() const { return delay2_; } const NetExpr* decay_time() const { return delay3_; } @@ -121,17 +138,11 @@ class NetObj : public Attrib, public virtual LineInfo { void fall_time(const NetExpr* d) { delay2_ = d; } void decay_time(const NetExpr* d) { delay3_ = d; } - Link&pin(unsigned idx); - const Link&pin(unsigned idx) const; - - void dump_node_pins(ostream&, unsigned) const; void dump_obj_attr(ostream&, unsigned) const; private: NetScope*scope_; perm_string name_; - Link*pins_; - const unsigned npins_; const NetExpr* delay1_; const NetExpr* delay2_; const NetExpr* delay3_; @@ -151,11 +162,31 @@ class IslandBranch { struct ivl_island_s* island; }; +/* + * A NetBranch is a construct of Verilog-A that is a branch between + * two nodes. The branch has exactly 2 pins and a discipline. + * + * pin(0) is the source of flow through a branch and the plus side of + * potential. Pin(1) is the sink of flow and the minus (or ground) of + * potential. + */ +class NetBranch : public NetPins { + + public: + explicit NetBranch(discipline_t*dis); + explicit NetBranch(discipline_t*dis, perm_string name); + ~NetBranch(); + + private: + discipline_t*discipline_; + perm_string name_; +}; + class Link { friend void connect(Link&, Link&); friend void connect(Nexus*, Link&); - friend class NetObj; + friend class NetPins; friend class Nexus; public: @@ -189,8 +220,8 @@ class Link { void set_init(verinum::V val); verinum::V get_init() const; - void cur_link(NetObj*&net, unsigned &pin); - void cur_link(const NetObj*&net, unsigned &pin) const; + void cur_link(NetPins*&net, unsigned &pin); + void cur_link(const NetPins*&net, unsigned &pin) const; // Get a pointer to the nexus that represents all the links // connected to me. @@ -217,8 +248,8 @@ class Link { // Return information about the object that this link is // a part of. - const NetObj*get_obj() const; - NetObj*get_obj(); + const NetPins*get_obj() const; + NetPins*get_obj(); unsigned get_pin() const; // A link of an object (sometimes called a "pin") has a @@ -231,7 +262,7 @@ class Link { private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. - NetObj *node_; + NetPins *node_; unsigned pin_; DIR dir_; @@ -521,6 +552,10 @@ class NetNet : public NetObj { bool get_isint() const; void set_isint(bool); + /* Attach a discipline to the net. */ + discipline_t* get_discipline() const; + void set_discipline(discipline_t*dis); + /* These methods return the msb and lsb indices for the most significant and least significant bits. These are signed longs, and may be different from pin numbers. For example, @@ -588,6 +623,7 @@ class NetNet : public NetObj { ivl_variable_type_t data_type_; bool signed_; bool isint_; // original type of integer + discipline_t*discipline_; long msb_, lsb_; const unsigned dimensions_; @@ -2880,7 +2916,7 @@ class NetEUFunc : public NetExpr { class NetEAccess : public NetExpr { public: - explicit NetEAccess(nature_t*nat); + explicit NetEAccess(NetBranch*br, nature_t*nat); ~NetEAccess(); virtual ivl_variable_type_t expr_type() const; @@ -2891,6 +2927,7 @@ class NetEAccess : public NetExpr { virtual NexusSet* nex_input(bool rem_out = true); private: + NetBranch*branch_; nature_t*nature_; }; diff --git a/pform_disciplines.cc b/pform_disciplines.cc index cca4cc0ac..2ce7aeedd 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -205,6 +205,7 @@ void pform_attach_discipline(const struct vlltype&loc, error_count += 1; } else { + cur_net->set_data_type(IVL_VT_REAL); cur_net->set_discipline(discipline); } } diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 51f9d4ea9..cbba20ded 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -152,10 +152,14 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val) void dll_target::expr_access_func(const NetEAccess*net) { assert(expr_ == 0); - - cerr << net->get_fileline() << ": internal error: " - << "Nature access functions not implemented yet." << endl; - + // Make a stub Branch Access Function expression node. + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + expr_->type_ = IVL_EX_BACCESS; + expr_->value_ = IVL_VT_REAL; + expr_->file = net->get_file(); + expr_->lineno = net->get_lineno(); + expr_->width_ = 1; + expr_->signed_= 1; } void dll_target::expr_binary(const NetEBinary*net) diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 791b14b75..98092d127 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -43,6 +43,17 @@ static void show_array_expression(ivl_expr_t net, unsigned ind) ivl_signal_dimensions(sig), width, vt); } +static void show_branch_access_expression(ivl_expr_t net, unsigned ind) +{ + fprintf(out, "%*s\n", ind, ""); + + if (ivl_expr_value(net) != IVL_VT_REAL) { + fprintf(out, "%*sERROR: Expecting type IVL_VT_REAL, got %s\n", + ind, "", vt_type_string(net)); + stub_errors += 1; + } +} + static void show_binary_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); @@ -216,6 +227,10 @@ void show_expression(ivl_expr_t net, unsigned ind) show_array_expression(net, ind); break; + case IVL_EX_BACCESS: + show_branch_access_expression(net, ind); + break; + case IVL_EX_BINARY: show_binary_expression(net, ind); break; From 8d7b03576c37f9d762bfd701c68aedbbd7b16451 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 5 Aug 2008 10:38:43 +0100 Subject: [PATCH 330/377] Correctly implement unary XNOR Forgot to negate the output. --- tgt-vhdl/lpm.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index fde076681..c6d11331f 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -251,7 +251,7 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) 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, SF_REDUCE_XOR, false); + return reduction_lpm_to_expr(scope, lpm, SF_REDUCE_XOR, true); case IVL_LPM_SIGN_EXT: return sign_extend_lpm_to_expr(scope, lpm); case IVL_LPM_ARRAY: From c849dfeec45bb5950b4c828f71286e96eb24d5b3 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 5 Aug 2008 10:45:01 +0100 Subject: [PATCH 331/377] Add XNOR logic device --- tgt-vhdl/logic.cc | 2 ++ tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 816178383..a6a9558fa 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -124,6 +124,8 @@ static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) return inputs_to_expr(scope, VHDL_BINOP_NOR, log); case IVL_LO_XOR: return inputs_to_expr(scope, VHDL_BINOP_XOR, log); + case IVL_LO_XNOR: + return inputs_to_expr(scope, VHDL_BINOP_XNOR, log); case IVL_LO_BUF: case IVL_LO_BUFZ: return nexus_to_var_ref(scope, ivl_logic_pin(log, 1)); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index f8932d2f0..663ba086c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -725,7 +725,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", ">", "<=", ">=", "sll", "srl", "xor", "&", - "nand", "nor", NULL + "nand", "nor", "xnor", NULL }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index e09d6ab63..158ac1fee 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -83,6 +83,7 @@ enum vhdl_binop_t { VHDL_BINOP_CONCAT, VHDL_BINOP_NAND, VHDL_BINOP_NOR, + VHDL_BINOP_XNOR, }; /* From e01e038cf9416e1b05c661c41a0bf3ec42a61916 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 5 Aug 2008 11:02:36 +0100 Subject: [PATCH 332/377] Avoid generating useless `wait for 0ns' statements If the final statement in a process is a non-blocking assignment then there is no point adding a `wait for 0ns' after it since it will be immediately followed by another wait. This case is suprisingly common, so this patch helps generate much cleaner output without breaking the cases where the 0ns wait is actually required (e.g. to implement non-blocking assignment properly). --- tgt-vhdl/stmt.cc | 30 +++++++++++++++++++----------- tgt-vhdl/vhdl_target.h | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 981a6b92c..a12f3c15a 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -81,11 +81,12 @@ static int draw_stask(vhdl_procedural *proc, stmt_container *container, * the stmt_container class behaves like a Verilog block. */ static int draw_block(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, bool is_last) { int count = ivl_stmt_block_count(stmt); for (int i = 0; i < count; i++) { - if (draw_stmt(proc, container, ivl_stmt_block_stmt(stmt, i)) != 0) + ivl_statement_t stmt_i = ivl_stmt_block_stmt(stmt, i); + if (draw_stmt(proc, container, stmt_i, is_last && i == count - 1) != 0) return 1; } return 0; @@ -318,7 +319,7 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container, } static int draw_assign(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, bool is_last) { if (proc->get_scope()->allow_signal_assignment()) { // Blocking assignment is implemented as non-blocking assignment @@ -326,9 +327,12 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container, // This follows the Verilog semantics fairly closely. make_assignment(proc, container, stmt, false); - - container->add_stmt - (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); + + // Don't generate a zero-wait if this is the last statement in + // the process + if (!is_last) + container->add_stmt + (new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0))); } else make_assignment(proc, container, stmt, true); @@ -422,7 +426,7 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } } - draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true); container->add_stmt(wait); } else { @@ -462,7 +466,7 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } container->add_stmt(new vhdl_wait_stmt(VHDL_WAIT_UNTIL, test)); - draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt)); + draw_stmt(proc, container, ivl_stmt_sub_stmt(stmt), true); } return 0; @@ -609,9 +613,13 @@ int draw_repeat(vhdl_procedural *proc, stmt_container *container, * add them to the given VHDL process. The container is the * location to add statements: e.g. the process body, a branch * of an if statement, etc. + * + * The flag is_last should be set if this is the final statement + * in a block or process. It avoids generating useless `wait for 0ns' + * statements if the next statement would be a wait anyway. */ int draw_stmt(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, bool is_last) { assert(stmt); @@ -619,11 +627,11 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_STASK: return draw_stask(proc, container, stmt); case IVL_ST_BLOCK: - return draw_block(proc, container, stmt); + return draw_block(proc, container, stmt, is_last); case IVL_ST_NOOP: return draw_noop(proc, container, stmt); case IVL_ST_ASSIGN: - return draw_assign(proc, container, stmt); + return draw_assign(proc, container, stmt, is_last); case IVL_ST_ASSIGN_NB: return draw_nbassign(proc, container, stmt); case IVL_ST_DELAY: diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index a86b154e4..5d5753379 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -18,7 +18,7 @@ void error(const char *fmt, ...); int draw_scope(ivl_scope_t scope, void *_parent); int draw_process(ivl_process_t net, void *cd); int draw_stmt(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt); + ivl_statement_t stmt, bool is_last = false); int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm); void draw_logic(vhdl_arch *arch, ivl_net_logic_t log); From f86f454956015760274d619639dc8dc10dd572e2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 5 Aug 2008 11:09:51 +0100 Subject: [PATCH 333/377] Apply the last patch to if/case statements too This further cleans up the output by removing more useless `wait for 0ns' statements. --- tgt-vhdl/stmt.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index a12f3c15a..fff4760a4 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -473,7 +473,7 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } static int draw_if(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, bool is_last) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) @@ -483,11 +483,11 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container, 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); + draw_stmt(proc, vhdif->get_then_container(), cond_true_stmt, is_last); ivl_statement_t cond_false_stmt = ivl_stmt_cond_false(stmt); if (cond_false_stmt) - draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt); + draw_stmt(proc, vhdif->get_else_container(), cond_false_stmt, is_last); container->add_stmt(vhdif); @@ -495,7 +495,7 @@ static int draw_if(vhdl_procedural *proc, stmt_container *container, } static int draw_case(vhdl_procedural *proc, stmt_container *container, - ivl_statement_t stmt) + ivl_statement_t stmt, bool is_last) { vhdl_expr *test = translate_expr(ivl_stmt_cond_expr(stmt)); if (NULL == test) @@ -543,8 +543,9 @@ static int draw_case(vhdl_procedural *proc, stmt_container *container, vhdl_case_branch *branch = new vhdl_case_branch(when); vhdlcase->add_branch(branch); - - draw_stmt(proc, branch->get_container(), ivl_stmt_case_stmt(stmt, i)); + + ivl_statement_t stmt_i = ivl_stmt_case_stmt(stmt, i); + draw_stmt(proc, branch->get_container(), stmt_i, is_last); } if (!have_others) { @@ -640,10 +641,10 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_WAIT: return draw_wait(proc, container, stmt); case IVL_ST_CONDIT: - return draw_if(proc, container, stmt); + return draw_if(proc, container, stmt, is_last); case IVL_ST_CASE: case IVL_ST_CASEX: - return draw_case(proc, container, stmt); + return draw_case(proc, container, stmt, is_last); case IVL_ST_WHILE: return draw_while(proc, container, stmt); case IVL_ST_FOREVER: From 4cbec1c817ee27cd335cd53a2850c3e40b2b0b89 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 6 Aug 2008 11:18:01 +0100 Subject: [PATCH 334/377] Add XNOR binary operand --- tgt-vhdl/expr.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index c1d57fc12..e0bf5cb43 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -302,6 +302,9 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case 'O': // Bitwise NOR result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR); break; + case 'X': // Bitwise XNOR + result = translate_numeric(lhs, rhs, VHDL_BINOP_XNOR); + break; case '|': // Bitwise OR result = translate_numeric(lhs, rhs, VHDL_BINOP_OR); break; From 6f5f700cb9fa256f747fe7b1d1f63be078f70f8a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 7 Aug 2008 10:54:39 +0100 Subject: [PATCH 335/377] Very minimal implementation of tasks This expands the task in-line inside the process to avoid problems with global variables (VHDL processes cannot reference globals) --- tgt-vhdl/stmt.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index fff4760a4..43e3a3f7e 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -609,6 +609,24 @@ int draw_repeat(vhdl_procedural *proc, stmt_container *container, return 0; } +/* + * Tasks are difficult to translate to VHDL since they allow things + * not allowed by VHDL's corresponding procedures (e.g. updating + * global variables. The solution here is to expand tasks in-line. + */ +int draw_utask(vhdl_procedural *proc, stmt_container *container, + ivl_statement_t stmt) +{ + ivl_scope_t tscope = ivl_stmt_call(stmt); + + // TODO: adding some comments to the output would be helpful + + // TOOD: this completely ignores paremeters! + draw_stmt(proc, container, ivl_scope_def(tscope), false); + + return 0; +} + /* * Generate VHDL statements for the given Verilog statement and * add them to the given VHDL process. The container is the @@ -651,6 +669,8 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, return draw_forever(proc, container, stmt); case IVL_ST_REPEAT: return draw_repeat(proc, container, stmt); + case IVL_ST_UTASK: + return draw_utask(proc, container, stmt); default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), From 28d782e13c3457ef55ce90018030eb9f2158e674 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 7 Aug 2008 13:10:53 +0100 Subject: [PATCH 336/377] Remove redundant verilog_support.vhd file --- tgt-vhdl/verilog_support.vhd | 58 ------------------------------------ tgt-vhdl/vhdl_syntax.cc | 1 - 2 files changed, 59 deletions(-) delete mode 100644 tgt-vhdl/verilog_support.vhd diff --git a/tgt-vhdl/verilog_support.vhd b/tgt-vhdl/verilog_support.vhd deleted file mode 100644 index b52cecd89..000000000 --- a/tgt-vhdl/verilog_support.vhd +++ /dev/null @@ -1,58 +0,0 @@ --- --- Support routines for Icarus Verilog VHDL output --- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -package Verilog_Support is - - -- This routine implements $finish by terminating the simulation - -- It is implemented via the VHPI interface - procedure finish; - attribute foreign of finish : procedure is "VHPIDIRECT finish"; - - -- 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; - -end Verilog_Support; - -package body Verilog_Support is - - -- This is a dummy body to provide a default implementation - -- if VHPI is not supported - procedure finish is - begin - assert false severity failure; - end finish; - - function Reduce_OR(X : unsigned) return std_logic is - begin - for I in X'range loop - if X(I) = '1' then - return '1'; - end if; - end loop; - 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 - return '1'; - else - return '0'; - end if; - end function; - -end Verilog_Support; diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 663ba086c..bf60a2bff 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -110,7 +110,6 @@ 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); From e4d0a92d7c949d7b1daaff6694a1ff2e85296b83 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 7 Aug 2008 14:18:26 +0100 Subject: [PATCH 337/377] Division and modulus operators --- tgt-vhdl/expr.cc | 6 ++++++ tgt-vhdl/lpm.cc | 4 ++++ tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 2 ++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index e0bf5cb43..64630ac57 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -270,6 +270,12 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case '*': result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT); break; + case '/': + result = translate_numeric(lhs, rhs, VHDL_BINOP_DIV); + break; + case '%': + result = translate_numeric(lhs, rhs, VHDL_BINOP_MOD); + break; case 'e': result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); break; diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index c6d11331f..7dc25ddf5 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -227,6 +227,10 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB); case IVL_LPM_MULT: return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT); + case IVL_LPM_DIVIDE: + return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_DIV); + case IVL_LPM_MOD: + return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MOD); case IVL_LPM_CONCAT: return concat_lpm_to_expr(scope, lpm); case IVL_LPM_CMP_GE: diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index bf60a2bff..4cb29c66e 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -724,7 +724,7 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const const char* ops[] = { "and", "or", "=", "/=", "+", "-", "*", "<", ">", "<=", ">=", "sll", "srl", "xor", "&", - "nand", "nor", "xnor", NULL + "nand", "nor", "xnor", "/", "mod", NULL }; of << " " << ops[op_] << " "; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 158ac1fee..a9fd93024 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -84,6 +84,8 @@ enum vhdl_binop_t { VHDL_BINOP_NAND, VHDL_BINOP_NOR, VHDL_BINOP_XNOR, + VHDL_BINOP_DIV, + VHDL_BINOP_MOD, }; /* From bb0efda526518398c7843772d64b9b14dd46d50c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 7 Aug 2008 17:58:42 +0100 Subject: [PATCH 338/377] Make make_safe_name case insensitive --- tgt-vhdl/scope.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 55ff84e73..30e671a05 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -24,6 +24,7 @@ #include #include #include +#include static string make_safe_name(ivl_signal_t sig); @@ -264,9 +265,9 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) */ static string make_safe_name(ivl_signal_t sig) { - string name(ivl_signal_basename(sig)); - if (name[0] == '_') - name.insert(0, "VL"); + const char *base = ivl_signal_basename(sig); + if (base[0] == '_') + return string("VL") + base; const char *vhdl_reserved[] = { "in", "out", "entity", "architecture", "inout", "array", @@ -274,12 +275,12 @@ static string make_safe_name(ivl_signal_t sig) NULL }; for (const char **p = vhdl_reserved; *p != NULL; p++) { - if (name == *p) { - name.insert(0, "VL_"); + if (strcasecmp(*p, base) == 0) { + return string("VL_") + base; break; } } - return name; + return string(base); } /* From 13cb81f4bb1b82928a38195281ab2d36c9e2351f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 19:31:45 +0100 Subject: [PATCH 339/377] Add task signals to containing architecture This is necessary to support the in-line expansion of tasks --- tgt-vhdl/scope.cc | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 30e671a05..2b2c4e604 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -554,6 +554,45 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) return 0; } + +/* + * Create the signals necessary to expand this task later. + */ +static int draw_task(ivl_scope_t scope, ivl_scope_t parent) +{ + assert(ivl_scope_type(scope) == IVL_SCT_TASK); + + // Find the containing entity + vhdl_entity *ent = find_entity(ivl_scope_name(parent)); + assert(ent); + + const char *taskname = ivl_scope_tname(scope); + + 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 = + vhdl_type::type_for(ivl_signal_width(sig), + ivl_signal_signed(sig) != 0); + + string signame(make_safe_name(sig)); + + vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype); + + ostringstream ss; + ss << "Declared at " << ivl_signal_file(sig) << ":" + << ivl_signal_lineno(sig) << " (in task " << taskname << ")"; + decl->set_comment(ss.str().c_str()); + + ent->get_arch()->get_scope()->add_decl(decl); + + remember_signal(sig, ent->get_arch()->get_scope()); + rename_signal(sig, signame); + } + + return 0; +} + /* * Create an empty VHDL entity for a Verilog module. */ @@ -618,12 +657,13 @@ static int draw_functions(ivl_scope_t scope, void *_parent) { ivl_scope_t parent = static_cast(_parent); if (ivl_scope_type(scope) == IVL_SCT_FUNCTION) { - vhdl_entity *ent = find_entity(ivl_scope_name(parent)); - assert(ent); - if (draw_function(scope, parent) != 0) return 1; } + else if (ivl_scope_type(scope) == IVL_SCT_TASK) { + if (draw_task(scope, parent) != 0) + return 1; + } return ivl_scope_children(scope, draw_functions, scope); } From 090ae5fa568c50038f5b2aa6942023a14c018420 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 19:47:20 +0100 Subject: [PATCH 340/377] Catch case where signal with same name in task and module This fixes task3.14C --- tgt-vhdl/scope.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 2b2c4e604..c52106561 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -577,6 +577,12 @@ static int draw_task(ivl_scope_t scope, ivl_scope_t parent) string signame(make_safe_name(sig)); + // Check this signal isn't declared in the outer scope + if (ent->get_arch()->get_scope()->have_declared(signame)) { + signame += "_"; + signame += taskname; + } + vhdl_signal_decl *decl = new vhdl_signal_decl(signame.c_str(), sigtype); ostringstream ss; From 09851580902c1a1c7d06aa0332915351fcbe7109 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 20:07:22 +0100 Subject: [PATCH 341/377] Handle %% in $display --- tgt-vhdl/display.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index e70f1bce5..91367b466 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -141,10 +141,15 @@ int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ss << ch; p += 3; } - else if (*p == '%') { + else if (*p == '%' && *(++p) != '%') { flush_string(ss, container); - p++; // Ignore the format (!) + // TODO: This needs to be re-written + // ...it does not handle format codes at all! + // Unfortunately, there is no printf-like + // function in VHDL + + assert(i < count); ivl_expr_t net = ivl_stmt_parm(stmt, i++); assert(net); From eef1c968dc1d66e5d1c91bf9d276ebc245ff87f2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 20:09:40 +0100 Subject: [PATCH 342/377] Add message that casex cannot be translated ...with the correct behavior. It would be possible to just translate it as a regular VHDL case statement (as it was before this patch). But the behavior is not correct as VHDL only does the equivalent of case-equality in case statements and this can be confusing when debugging the output. An alternative might be to emit a warning rather than an error. --- tgt-vhdl/stmt.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 43e3a3f7e..f9db883bc 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -661,7 +661,6 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_CONDIT: return draw_if(proc, container, stmt, is_last); case IVL_ST_CASE: - case IVL_ST_CASEX: return draw_case(proc, container, stmt, is_last); case IVL_ST_WHILE: return draw_while(proc, container, stmt); @@ -671,6 +670,9 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, return draw_repeat(proc, container, stmt); case IVL_ST_UTASK: return draw_utask(proc, container, stmt); + case IVL_ST_CASEX: + error("casex statement cannot be translated to VHDL"); + return 1; default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), From 7ed8c0915db77b41f7e21511a860d5e3fe540d44 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 20:28:16 +0100 Subject: [PATCH 343/377] Add file/line comments to signal declarations --- tgt-vhdl/scope.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index c52106561..b5c406463 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -331,6 +331,12 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) case IVL_SIP_NONE: { vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); + + ostringstream ss; + ss << "Declared at " << ivl_signal_file(sig) << ":" + << ivl_signal_lineno(sig); + decl->set_comment(ss.str().c_str()); + ent->get_arch()->get_scope()->add_decl(decl); } break; From 709c850e69140c528e3766f56757f7e8fd15116c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 8 Aug 2008 20:35:27 +0100 Subject: [PATCH 344/377] Add correct file/line information to signals This patch adds a FILE_NAME function for signals to extract the file/line information from the net's LineInfo, replacing the dummy values. --- t-dll.cc | 3 +-- t-dll.h | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/t-dll.cc b/t-dll.cc index 06cd40220..e11692145 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2374,8 +2374,7 @@ void dll_target::signal(const NetNet*net) object, or creating the sigs_ array if this is the first signal. */ obj->scope_ = find_scope(des_, net->scope()); - obj->file = perm_string::literal("N/A"); - obj->lineno = 0; + FILE_NAME(obj, net); assert(obj->scope_); if (obj->scope_->nsigs_ == 0) { diff --git a/t-dll.h b/t-dll.h index 3bb1b9279..c409a6ce9 100644 --- a/t-dll.h +++ b/t-dll.h @@ -771,4 +771,10 @@ static inline void FILE_NAME(ivl_process_t net, const LineInfo*info) net->lineno = info->get_lineno(); } +static inline void FILE_NAME(ivl_signal_t net, const LineInfo*info) +{ + net->file = info->get_file(); + net->lineno = info->get_lineno(); +} + #endif From 8e0bf3ebff3027a53274c87978893982985c30f7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 10 Aug 2008 11:22:23 +0100 Subject: [PATCH 345/377] Add conversion from std_logic to (un)signed types Implemented using the expression (0 => X, others => '0') --- tgt-vhdl/cast.cc | 9 +++++++++ tgt-vhdl/vhdl_syntax.cc | 31 +++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 21 +++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 167efc4d2..43fcf6aaf 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -83,6 +83,15 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return conv; } + else if ((to->get_name() == VHDL_TYPE_UNSIGNED + || to->get_name() == VHDL_TYPE_SIGNED) && + type_->get_name() == VHDL_TYPE_STD_LOGIC) { + vhdl_bit_spec_expr *bs = + new vhdl_bit_spec_expr(new vhdl_type(*to), new vhdl_const_bit('0')); + bs->add_bit(0, this); + + return bs; + } else if (to->get_name() == VHDL_TYPE_STD_LOGIC && type_->get_name() == VHDL_TYPE_BOOLEAN) { require_support_function(SF_BOOLEAN_TO_LOGIC); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 4cb29c66e..c96ca6ffa 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -735,6 +735,37 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const of << ")"; } +vhdl_bit_spec_expr::~vhdl_bit_spec_expr() +{ + delete others_; + + std::list::iterator it; + for (it = bits_.begin(); it != bits_.end(); ++it) + delete (*it).e; +} + +void vhdl_bit_spec_expr::add_bit(int bit, vhdl_expr *e) +{ + bit_map bm = { bit, e }; + bits_.push_back(bm); +} + +void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const +{ + of << "("; + + std::list::const_iterator it; + for (it = bits_.begin(); it != bits_.end(); ++it) { + of << (*it).bit << " => "; + (*it).e->emit(of, level); + of << ", "; + } + + of << "others => "; + others_->emit(of, level); + of << ")"; +} + vhdl_case_branch::~vhdl_case_branch() { delete when_; diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a9fd93024..855173ab6 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -129,6 +129,27 @@ private: }; +/* + * An expression like (0 => '1', 2 => '0', others => 'Z') + */ +class vhdl_bit_spec_expr : public vhdl_expr { +public: + vhdl_bit_spec_expr(vhdl_type *type, vhdl_expr *others) + : vhdl_expr(type), others_(others) {} + ~vhdl_bit_spec_expr(); + + void add_bit(int bit, vhdl_expr *e); + void emit(std::ostream &of, int level) const; +private: + vhdl_expr *others_; + struct bit_map { + int bit; + vhdl_expr *e; + }; + std::list bits_; +}; + + class vhdl_const_string : public vhdl_expr { public: vhdl_const_string(const char *value) From 6dcf936807e14768c2595741f86906796e4c6cb5 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 12:58:46 +0100 Subject: [PATCH 346/377] Generate combined input for UDP devices Combinatorial UDPs will be implemented with a `with ... select' statemetnt. However the input to this must be "locally static". This patch joins the inputs into a vector which can be used as the select expression. --- tgt-vhdl/cast.cc | 7 +++++-- tgt-vhdl/logic.cc | 31 +++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.cc | 16 +++++++++++----- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 43fcf6aaf..c6675c686 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -84,10 +84,13 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return conv; } else if ((to->get_name() == VHDL_TYPE_UNSIGNED - || to->get_name() == VHDL_TYPE_SIGNED) && + || to->get_name() == VHDL_TYPE_SIGNED + || to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) && type_->get_name() == VHDL_TYPE_STD_LOGIC) { + + vhdl_expr *others = to->get_width() == 1 ? NULL : new vhdl_const_bit('0'); vhdl_bit_spec_expr *bs = - new vhdl_bit_spec_expr(new vhdl_type(*to), new vhdl_const_bit('0')); + new vhdl_bit_spec_expr(new vhdl_type(*to), others); bs->add_bit(0, this); return bs; diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index a6a9558fa..ccf95d9f0 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -22,6 +22,7 @@ #include "vhdl_element.hh" #include +#include #include @@ -106,6 +107,36 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) error("Sequential UDP devices not supported yet"); return; } + + // As with regular case statements, the expression in a + // `with .. select' statement must be "locally static". + // This is achieved by first combining the inputs into + // a temporary + + ostringstream ss; + ss << ivl_logic_basename(log) << "_Tmp"; + int msb = ivl_udp_nin(udp) - 1; + vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); + vhdl_signal_decl *tmp_decl = + new vhdl_signal_decl(ss.str().c_str(), tmp_type); + arch->get_scope()->add_decl(tmp_decl); + + vhdl_expr *tmp_rhs; + if (ivl_udp_nin(udp) == 1) { + tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); + tmp_rhs = tmp_rhs->cast(tmp_type); + } + else + tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log); + + ss.str(""); + ss << "Input to " << ivl_logic_basename(log) << " " + << ivl_udp_name(udp) << " UDP"; + tmp_decl->set_comment(ss.str()); + + vhdl_var_ref *tmp_ref = + new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL); + arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs)); } diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index c96ca6ffa..4e5bf581d 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -737,7 +737,8 @@ void vhdl_binop_expr::emit(std::ostream &of, int level) const vhdl_bit_spec_expr::~vhdl_bit_spec_expr() { - delete others_; + if (others_) + delete others_; std::list::iterator it; for (it = bits_.begin(); it != bits_.end(); ++it) @@ -755,14 +756,19 @@ void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const of << "("; std::list::const_iterator it; - for (it = bits_.begin(); it != bits_.end(); ++it) { + it = bits_.begin(); + while (it != bits_.end()) { of << (*it).bit << " => "; (*it).e->emit(of, level); - of << ", "; + if (++it != bits_.end()) + of << ", "; } - of << "others => "; - others_->emit(of, level); + if (others_) { + of << ", others => "; + others_->emit(of, level); + } + of << ")"; } From bf3734110e81febb95824129e16f3f0d1305dca9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 13:09:52 +0100 Subject: [PATCH 347/377] Add VHDL syntax element for `with .. select' statement This will be used to implement combinatorial UDPs --- tgt-vhdl/vhdl_syntax.cc | 38 ++++++++++++++++++++++++++++++++++++++ tgt-vhdl/vhdl_syntax.hh | 30 +++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 4e5bf581d..d07edc7ce 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -888,3 +888,41 @@ void vhdl_param_decl::emit(std::ostream &of, int level) const of << name_ << " : "; type_->emit(of, level); } + +vhdl_with_select_stmt::~vhdl_with_select_stmt() +{ + delete test_; + + for (when_list_t::const_iterator it = whens_.begin(); + it != whens_.end(); + ++it) { + delete (*it).value; + delete (*it).cond; + } +} + +void vhdl_with_select_stmt::emit(std::ostream &of, int level) const +{ + emit_comment(of, level); + + of << "with "; + test_->emit(of, level); + of << " select"; + newline(of, indent(level)); + + when_list_t::const_iterator it = whens_.begin(); + while (it != whens_.end()) { + if (++it != whens_.end()) { + of << ","; + newline(of, indent(level)); + } + else + of << ";"; + } +} + +void vhdl_with_select_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) +{ + when_part_t when = { value, cond }; + whens_.push_back(when); +} diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 855173ab6..6d3bf8fc5 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -254,6 +254,16 @@ public: typedef std::list conc_stmt_list_t; +/* + * A ' when ' clause that appears in several + * statement types. + */ +struct when_part_t { + vhdl_expr *value, *cond; +}; +typedef std::list when_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 @@ -272,13 +282,23 @@ private: vhdl_var_ref *lhs_; vhdl_expr *rhs_; vhdl_expr *after_; - - struct when_part_t { - vhdl_expr *value, *cond; - }; - std::list whens_; + when_list_t whens_; }; + +class vhdl_with_select_stmt : public vhdl_conc_stmt { +public: + vhdl_with_select_stmt(vhdl_expr *test) : test_(test) {} + ~vhdl_with_select_stmt(); + + void emit(std::ostream &of, int level) const; + void add_condition(vhdl_expr *value, vhdl_expr *cond); +private: + vhdl_expr *test_; + when_list_t whens_; +}; + + /* * Any sequential statement in a process. */ From 01bf741983785e5b4bb8db1f207e86ddac73e4e9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 13:23:50 +0100 Subject: [PATCH 348/377] Implement combinatorial UDPs Using a `with .. select' statement --- tgt-vhdl/logic.cc | 27 +++++++++++++++++++++++++-- tgt-vhdl/vhdl_syntax.cc | 11 +++++++++-- tgt-vhdl/vhdl_syntax.hh | 4 +++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index ccf95d9f0..6b3d1f55f 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -120,9 +120,10 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) vhdl_signal_decl *tmp_decl = new vhdl_signal_decl(ss.str().c_str(), tmp_type); arch->get_scope()->add_decl(tmp_decl); - + + int nin = ivl_udp_nin(udp); vhdl_expr *tmp_rhs; - if (ivl_udp_nin(udp) == 1) { + if (nin == 1) { tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); tmp_rhs = tmp_rhs->cast(tmp_type); } @@ -137,7 +138,29 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) vhdl_var_ref *tmp_ref = new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL); arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs)); + + // Now we can implement the UDP as a `with .. select' statement + // by reading values out of the table + ivl_nexus_t output_nex = ivl_logic_pin(log, 0); + vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex); + vhdl_with_select_stmt *ws = + new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out); + int nrows = ivl_udp_rows(udp); + for (int i = 0; i < nrows; i++) { + const char *row = ivl_udp_row(udp, i); + + vhdl_expr *value = new vhdl_const_bit(row[nin]); + vhdl_expr *cond = new vhdl_const_bits(row, nin, false); + + ws->add_condition(value, cond); + } + + ss.str(""); + ss << "UDP " << ivl_udp_name(udp); + ws->set_comment(ss.str()); + + arch->add_stmt(ws); } static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d07edc7ce..0e4716400 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -892,6 +892,7 @@ void vhdl_param_decl::emit(std::ostream &of, int level) const vhdl_with_select_stmt::~vhdl_with_select_stmt() { delete test_; + delete out_; for (when_list_t::const_iterator it = whens_.begin(); it != whens_.end(); @@ -903,15 +904,21 @@ vhdl_with_select_stmt::~vhdl_with_select_stmt() void vhdl_with_select_stmt::emit(std::ostream &of, int level) const { - emit_comment(of, level); - of << "with "; test_->emit(of, level); of << " select"; + emit_comment(of, level, true); newline(of, indent(level)); + out_->emit(of, level); + of << " <= "; + when_list_t::const_iterator it = whens_.begin(); while (it != whens_.end()) { + (*it).value->emit(of, level); + of << " when "; + (*it).cond->emit(of, level); + if (++it != whens_.end()) { of << ","; newline(of, indent(level)); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 6d3bf8fc5..281e5b459 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -288,13 +288,15 @@ private: class vhdl_with_select_stmt : public vhdl_conc_stmt { public: - vhdl_with_select_stmt(vhdl_expr *test) : test_(test) {} + vhdl_with_select_stmt(vhdl_expr *test, vhdl_var_ref *out) + : test_(test), out_(out) {} ~vhdl_with_select_stmt(); void emit(std::ostream &of, int level) const; void add_condition(vhdl_expr *value, vhdl_expr *cond); private: vhdl_expr *test_; + vhdl_var_ref *out_; when_list_t whens_; }; From d55a3a073ac731ec9ec87ee39a2ce8d4191afcd9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 13:53:42 +0100 Subject: [PATCH 349/377] Handle '?' in vl_to_vhdl_bit The rough translation is '-', although the semantics are incompatible in some cases (e.g. '-' = '1' is false) --- tgt-vhdl/vhdl_helper.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index d003ff1ef..a9c4b7717 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -69,6 +69,8 @@ static inline char vl_to_vhdl_bit(char bit) case 'x': case 'X': return 'U'; + case '?': + return '-'; } assert(false); } From 9d7e4ac15ffb1f5ba02638727b58467b85203757 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 20:36:09 +0100 Subject: [PATCH 350/377] Allow delays in combinatorial UDPs Add a `after' clause to the `with .. select' statement. --- tgt-vhdl/logic.cc | 3 ++- tgt-vhdl/vhdl_syntax.cc | 12 +++++++++--- tgt-vhdl/vhdl_syntax.hh | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 6b3d1f55f..37315be35 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -152,8 +152,9 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) vhdl_expr *value = new vhdl_const_bit(row[nin]); vhdl_expr *cond = new vhdl_const_bits(row, nin, false); + vhdl_expr *delay = translate_time_expr(ivl_logic_delay(log, 1)); - ws->add_condition(value, cond); + ws->add_condition(value, cond, delay); } ss.str(""); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 0e4716400..02ba26647 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -611,7 +611,7 @@ vhdl_cassign_stmt::~vhdl_cassign_stmt() void vhdl_cassign_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) { - when_part_t when = { value, cond }; + when_part_t when = { value, cond, NULL }; whens_.push_back(when); } @@ -899,6 +899,8 @@ vhdl_with_select_stmt::~vhdl_with_select_stmt() ++it) { delete (*it).value; delete (*it).cond; + if ((*it).delay) + delete (*it).delay; } } @@ -916,6 +918,10 @@ void vhdl_with_select_stmt::emit(std::ostream &of, int level) const when_list_t::const_iterator it = whens_.begin(); while (it != whens_.end()) { (*it).value->emit(of, level); + if ((*it).delay) { + of << " after "; + (*it).delay->emit(of, level); + } of << " when "; (*it).cond->emit(of, level); @@ -928,8 +934,8 @@ void vhdl_with_select_stmt::emit(std::ostream &of, int level) const } } -void vhdl_with_select_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond) +void vhdl_with_select_stmt::add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay) { - when_part_t when = { value, cond }; + when_part_t when = { value, cond, delay }; whens_.push_back(when); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 281e5b459..a4ebb7c5d 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -259,7 +259,7 @@ typedef std::list conc_stmt_list_t; * statement types. */ struct when_part_t { - vhdl_expr *value, *cond; + vhdl_expr *value, *cond, *delay; }; typedef std::list when_list_t; @@ -293,7 +293,7 @@ public: ~vhdl_with_select_stmt(); void emit(std::ostream &of, int level) const; - void add_condition(vhdl_expr *value, vhdl_expr *cond); + void add_condition(vhdl_expr *value, vhdl_expr *cond, vhdl_expr *delay=NULL); private: vhdl_expr *test_; vhdl_var_ref *out_; From 9b1f2d5971946b27887abfdcf76993a0239f48b9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 20:37:10 +0100 Subject: [PATCH 351/377] Remove UDP debug messages from output --- tgt-vhdl/logic.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 37315be35..46cf26372 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -99,10 +99,6 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { ivl_udp_t udp = ivl_logic_udp(log); - cout << "UDP " << ivl_udp_name(udp) << " nin=" - << ivl_udp_nin(udp) << " rows=" - << ivl_udp_rows(udp) << endl; - if (ivl_udp_sequ(udp)) { error("Sequential UDP devices not supported yet"); return; From c404b761b753c0eefc275a59ee029661f2be8caf Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 20:48:28 +0100 Subject: [PATCH 352/377] Change `out' ports to `buffer' when the signal is read Previously this was handled by creating an internal signal that was connected to the output and could also be read inside the entity. The correct solution is to make the output `buffer' rather than `out'. However, this does not work in the case when an output is connected to an output of a child entity, and that values is read in the parent. In this case *both* the outputs of the child and the parent need to be made `buffer'. --- tgt-vhdl/scope.cc | 44 +++++++++++------------------------------ tgt-vhdl/vhdl_syntax.cc | 3 +++ tgt-vhdl/vhdl_syntax.hh | 2 ++ 3 files changed, 17 insertions(+), 32 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index b5c406463..d105fa42e 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -425,45 +425,25 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, // 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. + // The VHDL equivalent of this is to make *both* output ports + // a `buffer'. vhdl_decl *decl = parent->get_arch()->get_scope()->get_decl(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 - string shadow_name(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 - (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(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(), ref); + // First change the mode in the parent entity + pdecl->set_mode(VHDL_PORT_BUFFER); + + // Now change the mode in the child entity + vhdl_port_decl *to_pdecl = + dynamic_cast(find_scope_for_signal(to)->get_decl(name)); + assert(to_pdecl); + to_pdecl->set_mode(VHDL_PORT_BUFFER); } + + inst->map_port(name.c_str(), ref); } /* diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 02ba26647..e8dce1629 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -373,6 +373,9 @@ void vhdl_port_decl::emit(std::ostream &of, int level) const case VHDL_PORT_INOUT: of << "inout "; break; + case VHDL_PORT_BUFFER: + of << "buffer "; + break; } type_->emit(of, level); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a4ebb7c5d..7180f4453 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -595,6 +595,7 @@ enum vhdl_port_mode_t { VHDL_PORT_IN, VHDL_PORT_OUT, VHDL_PORT_INOUT, + VHDL_PORT_BUFFER, }; /* @@ -610,6 +611,7 @@ public: void emit(std::ostream &of, int level) const; vhdl_port_mode_t get_mode() const { return mode_; } + void set_mode(vhdl_port_mode_t m) { mode_ = m; } private: vhdl_port_mode_t mode_; }; From a3929330b075d92a79202c7ddec5b35a3eae27cf Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 11 Aug 2008 20:53:13 +0100 Subject: [PATCH 353/377] Fix regression caused by UDP delay patch translate_time_expr cannot be passed a NULL ivl_expr_t. --- tgt-vhdl/logic.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 46cf26372..ca77c45d2 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -148,7 +148,11 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) vhdl_expr *value = new vhdl_const_bit(row[nin]); vhdl_expr *cond = new vhdl_const_bits(row, nin, false); - vhdl_expr *delay = translate_time_expr(ivl_logic_delay(log, 1)); + + ivl_expr_t delay_ex = ivl_logic_delay(log, 1); + vhdl_expr *delay = NULL; + if (delay_ex) + delay = translate_time_expr(delay_ex); ws->add_condition(value, cond, delay); } From dea54df71b60b24874c6abdb303f0f636a2b561f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 12 Aug 2008 09:47:03 +0100 Subject: [PATCH 354/377] Catch possibly NULL return value This is caused by using a hierarchical reference (which can't be translated to VHDL). The result of get_decl is NULL since the signal has been declared in a different VHDL architecture. Adding the assert is cleaner than having it segfault, for the moment, until a nicer error message can be added. --- tgt-vhdl/stmt.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index f9db883bc..371fc5cb5 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -126,6 +126,7 @@ static vhdl_var_ref *make_assign_lhs(ivl_lval_t lval, vhdl_scope *scope) string signame(get_renamed_signal(sig)); vhdl_decl *decl = scope->get_decl(signame); + assert(decl); vhdl_type *ltype = new vhdl_type(*decl->get_type()); vhdl_var_ref *lval_ref = new vhdl_var_ref(signame.c_str(), ltype); From d7b85c42a0ec4305af01e24b76815e14f5776198 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 13 Aug 2008 11:57:05 +0100 Subject: [PATCH 355/377] Split sequential and combinatorial UDPs into separate functions --- tgt-vhdl/logic.cc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index ca77c45d2..a5bc92fb5 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -95,15 +95,10 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) arch->add_stmt(cass); } -static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) +static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { ivl_udp_t udp = ivl_logic_udp(log); - - if (ivl_udp_sequ(udp)) { - error("Sequential UDP devices not supported yet"); - return; - } - + // As with regular case statements, the expression in a // `with .. select' statement must be "locally static". // This is achieved by first combining the inputs into @@ -164,6 +159,19 @@ static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) arch->add_stmt(ws); } +static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) +{ + error("Sequential UDP devices not supported yet"); +} + +static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) +{ + if (ivl_udp_sequ(ivl_logic_udp(log))) + seq_udp_logic(arch, log); + else + comb_udp_logic(arch, log); +} + static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log) { switch (ivl_logic_type(log)) { From a577ee447b51b80894d9951b5fb325854b356a7e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 13 Aug 2008 17:03:03 +0100 Subject: [PATCH 356/377] Generate process for sequential UDPs --- tgt-vhdl/logic.cc | 46 ++++++++++++++++++++++++++++++++++++++++- tgt-vhdl/vhdl_syntax.cc | 2 +- tgt-vhdl/vhdl_syntax.hh | 2 +- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index a5bc92fb5..97acb9a16 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -161,7 +161,51 @@ static void comb_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) static void seq_udp_logic(vhdl_arch *arch, ivl_net_logic_t log) { - error("Sequential UDP devices not supported yet"); + ivl_udp_t udp = ivl_logic_udp(log); + + // These will be translated to a process with a single + // case statement + + vhdl_process *proc = new vhdl_process(ivl_logic_basename(log)); + + ostringstream ss; + ss << "Generated from UDP " << ivl_udp_name(udp); + proc->set_comment(ss.str().c_str()); + + // Create a variable to hold the concatenation of the inputs + int msb = ivl_udp_nin(udp) - 1; + vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0); + proc->get_scope()->add_decl(new vhdl_var_decl("UDP_Inputs", tmp_type)); + + // Concatenate the inputs into a single expression that can be + // used as the test in a case statement (this can't be inserted + // directly into the case statement due to the requirement that + // the test expression be "locally static") + int nin = ivl_udp_nin(udp); + vhdl_expr *tmp_rhs = NULL; + if (nin == 1) { + vhdl_var_ref *ref = + nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1)); + tmp_rhs = ref->cast(tmp_type); + proc->add_sensitivity(ref->get_name()); + } + else { + vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, NULL); + + for (int i = 1; i < nin; i++) { + vhdl_var_ref *ref = + nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, i)); + concat->add_expr(ref); + proc->add_sensitivity(ref->get_name()); + } + + tmp_rhs = concat; + } + + proc->get_container()->add_stmt + (new vhdl_assign_stmt(new vhdl_var_ref("UDP_Inputs", NULL), tmp_rhs)); + + arch->add_stmt(proc); } static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e8dce1629..6bb246e4d 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -156,7 +156,7 @@ void vhdl_arch::emit(std::ostream &of, int level) const blank_line(of, level); // Extra blank line after architectures; } -void vhdl_process::add_sensitivity(const char *name) +void vhdl_process::add_sensitivity(const std::string &name) { sens_.push_back(name); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 7180f4453..c1c63bd25 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -724,7 +724,7 @@ public: vhdl_process(const char *name = "") : name_(name) {} void emit(std::ostream &of, int level) const; - void add_sensitivity(const char *name); + void add_sensitivity(const std::string &name); private: std::string name_; string_list_t sens_; From 026d9417344f79376a6edd27fc08ecff10bfc3df Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 15 Aug 2008 19:43:16 +0100 Subject: [PATCH 357/377] Avoid printing field widths in $display/$write output This removes some unwanted artifacts from the output. --- tgt-vhdl/display.cc | 88 +++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 91367b466..b230002cc 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -126,55 +126,59 @@ int draw_stask_display(vhdl_procedural *proc, stmt_container *container, // the expression will be null // The behaviour here seems to be to output a space ivl_expr_t net = ivl_stmt_parm(stmt, i++); - if (net) { - if (ivl_expr_type(net) == IVL_EX_STRING) { - std::ostringstream ss; - for (const char *p = ivl_expr_string(net); *p; p++) { - if (*p == '\\') { - // Octal escape - char ch = parse_octal(p+1); - if (ch == '\n') { - flush_string(ss, container); - display_line(container); - } - else - ss << ch; - p += 3; - } - else if (*p == '%' && *(++p) != '%') { + if (net == NULL) { + display_write(container, new vhdl_const_string(" ")); + continue; + } + + if (ivl_expr_type(net) == IVL_EX_STRING) { + ostringstream ss; + for (const char *p = ivl_expr_string(net); *p; p++) { + if (*p == '\\') { + // Octal escape + char ch = parse_octal(p+1); + if (ch == '\n') { flush_string(ss, container); - - // TODO: This needs to be re-written - // ...it does not handle format codes at all! - // Unfortunately, there is no printf-like - // function in VHDL - - assert(i < count); - ivl_expr_t net = ivl_stmt_parm(stmt, i++); - assert(net); - - vhdl_expr *base = translate_expr(net); - if (NULL == base) - return 1; - - display_write(container, base); + display_line(container); } else - ss << *p; + ss << ch; + p += 3; } + else if (*p == '%' && *(++p) != '%') { + flush_string(ss, container); + + // Skip over width for now + while (isdigit(*p)) ++p; + + // TODO: This needs to be re-written + // ...it does not handle format codes at all! + // Unfortunately, there is no printf-like + // function in VHDL - display_write(container, new vhdl_const_string(ss.str().c_str())); - } - else { - vhdl_expr *base = translate_expr(net); - if (NULL == base) - return 1; - - display_write(container, base); + assert(i < count); + ivl_expr_t net = ivl_stmt_parm(stmt, i++); + assert(net); + + vhdl_expr *base = translate_expr(net); + if (NULL == base) + return 1; + + display_write(container, base); + } + else + ss << *p; } + + display_write(container, new vhdl_const_string(ss.str().c_str())); + } + else { + vhdl_expr *base = translate_expr(net); + if (NULL == base) + return 1; + + display_write(container, base); } - else - display_write(container, new vhdl_const_string(" ")); } if (newline) From 6adc3c9f1314338607bd57a6a4852a0256110217 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sun, 17 Aug 2008 19:42:07 +0100 Subject: [PATCH 358/377] Add short section on VHDL to man page --- driver/iverilog.man | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/driver/iverilog.man b/driver/iverilog.man index 05d936a1d..3c74e9feb 100644 --- a/driver/iverilog.man +++ b/driver/iverilog.man @@ -223,6 +223,12 @@ mostly by EDIF format output. The Icarus Verilog fpga code generator can generate complete designs or EDIF macros that can in turn be imported into larger designs by other tools. The \fBfpga\fP target implies the synthesis \fB-S\fP flag. +.TP 8 +.B vhdl +This target produces a VHDL translation of the Verilog netlist. The +output is a single file containing VHDL entities corresponding to +the modules in the Verilog source code. Note that only a subset of +the Verilog language is supported. See the wiki for more information. .SH "WARNING TYPES" These are the types of warnings that can be selected by the \fB-W\fP From e2dd7425bde564d5b1d85b1f71aadb50f22da4e2 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 15:24:38 +0100 Subject: [PATCH 359/377] Add error messages for unsupported statement types --- tgt-vhdl/stmt.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 371fc5cb5..dbfc205e3 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -674,6 +674,13 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_CASEX: error("casex statement cannot be translated to VHDL"); return 1; + case IVL_ST_FORK: + error("fork statement cannot be translated to VHDL"); + return 1; + case IVL_ST_CASSIGN: + case IVL_ST_DEASSIGN: + error("continuous procedural assignment cannot be translated to VHDL"); + return 1; default: error("No VHDL translation for statement at %s:%d (type = %d)", ivl_stmt_file(stmt), ivl_stmt_lineno(stmt), From 86661c153890b54d034ef234147667d37a621671 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 15:29:30 +0100 Subject: [PATCH 360/377] Add a few more `unsupported' messages --- tgt-vhdl/stmt.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index dbfc205e3..94f550d21 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -671,6 +671,13 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, return draw_repeat(proc, container, stmt); case IVL_ST_UTASK: return draw_utask(proc, container, stmt); + case IVL_ST_FORCE: + case IVL_ST_RELEASE: + error("force/release statements cannot be translated to VHDL"); + return 1; + case IVL_ST_DISABLE: + error("disable statement cannot be translated to VHDL"); + return 1; case IVL_ST_CASEX: error("casex statement cannot be translated to VHDL"); return 1; From 7865264de0eef3261dd88da375e856f38665b19b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 15:34:58 +0100 Subject: [PATCH 361/377] Implement IVL_LPM_REPEAT --- tgt-vhdl/lpm.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 7dc25ddf5..3c2af5ead 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -218,6 +218,12 @@ static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype); } +static vhdl_expr *repeat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) +{ + vhdl_expr *in = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0)); + return new vhdl_bit_spec_expr(NULL, in); +} + static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) { switch (ivl_lpm_type(lpm)) { @@ -264,6 +270,8 @@ static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm) return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL); case IVL_LPM_SHIFTR: return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR); + case IVL_LPM_REPEAT: + return repeat_lpm_to_expr(scope, lpm); default: error("Unsupported LPM type: %d", ivl_lpm_type(lpm)); return NULL; From d53014a07f42e18d2e6baba50d271bd443c85d66 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 15:36:11 +0100 Subject: [PATCH 362/377] Fix leading comma it expression only has "others" part Stop syntax errors caused by things like this: (, others => '1') --- tgt-vhdl/vhdl_syntax.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 6bb246e4d..e24a40cfb 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -768,7 +768,7 @@ void vhdl_bit_spec_expr::emit(std::ostream &of, int level) const } if (others_) { - of << ", others => "; + of << (bits_.empty() ? "" : ", ") << "others => "; others_->emit(of, level); } From e1deba51ab358f82cc5ab305b0f1330632e05bd7 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 15:48:07 +0100 Subject: [PATCH 363/377] Handle BUFIF logic when vector inputs --- tgt-vhdl/cast.cc | 16 ++++++++++++++++ tgt-vhdl/logic.cc | 19 +++++++++++++++---- tgt-vhdl/vhdl_syntax.hh | 1 + 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index c6675c686..339e9c8ae 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -139,6 +139,22 @@ vhdl_expr *vhdl_expr::resize(int newwidth) return resize; } +vhdl_expr *vhdl_const_int::cast(const vhdl_type *to) +{ + if (to->get_name() == VHDL_TYPE_SIGNED + || to->get_name() == VHDL_TYPE_UNSIGNED) { + + const char *fname = to->get_name() == VHDL_TYPE_SIGNED + ? "To_Signed" : "To_Unsigned"; + vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(*to)); + conv->add_expr(this); + conv->add_expr(new vhdl_const_int(to->get_width())); + + return conv; + } + else + return vhdl_expr::cast(to); +} int vhdl_const_bits::bits_to_int() const { diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 97acb9a16..80e5fe28e 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -71,8 +71,17 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) vhdl_expr *sel = nexus_to_var_ref(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); + vhdl_expr *cmp; + if (ivl_logic_width(log) == 1) { + vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1'); + cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL); + } + else { + vhdl_expr *zero = (new vhdl_const_int(0))->cast(sel->get_type()); + vhdl_binop_t op = if0 ? VHDL_BINOP_EQ : VHDL_BINOP_NEQ; + cmp = new vhdl_binop_expr(sel, op, zero, NULL); + } + ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope()); char zbit; @@ -87,8 +96,10 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) default: zbit = 'Z'; } - - vhdl_const_bit *z = new vhdl_const_bit(zbit); + + vhdl_expr *z = new vhdl_const_bit(zbit); + if (ivl_logic_width(log) > 1) + z = new vhdl_bit_spec_expr(NULL, z); vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z); cass->add_condition(val, cmp); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index c1c63bd25..517d23f6c 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -202,6 +202,7 @@ public: vhdl_const_int(int64_t value) : vhdl_expr(vhdl_type::integer(), true), value_(value) {} void emit(std::ostream &of, int level) const; + vhdl_expr *cast(const vhdl_type *to); private: int64_t value_; }; From cb1d4fd2789ce4b164c359d035d53ecf1bba814e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Mon, 18 Aug 2008 16:15:05 +0100 Subject: [PATCH 364/377] Amend inaccurate comment --- tgt-vhdl/vhdl_syntax.hh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 517d23f6c..a03e002ab 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -245,8 +245,7 @@ private: }; /* - * A concurrent statement appears in architecture bodies but not - * processes. + * A concurrent statement appears in architecture bodies/ */ class vhdl_conc_stmt : public vhdl_element { public: From 4ebe09bb7281610041872a57b957f17c37a47504 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 20 Aug 2008 22:54:53 +0100 Subject: [PATCH 365/377] Various fixes to support automatic functions Mostly this ensures that a recursive call to a function is made with the correct types (this may involve generating code to cast expressions to the correct type). --- tgt-vhdl/cast.cc | 2 +- tgt-vhdl/expr.cc | 31 ++++++++++++++++++++++++++----- tgt-vhdl/stmt.cc | 2 +- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 339e9c8ae..013bb52b6 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -135,7 +135,7 @@ vhdl_expr *vhdl_expr::resize(int newwidth) vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); resize->add_expr(this); resize->add_expr(new vhdl_const_int(newwidth)); - + return resize; } diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 64630ac57..abd70c7f0 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -60,7 +60,7 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e) assert(scope); const char *renamed = get_renamed_signal(sig).c_str(); - + vhdl_decl *decl = scope->get_decl(renamed); assert(decl); @@ -192,7 +192,12 @@ static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs, else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN) lhs = lhs->cast(&boolean); - vhdl_type *rtype = new vhdl_type(*lhs->get_type()); + vhdl_type *rtype; + if (op == VHDL_BINOP_MULT) + rtype = new vhdl_type(lhs->get_type()->get_name(), + (lhs->get_type()->get_width()*2) - 1, 0); + else + rtype = new vhdl_type(*lhs->get_type()); return new vhdl_binop_expr(lhs, op, rhs, rtype); } @@ -282,7 +287,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case 'E': if (vectorop) result = translate_relation(lhs->cast(&std_logic_vector), - rhs->cast(&std_logic_vector), VHDL_BINOP_EQ); + rhs->cast(&std_logic_vector), VHDL_BINOP_EQ); else result = translate_relation(lhs, rhs, VHDL_BINOP_EQ); break; @@ -292,7 +297,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) case 'N': if (vectorop) result = translate_relation(lhs->cast(&std_logic_vector), - rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); + rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ); else result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ); break; @@ -438,7 +443,23 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) vhdl_type *rettype = expr_to_vhdl_type(e); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); - return translate_parms(fcall, e); + int nparams = ivl_expr_parms(e); + for (int i = 0; i < nparams; i++) { + vhdl_expr *param = translate_expr(ivl_expr_parm(e, i)); + if (NULL == param) + return NULL; + + // Ensure the parameter has the correct VHDL type + ivl_signal_t param_sig = ivl_scope_sig(defscope, i); + vhdl_type *param_type = + vhdl_type::type_for(ivl_signal_width(param_sig), + ivl_signal_signed(param_sig) != 0); + + fcall->add_expr(param->cast(param_type)); + delete param_type; + } + + return fcall; } static vhdl_expr *translate_ternary(ivl_expr_t e) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index 94f550d21..d5bcc6ccc 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -254,7 +254,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, return; } } - + T *a = new T(lhs, rhs); container->add_stmt(a); From 535ef6be3839ec16f489936407a40514ecb06933 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 21 Aug 2008 19:44:12 +0100 Subject: [PATCH 366/377] Change function return value from Verilog_Result to _Result --- tgt-vhdl/scope.cc | 5 +++-- tgt-vhdl/vhdl_syntax.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index d105fa42e..03d15e5e7 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -505,8 +505,9 @@ static int draw_function(ivl_scope_t scope, ivl_scope_t parent) func->add_param(new vhdl_param_decl(signame.c_str(), sigtype)); break; case IVL_SIP_OUTPUT: - // The magic variable Verilog_Result holds the return value - signame = "Verilog_Result"; + // The magic variable _Result holds the return value + signame = funcname; + signame += "_Result"; func->set_type(new vhdl_type(*sigtype)); default: func->get_scope()->add_decl diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index e24a40cfb..d8d9ebd62 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -871,7 +871,7 @@ void vhdl_function::emit(std::ostream &of, int level) const emit_children(of, variables_.get_decls(), level); of << "begin"; stmts_.emit(of, level); - of << " return Verilog_Result;"; + of << " return " << name_ << "_Result;"; newline(of, level); of << "end function;"; } From fae7ab24185939336a0a204079ce653fdeeae68b Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 22 Aug 2008 20:15:45 +0100 Subject: [PATCH 367/377] Use case-insensitive string comparison for get_decl This will allow us to detect cases where identifiers differ only by case --- tgt-vhdl/vhdl_syntax.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index d8d9ebd62..2de81f1c6 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -22,6 +22,7 @@ #include "vhdl_helper.hh" #include +#include #include #include @@ -57,7 +58,7 @@ vhdl_decl *vhdl_scope::get_decl(const std::string &name) const { decl_list_t::const_iterator it; for (it = decls_.begin(); it != decls_.end(); ++it) { - if ((*it)->get_name() == name) + if (strcasecmp((*it)->get_name().c_str(), name.c_str()) == 0) return *it; } From 63a1e251297c16722dce68aabebde436317dc935 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 22 Aug 2008 20:20:17 +0100 Subject: [PATCH 368/377] Catch case where component name and instance differ only in case This causes an error in VHDL (which is case-insensitive). This patch simply appends _Inst to the instance name if it detects this. --- tgt-vhdl/scope.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 03d15e5e7..5768f3b7b 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -752,14 +752,15 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) assert(parent_arch != NULL); // Create a forward declaration for it - if (!parent_arch->get_scope()->have_declared(ent->get_name())) { + vhdl_scope *parent_scope = parent_arch->get_scope(); + if (!parent_scope->have_declared(ent->get_name())) { vhdl_decl *comp_decl = vhdl_component_decl::component_decl_for(ent); parent_arch->get_scope()->add_decl(comp_decl); } // And an instantiation statement string inst_name(ivl_scope_basename(scope)); - if (inst_name == ent->get_name()) { + if (inst_name == ent->get_name() || parent_scope->have_declared(inst_name)) { // Cannot have instance name the same as type in VHDL inst_name += "_Inst"; } From 331a51e842b98110821abcc29f347777f9172526 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 22 Aug 2008 20:25:58 +0100 Subject: [PATCH 369/377] Add more warnings about untranslatable constructs --- tgt-vhdl/stmt.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index d5bcc6ccc..f1a5eb9c7 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -681,6 +681,9 @@ int draw_stmt(vhdl_procedural *proc, stmt_container *container, case IVL_ST_CASEX: error("casex statement cannot be translated to VHDL"); return 1; + case IVL_ST_CASEZ: + error("casez statement cannot be translated to VHDL"); + return 1; case IVL_ST_FORK: error("fork statement cannot be translated to VHDL"); return 1; From d21b3258e3712d8c443b0738804542287cb4e16a Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 22 Aug 2008 20:59:14 +0100 Subject: [PATCH 370/377] Support conversion of (un)signed to std_logic Take the least-significant bit. This fixes a couple of broken test cases. --- tgt-vhdl/cast.cc | 22 ++++++++++++++++++++++ tgt-vhdl/support.cc | 14 ++++++++++++++ tgt-vhdl/support.hh | 2 ++ 3 files changed, 38 insertions(+) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 013bb52b6..ff1b799f9 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -106,6 +106,28 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return ah; } + else if (to->get_name() == VHDL_TYPE_STD_LOGIC + && (type_->get_name() == VHDL_TYPE_SIGNED)) { + require_support_function(SF_SIGNED_TO_LOGIC); + + vhdl_fcall *ah = + new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_LOGIC), + vhdl_type::std_logic()); + ah->add_expr(this); + + return ah; + } + else if (to->get_name() == VHDL_TYPE_STD_LOGIC + && (type_->get_name() == VHDL_TYPE_UNSIGNED)) { + require_support_function(SF_UNSIGNED_TO_LOGIC); + + vhdl_fcall *ah = + new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_LOGIC), + 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 diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index e9592fa06..9ad74a3ca 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -44,6 +44,8 @@ const char *support_function::function_name(support_function_t type) case SF_TERNARY_UNSIGNED: return "Ternary_Unsigned"; case SF_TERNARY_SIGNED: return "Ternary_Signed"; case SF_LOGIC_TO_INTEGER: return "Logic_To_Integer"; + case SF_SIGNED_TO_LOGIC: return "Signed_To_Logic"; + case SF_UNSIGNED_TO_LOGIC: return "Unsigned_To_Logic"; default: assert(false); } @@ -60,6 +62,8 @@ vhdl_type *support_function::function_type(support_function_t type) case SF_REDUCE_AND: case SF_REDUCE_XOR: case SF_TERNARY_LOGIC: + case SF_SIGNED_TO_LOGIC: + case SF_UNSIGNED_TO_LOGIC: return vhdl_type::std_logic(); case SF_TERNARY_SIGNED: return new vhdl_type(VHDL_TYPE_SIGNED); @@ -102,6 +106,16 @@ void support_function::emit(std::ostream &of, int level) const << "return '0';" << nl_string(indent(level)) << "end if;"; break; + case SF_UNSIGNED_TO_LOGIC: + of << "(X : unsigned) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "return X(0);"; + break; + case SF_SIGNED_TO_LOGIC: + of << "(X : signed) return std_logic is" << nl_string(level) + << "begin" << nl_string(indent(level)) + << "return X(0);"; + break; case SF_REDUCE_OR: of << "(X : std_logic_vector) return std_logic is" << nl_string(level) << "begin" << nl_string(indent(level)) diff --git a/tgt-vhdl/support.hh b/tgt-vhdl/support.hh index 2cbee0c7b..234831c24 100644 --- a/tgt-vhdl/support.hh +++ b/tgt-vhdl/support.hh @@ -34,6 +34,8 @@ enum support_function_t { SF_TERNARY_UNSIGNED, SF_TERNARY_SIGNED, SF_LOGIC_TO_INTEGER, + SF_SIGNED_TO_LOGIC, + SF_UNSIGNED_TO_LOGIC, }; class support_function : public vhdl_function { From 8e023d12276f01985d88e25c2f54625c9d28945e Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 22 Aug 2008 21:27:24 +0100 Subject: [PATCH 371/377] Remove redundant function --- tgt-vhdl/expr.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index abd70c7f0..67fe82bf5 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -403,14 +403,6 @@ static vhdl_expr *translate_select(ivl_expr_t e) return from->resize(ivl_expr_width(e)); } -static vhdl_type *expr_to_vhdl_type(ivl_expr_t e) -{ - if (ivl_expr_signed(e)) - return vhdl_type::nsigned(ivl_expr_width(e)); - else - return vhdl_type::nunsigned(ivl_expr_width(e)); -} - template static T *translate_parms(T *t, ivl_expr_t e) { @@ -440,7 +432,8 @@ static vhdl_expr *translate_ufunc(ivl_expr_t e) const char *funcname = ivl_scope_tname(defscope); - vhdl_type *rettype = expr_to_vhdl_type(e); + vhdl_type *rettype = + vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype); int nparams = ivl_expr_parms(e); @@ -497,7 +490,8 @@ static vhdl_expr *translate_ternary(ivl_expr_t e) static vhdl_expr *translate_concat(ivl_expr_t e) { - vhdl_type *rtype = expr_to_vhdl_type(e); + vhdl_type *rtype = + vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0); vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype); int nrepeat = ivl_expr_repeat(e); From b5e65ac9ed984aff3fe60b665e836ab24cc2270f Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 27 Aug 2008 16:47:07 +0100 Subject: [PATCH 372/377] Refactor and clean up cast.cc This splits up the monolithic and confusing vhdl_expr::cast function into several smaller to_XXX functions which each generate code to cast an expression to type XXX. This makes it much easier to understand and maintain. --- tgt-vhdl/cast.cc | 245 +++++++++++++++++++++++----------------- tgt-vhdl/vhdl_syntax.hh | 16 ++- 2 files changed, 153 insertions(+), 108 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index ff1b799f9..253a1f93a 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -39,75 +39,119 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) 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(SF_UNSIGNED_TO_BOOLEAN); + else if (to->get_name() == VHDL_TYPE_BOOLEAN) + return to_boolean(); + else if (to->get_name() == VHDL_TYPE_INTEGER) + return to_integer(); + else if (to->get_name() == VHDL_TYPE_UNSIGNED + || to->get_name() == VHDL_TYPE_SIGNED + || to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) + return to_vector(to->get_name(), to->get_width()); + else if (to->get_name() == VHDL_TYPE_STD_LOGIC) + return to_std_logic(); + else + assert(false); +} - vhdl_fcall *conv = - 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(SF_SIGNED_TO_BOOLEAN); - - vhdl_fcall *conv = - new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN), - vhdl_type::boolean()); - conv->add_expr(this); - return conv; - } - else { - assert(false); - } - } - else if (to->get_name() == VHDL_TYPE_INTEGER) { - vhdl_fcall *conv; - if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { - require_support_function(SF_LOGIC_TO_INTEGER); - conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER), - vhdl_type::integer()); - } - else - conv = new vhdl_fcall("To_Integer", new vhdl_type(*to)); - - conv->add_expr(this); - - return conv; - } - else if ((to->get_name() == VHDL_TYPE_UNSIGNED - || to->get_name() == VHDL_TYPE_SIGNED - || to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) && - type_->get_name() == VHDL_TYPE_STD_LOGIC) { - - vhdl_expr *others = to->get_width() == 1 ? NULL : new vhdl_const_bit('0'); +/* + * Generate code to cast an expression to a vector type (std_logic_vector, + * signed, unsigned). + */ +vhdl_expr *vhdl_expr::to_vector(vhdl_type_name_t name, int w) +{ + if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { + vhdl_expr *others = w == 1 ? NULL : new vhdl_const_bit('0'); vhdl_bit_spec_expr *bs = - new vhdl_bit_spec_expr(new vhdl_type(*to), others); + new vhdl_bit_spec_expr(new vhdl_type(name, w - 1, 0), others); bs->add_bit(0, this); - + return bs; } - else if (to->get_name() == VHDL_TYPE_STD_LOGIC && - type_->get_name() == VHDL_TYPE_BOOLEAN) { + 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_type *t = new vhdl_type(name, w - 1, 0); + vhdl_fcall *conv = new vhdl_fcall(t->get_string().c_str(), t); + conv->add_expr(this); + + if (w != type_->get_width()) + return conv->resize(w); + else + return conv; + } +} + +/* + * Convert a generic expression to an Integer. + */ +vhdl_expr *vhdl_expr::to_integer() +{ + vhdl_fcall *conv; + if (type_->get_name() == VHDL_TYPE_STD_LOGIC) { + require_support_function(SF_LOGIC_TO_INTEGER); + conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER), + vhdl_type::integer()); + } + else + conv = new vhdl_fcall("To_Integer", vhdl_type::integer()); + + conv->add_expr(this); + + return conv; +} + +/* + * Convert a generic expression to a Boolean. + */ +vhdl_expr *vhdl_expr::to_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(SF_UNSIGNED_TO_BOOLEAN); + + vhdl_fcall *conv = + 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(SF_SIGNED_TO_BOOLEAN); + + vhdl_fcall *conv = + new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN), + vhdl_type::boolean()); + conv->add_expr(this); + return conv; + } + else { + assert(false); + } +} + +/* + * Generate code to convert and expression to std_logic. + */ +vhdl_expr *vhdl_expr::to_std_logic() +{ + if (type_->get_name() == VHDL_TYPE_BOOLEAN) { 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; } - else if (to->get_name() == VHDL_TYPE_STD_LOGIC - && (type_->get_name() == VHDL_TYPE_SIGNED)) { + else if (type_->get_name() == VHDL_TYPE_SIGNED) { require_support_function(SF_SIGNED_TO_LOGIC); vhdl_fcall *ah = @@ -117,8 +161,7 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) return ah; } - else if (to->get_name() == VHDL_TYPE_STD_LOGIC - && (type_->get_name() == VHDL_TYPE_UNSIGNED)) { + else if (type_->get_name() == VHDL_TYPE_UNSIGNED) { require_support_function(SF_UNSIGNED_TO_LOGIC); vhdl_fcall *ah = @@ -128,21 +171,13 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) 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; - } + else + assert(false); } +/* + * Change the width of a signed/unsigned type. + */ vhdl_expr *vhdl_expr::resize(int newwidth) { vhdl_type *rtype; @@ -161,21 +196,20 @@ vhdl_expr *vhdl_expr::resize(int newwidth) return resize; } -vhdl_expr *vhdl_const_int::cast(const vhdl_type *to) +vhdl_expr *vhdl_const_int::to_vector(vhdl_type_name_t name, int w) { - if (to->get_name() == VHDL_TYPE_SIGNED - || to->get_name() == VHDL_TYPE_UNSIGNED) { + if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) { - const char *fname = to->get_name() == VHDL_TYPE_SIGNED + const char *fname = name == VHDL_TYPE_SIGNED ? "To_Signed" : "To_Unsigned"; - vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(*to)); + vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(name, w - 1, 0)); conv->add_expr(this); - conv->add_expr(new vhdl_const_int(to->get_width())); + conv->add_expr(new vhdl_const_int(w)); return conv; } else - return vhdl_expr::cast(to); + return vhdl_expr::to_vector(name, w); } int vhdl_const_bits::bits_to_int() const @@ -193,41 +227,44 @@ int vhdl_const_bits::bits_to_int() const return result; } -vhdl_expr *vhdl_const_bits::cast(const vhdl_type *to) +vhdl_expr *vhdl_const_bits::to_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); +} + +vhdl_expr *vhdl_const_bits::to_vector(vhdl_type_name_t name, int w) { - 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) { + if (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) { - + else if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) { // Extend with sign bit - value_.resize(to->get_width(), value_[0]); + value_.resize(w, 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); + assert(false); } -vhdl_expr *vhdl_const_bit::cast(const vhdl_type *to) +vhdl_expr *vhdl_const_bits::to_integer() { - if (to->get_name() == VHDL_TYPE_INTEGER) - return new vhdl_const_int(bit_ == '1' ? 1 : 0); - else if (to->get_name() == VHDL_TYPE_BOOLEAN) - return new vhdl_const_bool(bit_ == '1'); - else - return vhdl_expr::cast(to); + return new vhdl_const_int(bits_to_int()); +} + +vhdl_expr *vhdl_const_bit::to_integer() +{ + return new vhdl_const_int(bit_ == '1' ? 1 : 0); +} + +vhdl_expr *vhdl_const_bit::to_boolean() +{ + return new vhdl_const_bool(bit_ == '1'); } diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index a03e002ab..4d5141e98 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -36,8 +36,13 @@ public: const vhdl_type *get_type() const { return type_; } bool constant() const { return isconst_; } - virtual vhdl_expr *cast(const vhdl_type *to); + + vhdl_expr *cast(const vhdl_type *to); virtual vhdl_expr *resize(int newwidth); + virtual vhdl_expr *to_boolean(); + virtual vhdl_expr *to_integer(); + virtual vhdl_expr *to_std_logic(); + virtual vhdl_expr *to_vector(vhdl_type_name_t name, int w); protected: vhdl_type *type_; bool isconst_; @@ -165,7 +170,9 @@ public: vhdl_const_bits(const char *value, int width, bool issigned); void emit(std::ostream &of, int level) const; const std::string &get_value() const { return value_; } - vhdl_expr *cast(const vhdl_type *to); + vhdl_expr *to_integer(); + vhdl_expr *to_std_logic(); + vhdl_expr *to_vector(vhdl_type_name_t name, int w); private: int bits_to_int() const; @@ -178,7 +185,8 @@ 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); + vhdl_expr *to_boolean(); + vhdl_expr *to_integer(); private: char bit_; }; @@ -202,7 +210,7 @@ public: vhdl_const_int(int64_t value) : vhdl_expr(vhdl_type::integer(), true), value_(value) {} void emit(std::ostream &of, int level) const; - vhdl_expr *cast(const vhdl_type *to); + vhdl_expr *to_vector(vhdl_type_name_t name, int w); private: int64_t value_; }; From 8323d5d01d7bb5d35af088705edd61cc8f783696 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Wed, 27 Aug 2008 16:59:05 +0100 Subject: [PATCH 373/377] Finish cast.cc cleanup Replace big if statement with switch statemetn --- tgt-vhdl/cast.cc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index 253a1f93a..2499e0c6f 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -39,18 +39,22 @@ vhdl_expr *vhdl_expr::cast(const vhdl_type *to) else return resize(to->get_width()); } - else if (to->get_name() == VHDL_TYPE_BOOLEAN) - return to_boolean(); - else if (to->get_name() == VHDL_TYPE_INTEGER) - return to_integer(); - else if (to->get_name() == VHDL_TYPE_UNSIGNED - || to->get_name() == VHDL_TYPE_SIGNED - || to->get_name() == VHDL_TYPE_STD_LOGIC_VECTOR) - return to_vector(to->get_name(), to->get_width()); - else if (to->get_name() == VHDL_TYPE_STD_LOGIC) - return to_std_logic(); - else - assert(false); + else { + switch (to->get_name()) { + case VHDL_TYPE_BOOLEAN: + return to_boolean(); + case VHDL_TYPE_INTEGER: + return to_integer(); + case VHDL_TYPE_UNSIGNED: + case VHDL_TYPE_SIGNED: + case VHDL_TYPE_STD_LOGIC_VECTOR: + return to_vector(to->get_name(), to->get_width()); + case VHDL_TYPE_STD_LOGIC: + return to_std_logic(); + default: + assert(false); + } + } } /* From 0e458501b30616d44fc702ea9913b63429f57bc9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 28 Aug 2008 21:53:12 +0100 Subject: [PATCH 374/377] Ensure binary operands have correct signedness Previously only signedness was only corrected for the result. This patch ensures the VHDL operands have the same signedness as their Verilog counterparts. This fixes a few of the signedX tests. --- tgt-vhdl/expr.cc | 64 +++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index 67fe82bf5..5e49f1857 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -38,6 +38,32 @@ static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned) return e->cast(&u); } +/* + * Generate code to ensure that the VHDL expression vhd_e has the + * same signedness as the Verilog expression vl_e. + */ +static vhdl_expr *correct_signedness(vhdl_expr *vhd_e, ivl_expr_t vl_e) +{ + bool should_be_signed = ivl_expr_signed(vl_e) != 0; + + if (vhd_e->get_type()->get_name() == VHDL_TYPE_UNSIGNED + && should_be_signed) { + //operand->print(); + //std::cout << "^ should be signed but is not" << std::endl; + + return change_signedness(vhd_e, true); + } + else if (vhd_e->get_type()->get_name() == VHDL_TYPE_SIGNED + && !should_be_signed) { + //operand->print(); + //std::cout << "^ should be unsigned but is not" << std::endl; + + return change_signedness(vhd_e, false); + } + else + return vhd_e; +} + /* * Convert a constant Verilog string to a constant VHDL string. */ @@ -134,22 +160,7 @@ static vhdl_expr *translate_unary(ivl_expr_t e) if (NULL == operand) return NULL; - bool should_be_signed = ivl_expr_signed(e) != 0; - - 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) { - //operand->print(); - //std::cout << "^ should be unsigned but is not" << std::endl; - - operand = change_signedness(operand, false); - } + operand = correct_signedness(operand, e); char opcode = ivl_expr_opcode(e); switch (opcode) { @@ -256,12 +267,16 @@ static vhdl_expr *translate_binary(ivl_expr_t e) (ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) && (rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED); - // May need to resize the left or right hand side + // May need to resize the left or right hand side or change the + // signedness if (vectorop) { if (lwidth < rwidth) lhs = lhs->resize(rwidth); else if (rwidth < lwidth) rhs = rhs->resize(lwidth); + + lhs = correct_signedness(lhs, ivl_expr_oper1(e)); + rhs = correct_signedness(rhs, ivl_expr_oper2(e)); } vhdl_expr *result; @@ -355,20 +370,7 @@ static vhdl_expr *translate_binary(ivl_expr_t e) return NULL; if (vectorop) { - bool should_be_signed = ivl_expr_signed(e) != 0; - - if (result->get_type()->get_name() == VHDL_TYPE_UNSIGNED && should_be_signed) { - //result->print(); - //std::cout << "^ should be signed but is not" << std::endl; - - 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_signedness(result, false); - } + result = correct_signedness(result, e); int actual_width = result->get_type()->get_width(); if (actual_width != result_width) { From e322cce65071836ce6f65b740945a2c8d8d30cec Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 21:15:43 -0700 Subject: [PATCH 375/377] Clean up $clog2() measurement of unsized numbers. If the argument to $clog2() is unsized constant, then trim it to the smallest representation that doesn't lose the sign, then do the $clog2 on that. Also, use integer_width instead of 32 for the minimum $clog2() result for a negative value. --- eval_tree.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 7559c36ad..99e408a60 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1614,7 +1614,6 @@ NetExpr* evaluate_clog2(NetExpr*arg) { NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); - bool is_neg = false; if (tmpi || tmpr) { verinum arg; if (tmpi) { @@ -1631,9 +1630,17 @@ NetExpr* evaluate_clog2(NetExpr*arg) return rtn; } + bool is_neg = false; uint64_t res = 0; - if (arg.is_negative()) is_neg = true; + if (arg.is_negative()) { + is_neg = true; + // If the length is not defined, then work with + // the trimmed version of the number. + if (! arg.has_len()) + arg = trim_vnum(arg); + } arg.has_sign(false); // $unsigned() + if (!arg.is_zero()) { arg = arg - verinum((uint64_t)1, 1); while (!arg.is_zero()) { @@ -1641,9 +1648,11 @@ NetExpr* evaluate_clog2(NetExpr*arg) arg = arg >> 1; } } - if (is_neg && res < 32) res = 32; + + if (is_neg && res < integer_width) + res = integer_width; + verinum tmp (res, 32); - tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; } From 3b778b1a0626ed95e9b398a1cb86012c89af73a5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 21:16:44 -0700 Subject: [PATCH 376/377] Minor improvements to expression debug prints. --- design_dump.cc | 2 ++ pform_dump.cc | 3 +++ verinum.cc | 12 ++++++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 1af627745..82f1f35bf 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1015,6 +1015,8 @@ void NetScope::dump(ostream&o) const ; pp != parameters.end() ; pp ++) { o << " parameter "; + o << pp->second.type << " "; + if ((*pp).second.signed_flag) o << "signed "; diff --git a/pform_dump.cc b/pform_dump.cc index f506bd655..8313646e6 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -280,6 +280,9 @@ void PEBinary::dump(ostream&out) const case 'N': out << "!=="; break; + case 'p': + out << "**"; + break; case 'R': out << ">>>"; break; diff --git a/verinum.cc b/verinum.cc index b4f20f32e..76c3fb75d 100644 --- a/verinum.cc +++ b/verinum.cc @@ -691,11 +691,15 @@ ostream& operator<< (ostream&o, const verinum&v) verinum::V trim_left = v.get(v.len()-1); unsigned idx; - for (idx = v.len()-1; idx > 0; idx -= 1) - if (trim_left != v.get(idx-1)) - break; + if (v.has_sign()) { + for (idx = v.len()-1; idx > 0; idx -= 1) + if (trim_left != v.get(idx-1)) + break; - o << trim_left; + o << trim_left; + } else { + idx = v.len(); + } while (idx > 0) { o << v.get(idx-1); From 8d21c0390ef3b6b0f39bedb8c7d0238e74bb9a78 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 22:08:46 -0700 Subject: [PATCH 377/377] Remove dead EEQ code. The EEQ function is handled by vvp_cmp_eeq, an arithmetic expression processor and the logic version of EEQ is never used. --- vvp/logic.cc | 32 -------------------------------- vvp/logic.h | 11 ----------- 2 files changed, 43 deletions(-) diff --git a/vvp/logic.cc b/vvp/logic.cc index ecfc947d7..3ba7c965b 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -109,35 +109,6 @@ void vvp_fun_and::run_run() vvp_send_vec4(ptr->out, result); } -vvp_fun_eeq::vvp_fun_eeq(unsigned wid, bool invert) -: vvp_fun_boolean_(wid), invert_(invert) -{ - count_functors_logic += 1; -} - -vvp_fun_eeq::~vvp_fun_eeq() -{ -} - -void vvp_fun_eeq::run_run() -{ - vvp_net_t*ptr = net_; - net_ = 0; - - vvp_vector4_t result (input_[0]); - - for (unsigned idx = 0 ; idx < result.size() ; idx += 1) { - vvp_bit4_t bitbit = result.value(idx); - bitbit = (bitbit == input_[1].value(idx))? BIT4_1 : BIT4_0; - if (invert_) - bitbit = ~bitbit; - - result.set_bit(idx, bitbit); - } - - vvp_send_vec4(ptr->out, result); -} - vvp_fun_buf::vvp_fun_buf() { net_ = 0; @@ -579,9 +550,6 @@ void compile_functor(char*label, char*type, unsigned width, } else if (strcmp(type, "RPMOS") == 0) { obj = new vvp_fun_rpmos(false); - } else if (strcmp(type, "EEQ") == 0) { - obj = new vvp_fun_eeq(width, false); - } else if (strcmp(type, "NOT") == 0) { obj = new vvp_fun_not(); diff --git a/vvp/logic.h b/vvp/logic.h index 24df457d2..841ce4aaa 100644 --- a/vvp/logic.h +++ b/vvp/logic.h @@ -52,17 +52,6 @@ class vvp_fun_and : public vvp_fun_boolean_ { bool invert_; }; -class vvp_fun_eeq : public vvp_fun_boolean_ { - - public: - explicit vvp_fun_eeq(unsigned wid, bool invert); - ~vvp_fun_eeq(); - - private: - void run_run(); - bool invert_; -}; - /* * The buffer functor is a very primitive functor that takes the input * from port-0 (and only port-0) and retransmits it as a vvp_vector4_t.