Implement blif support for constants and some logic/lpm gates.

This starts the handling of various logic gates.
This commit is contained in:
Stephen Williams 2013-07-18 19:39:49 -07:00
parent 01b81e0dbc
commit e0c9efd129
8 changed files with 404 additions and 57 deletions

View File

@ -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

View File

@ -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 <vector>
@ -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;
}

70
tgt-blif/constants.cc Normal file
View File

@ -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 <cstdio>
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);
}
}

69
tgt-blif/logic_gate.cc Normal file
View File

@ -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 <cassert>
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;
}

122
tgt-blif/lpm.cc Normal file
View File

@ -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 <cassert>
/*
* 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;
}

View File

@ -18,13 +18,16 @@
*/
# include "nex_data.h"
# include <iostream>
# include <cstdlib>
# include <cstdio>
# include <cstring>
# include <cassert>
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_;
}

View File

@ -20,6 +20,7 @@
*/
# include "ivl_target.h"
# include <cstddef>
/*
* 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

49
tgt-blif/priv.h Normal file
View File

@ -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 <cstdio>
/*
* 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