Virtualize Pins until needed
Reduces resource usage when compiling large memories.
Normal usage patterns still create large nexus arrays
in t-dll.cc:dll_target::signal().
This patch is extensively tested; it shouldn't break anything.
The existing debug "optimizer" flag is (ab)used to control
message printing when large (>1000 element) arrays are
devirtualized or nexus-ized.
The new global variable disable_virtual_pins is available
to force allocation of Pin arrays when they are declared,
but no user interface is provided.
See extensive discussion on iverilog-devel, March 4-5 2009,
title "pr2023076: large memories".
(cherry picked from commit 5bc41e1a17)
This commit is contained in:
parent
5ec7731e04
commit
b795d8c1d8
|
|
@ -89,6 +89,9 @@ extern bool debug_elab_pexpr;
|
||||||
extern bool debug_synth2;
|
extern bool debug_synth2;
|
||||||
extern bool debug_optimizer;
|
extern bool debug_optimizer;
|
||||||
|
|
||||||
|
/* Possibly temporary flag to control virtualization of pin arrays */
|
||||||
|
extern bool disable_virtual_pins;
|
||||||
|
|
||||||
/* Path to a directory useful for finding subcomponents. */
|
/* Path to a directory useful for finding subcomponents. */
|
||||||
extern const char*basedir;
|
extern const char*basedir;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,8 +208,12 @@ void NetNet::dump_net(ostream&o, unsigned ind) const
|
||||||
o << " scope=" << scope_path(scope());
|
o << " scope=" << scope_path(scope());
|
||||||
o << " #(" << rise_time() << "," << fall_time() << ","
|
o << " #(" << rise_time() << "," << fall_time() << ","
|
||||||
<< decay_time() << ") vector_width=" << vector_width()
|
<< decay_time() << ") vector_width=" << vector_width()
|
||||||
<< " pin_count=" << pin_count()
|
<< " pin_count=" << pin_count();
|
||||||
<< " init=";
|
if (pins_are_virtual()) {
|
||||||
|
o << " pins_are_virtual" << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
o << " init=";
|
||||||
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
|
for (unsigned idx = pin_count() ; idx > 0 ; idx -= 1)
|
||||||
o << pin(idx-1).get_init();
|
o << pin(idx-1).get_init();
|
||||||
|
|
||||||
|
|
|
||||||
5
main.cc
5
main.cc
|
|
@ -128,6 +128,11 @@ bool debug_elab_pexpr = false;
|
||||||
bool debug_synth2 = false;
|
bool debug_synth2 = false;
|
||||||
bool debug_optimizer = false;
|
bool debug_optimizer = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Miscellaneous flags.
|
||||||
|
*/
|
||||||
|
bool disable_virtual_pins = false; // XXX needs a way for user to set
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verbose messages enabled.
|
* Verbose messages enabled.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
42
netlist.cc
42
netlist.cc
|
|
@ -172,26 +172,45 @@ Link* find_next_output(Link*lnk)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetPins::NetPins(unsigned npins)
|
void NetPins::devirtualize_pins(void)
|
||||||
: npins_(npins)
|
|
||||||
{
|
{
|
||||||
|
if (pins_) return;
|
||||||
|
if (debug_optimizer && npins_ > 1000) cerr << "debug: devirtualizing " << npins_ << " pins." << endl;
|
||||||
|
|
||||||
pins_ = new Link[npins_];
|
pins_ = new Link[npins_];
|
||||||
pins_[0].pin_zero_ = true;
|
pins_[0].pin_zero_ = true;
|
||||||
pins_[0].node_ = this;
|
pins_[0].node_ = this;
|
||||||
|
pins_[0].dir_ = default_dir_;
|
||||||
|
pins_[0].init_ = default_init_;
|
||||||
|
|
||||||
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
|
for (unsigned idx = 1 ; idx < npins_ ; idx += 1) {
|
||||||
pins_[idx].pin_zero_ = false;
|
pins_[idx].pin_zero_ = false;
|
||||||
pins_[idx].pin_ = idx;
|
pins_[idx].pin_ = idx;
|
||||||
|
pins_[idx].dir_ = default_dir_;
|
||||||
|
pins_[idx].init_ = default_init_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NetPins::pins_are_virtual(void) const
|
||||||
|
{
|
||||||
|
return pins_ == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetPins::NetPins(unsigned npins)
|
||||||
|
: npins_(npins)
|
||||||
|
{
|
||||||
|
pins_ = NULL; // Wait until someone asks.
|
||||||
|
if (disable_virtual_pins) devirtualize_pins(); // Ask. Bummer.
|
||||||
|
}
|
||||||
|
|
||||||
NetPins::~NetPins()
|
NetPins::~NetPins()
|
||||||
{
|
{
|
||||||
delete[]pins_;
|
if (pins_) delete[]pins_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Link& NetPins::pin(unsigned idx)
|
Link& NetPins::pin(unsigned idx)
|
||||||
{
|
{
|
||||||
|
if (!pins_) devirtualize_pins();
|
||||||
if (idx >= npins_) {
|
if (idx >= npins_) {
|
||||||
cerr << get_fileline() << ": internal error: pin("<<idx<<")"
|
cerr << get_fileline() << ": internal error: pin("<<idx<<")"
|
||||||
<< " out of bounds("<<npins_<<")" << endl;
|
<< " out of bounds("<<npins_<<")" << endl;
|
||||||
|
|
@ -207,11 +226,22 @@ Link& NetPins::pin(unsigned idx)
|
||||||
|
|
||||||
const Link& NetPins::pin(unsigned idx) const
|
const Link& NetPins::pin(unsigned idx) const
|
||||||
{
|
{
|
||||||
|
assert(pins_);
|
||||||
assert(idx < npins_);
|
assert(idx < npins_);
|
||||||
assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx);
|
assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx);
|
||||||
return pins_[idx];
|
return pins_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetPins::set_default_dir(Link::DIR d)
|
||||||
|
{
|
||||||
|
default_dir_ = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetPins::set_default_init(verinum::V val)
|
||||||
|
{
|
||||||
|
default_init_ = val;
|
||||||
|
}
|
||||||
|
|
||||||
bool NetPins::is_linked(void)
|
bool NetPins::is_linked(void)
|
||||||
{
|
{
|
||||||
bool linked_flag = false;
|
bool linked_flag = false;
|
||||||
|
|
@ -479,7 +509,11 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins)
|
||||||
|
|
||||||
void NetNet::initialize_value_and_dir(verinum::V init_value, Link::DIR dir)
|
void NetNet::initialize_value_and_dir(verinum::V init_value, Link::DIR dir)
|
||||||
{
|
{
|
||||||
if (1) {
|
if (pins_are_virtual()) {
|
||||||
|
if (0) cerr << "NetNet setting Link default value and dir" << endl;
|
||||||
|
set_default_init(init_value);
|
||||||
|
set_default_dir(dir);
|
||||||
|
} else {
|
||||||
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) {
|
||||||
pin(idx).set_dir(dir);
|
pin(idx).set_dir(dir);
|
||||||
pin(idx).set_init(init_value);
|
pin(idx).set_init(init_value);
|
||||||
|
|
|
||||||
|
|
@ -193,11 +193,17 @@ class NetPins : public LineInfo {
|
||||||
const Link&pin(unsigned idx) const;
|
const Link&pin(unsigned idx) const;
|
||||||
|
|
||||||
void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const;
|
void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const;
|
||||||
|
void set_default_dir(Link::DIR d);
|
||||||
|
void set_default_init(verinum::V val);
|
||||||
bool is_linked();
|
bool is_linked();
|
||||||
|
bool pins_are_virtual(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Link*pins_;
|
Link*pins_;
|
||||||
|
void devirtualize_pins(void);
|
||||||
const unsigned npins_;
|
const unsigned npins_;
|
||||||
|
Link::DIR default_dir_;
|
||||||
|
verinum::V default_init_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* =========
|
/* =========
|
||||||
|
|
|
||||||
7
t-dll.cc
7
t-dll.cc
|
|
@ -2560,12 +2560,16 @@ void dll_target::signal(const NetNet*net)
|
||||||
obj->array_base = net->array_first();
|
obj->array_base = net->array_first();
|
||||||
obj->array_words = net->array_count();
|
obj->array_words = net->array_count();
|
||||||
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
|
obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0;
|
||||||
|
|
||||||
|
assert(obj->array_words == net->pin_count());
|
||||||
|
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: "
|
||||||
|
"t-dll creating nexus array " << obj->array_words << " long" << endl;
|
||||||
if (obj->array_words > 1)
|
if (obj->array_words > 1)
|
||||||
obj->pins = new ivl_nexus_t[obj->array_words];
|
obj->pins = new ivl_nexus_t[obj->array_words];
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
|
for (unsigned idx = 0 ; idx < obj->array_words ; idx += 1) {
|
||||||
|
|
||||||
const Nexus*nex = net->pin(idx).nexus();
|
const Nexus*nex = net->pins_are_virtual() ? 0 : net->pin(idx).nexus();
|
||||||
if (nex == 0) {
|
if (nex == 0) {
|
||||||
// Special case: This pin is connected to
|
// Special case: This pin is connected to
|
||||||
// nothing. This can happen, for example, if the
|
// nothing. This can happen, for example, if the
|
||||||
|
|
@ -2597,6 +2601,7 @@ void dll_target::signal(const NetNet*net)
|
||||||
obj->pin = tmp;
|
obj->pin = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: t-dll done with big nexus array" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dll_target::signal_paths(const NetNet*net)
|
bool dll_target::signal_paths(const NetNet*net)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue