diff --git a/Makefile.in b/Makefile.in index bb2a80393..007c8181c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -302,7 +302,7 @@ else WIN32_INSTALL = $(bindir)/iverilog-vpi$(suffix) endif -install: all installdirs $(libdir)/ivl$(suffix)/ivl@EXEEXT@ $(libdir)/ivl$(suffix)/include/constants.vams $(libdir)/ivl$(suffix)/include/disciplines.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC) +install: all installdirs $(libdir)/ivl$(suffix)/ivl@EXEEXT@ $(libdir)/ivl$(suffix)/include/constants.vams $(libdir)/ivl$(suffix)/include/disciplines.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/sv_vpi_user.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC) $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true $(bindir)/iverilog-vpi$(suffix): ./iverilog-vpi @@ -323,6 +323,9 @@ $(includedir)/ivl_target.h: $(srcdir)/ivl_target.h $(includedir)/_pli_types.h: _pli_types.h $(INSTALL_DATA) $< "$(DESTDIR)$(includedir)/_pli_types.h" +$(includedir)/sv_vpi_user.h: $(srcdir)/sv_vpi_user.h + $(INSTALL_DATA) $(srcdir)/sv_vpi_user.h "$(DESTDIR)$(includedir)/sv_vpi_user.h" + $(includedir)/vpi_user.h: $(srcdir)/vpi_user.h $(INSTALL_DATA) $(srcdir)/vpi_user.h "$(DESTDIR)$(includedir)/vpi_user.h" diff --git a/PTask.h b/PTask.h index a7fe3f7b5..949c6d20c 100644 --- a/PTask.h +++ b/PTask.h @@ -37,7 +37,9 @@ enum PTaskFuncEnum { PTF_INTEGER, PTF_REAL, PTF_REALTIME, - PTF_TIME + PTF_TIME, + PTF_ATOM2, + PTF_ATOM2_S }; struct PTaskFuncArg { diff --git a/compiler.h b/compiler.h index 962c2f531..1cd14d360 100644 --- a/compiler.h +++ b/compiler.h @@ -151,6 +151,16 @@ extern bool gn_io_range_error_flag; re-evaluated. */ extern bool gn_strict_ca_eval_flag; +/* If variables can be converted to uwires by a continuous assignment + (assuming no procedural assign, then return true. This will be true + for SystemVerilog */ +static inline bool gn_var_can_be_uwire(void) +{ + if (generation_flag == GN_VER2009) + return true; + return false; +} + /* The bits of these GN_KEYWORDS_* constants define non-intersecting sets of keywords. The compiler enables groups of keywords by setting lexor_keyword_mask with the OR of the bits for the keywords to be diff --git a/design_dump.cc b/design_dump.cc index b242abccd..2eb7c8793 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -335,9 +335,17 @@ void NetArrayDq::dump_node(ostream&o, unsigned ind) const dump_obj_attr(o, ind+4); } -void NetCastInt::dump_node(ostream&o, unsigned ind) const +void NetCastInt2::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "Cast to int. (NetCastInt): " << + o << setw(ind) << "" << "Cast to int2. (NetCastInt2): " << + name() << " width=" << width() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + +void NetCastInt4::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "Cast to int4. (NetCastInt4): " << name() << " width=" << width() << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); @@ -660,7 +668,8 @@ void NetUserFunc::dump_node(ostream&o, unsigned ind) const if (rise_time()) o << " #(" <<*rise_time() <<","<<*fall_time() - << "," <<*decay_time() << ")" << endl; + << "," <<*decay_time() << ")"; + o << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } diff --git a/elab_net.cc b/elab_net.cc index 06ef24b51..a9cdb25fa 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -414,6 +414,22 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, assert(sig); + /* If this is SystemVerilog and the variable is not yet + assigned by anything, then convert it to an unresolved + wire. */ + if (gn_var_can_be_uwire() + && (sig->type() == NetNet::REG) + && (sig->peek_eref() == 0) ) { + sig->type(NetNet::UNRESOLVED_WIRE); + } + + if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked()) { + cerr << get_fileline() << ": error: Unresolved net " << sig->name() + << " cannot have multiple drivers." << endl; + des->errors += 1; + return 0; + } + /* Don't allow registers as assign l-values. */ if (sig->type() == NetNet::REG) { cerr << get_fileline() << ": error: reg " << sig->name() diff --git a/elab_sig.cc b/elab_sig.cc index f78f4aae4..3f393b045 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -69,6 +69,15 @@ static bool get_const_argument(NetExpr*exp, verinum&res) return true; } +static bool get_const_argument(NetExpr*exp, long&res) +{ + verinum tmp; + bool rc = get_const_argument(exp, tmp); + if (rc == false) return false; + res = tmp.as_long(); + return true; +} + void Statement::elaborate_sig(Design*des, NetScope*scope) const { } @@ -472,18 +481,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const need_constant_expr = false; long mnum = 0, lnum = 0; - if (NetEConst*tmp = dynamic_cast(me)) { - mnum = tmp->value().as_long(); - } else { + if ( ! get_const_argument(me, mnum) ) { cerr << me->get_fileline() << ": error: " "Unable to evaluate constant expression " << *me << "." << endl; des->errors += 1; } - if (NetEConst*tmp = dynamic_cast(le)) { - lnum = tmp->value().as_long(); - } else { + if ( ! get_const_argument(le, lnum) ) { cerr << le->get_fileline() << ": error: " "Unable to evaluate constant expression " << *le << "." << endl; @@ -534,6 +539,48 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->data_type(IVL_VT_REAL); break; + case PTF_ATOM2: + case PTF_ATOM2_S: + ivl_assert(*this, return_type_.range != 0); + probe_expr_width(des, scope, (*return_type_.range)[0]); + probe_expr_width(des, scope, (*return_type_.range)[1]); + long use_wid; + { + need_constant_expr = true; + NetExpr*me = elab_and_eval(des, scope, + (*return_type_.range)[0], -1); + assert(me); + NetExpr*le = elab_and_eval(des, scope, + (*return_type_.range)[1], -1); + assert(le); + need_constant_expr = false; + + long mnum = 0, lnum = 0; + if ( ! get_const_argument(me, mnum) ) { + cerr << me->get_fileline() << ": error: " + "Unable to evaluate constant expression " + << *me << "." << endl; + des->errors += 1; + } + + if ( ! get_const_argument(le, lnum) ) { + cerr << le->get_fileline() << ": error: " + "Unable to evaluate constant expression " + << *le << "." << endl; + des->errors += 1; + } + + use_wid = mnum - lnum + 1; + } + ret_sig = new NetNet(scope, fname, NetNet::REG, use_wid); + ret_sig->set_line(*this); + ret_sig->set_signed(return_type_.type == PTF_ATOM2_S? true : false); + ret_sig->set_isint(true); + ret_sig->set_scalar(false); + ret_sig->port_type(NetNet::POUTPUT); + ret_sig->data_type(IVL_VT_BOOL); + break; + default: if (ports_) { cerr << get_fileline() << ": internal error: I don't know " diff --git a/elaborate.cc b/elaborate.cc index 2ba7073b0..0815917c2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -129,13 +129,17 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const need_driver_flag = true; /* Cast the right side when needed. */ - if ((lval->data_type() == IVL_VT_REAL && - rval->data_type() != IVL_VT_REAL)) { + if ((lval->data_type() == IVL_VT_REAL) && + (rval->data_type() != IVL_VT_REAL)) { rval = cast_to_real(des, scope, rval); need_driver_flag = false; - } else if ((lval->data_type() != IVL_VT_REAL && - rval->data_type() == IVL_VT_REAL)) { - rval = cast_to_int(des, scope, rval, lval->vector_width()); + } else if ((lval->data_type() == IVL_VT_BOOL) && + (rval->data_type() != IVL_VT_BOOL)) { + rval = cast_to_int2(des, scope, rval, lval->vector_width()); + need_driver_flag = false; + } else if ((lval->data_type() != IVL_VT_REAL) && + (rval->data_type() == IVL_VT_REAL)) { + rval = cast_to_int4(des, scope, rval, lval->vector_width()); need_driver_flag = false; } @@ -1370,7 +1374,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // thing needs to go to each instance when arrayed. if ((sig->data_type() == IVL_VT_REAL ) && !prts.empty() && (prts[0]->data_type() != IVL_VT_REAL )) { - sig = cast_to_int(des, scope, sig, + sig = cast_to_int4(des, scope, sig, prts_vector_width/instance.size()); } // If we have a bit/vector signal driving a real port @@ -1478,7 +1482,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const prts_vector_width = sig->vector_width(); for (unsigned pidx = 0; pidx < prts.size(); pidx += 1) { prts[pidx]->port_type(NetNet::NOT_A_PORT); - prts[pidx] = cast_to_int(des, scope, prts[pidx], + prts[pidx] = cast_to_int4(des, scope, prts[pidx], prts_vector_width / instance.size()); prts[pidx]->port_type(NetNet::POUTPUT); @@ -2261,6 +2265,12 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, rv->expr_width() >= wid); } + if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: Cast expression to int2" << endl; + rv = cast_to_int2(rv); + } + NetAssign*cur = new NetAssign(lv, rv); cur->set_line(*this); @@ -3558,6 +3568,14 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const rexp->set_width(lwid, true); rexp = pad_to_width(rexp, lwid, *this); + if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Cast force rvalue to int2" << endl; + } + rexp = cast_to_int2(rexp); + } + dev = new NetForce(lval, rexp); if (debug_elaborate) { diff --git a/emit.cc b/emit.cc index 64baab948..8cd2dcc07 100644 --- a/emit.cc +++ b/emit.cc @@ -72,9 +72,14 @@ bool NetCaseCmp::emit_node(struct target_t*tgt) const return true; } -bool NetCastInt::emit_node(struct target_t*tgt) const +bool NetCastInt2::emit_node(struct target_t*tgt) const { - return tgt->lpm_cast_int(this); + return tgt->lpm_cast_int2(this); +} + +bool NetCastInt4::emit_node(struct target_t*tgt) const +{ + return tgt->lpm_cast_int4(this); } bool NetCastReal::emit_node(struct target_t*tgt) const diff --git a/expr_synth.cc b/expr_synth.cc index c4d0c39c9..d8dc402ee 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -737,8 +737,16 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, NetExpr*root) tmp[idx] = parms_[idx]->synthesize(des, scope, root); if (tmp[idx] == 0) flag = false; /* Set the data type to the first one found. */ - if (data_type == IVL_VT_NO_TYPE) { - data_type = tmp[idx]->data_type(); + switch (data_type) { + case IVL_VT_NO_TYPE: + data_type = tmp[idx]->data_type(); + break; + case IVL_VT_BOOL: + if (tmp[idx]->data_type()==IVL_VT_LOGIC) + data_type = IVL_VT_LOGIC; + break; + default: + break; } } } @@ -985,7 +993,7 @@ NetNet* NetECast::synthesize(Design*des, NetScope*scope, NetExpr*root) switch (op()) { case 'i': - isig = cast_to_int(des, scope, isig, isig->vector_width()); + isig = cast_to_int4(des, scope, isig, isig->vector_width()); break; case 'r': isig = cast_to_real(des, scope, isig); diff --git a/ivl_target.h b/ivl_target.h index c63531697..f5c9ea421 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -272,7 +272,8 @@ typedef enum ivl_lpm_type_e { IVL_LPM_ABS = 32, IVL_LPM_ADD = 0, IVL_LPM_ARRAY = 30, - IVL_LPM_CAST_INT = 34, + IVL_LPM_CAST_INT = 34, + IVL_LPM_CAST_INT2 = 35, IVL_LPM_CAST_REAL = 33, IVL_LPM_CONCAT = 16, IVL_LPM_CMP_EEQ= 18, /* Case EQ (===) */ diff --git a/netlist.cc b/netlist.cc index 12d776f58..7ccc9289f 100644 --- a/netlist.cc +++ b/netlist.cc @@ -78,7 +78,7 @@ ostream& operator<< (ostream&o, NetNet::Type t) case NetNet::WIRE: o << "wire"; break; - case NetNet::UWIRE: + case NetNet::UNRESOLVED_WIRE: o << "uwire"; } return o; @@ -951,7 +951,14 @@ const NetScope* NetAnalogTop::scope() const return scope_; } -NetCastInt::NetCastInt(NetScope*scope__, perm_string n, unsigned width__) +NetCastInt2::NetCastInt2(NetScope*scope__, perm_string n, unsigned width__) +: NetNode(scope__, n, 2), width_(width__) +{ + pin(0).set_dir(Link::OUTPUT); + pin(1).set_dir(Link::INPUT); +} + +NetCastInt4::NetCastInt4(NetScope*scope__, perm_string n, unsigned width__) : NetNode(scope__, n, 2), width_(width__) { pin(0).set_dir(Link::OUTPUT); @@ -2359,11 +2366,13 @@ ivl_variable_type_t NetETernary::expr_type() const ivl_assert(*this, false_val_); ivl_variable_type_t tru = true_val_->expr_type(); ivl_variable_type_t fal = false_val_->expr_type(); + ivl_variable_type_t sel = cond_->expr_type(); if (tru == IVL_VT_LOGIC && fal == IVL_VT_BOOL) return IVL_VT_LOGIC; if (tru == IVL_VT_BOOL && fal == IVL_VT_LOGIC) return IVL_VT_LOGIC; - + if (sel == IVL_VT_LOGIC && (tru == IVL_VT_LOGIC || tru == IVL_VT_BOOL) && (fal == IVL_VT_LOGIC || fal == IVL_VT_BOOL)) + return IVL_VT_LOGIC; if (tru == IVL_VT_REAL && (fal == IVL_VT_LOGIC || fal == IVL_VT_BOOL)) return IVL_VT_REAL; if (fal == IVL_VT_REAL && (tru == IVL_VT_LOGIC || tru == IVL_VT_BOOL)) @@ -2455,6 +2464,9 @@ ivl_variable_type_t NetECast::expr_type() const case 'r': ret = IVL_VT_REAL; break; + case '2': + ret = IVL_VT_BOOL; + break; default: assert(0); } diff --git a/netlist.h b/netlist.h index e2c165d92..074dfc55c 100644 --- a/netlist.h +++ b/netlist.h @@ -553,7 +553,7 @@ class NetNet : public NetObj { public: enum Type { NONE, IMPLICIT, IMPLICIT_REG, INTEGER, WIRE, TRI, TRI1, SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, - UWIRE }; + UNRESOLVED_WIRE }; enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; @@ -1016,10 +1016,24 @@ class NetArrayDq : public NetNode { * Convert an IVL_VT_REAL input to a logical value with the * given width. The input is pin(1) and the output is pin(0). */ -class NetCastInt : public NetNode { +class NetCastInt4 : public NetNode { public: - NetCastInt(NetScope*s, perm_string n, unsigned width); + NetCastInt4(NetScope*s, perm_string n, unsigned width); + + unsigned width() const { return width_; } + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + unsigned width_; +}; + +class NetCastInt2 : public NetNode { + + public: + NetCastInt2(NetScope*s, perm_string n, unsigned width); unsigned width() const { return width_; } @@ -3763,6 +3777,7 @@ class NetETernary : public NetExpr { * X -- Reduction NXOR (~^ or ^~) * m -- abs(x) (i.e. "magnitude") * i -- Cast from real to integer (vector) + * 2 -- Cast from real or logic (vector) to bool (vector) * r -- Cast from integer (vector) to real */ class NetEUnary : public NetExpr { diff --git a/netmisc.cc b/netmisc.cc index 9fa1a0e95..73d1f3b58 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -116,7 +116,27 @@ NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) return tmp; } -NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid) +NetNet* cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid) +{ + if (src->data_type() == IVL_VT_BOOL) + return src; + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + tmp->data_type(IVL_VT_BOOL); + tmp->set_line(*src); + tmp->local_flag(true); + + NetCastInt2*cast = new NetCastInt2(scope, scope->local_symbol(), wid); + cast->set_line(*src); + des->add_node(cast); + + connect(cast->pin(0), tmp->pin(0)); + connect(cast->pin(1), src->pin(0)); + + return tmp; +} + +NetNet* cast_to_int4(Design*des, NetScope*scope, NetNet*src, unsigned wid) { if (src->data_type() != IVL_VT_REAL) return src; @@ -126,7 +146,7 @@ NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid) tmp->set_line(*src); tmp->local_flag(true); - NetCastInt*cast = new NetCastInt(scope, scope->local_symbol(), wid); + NetCastInt4*cast = new NetCastInt4(scope, scope->local_symbol(), wid); cast->set_line(*src); des->add_node(cast); @@ -156,6 +176,14 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) return tmp; } +NetExpr* cast_to_int2(NetExpr*expr) +{ + NetECast*cast = new NetECast('2', expr); + cast->set_line(*expr); + cast->cast_signed(expr->has_sign()); + return cast; +} + /* * Add a signed constant to an existing expression. Generate a new * NetEBAdd node that has the input expression and an expression made diff --git a/netmisc.h b/netmisc.h index 6992faea0..3d88ca8aa 100644 --- a/netmisc.h +++ b/netmisc.h @@ -74,9 +74,12 @@ extern NetNet*pad_to_width_signed(Design*des, NetNet*n, unsigned w, * Generate the nodes necessary to cast an expression (a net) to a * real value. */ -extern NetNet*cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid); +extern NetNet*cast_to_int4(Design*des, NetScope*scope, NetNet*src, unsigned wid); +extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid); extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src); +extern NetExpr*cast_to_int2(NetExpr*expr); + /* * Take the input expression and return a variation that assures that * the expression is 1-bit wide and logical. This reflects the needs diff --git a/parse.y b/parse.y index fe87b00e7..cc1e8118d 100644 --- a/parse.y +++ b/parse.y @@ -106,6 +106,16 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +{ + svector*range = new svector(2); + + (*range)[0] = new PENumber(new verinum(wid-1, integer_width)); + (*range)[1] = new PENumber(new verinum((uint64_t)0, integer_width)); + + return range; +} + static list* list_from_identifier(char*id) { list*tmp = new list; @@ -167,6 +177,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) bool flag; char letter; + int int_val; /* text items are C strings allocated by the lexor using strdup. They can be put into lists with the texts type. */ @@ -319,7 +330,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %type from_exclude %type number -%type signed_opt udp_reg_opt edge_operator automatic_opt +%type unsigned_signed_opt signed_unsigned_opt +%type udp_reg_opt edge_operator automatic_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry @@ -393,6 +405,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %type specify_simple_path specify_simple_path_decl %type specify_edge_path specify_edge_path_decl +%type atom2_type + %token K_TAND %right '?' ':' %left K_LOR @@ -494,7 +508,7 @@ attribute block_item_decl : attribute_list_opt K_reg - primitive_type_opt signed_opt range + primitive_type_opt unsigned_signed_opt range register_variable_list ';' { ivl_variable_type_t dtype = $3; if (dtype == IVL_VT_NO_TYPE) @@ -507,7 +521,7 @@ block_item_decl range. This is the rule for a scalar. */ | attribute_list_opt K_reg - primitive_type_opt signed_opt + primitive_type_opt unsigned_signed_opt register_variable_list ';' { ivl_variable_type_t dtype = $3; if (dtype == IVL_VT_NO_TYPE) @@ -516,18 +530,24 @@ block_item_decl if ($1) delete $1; } - /* Integer declarations are simpler in that they do not have all the - trappings of a general variable declaration. All of that is - implicit in the "integer" of the declaration. */ + /* Integer atom declarations are simpler in that they do not have + all the trappings of a general variable declaration. All of that + is implicit in the "integer" of the declaration. */ - | attribute_list_opt K_integer register_variable_list ';' - { pform_set_reg_integer($3); - if ($1) delete $1; - } + | attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' + { pform_set_reg_integer($4); + if ($1) delete $1; + } - | attribute_list_opt K_time register_variable_list ';' - { pform_set_reg_time($3); - } + | attribute_list_opt K_time register_variable_list ';' + { pform_set_reg_time($3); + if ($1) delete $1; + } + + | attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';' + { pform_set_integer_2atom($2, $3, $4); + if ($1) delete $1; + } /* real declarations are fairly simple as there is no range of signed flag in the declaration. Create the real as a NetNet::REG @@ -1880,7 +1900,7 @@ list_of_port_declarations port_declaration : attribute_list_opt - K_input net_type_opt primitive_type_opt signed_opt range_opt IDENTIFIER + K_input net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($7); ptmp = pform_module_port_reference(name, @2.text, @@ -1897,8 +1917,27 @@ port_declaration delete[]$7; $$ = ptmp; } + | attribute_list_opt K_input atom2_type signed_unsigned_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($5); + svector*use_range = make_range_from_width($3); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::PINPUT, + NetNet::UNRESOLVED_WIRE, IVL_VT_BOOL, + $4, use_range, $1); + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_net_type = NetNet::UNRESOLVED_WIRE; + port_declaration_context.var_type = IVL_VT_BOOL; + port_declaration_context.sign_flag = $4; + delete port_declaration_context.range; + port_declaration_context.range = use_range; + delete $1; + delete[]$5; + $$ = ptmp; + } | attribute_list_opt - K_inout net_type_opt primitive_type_opt signed_opt range_opt IDENTIFIER + K_inout net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($7); ptmp = pform_module_port_reference(name, @2.text, @@ -1916,7 +1955,7 @@ port_declaration $$ = ptmp; } | attribute_list_opt - K_output net_type_opt primitive_type_opt signed_opt range_opt IDENTIFIER + K_output net_type_opt primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($7); ptmp = pform_module_port_reference(name, @2.text, @@ -1934,7 +1973,7 @@ port_declaration $$ = ptmp; } | attribute_list_opt - K_output var_type primitive_type_opt signed_opt range_opt IDENTIFIER + K_output var_type primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($7); ptmp = pform_module_port_reference(name, @2.text, @@ -1952,7 +1991,7 @@ port_declaration $$ = ptmp; } | attribute_list_opt - K_output var_type primitive_type_opt signed_opt range_opt IDENTIFIER '=' expression + K_output var_type primitive_type_opt unsigned_signed_opt range_opt IDENTIFIER '=' expression { Module::port_t*ptmp; perm_string name = lex_strings.make($7); ptmp = pform_module_port_reference(name, @2.text, @@ -1972,6 +2011,25 @@ port_declaration delete[]$7; $$ = ptmp; } + | attribute_list_opt K_output atom2_type signed_unsigned_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($5); + svector*use_range = make_range_from_width($3); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, + NetNet::IMPLICIT_REG, IVL_VT_BOOL, + $4, use_range, $1); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.port_net_type = NetNet::IMPLICIT_REG; + port_declaration_context.var_type = IVL_VT_BOOL; + port_declaration_context.sign_flag = $4; + delete port_declaration_context.range; + port_declaration_context.range = use_range; + delete $1; + delete[]$5; + $$ = ptmp; + } ; @@ -1981,7 +2039,38 @@ net_type_opt | { $$ = NetNet::IMPLICIT; } ; -signed_opt : K_signed { $$ = true; } | {$$ = false; } ; + /* + * The signed_opt rule will return "true" if K_signed is present, + * for "false" otherwise. This rule corresponds to the declaration + * defaults for reg/bit/logic. + * + * The signed_unsigned_opt rule with match K_signed or K_unsigned + * and return true or false as appropriate. The default is + * "true". This corresponds to the declaration defaults for + * byte/shortint/int/longint. + */ +unsigned_signed_opt + : K_signed { $$ = true; } + | K_unsigned { $$ = false; } + | { $$ = false; } + ; + +signed_unsigned_opt + : K_signed { $$ = true; } + | K_unsigned { $$ = false; } + | { $$ = true; } + ; + + /* + * In some places we can take any of the 4 2-value atom-type + * names. All the context needs to know if that type is its width. + */ +atom2_type + : K_byte { $$ = 8; } + | K_shortint { $$ = 16; } + | K_int { $$ = 32; } + | K_longint { $$ = 64; } + ; /* An lpvalue is the expression that can go on the left side of a procedural assignment. This rule handles only procedural @@ -2118,7 +2207,7 @@ module_item resort to the default type LOGIC. */ : attribute_list_opt net_type - primitive_type_opt signed_opt range_opt + primitive_type_opt unsigned_signed_opt range_opt delay3_opt net_variable_list ';' @@ -2139,7 +2228,7 @@ module_item declarations. */ | attribute_list_opt net_type - primitive_type_opt signed_opt range_opt + primitive_type_opt unsigned_signed_opt range_opt delay3_opt net_decl_assigns ';' { ivl_variable_type_t dtype = $3; @@ -2158,7 +2247,7 @@ module_item gives strength to the assignment drivers. */ | attribute_list_opt net_type - primitive_type_opt signed_opt + primitive_type_opt unsigned_signed_opt drive_strength net_decl_assigns ';' { ivl_variable_type_t dtype = $3; @@ -2178,7 +2267,7 @@ module_item delete $4; } - | port_type signed_opt range_opt delay3_opt list_of_identifiers ';' + | port_type unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' { pform_set_port_type(@1, $5, $3, $2, $1); } @@ -2186,12 +2275,12 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | port_type net_type signed_opt range_opt list_of_identifiers ';' + | port_type net_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, $1, IVL_VT_NO_TYPE, 0, SR_BOTH); } - | K_output var_type signed_opt range_opt list_of_port_identifiers ';' + | K_output var_type unsigned_signed_opt range_opt list_of_port_identifiers ';' { list >::const_iterator pp; list*tmp = new list; for (pp = $5->begin(); pp != $5->end(); pp++) { @@ -2211,19 +2300,19 @@ module_item because the port declaration implies an external driver, which cannot be attached to a reg. These rules catch that error early. */ - | K_input var_type signed_opt range_opt list_of_identifiers ';' + | K_input var_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, NetNet::PINPUT, IVL_VT_NO_TYPE, 0); yyerror(@2, "error: reg variables cannot be inputs."); } - | K_inout var_type signed_opt range_opt list_of_identifiers ';' + | K_inout var_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, NetNet::PINOUT, IVL_VT_NO_TYPE, 0); yyerror(@2, "error: reg variables cannot be inouts."); } - | port_type signed_opt range_opt delay3_opt error ';' + | port_type unsigned_signed_opt range_opt delay3_opt error ';' { yyerror(@1, "error: Invalid variable list" " in port declaration."); if ($3) delete $3; @@ -2639,10 +2728,11 @@ net_decl_assigns ; primitive_type - : K_logic { $$ = IVL_VT_LOGIC; } - | K_bool { $$ = IVL_VT_BOOL; } - | K_real { $$ = IVL_VT_REAL; } - ; + : K_logic { $$ = IVL_VT_LOGIC; } + | K_bool { $$ = IVL_VT_BOOL; /* Icarus Verilog xtypes */} + | K_bit { $$ = IVL_VT_BOOL; /* IEEE1800 / IEEE1364-2009 */} + | K_real { $$ = IVL_VT_REAL; } +; primitive_type_opt : primitive_type { $$ = $1; } | { $$ = IVL_VT_NO_TYPE; } ; @@ -2657,12 +2747,12 @@ net_type | K_supply1 { $$ = NetNet::SUPPLY1; } | K_wor { $$ = NetNet::WOR; } | K_trior { $$ = NetNet::TRIOR; } - | K_wone { $$ = NetNet::UWIRE; + | K_wone { $$ = NetNet::UNRESOLVED_WIRE; cerr << @1.text << ":" << @1.first_line << ": warning: " "'wone' is deprecated, please use 'uwire' " "instead." << endl; } - | K_uwire { $$ = NetNet::UWIRE; } + | K_uwire { $$ = NetNet::UNRESOLVED_WIRE; } ; var_type @@ -3195,14 +3285,18 @@ dimensions /* This is used to express the return type of a function. */ function_range_or_type_opt - : range { $$.range = $1; $$.type = PTF_REG; } - | K_signed range { $$.range = $2; $$.type = PTF_REG_S; } - | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } - | K_real { $$.range = 0; $$.type = PTF_REAL; } - | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } - | K_time { $$.range = 0; $$.type = PTF_TIME; } - | { $$.range = 0; $$.type = PTF_REG; } - ; + : range { $$.range = $1; $$.type = PTF_REG; } + | K_signed range { $$.range = $2; $$.type = PTF_REG_S; } + | K_unsigned range { $$.range = $2; $$.type = PTF_REG; } + | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } + | K_real { $$.range = 0; $$.type = PTF_REAL; } + | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } + | K_time { $$.range = 0; $$.type = PTF_TIME; } + | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } + | { $$.range = 0; $$.type = PTF_REG; } + ; /* The register_variable rule is matched only when I am parsing variables in a "reg" definition. I therefore know that I am @@ -4039,30 +4133,27 @@ reg_opt task_port_item - : K_input reg_opt signed_opt range_opt list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINPUT, + : K_input reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(NetNet::PINPUT, IVL_VT_NO_TYPE, $3, $4, $5, @1.text, @1.first_line); - $$ = tmp; - } - | K_output reg_opt signed_opt range_opt list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, + $$ = tmp; + } + | K_output reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, IVL_VT_LOGIC, $3, $4, $5, @1.text, @1.first_line); - $$ = tmp; - } - | K_inout reg_opt signed_opt range_opt list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINOUT, + $$ = tmp; + } + | K_inout reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(NetNet::PINOUT, IVL_VT_LOGIC, $3, $4, $5, @1.text, @1.first_line); - $$ = tmp; - } + $$ = tmp; + } /* When the port is an integer, infer a signed vector of the integer shape. Generate a range ([31:0]) to make it work. */ @@ -4206,7 +4297,7 @@ task_item_list_opt task_port_decl - : K_input reg_opt signed_opt range_opt IDENTIFIER + : K_input reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4220,7 +4311,7 @@ task_port_decl $$ = tmp; } - | K_output reg_opt signed_opt range_opt IDENTIFIER + | K_output reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4233,7 +4324,7 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - | K_inout reg_opt signed_opt range_opt IDENTIFIER + | K_inout reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4315,66 +4406,48 @@ task_port_decl /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_time IDENTIFIER - { svector*range_stub = new svector(2); - PExpr*re; - re = new PENumber(new verinum((uint64_t)63, integer_width)); - (*range_stub)[0] = re; - re = new PENumber(new verinum((uint64_t)0, integer_width)); - (*range_stub)[1] = re; - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time IDENTIFIER - { svector*range_stub = new svector(2); - PExpr*re; - re = new PENumber(new verinum((uint64_t)63, integer_width)); - (*range_stub)[0] = re; - re = new PENumber(new verinum((uint64_t)0, integer_width)); - (*range_stub)[1] = re; - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time IDENTIFIER - { svector*range_stub = new svector(2); - PExpr*re; - re = new PENumber(new verinum((uint64_t)63, integer_width)); - (*range_stub)[0] = re; - re = new PENumber(new verinum((uint64_t)0, integer_width)); - (*range_stub)[1] = re; - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } + | K_input K_time IDENTIFIER + { svector*range_stub = make_range_from_width(64); + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::PINPUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } + | K_output K_time IDENTIFIER + { svector*range_stub = make_range_from_width(64); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::POUTPUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } + | K_inout K_time IDENTIFIER + { svector*range_stub = make_range_from_width(64); + port_declaration_context.port_type = NetNet::PINOUT; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::PINOUT, + IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } /* Ports can be real or realtime. */ @@ -4417,7 +4490,51 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - ; + + /* Ports can be 2-value atom types. */ + + | K_input atom2_type signed_unsigned_opt IDENTIFIER + { svector*range_stub = make_range_from_width($2); + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.var_type = IVL_VT_BOOL; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::PINPUT, + IVL_VT_BOOL, $3, + range_stub, list_from_identifier($4), + @1.text, @1.first_line); + $$ = tmp; + } + + | K_output atom2_type signed_unsigned_opt IDENTIFIER + { svector*range_stub = make_range_from_width($2); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.var_type = IVL_VT_BOOL; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::POUTPUT, + IVL_VT_BOOL, $3, + range_stub, list_from_identifier($4), + @1.text, @1.first_line); + $$ = tmp; + } + + | K_inout atom2_type signed_unsigned_opt IDENTIFIER + { svector*range_stub = make_range_from_width($2); + port_declaration_context.port_type = NetNet::PINOUT; + port_declaration_context.var_type = IVL_VT_BOOL; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(NetNet::PINOUT, + IVL_VT_BOOL, $3, + range_stub, list_from_identifier($4), + @1.text, @1.first_line); + $$ = tmp; + } +; task_port_decl_list : task_port_decl_list ',' task_port_decl diff --git a/pform.cc b/pform.cc index 5949f3091..6591622e6 100644 --- a/pform.cc +++ b/pform.cc @@ -2431,6 +2431,38 @@ void pform_set_reg_time(list*names) delete names; } +static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_string name) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur == 0) { + cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_BOOL); + pform_put_wire_in_scope(name, cur); + } else { + bool rc = cur->set_wire_type(NetNet::REG); + assert(rc); + rc = cur->set_data_type(IVL_VT_BOOL); + assert(rc); + } + + assert(cur); + + cur->set_signed(signed_flag); + cur->set_range(new PENumber(new verinum(width-1, integer_width)), + new PENumber(new verinum((uint64_t)0, integer_width)), + SR_NET, false); +} + +void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() + ; cur ++ ) { + perm_string txt = *cur; + pform_set_integer_2atom(width, signed_flag, txt); + } + delete names; +} + svector* pform_make_udp_input_ports(list*names) { svector*out = new svector(names->size()); diff --git a/pform.h b/pform.h index ea50b318a..fa5debc72 100644 --- a/pform.h +++ b/pform.h @@ -275,6 +275,8 @@ extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); +extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); + /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are diff --git a/pform_dump.cc b/pform_dump.cc index b80bb4d49..cbef88cc1 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -787,6 +787,12 @@ void PFunction::dump(ostream&out, unsigned ind) const case PTF_TIME: out << "time "; break; + case PTF_ATOM2: + out << "int unsigned "; + break; + case PTF_ATOM2_S: + cout << "int signed "; + break; } if (return_type_.range) { diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf index 315c22ba0..01009dc3d 100644 --- a/scripts/devel-stub.conf +++ b/scripts/devel-stub.conf @@ -6,7 +6,7 @@ # # NOTE: DO NOT INSTALL THIS FILE! # -generation:2005 +generation:2009 generation:specify generation:xtypes generation:verilog-ams diff --git a/sv_vpi_user.h b/sv_vpi_user.h new file mode 100644 index 000000000..d06c16689 --- /dev/null +++ b/sv_vpi_user.h @@ -0,0 +1,54 @@ +#ifndef __sv_vpi_user_H +#define __sv_vpi_user_H +/* + * Copyright (c) 2010 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vpi_user.h" + +#if defined(__MINGW32__) || defined (__CYGWIN32__) +# define DLLEXPORT __declspec(dllexport) +#else +# define DLLEXPORT +#endif + +#ifdef __cplusplus +# define EXTERN_C_START extern "C" { +# define EXTERN_C_END } +#else +# define EXTERN_C_START +# define EXTERN_C_END +#endif + +#ifndef __GNUC__ +# undef __attribute__ +# define __attribute__(x) +#endif + +EXTERN_C_START + +/********* OBJECT TYPES ***********/ +#define vpiLongIntVar 610 +#define vpiShortIntVar 611 +#define vpiIntVar 612 +#define vpiByteVar 614 +#define vpiLogicVar vpiReg + +EXTERN_C_END + +#endif diff --git a/t-dll-api.cc b/t-dll-api.cc index 285ab6e3a..81d5bf669 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -964,6 +964,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) switch (net->type) { case IVL_LPM_ABS: case IVL_LPM_CAST_INT: + case IVL_LPM_CAST_INT2: case IVL_LPM_CAST_REAL: assert(idx == 0); return net->u_.arith.a; @@ -1108,6 +1109,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net) case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_CAST_INT: + case IVL_LPM_CAST_INT2: case IVL_LPM_CAST_REAL: case IVL_LPM_CMP_GE: case IVL_LPM_CMP_GT: @@ -1259,6 +1261,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_MULT: case IVL_LPM_POW: case IVL_LPM_SUB: + case IVL_LPM_CAST_INT2: return net->u_.arith.signed_flag; case IVL_LPM_RE_AND: case IVL_LPM_RE_OR: diff --git a/t-dll.cc b/t-dll.cc index 1db7a6fc9..2eff9604e 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1488,16 +1488,17 @@ void dll_target::lpm_clshift(const NetCLShift*net) scope_add_lpm(obj->scope, obj); } -bool dll_target::lpm_cast_int(const NetCastInt*net) +bool dll_target::lpm_arith1_(ivl_lpm_type_t lpm_type, unsigned width, bool signed_flag, const NetNode*net) { ivl_lpm_t obj = new struct ivl_lpm_s; - obj->type = IVL_LPM_CAST_INT; - obj->name = net->name(); // NetCastInt names are permallocated + obj->type = lpm_type; + obj->name = net->name(); // NetCastInt2 names are permallocated assert(net->scope()); obj->scope = find_scope(des_, net->scope()); assert(obj->scope); - obj->width = net->width(); + obj->width = width; + obj->u_.arith.signed_flag = signed_flag? 1 : 0; const Nexus*nex; @@ -1520,37 +1521,19 @@ bool dll_target::lpm_cast_int(const NetCastInt*net) return true; } +bool dll_target::lpm_cast_int2(const NetCastInt2*net) +{ + return lpm_arith1_(IVL_LPM_CAST_INT2, net->width(), true, net); +} + +bool dll_target::lpm_cast_int4(const NetCastInt4*net) +{ + return lpm_arith1_(IVL_LPM_CAST_INT, net->width(), true, net); +} + bool dll_target::lpm_cast_real(const NetCastReal*net) { - ivl_lpm_t obj = new struct ivl_lpm_s; - obj->type = IVL_LPM_CAST_REAL; - obj->name = net->name(); // NetCastReal names are permallocated - assert(net->scope()); - obj->scope = find_scope(des_, net->scope()); - assert(obj->scope); - - obj->width = 0; - obj->u_.arith.signed_flag = net->signed_flag()? 1 : 0; - - const Nexus*nex; - - nex = net->pin(0).nexus(); - assert(nex->t_cookie()); - - obj->u_.arith.q = nex->t_cookie(); - - nex = net->pin(1).nexus(); - assert(nex->t_cookie()); - obj->u_.arith.a = nex->t_cookie(); - - nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); - nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); - - make_lpm_delays_(obj, net); - - scope_add_lpm(obj->scope, obj); - - return true; + return lpm_arith1_(IVL_LPM_CAST_REAL, 0, net->signed_flag(), net); } /* @@ -2389,7 +2372,7 @@ void dll_target::signal(const NetNet*net) /* We will convert this to a TRI after we check that there is only one driver. */ - case NetNet::UWIRE: + case NetNet::UNRESOLVED_WIRE: obj->type_ = IVL_SIT_UWIRE; break; diff --git a/t-dll.h b/t-dll.h index 8967c59f0..53bc7ec89 100644 --- a/t-dll.h +++ b/t-dll.h @@ -67,7 +67,8 @@ struct dll_target : public target_t, public expr_scan_t { void lpm_abs(const NetAbs*); void lpm_add_sub(const NetAddSub*); bool lpm_array_dq(const NetArrayDq*); - bool lpm_cast_int(const NetCastInt*); + bool lpm_cast_int2(const NetCastInt2*); + bool lpm_cast_int4(const NetCastInt4*); bool lpm_cast_real(const NetCastReal*); void lpm_clshift(const NetCLShift*); void lpm_compare(const NetCompare*); @@ -175,6 +176,8 @@ struct dll_target : public target_t, public expr_scan_t { ivl_event_t make_lpm_trigger(const NetEvWait*ev); + bool lpm_arith1_(ivl_lpm_type_t lpm_type, unsigned wid, bool signed_flag, const NetNode*net); + static ivl_expr_t expr_from_value_(const verinum&that); }; diff --git a/target.cc b/target.cc index 8e5147c0f..a3581c878 100644 --- a/target.cc +++ b/target.cc @@ -114,10 +114,17 @@ bool target_t::lpm_array_dq(const NetArrayDq*) return false; } -bool target_t::lpm_cast_int(const NetCastInt*) +bool target_t::lpm_cast_int2(const NetCastInt2*) { cerr << "target (" << typeid(*this).name() << "): " - "Unhandled NetCastInt." << endl; + "Unhandled NetCastInt2." << endl; + return false; +} + +bool target_t::lpm_cast_int4(const NetCastInt4*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetCastInt4." << endl; return false; } diff --git a/target.h b/target.h index b957f1693..1f97f3dd4 100644 --- a/target.h +++ b/target.h @@ -75,7 +75,8 @@ struct target_t { virtual void lpm_add_sub(const NetAddSub*); virtual bool lpm_array_dq(const NetArrayDq*); virtual void lpm_clshift(const NetCLShift*); - virtual bool lpm_cast_int(const NetCastInt*); + virtual bool lpm_cast_int2(const NetCastInt2*); + virtual bool lpm_cast_int4(const NetCastInt4*); virtual bool lpm_cast_real(const NetCastReal*); virtual void lpm_compare(const NetCompare*); virtual void lpm_divide(const NetDivide*); diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index c5481aec3..4eb6ec311 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -468,6 +468,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_ARRAY: + case IVL_LPM_CAST_INT2: case IVL_LPM_CAST_INT: case IVL_LPM_CAST_REAL: case IVL_LPM_CONCAT: diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 8e0f8fcfa..554462193 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -55,6 +55,12 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr) clr_word(res); } +static void function_argument_bool(ivl_signal_t port, ivl_expr_t expr) +{ + /* For now, treat bit2 variables as bit4 variables. */ + function_argument_logic(port, expr); +} + static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr) { ivl_variable_type_t dtype = ivl_signal_data_type(port); @@ -65,6 +71,9 @@ static void draw_function_argument(ivl_signal_t port, ivl_expr_t expr) case IVL_VT_REAL: function_argument_real(port, expr); break; + case IVL_VT_BOOL: + function_argument_bool(port, expr); + break; default: fprintf(stderr, "XXXX function argument %s type=%d?!\n", ivl_signal_basename(port), dtype); diff --git a/tgt-vvp/eval_bool.c b/tgt-vvp/eval_bool.c index c7cfee6bb..5a8c1ce6f 100644 --- a/tgt-vvp/eval_bool.c +++ b/tgt-vvp/eval_bool.c @@ -47,10 +47,14 @@ static int eval_bool64_logic(ivl_expr_t expr) { int res; struct vector_info tmp; + const char*s_flag = ""; tmp = draw_eval_expr(expr, STUFF_OK_XZ); res = allocate_word(); - fprintf(vvp_out, " %%ix/get %d, %u, %u;\n", res, tmp.base, tmp.wid); + if (ivl_expr_signed(expr)) + s_flag = "/s"; + + fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res, tmp.base, tmp.wid); clr_vector(tmp); return res; diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 67c6cac10..cb2ff47be 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -3126,6 +3126,21 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) local_count += 1; break; + case '2': /* Cast logic to bool */ + assert(ivl_expr_value(sub) == IVL_VT_LOGIC); + res = draw_eval_expr_wid(sub, wid, 0); + + /* Handle special case that value is 0 or 1. */ + if (res.base == 0 || res.base == 1) + break; + if (res.base == 2 || res.base == 2) { + res.base = 0; + break; + } + + fprintf(vvp_out, " %%cast2 %d, %d, %u;\n", res.base, res.base, res.wid); + break; + case 'i': /* Cast a real value to an integer. */ assert(ivl_expr_value(sub) == IVL_VT_REAL); word = draw_eval_real(sub); diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 64137c2fe..106d42d4f 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -427,6 +427,12 @@ static void draw_reg_in_scope(ivl_signal_t sig) const char*local_flag = ivl_signal_local(sig)? "*" : ""; switch (ivl_signal_data_type(sig)) { + case IVL_VT_BOOL: + if (ivl_signal_signed(sig)) + datatype_flag = "/2s"; + else + datatype_flag = "/2u"; + break; case IVL_VT_REAL: datatype_flag = "/real"; break; @@ -470,6 +476,12 @@ static void draw_net_in_scope(ivl_signal_t sig) unsigned iword; switch (ivl_signal_data_type(sig)) { + case IVL_VT_BOOL: + if (ivl_signal_signed(sig)) + datatype_flag = "/2s"; + else + datatype_flag = "/2u"; + break; case IVL_VT_REAL: datatype_flag = "/real"; break; @@ -1209,6 +1221,19 @@ static void draw_lpm_abs(ivl_lpm_t net) net, dly, src_table[0]); } +static void draw_lpm_cast_int2(ivl_lpm_t net) +{ + const char*src_table[1]; + const char*dly; + + draw_lpm_data_inputs(net, 0, 1, src_table); + + dly = draw_lpm_output_delay(net, IVL_VT_BOOL); + + fprintf(vvp_out, "L_%p%s .cast/2 %u, %s;\n", + net, dly, ivl_lpm_width(net), src_table[0]); +} + static void draw_lpm_cast_int(ivl_lpm_t net) { const char*src_table[1]; @@ -1829,6 +1854,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) draw_lpm_cast_int(net); return; + case IVL_LPM_CAST_INT2: + draw_lpm_cast_int2(net); + return; + case IVL_LPM_CAST_REAL: draw_lpm_cast_real(net); return; diff --git a/vpi/sys_display.c b/vpi/sys_display.c index b59a1d338..386338b7f 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1048,6 +1048,10 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name, case vpiNet: case vpiReg: case vpiIntegerVar: + case vpiByteVar: + case vpiShortIntVar: + case vpiIntVar: + case vpiLongIntVar: case vpiTimeVar: case vpiRealVar: case vpiSysFuncCall: diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index 094416f28..f384cdef7 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -20,7 +20,7 @@ */ #include "vpi_config.h" -#include "vpi_user.h" +#include "sv_vpi_user.h" /* * Context structure for PRNG in mt19937int.c diff --git a/vvp/README.txt b/vvp/README.txt index 8e43030b5..1819598f1 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -278,8 +278,10 @@ A variable is a bit vector that can be written by behavioral code (so has no structural input) and propagates its output to a functor. The general syntax of a variable is: -