From e0c9efd12953fd9e2e7e91f00a2308e02e8f2a4e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 18 Jul 2013 19:39:49 -0700 Subject: [PATCH] Implement blif support for constants and some logic/lpm gates. This starts the handling of various logic gates. --- tgt-blif/Makefile.in | 2 +- tgt-blif/blif.cc | 104 +++++++++++++++++------------------ tgt-blif/constants.cc | 70 +++++++++++++++++++++++ tgt-blif/logic_gate.cc | 69 +++++++++++++++++++++++ tgt-blif/lpm.cc | 122 +++++++++++++++++++++++++++++++++++++++++ tgt-blif/nex_data.cc | 36 +++++++++++- tgt-blif/nex_data.h | 9 +++ tgt-blif/priv.h | 49 +++++++++++++++++ 8 files changed, 404 insertions(+), 57 deletions(-) create mode 100644 tgt-blif/constants.cc create mode 100644 tgt-blif/logic_gate.cc create mode 100644 tgt-blif/lpm.cc create mode 100644 tgt-blif/priv.h diff --git a/tgt-blif/Makefile.in b/tgt-blif/Makefile.in index 925874a4b..4cc7c0c27 100644 --- a/tgt-blif/Makefile.in +++ b/tgt-blif/Makefile.in @@ -44,7 +44,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CXXFLAGS = @WARNING_FLAGS@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ -O = blif.o nex_data.o +O = blif.o constants.o logic_gate.o lpm.o nex_data.o all: dep blif.tgt diff --git a/tgt-blif/blif.cc b/tgt-blif/blif.cc index 845186ae2..ada8ac849 100644 --- a/tgt-blif/blif.cc +++ b/tgt-blif/blif.cc @@ -19,7 +19,7 @@ # include "version_base.h" # include "version_tag.h" -# include "config.h" +# include "priv.h" # include "ivl_target.h" # include "nex_data.h" # include @@ -51,11 +51,20 @@ static const char*version_string = " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" ; -static int emit_blif(const char*blif_path, ivl_scope_t model); +int blif_errors = 0; + +static void emit_blif(const char*blif_path, ivl_design_t des, ivl_scope_t model); + +static int process_scan_fun(ivl_process_t net, void*raw) +{ + fprintf(stderr, "%s:%u: sorry: BLIF: Processes not supported yet.\n", + ivl_process_file(net), ivl_process_lineno(net)); + blif_errors += 1; + return 0; +} 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 @@ -75,11 +84,14 @@ int target_design(ivl_design_t des) return 1; } + // Detect processes and dispatch them. + ivl_design_process(des, &process_scan_fun, 0); + // Emit to the destination file. assert(blif_path); - rc += emit_blif(blif_path, roots[0]); + emit_blif(blif_path, des, roots[0]); - return rc; + return blif_errors; } @@ -122,57 +134,33 @@ static void print_signal_bits(FILE*fd, ivl_signal_t sig) } } -static void print_logic_gate(FILE*fd, ivl_net_logic_t net) + +static void emit_scope(FILE*fd, ivl_scope_t scope) { -#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()); + for (unsigned idx = 0 ; idx < ivl_scope_logs(scope) ; idx += 1) { + ivl_net_logic_t net = ivl_scope_log(scope, idx); + assert(net); + blif_errors += print_logic_gate(fd, net); } - 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; + for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) { + ivl_lpm_t net = ivl_scope_lpm(scope, idx); + blif_errors += print_lpm(fd, net); + } + + for (size_t idx = 0 ; idx < ivl_scope_childs(scope) ; idx += 1) { + ivl_scope_t child = ivl_scope_child(scope, idx); + emit_scope(fd, child); } } -static int emit_blif(const char*blif_path, ivl_scope_t model) +static void emit_blif(const char*blif_path, ivl_design_t des, ivl_scope_t model) { - int rc = 0; - FILE*fd = fopen(blif_path, "wt"); if (fd == 0) { perror(blif_path); - return 1; + blif_errors += 1; + return; } fprintf(fd, ".model %s\n", ivl_scope_basename(model)); @@ -197,7 +185,7 @@ static int emit_blif(const char*blif_path, ivl_scope_t model) fprintf(stderr, "BLIF: error: " "Model port %s is bi-directional.\n", ivl_signal_basename(prt)); - rc += 1; + blif_errors += 1; ports_in.push_back(prt); ports_out.push_back(prt); break; @@ -221,14 +209,22 @@ static int emit_blif(const char*blif_path, ivl_scope_t model) 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); - } + emit_scope(fd, model); + + emit_constants(fd, des, model); fprintf(fd, ".end\n"); fclose(fd); - - return rc; +} + +bool scope_is_in_model(ivl_scope_t model, ivl_scope_t scope) +{ + while (scope) { + if (scope==model) + return true; + + scope = ivl_scope_parent(scope); + } + + return false; } diff --git a/tgt-blif/constants.cc b/tgt-blif/constants.cc new file mode 100644 index 000000000..c9a49758b --- /dev/null +++ b/tgt-blif/constants.cc @@ -0,0 +1,70 @@ +/* + * 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 "priv.h" +# include "nex_data.h" +# include + +static void print_constant(FILE*fd, ivl_net_const_t net) +{ + unsigned wid = ivl_const_width(net); + const char*val = ivl_const_bits(net); + ivl_nexus_t nex = ivl_const_nex(net); + blif_nex_data_t*ned = blif_nex_data_t::get_nex_data(nex); + + if (wid == 1) { + switch (val[0]) { + case '1': + fprintf(fd, ".names %s # const 1\n1\n", ned->get_name()); + break; + case '0': + fprintf(fd, ".names %s # const 0\n", ned->get_name()); + break; + default: + fprintf(fd, ".names %s # const %c\n", ned->get_name(), val[0]); + break; + } + return; + } + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + switch (val[idx]) { + case '1': + fprintf(fd, ".names %s[%u]\n # const 1\n", ned->get_name(), idx); + break; + case '0': + fprintf(fd, ".names %s[%u]\n # const 0", ned->get_name(), idx); + break; + default: + fprintf(fd, ".names %s[%u]\n # const %c", ned->get_name(), idx, val[idx]); + break; + } + } +} + +void emit_constants(FILE*fd, ivl_design_t des, ivl_scope_t model) +{ + for (unsigned idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) { + ivl_net_const_t net = ivl_design_const(des, idx); + if (! scope_is_in_model(model, ivl_const_scope(net))) + continue; + + print_constant(fd, net); + } +} diff --git a/tgt-blif/logic_gate.cc b/tgt-blif/logic_gate.cc new file mode 100644 index 000000000..df9bed350 --- /dev/null +++ b/tgt-blif/logic_gate.cc @@ -0,0 +1,69 @@ +/* + * 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 "priv.h" +# include "nex_data.h" +# include + +int print_logic_gate(FILE*fd, ivl_net_logic_t net) +{ + int rc = 0; + + // Do not handle logic gate widths. + assert(ivl_logic_width(net) == 1); + + ivl_nexus_t nex_out = ivl_logic_pin(net,0); + blif_nex_data_t*ned_out = blif_nex_data_t::get_nex_data(nex_out); + + assert(ned_out->get_width() == 1); + + fprintf(fd, ".names"); + for (unsigned idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { + ivl_nexus_t nex = ivl_logic_pin(net,idx); + blif_nex_data_t*ned = blif_nex_data_t::get_nex_data(nex); + fprintf(fd, " %s", ned->get_name()); + } + + fprintf(fd, " %s", ned_out->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"); + rc += 1; + break; + } + + return rc; +} diff --git a/tgt-blif/lpm.cc b/tgt-blif/lpm.cc new file mode 100644 index 000000000..da8f9d0e5 --- /dev/null +++ b/tgt-blif/lpm.cc @@ -0,0 +1,122 @@ +/* + * 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 "priv.h" +# include "nex_data.h" +# include + +/* + * Implement IVL_LPM_CONCAT devices by creating a .names buffer for + * each bit of the output. Connect the output bit to the input bit. So + * for example: + * Q = {A, B, C} + * becomes: + * .names C Q[0] + * 1 1 + * .names B Q[1] + * 1 1 + * .names A Q[2] + * 1 1 + * (In this example, A, B, and C are 1 bit.) + */ +static int print_concat(FILE*fd, ivl_lpm_t net) +{ + fprintf(fd, "# %s:%u: IVL_LPM_CONCAT: width=%u\n", + ivl_lpm_file(net), ivl_lpm_lineno(net), ivl_lpm_width(net)); + + ivl_nexus_t nex_q = ivl_lpm_q(net); + blif_nex_data_t*ned_q = blif_nex_data_t::get_nex_data(nex_q); + + ivl_nexus_t nex_d = ivl_lpm_data(net,0); + blif_nex_data_t*ned_d = blif_nex_data_t::get_nex_data(nex_d); + unsigned didx = 0; + unsigned dpos = 0; + for (unsigned wid = 0 ; wid < ivl_lpm_width(net) ; wid += 1) { + if (dpos >= ned_d->get_width()) { + didx += 1; + dpos = 0; + nex_d = ivl_lpm_data(net,didx); + ned_d = blif_nex_data_t::get_nex_data(nex_d); + } + + char dsub[8]; + if (ned_d->get_width() > 1) + snprintf(dsub, sizeof dsub, "[%u]", dpos); + else + dsub[0] = 0; + + fprintf(fd, ".names %s%s %s[%u]\n1 1\n", + ned_d->get_name(), dsub, + ned_q->get_name(), wid); + dpos += 1; + } + + return 0; +} + +/* + * This implements the IVL_LPM_PART_VP, which is the vector-to-part + * part select. Implement this as a .names buffer. + */ +static int print_part_vp(FILE*fd, ivl_lpm_t net) +{ + int rc = 0; + + ivl_nexus_t nex_out = ivl_lpm_q(net); + blif_nex_data_t*ned_out = blif_nex_data_t::get_nex_data(nex_out); + + // Only handle bit selects. + assert(ned_out->get_width() == 1); + // Only handle constant part select base. + assert(ivl_lpm_data(net,1) == 0); + + unsigned bit_sel = ivl_lpm_base(net); + + ivl_nexus_t nex_in = ivl_lpm_data(net,0); + blif_nex_data_t*ned_in = blif_nex_data_t::get_nex_data(nex_in); + + assert(bit_sel < ned_in->get_width()); + + fprintf(fd, ".names %s[%u] %s\n1 1\n", ned_in->get_name(), bit_sel, ned_out->get_name()); + + return rc; +} + +int print_lpm(FILE*fd, ivl_lpm_t net) +{ + int rc = 0; + + switch (ivl_lpm_type(net)) { + case IVL_LPM_CONCAT: + case IVL_LPM_CONCATZ: + rc += print_concat(fd, net); + break; + case IVL_LPM_PART_VP: + rc += print_part_vp(fd, net); + break; + default: + fprintf(fd, "# XXXX ivl_lpm_type(net) --> %d\n", ivl_lpm_type(net)); + fprintf(stderr, "%s:%u: sorry: ivl_lpm_type(net)==%d not implemented.\n", + ivl_lpm_file(net), ivl_lpm_lineno(net), ivl_lpm_type(net)); + rc += 1; + break; + } + + return rc; +} diff --git a/tgt-blif/nex_data.cc b/tgt-blif/nex_data.cc index 4abad4d54..5e541c13a 100644 --- a/tgt-blif/nex_data.cc +++ b/tgt-blif/nex_data.cc @@ -18,13 +18,16 @@ */ # include "nex_data.h" +# include # include # include # include # include +using namespace std; + inline blif_nex_data_t::blif_nex_data_t(ivl_nexus_t nex) -: nex_(nex), name_(0) +: nex_(nex), name_(0), width_(0) { } @@ -59,7 +62,14 @@ const char* blif_nex_data_t::get_name(void) if (sig == 0) continue; - name_ = strdup(ivl_signal_basename(sig)); + string tmp = ivl_signal_basename(sig); + for (ivl_scope_t sscope = ivl_signal_scope(sig) ; ivl_scope_parent(sscope) ; sscope = ivl_scope_parent(sscope)) { + tmp = ivl_scope_basename(sscope) + string("/") + tmp; + } + + name_ = strdup(tmp.c_str()); + width_ = ivl_signal_width(sig); + assert(width_ > 0); break; } @@ -72,3 +82,25 @@ const char* blif_nex_data_t::get_name(void) assert(name_); return name_; } + +/* + * Get the width from any signal that is attached to the nexus. + */ +size_t blif_nex_data_t::get_width(void) +{ + if (width_ > 0) + return width_; + + 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; + + width_ = ivl_signal_width(sig); + break; + } + + assert(width_ > 0); + return width_; +} diff --git a/tgt-blif/nex_data.h b/tgt-blif/nex_data.h index c326f5e8e..76af04a8f 100644 --- a/tgt-blif/nex_data.h +++ b/tgt-blif/nex_data.h @@ -20,6 +20,7 @@ */ # include "ivl_target.h" +# include /* * The ivl_target.h API allows for binding data to a nexus. This class @@ -41,14 +42,22 @@ class blif_nex_data_t { // the same nexus. static blif_nex_data_t* get_nex_data(ivl_nexus_t nex); + // In certain situations, we know a priori what we want the + // nexus name to be. In those cases, the context can use this + // method to set the name. Note that this must be called + // before the name is otherwise queried. void set_name(const char*); // Get the symbolic name chosen for this nexus. const char*get_name(void); + // Get the vector width for this nexus. + size_t get_width(void); + public: ivl_nexus_t nex_; char*name_; + size_t width_; }; #endif diff --git a/tgt-blif/priv.h b/tgt-blif/priv.h new file mode 100644 index 000000000..55a765a71 --- /dev/null +++ b/tgt-blif/priv.h @@ -0,0 +1,49 @@ +#ifndef __priv_H +#define __priv_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" +# include + +/* + * Errors are counted here. When the blif processing is done, this + * value is returned to ivl so that it can report error counts. + */ +extern int blif_errors; + +extern int print_logic_gate(FILE*fd, ivl_net_logic_t net); + +extern int print_lpm(FILE*fd, ivl_lpm_t net); + +/* + * Emit all the constants for a model. This works by scanning the + * design for all constants, testing that they are part of the model, + * and writing them out as .names records. + */ +extern void emit_constants(FILE*fd, ivl_design_t des, ivl_scope_t model); + +/* + * Return true if the passed scope is under the model scope, at any + * depth. The scope may be an immediate child, or a child several + * levels removed. + */ +extern bool scope_is_in_model(ivl_scope_t model, ivl_scope_t scope); + +#endif