diff --git a/.gitignore b/.gitignore index c6762b15b..133d6c815 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,8 @@ dep *.vpi /cadpli/cadpli.vpl +/tgt-blif/Makefile + # lex, yacc and gperf output /driver/cflexor.c /driver/cfparse.c diff --git a/Makefile.in b/Makefile.in index 78f50a4f3..04747cf0c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -38,7 +38,7 @@ srcdir = @srcdir@ datarootdir = @datarootdir@ SUBDIRS = ivlpp vhdlpp vvp vpi libveriuser cadpli tgt-null tgt-stub tgt-vvp \ - tgt-vhdl tgt-vlog95 tgt-pcb driver + tgt-vhdl tgt-vlog95 tgt-pcb tgt-blif driver # Only run distclean for these directories. NOTUSED = tgt-fpga tgt-pal tgt-verilog diff --git a/configure.in b/configure.in index f50207b12..e7aa13457 100644 --- a/configure.in +++ b/configure.in @@ -325,4 +325,4 @@ AC_MSG_ERROR(cannot configure white space in libdir: $libdir) fi AC_MSG_RESULT(ok) -AC_OUTPUT(Makefile ivlpp/Makefile vhdlpp/Makefile vvp/Makefile vpi/Makefile driver/Makefile driver-vpi/Makefile cadpli/Makefile libveriuser/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-vvp/Makefile tgt-vhdl/Makefile tgt-fpga/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vlog95/Makefile tgt-pcb/Makefile) +AC_OUTPUT(Makefile ivlpp/Makefile vhdlpp/Makefile vvp/Makefile vpi/Makefile driver/Makefile driver-vpi/Makefile cadpli/Makefile libveriuser/Makefile tgt-null/Makefile tgt-stub/Makefile tgt-vvp/Makefile tgt-vhdl/Makefile tgt-fpga/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vlog95/Makefile tgt-pcb/Makefile tgt-blif/Makefile) diff --git a/tgt-blif/Makefile.in b/tgt-blif/Makefile.in new file mode 100644 index 000000000..925874a4b --- /dev/null +++ b/tgt-blif/Makefile.in @@ -0,0 +1,104 @@ +# +# 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., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +SHELL = /bin/sh + +suffix = @install_suffix@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +srcdir = @srcdir@ + +VPATH = $(srcdir) + +bindir = @bindir@ +libdir = @libdir@ + +CC = @CC@ +CC = @CXX@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +ifeq (@srcdir@,.) +INCLUDE_PATH = -I. -I.. +else +INCLUDE_PATH = -I. -I.. -I$(srcdir) -I$(srcdir)/.. +endif + +CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ +CXXFLAGS = @WARNING_FLAGS@ @CXXFLAGS@ +LDFLAGS = @LDFLAGS@ + +O = blif.o nex_data.o + +all: dep blif.tgt + +check: all + +clean: + rm -rf *.o dep blif.tgt + +distclean: clean + rm -f Makefile config.log + +cppcheck: $(O:.o=.c) + cppcheck --enable=all -f $(INCLUDE_PATH) $^ + +Makefile: $(srcdir)/Makefile.in ../config.status + cd ..; ./config.status --file=tgt-blif/$@ + +dep: + mkdir dep + +%.o: %.cc + $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o + mv $*.d dep + +ifeq (@WIN32@,yes) + TGTLDFLAGS=-L.. -livl + TGTDEPLIBS=../libivl.a +else + TGTLDFLAGS= + TGTDEPLIBS= +endif + +blif.tgt: $O $(TGTDEPLIBS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) + +install: all installdirs $(libdir)/ivl$(suffix)/blif.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/blif.conf $(libdir)/ivl$(suffix)/blif-s.conf + +$(libdir)/ivl$(suffix)/blif.tgt: ./blif.tgt + $(INSTALL_PROGRAM) ./blif.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/blif.tgt" + +$(libdir)/ivl$(suffix)/blif.conf: $(srcdir)/blif.conf + $(INSTALL_DATA) $(srcdir)/blif.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/blif.conf" + +$(libdir)/ivl$(suffix)/blif-s.conf: $(srcdir)/blif-s.conf + $(INSTALL_DATA) $(srcdir)/blif-s.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/blif-s.conf" + + +installdirs: $(srcdir)/../mkinstalldirs + $(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)/ivl$(suffix)" + +uninstall: + rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/blif.tgt" + rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/blif.conf" + rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/blif-s.conf" + + +-include $(patsubst %.o, dep/%.d, $O) diff --git a/tgt-blif/blif-s.conf b/tgt-blif/blif-s.conf new file mode 100644 index 000000000..05d8105b9 --- /dev/null +++ b/tgt-blif/blif-s.conf @@ -0,0 +1,6 @@ +functor:synth2 +functor:synth +functor:syn-rules +functor:cprop +functor:nodangle +flag:DLL=blif.tgt diff --git a/tgt-blif/blif.cc b/tgt-blif/blif.cc new file mode 100644 index 000000000..845186ae2 --- /dev/null +++ b/tgt-blif/blif.cc @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "version_base.h" +# include "version_tag.h" +# include "config.h" +# include "ivl_target.h" +# include "nex_data.h" +# include +# include +# include +# include + +using namespace std; + +/* + * This is a BLIF target module. + */ + +static const char*version_string = +"Icarus Verilog BLIF Code Generator " VERSION " (" VERSION_TAG ")\n\n" +"Copyright (c) 2013 Stephen Williams (steve@icarus.com)\n\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License along\n" +" with this program; if not, write to the Free Software Foundation, Inc.,\n" +" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" +; + +static int emit_blif(const char*blif_path, ivl_scope_t model); + +int target_design(ivl_design_t des) +{ + int rc = 0; + const char*blif_path = ivl_design_flag(des, "-o"); + + // Locate the root scope for the design. Note that the BLIF + // format implies that there is a single root of the model. + ivl_scope_t*roots; + unsigned nroots; + ivl_design_roots(des, &roots, &nroots); + if (nroots != 1) { + fprintf(stderr, "BLIF: The BLIF code generator requires that there be only one root scope.\n"); + return 1; + } + + assert(roots[0]); + + if (ivl_scope_type(roots[0]) != IVL_SCT_MODULE) { + fprintf(stderr, "BLIF: The root scope %s must be a module.\n", ivl_scope_basename(roots[0])); + return 1; + } + + // Emit to the destination file. + assert(blif_path); + rc += emit_blif(blif_path, roots[0]); + + return rc; +} + + +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} + +/* + * Print all the bits of a signal. This is for the .input or .output + * lines of a .model. All the bits need to be exploded, so print each + * bit of a vector as its own name. + */ +static void print_signal_bits(FILE*fd, ivl_signal_t sig) +{ + ivl_nexus_t nex = ivl_signal_nex(sig, 0); + blif_nex_data_t* ned = blif_nex_data_t::get_nex_data(nex); + ned->set_name(ivl_signal_basename(sig)); + + if (ivl_signal_packed_dimensions(sig) == 0) { + fprintf(fd, " %s", ivl_signal_basename(sig)); + return; + } + + assert(ivl_signal_packed_dimensions(sig) == 1); + + int msb = ivl_signal_packed_msb(sig,0); + int lsb = ivl_signal_packed_lsb(sig,0); + if (msb < lsb) { + int tmp = msb; + msb = lsb; + lsb = tmp; + } + + for (int idx = msb ; idx >= lsb ; idx -= 1) { + fprintf(fd, " %s[%d]", ivl_signal_basename(sig), idx); + } +} + +static void print_logic_gate(FILE*fd, ivl_net_logic_t net) +{ +#if 0 + fprintf(fd, "# LOGIC: name=%s, type=%d, pins=%u, width=%u\n", + ivl_logic_basename(net), ivl_logic_type(net), + ivl_logic_pins(net), ivl_logic_width(net)); +#endif + + fprintf(fd, ".names"); + ivl_nexus_t nex; + blif_nex_data_t*ned; + for (unsigned idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { + nex = ivl_logic_pin(net,idx); + ned = blif_nex_data_t::get_nex_data(nex); + fprintf(fd, " %s", ned->get_name()); + } + nex = ivl_logic_pin(net,0); + ned = blif_nex_data_t::get_nex_data(nex); + fprintf(fd, " %s", ned->get_name()); + fprintf(fd, "\n"); + + switch (ivl_logic_type(net)) { + case IVL_LO_AND: + for (unsigned idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) + fprintf(fd, "1"); + fprintf(fd, " 1\n"); + break; + case IVL_LO_OR: + assert(ivl_logic_pins(net)==3); + fprintf(fd, "1- 1\n"); + fprintf(fd, "-1 1\n"); + break; + case IVL_LO_XOR: + assert(ivl_logic_pins(net)==3); + fprintf(fd, "10 1\n"); + fprintf(fd, "01 1\n"); + break; + default: + fprintf(fd, "# ERROR: Logic type not handled\n"); + break; + } +} + +static int emit_blif(const char*blif_path, ivl_scope_t model) +{ + int rc = 0; + + FILE*fd = fopen(blif_path, "wt"); + if (fd == 0) { + perror(blif_path); + return 1; + } + + fprintf(fd, ".model %s\n", ivl_scope_basename(model)); + + // The root scope + vector ports_in; + vector ports_out; + for (unsigned idx = 0 ; idx < ivl_scope_sigs(model) ; idx += 1) { + ivl_signal_t prt = ivl_scope_sig(model, idx); + ivl_signal_port_t dir = ivl_signal_port(prt); + + switch (dir) { + case IVL_SIP_NONE: + break; + case IVL_SIP_INPUT: + ports_in.push_back(prt); + break; + case IVL_SIP_OUTPUT: + ports_out.push_back(prt); + break; + case IVL_SIP_INOUT: + fprintf(stderr, "BLIF: error: " + "Model port %s is bi-directional.\n", + ivl_signal_basename(prt)); + rc += 1; + ports_in.push_back(prt); + ports_out.push_back(prt); + break; + } + } + + if (ports_in.size() > 0) { + fprintf(fd, ".inputs"); + for (size_t idx = 0 ; idx < ports_in.size() ; idx += 1) { + ivl_signal_t prt = ports_in[idx]; + print_signal_bits(fd, prt); + } + fprintf(fd, "\n"); + } + if (ports_out.size() > 0) { + fprintf(fd, ".outputs"); + for (size_t idx = 0 ; idx < ports_out.size() ; idx += 1) { + ivl_signal_t prt = ports_out[idx]; + print_signal_bits(fd, prt); + } + fprintf(fd, "\n"); + } + + for (unsigned idx = 0 ; idx < ivl_scope_logs(model) ; idx += 1) { + ivl_net_logic_t net = ivl_scope_log(model, idx); + assert(net); + print_logic_gate(fd, net); + } + + fprintf(fd, ".end\n"); + fclose(fd); + + return rc; +} diff --git a/tgt-blif/blif.conf b/tgt-blif/blif.conf new file mode 100644 index 000000000..0d9fbf8ea --- /dev/null +++ b/tgt-blif/blif.conf @@ -0,0 +1,3 @@ +functor:cprop +functor:nodangle +flag:DLL=blif.tgt diff --git a/tgt-blif/nex_data.cc b/tgt-blif/nex_data.cc new file mode 100644 index 000000000..4abad4d54 --- /dev/null +++ b/tgt-blif/nex_data.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "nex_data.h" +# include +# include +# include +# include + +inline blif_nex_data_t::blif_nex_data_t(ivl_nexus_t nex) +: nex_(nex), name_(0) +{ +} + +blif_nex_data_t::~blif_nex_data_t() +{ + if (name_) free(name_); +} + +blif_nex_data_t* blif_nex_data_t::get_nex_data(ivl_nexus_t nex) +{ + void*tmp = ivl_nexus_get_private(nex); + if (tmp != 0) return reinterpret_cast (tmp); + + blif_nex_data_t*data = new blif_nex_data_t(nex); + ivl_nexus_set_private(nex, data); + return data; +} + +void blif_nex_data_t::set_name(const char*txt) +{ + assert(name_ == 0); + name_ = strdup(txt); +} + +const char* blif_nex_data_t::get_name(void) +{ + if (name_) return name_; + + for (unsigned idx = 0 ; idx < ivl_nexus_ptrs(nex_) ; idx += 1) { + ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex_, idx); + ivl_signal_t sig = ivl_nexus_ptr_sig(ptr); + if (sig == 0) + continue; + + name_ = strdup(ivl_signal_basename(sig)); + break; + } + + if (name_ == 0) { + char buf[64]; + snprintf(buf, sizeof buf, "@%p", nex_); + name_ = strdup(buf); + } + + assert(name_); + return name_; +} diff --git a/tgt-blif/nex_data.h b/tgt-blif/nex_data.h new file mode 100644 index 000000000..c326f5e8e --- /dev/null +++ b/tgt-blif/nex_data.h @@ -0,0 +1,54 @@ +#ifndef __nex_data_H +#define __nex_data_H +/* + * Copyright (c) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "ivl_target.h" + +/* + * The ivl_target.h API allows for binding data to a nexus. This class + * represents the data that we want to attach to a nexus. + */ +class blif_nex_data_t { + + private: + // The constructors are private. Only the get_nex_data() + // function can create these objects. + blif_nex_data_t(ivl_nexus_t nex); + ~blif_nex_data_t(); + + public: + // Return the blif_nex_data_t object that is associated with + // the given nexus. If the nexus does not have a nex_data_t + // object, then create it and bind it to the nexus. Thus, this + // function will always return the same nex_data instance for + // the same nexus. + static blif_nex_data_t* get_nex_data(ivl_nexus_t nex); + + void set_name(const char*); + + // Get the symbolic name chosen for this nexus. + const char*get_name(void); + + public: + ivl_nexus_t nex_; + char*name_; +}; + +#endif