PV-to-concat belnding should use a strength-aware concat.
This commit is contained in:
parent
673675fecd
commit
751587e112
5
cprop.cc
5
cprop.cc
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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() << ")";
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
2
t-dll.cc
2
t-dll.cc
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
100
vvp/concat.cc
100
vvp/concat.cc
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
14
vvp/parse.y
14
vvp/parse.y
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue