Merge branch 'master' into vec4-stack

Conflicts:
	elab_lval.cc
This commit is contained in:
Stephen Williams 2014-02-10 16:26:22 -08:00
commit 1d63875e5d
19 changed files with 706 additions and 60 deletions

View File

@ -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 tgt-blif driver
tgt-vhdl tgt-vlog95 tgt-pcb tgt-blif tgt-sizer driver
# Only run distclean for these directories.
NOTUSED = tgt-fpga tgt-pal tgt-verilog

View File

@ -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 tgt-blif/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 tgt-sizer/Makefile)

View File

@ -301,7 +301,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
/* Get the signal referenced by the identifier, and make sure
it is a register. Wires are not allowed in this context,
unless this is the l-value of a force. */
if ((reg->type() != NetNet::REG) && !is_force) {
if ((reg->type() != NetNet::REG)
&& (reg->type() != NetNet::UNRESOLVED_WIRE)
&& !is_force) {
cerr << get_fileline() << ": error: " << path_ <<
" is not a valid l-value in " << scope_path(use_scope) <<
"." << endl;
@ -326,7 +328,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
// where the name is a member/method of a struct/class.
ivl_assert(*this, method_name.nil());
bool need_const_idx = is_cassign || is_force;
bool need_const_idx = is_cassign || is_force || (reg->type()==NetNet::UNRESOLVED_WIRE);
if (reg->unpacked_dimensions() > 0)
return elaborate_lval_net_word_(des, scope, reg, need_const_idx);
@ -370,6 +372,14 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
ivl_assert(*this, use_sel == index_component_t::SEL_NONE);
if (reg->type()==NetNet::UNRESOLVED_WIRE && !is_force) {
cerr << get_fileline() << ": error: "
<< path_ << " Unable to assign to unresolved wires."
<< endl;
des->errors += 1;
return 0;
}
/* No select expressions. */
NetAssign_*lv = new NetAssign_(reg);
@ -531,6 +541,13 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
<< "canon_index=" << *canon_index << endl;
}
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
cerr << get_fileline() << ": error: "
<< "Unable to assign words of unresolved wire array." << endl;
des->errors += 1;
return 0;
}
NetAssign_*lv = new NetAssign_(reg);
lv->set_word(canon_index);
@ -623,6 +640,19 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
}
}
if (debug_elaborate && (reg->type()==NetNet::UNRESOLVED_WIRE)) {
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_bit_: "
<< "Try to assign bits of unresolved wire."
<< endl;
}
// Notice that we might be assigning to an unresolved wire. This
// can happen if we are actually assigning to a variable that
// has a partial continuous assignment to it. If that is the
// case, then the bit select must be constant.
ivl_assert(*this, need_const_idx || (reg->type()!=NetNet::UNRESOLVED_WIRE));
if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
// Special case: this is a slice of a multi-dimensional
// packed array. For example:
@ -637,8 +667,19 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
ivl_assert(*this, rcl);
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
bool rct = reg->test_and_set_part_driver(loff+lwid-1, loff);
if (rct) {
cerr << get_fileline() << ": error: "
<< "These bits are already driven." << endl;
des->errors += 1;
}
}
lv->set_part(new NetEConst(verinum(loff)), lwid);
} else {
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
unsigned long lwid;
mux = normalize_variable_slice_base(prefix_indices, mux,
reg, lwid);
@ -646,6 +687,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
}
} else if (reg->data_type() == IVL_VT_STRING) {
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
// Special case: This is a select of a string
// variable. The target of the assignment is a character
// select of a string. Force the r-value to be an 8bit
@ -662,6 +704,8 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
lv->set_part(new NetEConst(verinum(lsb)), 8);
} else if (mux) {
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select
// expression.
@ -679,6 +723,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
// NOTE: Don't know what to do about unresolved wires
// here, but they are probably wrong.
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
} else {
// Constant bit select that does something useful.
long loff = reg->sb_to_idx(prefix_indices,lsb);
@ -691,6 +739,15 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
return 0;
}
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
bool rct = reg->test_and_set_part_driver(loff, loff);
if (rct) {
cerr << get_fileline() << ": error: "
<< "Bit " << loff << " is already driven." << endl;
des->errors += 1;
}
}
lv->set_part(new NetEConst(verinum(loff)), 1);
}
@ -705,6 +762,14 @@ bool PEIdent::elaborate_lval_darray_bit_(Design*des, NetScope*scope, NetAssign_*
// For now, only support single-dimension dynamic arrays.
ivl_assert(*this, name_tail.index.size() == 1);
if (lv->sig()->type()==NetNet::UNRESOLVED_WIRE) {
cerr << get_fileline() << ": error: "
<< path_ << " Unable to darray word select unresolved wires."
<< endl;
des->errors += 1;
return false;
}
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
@ -747,6 +812,17 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
return true;
}
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
bool rct = reg->test_and_set_part_driver(msb, lsb);
if (rct) {
cerr << get_fileline() << ": error: "
<< path_ << "Part select is double-driving unresolved wire."
<< endl;
des->errors += 1;
return false;
}
}
const vector<netrange_t>&packed = reg->packed_dims();
long loff, moff;
@ -1127,6 +1203,14 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
packed_base = 0;
}
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
cerr << get_fileline() << ": error: "
<< path_ << " Unable to member-select unresolved wires."
<< endl;
des->errors += 1;
return false;
}
if (packed_base == 0) {
lv->set_part(new NetEConst(verinum(off)), use_width);
return true;

View File

@ -710,7 +710,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
unsigned subnet_wid = midx-lidx+1;
/* Check if the l-value bits are double-driven. */
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) {
if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_and_set_part_driver(midx,lidx)) {
cerr << get_fileline() << ": error: Unresolved net/uwire "
<< sig->name() << " cannot have multiple drivers." << endl;
des->errors += 1;

View File

@ -868,7 +868,7 @@ unsigned NetNet::peek_eref() const
* Test each of the bits in the range, and set them. If any bits are
* already set then return true.
*/
bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb)
bool NetNet::test_and_set_part_driver(unsigned pmsb, unsigned plsb)
{
if (lref_mask_.empty())
lref_mask_.resize(vector_width());

View File

@ -726,17 +726,22 @@ class NetNet : public NetObj, public PortType {
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
/* NetESignal objects may reference this object. Keep a
reference count so that I keep track of them. */
// NetESignal objects may reference this object. Keep a
// reference count so that I keep track of them.
void incr_eref();
void decr_eref();
unsigned peek_eref() const;
/* Assignment statements count their lrefs here. */
// Assignment statements count their lrefs here. And by
// asignment statements, we mean BEHAVIORAL assignments.
void incr_lref();
void decr_lref();
unsigned peek_lref() const { return lref_count_; }
bool test_part_lref(unsigned msb, unsigned lsb);
// Treating this node as a uwire, this function tests whether
// any bits in the canonical part are already driven. This is
// only useful for UNRESOLVED_WIRE objects.
bool test_and_set_part_driver(unsigned msb, unsigned lsb);
unsigned get_refs() const;

View File

@ -3853,8 +3853,15 @@ port_declaration
use_type = NetNet::IMPLICIT;
else
use_type = NetNet::IMPLICIT_REG;
// The SystemVerilog types that can show up as
// output ports are implicitly (on the inside)
// variables because "reg" is not valid syntax
// here.
} else if (dynamic_cast<atom2_type_t*> ($4)) {
use_type = NetNet::IMPLICIT_REG;
} else if (dynamic_cast<struct_type_t*> ($4)) {
use_type = NetNet::IMPLICIT_REG;
}
}
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);

View File

@ -58,9 +58,9 @@ struct symbol_search_results {
NetEvent*eve;
};
bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
pform_name_t path, struct symbol_search_results*res,
NetScope*start_scope = 0)
static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
pform_name_t path, struct symbol_search_results*res,
NetScope*start_scope = 0)
{
assert(scope);
bool prefix_scope = false;
@ -100,6 +100,9 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
"`" << path_tail.name << "' in path `" << path << "'" << endl;
des->errors += 1;
}
} else {
// Prefix is present, but is NOT a scope. Fail!
return false;
}
}

118
synth2.cc
View File

@ -189,18 +189,18 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
unsigned sel_width = esig->vector_width();
assert(sel_width > 0);
unsigned mux_width = 0;
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
mux_width += nex_out.pin(idx).nexus()->vector_width();
ivl_assert(*this, nex_map.size() == nex_out.pin_count());
unsigned map_width = 0;
for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1)
map_width += nex_map[idx].wid;
vector<unsigned> mux_width (nex_out.pin_count());
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
mux_width[idx] = nex_map[idx].wid;
if (debug_synth2) {
cerr << get_fileline() << ": NetCase::synth_async: "
<< "idx=" << idx
<< ", mux_width[idx]=" << mux_width[idx] << endl;
}
}
/* Calculate the mux width from the map, the mex_map values
are from the top level and are more reliable. */
if (map_width > mux_width)
mux_width = map_width;
/* Collect all the statements into a map of index to
statement. The guard expression it evaluated to be the
@ -230,6 +230,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
max_guard_value = sel_idx;
}
// The mux_size is the number of inputs that are selected.
unsigned mux_size = max_guard_value + 1;
// If the sel_width can select more than just the explicit
@ -240,48 +241,59 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
}
NetMux*mux = new NetMux(scope, scope->local_symbol(),
mux_width, mux_size, sel_width);
des->add_node(mux);
/* The select signal is already synthesized. Simply hook it up. */
connect(mux->pin_Sel(), esig->pin(0));
/* For now, assume that the output is only 1 signal. */
ivl_assert(*this, nex_out.pin_count() == 1);
connect(mux->pin_Result(), nex_out.pin(0));
/* Make sure the output is already connected to a net. */
if (mux->pin_Result().nexus()->pick_any_net() == 0) {
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width-1, 0);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::TRI, tmp_vec);
tmp->local_flag(true);
ivl_assert(*this, tmp->vector_width() != 0);
connect(mux->pin_Result(), tmp->pin(0));
}
/* If there is a default clause, synthesize is once and we'll
link it in wherever it is needed. */
NetNet*default_sig = 0;
NetBus default_bus (scope, nex_map.size());
vector<NetNet*>default_sig (nex_map.size());
if (statement_default) {
NetBus tmp (scope, nex_map.size());
statement_default->synth_async(des, scope, nex_map, tmp);
statement_default->synth_async(des, scope, nex_map, default_bus);
// Get the signal from the synthesized statement. This
// will be hooked to all the default cases.
ivl_assert(*this, tmp.pin_count()==1);
default_sig = tmp.pin(0).nexus()->pick_any_net();
ivl_assert(*this, default_sig);
ivl_assert(*this, default_bus.pin_count()==1);
default_sig[0] = default_bus.pin(0).nexus()->pick_any_net();
ivl_assert(*this, default_sig[0]);
}
vector<NetMux*> mux (mux_width.size());
for (size_t mdx = 0 ; mdx < mux_width.size() ; mdx += 1) {
mux[mdx] = new NetMux(scope, scope->local_symbol(),
mux_width[mdx], mux_size, sel_width);
des->add_node(mux[mdx]);
// The select signal is already synthesized, and is
// common for every mux of this case statement. Simply
// hook it up.
connect(mux[mdx]->pin_Sel(), esig->pin(0));
// The outputs are in the nex_out, and connected to the
// mux Result pins.
connect(mux[mdx]->pin_Result(), nex_out.pin(mdx));
// Make sure the output is now connected to a net. If
// not, then create a fake one to carry the net-ness of
// the pin.
if (mux[mdx]->pin_Result().nexus()->pick_any_net() == 0) {
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::TRI, tmp_vec);
tmp->local_flag(true);
ivl_assert(*this, tmp->vector_width() != 0);
connect(mux[mdx]->pin_Result(), tmp->pin(0));
}
}
for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
NetProc*stmt = statement_map[idx];
if (stmt==0 && default_sig!=0) {
connect(mux->pin_Data(idx), default_sig->pin(0));
if (stmt==0 && statement_default) {
ivl_assert(*this, default_sig.size() == mux.size());
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1)
connect(mux[mdx]->pin_Data(idx), default_sig[mdx]->pin(0));
continue;
}
if (stmt == 0) {
@ -294,9 +306,24 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
NetBus tmp (scope, nex_map.size());
stmt->synth_async(des, scope, nex_map, tmp);
ivl_assert(*this, tmp.pin_count()==1);
connect(mux->pin_Data(idx), tmp.pin(0));
ivl_assert(*this, mux->pin_Data(idx).nexus()->pick_any_net());
ivl_assert(*this, tmp.pin_count() == mux.size());
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) {
connect(mux[mdx]->pin_Data(idx), tmp.pin(mdx));
if (mux[mdx]->pin_Data(idx).nexus()->pick_any_net()==0) {
cerr << get_fileline() << ": warning: case " << idx
<< " has no input for mux " << mdx << "." << endl;
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1, 0);
NetNet*tmpn = new NetNet(scope, scope->local_symbol(),
NetNet::TRI, tmp_vec);
tmpn->local_flag(true);
ivl_assert(*this, tmpn->vector_width() != 0);
connect(mux[mdx]->pin_Data(idx), tmpn->pin(0));
}
ivl_assert(*this, mux[mdx]->pin_Data(idx).nexus()->pick_any_net());
}
}
return true;
@ -842,15 +869,16 @@ bool NetProcTop::synth_sync(Design*des)
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
ivl_assert(*this, nex_set[idx].nex);
if (debug_synth2) {
cerr << get_fileline() << ": debug: "
<< "Top level making a "
<< nex_set[idx].nex->vector_width() << "-wide "
<< nex_set[idx].wid << "-wide "
<< "NetFF device." << endl;
}
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
nex_set[idx].nex->vector_width());
nex_set[idx].wid);
des->add_node(ff2);
ff2->set_line(*this);

