Compiler fix for pr3296466.

The compiler was handling bi-directional pass switches using the default
case for primitive gates, where the first port is treated as an output
and the remaining ports are treated as inputs. This patch adds a special
case for pass switches, so that the first two ports are treated as
bi-directional.
This commit is contained in:
Martin Whitaker 2011-06-09 08:39:03 +01:00 committed by Stephen Williams
parent 3362fbc0db
commit 4e86274ff2
2 changed files with 57 additions and 35 deletions

View File

@ -166,7 +166,8 @@ class PGBuiltin : public PGate {
unsigned calculate_array_count_(Design*, NetScope*, unsigned calculate_array_count_(Design*, NetScope*,
long&high, long&low) const; long&high, long&low) const;
unsigned calculate_output_count_(void) const; void calculate_gate_and_lval_count_(unsigned&gate_count,
unsigned&lval_count) const;
NetNode* create_gate_for_output_(Design*, NetScope*, NetNode* create_gate_for_output_(Design*, NetScope*,
perm_string gate_name, perm_string gate_name,

View File

@ -271,26 +271,35 @@ unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
return count; return count;
} }
unsigned PGBuiltin::calculate_output_count_(void) const void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count,
unsigned&lval_count) const
{ {
unsigned output_count;
switch (type()) { switch (type()) {
case BUF: case BUF:
case NOT: case NOT:
if (pin_count() > 2) output_count = pin_count() - 1; if (pin_count() > 2) gate_count = pin_count() - 1;
else output_count = 1; else gate_count = 1;
lval_count = gate_count;
break; break;
case PULLDOWN: case PULLDOWN:
case PULLUP: case PULLUP:
output_count = pin_count(); gate_count = pin_count();
lval_count = gate_count;
break;
case TRAN:
case RTRAN:
case TRANIF0:
case TRANIF1:
case RTRANIF0:
case RTRANIF1:
gate_count = 1;
lval_count = 2;
break; break;
default: default:
output_count = 1; gate_count = 1;
lval_count = 1;
break; break;
} }
return output_count;
} }
NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope,
@ -694,22 +703,28 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
unsigned array_count = calculate_array_count_(des, scope, high, low); unsigned array_count = calculate_array_count_(des, scope, high, low);
if (array_count == 0) return; if (array_count == 0) return;
unsigned output_count = calculate_output_count_(); unsigned gate_count = 0, lval_count = 0;
calculate_gate_and_lval_count_(gate_count, lval_count);
/* Now we have a gate count. Elaborate the output expressions /* Now we have a gate count. Elaborate the lval (output or
only. We do it early so that we can see if we can make bi-directional) expressions only. We do it early so that
wide gates instead of an array of gates. */ we can see if we can make wide gates instead of an array
of gates. */
vector<NetNet*>lval_sigs (output_count); vector<NetNet*>lval_sigs (lval_count);
for (unsigned idx = 0 ; idx < output_count ; idx += 1) { for (unsigned idx = 0 ; idx < lval_count ; idx += 1) {
if (pin(idx) == 0) { if (pin(idx) == 0) {
cerr << get_fileline() << ": error: Logic gate port " cerr << get_fileline() << ": error: Logic gate port "
"expressions are not optional." << endl; "expressions are not optional." << endl;
des->errors += 1; des->errors += 1;
return; return;
} }
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope); if (lval_count > gate_count)
lval_sigs[idx] = pin(idx)->elaborate_bi_net(des, scope);
else
lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope);
// The only way this should return zero is if an error // The only way this should return zero is if an error
// happened, so for that case just return. // happened, so for that case just return.
if (lval_sigs[idx] == 0) return; if (lval_sigs[idx] == 0) return;
@ -757,19 +772,19 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
des, scope); des, scope);
/* Allocate all the netlist nodes for the gates. */ /* Allocate all the netlist nodes for the gates. */
vector<NetNode*>cur (array_count*output_count); vector<NetNode*>cur (array_count*gate_count);
/* Now make as many gates as the bit count dictates. Give each /* Now make as many gates as the bit count dictates. Give each
a unique name, and set the delay times. */ a unique name, and set the delay times. */
for (unsigned idx = 0 ; idx < array_count*output_count ; idx += 1) { for (unsigned idx = 0 ; idx < array_count*gate_count ; idx += 1) {
unsigned array_idx = idx/output_count; unsigned array_idx = idx/gate_count;
unsigned output_idx = idx%output_count; unsigned gate_idx = idx%gate_count;
ostringstream tmp; ostringstream tmp;
unsigned index = (low < high)? (low+array_idx) : (low-array_idx); unsigned index = (low < high)? (low+array_idx) : (low-array_idx);
tmp << name << "<" << index << "." << output_idx << ">"; tmp << name << "<" << index << "." << gate_idx << ">";
perm_string inm = lex_strings.make(tmp.str()); perm_string inm = lex_strings.make(tmp.str());
cur[idx] = create_gate_for_output_(des, scope, inm, instance_width); cur[idx] = create_gate_for_output_(des, scope, inm, instance_width);
@ -808,7 +823,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
return; return;
} }
NetNet*sig = 0; NetNet*sig = 0;
if (idx < output_count) { if (idx < lval_count) {
sig = lval_sigs[idx]; sig = lval_sigs[idx];
} else { } else {
@ -872,11 +887,11 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
// Although in Verilog proper a multiple // Although in Verilog proper a multiple
// output gate has only 1 input, this conditional // output gate has only 1 input, this conditional
// handles gates with N outputs and M inputs. // handles gates with N outputs and M inputs.
if (idx < output_count) { if (idx < gate_count) {
connect(cur[idx]->pin(0), sig->pin(0)); connect(cur[idx]->pin(0), sig->pin(0));
} else { } else {
for (unsigned dev = 0 ; dev < output_count; dev += 1) for (unsigned dev = 0 ; dev < gate_count; dev += 1)
connect(cur[dev]->pin(idx-output_count+1), sig->pin(0)); connect(cur[dev]->pin(idx-gate_count+1), sig->pin(0));
} }
} else if (sig->vector_width() == 1) { } else if (sig->vector_width() == 1) {
@ -886,26 +901,32 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
output port, connect it to all array_count output port, connect it to all array_count
devices that have outputs at this devices that have outputs at this
position. Otherwise, idx is an input to all position. Otherwise, idx is an input to all
array_count*output_count devices. */ array_count*gate_count devices. */
if (idx < output_count) { if (idx < gate_count) {
for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) { for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) {
unsigned dev = gdx*output_count; unsigned dev = gdx*gate_count;
connect(cur[dev+idx]->pin(0), sig->pin(0)); connect(cur[dev+idx]->pin(0), sig->pin(0));
} }
} else { } else {
unsigned use_idx = idx - output_count + 1; unsigned use_idx = idx - gate_count + 1;
for (unsigned gdx = 0 ; gdx < cur.size() ; gdx += 1) for (unsigned gdx = 0 ; gdx < cur.size() ; gdx += 1)
connect(cur[gdx]->pin(use_idx), sig->pin(0)); connect(cur[gdx]->pin(use_idx), sig->pin(0));
} }
} else if (sig->vector_width() == array_count) { } else if (sig->vector_width() == array_count) {
/* Bi-directional switches should get collapsed into
a single wide instance, so should never reach this
point. Check this is so, as the following code
doesn't handle bi-directional connections. */
ivl_assert(*this, lval_count == gate_count);
/* Handle the general case that each bit of the /* Handle the general case that each bit of the
value is connected to a different instance. In value is connected to a different instance. In
this case, the output is handled slightly this case, the output is handled slightly
different from the inputs. */ different from the inputs. */
if (idx < output_count) { if (idx < gate_count) {
NetConcat*cc = new NetConcat(scope, NetConcat*cc = new NetConcat(scope,
scope->local_symbol(), scope->local_symbol(),
sig->vector_width(), sig->vector_width(),
@ -918,7 +939,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
/* Connect the outputs of the gates to the concat. */ /* Connect the outputs of the gates to the concat. */
for (unsigned gdx = 0 ; gdx < array_count; gdx += 1) { for (unsigned gdx = 0 ; gdx < array_count; gdx += 1) {
unsigned dev = gdx*output_count; unsigned dev = gdx*gate_count;
connect(cur[dev+idx]->pin(0), cc->pin(gdx+1)); connect(cur[dev+idx]->pin(0), cc->pin(gdx+1));
NetNet*tmp2 = new NetNet(scope, NetNet*tmp2 = new NetNet(scope,
@ -944,9 +965,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
tmp2->local_flag(true); tmp2->local_flag(true);
tmp2->data_type(sig->data_type()); tmp2->data_type(sig->data_type());
connect(tmp1->pin(0), tmp2->pin(0)); connect(tmp1->pin(0), tmp2->pin(0));
unsigned use_idx = idx - output_count + 1; unsigned use_idx = idx - gate_count + 1;
unsigned dev = gdx*output_count; unsigned dev = gdx*gate_count;
for (unsigned gdx2 = 0 ; gdx2 < output_count ; gdx2 += 1) for (unsigned gdx2 = 0 ; gdx2 < gate_count ; gdx2 += 1)
connect(cur[dev+gdx2]->pin(use_idx), tmp1->pin(0)); connect(cur[dev+gdx2]->pin(use_idx), tmp1->pin(0));
} }