PV-to-concat belnding should use a strength-aware concat.

This commit is contained in:
Stephen Williams 2013-02-02 10:44:16 -08:00
parent 673675fecd
commit 751587e112
16 changed files with 180 additions and 44 deletions

View File

@ -80,6 +80,11 @@ void cprop_functor::lpm_compare_eq_(Design*, NetCompare*)
void cprop_functor::lpm_concat(Design*des, NetConcat*obj)
{
// Sorry, I don't know how to constant-propagate through
// transparent concatenations.
if (obj->transparent())
return;
verinum result (verinum::Vz, obj->width());
unsigned off = 0;

View File

@ -445,8 +445,12 @@ void NetCompare::dump_node(ostream&o, unsigned ind) const
void NetConcat::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetConcat: "
<< name();
if (transparent_)
o << setw(ind) << "" << "NetConcat8: ";
else
o << setw(ind) << "" << "NetConcat: ";
o << name();
if (rise_time())
o << " #(" << *rise_time()
<< "," << *fall_time() << "," << *decay_time() << ")";

View File

@ -295,6 +295,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_CAST_INT2 = 35,
IVL_LPM_CAST_REAL = 33,
IVL_LPM_CONCAT = 16,
IVL_LPM_CONCATZ = 36, /* Transparent concat */
IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */
IVL_LPM_CMP_EQ = 10,
IVL_LPM_CMP_GE = 1,

View File

@ -1121,8 +1121,8 @@ NetCastReal::NetCastReal(NetScope*scope__, perm_string n, bool signed_flag__)
pin(1).set_dir(Link::INPUT);
}
NetConcat::NetConcat(NetScope*scope__, perm_string n, unsigned wid, unsigned cnt)
: NetNode(scope__, n, cnt+1), width_(wid)
NetConcat::NetConcat(NetScope*scope__, perm_string n, unsigned wid, unsigned cnt, bool trans_flag)
: NetNode(scope__, n, cnt+1), width_(wid), transparent_(trans_flag)
{
pin(0).set_dir(Link::OUTPUT);
for (unsigned idx = 1 ; idx < cnt+1 ; idx += 1) {

View File

@ -1344,10 +1344,16 @@ class NetCompare : public NetNode {
class NetConcat : public NetNode {
public:
NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt);
NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt,
bool transparent_flag = false);
~NetConcat();
unsigned width() const;
// This is true if the concatenation is a transparent
// concatenation, meaning strengths are passed through as
// is. In this case, the output strengths of this node will be
// ignored.
bool transparent() const { return transparent_; }
void dump_node(ostream&, unsigned ind) const;
bool emit_node(struct target_t*) const;
@ -1355,6 +1361,7 @@ class NetConcat : public NetNode {
private:
unsigned width_;
bool transparent_;
};

View File

@ -1138,7 +1138,8 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig)
}
NetConcat*cat = new NetConcat(scope, scope->local_symbol(),
ps_map.size(), device_count);
ps_map.size(), device_count,
true);
des->add_node(cat);
cat->set_line(*sig);

View File

@ -1176,6 +1176,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
return net->u_.ff.d.pin;
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
assert(idx < net->u_.concat.inputs);
return net->u_.concat.pins[idx+1];
@ -1312,6 +1313,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net)
return net->u_.ufunc.pins[0];
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
return net->u_.concat.pins[0];
case IVL_LPM_PART_VP:
@ -1394,6 +1396,7 @@ extern "C" unsigned ivl_lpm_selects(ivl_lpm_t net)
case IVL_LPM_ARRAY:
return net->u_.array.swid;
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
cerr << "error: ivl_lpm_selects() is no longer supported for "
"IVL_LPM_CONCAT, use ivl_lpm_size() instead." << endl;
default:
@ -1443,6 +1446,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
case IVL_LPM_UFUNC:
return 0;
case IVL_LPM_CONCAT: // Concatenations are always unsigned
case IVL_LPM_CONCATZ: // Concatenations are always unsigned
return 0;
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
@ -1469,6 +1473,7 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net)
case IVL_LPM_REPEAT:
return net->u_.repeat.count;
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
return net->u_.concat.inputs;
case IVL_LPM_ABS:
case IVL_LPM_CAST_INT:

View File

@ -1989,7 +1989,7 @@ void dll_target::lpm_pow(const NetPow*net)
bool dll_target::concat(const NetConcat*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_CONCAT;
obj->type = net->transparent()? IVL_LPM_CONCATZ : IVL_LPM_CONCAT;
obj->name = net->name(); // NetConcat names are permallocated
assert(net->scope());
obj->scope = find_scope(des_, net->scope());

View File

@ -440,7 +440,7 @@ static void show_lpm_cmp_ne(ivl_lpm_t net)
check_cmp_widths(net);
}
/* IVL_LPM_CONCAT
/* IVL_LPM_CONCAT, IVL_LPM_CONCATZ
* The concat device takes N inputs (N=ivl_lpm_size) and generates
* a single output. The total output is known from the ivl_lpm_width
* function. The widths of all the inputs are inferred from the widths
@ -453,9 +453,10 @@ static void show_lpm_concat(ivl_lpm_t net)
unsigned width_sum = 0;
unsigned width = ivl_lpm_width(net);
const char*z = ivl_lpm_type(net)==IVL_LPM_CONCATZ? "Z" : "";
fprintf(out, " LPM_CONCAT %s: <width=%u, inputs=%u>\n",
ivl_lpm_basename(net), width, ivl_lpm_size(net));
fprintf(out, " LPM_CONCAT%s %s: <width=%u, inputs=%u>\n",
z, ivl_lpm_basename(net), width, ivl_lpm_size(net));
fprintf(out, " O: %p\n", ivl_lpm_q(net));
for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) {
@ -954,6 +955,7 @@ static void show_lpm(ivl_lpm_t net)
break;
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
show_lpm_concat(net);
break;

View File

@ -477,6 +477,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_CAST_INT:
case IVL_LPM_CAST_REAL:
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
case IVL_LPM_CMP_EEQ:
case IVL_LPM_CMP_EQ:
case IVL_LPM_CMP_GE:

View File

@ -417,31 +417,6 @@ const char*draw_input_from_net(ivl_nexus_t nex)
}
/* Create flag string for port nature */
static const char *port_type_str( ivl_signal_port_t ptype )
{
switch( ptype )
{
case IVL_SIP_INPUT :
return "INPUT";
case IVL_SIP_OUTPUT :
return "OUTPUT";
case IVL_SIP_INOUT :
return "INOUT";
case IVL_SIP_NONE :
default :
return "NOT_PORT";
}
}
/* Create flag string for et nature" port nature / localness */
static const char *port_nature_flag_str( ivl_signal_t sig )
{
return port_type_str( ivl_signal_port(sig) );
}
static const char *local_flag_str( ivl_signal_t sig )
{
return ivl_signal_local(sig)? "*" : "";
@ -1606,13 +1581,14 @@ static void draw_lpm_concat(ivl_lpm_t net)
const char*src_table[4];
unsigned icnt = ivl_lpm_size(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
const char*z = ivl_lpm_type(net)==IVL_LPM_CONCATZ? "8" : "";
if (icnt <= 4) {
/* This is the easiest case. There are 4 or fewer input
vectors, so the entire IVL_LPM_CONCAT can be
implemented with a single .concat node. */
draw_lpm_data_inputs(net, 0, icnt, src_table);
fprintf(vvp_out, "L_%p%s .concat ", net, dly);
fprintf(vvp_out, "L_%p%s .concat%s ", net, dly, z);
lpm_concat_inputs(net, 0, icnt, src_table);
} else {
@ -1640,7 +1616,7 @@ static void draw_lpm_concat(ivl_lpm_t net)
trans = icnt - idx;
draw_lpm_data_inputs(net, idx, trans, src_table);
fprintf(vvp_out, "LS_%p_0_%u .concat ", net, idx);
fprintf(vvp_out, "LS_%p_0_%u .concat%s ", net, idx, z);
wid = lpm_concat_inputs(net, idx, trans, src_table);
tree[idx/4].base = idx;
@ -1669,8 +1645,8 @@ static void draw_lpm_concat(ivl_lpm_t net)
if ((idx+trans) > icnt)
trans = icnt - idx;
fprintf(vvp_out, "LS_%p_%u_%u .concat [",
net, depth, idx);
fprintf(vvp_out, "LS_%p_%u_%u .concat%s [",
net, depth, idx, z);
for (tdx = 0 ; tdx < trans ; tdx += 1) {
fprintf(vvp_out, " %u", tree[idx+tdx].wid);
@ -1698,7 +1674,7 @@ static void draw_lpm_concat(ivl_lpm_t net)
/* Finally, draw the root node that takes in the final
row of tree nodes and generates a single output. */
fprintf(vvp_out, "L_%p%s .concat [", net, dly);
fprintf(vvp_out, "L_%p%s .concat%s [", net, dly, z);
for (idx = 0 ; idx < icnt ; idx += 1)
fprintf(vvp_out, " %u", tree[idx].wid);
for ( ; idx < 4 ; idx += 1)
@ -2074,6 +2050,7 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
return;
case IVL_LPM_CONCAT:
case IVL_LPM_CONCATZ:
draw_lpm_concat(net);
return;

View File

@ -120,6 +120,10 @@ extern void compile_concat(char*label, unsigned w0, unsigned w1,
unsigned w2, unsigned w3,
unsigned argc, struct symb_s*argv);
extern void compile_concat8(char*label, unsigned w0, unsigned w1,
unsigned w2, unsigned w3,
unsigned argc, struct symb_s*argv);
/*
* Arrange for the system task/function call to have its compiletf
* function called.

View File

@ -110,6 +110,106 @@ void compile_concat(char*label, unsigned w0, unsigned w1,
free(argv);
}
vvp_fun_concat8::vvp_fun_concat8(unsigned w0, unsigned w1,
unsigned w2, unsigned w3)
: val_(w0+w1+w2+w3)
{
wid_[0] = w0;
wid_[1] = w1;
wid_[2] = w2;
wid_[3] = w3;
for (unsigned idx = 0 ; idx < val_.size() ; idx += 1)
val_.set_bit(idx, vvp_scalar_t(BIT4_Z, 0, 0));
}
vvp_fun_concat8::~vvp_fun_concat8()
{
}
void vvp_fun_concat8::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t)
{
vvp_vector8_t bit8 (bit, 6, 6);
recv_vec8(port, bit8);
}
void vvp_fun_concat8::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
vvp_vector8_t bit8 (bit, 6, 6);
recv_vec8_pv(port, bit8, base, wid, vwid);
}
void vvp_fun_concat8::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
unsigned pdx = port.port();
if (bit.size() != wid_[pdx]) {
cerr << "internal error: port " << pdx
<< " expects wid=" << wid_[pdx]
<< ", got wid=" << bit.size() << endl;
assert(0);
}
unsigned off = 0;
for (unsigned idx = 0 ; idx < pdx ; idx += 1)
off += wid_[idx];
for (unsigned idx = 0 ; idx < wid_[pdx] ; idx += 1) {
val_.set_bit(off+idx, bit.value(idx));
}
port.ptr()->send_vec8(val_);
}
void vvp_fun_concat8::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
assert(bit.size() == wid);
unsigned pdx = port.port();
if (vwid != wid_[pdx]) {
cerr << "internal error: port " << pdx
<< " expects wid=" << wid_[pdx]
<< ", got wid=" << vwid << endl;
assert(0);
}
unsigned off = 0;
for (unsigned idx = 0 ; idx < pdx ; idx += 1)
off += wid_[idx];
unsigned limit = off + wid_[pdx];
off += base;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (off+idx >= limit) break;
val_.set_bit(off+idx, bit.value(idx));
}
port.ptr()->send_vec8(val_);
}
void compile_concat8(char*label, unsigned w0, unsigned w1,
unsigned w2, unsigned w3,
unsigned argc, struct symb_s*argv)
{
vvp_fun_concat8*fun = new vvp_fun_concat8(w0, w1, w2, w3);
vvp_net_t*net = new vvp_net_t;
net->fun = fun;
define_functor_symbol(label, net);
free(label);
inputs_connect(net, argc, argv);
free(argv);
}
vvp_fun_repeat::vvp_fun_repeat(unsigned width, unsigned repeat)
: wid_(width), rep_(repeat)
{

View File

@ -146,6 +146,7 @@ static char* strdupnew(char const *str)
".cmp/gt.r" { return K_CMP_GT_R; }
".cmp/gt.s" { return K_CMP_GT_S; }
".concat" { return K_CONCAT; }
".concat8" { return K_CONCAT8; }
".delay" { return K_DELAY; }
".dff" { return K_DFF; }
".enum2" { return K_ENUM2; }

View File

@ -82,7 +82,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_CLASS
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
%token K_CONCAT K_DEBUG K_DELAY K_DFF
%token K_CONCAT K_CONCAT8 K_DEBUG K_DELAY K_DFF
%token K_ENUM2 K_ENUM2_S K_ENUM4 K_ENUM4_S K_EVENT K_EVENT_OR
%token K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND K_MODPATH
%token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U K_NET8 K_NET8_S
@ -282,9 +282,15 @@ statement
| T_LABEL K_PART_V_S T_SYMBOL ',' T_SYMBOL ',' T_NUMBER ';'
{ compile_part_select_var($1, $3, $5, $7, true); }
| T_LABEL K_CONCAT '[' T_NUMBER T_NUMBER T_NUMBER T_NUMBER ']' ','
symbols ';'
{ compile_concat($1, $4, $5, $6, $7, $10.cnt, $10.vect); }
/* Concatenations */
| T_LABEL K_CONCAT '[' T_NUMBER T_NUMBER T_NUMBER T_NUMBER ']' ','
symbols ';'
{ compile_concat($1, $4, $5, $6, $7, $10.cnt, $10.vect); }
| T_LABEL K_CONCAT8 '[' T_NUMBER T_NUMBER T_NUMBER T_NUMBER ']' ','
symbols ';'
{ compile_concat8($1, $4, $5, $6, $7, $10.cnt, $10.vect); }
/* The ABS statement is a special arithmetic node that takes 1
input. Re-use the symbols rule. */

View File

@ -1334,6 +1334,28 @@ class vvp_fun_concat : public vvp_net_fun_t {
vvp_vector4_t val_;
};
class vvp_fun_concat8 : public vvp_net_fun_t {
public:
vvp_fun_concat8(unsigned w0, unsigned w1,
unsigned w2, unsigned w3);
~vvp_fun_concat8();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
void recv_vec8_pv(vvp_net_ptr_t p, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
private:
unsigned wid_[4];
vvp_vector8_t val_;
};
/*
* The vvp_fun_force class objects are net functors that use their input
* to force the associated filter. They do not actually have an