103
tgt-sizer/Makefile.in Normal file
View File

@ -0,0 +1,103 @@
#
# 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@
CXX = @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@ @WARNING_FLAGS_CXX@ @CXXFLAGS@
LDFLAGS = @LDFLAGS@
O = sizer.o scan_lpms.o scan_logs.o
all: dep sizer.tgt
check: all
clean:
rm -rf *.o dep sizer.tgt
distclean: clean
rm -f Makefile config.log
cppcheck: $(O:.o=.cc)
cppcheck --enable=all -f $(INCLUDE_PATH) $^
Makefile: $(srcdir)/Makefile.in ../config.status
cd ..; ./config.status --file=tgt-sizer/$@
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
sizer.tgt: $O $(TGTDEPLIBS)
$(CXX) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS)
install: all installdirs $(libdir)/ivl$(suffix)/sizer.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/sizer.conf $(libdir)/ivl$(suffix)/sizer-s.conf
$(libdir)/ivl$(suffix)/sizer.tgt: ./sizer.tgt
$(INSTALL_PROGRAM) ./sizer.tgt "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer.tgt"
$(libdir)/ivl$(suffix)/sizer.conf: $(srcdir)/sizer.conf
$(INSTALL_DATA) $(srcdir)/sizer.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer.conf"
$(libdir)/ivl$(suffix)/sizer-s.conf: $(srcdir)/sizer-s.conf
$(INSTALL_DATA) $(srcdir)/sizer-s.conf "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer-s.conf"
installdirs: $(srcdir)/../mkinstalldirs
$(srcdir)/../mkinstalldirs "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libdir)/ivl$(suffix)"
uninstall:
rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer.tgt"
rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer.conf"
rm -f "$(DESTDIR)$(libdir)/ivl$(suffix)/sizer-s.conf"
-include $(patsubst %.o, dep/%.d, $O)

50
tgt-sizer/scan_logs.cc Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2014 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 "sizer_priv.h"
void scan_logs_gates(ivl_scope_t, ivl_net_logic_t log, struct sizer_statistics&stats)
{
unsigned wid = ivl_logic_width(log);
stats.gate_count += wid;
}
void scan_logs(ivl_scope_t scope, struct sizer_statistics&stats)
{
for (unsigned idx = 0 ; idx < ivl_scope_logs(scope) ; idx += 1) {
ivl_net_logic_t log = ivl_scope_log(scope, idx);
switch (ivl_logic_type(log)) {
case IVL_LO_AND:
case IVL_LO_OR:
case IVL_LO_XOR:
case IVL_LO_NAND:
case IVL_LO_NOR:
case IVL_LO_XNOR:
case IVL_LO_BUF:
case IVL_LO_NOT:
scan_logs_gates(scope, log, stats);
break;
default:
stats.log_bytype[ivl_logic_type(log)] += 1;
break;
}
}
}

78
tgt-sizer/scan_lpms.cc Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2014 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 "sizer_priv.h"
using namespace std;
/*
* Count each bit of flip-flops. It is clear and obvious how these
* come out, so no need to make alternate counts as well.
*/
static void scan_lpms_ff(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats)
{
ivl_nexus_t out = ivl_lpm_q(lpm);
unsigned wid = get_nexus_width(out);
stats.flop_count += wid;
}
/*
* Count adders as 2m gates.
* Also keep a count of adders by width, just out of curiosity.
*/
static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats)
{
unsigned wid = ivl_lpm_width(lpm);
stats.adder_count[wid] += 1;
stats.gate_count += 2*wid;
}
void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
{
for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) {
ivl_lpm_t lpm = ivl_scope_lpm(scope,idx);
switch (ivl_lpm_type(lpm)) {
// Part select nodes don't actually take up
// hardware. These represent things like bundle
// manipulations, which are done in routing.
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
case IVL_LPM_REPEAT:
break;
case IVL_LPM_ADD:
scans_lpms_add(scope, lpm, stats);
break;
// D-Type flip-flops.
case IVL_LPM_FF:
scan_lpms_ff(scope, lpm, stats);
break;
default:
stats.lpm_bytype[ivl_lpm_type(lpm)] += 1;
break;
}
}
}

