Merge branch 'master' into vec4-stack
Conflicts: elab_lval.cc
This commit is contained in:
commit
1d63875e5d
|
|
@ -38,7 +38,7 @@ srcdir = @srcdir@
|
||||||
datarootdir = @datarootdir@
|
datarootdir = @datarootdir@
|
||||||
|
|
||||||
SUBDIRS = ivlpp vhdlpp vvp vpi libveriuser cadpli tgt-null tgt-stub tgt-vvp \
|
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.
|
# Only run distclean for these directories.
|
||||||
NOTUSED = tgt-fpga tgt-pal tgt-verilog
|
NOTUSED = tgt-fpga tgt-pal tgt-verilog
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -325,4 +325,4 @@ AC_MSG_ERROR(cannot configure white space in libdir: $libdir)
|
||||||
fi
|
fi
|
||||||
AC_MSG_RESULT(ok)
|
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)
|
||||||
|
|
|
||||||
88
elab_lval.cc
88
elab_lval.cc
|
|
@ -301,7 +301,9 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
/* Get the signal referenced by the identifier, and make sure
|
/* Get the signal referenced by the identifier, and make sure
|
||||||
it is a register. Wires are not allowed in this context,
|
it is a register. Wires are not allowed in this context,
|
||||||
unless this is the l-value of a force. */
|
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_ <<
|
cerr << get_fileline() << ": error: " << path_ <<
|
||||||
" is not a valid l-value in " << scope_path(use_scope) <<
|
" is not a valid l-value in " << scope_path(use_scope) <<
|
||||||
"." << endl;
|
"." << endl;
|
||||||
|
|
@ -326,7 +328,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
||||||
// where the name is a member/method of a struct/class.
|
// where the name is a member/method of a struct/class.
|
||||||
ivl_assert(*this, method_name.nil());
|
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)
|
if (reg->unpacked_dimensions() > 0)
|
||||||
return elaborate_lval_net_word_(des, scope, reg, need_const_idx);
|
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);
|
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. */
|
/* No select expressions. */
|
||||||
|
|
||||||
NetAssign_*lv = new NetAssign_(reg);
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
|
|
@ -531,6 +541,13 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des,
|
||||||
<< "canon_index=" << *canon_index << endl;
|
<< "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);
|
NetAssign_*lv = new NetAssign_(reg);
|
||||||
lv->set_word(canon_index);
|
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()) {
|
if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
|
||||||
// Special case: this is a slice of a multi-dimensional
|
// Special case: this is a slice of a multi-dimensional
|
||||||
// packed array. For example:
|
// 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);
|
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
|
||||||
ivl_assert(*this, rcl);
|
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);
|
lv->set_part(new NetEConst(verinum(loff)), lwid);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||||
unsigned long lwid;
|
unsigned long lwid;
|
||||||
mux = normalize_variable_slice_base(prefix_indices, mux,
|
mux = normalize_variable_slice_base(prefix_indices, mux,
|
||||||
reg, lwid);
|
reg, lwid);
|
||||||
|
|
@ -646,6 +687,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (reg->data_type() == IVL_VT_STRING) {
|
} 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
|
// Special case: This is a select of a string
|
||||||
// variable. The target of the assignment is a character
|
// variable. The target of the assignment is a character
|
||||||
// select of a string. Force the r-value to be an 8bit
|
// 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);
|
lv->set_part(new NetEConst(verinum(lsb)), 8);
|
||||||
|
|
||||||
} else if (mux) {
|
} else if (mux) {
|
||||||
|
ivl_assert(*this, reg->type()!=NetNet::UNRESOLVED_WIRE);
|
||||||
|
|
||||||
// Non-constant bit mux. Correct the mux for the range
|
// Non-constant bit mux. Correct the mux for the range
|
||||||
// of the vector, then set the l-value part select
|
// of the vector, then set the l-value part select
|
||||||
// expression.
|
// expression.
|
||||||
|
|
@ -679,6 +723,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
// Constant bit mux that happens to select the only bit
|
// Constant bit mux that happens to select the only bit
|
||||||
// of the l-value. Don't bother with any select at all.
|
// 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 {
|
} else {
|
||||||
// Constant bit select that does something useful.
|
// Constant bit select that does something useful.
|
||||||
long loff = reg->sb_to_idx(prefix_indices,lsb);
|
long loff = reg->sb_to_idx(prefix_indices,lsb);
|
||||||
|
|
@ -691,6 +739,15 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
|
||||||
return 0;
|
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);
|
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.
|
// For now, only support single-dimension dynamic arrays.
|
||||||
ivl_assert(*this, name_tail.index.size() == 1);
|
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();
|
const index_component_t&index_tail = name_tail.index.back();
|
||||||
ivl_assert(*this, index_tail.msb != 0);
|
ivl_assert(*this, index_tail.msb != 0);
|
||||||
ivl_assert(*this, index_tail.lsb == 0);
|
ivl_assert(*this, index_tail.lsb == 0);
|
||||||
|
|
@ -747,6 +812,17 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
|
||||||
return true;
|
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();
|
const vector<netrange_t>&packed = reg->packed_dims();
|
||||||
|
|
||||||
long loff, moff;
|
long loff, moff;
|
||||||
|
|
@ -1127,6 +1203,14 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope,
|
||||||
packed_base = 0;
|
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) {
|
if (packed_base == 0) {
|
||||||
lv->set_part(new NetEConst(verinum(off)), use_width);
|
lv->set_part(new NetEConst(verinum(off)), use_width);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -710,7 +710,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||||
unsigned subnet_wid = midx-lidx+1;
|
unsigned subnet_wid = midx-lidx+1;
|
||||||
|
|
||||||
/* Check if the l-value bits are double-driven. */
|
/* 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 "
|
cerr << get_fileline() << ": error: Unresolved net/uwire "
|
||||||
<< sig->name() << " cannot have multiple drivers." << endl;
|
<< sig->name() << " cannot have multiple drivers." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
|
||||||
|
|
@ -868,7 +868,7 @@ unsigned NetNet::peek_eref() const
|
||||||
* Test each of the bits in the range, and set them. If any bits are
|
* Test each of the bits in the range, and set them. If any bits are
|
||||||
* already set then return true.
|
* 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())
|
if (lref_mask_.empty())
|
||||||
lref_mask_.resize(vector_width());
|
lref_mask_.resize(vector_width());
|
||||||
|
|
|
||||||
13
netlist.h
13
netlist.h
|
|
@ -726,17 +726,22 @@ class NetNet : public NetObj, public PortType {
|
||||||
bool local_flag() const { return local_flag_; }
|
bool local_flag() const { return local_flag_; }
|
||||||
void local_flag(bool f) { local_flag_ = f; }
|
void local_flag(bool f) { local_flag_ = f; }
|
||||||
|
|
||||||
/* NetESignal objects may reference this object. Keep a
|
// NetESignal objects may reference this object. Keep a
|
||||||
reference count so that I keep track of them. */
|
// reference count so that I keep track of them.
|
||||||
void incr_eref();
|
void incr_eref();
|
||||||
void decr_eref();
|
void decr_eref();
|
||||||
unsigned peek_eref() const;
|
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 incr_lref();
|
||||||
void decr_lref();
|
void decr_lref();
|
||||||
unsigned peek_lref() const { return lref_count_; }
|
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;
|
unsigned get_refs() const;
|
||||||
|
|
||||||
|
|
|
||||||
7
parse.y
7
parse.y
|
|
@ -3853,8 +3853,15 @@ port_declaration
|
||||||
use_type = NetNet::IMPLICIT;
|
use_type = NetNet::IMPLICIT;
|
||||||
else
|
else
|
||||||
use_type = NetNet::IMPLICIT_REG;
|
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)) {
|
} else if (dynamic_cast<atom2_type_t*> ($4)) {
|
||||||
use_type = NetNet::IMPLICIT_REG;
|
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);
|
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ struct symbol_search_results {
|
||||||
NetEvent*eve;
|
NetEvent*eve;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
static bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
||||||
pform_name_t path, struct symbol_search_results*res,
|
pform_name_t path, struct symbol_search_results*res,
|
||||||
NetScope*start_scope = 0)
|
NetScope*start_scope = 0)
|
||||||
{
|
{
|
||||||
assert(scope);
|
assert(scope);
|
||||||
bool prefix_scope = false;
|
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;
|
"`" << path_tail.name << "' in path `" << path << "'" << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Prefix is present, but is NOT a scope. Fail!
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
118
synth2.cc
118
synth2.cc
|
|
@ -189,18 +189,18 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
unsigned sel_width = esig->vector_width();
|
unsigned sel_width = esig->vector_width();
|
||||||
assert(sel_width > 0);
|
assert(sel_width > 0);
|
||||||
|
|
||||||
unsigned mux_width = 0;
|
ivl_assert(*this, nex_map.size() == nex_out.pin_count());
|
||||||
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
|
|
||||||
mux_width += nex_out.pin(idx).nexus()->vector_width();
|
|
||||||
|
|
||||||
unsigned map_width = 0;
|
vector<unsigned> mux_width (nex_out.pin_count());
|
||||||
for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1)
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
|
||||||
map_width += nex_map[idx].wid;
|
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
|
/* Collect all the statements into a map of index to
|
||||||
statement. The guard expression it evaluated to be the
|
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;
|
max_guard_value = sel_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The mux_size is the number of inputs that are selected.
|
||||||
unsigned mux_size = max_guard_value + 1;
|
unsigned mux_size = max_guard_value + 1;
|
||||||
|
|
||||||
// If the sel_width can select more than just the explicit
|
// 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
|
/* If there is a default clause, synthesize is once and we'll
|
||||||
link it in wherever it is needed. */
|
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) {
|
if (statement_default) {
|
||||||
|
|
||||||
NetBus tmp (scope, nex_map.size());
|
statement_default->synth_async(des, scope, nex_map, default_bus);
|
||||||
statement_default->synth_async(des, scope, nex_map, tmp);
|
|
||||||
|
|
||||||
// Get the signal from the synthesized statement. This
|
// Get the signal from the synthesized statement. This
|
||||||
// will be hooked to all the default cases.
|
// will be hooked to all the default cases.
|
||||||
ivl_assert(*this, tmp.pin_count()==1);
|
ivl_assert(*this, default_bus.pin_count()==1);
|
||||||
default_sig = tmp.pin(0).nexus()->pick_any_net();
|
default_sig[0] = default_bus.pin(0).nexus()->pick_any_net();
|
||||||
ivl_assert(*this, default_sig);
|
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) {
|
for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
|
||||||
|
|
||||||
NetProc*stmt = statement_map[idx];
|
NetProc*stmt = statement_map[idx];
|
||||||
if (stmt==0 && default_sig!=0) {
|
if (stmt==0 && statement_default) {
|
||||||
connect(mux->pin_Data(idx), default_sig->pin(0));
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
if (stmt == 0) {
|
if (stmt == 0) {
|
||||||
|
|
@ -294,9 +306,24 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
NetBus tmp (scope, nex_map.size());
|
NetBus tmp (scope, nex_map.size());
|
||||||
stmt->synth_async(des, scope, nex_map, tmp);
|
stmt->synth_async(des, scope, nex_map, tmp);
|
||||||
|
|
||||||
ivl_assert(*this, tmp.pin_count()==1);
|
ivl_assert(*this, tmp.pin_count() == mux.size());
|
||||||
connect(mux->pin_Data(idx), tmp.pin(0));
|
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) {
|
||||||
ivl_assert(*this, mux->pin_Data(idx).nexus()->pick_any_net());
|
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;
|
return true;
|
||||||
|
|
@ -842,15 +869,16 @@ bool NetProcTop::synth_sync(Design*des)
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||||
|
|
||||||
|
ivl_assert(*this, nex_set[idx].nex);
|
||||||
if (debug_synth2) {
|
if (debug_synth2) {
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
<< "Top level making a "
|
<< "Top level making a "
|
||||||
<< nex_set[idx].nex->vector_width() << "-wide "
|
<< nex_set[idx].wid << "-wide "
|
||||||
<< "NetFF device." << endl;
|
<< "NetFF device." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
||||||
nex_set[idx].nex->vector_width());
|
nex_set[idx].wid);
|
||||||
des->add_node(ff2);
|
des->add_node(ff2);
|
||||||
ff2->set_line(*this);
|
ff2->set_line(*this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
functor:synth2
|
||||||
|
functor:synth
|
||||||
|
functor:syn-rules
|
||||||
|
functor:cprop
|
||||||
|
functor:nodangle
|
||||||
|
flag:DLL=sizer.tgt
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
functor:synth2
|
||||||
|
functor:synth
|
||||||
|
functor:syn-rules
|
||||||
|
functor:cprop
|
||||||
|
functor:nodangle
|
||||||
|
flag:DLL=sizer.tgt
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
assert(ivl_lval_width(lval) == wid);
|
||||||
|
|
||||||
/* If the word index is a constant, then we can write
|
/* If the word index is a constant, then we can write
|
||||||
directly to the word and save the index calculation. */
|
directly to the word and save the index
|
||||||
if (word_ix == 0) {
|
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, " %%ix/load 0, %lu, 0;\n", part_off);
|
||||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
||||||
sig, use_word, bit, wid);
|
sig, use_word, bit, wid);
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,9 @@ rm -rf $RPM_BUILD_ROOT
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.tgt
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.tgt
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/null.conf
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/null-s.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.tgt
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub.conf
|
||||||
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub-s.conf
|
%attr(-,root,root) %{_libdir}/ivl%{suff}/stub-s.conf
|
||||||
|
|
|
||||||
|
|
@ -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
|
* The vvp_wire is different from vvp_variable objects in that it
|
||||||
* exists only as a filter. The vvp_wire class tree is for
|
* exists only as a filter. The vvp_wire class tree is for
|
||||||
* implementing verilog wires/nets (as opposed to regs/variables).
|
* 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 {
|
class vvp_wire_base : public vvp_net_fil_t, public vvp_signal_value {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue