diff --git a/cprop.cc b/cprop.cc index a37e66982..61cf8b554 100644 --- a/cprop.cc +++ b/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; diff --git a/design_dump.cc b/design_dump.cc index 9ad63954b..a5709fcc9 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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() << ")"; diff --git a/ivl_target.h b/ivl_target.h index 38056da91..76c5a5412 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -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, diff --git a/netlist.cc b/netlist.cc index cdc76e35b..c241d083a 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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) { diff --git a/netlist.h b/netlist.h index 7f502f5a3..5fef754b0 100644 --- a/netlist.h +++ b/netlist.h @@ -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_; }; diff --git a/netmisc.cc b/netmisc.cc index 978d0825a..98e90ed47 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -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); diff --git a/t-dll-api.cc b/t-dll-api.cc index bbd8490f7..7a7eebec5 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -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: diff --git a/t-dll.cc b/t-dll.cc index 2af801995..f42d8bf30 100644 --- a/t-dll.cc +++ b/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()); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 83426e0cb..a434c5beb 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -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: \n", - ivl_lpm_basename(net), width, ivl_lpm_size(net)); + fprintf(out, " LPM_CONCAT%s %s: \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; diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index b48a6fe78..2f29818e9 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -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: diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c52ca8b07..1bd1354d6 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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; diff --git a/vvp/compile.h b/vvp/compile.h index 696db0238..6685cc2d1 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -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. diff --git a/vvp/concat.cc b/vvp/concat.cc index f128bcd19..b16d6a615 100644 --- a/vvp/concat.cc +++ b/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) { diff --git a/vvp/lexor.lex b/vvp/lexor.lex index aaf9dde5f..9cfd7880f 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -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; } diff --git a/vvp/parse.y b/vvp/parse.y index 6a6de6a29..a012ddcc2 100644 --- a/vvp/parse.y +++ b/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. */ diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 70dc48ee0..b05c6acdf 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -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