6
tgt-sizer/sizer-s.conf Normal file
View File

@ -0,0 +1,6 @@
functor:synth2
functor:synth
functor:syn-rules
functor:cprop
functor:nodangle
flag:DLL=sizer.tgt

199
tgt-sizer/sizer.cc Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2014 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 "sizer_priv.h"
# include <cstdio>
# include <cstring>
# include <cassert>
using namespace std;
/*
* This is a null target module. It does nothing.
*/
static const char*version_string =
"Icarus Verilog SIZER Statistics Generator " VERSION " (" VERSION_TAG ")\n\n"
"Copyright (c) 2014 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"
;
int sizer_errors = 0;
FILE*sizer_out = 0;
static int process_scan_fun(ivl_process_t net, void*raw);
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t model, struct sizer_statistics&stats);
static void show_stats(struct sizer_statistics&stats);
/*
* This is called by the ivl core to get version information from the
* loadable code generator.
*/
const char* target_query(const char*key)
{
if (strcmp(key,"version") == 0)
return version_string;
return 0;
}
/*
* This is the main entry point from the IVL core.
*/
int target_design(ivl_design_t des)
{
const char*sizer_path = ivl_design_flag(des, "-o");
sizer_out = fopen(sizer_path, "wt");
assert(sizer_out);
// Detect processes and dispatch them.
ivl_design_process(des, &process_scan_fun, 0);
// Locate the root scopes for the design.
ivl_scope_t*roots;
unsigned nroots;
ivl_design_roots(des, &roots, &nroots);
// Process all the root scopes. It is possible that there are
// multiple root scopes, we will give isolated numbers for
// each and keep then separate.
for (unsigned idx = 0 ; idx < nroots ; idx += 1) {
if (ivl_scope_type(roots[idx]) != IVL_SCT_MODULE) {
fprintf(stderr, "SIZER: The root scope %s must be a module.\n", ivl_scope_basename(roots[idx]));
sizer_errors += 1;
continue;
}
struct sizer_statistics stats;
emit_sizer_scope(des, roots[idx], stats);
fprintf(sizer_out, "**** TOTALS\n");
show_stats(stats);
}
return sizer_errors;
}
/*
* Processes are not collected into scopes, but we should not have any
* left anyhow. Give error messages for all the processes that we find
* to be remaining.
*/
static int process_scan_fun(ivl_process_t net, void* /*raw*/)
{
fprintf(stderr, "%s:%u: SIZER: Processes not synthesized for statistics.\n",
ivl_process_file(net), ivl_process_lineno(net));
sizer_errors += 1;
return 0;
}
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t scope, struct sizer_statistics&stats)
{
fprintf(sizer_out, "**** module/scope: %s\n", ivl_scope_name(scope));
scan_logs(scope, stats);
scan_lpms(scope, stats);
show_stats(stats);
for (size_t idx = 0 ; idx < ivl_scope_childs(scope) ; idx += 1) {
ivl_scope_t child = ivl_scope_child(scope,idx);
struct sizer_statistics child_stats;
emit_sizer_scope(des, child, child_stats);
stats += child_stats;
}
}
static void show_stats(struct sizer_statistics&stats)
{
fprintf(sizer_out, " Flip-Flops : %u\n", stats.flop_count);
fprintf(sizer_out, " Logic Gates : %u\n", stats.gate_count);
for (map<unsigned,unsigned>::const_iterator cur = stats.adder_count.begin()
; cur != stats.adder_count.end() ; ++ cur) {
fprintf(sizer_out, " ADDER[%u]: %u\n", cur->first, cur->second);
}
// These are diagnostic outputs for when more detail is needed.
for (map<ivl_lpm_type_t,unsigned>::const_iterator cur = stats.lpm_bytype.begin()
; cur != stats.lpm_bytype.end() ; ++ cur) {
fprintf(sizer_out, " LPM[%d]: %u unaccounted\n", cur->first, cur->second);
}
for (map<ivl_logic_t,unsigned>::const_iterator cur = stats.log_bytype.begin()
; cur != stats.log_bytype.end() ; ++ cur) {
fprintf(sizer_out, " LOG[%d]: %u unaccounted\n", cur->first, cur->second);
}
}
unsigned get_nexus_width(ivl_nexus_t nex)
{
ivl_signal_t sig = 0;
for (unsigned idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
sig = ivl_nexus_ptr_sig(ptr);
if (sig) return ivl_signal_width(sig);
}
fprintf(stderr, "SIZER: Unable to find width of nexus?!\n");
sizer_errors += 1;
return 0;
}
struct sizer_statistics& sizer_statistics::operator += (const sizer_statistics&that)
{
flop_count += that.flop_count;
gate_count += that.gate_count;
for (map<unsigned,unsigned>::const_iterator cur = that.adder_count.begin()
; cur != that.adder_count.end() ; ++ cur)
adder_count[cur->first] += cur->second;
for (map<ivl_lpm_type_t,unsigned>::const_iterator cur = that.lpm_bytype.begin()
; cur != that.lpm_bytype.end() ; ++ cur)
lpm_bytype[cur->first] += cur->second;
for (map<ivl_logic_t,unsigned>::const_iterator cur = that.log_bytype.begin()
; cur != that.log_bytype.end() ; ++ cur)
log_bytype[cur->first] += cur->second;
return *this;
}

6
tgt-sizer/sizer.conf Normal file
View File

@ -0,0 +1,6 @@
functor:synth2
functor:synth
functor:syn-rules
functor:cprop
functor:nodangle
flag:DLL=sizer.tgt

56
tgt-sizer/sizer_priv.h Normal file
View File

@ -0,0 +1,56 @@
#ifndef __sizer_priv_H
#define __sizer_priv_H
/*
* Copyright (c) 2014 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 "config.h"
# include "ivl_target.h"
# include <map>
# include <cstdio>
struct sizer_statistics {
// These are the accumulated global statistics
unsigned flop_count;
unsigned gate_count;
// Count adders of various dimension
std::map<unsigned,unsigned> adder_count;
// Different kinds of nodes that we have not accounted for
std::map<ivl_lpm_type_t,unsigned> lpm_bytype;
std::map<ivl_logic_t,unsigned> log_bytype;
inline sizer_statistics()
{
flop_count = 0;
gate_count = 0;
}
struct sizer_statistics& operator += (const struct sizer_statistics&that);
};
extern int sizer_errors;
extern FILE*sizer_out;
extern void scan_logs(ivl_scope_t scope, struct sizer_statistics&stats);
extern void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats);
extern unsigned get_nexus_width(ivl_nexus_t nex);
#endif

View File

@ -438,8 +438,16 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
assert(ivl_lval_width(lval) == wid);
/* If the word index is a constant, then we can write
directly to the word and save the index calculation. */
if (word_ix == 0) {
directly to the word and save the index
calculation. Also, note the special case that we are
writing to a UWIRE. In that case, use the %force/x0
instruction to get the desired effect. */
if (word_ix == 0 && ivl_signal_type(sig)==IVL_SIT_UWIRE) {
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%force/x0 v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);
} else if (word_ix == 0) {
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
sig, use_word, bit, wid);

View File

@ -74,6 +74,9 @@ rm -rf $RPM_BUILD_ROOT
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.tgt
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.conf
%attr(-,root,root) %{_libdir}/ivl%{suff}/null-s.conf
%attr(-,root,root) %{_libdir}/ivl%{suff}/sizer.tgt
%attr(-,root,root) %{_libdir}/ivl%{suff}/sizer.conf
%attr(-,root,root) %{_libdir}/ivl%{suff}/sizer-s.conf
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub.tgt
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub.conf
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub-s.conf

View File

@ -394,6 +394,16 @@ class vvp_fun_signal_object_aa : public vvp_fun_signal_object, public automatic_
* The vvp_wire is different from vvp_variable objects in that it
* exists only as a filter. The vvp_wire class tree is for
* implementing verilog wires/nets (as opposed to regs/variables).
*
* vvp_vpi_callback
* |
* |
* vvp_net_fil_t vvp_signal_value
* | |
* \ /
* \ /
* \ /
* vvp_wire_base
*/
class vvp_wire_base : public vvp_net_fil_t, public vvp_signal_value {