diff --git a/.gitignore b/.gitignore index 4547e8487..dafd965e3 100644 --- a/.gitignore +++ b/.gitignore @@ -35,16 +35,19 @@ Makefile /_pli_types.h config.h /tgt-pcb/pcb_config.h -/tgt-pcb/fp.cc -/tgt-pcb/fp.h -/tgt-pcb/fp.output -/tgt-pcb/fp_lex.cc /tgt-vvp/vvp_config.h /tgt-vhdl/vhdl_config.h +/vhdlpp/vhdlpp_config.h /vpi/vpi_config.h stamp-*-h -/version.h /version_tag.h +/version_base.h + +/driver-vpi/iverilog-vpi.man +/driver-vpi/res.rc +/driver/iverilog.man +/vvp/libvvp.pc +/vvp/vvp.man # Directories autom4te.cache @@ -56,8 +59,6 @@ dep *.vpi /cadpli/cadpli.vpl -/tgt-blif/Makefile - # lex, yacc and gperf output /driver/cflexor.c /driver/cfparse.c @@ -66,14 +67,6 @@ dep /ivlpp/lexor.c -/vhdlpp/lexor.cc -/vhdlpp/lexor_keyword.cc -/vhdlpp/parse.cc -/vhdlpp/parse.h -/vhdlpp/parse.output -/vhdlpp/vhdlpp_config.h -/vhdlpp/vhdlpp - /lexor.cc /lexor_keyword.cc /parse.cc @@ -82,6 +75,17 @@ dep /syn-rules.cc /syn-rules.output +/tgt-pcb/fp.cc +/tgt-pcb/fp.h +/tgt-pcb/fp.output +/tgt-pcb/fp_lex.cc + +/vhdlpp/lexor.cc +/vhdlpp/lexor_keyword.cc +/vhdlpp/parse.cc +/vhdlpp/parse.h +/vhdlpp/parse.output + /vpi/sdf_lexor.c /vpi/sdf_parse.c /vpi/sdf_parse.h @@ -101,17 +105,13 @@ dep # Program created files /vvp/tables.cc -/iverilog-vpi.man -/driver-vpi/res.rc -/driver/iverilog.man -/vvp/vvp.man - # The executables. *.exe /driver/iverilog -/iverilog-vpi +/driver-vpi/iverilog-vpi /ivl /ivlpp/ivlpp +/vhdlpp/vhdlpp /vvp/vvp /ivl.exp @@ -119,3 +119,4 @@ dep # Check output /check.vvp +/driver/top.vvp diff --git a/Documentation/developer/guide/vvp/opcodes.rst b/Documentation/developer/guide/vvp/opcodes.rst index dd7e6cffc..3303e8b50 100644 --- a/Documentation/developer/guide/vvp/opcodes.rst +++ b/Documentation/developer/guide/vvp/opcodes.rst @@ -812,6 +812,10 @@ result is pushed back on the vec4 stack. This opcode multiplies two real words together. +* %neg/wr + +This opcode negates the real value on top of the real stack. + * %nand Perform the bitwise NAND of two vec4 vectors, and push the result. Each diff --git a/Makefile.in b/Makefile.in index 2503db9c7..f97cd0743 100644 --- a/Makefile.in +++ b/Makefile.in @@ -85,6 +85,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ LEX = @LEX@ YACC = @YACC@ +YACC_CONFLICT_FLAGS = -Werror=conflicts-sr -Werror=conflicts-rr MAN = @MAN@ PS2PDF = @PS2PDF@ GROFF = @GROFF@ @@ -241,10 +242,10 @@ parse.o: parse.cc # Use pattern rules to avoid parallel build issues (see pr3462585) parse%cc parse%h: $(srcdir)/parse%y - $(YACC) --verbose -t -p VL --defines=parse.h -o parse.cc $< + $(YACC) --verbose $(YACC_CONFLICT_FLAGS) -t -p VL --defines=parse.h -o parse.cc $< syn-rules.cc: $(srcdir)/syn-rules.y - $(YACC) --verbose -t -p syn_ -o $@ $< + $(YACC) --verbose $(YACC_CONFLICT_FLAGS) -t -p syn_ -o $@ $< lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -t $< > $@ diff --git a/PExpr.cc b/PExpr.cc index 8a32b0506..b2151f970 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -108,6 +108,16 @@ PEAssignPattern::~PEAssignPattern() { } +bool PEAssignPattern::has_aa_term(Design*des, NetScope*scope) const +{ + bool flag = false; + for (const auto *parm : parms_) { + if (parm) + flag = parm->has_aa_term(des, scope) || flag; + } + return flag; +} + PEBinary::PEBinary(char op, PExpr*l, PExpr*r) : op_(op), left_(l), right_(r) { @@ -261,26 +271,47 @@ PECallFunction::PECallFunction(perm_string n, const list &parms) { } +PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method, + const vector &parms) +: path_(method), parms_(parms), chain_prefix_(chain_prefix), is_overridden_(false) +{ +} + +PECallFunction::PECallFunction(PExpr* chain_prefix, const pform_name_t &method, + const list &parms) +: path_(method), parms_(parms.begin(), parms.end()), + chain_prefix_(chain_prefix), is_overridden_(false) +{ +} + PECallFunction::~PECallFunction() { + delete chain_prefix_; } void PECallFunction::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) { + if (chain_prefix_) { + chain_prefix_->declare_implicit_nets(scope, type); + } for (const auto &parm : parms_) { - if (parm.parm) + if (parm.parm) { parm.parm->declare_implicit_nets(scope, type); + } } } bool PECallFunction::has_aa_term(Design*des, NetScope*scope) const { - bool flag = false; + if (chain_prefix_ && chain_prefix_->has_aa_term(des, scope)) { + return true; + } for (const auto &parm : parms_) { - if (parm.parm) - flag |= parm.parm->has_aa_term(des, scope); + if (parm.parm && parm.parm->has_aa_term(des, scope)) { + return true; + } } - return flag; + return false; } PEConcat::PEConcat(const list&p, PExpr*r) diff --git a/PExpr.h b/PExpr.h index 290b0f093..af31e0932 100644 --- a/PExpr.h +++ b/PExpr.h @@ -37,6 +37,7 @@ class NetExpr; class NetScope; class PPackage; struct symbol_search_results; +class netclass_t; /* * The PExpr class hierarchy supports the description of @@ -208,6 +209,8 @@ class PEAssignPattern : public PExpr { void dump(std::ostream&) const override; + virtual bool has_aa_term(Design*des, NetScope*scope) const override; + virtual unsigned test_width(Design*des, NetScope*scope, width_mode_t&mode) override; virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, ivl_type_t type, unsigned flags) const override; @@ -488,18 +491,12 @@ class PEIdent : public PExpr { const NetScope*found_in, ivl_type_t par_type, unsigned expr_wid) const; - NetExpr*elaborate_expr_param_idx_up_(Design*des, - NetScope*scope, - const NetExpr*par, - const NetScope*found_in, - ivl_type_t par_type, - bool need_const) const; - NetExpr*elaborate_expr_param_idx_do_(Design*des, - NetScope*scope, - const NetExpr*par, - const NetScope*found_in, - ivl_type_t par_type, - bool need_const) const; + NetExpr*elaborate_expr_param_idx_up_do_(Design*des, + NetScope*scope, + const NetExpr*par, + const NetScope*found_in, + ivl_type_t par_type, + bool up, bool need_const) const; NetExpr*elaborate_expr_net(Design*des, NetScope*scope, NetNet*net, @@ -517,16 +514,11 @@ class PEIdent : public PExpr { NetESignal*net, NetScope*found, unsigned expr_wid) const; - NetExpr*elaborate_expr_net_idx_up_(Design*des, - NetScope*scope, - NetESignal*net, - NetScope*found, - bool need_const) const; - NetExpr*elaborate_expr_net_idx_do_(Design*des, - NetScope*scope, - NetESignal*net, - NetScope*found, - bool need_const) const; + NetExpr*elaborate_expr_net_idx_up_do_(Design*des, + NetScope*scope, + NetESignal*net, + NetScope*found, + bool up, bool need_const) const; NetExpr*elaborate_expr_net_bit_(Design*des, NetScope*scope, NetESignal*net, @@ -928,8 +920,18 @@ class PECallFunction : public PExpr { explicit PECallFunction(const pform_name_t &n, const std::list &parms); explicit PECallFunction(perm_string n, const std::list &parms); + // SystemVerilog: prefix().method(args) — prefix elaborates to a class handle. + explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method, + const std::vector &parms); + explicit PECallFunction(PExpr* chain_prefix, const pform_name_t &method, + const std::list &parms); + ~PECallFunction() override; + // For chained-call resolution (path is only the final method name). + const pform_scoped_name_t& peek_path(void) const { return path_; } + const PExpr* peek_chain_prefix(void) const { return chain_prefix_; } + virtual void dump(std::ostream &) const override; virtual void declare_implicit_nets(LexicalScope*scope, NetNet::Type type) override; @@ -948,6 +950,8 @@ class PECallFunction : public PExpr { private: pform_scoped_name_t path_; std::vector parms_; + // If non-null, this call is prefix().tail_name(...) (SV method chain). + PExpr* chain_prefix_ = nullptr; // For system functions. bool is_overridden_; @@ -985,7 +989,26 @@ class PECallFunction : public PExpr { unsigned elaborate_arguments_(Design*des, NetScope*scope, const NetFuncDef*def, bool need_const, std::vector&parms, - unsigned parm_off) const; + unsigned parm_off, + const std::vector*src_parms = nullptr) const; + + NetExpr* elaborate_class_method_net_(Design*des, NetScope*scope, + NetNet*net, const netclass_t*class_type, + perm_string method_name, + const std::vector*src_parms) const; + + NetExpr* elaborate_class_method_net_this_(Design*des, NetScope*scope, + NetExpr* this_expr, + const netclass_t*class_type, + perm_string method_name, + const std::vector*src_parms) const; + + NetExpr* elaborate_expr_method_chained_(Design*des, NetScope*scope, + symbol_search_results&search_results) const; + + NetExpr* elaborate_expr_chain_(Design*des, NetScope*scope, unsigned flags) const; + + unsigned test_width_chain_(Design*des, NetScope*scope, width_mode_t&mode); }; /* diff --git a/PGenerate.h b/PGenerate.h index d2d293262..24745c7dc 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -26,10 +26,12 @@ # include # include # include +# include # include "pform_types.h" class Design; class NetScope; +class PClass; class PExpr; class PFunction; class PProcess; @@ -92,9 +94,11 @@ class PGenerate : public PNamedItem, public LexicalScope { std::list gates; void add_gate(PGate*); - // Tasks instantiated within this scheme. + // Definitions instantiated within this scheme. std::map tasks; std::mapfuncs; + std::map classes; + std::vector classes_lexical; // Generate schemes can contain further generate schemes. std::list generate_schemes; diff --git a/Statement.h b/Statement.h index d410caaef..03fee609b 100644 --- a/Statement.h +++ b/Statement.h @@ -40,6 +40,8 @@ class NetCAssign; class NetDeassign; class NetForce; class NetScope; +class NetNet; +class netdarray_t; /* * The PProcess is the root of a behavioral process. Each process gets @@ -261,16 +263,42 @@ class PCallTask : public Statement { perm_string method_name, const char *sys_task_name, const std::vector &parm_names = {}) const; + NetProc*elaborate_sys_task_property_method_(Design*des, NetScope*scope, + NetNet*net, int property_idx, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names = {}) const; NetProc*elaborate_queue_method_(Design*des, NetScope*scope, NetNet*net, perm_string method_name, const char *sys_task_name, const std::vector &parm_names) const; + NetProc*elaborate_queue_property_method_(Design*des, NetScope*scope, + NetNet*net, int property_idx, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const; NetProc*elaborate_method_func_(NetScope*scope, NetNet*net, ivl_type_t type, perm_string method_name, const char*sys_task_name) const; + NetProc*elaborate_method_property_func_(NetScope*scope, + NetNet*net, int property_idx, + ivl_type_t type, + perm_string method_name, + const char*sys_task_name) const; + NetProc*elaborate_queue_method_expr_(Design*des, NetScope*scope, + NetExpr*queue_base, + const netdarray_t*use_darray, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const; + NetProc*elaborate_method_func_expr_(NetScope*scope, + NetExpr*queue_base, + ivl_type_t type, + perm_string method_name, + const char*sys_task_name) const; bool test_task_calls_ok_(Design*des, const NetScope*scope) const; PPackage*package_; diff --git a/config.guess b/config.guess index a9d01fde4..c7f4c3294 100644 --- a/config.guess +++ b/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2025 Free Software Foundation, Inc. +Copyright 1992-2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -150,7 +150,7 @@ UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in -Linux|GNU|GNU/*) +Ironclad|Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build @@ -167,6 +167,8 @@ Linux|GNU|GNU/*) LIBC=gnu #elif defined(__LLVM_LIBC__) LIBC=llvm + #elif defined(__mlibc__) + LIBC=mlibc #else #include /* First heuristic to detect musl libc. */ @@ -1186,6 +1188,9 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; + sw_64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; @@ -1598,10 +1603,10 @@ EOF GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; x86_64:[Ii]ronclad:*:*|i?86:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-pc-ironclad-mlibc + GUESS=$UNAME_MACHINE-pc-ironclad-$LIBC ;; *:[Ii]ronclad:*:*) - GUESS=$UNAME_MACHINE-unknown-ironclad-mlibc + GUESS=$UNAME_MACHINE-unknown-ironclad-$LIBC ;; esac diff --git a/config.sub b/config.sub index 3d35cde17..404aa0824 100644 --- a/config.sub +++ b/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2025 Free Software Foundation, Inc. +# Copyright 1992-2026 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268,SC2162 # see below for rationale -timestamp='2025-07-10' +timestamp='2026-05-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2025 Free Software Foundation, Inc. +Copyright 1992-2026 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1432,6 +1432,7 @@ case $cpu-$vendor in | sparcv9v \ | spu \ | sv1 \ + | sw_64 \ | sx* \ | tahoe \ | thumbv7* \ @@ -1525,7 +1526,7 @@ EOF ;; ironclad*) kernel=ironclad - os=`echo "$basic_os" | sed -e 's|ironclad|mlibc|'` + os=`echo "$basic_os" | sed -e 's|ironclad|gnu|'` ;; linux*) kernel=linux @@ -2220,7 +2221,7 @@ case $kernel-$os-$obj in ;; uclinux-uclibc*- | uclinux-gnu*- ) ;; - ironclad-mlibc*-) + ironclad-gnu*- | ironclad-mlibc*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; diff --git a/design_dump.cc b/design_dump.cc index fe5d9edf3..ee9a1cb8e 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1138,7 +1138,7 @@ void NetAssignNB::dump(ostream&o, unsigned ind) const if (rval()) o << *rval() << ";" << endl; else - o << "rval elaboration error>;" << endl; + o << ";" << endl; } diff --git a/elab_expr.cc b/elab_expr.cc index 604e8d99d..693e51abf 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -55,10 +55,51 @@ bool type_is_vectorable(ivl_variable_type_t type) } } +/* + * For a().b()… call chains, find the class type of the prefix expression + * (the value before the final ".method(args)"). + */ +static const netclass_t* resolve_call_chain_prefix_class(Design*des, NetScope*scope, + PECallFunction* link) +{ + if (link == 0) return 0; + + if (link->peek_chain_prefix() == 0) { + symbol_search_results sr; + if (!symbol_search(link, des, scope, link->peek_path(), UINT_MAX, &sr)) { + return 0; + } + if (!sr.is_scope() || sr.scope->type() != NetScope::FUNC) { + return 0; + } + NetFuncDef* fundef = sr.scope->func_def(); + ivl_assert(*link, fundef); + NetScope* dscope = fundef->scope(); + NetNet* res = dscope->find_signal(dscope->basename()); + if (res == 0) return 0; + return dynamic_cast(res->net_type()); + } + + PECallFunction* inner = dynamic_cast( + const_cast(link->peek_chain_prefix())); + if (inner == 0) return 0; + + const netclass_t* recv_class = resolve_call_chain_prefix_class(des, scope, inner); + if (recv_class == 0) return 0; + + perm_string mname = peek_tail_name(link->peek_path()); + NetScope* mscope = recv_class->method_from_name(mname); + if (mscope == 0) return 0; + NetFuncDef* mdef = mscope->func_def(); + if (mdef == 0) return 0; + NetNet* mres = mscope->find_signal(mscope->basename()); + if (mres == 0) return 0; + return dynamic_cast(mres->net_type()); +} + static ivl_nature_t find_access_function(const pform_scoped_name_t &path) { - if (path.package || path.name.size() != 1) - return nullptr; + if (path.package || path.name.size() != 1) return nullptr; return access_function_nature[peek_tail_name(path)]; } @@ -461,7 +502,6 @@ NetExpr* PEAssignPattern::elaborate_expr(Design*des, NetScope*, unsigned, unsign cerr << get_fileline() << ": : Expression is: " << *this << endl; des->errors += 1; - ivl_assert(*this, 0); return 0; } @@ -916,6 +956,17 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, eval_expr(lp, l_width_); eval_expr(rp, r_width_); + // test_width() does not equalize operand widths for string + // operands, but constant evaluation expects equal widths. + if (left_->expr_type() == IVL_VT_STRING || + right_->expr_type() == IVL_VT_STRING) { + if (dynamic_cast(lp) && dynamic_cast(rp)) { + unsigned use_wid = max(lp->expr_width(), rp->expr_width()); + lp = pad_to_width(lp, use_wid, false, *this); + rp = pad_to_width(rp, use_wid, false, *this); + } + } + // Handle some operand-specific special cases... switch (op_) { case 'E': /* === */ @@ -1540,12 +1591,36 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, << "search_results.net->net_type: " << *search_results.net->net_type() << endl; } - // Don't support multiple chained methods yet. + // Chained class methods: obj.m1().m2() — width is that of the last call. if (search_results.path_tail.size() > 1) { + if (search_results.net && search_results.net->data_type()==IVL_VT_CLASS) { + const netclass_t* cur_class = dynamic_cast(search_results.type); + if (cur_class) { + size_t ntail = search_results.path_tail.size(); + size_t idx = 0; + for (auto it = search_results.path_tail.begin() + ; it != search_results.path_tail.end() ; ++it, ++idx) { + perm_string mname = it->name; + NetScope*meth = cur_class->method_from_name(mname); + if (meth == 0) return 0; + const NetNet*res = meth->find_signal(meth->basename()); + if (res == 0) return 0; + if (idx + 1 == ntail) { + expr_type_ = res->data_type(); + expr_width_ = res->vector_width(); + min_width_ = expr_width_; + signed_flag_ = res->get_signed(); + return expr_width_; + } + cur_class = dynamic_cast(res->net_type()); + if (cur_class == 0) return 0; + } + } + } if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::test_width_method_: " << "Chained path tail (" << search_results.path_tail - << ") not supported." << endl; + << ") not supported for this expression type." << endl; } return 0; } @@ -1582,8 +1657,8 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, // the expr_width for the return value of the queue method. For example: // .x.size(); // In this example, x is a queue. - if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE - && search_results.path_head.back().index.empty()) { + if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE && + search_results.path_head.back().index.empty()) { const NetNet*net = search_results.net; const netdarray_t*darray = net->darray_type(); @@ -1718,9 +1793,38 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*, return 0; } +unsigned PECallFunction::test_width_chain_(Design*des, NetScope*scope, + width_mode_t&) +{ + expr_width_ = 0; + PECallFunction* inner_pf = dynamic_cast(chain_prefix_); + if (inner_pf == 0) return 0; + + const netclass_t* cls = resolve_call_chain_prefix_class(des, scope, inner_pf); + if (cls == 0) return 0; + + perm_string mname = peek_tail_name(path_); + NetScope* mscope = cls->method_from_name(mname); + if (mscope == 0) return 0; + + NetFuncDef* mdef = mscope->func_def(); + if (mdef == 0 || mdef->is_void()) return 0; + + NetNet* mres = mscope->find_signal(mscope->basename()); + if (mres == 0) return 0; + + expr_type_ = mres->data_type(); + expr_width_ = mres->vector_width(); + min_width_ = expr_width_; + signed_flag_ = mres->get_signed(); + return expr_width_; +} + unsigned PECallFunction::test_width(Design*des, NetScope*scope, width_mode_t&mode) { + if (chain_prefix_) return test_width_chain_(des, scope, mode); + if (debug_elaborate) { cerr << get_fileline() << ": PECallFunction::test_width: " << "path_: " << path_ << endl; @@ -2732,7 +2836,6 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { - const netclass_t *class_type = dynamic_cast(sr.type); const name_component_t comp = sr.path_tail.front(); @@ -2810,6 +2913,27 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope, canon_index = make_canonical_index(des, scope, this, comp.index, tmp_ua, false); } + } else if (dynamic_cast(tmp_type)) { + /* Queue or dynamic-array property: optional index, e.g. c.q[i] + * or whole-container reference c.q. */ + const std::list*idx_list = &comp.index; + if (idx_list->empty() && !path_.back().index.empty()) { + idx_list = &path_.back().index; + } + if (idx_list->size() == 0) { + canon_index = nullptr; + } else if (idx_list->size() != 1) { + cerr << get_fileline() << ": error: " + << "Got " << idx_list->size() << " indices, " + << "expecting 0 or 1 for the queue/dynamic-array property " + << class_type->get_prop_name(pidx) << "." << endl; + des->errors++; + } else { + const index_component_t&use_index = idx_list->back(); + ivl_assert(*this, use_index.msb != 0); + ivl_assert(*this, use_index.lsb == 0); + canon_index = elab_and_eval(des, scope, use_index.msb, -1, false); + } } if (debug_elaborate && canon_index) { @@ -2848,6 +2972,8 @@ NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope, { flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag + if (chain_prefix_) return elaborate_expr_chain_(des, scope, flags); + // Search for the symbol. This should turn up a scope. symbol_search_results search_results; bool search_flag = symbol_search(this, des, scope, path_, UINT_MAX, &search_results); @@ -3128,13 +3254,16 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, const NetFuncDef*def, bool need_const, vector&parms, - unsigned parm_off) const + unsigned parm_off, + const vector*src_parms) const { unsigned parm_errors = 0; unsigned missing_parms = 0; + const vector&use_parms = src_parms ? *src_parms : parms_; + const unsigned parm_count = parms.size() - parm_off; - const unsigned actual_count = parms_.size(); + const unsigned actual_count = use_parms.size(); if (parm_count == 0 && actual_count == 0) return 0; @@ -3147,7 +3276,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, des->errors += 1; } - auto args = map_named_args(des, def, parms_, parm_off); + auto args = map_named_args(des, def, use_parms, parm_off); for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { unsigned pidx = idx + parm_off; @@ -3202,6 +3331,198 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope, return parm_errors; } +/* + * Elaborate a call to a single class method, optionally using an alternate + * argument vector (for chained calls where inner methods use no user args). + */ +NetExpr* PECallFunction::elaborate_class_method_net_(Design*des, NetScope*scope, + NetNet*net, const netclass_t*class_type, + perm_string method_name, + const vector*src_parms) const +{ + NetESignal*ethis = new NetESignal(net); + ethis->set_line(*this); + return elaborate_class_method_net_this_(des, scope, ethis, class_type, + method_name, src_parms); +} + +NetExpr* PECallFunction::elaborate_class_method_net_this_(Design*des, NetScope*scope, + NetExpr* this_expr, + const netclass_t*class_type, + perm_string method_name, + const vector*src_parms) const +{ + NetScope*method = class_type->method_from_name(method_name); + + if (method == 0) { + cerr << get_fileline() << ": Error: " << method_name + << " is not a method of class " << class_type->get_name() + << "." << endl; + des->errors += 1; + return 0; + } + + if (method->type() != NetScope::FUNC) { + cerr << get_fileline() << ": error: Method " << method_name + << " of class " << class_type->get_name() + << " is not a function." << endl; + des->errors += 1; + return 0; + } + + const NetFuncDef*def = method->func_def(); + ivl_assert(*this, def); + + NetNet*res = method->find_signal(method->basename()); + ivl_assert(*this, res); + + vector parms(def->port_count()); + ivl_assert(*this, def->port_count() >= 1); + + parms[0] = this_expr; + + elaborate_arguments_(des, scope, def, false, parms, 1, src_parms); + + NetESignal*eres = new NetESignal(res); + NetEUFunc*call = new NetEUFunc(scope, method, eres, parms, false); + call->set_line(*this); + return call; +} + +NetExpr* PECallFunction::elaborate_expr_chain_(Design*des, NetScope*scope, + unsigned flags) const +{ + ivl_assert(*this, chain_prefix_); + NetExpr* inner = chain_prefix_->elaborate_expr(des, scope, -1, flags); + if (inner == 0) return 0; + + const netclass_t* cls = dynamic_cast(inner->net_type()); + if (cls == 0) { + cerr << get_fileline() << ": error: " + << "The prefix of a chained call (a().b()) must be an expression " + << "with class type." << endl; + des->errors += 1; + delete inner; + return 0; + } + + perm_string method_name = peek_tail_name(path_); + return elaborate_class_method_net_this_(des, scope, inner, cls, + method_name, &parms_); +} + +/* + * Handle obj.m1().m2(args): arguments apply only to the last call; intermediate + * methods must be class methods returning class handles. + */ +NetExpr* PECallFunction::elaborate_expr_method_chained_(Design*des, NetScope*scope, + symbol_search_results&search_results) const +{ + static const vector no_parms; + + if (search_results.par_val && search_results.type) { + cerr << get_fileline() << ": sorry: " + << "Method name nesting is not supported for parameter methods yet." << endl; + des->errors += 1; + return 0; + } + + NetExpr* sub_expr = 0; + if (search_results.net) { + NetESignal*tmp = new NetESignal(search_results.net); + tmp->set_line(*this); + sub_expr = tmp; + } + + if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE && + search_results.path_head.back().index.size()==1) { + + const NetNet*net = search_results.net; + const netdarray_t*darray = net->darray_type(); + const index_component_t&use_index = search_results.path_head.back().index.back(); + ivl_assert(*this, use_index.msb != 0); + ivl_assert(*this, use_index.lsb == 0); + + NetExpr*mux = elab_and_eval(des, scope, use_index.msb, -1, false); + if (!mux) return 0; + + NetESelect*tmp = new NetESelect(sub_expr, mux, darray->element_width(), darray->element_type()); + tmp->set_line(*this); + sub_expr = tmp; + } + + if (!sub_expr) { + cerr << get_fileline() << ": internal error: " + << "Method chain elaborate lost base sub-expression." << endl; + des->errors += 1; + return 0; + } + + if (sub_expr->expr_type() != IVL_VT_CLASS) { + cerr << get_fileline() << ": sorry: " + << "Method name nesting for this expression type is not supported yet " + << "(only class handle chains)." << endl; + cerr << get_fileline() << ": : " + << "method path: " << search_results.path_tail << endl; + des->errors += 1; + return 0; + } + + NetNet* cur_net = search_results.net; + const netclass_t* cur_class = dynamic_cast(search_results.type); + if (cur_class == 0) { + cur_class = dynamic_cast(cur_net->net_type()); + } + if (cur_class == 0) { + cerr << get_fileline() << ": internal error: " + << "IVL_VT_CLASS net without netclass_t type." << endl; + des->errors += 1; + return 0; + } + + size_t chain_len = search_results.path_tail.size() - 1; + size_t step_idx = 0; + for (auto it = search_results.path_tail.begin() + ; step_idx < chain_len ; ++it, ++step_idx) { + perm_string method_name = it->name; + + NetExpr* step = elaborate_class_method_net_(des, scope, cur_net, cur_class, + method_name, &no_parms); + if (step == 0) return 0; + + NetEUFunc*uf = dynamic_cast (step); + if (uf == 0) { + cerr << get_fileline() << ": internal error: " + << "expected class method call to be NetEUFunc." << endl; + des->errors += 1; + return 0; + } + + const NetESignal*rs = uf->result_sig(); + ivl_assert(*this, rs); + cur_net = const_cast(rs->sig()); + ivl_assert(*this, cur_net); + cur_class = dynamic_cast(cur_net->net_type()); + if (cur_class == 0) { + cerr << get_fileline() << ": sorry: " + << "Method chaining requires intermediate results to be class handles; " + << "after `" << method_name << "` the type is not a class." << endl; + des->errors += 1; + return 0; + } + } + + symbol_search_results tail_sr; + tail_sr.scope = search_results.scope; + tail_sr.path_head = search_results.path_head; + tail_sr.path_tail.clear(); + tail_sr.path_tail.push_back(search_results.path_tail.back()); + tail_sr.net = cur_net; + tail_sr.type = cur_class; + + return elaborate_expr_method_(des, scope, tail_sr); +} + /* * Look for a method of a given object. The search_results gives us the * information we need to look into this case: The net is the object that will @@ -3225,12 +3546,82 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, return 0; } + // e.g. c.q.size() — path_tail is {q, size}; q is a queue-typed property + if (search_results.path_tail.size() == 2) { + const netclass_t*cls = dynamic_cast(search_results.type); + if (!cls && search_results.net && search_results.net->net_type()) { + cls = dynamic_cast(search_results.net->net_type()); + } + if (cls && search_results.net) { + perm_string prop_name = search_results.path_tail.front().name; + int pidx = cls->property_idx_from_name(prop_name); + if (pidx >= 0) { + ivl_type_t ptype = cls->get_prop_type(pidx); + if (ptype && dynamic_cast(ptype)) { + NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr); + prop->set_line(*this); + perm_string method_name = search_results.path_tail.back().name; + const netqueue_t*queue = dynamic_cast(ptype); + ivl_assert(*this, queue); + ivl_type_t element_type = queue->element_type(); + if (method_name == "size") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: size() method " + << "takes no arguments" << endl; + des->errors += 1; + } + NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1); + sys_expr->set_line(*this); + sys_expr->parm(0, prop); + return sys_expr; + } + if (method_name == "pop_back") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: pop_back() method " + << "takes no arguments" << endl; + des->errors += 1; + } + NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_back", + element_type, 1); + sys_expr->set_line(*this); + sys_expr->parm(0, prop); + return sys_expr; + } + if (method_name == "pop_front") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: pop_front() method " + << "takes no arguments" << endl; + des->errors += 1; + } + NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_front", + element_type, 1); + sys_expr->set_line(*this); + sys_expr->parm(0, prop); + return sys_expr; + } + } + if (ptype && ptype->base_type() == IVL_VT_DARRAY) { + NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr); + prop->set_line(*this); + perm_string method_name = search_results.path_tail.back().name; + if (method_name == "size") { + if (parms_.size() != 0) { + cerr << get_fileline() << ": error: size() method " + << "takes no arguments" << endl; + des->errors += 1; + } + NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1); + sys_expr->set_line(*this); + sys_expr->parm(0, prop); + return sys_expr; + } + } + } + } + } + if (search_results.path_tail.size() > 1) { - cerr << get_fileline() << ": sorry: " - << "Method name nesting is not supported yet." << endl; - cerr << get_fileline() << ": : " - << "method path: " << search_results.path_tail << endl; - return 0; + return elaborate_expr_method_chained_(des, scope, search_results); } if (debug_elaborate) { @@ -3271,8 +3662,8 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, // .x[e].len() // If x is a queue of strings, then x[e] is a string. Elaborate the x[e] // expression and pass that to the len() method. - if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE - && search_results.path_head.back().index.size()==1) { + if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE && + search_results.path_head.back().index.size()==1) { const NetNet*net = search_results.net; const netdarray_t*darray = net->darray_type(); @@ -3326,8 +3717,8 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, // Queue methods. This handles the case that the located signal is a // QUEUE object, and there is a method. - if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE - && search_results.path_head.back().index.size()==0) { + if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE && + search_results.path_head.back().index.size()==0) { // Get the method name that we are looking for. perm_string method_name = search_results.path_tail.back().name; @@ -3394,41 +3785,13 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, // Class methods. Generate function call to the class method. if (sub_expr->expr_type()==IVL_VT_CLASS) { - // Get the method name that we are looking for. perm_string method_name = search_results.path_tail.back().name; NetNet*net = search_results.net; const netclass_t*class_type = dynamic_cast(search_results.type); ivl_assert(*this, class_type); - NetScope*method = class_type->method_from_name(method_name); - - if (method == 0) { - cerr << get_fileline() << ": Error: " << method_name - << " is not a method of class " << class_type->get_name() - << "." << endl; - des->errors += 1; - return 0; - } - - const NetFuncDef*def = method->func_def(); - ivl_assert(*this, def); - - NetNet*res = method->find_signal(method->basename()); - ivl_assert(*this, res); - - vector parms(def->port_count()); - ivl_assert(*this, def->port_count() >= 1); - - NetESignal*ethis = new NetESignal(net); - ethis->set_line(*this); - parms[0] = ethis; - - elaborate_arguments_(des, scope, def, false, parms, 1); - - NetESignal*eres = new NetESignal(res); - NetEUFunc*call = new NetEUFunc(scope, method, eres, parms, false); - call->set_line(*this); - return call; + return elaborate_class_method_net_(des, scope, net, class_type, + method_name, nullptr); } // String methods. @@ -3466,10 +3829,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, } if (method_name == "substr") { - if (parms_.size() != 2) + if (parms_.size() != 2) { cerr << get_fileline() << ": error: Method `substr()`" << " requires 2 arguments, got " << parms_.size() << "." << endl; + des->errors += 1; + } static const std::vector parm_names = { perm_string::literal("i"), @@ -3485,8 +3850,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, sys_expr->parm(0, sub_expr); for (int i = 0; i < 2; i++) { - if (!args[i]) + if (!args[i]) { + NetEConst*expr = make_const_0(32); + expr->set_line(*this); + sys_expr->parm(i + 1, expr); continue; + } auto expr = elaborate_rval_expr(des, scope, &netvector_t::atom2u32, @@ -5381,11 +5750,11 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined, } } -NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, +NetExpr* PEIdent::elaborate_expr_param_idx_up_do_(Design*des, NetScope*scope, const NetExpr*par, const NetScope*found_in, ivl_type_t par_type, - bool need_const) const + bool up, bool need_const) const { const NetEConst*par_ex = dynamic_cast (par); ivl_assert(*this, par_ex); @@ -5404,12 +5773,14 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, if (debug_elaborate) cerr << get_fileline() << ": debug: Calculate part select " - << name << "[" << *base << "+:" << wid << "] from range " + << name << "[" << *base << (up ? "+:" : "-:") << wid + << "] from range " << "[" << par_msv << ":" << par_lsv << "]." << endl; if (base->expr_type() == IVL_VT_REAL) { cerr << get_fileline() << ": error: Indexed part select base " - "expression for " << name << "[" << *base << "+:" << wid + "expression for " << name << "[" << *base + << (up ? "+:" : "-:") << wid << "] cannot be a real value." << endl; des->errors += 1; return 0; @@ -5424,107 +5795,23 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, ex->set_line(*this); if (warn_ob_select) { cerr << get_fileline() << ": warning: " << name - << "['bx+:" << wid + << "['bx" << (up ? "+" : "-") << ":" << wid << "] is always outside vector." << endl; } return ex; } long lsv = base_c->value().as_long(); long par_base = par_lsv; - - // Watch out for reversed bit numbering. We're making - // the part select from LSB to MSB. - if (par_msv < par_lsv) { - par_base = lsv; - lsv = par_lsv - wid + 1; - } - - if (warn_ob_select) { - bool defined = true; - // Check to see if the parameter has a defined range. - if (par_type == 0) { - defined = false; - } - // Get the parameter values width. - long pwid = -1; - if (par_ex->has_width()) pwid = par_ex->expr_width()-1; - warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid, - pwid, this, name, true); - } - verinum result = param_part_select_bits(par_ex->value(), wid, - lsv-par_base); - NetEConst*result_ex = new NetEConst(result); - result_ex->set_line(*this); - return result_ex; - } - - base = normalize_variable_base(base, par_msv, par_lsv, wid, true); - - /* Create a parameter reference for the variable select. */ - NetEConstParam*ptmp = new NetEConstParam(found_in, name, par_ex->value()); - ptmp->set_line(found_in->get_parameter_line_info(name)); - - NetExpr*tmp = new NetESelect(ptmp, base, wid, IVL_SEL_IDX_UP); - tmp->set_line(*this); - return tmp; -} - -NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, - const NetExpr*par, - const NetScope*found_in, - ivl_type_t par_type, - bool need_const) const -{ - const NetEConst*par_ex = dynamic_cast (par); - ivl_assert(*this, par_ex); - - long par_msv, par_lsv; - if(! calculate_param_range(*this, par_type, par_msv, par_lsv, - par_ex->value().len())) return 0; - - NetExpr*base = calculate_up_do_base_(des, scope, need_const); - if (base == 0) return 0; - - // Use the part select width already calculated by test_width(). - unsigned long wid = min_width_; - - perm_string name = peek_tail_name(path_); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: Calculate part select " - << name << "[" << *base << "-:" << wid << "] from range " - << "[" << par_msv << ":" << par_lsv << "]." << endl; - - if (base->expr_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: Indexed part select base " - "expression for " << name << "[" << *base << "-:" << wid - << "] cannot be a real value." << endl; - des->errors += 1; - return 0; - } - - // Handle the special case that the base is constant. In this - // case, just precalculate the entire constant result. - if (const NetEConst*base_c = dynamic_cast (base)) { - if (! base_c->value().is_defined()) { - NetEConst *ex; - ex = new NetEConst(verinum(verinum::Vx, wid, true)); - ex->set_line(*this); - if (warn_ob_select) { - cerr << get_fileline() << ": warning: " << name - << "['bx-:" << wid - << "] is always outside vector." << endl; - } - return ex; - } - long lsv = base_c->value().as_long(); - long par_base = par_lsv + wid - 1; + if (!up) + par_base += wid - 1; // Watch out for reversed bit numbering. We're making // the part select from LSB to MSB. if (par_msv < par_lsv) { par_base = lsv; lsv = par_lsv; + if (up) + lsv -= wid - 1; } if (warn_ob_select) { @@ -5537,7 +5824,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, long pwid = -1; if (par_ex->has_width()) pwid = par_ex->expr_width()-1; warn_param_ob(par_msv, par_lsv, defined, lsv-par_base, wid, - pwid, this, name, false); + pwid, this, name, up); } verinum result = param_part_select_bits(par_ex->value(), wid, @@ -5547,13 +5834,13 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, return result_ex; } - base = normalize_variable_base(base, par_msv, par_lsv, wid, false); + base = normalize_variable_base(base, par_msv, par_lsv, wid, up); /* Create a parameter reference for the variable select. */ NetEConstParam*ptmp = new NetEConstParam(found_in, name, par_ex->value()); ptmp->set_line(found_in->get_parameter_line_info(name)); - NetExpr*tmp = new NetESelect(ptmp, base, wid, IVL_SEL_IDX_DOWN); + NetExpr*tmp = new NetESelect(ptmp, base, wid, up ? IVL_SEL_IDX_UP : IVL_SEL_IDX_DOWN); tmp->set_line(*this); return tmp; } @@ -5633,12 +5920,12 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, par_type, expr_wid); if (use_sel == index_component_t::SEL_IDX_UP) - return elaborate_expr_param_idx_up_(des, scope, par, found_in, - par_type, need_const); + return elaborate_expr_param_idx_up_do_(des, scope, par, found_in, + par_type, true, need_const); if (use_sel == index_component_t::SEL_IDX_DO) - return elaborate_expr_param_idx_do_(des, scope, par, found_in, - par_type, need_const); + return elaborate_expr_param_idx_up_do_(des, scope, par, found_in, + par_type, false, need_const); NetExpr*tmp = 0; @@ -5803,12 +6090,12 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, expr_wid); if (word_sel == index_component_t::SEL_IDX_UP) - return elaborate_expr_net_idx_up_(des, scope, res, found_in, - need_const); + return elaborate_expr_net_idx_up_do_(des, scope, res, found_in, + true, need_const); if (word_sel == index_component_t::SEL_IDX_DO) - return elaborate_expr_net_idx_do_(des, scope, res, found_in, - need_const); + return elaborate_expr_net_idx_up_do_(des, scope, res, found_in, + false, need_const); if (word_sel == index_component_t::SEL_BIT) return elaborate_expr_net_bit_(des, scope, res, found_in, @@ -5962,10 +6249,11 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, } /* - * Part select indexed up, i.e. net[ +: ] + * Part select indexed up or down, i.e. net[ +: ] */ -NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, +NetExpr* PEIdent::elaborate_expr_net_idx_up_do_(Design*des, NetScope*scope, NetESignal*net, NetScope*, + bool up, bool need_const) const { if (net->sig()->data_type() == IVL_VT_STRING) { @@ -5984,13 +6272,15 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, if (!base) return nullptr; + // Use the part select width already calculated by test_width(). unsigned long wid = min_width_; + const char *op = up ? "+" : "-"; if (base->expr_type() == IVL_VT_REAL) { cerr << get_fileline() << ": error: Indexed part select base " "expression for " << net->sig()->name() << "[" << *base - << "+:" << wid << "] cannot be a real value." << endl; + << op << ":" << wid << "] cannot be a real value." << endl; des->errors += 1; return 0; } @@ -6001,13 +6291,13 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, if (const NetEConst*base_c = dynamic_cast (base)) { NetExpr*ex; if (base_c->value().is_defined()) { - long lsv = base_c->value().as_long(); + long msv = base_c->value().as_long(); long rel_base = 0; // Check whether an unsigned base fits in a 32 bit int. // This ensures correct results for the vlog95 target, and // for the vvp target on LLP64 platforms (Microsoft Windows). - if (!base_c->has_sign() && (int32_t)lsv < 0) { + if (!base_c->has_sign() && (int32_t)msv < 0) { // Return 'bx for a wrapped around base. ex = new NetEConst(verinum(verinum::Vx, wid, true)); ex->set_line(*this); @@ -6015,7 +6305,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, if (warn_ob_select) { cerr << get_fileline() << ": warning: " << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "[" << (unsigned long)lsv << "+:" << wid + cerr << "[" << (unsigned long)msv << op << ":" << wid << "] is always outside vector." << endl; } return ex; @@ -6031,12 +6321,17 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, ivl_assert(*this, swid > 0); long loff, moff; unsigned long lwid, mwid; + long lsv = msv; + if (up) + lsv += (wid/swid)-1; + else + lsv -= (wid/swid)-1; bool lrc, mrc; - mrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid); - lrc = net->sig()->sb_to_slice(prefix_indices, lsv+(wid/swid)-1, loff, lwid); + mrc = net->sig()->sb_to_slice(prefix_indices, msv, moff, mwid); + lrc = net->sig()->sb_to_slice(prefix_indices, lsv, loff, lwid); if (!mrc || !lrc) { cerr << get_fileline() << ": error: "; - cerr << "Part-select [" << lsv << "+:" << (wid/swid); + cerr << "Part-select [" << msv << op << ":" << (wid/swid); cerr << "] exceeds the declared bounds for "; cerr << net->sig()->name(); if (net->sig()->unpacked_dimensions() > 0) cerr << "[]"; @@ -6056,10 +6351,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, long offset = 0; // We want the last range, which is where we work. const netrange_t&rng = packed.back(); - if (rng.get_msb() < rng.get_lsb()) { + if ((rng.get_msb() > rng.get_lsb()) ^ up) { offset = -wid + 1; } - rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset; + rel_base = net->sig()->sb_to_idx(prefix_indices, msv) + offset; } // If the part select covers exactly the entire @@ -6070,7 +6365,6 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, net->cast_signed(false); return net; } - // Otherwise, make a part select that covers the right // range. ex = new NetEConst(verinum(rel_base)); @@ -6079,14 +6373,14 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, cerr << get_fileline() << ": warning: " << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "[" << lsv << "+:" << wid + cerr << "[" << msv << op << ":" << wid << "] is selecting before vector." << endl; } if (rel_base + wid > net->vector_width()) { cerr << get_fileline() << ": warning: " << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "[" << lsv << "+:" << wid + cerr << "[" << msv << op << ":" << wid << "] is selecting after vector." << endl; } } @@ -6098,7 +6392,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, if (warn_ob_select) { cerr << get_fileline() << ": warning: " << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "['bx+:" << wid + cerr << "['bx" << op << ":" << wid << "] is always outside vector." << endl; } return ex; @@ -6115,175 +6409,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, // Convert the non-constant part select index expression into // an expression that returns a canonical base. - base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, true); + base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, up); - NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP); - ss->set_line(*this); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part " - << "select base="<< *base << ", wid="<< wid << endl; - } - - return ss; -} - -/* - * Part select indexed down, i.e. net[ -: ] - */ -NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, - NetESignal*net, NetScope*, - bool need_const) const -{ - if (net->sig()->data_type() == IVL_VT_STRING) { - cerr << get_fileline() << ": error: Cannot take the index part " - "select of a string ('" << net->name() << "')." << endl; - des->errors += 1; - return 0; - } - - listprefix_indices; - bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); - if (!rc) - return 0; - - NetExpr*base = calculate_up_do_base_(des, scope, need_const); - if (!base) - return nullptr; - - // Use the part select width already calculated by test_width(). - unsigned long wid = min_width_; - - if (base->expr_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: Indexed part select base " - "expression for " << net->sig()->name() << "[" << *base - << "-:" << wid << "] cannot be a real value." << endl; - des->errors += 1; - return 0; - } - - // Handle the special case that the base is constant as - // well. In this case it can be converted to a conventional - // part select. - if (const NetEConst*base_c = dynamic_cast (base)) { - NetExpr*ex; - if (base_c->value().is_defined()) { - long lsv = base_c->value().as_long(); - long rel_base = 0; - - // Check whether an unsigned base fits in a 32 bit int. - // This ensures correct results for the vlog95 target, and - // for the vvp target on LLP64 platforms (Microsoft Windows). - if (!base_c->has_sign() && (int32_t)lsv < 0) { - // Return 'bx for a wrapped around base. - ex = new NetEConst(verinum(verinum::Vx, wid, true)); - ex->set_line(*this); - delete base; - if (warn_ob_select) { - cerr << get_fileline() << ": warning: " << net->name(); - if (net->word_index()) cerr << "[]"; - cerr << "[" << (unsigned long)lsv << "-:" << wid - << "] is always outside vector." << endl; - } - return ex; - } - - // Get the signal range. - const netranges_t&packed = net->sig()->packed_dims(); - if (prefix_indices.size()+1 < net->sig()->packed_dims().size()) { - // Here we are selecting one or more sub-arrays. - // Make this work by finding the indexed sub-arrays and - // creating a generated slice that spans the whole range. - unsigned long swid = net->sig()->slice_width(prefix_indices.size()+1); - ivl_assert(*this, swid > 0); - long loff, moff; - unsigned long lwid, mwid; - bool lrc, mrc; - mrc = net->sig()->sb_to_slice(prefix_indices, lsv, moff, mwid); - lrc = net->sig()->sb_to_slice(prefix_indices, lsv-(wid/swid)+1, loff, lwid); - if (!mrc || !lrc) { - cerr << get_fileline() << ": error: "; - cerr << "Part-select [" << lsv << "-:" << (wid/swid); - cerr << "] exceeds the declared bounds for "; - cerr << net->sig()->name(); - if (net->sig()->unpacked_dimensions() > 0) cerr << "[]"; - cerr << "." << endl; - des->errors += 1; - return 0; - } - ivl_assert(*this, mwid == swid); - ivl_assert(*this, lwid == swid); - - if (moff > loff) { - rel_base = loff; - } else { - rel_base = moff; - } - } else { - long offset = 0; - // We want the last range, which is where we work. - const netrange_t&rng = packed.back(); - if (rng.get_msb() > rng.get_lsb()) { - offset = -wid + 1; - } - rel_base = net->sig()->sb_to_idx(prefix_indices, lsv) + offset; - } - - // If the part select covers exactly the entire - // vector, then do not bother with it. Return the - // signal itself. - if (rel_base == (long)(wid-1) && wid == net->vector_width()) { - delete base; - net->cast_signed(false); - return net; - } - - // Otherwise, make a part select that covers the right - // range. - ex = new NetEConst(verinum(rel_base)); - if (warn_ob_select) { - if (rel_base < 0) { - cerr << get_fileline() << ": warning: " - << net->name(); - if (net->word_index()) cerr << "[]"; - cerr << "[" << lsv << "-:" << wid - << "] is selecting before vector." << endl; - } - if (rel_base + wid > net->vector_width()) { - cerr << get_fileline() << ": warning: " - << net->name(); - if (net->word_index()) cerr << "[]"; - cerr << "[" << lsv << "-:" << wid - << "] is selecting after vector." << endl; - } - } - } else { - // Return 'bx for an undefined base. - ex = new NetEConst(verinum(verinum::Vx, wid, true)); - ex->set_line(*this); - delete base; - if (warn_ob_select) { - cerr << get_fileline() << ": warning: " << net->name(); - if (net->word_index()) cerr << "[]"; - cerr << "['bx-:" << wid - << "] is always outside vector." << endl; - } - return ex; - } - NetESelect*ss = new NetESelect(net, ex, wid); - ss->set_line(*this); - - delete base; - return ss; - } - - ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size()); - - // Convert the non-constant part select index expression into - // an expression that returns a canonical base. - base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, false); - - NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_DOWN); + NetESelect*ss = new NetESelect(net, base, wid, up ? IVL_SEL_IDX_UP : IVL_SEL_IDX_DOWN); ss->set_line(*this); if (debug_elaborate) { @@ -6602,12 +6730,12 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, expr_wid); if (use_sel == index_component_t::SEL_IDX_UP) - return elaborate_expr_net_idx_up_(des, scope, node, found_in, - need_const); + return elaborate_expr_net_idx_up_do_(des, scope, node, found_in, + true, need_const); if (use_sel == index_component_t::SEL_IDX_DO) - return elaborate_expr_net_idx_do_(des, scope, node, found_in, - need_const); + return elaborate_expr_net_idx_up_do_(des, scope, node, found_in, + false, need_const); if (use_sel == index_component_t::SEL_BIT) return elaborate_expr_net_bit_(des, scope, node, found_in, diff --git a/elab_lval.cc b/elab_lval.cc index 1068954d1..2251c186a 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -298,6 +298,15 @@ NetAssign_*PEIdent::elaborate_lval_var_(Design *des, NetScope *scope, // Past this point, we should have taken care of the cases // where the name is a member/method of a struct/class. // XXXX ivl_assert(*this, method_name.nil()); + if (!tail_path.empty()) { + cerr << get_fileline() << ": error: Variable " + << reg->name() + << " does not have a field named: " + << tail_path << "." << endl; + des->errors += 1; + return nullptr; + } + ivl_assert(*this, tail_path.empty()); bool need_const_idx = is_cassign || is_force; @@ -883,8 +892,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, calculate_up_do_width_(des, scope, wid); NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1); + if (!base) + return false; - if (base && base->expr_type() == IVL_VT_REAL) { + if (base->expr_type() == IVL_VT_REAL) { cerr << get_fileline() << ": error: Indexed part select base " "expression for "; cerr << lv->sig()->name() << "[" << *base; diff --git a/elab_scope.cc b/elab_scope.cc index bd9065fd3..43d46de3b 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1322,6 +1322,10 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) collect_scope_signals(scope, wires); + elaborate_scope_enumerations(des, scope, enum_sets); + + elaborate_scope_classes(des, scope, classes_lexical); + // Run through the defparams for this scope and save the result // in a table for later final override. @@ -1662,6 +1666,8 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const collect_scope_signals(scope, wires); + elaborate_scope_enumerations(des, scope, enum_sets); + // Scan through all the named events in this scope. elaborate_scope_events_(des, scope, events); @@ -1682,6 +1688,8 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const collect_scope_signals(scope, wires); + elaborate_scope_enumerations(des, scope, enum_sets); + // Scan through all the named events in this scope. elaborate_scope_events_(des, scope, events); @@ -1732,6 +1740,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const collect_scope_signals(my_scope, wires); + elaborate_scope_enumerations(des, my_scope, enum_sets); + // Scan through all the named events in this scope. elaborate_scope_events_(des, my_scope, events); } diff --git a/elab_sig.cc b/elab_sig.cc index f23145c22..f8cb069ef 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -404,11 +404,6 @@ void netclass_t::elaborate_sig(Design*des, PClass*pclass) << " type=" << *use_type << endl; } - if (dynamic_cast (use_type)) { - cerr << cur->second.get_fileline() << ": sorry: " - << "Queues inside classes are not yet supported." << endl; - des->errors++; - } set_property(cur->first, cur->second.qual, use_type); if (! cur->second.qual.test_static()) @@ -607,6 +602,7 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const elaborate_sig_funcs(des, scope, funcs); elaborate_sig_tasks(des, scope, tasks); + elaborate_sig_classes(des, scope, classes); typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() diff --git a/elaborate.cc b/elaborate.cc index 988110c7f..2b8d46c15 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -47,6 +47,7 @@ # include "netenum.h" # include "netvector.h" # include "netdarray.h" +# include "netqueue.h" # include "netparray.h" # include "netscalar.h" # include "netclass.h" @@ -3250,15 +3251,6 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const NetEvWait*event = 0; if (count_ != 0 || event_ != 0) { if (count_ != 0) { - if (scope->is_auto() && count_->has_aa_term(des, scope)) { - cerr << get_fileline() << ": error: automatically " - "allocated variables may not be referenced " - "in intra-assignment event controls of " - "non-blocking assignments." << endl; - des->errors += 1; - return 0; - } - ivl_assert(*this, event_ != 0); count = elab_and_eval(des, scope, count_, -1); if (count == 0) { @@ -4073,19 +4065,66 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope, return sys; } -/* - * This private method is called to elaborate queue push methods. The - * sys_task_name is the internal system-task name to use. - */ -NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, - NetNet*net, - perm_string method_name, - const char *sys_task_name, - const std::vector &parm_names) const +NetProc* PCallTask::elaborate_sys_task_property_method_(Design*des, NetScope*scope, + NetNet*net, int property_idx, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const { - NetESignal*sig = new NetESignal(net); - sig->set_line(*this); + NetEProperty*prop = new NetEProperty(net, property_idx, 0); + prop->set_line(*this); + unsigned nparms = parms_.size(); + + vectorargv (1 + nparms); + argv[0] = prop; + + if (method_name == "delete") { + const netclass_t*cls = dynamic_cast(net->net_type()); + ivl_assert(*this, cls); + ivl_type_t pt = cls->get_prop_type(property_idx); + bool is_queue = pt && pt->base_type() == IVL_VT_QUEUE; + if (is_queue) { + if (nparms > 1) { + cerr << get_fileline() << ": error: queue delete() " + << "method takes zero or one argument." << endl; + des->errors += 1; + } + } else if (nparms > 0) { + cerr << get_fileline() << ": error: darray delete() " + << "method takes no arguments." << endl; + des->errors += 1; + } + } else if (parm_names.size() != parms_.size()) { + cerr << get_fileline() << ": error: " << method_name + << "() method takes " << parm_names.size() << " arguments, got " + << parms_.size() << "." << endl; + des->errors++; + } + + auto args = map_named_args(des, parm_names, parms_); + for (unsigned idx = 0 ; idx < nparms ; idx += 1) { + argv[idx + 1] = elab_sys_task_arg(des, scope, method_name, + idx, args[idx]); + } + + NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv); + sys->set_line(*this); + return sys; +} + +/* + * Common implementation for queue push/insert methods. The queue_base + * expression is either a NetESignal or NetEProperty; use_darray + * supplies the element type. + */ +NetProc* PCallTask::elaborate_queue_method_expr_(Design*des, NetScope*scope, + NetExpr*queue_base, + const netdarray_t*use_darray, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const +{ unsigned nparms = parms_.size(); // insert() requires two arguments. if ((method_name == "insert") && (nparms != 2)) { @@ -4099,21 +4138,10 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, << "() method requires a single argument." << endl; des->errors += 1; } - - // Get the context width if this is a logic type. - ivl_variable_type_t base_type = net->darray_type()->element_base_type(); - int context_width = -1; - switch (base_type) { - case IVL_VT_BOOL: - case IVL_VT_LOGIC: - context_width = net->darray_type()->element_width(); - break; - default: - break; - } - - vectorargv (nparms+1); - argv[0] = sig; + ivl_type_t element_type = use_darray->element_type(); + unsigned expected_nparms = method_name == "insert" ? 2 : 1; + vectorargv (expected_nparms+1); + argv[0] = queue_base; auto args = map_named_args(des, parm_names, parms_); if (method_name != "insert") { @@ -4123,8 +4151,8 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, << "() methods first argument is missing." << endl; des->errors += 1; } else { - argv[1] = elab_and_eval(des, scope, args[0], context_width, - false, false, base_type); + argv[1] = elaborate_rval_expr(des, scope, element_type, + args[0]); } } else { if (nparms == 0 || !args[0]) { @@ -4133,8 +4161,9 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, << "() methods first argument is missing." << endl; des->errors += 1; } else { - argv[1] = elab_and_eval(des, scope, args[0], context_width, - false, false, IVL_VT_LOGIC); + argv[1] = elaborate_rval_expr(des, scope, + netvector_t::integer_type(), + args[0]); } if (nparms < 2 || !args[1]) { @@ -4143,8 +4172,8 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, << "() methods second argument is missing." << endl; des->errors += 1; } else { - argv[2] = elab_and_eval(des, scope, args[1], context_width, - false, false, base_type); + argv[2] = elaborate_rval_expr(des, scope, element_type, + args[1]); } } @@ -4153,14 +4182,55 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, return sys; } +/* + * This private method is called to elaborate queue push methods. The + * sys_task_name is the internal system-task name to use. + */ +NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope, + NetNet*net, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const +{ + NetESignal*sig = new NetESignal(net); + sig->set_line(*this); + + const netdarray_t*use_darray = net->darray_type(); + ivl_assert(*this, use_darray); + + return elaborate_queue_method_expr_(des, scope, sig, use_darray, + method_name, sys_task_name, + parm_names); +} + +NetProc* PCallTask::elaborate_queue_property_method_(Design*des, NetScope*scope, + NetNet*net, int property_idx, + perm_string method_name, + const char *sys_task_name, + const std::vector &parm_names) const +{ + const netclass_t*cls = dynamic_cast(net->net_type()); + ivl_assert(*this, cls); + ivl_type_t ptype = cls->get_prop_type(property_idx); + const netdarray_t*use_darray = dynamic_cast(ptype); + ivl_assert(*this, use_darray); + + NetEProperty*prop = new NetEProperty(net, property_idx, 0); + prop->set_line(*this); + + return elaborate_queue_method_expr_(des, scope, prop, use_darray, + method_name, sys_task_name, + parm_names); +} + /* * This is used for array/queue function methods called as tasks. */ -NetProc* PCallTask::elaborate_method_func_(NetScope*scope, - NetNet*net, - ivl_type_t type, - perm_string method_name, - const char*sys_task_name) const +NetProc* PCallTask::elaborate_method_func_expr_(NetScope*scope, + NetExpr*queue_base, + ivl_type_t type, + perm_string method_name, + const char*sys_task_name) const { if (!void_cast_) { cerr << get_fileline() << ": warning: method function '" @@ -4170,9 +4240,7 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope, // Generate the function. NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1); sys_expr->set_line(*this); - NetESignal*arg = new NetESignal(net); - arg->set_line(*net); - sys_expr->parm(0, arg); + sys_expr->parm(0, queue_base); // Create a L-value that matches the function return type. NetNet*tmp; tmp = new NetNet(scope, scope->local_symbol(), NetNet::REG, type); @@ -4184,6 +4252,30 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope, return cur; } +NetProc* PCallTask::elaborate_method_func_(NetScope*scope, + NetNet*net, + ivl_type_t type, + perm_string method_name, + const char*sys_task_name) const +{ + NetESignal*arg = new NetESignal(net); + arg->set_line(*this); + return elaborate_method_func_expr_(scope, arg, type, + method_name, sys_task_name); +} + +NetProc* PCallTask::elaborate_method_property_func_(NetScope*scope, + NetNet*net, int property_idx, + ivl_type_t type, + perm_string method_name, + const char*sys_task_name) const +{ + NetEProperty*prop = new NetEProperty(net, property_idx, 0); + prop->set_line(*this); + return elaborate_method_func_expr_(scope, prop, type, + method_name, sys_task_name); +} + NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, bool add_this_flag) const { @@ -4232,13 +4324,93 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, << net->name() << ".data_type() --> " << net->data_type() << endl; } + // Class handle with one path_tail component: queue/darray property method + // e.g. c.q.push_back(x) => sr.path_tail = {q}, method_name = push_back + if (sr.path_tail.size() == 1) { + const netclass_t*cls = dynamic_cast(sr.type); + if (!cls && net->net_type()) { + cls = dynamic_cast(net->net_type()); + } + if (cls) { + perm_string prop_name = sr.path_tail.front().name; + int pidx = cls->property_idx_from_name(prop_name); + if (pidx >= 0) { + ivl_type_t ptype = cls->get_prop_type(pidx); + if (ptype && dynamic_cast(ptype)) { + const netdarray_t*use_darray = dynamic_cast(ptype); + ivl_assert(*this, use_darray); + + if (method_name == "push_back") { + static const std::vector parm_names = { + perm_string::literal("item") + }; + return elaborate_queue_property_method_(des, scope, net, pidx, + method_name, + "$ivl_queue_method$push_back", + parm_names); + } + if (method_name == "push_front") { + static const std::vector parm_names = { + perm_string::literal("item") + }; + return elaborate_queue_property_method_(des, scope, net, pidx, + method_name, + "$ivl_queue_method$push_front", + parm_names); + } + if (method_name == "insert") { + static const std::vector parm_names = { + perm_string::literal("index"), + perm_string::literal("item") + }; + return elaborate_queue_property_method_(des, scope, net, pidx, + method_name, + "$ivl_queue_method$insert", + parm_names); + } + if (method_name == "pop_front") { + return elaborate_method_property_func_(scope, net, pidx, + use_darray->element_type(), + method_name, + "$ivl_queue_method$pop_front"); + } + if (method_name == "pop_back") { + return elaborate_method_property_func_(scope, net, pidx, + use_darray->element_type(), + method_name, + "$ivl_queue_method$pop_back"); + } + if (method_name == "size") { + return elaborate_method_property_func_(scope, net, pidx, + &netvector_t::atom2s32, + method_name, "$size"); + } + } else if (ptype && ptype->base_type() == IVL_VT_DARRAY) { + if (method_name == "delete") { + static const std::vector parm_names = { + perm_string::literal("index") + }; + return elaborate_sys_task_property_method_(des, scope, net, pidx, + method_name, + "$ivl_darray_method$delete", + parm_names); + } + if (method_name == "size") { + return elaborate_method_property_func_(scope, net, pidx, + &netvector_t::atom2s32, + method_name, "$size"); + } + } + } + } + } + // Is this a method of a "string" type? if (dynamic_cast(net->net_type())) { if (method_name == "itoa") { static const std::vector parm_names = { perm_string::literal("i") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_string_method$itoa", parm_names); @@ -4246,7 +4418,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, static const std::vector parm_names = { perm_string::literal("i") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_string_method$hextoa", parm_names); @@ -4254,7 +4425,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, static const std::vector parm_names = { perm_string::literal("i") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_string_method$octtoa", parm_names); @@ -4262,7 +4432,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, static const std::vector parm_names = { perm_string::literal("i") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_string_method$bintoa", parm_names); @@ -4270,7 +4439,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, static const std::vector parm_names = { perm_string::literal("r") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_string_method$realtoa", parm_names); @@ -4283,7 +4451,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, static const std::vector parm_names = { perm_string::literal("index") }; - return elaborate_sys_task_method_(des, scope, net, method_name, "$ivl_darray_method$delete", parm_names); @@ -4320,7 +4487,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, } if (net->queue_type()) { - const netdarray_t*use_darray = net->darray_type(); if (method_name == "push_back") { static const std::vector parm_names = { perm_string::literal("item") @@ -4347,11 +4513,13 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope, "$ivl_queue_method$insert", parm_names); } else if (method_name == "pop_front") { + const netdarray_t*use_darray = net->darray_type(); return elaborate_method_func_(scope, net, use_darray->element_type(), method_name, "$ivl_queue_method$pop_front"); } else if (method_name == "pop_back") { + const netdarray_t*use_darray = net->darray_type(); return elaborate_method_func_(scope, net, use_darray->element_type(), method_name, @@ -7237,6 +7405,7 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const if (result_flag) { elaborate_functions(des, scope, funcs); elaborate_tasks(des, scope, tasks); + elaborate_classes(des, scope, classes); for (const auto gt : gates) gt->elaborate(des, scope); diff --git a/eval_tree.cc b/eval_tree.cc index 7cbb49321..cab465892 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -26,6 +26,7 @@ # include # include "netlist.h" +# include "netclass.h" # include "ivl_assert.h" # include "netmisc.h" @@ -2182,6 +2183,25 @@ static bool get_array_info(const NetExpr*arg, long dim, left = range.get_msb(); right = range.get_lsb(); return false; + } + /* Class property (e.g. queue field): size is dynamic; defer to runtime + * instead of folding to all-X in evaluate_array_funcs_. */ + if (const NetEProperty*prop = dynamic_cast(arg)) { + const NetNet*obj = prop->get_sig(); + const netclass_t*cls = dynamic_cast(obj->net_type()); + if (cls == 0) return true; + ivl_type_t ptype = cls->get_prop_type(prop->property_idx()); + if (ptype == 0) return true; + switch (ptype->base_type()) { + case IVL_VT_DARRAY: + case IVL_VT_QUEUE: + case IVL_VT_STRING: + defer = true; + return true; + default: + break; + } + return true; } /* The argument must be a signal that has enough dimensions. */ const NetESignal*esig = dynamic_cast(arg); diff --git a/ivl.def b/ivl.def index 867d832f4..f95572ba6 100644 --- a/ivl.def +++ b/ivl.def @@ -337,6 +337,7 @@ ivl_type_packed_width ivl_type_prop_name ivl_type_prop_type ivl_type_properties +ivl_type_queue_max ivl_type_signed ivl_udp_init diff --git a/ivl_target.h b/ivl_target.h index b33ea9aa4..b4eec2c3b 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -2400,6 +2400,10 @@ extern int ivl_type_properties(ivl_type_t net); extern const char* ivl_type_prop_name(ivl_type_t net, int idx); extern ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx); +/* Maximum element count for a queue type (0 = unbounded). Only valid + * when ivl_type_base(net) == IVL_VT_QUEUE. */ +extern unsigned ivl_type_queue_max(ivl_type_t net); + #if defined(__MINGW32__) || defined (__CYGWIN__) # define DLLEXPORT __declspec(dllexport) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 6da2aaafe..a1d64dea3 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -2368,6 +2368,8 @@ void reset_lexor(FILE* out, char* paths[]) isp->stringify_flag = 0; isp->comment = NULL; + yyout = out; + if (isp->file == 0) { perror(paths[0]); error_count += 1; @@ -2382,8 +2384,6 @@ void reset_lexor(FILE* out, char* paths[]) } } - yyout = out; - yyrestart(isp->file); assert(istack == 0); diff --git a/ivtest/gold/br1005.gold b/ivtest/gold/br1005.gold index e59c1def5..c054f026b 100644 --- a/ivtest/gold/br1005.gold +++ b/ivtest/gold/br1005.gold @@ -1,18 +1,5 @@ -./ivltests/br1005.v:2: sorry: Queues inside classes are not yet supported. -./ivltests/br1005.v:15: error: Enable of unknown task ``a.q.push_back''. -./ivltests/br1005.v:16: error: Enable of unknown task ``a.q.push_back''. -./ivltests/br1005.v:17: error: Enable of unknown task ``a.q.push_back''. -./ivltests/br1005.v:18: error: Enable of unknown task ``a.q.push_back''. -./ivltests/br1005.v:19: sorry: Method name nesting is not supported yet. -./ivltests/br1005.v:19: : method path: q.pop_front -./ivltests/br1005.v:19: error: Object test.a has no method "q.pop_front(...)". -./ivltests/br1005.v:22: sorry: Method name nesting is not supported yet. -./ivltests/br1005.v:22: : method path: q.pop_front -./ivltests/br1005.v:22: error: Object test.a has no method "q.pop_front(...)". -./ivltests/br1005.v:25: sorry: Method name nesting is not supported yet. -./ivltests/br1005.v:25: : method path: q.pop_front -./ivltests/br1005.v:25: error: Object test.a has no method "q.pop_front(...)". -./ivltests/br1005.v:28: sorry: Method name nesting is not supported yet. -./ivltests/br1005.v:28: : method path: q.pop_front -./ivltests/br1005.v:28: error: Object test.a has no method "q.pop_front(...)". -9 error(s) during elaboration. +1 +2 +3 +4 +PASSED diff --git a/ivtest/gold/br_gh1175c.gold b/ivtest/gold/br_gh1175c.gold index 6396fbcf3..3fe2d3526 100644 --- a/ivtest/gold/br_gh1175c.gold +++ b/ivtest/gold/br_gh1175c.gold @@ -1,4 +1,3 @@ ./ivltests/br_gh1175c.v:3: syntax error ./ivltests/br_gh1175c.v:3: errors in UDP table ./ivltests/br_gh1175c.v:1: error: Invalid table for UDP primitive id_0. - diff --git a/ivtest/gold/br_gh1175d.gold b/ivtest/gold/br_gh1175d.gold index 6c42835a7..02daa6584 100644 --- a/ivtest/gold/br_gh1175d.gold +++ b/ivtest/gold/br_gh1175d.gold @@ -1,4 +1,3 @@ ./ivltests/br_gh1175d.v:3: syntax error ./ivltests/br_gh1175d.v:3: errors in UDP table ./ivltests/br_gh1175d.v:1: error: Invalid table for UDP primitive id_0. - diff --git a/ivtest/gold/br_gh1175e.gold b/ivtest/gold/br_gh1175e.gold index 349b984e1..8ee414e94 100644 --- a/ivtest/gold/br_gh1175e.gold +++ b/ivtest/gold/br_gh1175e.gold @@ -1,4 +1,3 @@ ./ivltests/br_gh1175e.v:3: syntax error ./ivltests/br_gh1175e.v:3: errors in UDP table ./ivltests/br_gh1175e.v:1: error: Invalid table for UDP primitive id_0. - diff --git a/ivtest/gold/br_gh72b_fail.gold b/ivtest/gold/br_gh72b_fail.gold index 57f44c49c..80abadc09 100644 --- a/ivtest/gold/br_gh72b_fail.gold +++ b/ivtest/gold/br_gh72b_fail.gold @@ -3,4 +3,4 @@ ./ivltests/br_gh72b_fail.v:8: error: too few arguments for `macro2 ./ivltests/br_gh72b_fail.v:9: error: too few arguments for `macro2 ./ivltests/br_gh72b_fail.v:10: error: too many arguments for `macro2 -Preprocessor failed with 5 errors. +Preprocessor failed with 5 error(s). diff --git a/ivtest/gold/udp_empty_table_fail-iverilog-stderr.gold b/ivtest/gold/udp_empty_table_fail-iverilog-stderr.gold new file mode 100644 index 000000000..1ea319f87 --- /dev/null +++ b/ivtest/gold/udp_empty_table_fail-iverilog-stderr.gold @@ -0,0 +1,2 @@ +ivltests/udp_empty_table_fail.v:7: error: Empty UDP table. +ivltests/udp_empty_table_fail.v:3: error: Invalid table for UDP primitive udp_empty_table_fail. diff --git a/ivtest/ivltests/br_gh1384.v b/ivtest/ivltests/br_gh1384.v new file mode 100644 index 000000000..f58f8a283 --- /dev/null +++ b/ivtest/ivltests/br_gh1384.v @@ -0,0 +1,50 @@ +// Check that classes declared inside generate blocks can be used. + +module test; + + reg failed; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + if (1) begin : g + class C; + int value; + + function new(int value); + this.value = value; + endfunction + endclass + + C c = new(42); + end + + for (genvar i = 0; i < 2; i = i + 1) begin : h + class C; + int value; + + function new(int value); + this.value = value + i; + endfunction + endclass + + C c = new(10); + end + + initial begin + failed = 1'b0; + + `check(g.c.value, 42); + `check(h[0].c.value, 10); + `check(h[1].c.value, 11); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/br_gh1385.v b/ivtest/ivltests/br_gh1385.v new file mode 100644 index 000000000..40a382b2f --- /dev/null +++ b/ivtest/ivltests/br_gh1385.v @@ -0,0 +1,39 @@ +// Check that enum literals declared inside generate blocks are available in +// the generated scope. + +module test; + + reg failed; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + if (1) begin : g + typedef enum logic [3:0] { + A = 4'd1, + B = 4'd2 + } EN_T; + + EN_T e = A; + + initial begin + failed = 1'b0; + + #1; + `check(e, A); + + e = B; + `check(e, B); + + if (!failed) begin + $display("PASSED"); + end + end + end + +endmodule diff --git a/ivtest/ivltests/br_gh1385a.v b/ivtest/ivltests/br_gh1385a.v new file mode 100644 index 000000000..e0cd4d1c1 --- /dev/null +++ b/ivtest/ivltests/br_gh1385a.v @@ -0,0 +1,37 @@ +// Check that enum literals declared inside named blocks are available in +// the block scope. + +module test; + + reg failed; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + initial begin : b + typedef enum logic [3:0] { + A = 4'd1, + B = 4'd2 + } EN_T; + + static EN_T e = A; + + failed = 1'b0; + + #1; + `check(e, A); + + e = B; + `check(e, B); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/br_gh1385b.v b/ivtest/ivltests/br_gh1385b.v new file mode 100644 index 000000000..26d15a52f --- /dev/null +++ b/ivtest/ivltests/br_gh1385b.v @@ -0,0 +1,41 @@ +// Check that enum literals declared inside tasks are available in the task +// scope. + +module test; + + reg failed; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + task check_task_enum; + typedef enum logic [3:0] { + A = 4'd1, + B = 4'd2 + } EN_T; + + static EN_T e = A; + + `check(e, A); + + e = B; + `check(e, B); + endtask + + initial begin + failed = 1'b0; + + #1; + check_task_enum(); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/br_gh1385c.v b/ivtest/ivltests/br_gh1385c.v new file mode 100644 index 000000000..0a5117ee6 --- /dev/null +++ b/ivtest/ivltests/br_gh1385c.v @@ -0,0 +1,39 @@ +// Check that enum literals declared inside functions are available in the +// function scope. + +module test; + + reg failed; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + function logic [3:0] check_func_enum; + typedef enum logic [3:0] { + A = 4'd1, + B = 4'd2 + } EN_T; + + static EN_T e = A; + + e = B; + check_func_enum = e; + endfunction + + initial begin + failed = 1'b0; + + #1; + `check(check_func_enum(), 4'd2); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/br_gh670.v b/ivtest/ivltests/br_gh670.v new file mode 100644 index 000000000..d267dc51d --- /dev/null +++ b/ivtest/ivltests/br_gh670.v @@ -0,0 +1,37 @@ +// Regression test for GitHub issue #670. +// Check that a class function can have the same name as the class. + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + class test; + int value; + + function void test(); + value = 32'd42; + endfunction + endclass + + initial begin + test tst; + + failed = 1'b0; + tst = new; + tst.test(); + + `check(tst.value, 32'd42, "Class function name did not hide class name"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/case_mux_array_word.v b/ivtest/ivltests/case_mux_array_word.v new file mode 100644 index 000000000..800798482 --- /dev/null +++ b/ivtest/ivltests/case_mux_array_word.v @@ -0,0 +1,52 @@ +// Check that case statement muxes work with array word inputs. + +module test; + + reg [7:0] mem [0:3]; + reg [1:0] sel; + reg [7:0] out; + reg failed; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + always @* begin + case (sel) + 2'd0: out = mem[0]; + 2'd1: out = mem[1]; + 2'd2: out = mem[2]; + 2'd3: out = mem[3]; + endcase + end + + (* ivl_synthesis_off *) + initial begin + failed = 1'b0; + + mem[0] = 8'h12; + mem[1] = 8'h34; + mem[2] = 8'h56; + mem[3] = 8'h78; + + sel = 2'd0; + #1 `check(out, 8'h12); + + sel = 2'd1; + #1 `check(out, 8'h34); + + sel = 2'd2; + #1 `check(out, 8'h56); + + sel = 2'd3; + #1 `check(out, 8'h78); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/final_nested_block_task_fail.v b/ivtest/ivltests/final_nested_block_task_fail.v new file mode 100644 index 000000000..b19f918f5 --- /dev/null +++ b/ivtest/ivltests/final_nested_block_task_fail.v @@ -0,0 +1,12 @@ +// Check that final context is preserved when elaborating nested blocks. + +module test; + + task t; + endtask + + final begin : nested + t; + end + +endmodule diff --git a/ivtest/ivltests/func_nested_block_nb_fail.v b/ivtest/ivltests/func_nested_block_nb_fail.v new file mode 100644 index 000000000..ad1969eb8 --- /dev/null +++ b/ivtest/ivltests/func_nested_block_nb_fail.v @@ -0,0 +1,21 @@ +// Check that function context is preserved when elaborating nested blocks. + +module test; + + reg x; + integer y; + + function integer f; + input a; + begin : nested + x <= a; + f = 0; + end + endfunction + + initial begin + y = f(1'b1); + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/nb_ec_repeat_auto.v b/ivtest/ivltests/nb_ec_repeat_auto.v new file mode 100644 index 000000000..c9e7dff87 --- /dev/null +++ b/ivtest/ivltests/nb_ec_repeat_auto.v @@ -0,0 +1,46 @@ +// Check that non-blocking event control repeat counts can use automatic terms. + +module test; + + reg clk; + reg failed; + reg [3:0] result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + task automatic schedule_update; + input integer count; + begin + result <= repeat(count) @(posedge clk) 4'ha; + end + endtask + + always #5 clk = ~clk; + + initial begin + clk = 1'b0; + failed = 1'b0; + result = 4'h0; + + schedule_update(2); + + @(posedge clk); + #1; + `check(result, 4'h0); + + @(posedge clk); + #1; + `check(result, 4'ha); + + if (!failed) begin + $display("PASSED"); + end + $finish; + end + +endmodule diff --git a/ivtest/ivltests/param_string_compare.v b/ivtest/ivltests/param_string_compare.v new file mode 100644 index 000000000..61e1f81e6 --- /dev/null +++ b/ivtest/ivltests/param_string_compare.v @@ -0,0 +1,36 @@ +// Regression test: comparing a `string` parameter to a string constant of +// a different length must constant-fold cleanly instead of tripping the +// "lv.len() == rv.len()" assertion in the NetEBComp evaluation functions. +// Covers ==, !=, ===, !==, ==? and !=? with the string operand on either +// side and both shorter and longer than the other operand. + +module main #(parameter string Target = "A", + parameter string Long = "ABC"); + + integer errors = 0; + + // Equality / inequality, parameter shorter than the literal. + if (Target == "AA") initial begin errors += 1; $display("FAILED: Target == \"AA\""); end + if (Target != "A") initial begin errors += 1; $display("FAILED: Target != \"A\""); end + + // Literal on the left. + if ("AA" == Target) initial begin errors += 1; $display("FAILED: \"AA\" == Target"); end + + // Parameter longer than the literal. + if (Long == "AB") initial begin errors += 1; $display("FAILED: Long == \"AB\""); end + if (Long != "ABC") initial begin errors += 1; $display("FAILED: Long != \"ABC\""); end + + // Two string parameters of different lengths. + if (Target == Long) initial begin errors += 1; $display("FAILED: Target == Long"); end + + // Case equality. + if (Target === "AA") initial begin errors += 1; $display("FAILED: Target === \"AA\""); end + if (Target !== "A") initial begin errors += 1; $display("FAILED: Target !== \"A\""); end + + // Wildcard equality. + if (Target ==? "AA") initial begin errors += 1; $display("FAILED: Target ==? \"AA\""); end + if (Target !=? "A") initial begin errors += 1; $display("FAILED: Target !=? \"A\""); end + + initial #1 if (errors == 0) $display("PASSED"); + +endmodule diff --git a/ivtest/ivltests/real_delay_assign.v b/ivtest/ivltests/real_delay_assign.v new file mode 100644 index 000000000..a9d8c7231 --- /dev/null +++ b/ivtest/ivltests/real_delay_assign.v @@ -0,0 +1,20 @@ +// Check that blocking intra-assignment delays can assign real values. + +module test; + real r; + reg failed; + + initial begin + failed = 1'b0; + + r = #1 1.25; + if (r != 1.25) begin + $display("FAILED(%0d). Expected 1.25, got %0.2f", `__LINE__, r); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/real_negative_zero.v b/ivtest/ivltests/real_negative_zero.v new file mode 100644 index 000000000..03199005c --- /dev/null +++ b/ivtest/ivltests/real_negative_zero.v @@ -0,0 +1,35 @@ +// Check that the vvp code generator preserves the sign of a negative zero +// real constant. The sign used to be detected with (value < 0), which is +// false for IEEE 754 -0.0, so a -0.0 constant was emitted as +0.0 and the +// compiled value no longer matched the runtime real value. + +module test; + + real nz; + real pz; + + initial begin + nz = -0.0; + pz = 0.0; + + // The sign bit is the only thing that tells -0.0 from +0.0. + if ($realtobits(nz) !== 64'h8000_0000_0000_0000) begin + $display("FAILED: -0.0 stored as %h", $realtobits(nz)); + $finish; + end + + if ($realtobits(pz) !== 64'h0000_0000_0000_0000) begin + $display("FAILED: 0.0 stored as %h", $realtobits(pz)); + $finish; + end + + // The reciprocal makes the sign observable: 1.0/-0.0 is -inf. + if (1.0 / nz >= 0.0) begin + $display("FAILED: 1.0/-0.0 = %g", 1.0 / nz); + $finish; + end + + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/real_unary_minus_inf.v b/ivtest/ivltests/real_unary_minus_inf.v new file mode 100644 index 000000000..543644d68 --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_inf.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves infinities. + +module test; + + reg failed; + real inf; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + inf = $bitstoreal(64'h7ff0000000000000); + + result = -inf; + `check($realtobits(result), 64'hfff0000000000000); + + result = -result; + `check($realtobits(result), 64'h7ff0000000000000); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/real_unary_minus_nan.v b/ivtest/ivltests/real_unary_minus_nan.v new file mode 100644 index 000000000..f9ea679aa --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_nan.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves NaN bits. + +module test; + + reg failed; + real nan; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + nan = $bitstoreal(64'h7ff8000000000001); + + result = -nan; + `check($realtobits(result), 64'hfff8000000000001); + + result = -result; + `check($realtobits(result), 64'h7ff8000000000001); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/real_unary_minus_zero.v b/ivtest/ivltests/real_unary_minus_zero.v new file mode 100644 index 000000000..1c92bc27d --- /dev/null +++ b/ivtest/ivltests/real_unary_minus_zero.v @@ -0,0 +1,31 @@ +// Check that unary real minus preserves the sign of zero. + +module test; + + reg failed; + real zero; + real result; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %h, got %h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + zero = 0.0; + + result = -zero; + `check($realtobits(result), 64'h8000000000000000); + + result = -result; + `check($realtobits(result), 64'h0000000000000000); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_assign_pattern_auto_force_fail.v b/ivtest/ivltests/sv_assign_pattern_auto_force_fail.v new file mode 100644 index 000000000..d260e122b --- /dev/null +++ b/ivtest/ivltests/sv_assign_pattern_auto_force_fail.v @@ -0,0 +1,19 @@ +// Check that assignment patterns cannot reference automatic variables in +// procedural force statements. + +module test; + + reg [3:0] result; + + task automatic t; + input [3:0] value; + begin + force result = '{value[3], value[2], value[1], value[0]}; + end + endtask + + initial begin + t(4'ha); + end + +endmodule diff --git a/ivtest/ivltests/sv_bad_member_lval_proc_fail.v b/ivtest/ivltests/sv_bad_member_lval_proc_fail.v new file mode 100644 index 000000000..5b43b7afe --- /dev/null +++ b/ivtest/ivltests/sv_bad_member_lval_proc_fail.v @@ -0,0 +1,9 @@ +// Check that bogus member access on procedural l-values reports an error. + +module test; + logic r; + + initial begin + r.bad = 1'b1; + end +endmodule diff --git a/ivtest/ivltests/sv_call_chain_method1.v b/ivtest/ivltests/sv_call_chain_method1.v new file mode 100644 index 000000000..d6ba43dee --- /dev/null +++ b/ivtest/ivltests/sv_call_chain_method1.v @@ -0,0 +1,25 @@ +// Chained call: function returns class handle, then method on result (a().b()). + +module test; + + class C; + function int f; + f = 7; + endfunction + endclass + + function C get_c; + get_c = new; + endfunction + + initial begin + int x; + x = get_c().f(); + if (x !== 7) begin + $display("FAILED"); + end else begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_prop_class_name.v b/ivtest/ivltests/sv_class_prop_class_name.v new file mode 100644 index 000000000..2a8c768f7 --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_class_name.v @@ -0,0 +1,37 @@ +// Check that a class property can have the same name as the class. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + class C; + int C; + + function int get; + return C; + endfunction + endclass + + C obj; + + initial begin + obj = new; + + obj.C = 23; + + `check(obj.get(), 23); + `check(obj.C, 23); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_prop_packed_dims.v b/ivtest/ivltests/sv_class_prop_packed_dims.v new file mode 100644 index 000000000..05d97179e --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_packed_dims.v @@ -0,0 +1,40 @@ +// Check that multi-dimensional packed vector class properties are supported. + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0h, got %0h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + class C; + logic [1:0][3:0] x; + bit [0:1][0:3] y; + endclass + + C c; + + initial begin + c = new; + + c.x = 8'h5a; + c.y = 8'hc3; + `check(c.x, 8'h5a); + `check(c.y, 8'hc3); + + c.x += 8'h01; + c.y ^= 8'hff; + `check(c.x, 8'h5b); + `check(c.y, 8'h3c); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_prop_type_name.v b/ivtest/ivltests/sv_class_prop_type_name.v new file mode 100644 index 000000000..2ba13dea3 --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_type_name.v @@ -0,0 +1,39 @@ +// Check that a class property can have the same name as an outer type. + +module test; + + typedef int T; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + class C; + int T; + + function int get; + return T; + endfunction + endclass + + C obj; + + initial begin + obj = new; + + obj.T = 11; + + `check(obj.get(), 11); + `check(obj.T, 11); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_prop_wildcard_type_name.v b/ivtest/ivltests/sv_class_prop_wildcard_type_name.v new file mode 100644 index 000000000..f5a4a1762 --- /dev/null +++ b/ivtest/ivltests/sv_class_prop_wildcard_type_name.v @@ -0,0 +1,45 @@ +// Check that a class property can shadow a wildcard-imported type name. + +package P; + + typedef int T; + +endpackage + +module test; + + import P::*; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + class C; + int T; + + function int get; + return T; + endfunction + endclass + + C obj; + + initial begin + obj = new; + + obj.T = 47; + + `check(obj.get(), 47); + `check(obj.T, 47); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_class_queue_prop_methods.v b/ivtest/ivltests/sv_class_queue_prop_methods.v new file mode 100644 index 000000000..47d879bd7 --- /dev/null +++ b/ivtest/ivltests/sv_class_queue_prop_methods.v @@ -0,0 +1,39 @@ +// Regression: queue-typed class properties — push_front/push_back and +// pop_front/pop_back. (VVP asm must recognize %store/prop/qf/* and +// %qpop/prop/*; opcode_table must stay lexicographically sorted.) + +module test; + + bit failed = 1'b0; + + `define check(val, exp) do \ + if (val !== exp) begin \ + $display("FAILED(%0d). expected %0d, got %0d", `__LINE__, exp, val); \ + failed = 1'b1; \ + end \ + while(0) + + class C; + int q[$]; + endclass + + C c; + int t; + + initial begin + c = new; + c.q.push_back(1); + c.q.push_front(0); + c.q.push_back(2); + t = c.q.pop_back(); + `check(t, 32'd2); + `check(c.q.size(), 32'd2); + t = c.q.pop_front(); + `check(t, 32'd0); + `check(c.q[0], 32'd1); + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_class_task_expr_fail.v b/ivtest/ivltests/sv_class_task_expr_fail.v new file mode 100644 index 000000000..261f8135e --- /dev/null +++ b/ivtest/ivltests/sv_class_task_expr_fail.v @@ -0,0 +1,19 @@ +// Check that using a class task as an expression reports an error. + +module test; + + class C; + task t; + endtask + endclass + + C c; + + initial begin + int x; + c = new; + x = c.t(); + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_lval_idx_part_invalid_base_down_fail.v b/ivtest/ivltests/sv_lval_idx_part_invalid_base_down_fail.v new file mode 100644 index 000000000..769a76899 --- /dev/null +++ b/ivtest/ivltests/sv_lval_idx_part_invalid_base_down_fail.v @@ -0,0 +1,9 @@ +// Check that invalid indexed part-select l-value bases report an error. + +module test; + reg [31:0] a; + + initial begin + a[does_not_exist -: 2] = 2'b00; + end +endmodule diff --git a/ivtest/ivltests/sv_partsel_var_negative_packed.v b/ivtest/ivltests/sv_partsel_var_negative_packed.v new file mode 100644 index 000000000..bf9a28720 --- /dev/null +++ b/ivtest/ivltests/sv_partsel_var_negative_packed.v @@ -0,0 +1,33 @@ +// Check variable selects of packed arrays with negative bounds. + +module test; + + reg failed; + reg [-8:-1][3:0] a; + reg signed [2:0] i; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + a = '0; + + i = -1; + a[i] = 4'ha; + i = -2; + a[i] = 4'h5; + + `check(a[-1], 4'ha); + `check(a[-2], 4'h5); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_queue_ap_method.v b/ivtest/ivltests/sv_queue_ap_method.v new file mode 100644 index 000000000..41f174422 --- /dev/null +++ b/ivtest/ivltests/sv_queue_ap_method.v @@ -0,0 +1,33 @@ +// Check that assignment patterns are supported for queue method arguments. + +module test; + + bit failed; + bit [1:0][3:0] q[$]; + + `define check(val, exp) do begin \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0h, got %0h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end \ + end while (0) + + initial begin + failed = 1'b0; + + q.push_back('{4'h1, 4'h2}); + q.push_front('{4'h3, 4'h4}); + q.insert(1, '{4'h5, 4'h6}); + + `check(q.size(), 3); + `check(q[0], 8'h34); + `check(q[1], 8'h56); + `check(q[2], 8'h12); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_queue_method_insert_too_few_arg_fail.v b/ivtest/ivltests/sv_queue_method_insert_too_few_arg_fail.v new file mode 100644 index 000000000..b2cb9efe6 --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_insert_too_few_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue insert() rejects too few arguments. + +module test; + int q[$]; + + initial begin + q.insert(0); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_method_insert_too_many_arg_fail.v b/ivtest/ivltests/sv_queue_method_insert_too_many_arg_fail.v new file mode 100644 index 000000000..ceade7d15 --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_insert_too_many_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue insert() rejects too many arguments. + +module test; + int q[$]; + + initial begin + q.insert(0, 1, 2); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_method_push_back_too_few_arg_fail.v b/ivtest/ivltests/sv_queue_method_push_back_too_few_arg_fail.v new file mode 100644 index 000000000..374e03edc --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_push_back_too_few_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue push_back() rejects too few arguments. + +module test; + int q[$]; + + initial begin + q.push_back(); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_method_push_back_too_many_arg_fail.v b/ivtest/ivltests/sv_queue_method_push_back_too_many_arg_fail.v new file mode 100644 index 000000000..276004280 --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_push_back_too_many_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue push_back() rejects too many arguments. + +module test; + int q[$]; + + initial begin + q.push_back(1, 2); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_method_push_front_too_few_arg_fail.v b/ivtest/ivltests/sv_queue_method_push_front_too_few_arg_fail.v new file mode 100644 index 000000000..a82bcb3cd --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_push_front_too_few_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue push_front() rejects too few arguments. + +module test; + int q[$]; + + initial begin + q.push_front(); + end +endmodule diff --git a/ivtest/ivltests/sv_queue_method_push_front_too_many_arg_fail.v b/ivtest/ivltests/sv_queue_method_push_front_too_many_arg_fail.v new file mode 100644 index 000000000..f7862a21a --- /dev/null +++ b/ivtest/ivltests/sv_queue_method_push_front_too_many_arg_fail.v @@ -0,0 +1,9 @@ +// Check that queue push_front() rejects too many arguments. + +module test; + int q[$]; + + initial begin + q.push_front(1, 2); + end +endmodule diff --git a/ivtest/ivltests/sv_string_method_substr_too_few_arg_fail.v b/ivtest/ivltests/sv_string_method_substr_too_few_arg_fail.v new file mode 100644 index 000000000..d0a45e78e --- /dev/null +++ b/ivtest/ivltests/sv_string_method_substr_too_few_arg_fail.v @@ -0,0 +1,10 @@ +// Check that string substr() rejects too few arguments. + +module test; + string s; + string t; + + initial begin + t = s.substr(0); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_ams_name_fields.v b/ivtest/ivltests/sv_type_identifier_ams_name_fields.v new file mode 100644 index 000000000..d9569b764 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_ams_name_fields.v @@ -0,0 +1,18 @@ +// Check that nature name fields can shadow visible type identifiers. + +typedef int ACCESS_NAME; +typedef int IDT_NAME; +typedef int DDT_NAME; + +nature type_id_nature; + units = "V"; + access = ACCESS_NAME; + idt_nature = IDT_NAME; + ddt_nature = DDT_NAME; +endnature + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_attribute_name.v b/ivtest/ivltests/sv_type_identifier_attribute_name.v new file mode 100644 index 000000000..0e3654347 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_attribute_name.v @@ -0,0 +1,12 @@ +// Check that attribute names can match visible type identifiers. + +typedef int ATTR; + +(* ATTR = 1 *) +module test; + + initial begin + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_attribute_target.v b/ivtest/ivltests/sv_type_identifier_attribute_target.v new file mode 100644 index 000000000..5b5b5bef7 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_attribute_target.v @@ -0,0 +1,23 @@ +// Check that $attribute targets can match visible type identifiers. + +primitive ATTR_TYPE (out, in); + output out; + input in; + + table + 0 : 0; + 1 : 1; + endtable +endprimitive + +typedef int ATTR_TYPE; + +$attribute(ATTR_TYPE, "test", "true") + +module test; + + initial begin + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_block_label_name.v b/ivtest/ivltests/sv_type_identifier_block_label_name.v new file mode 100644 index 000000000..36dc7fc7c --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_block_label_name.v @@ -0,0 +1,28 @@ +// Check that block labels can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + reg value; + + initial begin + failed = 1'b0; + value = 0; + + begin : T + value = value + 1; + end : T + + if (value !== 1) begin + $display("FAILED(%0d). block labels did not hide typedefs", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_config_name.v b/ivtest/ivltests/sv_type_identifier_config_name.v new file mode 100644 index 000000000..e57962585 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_config_name.v @@ -0,0 +1,13 @@ +// Check that a config name can shadow a visible type identifier. + +typedef int CFG_NAME; + +config CFG_NAME; + design test; +endconfig + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_discipline_name.v b/ivtest/ivltests/sv_type_identifier_discipline_name.v new file mode 100644 index 000000000..a0615de42 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_discipline_name.v @@ -0,0 +1,25 @@ +// Check that discipline names can match visible type identifiers. + +nature potential_nature; + units = "V"; + access = POTENTIAL_ACCESS; +endnature + +nature flow_nature; + units = "A"; + access = FLOW_ACCESS; +endnature + +typedef int DISCIPLINE_NAME; + +discipline DISCIPLINE_NAME; + potential potential_nature; + flow flow_nature; + domain continuous; +enddiscipline + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_discipline_nature_ref.v b/ivtest/ivltests/sv_type_identifier_discipline_nature_ref.v new file mode 100644 index 000000000..24c9a6cba --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_discipline_nature_ref.v @@ -0,0 +1,26 @@ +// Check that discipline nature references can match visible type identifiers. + +nature potential_nature; + units = "V"; + access = POTENTIAL_ACCESS; +endnature + +nature flow_nature; + units = "A"; + access = FLOW_ACCESS; +endnature + +typedef int potential_nature; +typedef int flow_nature; + +discipline electrical; + potential potential_nature; + flow flow_nature; + domain continuous; +enddiscipline + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_enum_item_name.v b/ivtest/ivltests/sv_type_identifier_enum_item_name.v new file mode 100644 index 000000000..9be765a20 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_enum_item_name.v @@ -0,0 +1,40 @@ +// Check that enum item names can shadow visible type identifiers. + +typedef int T; +typedef int U; +typedef int V; + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + enum { + T = 3, + U[2] = 5, + V[3:4] = 9 + } e; + + initial begin + failed = 1'b0; + + e = T; + + `check(e, 3, "Enum item name did not hide typedef"); + `check(U0, 5, "Enum item sequence name did not hide typedef"); + `check(U1, 6, "Enum item sequence value mismatch"); + `check(V3, 9, "Enum item range name did not hide typedef"); + `check(V4, 10, "Enum item range value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_event_name.v b/ivtest/ivltests/sv_type_identifier_event_name.v new file mode 100644 index 000000000..b6937562c --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_event_name.v @@ -0,0 +1,31 @@ +// Check that event names can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + reg seen; + + event T; + + initial begin + failed = 1'b0; + seen = 1'b0; + + #1 -> T; + #1; + + if (seen !== 1'b1) begin + $display("FAILED(%0d). Event T was not triggered", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + + always @T seen = 1'b1; + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_for_name.v b/ivtest/ivltests/sv_type_identifier_for_name.v new file mode 100644 index 000000000..2963e6a33 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_for_name.v @@ -0,0 +1,32 @@ +// Check that for loop variables can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + int unsigned values [3]; + + initial begin + int unsigned total; + + failed = 1'b0; + total = 0; + + for (int unsigned T = 0; T < 3; T += 1) begin + total += T; + values[T] = 10 + T; + end + + if (total != 3 || values[0] != 10 || + values[1] != 11 || values[2] != 12) begin + $display("FAILED(%0d). for loop variable did not hide typedef", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_foreach_array_name.v b/ivtest/ivltests/sv_type_identifier_foreach_array_name.v new file mode 100644 index 000000000..8a76ebae6 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_foreach_array_name.v @@ -0,0 +1,25 @@ +// Check that foreach array expressions can shadow visible type identifiers. + +typedef int A; + +module test; + + reg failed; + + initial begin + failed = 1'b0; + + // The array declaration follows the foreach loop, so the lexer only sees + // the visible typedef when parsing the array expression name. + foreach (A[]) begin + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + + int unsigned A [3]; + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_foreach_name.v b/ivtest/ivltests/sv_type_identifier_foreach_name.v new file mode 100644 index 000000000..351326619 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_foreach_name.v @@ -0,0 +1,29 @@ +// Check that foreach loop variables can shadow visible type identifiers. + +typedef int I; +typedef int J; + +module test; + + reg failed; + int array [2][2]; + + initial begin + failed = 1'b0; + + foreach (array[I,J]) begin + array[I][J] = I * 10 + J; + end + + if (array[0][0] != 0 || array[0][1] != 1 || + array[1][0] != 10 || array[1][1] != 11) begin + $display("FAILED(%0d). foreach indices did not hide typedefs", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_fork_label_name.v b/ivtest/ivltests/sv_type_identifier_fork_label_name.v new file mode 100644 index 000000000..507312c78 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_fork_label_name.v @@ -0,0 +1,28 @@ +// Check that fork block labels can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + reg value; + + initial begin + failed = 1'b0; + value = 1'b0; + + fork : T + value = 1'b1; + join : T + + if (value !== 1'b1) begin + $display("FAILED(%0d). fork label did not hide typedef", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_function_name.v b/ivtest/ivltests/sv_type_identifier_function_name.v new file mode 100644 index 000000000..eba36bfd8 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_function_name.v @@ -0,0 +1,51 @@ +// Check that function names can shadow visible type identifiers. + +typedef int T; +typedef int U; + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + function int T(input int value); + return value + 32'd1; + endfunction + + function U; + U = 1'b1; + endfunction + + class C; + function int T(input int value); + return value + 32'd2; + endfunction + + function int C(input int value); + return value + 32'd3; + endfunction + endclass + + initial begin + C c; + + failed = 1'b0; + c = new; + + `check(T(32'd41), 32'd42, "Function name did not hide typedef"); + `check(U(), 1'b1, "Implicit function name did not hide typedef"); + `check(c.T(32'd40), 32'd42, "Class function name did not hide typedef"); + `check(c.C(32'd39), 32'd42, "Class function name did not hide class name"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_generate_label_name.v b/ivtest/ivltests/sv_type_identifier_generate_label_name.v new file mode 100644 index 000000000..01ac046e8 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_generate_label_name.v @@ -0,0 +1,25 @@ +// Check that generate block labels can shadow visible type identifiers. + +typedef int G; +module test; + + reg failed; + + if (1) begin : G + localparam int VALUE = 1; + end : G + + initial begin + failed = 1'b0; + + if (G.VALUE != 1) begin + $display("FAILED(%0d). generate labels did not hide typedefs", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_genvar_name.v b/ivtest/ivltests/sv_type_identifier_genvar_name.v new file mode 100644 index 000000000..499a25712 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_genvar_name.v @@ -0,0 +1,27 @@ +// Check that a genvar name can shadow a visible type identifier. + +typedef int G; + +module test; + reg failed; + + genvar G; + generate + for (G = 0; G < 2; G = G + 1) begin : gen_block + localparam int VALUE = G; + end + endgenerate + + initial begin + failed = 1'b0; + + if (gen_block[0].VALUE != 0 || gen_block[1].VALUE != 1) begin + $display("FAILED(%0d). genvar name did not hide typedef", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_modport_name.v b/ivtest/ivltests/sv_type_identifier_modport_name.v new file mode 100644 index 000000000..f58feab4c --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_modport_name.v @@ -0,0 +1,19 @@ +// Check that a modport name can shadow a visible type identifier. + +typedef int M; + +interface type_id_modport_ifc; + logic value; + + modport M(input value); +endinterface + +module test; + + type_id_modport_ifc i_ifc(); + + initial begin + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_modport_named_port.v b/ivtest/ivltests/sv_type_identifier_modport_named_port.v new file mode 100644 index 000000000..53e6adbfd --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_modport_named_port.v @@ -0,0 +1,18 @@ +// Check that a modport simple port selector can shadow a visible typedef name. + +interface I; + typedef int T; + logic value; + + modport m(input .T(value)); +endinterface + +module test; + + I i(); + + initial begin + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_module_name.v b/ivtest/ivltests/sv_type_identifier_module_name.v new file mode 100644 index 000000000..57425f2e6 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_module_name.v @@ -0,0 +1,17 @@ +// Check that a module name can shadow a visible type identifier. + +package p; + typedef int M; +endpackage + +import p::*; + +module M; + initial begin + $display("PASSED"); + end +endmodule + +module test; + M i(); +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_named_constructor_argument.v b/ivtest/ivltests/sv_type_identifier_named_constructor_argument.v new file mode 100644 index 000000000..8bbc0f298 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_named_constructor_argument.v @@ -0,0 +1,36 @@ +// Check that a named constructor argument selector can match a visible typedef name. + +module test; + + class C; + integer value; + + function new(input integer T, input integer B); + value = T + B; + endfunction + endclass + + typedef int T; + + reg failed; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + C c; + + failed = 1'b0; + c = new(.T(40), .B(2)); + `check(c.value, 42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_named_function_argument.v b/ivtest/ivltests/sv_type_identifier_named_function_argument.v new file mode 100644 index 000000000..d193a241f --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_named_function_argument.v @@ -0,0 +1,31 @@ +// Check that a named function argument selector can match a visible typedef name. + +module test; + + function integer f(input integer T, input integer B); + f = T + B; + endfunction + + typedef int T; + + reg failed; + integer value; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + value = f(.T(40), .B(2)); + `check(value, 42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_named_parameter_value.v b/ivtest/ivltests/sv_type_identifier_named_parameter_value.v new file mode 100644 index 000000000..d448253de --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_named_parameter_value.v @@ -0,0 +1,33 @@ +// Check that a named parameter override selector can match a visible typedef name. + +module M #(parameter integer T = 0) (output [31:0] Y); + assign Y = T; +endmodule + +module test; + + typedef int T; + + reg failed; + wire [31:0] y; + + M #(.T(32'd42)) i_m(.Y(y)); + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + #1; + `check(y, 32'd42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_named_port_connection.v b/ivtest/ivltests/sv_type_identifier_named_port_connection.v new file mode 100644 index 000000000..be9ed82ff --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_named_port_connection.v @@ -0,0 +1,35 @@ +// Check that a named port connection selector can match a visible typedef name. + +module M(input [3:0] T, output [3:0] Y); + assign Y = T; +endmodule + +module test; + + typedef int T; + + reg failed; + reg [3:0] value; + wire [3:0] y; + + M i_m(.T(value), .Y(y)); + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0h, got %0h", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + value = 4'ha; + #1; + `check(y, 4'ha); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_named_task_argument.v b/ivtest/ivltests/sv_type_identifier_named_task_argument.v new file mode 100644 index 000000000..0ee84ae4f --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_named_task_argument.v @@ -0,0 +1,31 @@ +// Check that a named task argument selector can match a visible typedef name. + +module test; + + task t(input integer T, output integer result); + result = T; + endtask + + typedef int T; + + reg failed; + integer value; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + t(.T(42), .result(value)); + `check(value, 42); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_nature_name.v b/ivtest/ivltests/sv_type_identifier_nature_name.v new file mode 100644 index 000000000..1d2a9e174 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_nature_name.v @@ -0,0 +1,14 @@ +// Check that nature names can match visible type identifiers. + +typedef int NATURE_NAME; + +nature NATURE_NAME; + units = "V"; + access = NATURE_ACCESS; +endnature + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_net_name.v b/ivtest/ivltests/sv_type_identifier_net_name.v new file mode 100644 index 000000000..c92883ea0 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_net_name.v @@ -0,0 +1,103 @@ +// Check that net names can shadow visible type identifiers. + +typedef logic [7:0] T; +typedef int U; +typedef logic [5:0] V; + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module net_name(output reg failed); + wire T = 1'b1; + + initial begin + failed = 1'b0; + + `check(T, 1'b1, "wire T did not declare a one-bit net"); + end +endmodule + +module net_list(output reg failed); + wire T, U; + + assign T = 1'b0; + assign U = 1'b1; + + initial begin + failed = 1'b0; + + `check(T, 1'b0, "type identifier net list first value mismatch"); + `check(U, 1'b1, "type identifier net list continuation mismatch"); + end +endmodule + +module net_array(output reg failed); + wire T [1:0]; + + assign T[0] = 1'b0; + assign T[1] = 1'b1; + + initial begin + failed = 1'b0; + + `check(T[0], 1'b0, "type identifier net array first value mismatch"); + `check(T[1], 1'b1, "type identifier net array second value mismatch"); + end +endmodule + +module net_type(output reg failed); + wire T x = 8'ha5; + wire T [1:0] y = 16'h5aa5; + wire V v0, V; + wire T T; + + assign v0 = 6'h2a; + assign V = 6'h15; + assign T = 8'h3c; + + initial begin + failed = 1'b0; + + `check($bits(x), 8, "typed net declaration width regressed"); + `check(x, 8'ha5, "typed net declaration value regressed"); + `check($bits(y), 16, "typed packed net declaration width regressed"); + `check(y, 16'h5aa5, "typed packed net declaration value regressed"); + `check($bits(v0), 6, "type identifier net declaration list first width mismatch"); + `check($bits(V), 6, "type identifier net declaration list did not allow typedef name as continuation"); + `check(V, 6'h15, "type identifier net declaration list value mismatch"); + `check($bits(T), 8, "type-name net declaration did not keep typedef type"); + `check(T, 8'h3c, "type-name net declaration value mismatch"); + end +endmodule + +module test; + reg failed; + wire f0; + wire f1; + wire f2; + wire f3; + + net_name m0(f0); + net_list m1(f1); + net_array m2(f2); + net_type m3(f3); + + initial begin + failed = 1'b0; + + #1; + + `check(f0, 1'b0, "wire T module failed"); + `check(f1, 1'b0, "wire T, U module failed"); + `check(f2, 1'b0, "wire T array module failed"); + `check(f3, 1'b0, "typed wire T module failed"); + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_package_item.v b/ivtest/ivltests/sv_type_identifier_package_item.v new file mode 100644 index 000000000..d64259aec --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_package_item.v @@ -0,0 +1,31 @@ +// Check that package import and export items can name a type identifier. + +package type_id_name_pkg; + typedef logic [3:0] T; +endpackage + +package type_id_name_export_pkg; + import type_id_name_pkg::T; + export type_id_name_pkg::T; +endpackage + +module test; + import type_id_name_export_pkg::T; + + reg failed; + T value; + + initial begin + failed = 1'b0; + value = 4'ha; + + if ($bits(value) != 4 || value != 4'ha) begin + $display("FAILED(%0d). Imported type mismatch", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_package_name.v b/ivtest/ivltests/sv_type_identifier_package_name.v new file mode 100644 index 000000000..3a470d562 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_package_name.v @@ -0,0 +1,30 @@ +// Check that package names can shadow visible type identifiers. + +package p; + typedef int T; +endpackage + +import p::*; + +package T; + parameter int VALUE = 23; +endpackage + +module test; + + reg failed; + + initial begin + failed = 1'b0; + + if (T::VALUE !== 23) begin + $display("FAILED(%0d). Package name did not hide typedef", `__LINE__); + failed = 1'b1; + end + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v b/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v new file mode 100644 index 000000000..f303cfcf1 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v @@ -0,0 +1,35 @@ +// Check that parameter declaration names can shadow visible type identifiers. + +typedef int L; +typedef int P; +typedef int Q; +typedef int R; + +module test; + + reg failed; + + parameter P = 7, R = 13; + localparam Q = 11, L = 17; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(P, 7, "parameter name did not hide typedef"); + `check(R, 13, "parameter list continuation did not hide typedef"); + `check(Q, 11, "localparam name did not hide typedef"); + `check(L, 17, "localparam list continuation did not hide typedef"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_port_name.v b/ivtest/ivltests/sv_type_identifier_parameter_port_name.v new file mode 100644 index 000000000..76429bebd --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_port_name.v @@ -0,0 +1,85 @@ +// Check that parameter port declaration names can shadow visible type identifiers. + +typedef int P; +typedef int Q; +typedef int R; +typedef logic [7:0] T; +typedef int TP; + +package p; + typedef logic [5:0] PT; +endpackage + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module M #( + parameter int P = 5, + Q = 9, + int R = 13, + T typed_value = 8'ha5, + T T = 8'h3c, + p::PT pkg_value = 6'h2a, + parameter type TP = logic [5:0] +) (output reg failed); + + TP type_param_value; + + initial begin + failed = 1'b0; + type_param_value = 6'h15; + + `check(P, 5, "parameter port typed value mismatch"); + `check(Q, 9, "parameter port untyped continuation mismatch"); + `check(R, 13, "parameter port atomic type continuation mismatch"); + `check($bits(typed_value), 8, "parameter port typedef type continuation width mismatch"); + `check(typed_value, 8'ha5, "parameter port typedef type continuation value mismatch"); + `check($bits(T), 8, "parameter port type-name continuation did not keep typedef type"); + `check(T, 8'h3c, "parameter port type-name continuation value mismatch"); + `check($bits(pkg_value), 6, "parameter port package type continuation width mismatch"); + `check(pkg_value, 6'h2a, "parameter port package type continuation value mismatch"); + `check($bits(type_param_value), 6, "parameter port type parameter mismatch"); + `check(type_param_value, 6'h15, "parameter port type parameter value mismatch"); + end + +endmodule + +module N #(P = 3, T typed_value = 8'h5a) (output reg failed); + + initial begin + failed = 1'b0; + + `check(P, 3, "omitted parameter keyword mismatch"); + `check($bits(typed_value), 8, "omitted parameter keyword typedef width mismatch"); + `check(typed_value, 8'h5a, "omitted parameter keyword typedef value mismatch"); + end + +endmodule + +module test; + + reg failed; + wire failed_m; + wire failed_n; + + M i_m(failed_m); + N i_n(failed_n); + + initial begin + failed = 1'b0; + + #1; + + `check(failed_m, 1'b0, "parameter port module failed"); + `check(failed_n, 1'b0, "omitted parameter keyword module failed"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v b/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v new file mode 100644 index 000000000..857dff533 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v @@ -0,0 +1,41 @@ +// Check that typed parameter declaration names can shadow visible type identifiers. + +typedef int P; +typedef logic [7:0] T; +typedef logic [6:0] U; + +module test; + + reg failed; + + parameter int P = 13; + parameter T typed_value = 8'ha5; + parameter T T = 8'h3c; + parameter U u0 = 7'h2a, U = 7'h15; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(P, 13, "typed parameter name did not hide typedef"); + `check($bits(typed_value), 8, "typed parameter width mismatch"); + `check(typed_value, 8'ha5, "typed parameter value mismatch"); + `check($bits(T), 8, "type-name parameter did not keep typedef type"); + `check(T, 8'h3c, "type-name parameter value mismatch"); + `check($bits(u0), 7, "parameter list first declaration did not keep typedef type"); + `check(u0, 7'h2a, "parameter list first value mismatch"); + `check($bits(U), 7, "parameter list continuation did not allow typedef name as parameter name"); + `check(U, 7'h15, "parameter list continuation value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v b/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v new file mode 100644 index 000000000..2494d7b48 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v @@ -0,0 +1,32 @@ +// Check that type parameter declaration names can shadow visible type identifiers. + +typedef int TP; + +module test; + + reg failed; + + parameter type TP = logic [3:0]; + + TP type_param_value; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + type_param_value = 4'hc; + + `check($bits(type_param_value), 4, "type parameter name did not hide typedef"); + `check(type_param_value, 4'hc, "type parameter value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_port_name.v b/ivtest/ivltests/sv_type_identifier_port_name.v new file mode 100644 index 000000000..b5a8f5b41 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_port_name.v @@ -0,0 +1,236 @@ +// Check that module port names can shadow visible type identifiers. + +typedef logic [3:0] T; + +package p; + typedef logic [5:0] PT; +endpackage + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module ansi_name(input T); +endmodule + +module ansi_type(input T x); +endmodule + +module ansi_name_dim(input T [1:0]); +endmodule + +module ansi_type_dim(input T [1:0] x); +endmodule + +module ansi_name_list(input T, U); +endmodule + +module ansi_type_list(input T x, y); +endmodule + +module ansi_type_list_shadow(input T x, T); +endmodule + +module ansi_type_name(input T T, output logic ok); + initial ok = ($bits(T) == 4); +endmodule + +module ansi_type_redecl(input n, T x); +endmodule + +module ansi_type_redecl_dim(input n, T [1:0] x); +endmodule + +module ansi_name_redecl_dim(input n, T [1:0]); +endmodule + +module ansi_pkg_type_redecl(input n, p::PT x); +endmodule + +module ansi_pkg_type_redecl_dim(input n, p::PT [1:0] x); +endmodule + +module decl_name(T); + input T; +endmodule + +module decl_type(x); + input T x; +endmodule + +module decl_type_dim(x); + input T [1:0] x; +endmodule + +module decl_external(.T(x)); + input x; +endmodule + +module decl_name_list(T, U); + input T, U; +endmodule + +module decl_type_list(x, y); + input T x, y; +endmodule + +module decl_type_list_shadow(x, T); + input T x, T; +endmodule + +module decl_type_name(T, ok); + input T T; + output logic ok; + + initial ok = ($bits(T) == 4); +endmodule + +module test; + + reg failed; + logic n; + T t; + logic n_dim [1:0]; + T [1:0] t_dim; + logic n0, n1; + T t0, t1; + logic rn; + T rt; + T [1:0] rt_dim; + logic rn_dim; + logic rt_name_dim [1:0]; + logic rp_n; + logic [5:0] rp_t; + logic rp_dim_n; + logic [1:0][5:0] rp_t_dim; + logic d_n; + T d_t; + T [1:0] d_t_dim; + logic d_ext; + logic d_n0, d_n1; + T d_t0, d_t1; + T s_t0, s_t1; + T d_s_t0, d_s_t1; + T p_tn; + T d_p_tn; + logic p_tn_ok; + logic d_p_tn_ok; + + ansi_name m0(n); + ansi_type m1(t); + ansi_name_dim m2(n_dim); + ansi_type_dim m3(t_dim); + ansi_name_list m4(n0, n1); + ansi_type_list m5(t0, t1); + ansi_type_list_shadow m17(s_t0, s_t1); + ansi_type_name m19(p_tn, p_tn_ok); + ansi_type_redecl m12(rn, rt); + ansi_type_redecl_dim m13(rn, rt_dim); + ansi_name_redecl_dim m14(rn_dim, rt_name_dim); + ansi_pkg_type_redecl m15(rp_n, rp_t); + ansi_pkg_type_redecl_dim m16(rp_dim_n, rp_t_dim); + decl_name m6(d_n); + decl_type m7(d_t); + decl_type_dim m8(d_t_dim); + decl_external m9(d_ext); + decl_name_list m10(d_n0, d_n1); + decl_type_list m11(d_t0, d_t1); + decl_type_list_shadow m18(d_s_t0, d_s_t1); + decl_type_name m20(d_p_tn, d_p_tn_ok); + + initial begin + failed = 1'b0; + + n = 1'b1; + t = 4'ha; + n_dim[0] = 1'b0; + n_dim[1] = 1'b1; + t_dim[0] = 4'h3; + t_dim[1] = 4'hc; + n0 = 1'b0; + n1 = 1'b1; + t0 = 4'h5; + t1 = 4'ha; + s_t0 = 4'h6; + s_t1 = 4'h9; + p_tn = 4'h3; + rn = 1'b1; + rt = 4'hc; + rt_dim[0] = 4'h3; + rt_dim[1] = 4'ha; + rn_dim = 1'b0; + rt_name_dim[0] = 1'b1; + rt_name_dim[1] = 1'b0; + rp_n = 1'b1; + rp_t = 6'h2a; + rp_dim_n = 1'b0; + rp_t_dim[0] = 6'h15; + rp_t_dim[1] = 6'h2a; + d_n = 1'b1; + d_t = 4'h6; + d_t_dim[0] = 4'h7; + d_t_dim[1] = 4'h8; + d_ext = 1'b0; + d_n0 = 1'b1; + d_n1 = 1'b0; + d_t0 = 4'h9; + d_t1 = 4'h6; + d_s_t0 = 4'h5; + d_s_t1 = 4'ha; + d_p_tn = 4'hc; + + #1; + + `check($bits(n), 1, "input T was not parsed as a port name"); + `check($bits(t), 4, "input T x was not parsed as a typed port"); + `check($bits(n_dim), 2, "input T [1:0] was not parsed as a port array"); + `check($bits(t_dim), 8, "input T [1:0] x was not parsed as a typed port array"); + `check($bits(n0), 1, "input T, U first port did not keep implicit type"); + `check($bits(n1), 1, "input T, U continuation did not keep implicit type"); + `check($bits(t0), 4, "input T x, y first port did not keep typedef type"); + `check($bits(t1), 4, "input T x, y continuation did not keep typedef type"); + `check(t0, 4'h5, "Typed port list first value mismatch"); + `check(t1, 4'ha, "Typed port list continuation mismatch"); + `check($bits(s_t0), 4, "input T x, T first port did not keep typedef type"); + `check($bits(s_t1), 4, "input T x, T continuation did not allow typedef name as port name"); + `check(s_t1, 4'h9, "Typed port list shadowing value mismatch"); + `check($bits(p_tn), 4, "input T T did not keep typedef type"); + `check(p_tn_ok, 1'b1, "input T T was not available as a typed port"); + `check($bits(rn), 1, "input n, T x first port did not keep implicit type"); + `check($bits(rt), 4, "input n, T x second port did not keep typedef type"); + `check(rt, 4'hc, "Inherited-direction typedef port value mismatch"); + `check($bits(rt_dim), 8, "input n, T [1:0] x did not keep typedef packed dimensions"); + `check(rt_dim[0], 4'h3, "Inherited-direction typedef packed array value mismatch"); + `check(rt_dim[1], 4'ha, "Inherited-direction typedef packed array value mismatch"); + `check($bits(rn_dim), 1, "input n, T [1:0] first port did not keep implicit type"); + `check($bits(rt_name_dim), 2, "input n, T [1:0] second port was not parsed as a port array"); + `check($bits(rp_t), 6, "input n, p::PT x second port did not keep package typedef type"); + `check(rp_t, 6'h2a, "Inherited-direction package typedef port value mismatch"); + `check($bits(rp_t_dim), 12, "input n, p::PT [1:0] x did not keep package typedef packed dimensions"); + `check(rp_t_dim[0], 6'h15, "Inherited-direction package typedef packed array value mismatch"); + `check(rp_t_dim[1], 6'h2a, "Inherited-direction package typedef packed array value mismatch"); + `check($bits(d_n), 1, "input T was not parsed as a port declaration name"); + `check($bits(d_t), 4, "input T x was not parsed as a typed port declaration"); + `check($bits(d_t_dim), 8, "input T [1:0] x was not parsed as a typed port declaration array"); + `check($bits(d_ext), 1, ".T(x) was not parsed as an external port name"); + `check($bits(d_n0), 1, "input T, U first declaration did not keep implicit type"); + `check($bits(d_n1), 1, "input T, U continuation declaration did not keep implicit type"); + `check($bits(d_t0), 4, "input T x, y first declaration did not keep typedef type"); + `check($bits(d_t1), 4, "input T x, y continuation declaration did not keep typedef type"); + `check(d_t0, 4'h9, "Typed port declaration list first value mismatch"); + `check(d_t1, 4'h6, "Typed port declaration list continuation mismatch"); + `check($bits(d_s_t0), 4, "input T x, T first declaration did not keep typedef type"); + `check($bits(d_s_t1), 4, "input T x, T declaration did not allow typedef name as port name"); + `check(d_s_t1, 4'ha, "Typed port declaration list shadowing value mismatch"); + `check($bits(d_p_tn), 4, "non-ANSI input T T did not keep typedef type"); + `check(d_p_tn_ok, 1'b1, "non-ANSI input T T was not available as a typed port"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_specparam_name.v b/ivtest/ivltests/sv_type_identifier_specparam_name.v new file mode 100644 index 000000000..16572d095 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_specparam_name.v @@ -0,0 +1,14 @@ +// Check that a specparam name can shadow a visible type identifier. + +typedef int SP_DELAY; + +module test(input in, output out); + specify + specparam SP_DELAY = 1; + (in => out) = SP_DELAY; + endspecify + + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v b/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v new file mode 100644 index 000000000..835c84b82 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_task_function_argument_name.v @@ -0,0 +1,120 @@ +// Check that task and function argument names can shadow visible type identifiers. + +typedef int T; + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + function int f_name(input T); + return ($bits(T) == 1 && T === 1'b1) ? 32'd33 : -1; + endfunction + + function int f_type(input T value); + return ($bits(value) == 32) ? value : -1; + endfunction + + function int f_type_list(input T value, T); + return $bits(value) + $bits(T); + endfunction + + function int f_type_name(input T T); + return $bits(T); + endfunction + + function int f_decl_name; + input T; + return $bits(T); + endfunction + + function int f_decl_type; + input T value; + return $bits(value); + endfunction + + function int f_decl_type_name; + input T T; + return $bits(T); + endfunction + + task t_name(input T, output int value); + value = ($bits(T) == 1 && T === 1'b1) ? 32'd44 : -1; + endtask + + task t_type(input T value, output int result); + result = ($bits(value) == 32) ? value : -1; + endtask + + task t_type_list(input T value, T, output int result); + result = $bits(value) + $bits(T); + endtask + + task t_type_name(input T T, output int value); + value = $bits(T); + endtask + + task t_decl_name; + input T; + output int value; + value = $bits(T); + endtask + + task t_decl_type; + input T value; + output int result; + result = $bits(value); + endtask + + task t_decl_type_name; + input T T; + output int value; + value = $bits(T); + endtask + + initial begin + int r0; + int r1; + int r2; + int r3; + int r4; + int r5; + int r6; + + failed = 1'b0; + + t_name(1'b1, r0); + t_type(32'd55, r1); + t_type_list(32'd11, 32'd22, r2); + t_decl_name(1'b1, r3); + t_decl_type(32'd33, r4); + t_type_name(32'd44, r5); + t_decl_type_name(32'd55, r6); + + `check(f_name(1'b1), 32'd33, "Function argument did not hide typedef"); + `check(f_type(32'd66), 32'd66, "Function typed argument regressed"); + `check(f_type_list(32'd11, 32'd22), 64, "Function typed argument list shadowing mismatch"); + `check(f_type_name(32'd33), 32, "Function type-name argument did not keep typedef type"); + `check(f_decl_name(1'b1), 1, "Function non-ANSI argument did not hide typedef"); + `check(f_decl_type(32'd66), 32, "Function non-ANSI typed argument regressed"); + `check(f_decl_type_name(32'd77), 32, "Function non-ANSI type-name argument did not keep typedef type"); + `check(r0, 32'd44, "Task argument did not hide typedef"); + `check(r1, 32'd55, "Task typed argument regressed"); + `check(r2, 64, "Task typed argument list shadowing mismatch"); + `check(r3, 1, "Task non-ANSI argument did not hide typedef"); + `check(r4, 32, "Task non-ANSI typed argument regressed"); + `check(r5, 32, "Task type-name argument did not keep typedef type"); + `check(r6, 32, "Task non-ANSI type-name argument did not keep typedef type"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_task_name.v b/ivtest/ivltests/sv_type_identifier_task_name.v new file mode 100644 index 000000000..fefcbfc98 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_task_name.v @@ -0,0 +1,62 @@ +// Check that task names can shadow visible type identifiers. + +typedef int T; +typedef int U; + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + task T(input int value, output int result); + result = value + 32'd1; + endtask + + task U; + output int result; + + result = 32'd33; + endtask + + class C; + task T(input int value, output int result); + result = value + 32'd2; + endtask + + task C(input int value, output int result); + result = value + 32'd3; + endtask + endclass + + initial begin + C c; + int r0; + int r1; + int r2; + int r3; + + failed = 1'b0; + c = new; + + T(32'd41, r0); + U(r1); + c.T(32'd40, r2); + c.C(32'd39, r3); + + `check(r0, 32'd42, "Task name did not hide typedef"); + `check(r1, 32'd33, "Non-ANSI task name did not hide typedef"); + `check(r2, 32'd42, "Class task name did not hide typedef"); + `check(r3, 32'd42, "Class task name did not hide class name"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_udp_ansi_name.v b/ivtest/ivltests/sv_type_identifier_udp_ansi_name.v new file mode 100644 index 000000000..4b44eee0d --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_udp_ansi_name.v @@ -0,0 +1,25 @@ +// Check that ANSI-style UDP names can shadow visible type identifiers. + +package p; + typedef int ANSI_UDP; + typedef int Y; + typedef int I0; + typedef int I1; +endpackage + +import p::*; + +primitive ANSI_UDP (output Y, input I0, input I1); + table + 00 : 0; + 01 : 0; + 10 : 0; + 11 : 1; + endtable +endprimitive + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_udp_name.v b/ivtest/ivltests/sv_type_identifier_udp_name.v new file mode 100644 index 000000000..666dd4053 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_udp_name.v @@ -0,0 +1,29 @@ +// Check that old-style UDP names can shadow visible type identifiers. + +package p; + typedef int OLD_UDP; + typedef int Q; + typedef int A; + typedef int B; +endpackage + +import p::*; + +primitive OLD_UDP (Q, A, B); + output reg Q; + input A, B; + initial Q = 0; + + table + 00 : ? : 0; + 01 : ? : 0; + 10 : ? : 0; + 11 : ? : 1; + endtable +endprimitive + +module test; + initial begin + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_variable_name.v b/ivtest/ivltests/sv_type_identifier_variable_name.v new file mode 100644 index 000000000..c4fadae33 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_variable_name.v @@ -0,0 +1,152 @@ +// Check that variable names can shadow visible type identifiers. + +typedef logic [7:0] T; +typedef int V; +typedef int W; +typedef logic [6:0] A; +typedef logic [5:0] B; +typedef logic [4:0] C; +typedef logic [3:0] D; +typedef logic [2:0] E; +typedef logic [1:0] F; +typedef logic [2:0] G; +typedef logic [3:0] H; +typedef logic [4:0] I; +typedef logic [2:0] P; +bit X; + +package p; + var C; + var D x, D; + var P P; +endpackage + +module test; + + reg failed; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + typedef logic [3:0] X; + + T outer; + T a, b; + A a0, A; + E E; + int T, U; + var V; + var B b0, B; + var F F; + X x; + + function int f; + int T; + + T = 32'd11; + return T; + endfunction + + function int f_type_name; + H H; + + H = 4'ha; + return $bits(H) + H; + endfunction + + task t(output int value); + int T; + + T = 32'd22; + value = T; + endtask + + task t_type_name(output int value); + I I; + + I = 5'h15; + value = $bits(I) + I; + endtask + + initial begin + int r; + int r_type_name; + int tr_type_name; + var W; + + failed = 1'b0; + + outer = 8'ha5; + a = 8'h33; + b = 8'hcc; + a0 = 7'h2a; + A = 7'h15; + E = 3'h5; + T = 32'd23; + U = 32'd41; + V = 1'b1; + b0 = 6'h2a; + B = 6'h15; + F = 2'h2; + W = 1'b0; + x = 4'hc; + t(r); + t_type_name(tr_type_name); + + begin : block_scope + int T; + + T = 32'd7; + `check(T, 32'd7, "Block declaration did not hide typedef"); + end + + begin : block_type_name + G G; + + G = 3'h3; + `check($bits(G), 3, "Block type-name declaration did not keep typedef type"); + `check(G, 3'h3, "Block type-name declaration value mismatch"); + end + + r_type_name = f_type_name(); + + `check(outer, 8'ha5, "Typedef value changed"); + `check(T, 32'd23, "Module declaration did not hide typedef"); + `check(U, 32'd41, "Declaration list continuation mismatch"); + `check($bits(V), 1, "Module var declaration did not hide typedef width"); + `check(V, 1'b1, "Module var declaration did not hide typedef value"); + `check($bits(W), 1, "Block var declaration did not hide typedef width"); + `check(W, 1'b0, "Block var declaration did not hide typedef value"); + `check(a, 8'h33, "Type declaration list first value mismatch"); + `check(b, 8'hcc, "Type declaration list continuation mismatch"); + `check($bits(a0), 7, "Type declaration list did not keep typedef type"); + `check($bits(A), 7, "Type declaration list did not allow typedef name as continuation"); + `check(A, 7'h15, "Type declaration list shadowing value mismatch"); + `check($bits(E), 3, "Type-name declaration did not keep typedef type"); + `check(E, 3'h5, "Type-name declaration value mismatch"); + `check($bits(b0), 6, "Var declaration list did not keep typedef type"); + `check($bits(B), 6, "Var declaration list did not allow typedef name as continuation"); + `check(B, 6'h15, "Var declaration list shadowing value mismatch"); + `check($bits(F), 2, "Var type-name declaration did not keep typedef type"); + `check(F, 2'h2, "Var type-name declaration value mismatch"); + `check($bits(p::C), 1, "Package var declaration did not hide typedef width"); + `check($bits(p::x), 4, "Package type declaration list first width mismatch"); + `check($bits(p::D), 4, "Package type declaration list did not allow typedef name as continuation"); + `check($bits(p::P), 3, "Package type-name declaration did not keep typedef type"); + `check(f(), 32'd11, "Function declaration did not hide typedef"); + `check(r_type_name, 14, "Function type-name declaration mismatch"); + `check(r, 32'd22, "Task declaration did not hide typedef"); + `check(tr_type_name, 26, "Task type-name declaration mismatch"); + `check($bits(x), 4, "Local typedef did not hide outer identifier"); + `check(x, 4'hc, "Local typedef value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/udp_ansi_initial_nonreg_fail.v b/ivtest/ivltests/udp_ansi_initial_nonreg_fail.v new file mode 100644 index 000000000..25ce9da6d --- /dev/null +++ b/ivtest/ivltests/udp_ansi_initial_nonreg_fail.v @@ -0,0 +1,8 @@ +// Check that an ANSI-style UDP output initializer requires a reg output. + +primitive udp_ansi_initial_nonreg_fail (output o = 1'b0, input i); + table + 0 : 0; + 1 : 1; + endtable +endprimitive diff --git a/ivtest/ivltests/udp_ansi_initial_reg.v b/ivtest/ivltests/udp_ansi_initial_reg.v new file mode 100644 index 000000000..cfbcdd6b1 --- /dev/null +++ b/ivtest/ivltests/udp_ansi_initial_reg.v @@ -0,0 +1,21 @@ +// Check that an ANSI-style UDP reg output can have an initializer. + +primitive udp_ansi_initial_reg (output reg o = 1'b0, input i); + table + 0 : ? : 0; + 1 : ? : 1; + endtable +endprimitive + +module test; + reg i; + wire o; + + udp_ansi_initial_reg i_udp(o, i); + + initial begin + i = 1'b0; + #1; + $display("PASSED"); + end +endmodule diff --git a/ivtest/ivltests/udp_empty_table_fail.v b/ivtest/ivltests/udp_empty_table_fail.v new file mode 100644 index 000000000..1dc9df054 --- /dev/null +++ b/ivtest/ivltests/udp_empty_table_fail.v @@ -0,0 +1,9 @@ +// Check that an empty old-style UDP table generates an error. + +primitive udp_empty_table_fail (o, i); + output o; + input i; + + table + endtable +endprimitive diff --git a/ivtest/ivltests/udp_initial_nonreg_fail.v b/ivtest/ivltests/udp_initial_nonreg_fail.v new file mode 100644 index 000000000..689b63e45 --- /dev/null +++ b/ivtest/ivltests/udp_initial_nonreg_fail.v @@ -0,0 +1,12 @@ +// Check that an old-style UDP initial statement requires a reg output. + +primitive udp_initial_nonreg_fail (o, i); + output o; + input i; + initial o = 1'b0; + + table + 0 : 0; + 1 : 1; + endtable +endprimitive diff --git a/ivtest/ivltests/udp_port_decl_conflict_fail.v b/ivtest/ivltests/udp_port_decl_conflict_fail.v new file mode 100644 index 000000000..00ebdfe55 --- /dev/null +++ b/ivtest/ivltests/udp_port_decl_conflict_fail.v @@ -0,0 +1,12 @@ +// Check that conflicting UDP port declarations generate an error. + +primitive udp_port_decl_conflict_fail (o, i); + output o; + input o; + input i; + + table + 0 : 0; + 1 : 1; + endtable +endprimitive diff --git a/ivtest/regress-fsv.list b/ivtest/regress-fsv.list index afe656c74..9f40cd7a7 100644 --- a/ivtest/regress-fsv.list +++ b/ivtest/regress-fsv.list @@ -84,9 +84,6 @@ module_input_port_list_def normal ivltests module_input_port_type normal ivltests parameter_in_generate1 normal ivltests parameter_no_default normal ivltests -parameter_omit1 normal ivltests -parameter_omit2 normal ivltests -parameter_omit3 normal ivltests pr3015421 CE ivltests gold=pr3015421-fsv.gold resetall normal,-Wtimescale ivltests gold=resetall-fsv.gold scope2b normal ivltests @@ -113,7 +110,6 @@ array_lval_select3a NI ivltests br605a NI ivltests br605b NI ivltests br971 NI ivltests -br1005 NI ivltests br1015a NI ivltests br1015b NI ivltests br_ml20150315b NI ivltests diff --git a/ivtest/regress-ivl1.list b/ivtest/regress-ivl1.list index af0a5b3e5..599805f1c 100644 --- a/ivtest/regress-ivl1.list +++ b/ivtest/regress-ivl1.list @@ -274,7 +274,6 @@ array_lval_select3a CE ivltests br605a EF ivltests br605b EF ivltests br971 EF ivltests -br1005 CE,-g2009 ivltests br1015b CE,-g2009 ivltests br_ml20150315b CE,-g2009 ivltests sv_deferred_assert1 CE,-g2009 ivltests gold=sv_deferred_assert1.gold diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index dade32337..ee2dc7757 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -416,6 +416,7 @@ net_string_fail CE,-g2005-sv ivltests package_vec_part_select normal,-g2005-sv ivltests packeda normal,-g2009 ivltests packeda2 normal,-g2009 ivltests +param_string_compare normal,-g2009 ivltests parameter_in_generate2 CE,-g2005-sv ivltests parameter_no_default normal,-g2005-sv ivltests parameter_no_default_fail1 CE ivltests diff --git a/ivtest/regress-vlg.list b/ivtest/regress-vlg.list index 55fbc8cc5..a2a1f86ed 100644 --- a/ivtest/regress-vlg.list +++ b/ivtest/regress-vlg.list @@ -761,12 +761,6 @@ param_times normal ivltests # param has multiplication. parameter_1bit normal ivltests parameter_in_generate1 CE ivltests parameter_no_default CE ivltests -parameter_omit1 CE ivltests -parameter_omit2 CE ivltests -parameter_omit3 CE ivltests -parameter_omit_invalid1 CE ivltests -parameter_omit_invalid2 CE ivltests -parameter_omit_invalid3 CE ivltests parameter_override_invalid1 CE ivltests parameter_override_invalid2 CE ivltests parameter_override_invalid3 CE ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index 3f82374c8..647d3b2f7 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -360,6 +360,7 @@ unp_array_typedef CE,-g2009,-pallowsigned=1 ivltests # Also string br959 CE,-g2009 ivltests br1003a CE,-g2009 ivltests br1004 CE,-g2009 ivltests +br1005 CE,-g2009 ivltests br_gh104a CE,-g2009 ivltests br_gh167a CE,-g2009 ivltests br_gh167b CE,-g2009 ivltests @@ -603,10 +604,10 @@ br_gh219 EF,-g2009,-pallowsigned=1 ivltests # creates a CA for the part select, but has nothing to connect it to. # It leaves the gate output unconnected. rise_fall_decay2 CE ivltests -# The code generator is generating unnecessary calls to $unsigned. +# The code generator emits signed casts for this test. array_packed_2d normal,-g2009,-pallowsigned=1 ivltests gold=array_packed_2d.gold -br_gh112c normal,-g2009,-pallowsigned=1 ivltests -br_gh112d normal,-g2009,-pallowsigned=1 ivltests +br_gh112c normal,-g2009 ivltests +br_gh112d normal,-g2009 ivltests # This generates a very larg (65536 bit) constant, and the parser can't cope. br_gh162 TE ivltests @@ -827,7 +828,7 @@ writemem-error normal ivltests gold=writemem-error-vlog95.gold # For Verilog 95 signed is supported as an option (-pallowsigned=1). array6 normal,-pallowsigned=1 ivltests -assign_op_oob normal,-g2009,-pallowsigned=1 ivltests +assign_op_oob normal,-g2009 ivltests assign_op_type normal,-g2009,-pallowsigned=1 ivltests bitp1 normal,-g2009,-pallowsigned=1 ivltests bits normal,-g2009,-pallowsigned=1 ivltests @@ -867,8 +868,8 @@ br_gh1237 normal,-pallowsigned=1 ivltests ca_mult normal,-pallowsigned=1 ivltests gold=ca_mult.gold cast_int normal,-pallowsigned=1 ivltests cfunc_assign_op_vec normal,-g2009,-pallowsigned=1 ivltests -constfunc4 normal,-pallowsigned=1 ivltests -constfunc6 normal,-pallowsigned=1 ivltests +constfunc4 normal ivltests +constfunc6 normal ivltests constfunc7 normal,-pallowsigned=1 ivltests constfunc13 normal,-pallowsigned=1 ivltests constfunc14 normal,-pallowsigned=1 ivltests @@ -909,7 +910,7 @@ pr1793749 normal,-pallowsigned=1 ivltests gold=pr1793749.gold pr1879226 normal,-pallowsigned=1 ivltests pr1883052 normal,-pallowsigned=1 ivltests pr1883052b normal,-pallowsigned=1 ivltests -pr1950282 normal,-pallowsigned=1 ivltests +pr1950282 normal ivltests pr1958801 normal,-pallowsigned=1 ivltests pr1993479 normal,-pallowsigned=1 ivltests gold=pr1993479.gold pr2030767 normal,-pallowsigned=1 ivltests @@ -959,7 +960,7 @@ simple_byte normal,-g2009,-pallowsigned=1 ivltests simple_int normal,-g2009,-pallowsigned=1 ivltests simple_longint normal,-g2009,-pallowsigned=1 ivltests simple_shortint normal,-g2009,-pallowsigned=1 ivltests -size_cast3 normal,-g2009,-pallowsigned=1 ivltests +size_cast3 normal,-g2009 ivltests size_cast5 normal,-g2009,-pallowsigned=1 ivltests struct_member_signed normal,-g2009,-pallowsigned=1 ivltests struct_packed_array normal,-g2009,-pallowsigned=1 ivltests diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 09f0498cf..c24235408 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -37,6 +37,7 @@ br_gh440 vvp_tests/br_gh440.json br_gh483a vvp_tests/br_gh483a.json br_gh483b vvp_tests/br_gh483b.json br_gh552 vvp_tests/br_gh552.json +br_gh670 vvp_tests/br_gh670.json br_gh687 vvp_tests/br_gh687.json br_gh703 vvp_tests/br_gh703.json br_gh710a vvp_tests/br_gh710a.json @@ -82,11 +83,17 @@ br_gh1258a vvp_tests/br_gh1258a.json br_gh1258b vvp_tests/br_gh1258b.json br_gh1286 vvp_tests/br_gh1286.json br_gh1323 vvp_tests/br_gh1323.json +br_gh1384 vvp_tests/br_gh1384.json +br_gh1385 vvp_tests/br_gh1385.json +br_gh1385a vvp_tests/br_gh1385a.json +br_gh1385b vvp_tests/br_gh1385b.json +br_gh1385c vvp_tests/br_gh1385c.json ca_time_real vvp_tests/ca_time_real.json case1 vvp_tests/case1.json case2 vvp_tests/case2.json case2-S vvp_tests/case2-S.json case3 vvp_tests/case3.json +case_mux_array_word vvp_tests/case_mux_array_word.json casex_synth vvp_tests/casex_synth.json cast_int_ams vvp_tests/cast_int_ams.json cast_real_invalid1 vvp_tests/cast_real_invalid1.json @@ -137,9 +144,11 @@ early_sig_elab3 vvp_tests/early_sig_elab3.json eofmt_percent vvp_tests/eofmt_percent.json fdisplay3 vvp_tests/fdisplay3.json final3 vvp_tests/final3.json +final_nested_block_task_fail vvp_tests/final_nested_block_task_fail.json fmonitor1 vvp_tests/fmonitor1.json fmonitor2 vvp_tests/fmonitor2.json fread-error vvp_tests/fread-error.json +func_nested_block_nb_fail vvp_tests/func_nested_block_nb_fail.json line_directive vvp_tests/line_directive.json localparam_type vvp_tests/localparam_type.json macro_str_esc vvp_tests/macro_str_esc.json @@ -166,6 +175,7 @@ module_port_array1 vvp_tests/module_port_array1.json module_port_array_fail1 vvp_tests/module_port_array_fail1.json module_port_array_init1 vvp_tests/module_port_array_init1.json monitor4 vvp_tests/monitor4.json +nb_ec_repeat_auto vvp_tests/nb_ec_repeat_auto.json named_event_edge_fail vvp_tests/named_event_edge_fail.json named_event_negedge_fail vvp_tests/named_event_negedge_fail.json named_event_posedge_fail vvp_tests/named_event_posedge_fail.json @@ -205,6 +215,11 @@ pv_wr_fn_vec2 vvp_tests/pv_wr_fn_vec2.json pv_wr_fn_vec4 vvp_tests/pv_wr_fn_vec4.json queue_fail vvp_tests/queue_fail.json readmem-invalid vvp_tests/readmem-invalid.json +real_delay_assign vvp_tests/real_delay_assign.json +real_negative_zero vvp_tests/real_negative_zero.json +real_unary_minus_inf vvp_tests/real_unary_minus_inf.json +real_unary_minus_nan vvp_tests/real_unary_minus_nan.json +real_unary_minus_zero vvp_tests/real_unary_minus_zero.json scaled_real vvp_tests/scaled_real.json scan-invalid vvp_tests/scan-invalid.json sdf_interconnect1 vvp_tests/sdf_interconnect1.json @@ -246,7 +261,9 @@ sv_array_cassign9 vvp_tests/sv_array_cassign9.json sv_array_cassign10 vvp_tests/sv_array_cassign10.json sv_array_cassign_single vvp_tests/sv_array_cassign_single.json sv_array_cassign_single_fail1 vvp_tests/sv_array_cassign_single_fail1.json +sv_assign_pattern_auto_force_fail vvp_tests/sv_assign_pattern_auto_force_fail.json sv_automatic_2state vvp_tests/sv_automatic_2state.json +sv_bad_member_lval_proc_fail vvp_tests/sv_bad_member_lval_proc_fail.json sv_byte_array_string1 vvp_tests/sv_byte_array_string1.json sv_byte_array_string2 vvp_tests/sv_byte_array_string2.json sv_byte_array_string3 vvp_tests/sv_byte_array_string3.json @@ -256,6 +273,7 @@ sv_byte_array_string_fail2 vvp_tests/sv_byte_array_string_fail2.json sv_byte_array_string_fail3 vvp_tests/sv_byte_array_string_fail3.json sv_byte_array_string_fail4 vvp_tests/sv_byte_array_string_fail4.json sv_byte_array_string_fail5 vvp_tests/sv_byte_array_string_fail5.json +sv_call_chain_method1 vvp_tests/sv_call_chain_method1.json sv_chained_constructor1 vvp_tests/sv_chained_constructor1.json sv_chained_constructor2 vvp_tests/sv_chained_constructor2.json sv_chained_constructor3 vvp_tests/sv_chained_constructor3.json @@ -263,12 +281,18 @@ sv_chained_constructor4 vvp_tests/sv_chained_constructor4.json sv_chained_constructor5 vvp_tests/sv_chained_constructor5.json sv_class_prop_assign_op1 vvp_tests/sv_class_prop_assign_op1.json sv_class_prop_assign_op2 vvp_tests/sv_class_prop_assign_op2.json +sv_class_prop_class_name vvp_tests/sv_class_prop_class_name.json sv_class_prop_logic vvp_tests/sv_class_prop_logic.json +sv_class_prop_packed_dims vvp_tests/sv_class_prop_packed_dims.json +sv_class_prop_type_name vvp_tests/sv_class_prop_type_name.json +sv_class_prop_wildcard_type_name vvp_tests/sv_class_prop_wildcard_type_name.json sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_real1.json sv_class_prop_nest_str1 vvp_tests/sv_class_prop_nest_str1.json sv_class_prop_nest_vec1 vvp_tests/sv_class_prop_nest_vec1.json +sv_class_queue_prop_methods vvp_tests/sv_class_queue_prop_methods.json +sv_class_task_expr_fail vvp_tests/sv_class_task_expr_fail.json sv_const1 vvp_tests/sv_const1.json sv_const2 vvp_tests/sv_const2.json sv_const3 vvp_tests/sv_const3.json @@ -334,6 +358,7 @@ sv_lval_concat_uarray_fail1 vvp_tests/sv_lval_concat_uarray_fail1.json sv_lval_concat_uarray_fail2 vvp_tests/sv_lval_concat_uarray_fail2.json sv_lval_concat_uarray_fail3 vvp_tests/sv_lval_concat_uarray_fail3.json sv_lval_concat_uarray_fail4 vvp_tests/sv_lval_concat_uarray_fail4.json +sv_lval_idx_part_invalid_base_down_fail vvp_tests/sv_lval_idx_part_invalid_base_down_fail.json sv_mixed_assign1 vvp_tests/sv_mixed_assign1.json sv_mixed_assign2 vvp_tests/sv_mixed_assign2.json sv_mixed_assign_error1 vvp_tests/sv_mixed_assign_error1.json @@ -348,11 +373,65 @@ sv_net_array_decl_assign vvp_tests/sv_net_array_decl_assign.json sv_net_decl_assign vvp_tests/sv_net_decl_assign.json sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json +parameter_omit1 vvp_tests/parameter_omit1.json +parameter_omit2 vvp_tests/parameter_omit2.json +parameter_omit3 vvp_tests/parameter_omit3.json +parameter_omit_invalid1 vvp_tests/parameter_omit_invalid1.json +parameter_omit_invalid2 vvp_tests/parameter_omit_invalid2.json +parameter_omit_invalid3 vvp_tests/parameter_omit_invalid3.json sv_parameter_type vvp_tests/sv_parameter_type.json +sv_partsel_var_negative_packed vvp_tests/sv_partsel_var_negative_packed.json +sv_queue_ap_method vvp_tests/sv_queue_ap_method.json sv_queue_assign_op vvp_tests/sv_queue_assign_op.json +sv_queue_method_insert_too_few_arg_fail vvp_tests/sv_queue_method_insert_too_few_arg_fail.json +sv_queue_method_insert_too_many_arg_fail vvp_tests/sv_queue_method_insert_too_many_arg_fail.json +sv_queue_method_push_back_too_few_arg_fail vvp_tests/sv_queue_method_push_back_too_few_arg_fail.json +sv_queue_method_push_back_too_many_arg_fail vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json +sv_queue_method_push_front_too_few_arg_fail vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json +sv_queue_method_push_front_too_many_arg_fail vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json sv_soft_packed_union vvp_tests/sv_soft_packed_union.json sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json +sv_string_method_substr_too_few_arg_fail vvp_tests/sv_string_method_substr_too_few_arg_fail.json sv_super_member_fail vvp_tests/sv_super_member_fail.json +sv_type_identifier_ams_name_fields vvp_tests/sv_type_identifier_ams_name_fields.json +sv_type_identifier_attribute_name vvp_tests/sv_type_identifier_attribute_name.json +sv_type_identifier_attribute_target vvp_tests/sv_type_identifier_attribute_target.json +sv_type_identifier_block_label_name vvp_tests/sv_type_identifier_block_label_name.json +sv_type_identifier_config_name vvp_tests/sv_type_identifier_config_name.json +sv_type_identifier_discipline_name vvp_tests/sv_type_identifier_discipline_name.json +sv_type_identifier_discipline_nature_ref vvp_tests/sv_type_identifier_discipline_nature_ref.json +sv_type_identifier_enum_item_name vvp_tests/sv_type_identifier_enum_item_name.json +sv_type_identifier_event_name vvp_tests/sv_type_identifier_event_name.json +sv_type_identifier_for_name vvp_tests/sv_type_identifier_for_name.json +sv_type_identifier_foreach_array_name vvp_tests/sv_type_identifier_foreach_array_name.json +sv_type_identifier_foreach_name vvp_tests/sv_type_identifier_foreach_name.json +sv_type_identifier_fork_label_name vvp_tests/sv_type_identifier_fork_label_name.json +sv_type_identifier_function_name vvp_tests/sv_type_identifier_function_name.json +sv_type_identifier_generate_label_name vvp_tests/sv_type_identifier_generate_label_name.json +sv_type_identifier_genvar_name vvp_tests/sv_type_identifier_genvar_name.json +sv_type_identifier_modport_name vvp_tests/sv_type_identifier_modport_name.json +sv_type_identifier_modport_named_port vvp_tests/sv_type_identifier_modport_named_port.json +sv_type_identifier_module_name vvp_tests/sv_type_identifier_module_name.json +sv_type_identifier_named_constructor_argument vvp_tests/sv_type_identifier_named_constructor_argument.json +sv_type_identifier_named_function_argument vvp_tests/sv_type_identifier_named_function_argument.json +sv_type_identifier_named_parameter_value vvp_tests/sv_type_identifier_named_parameter_value.json +sv_type_identifier_named_port_connection vvp_tests/sv_type_identifier_named_port_connection.json +sv_type_identifier_named_task_argument vvp_tests/sv_type_identifier_named_task_argument.json +sv_type_identifier_nature_name vvp_tests/sv_type_identifier_nature_name.json +sv_type_identifier_net_name vvp_tests/sv_type_identifier_net_name.json +sv_type_identifier_package_item vvp_tests/sv_type_identifier_package_item.json +sv_type_identifier_package_name vvp_tests/sv_type_identifier_package_name.json +sv_type_identifier_parameter_decl_name vvp_tests/sv_type_identifier_parameter_decl_name.json +sv_type_identifier_parameter_port_name vvp_tests/sv_type_identifier_parameter_port_name.json +sv_type_identifier_parameter_type_decl_name vvp_tests/sv_type_identifier_parameter_type_decl_name.json +sv_type_identifier_parameter_type_param_name vvp_tests/sv_type_identifier_parameter_type_param_name.json +sv_type_identifier_port_name vvp_tests/sv_type_identifier_port_name.json +sv_type_identifier_specparam_name vvp_tests/sv_type_identifier_specparam_name.json +sv_type_identifier_task_function_argument_name vvp_tests/sv_type_identifier_task_function_argument_name.json +sv_type_identifier_task_name vvp_tests/sv_type_identifier_task_name.json +sv_type_identifier_udp_ansi_name vvp_tests/sv_type_identifier_udp_ansi_name.json +sv_type_identifier_udp_name vvp_tests/sv_type_identifier_udp_name.json +sv_type_identifier_variable_name vvp_tests/sv_type_identifier_variable_name.json sv_type_param_restrict_class1 vvp_tests/sv_type_param_restrict_class1.json sv_type_param_restrict_class2 vvp_tests/sv_type_param_restrict_class2.json sv_type_param_restrict_class_fail1 vvp_tests/sv_type_param_restrict_class_fail1.json @@ -379,6 +458,11 @@ test_va_math vvp_tests/test_va_math.json test_vams_math vvp_tests/test_vams_math.json timing_check_syntax vvp_tests/timing_check_syntax.json timing_check_delayed_signals vvp_tests/timing_check_delayed_signals.json +udp_ansi_initial_nonreg_fail vvp_tests/udp_ansi_initial_nonreg_fail.json +udp_ansi_initial_reg vvp_tests/udp_ansi_initial_reg.json +udp_empty_table_fail vvp_tests/udp_empty_table_fail.json +udp_initial_nonreg_fail vvp_tests/udp_initial_nonreg_fail.json +udp_port_decl_conflict_fail vvp_tests/udp_port_decl_conflict_fail.json uwire_fail2 vvp_tests/uwire_fail2.json uwire_fail3 vvp_tests/uwire_fail3.json value_range1 vvp_tests/value_range1.json diff --git a/ivtest/run_ivl.py b/ivtest/run_ivl.py index 3a1aa16b7..aa2206928 100644 --- a/ivtest/run_ivl.py +++ b/ivtest/run_ivl.py @@ -129,6 +129,10 @@ def run_cmd(cmd: list) -> subprocess.CompletedProcess: res = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False) return res +def is_execution_error(returncode: int) -> bool: + '''Check if a command failed due to an execution error.''' + return returncode < 0 or returncode >= 128 + # pylint: disable-next=invalid-name def run_CE(options: dict, cfg: dict) -> list: @@ -154,10 +158,12 @@ def run_CE(options: dict, cfg: dict) -> list: if res.returncode == 0: return [1, "Failed - CE (no error reported)."] - if res.returncode >= 256: + if is_execution_error(res.returncode): return [1, "Failed - CE (execution error)."] - if options['gold'] is not None and not check_gold(options, log_list): - return [1, "Failed - CE (Gold file doesn't match output)."] + if options['gold'] is not None: + gold_rtn = check_gold(options, log_list) + if gold_rtn[0]: + return [1, "Failed - CE (Gold file doesn't match output)."] return [0, "Passed - CE."] @@ -248,6 +254,8 @@ def options_to_pass(options: dict) -> list: def build_ivl_return(translation_fail: bool, res: subprocess.CompletedProcess) -> list: '''Generate the return for the iverilog run.''' + if is_execution_error(res.returncode): + return [1, "Failed - iverilog execution error."] if translation_fail: if res.returncode != 0: return [0, "Passed - TE."] @@ -258,11 +266,11 @@ def build_ivl_return(translation_fail: bool, res: subprocess.CompletedProcess) - def build_vvp_return(expected_fail: bool, res: subprocess.CompletedProcess) -> list: '''Generate the return for the vvp run.''' + if is_execution_error(res.returncode): + return [1, "Failed - vvp execution error"] if res.returncode != 0 and expected_fail: return [0, "Passed - EF."] - if res.returncode >= 256: - return [1, "Failed - vvp execution error"] - if res.returncode > 0 and res.returncode < 256 and not expected_fail: + if res.returncode > 0 and not expected_fail: return [1, "Failed - vvp error, but expected to succeed"] return [] diff --git a/ivtest/vvp_tests/br_gh1384.json b/ivtest/vvp_tests/br_gh1384.json new file mode 100644 index 000000000..2f6ac5c8b --- /dev/null +++ b/ivtest/vvp_tests/br_gh1384.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "br_gh1384.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/br_gh1385.json b/ivtest/vvp_tests/br_gh1385.json new file mode 100644 index 000000000..8cdc9e3d5 --- /dev/null +++ b/ivtest/vvp_tests/br_gh1385.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "br_gh1385.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Generate scopes are not translated", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/br_gh1385a.json b/ivtest/vvp_tests/br_gh1385a.json new file mode 100644 index 000000000..86da73c46 --- /dev/null +++ b/ivtest/vvp_tests/br_gh1385a.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "br_gh1385a.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/br_gh1385b.json b/ivtest/vvp_tests/br_gh1385b.json new file mode 100644 index 000000000..1949f3d57 --- /dev/null +++ b/ivtest/vvp_tests/br_gh1385b.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "br_gh1385b.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/br_gh1385c.json b/ivtest/vvp_tests/br_gh1385c.json new file mode 100644 index 000000000..0e6955bc5 --- /dev/null +++ b/ivtest/vvp_tests/br_gh1385c.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "br_gh1385c.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/br_gh670.json b/ivtest/vvp_tests/br_gh670.json new file mode 100644 index 000000000..5effa2a3f --- /dev/null +++ b/ivtest/vvp_tests/br_gh670.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "br_gh670.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/case_mux_array_word.json b/ivtest/vvp_tests/case_mux_array_word.json new file mode 100644 index 000000000..b3303aeb1 --- /dev/null +++ b/ivtest/vvp_tests/case_mux_array_word.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "case_mux_array_word.v", + "iverilog-args" : [ "-S" ] +} diff --git a/ivtest/vvp_tests/final_nested_block_task_fail.json b/ivtest/vvp_tests/final_nested_block_task_fail.json new file mode 100644 index 000000000..8c017453f --- /dev/null +++ b/ivtest/vvp_tests/final_nested_block_task_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "final_nested_block_task_fail.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/func_nested_block_nb_fail.json b/ivtest/vvp_tests/func_nested_block_nb_fail.json new file mode 100644 index 000000000..47984b1dd --- /dev/null +++ b/ivtest/vvp_tests/func_nested_block_nb_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "func_nested_block_nb_fail.v" +} diff --git a/ivtest/vvp_tests/nb_ec_repeat_auto.json b/ivtest/vvp_tests/nb_ec_repeat_auto.json new file mode 100644 index 000000000..382425f56 --- /dev/null +++ b/ivtest/vvp_tests/nb_ec_repeat_auto.json @@ -0,0 +1,8 @@ +{ + "type" : "normal", + "source" : "nb_ec_repeat_auto.v", + "vlog95" : { + "__comment" : "Automatic tasks are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/parameter_omit1.json b/ivtest/vvp_tests/parameter_omit1.json new file mode 100644 index 000000000..3dd77e1cd --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit1.json @@ -0,0 +1,7 @@ +{ + "type" : "CE", + "source" : "parameter_omit1.v", + "force-sv" : { + "type" : "normal" + } +} diff --git a/ivtest/vvp_tests/parameter_omit2.json b/ivtest/vvp_tests/parameter_omit2.json new file mode 100644 index 000000000..cb09ba0c4 --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit2.json @@ -0,0 +1,7 @@ +{ + "type" : "CE", + "source" : "parameter_omit2.v", + "force-sv" : { + "type" : "normal" + } +} diff --git a/ivtest/vvp_tests/parameter_omit3.json b/ivtest/vvp_tests/parameter_omit3.json new file mode 100644 index 000000000..9970cd8d1 --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit3.json @@ -0,0 +1,7 @@ +{ + "type" : "CE", + "source" : "parameter_omit3.v", + "force-sv" : { + "type" : "normal" + } +} diff --git a/ivtest/vvp_tests/parameter_omit_invalid1.json b/ivtest/vvp_tests/parameter_omit_invalid1.json new file mode 100644 index 000000000..d906a0c44 --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit_invalid1.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "parameter_omit_invalid1.v" +} diff --git a/ivtest/vvp_tests/parameter_omit_invalid2.json b/ivtest/vvp_tests/parameter_omit_invalid2.json new file mode 100644 index 000000000..a3205e5ad --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit_invalid2.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "parameter_omit_invalid2.v" +} diff --git a/ivtest/vvp_tests/parameter_omit_invalid3.json b/ivtest/vvp_tests/parameter_omit_invalid3.json new file mode 100644 index 000000000..106baed2c --- /dev/null +++ b/ivtest/vvp_tests/parameter_omit_invalid3.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "parameter_omit_invalid3.v" +} diff --git a/ivtest/vvp_tests/real_delay_assign.json b/ivtest/vvp_tests/real_delay_assign.json new file mode 100644 index 000000000..b4442c9fb --- /dev/null +++ b/ivtest/vvp_tests/real_delay_assign.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_delay_assign.v" +} diff --git a/ivtest/vvp_tests/real_negative_zero.json b/ivtest/vvp_tests/real_negative_zero.json new file mode 100644 index 000000000..1165f27f5 --- /dev/null +++ b/ivtest/vvp_tests/real_negative_zero.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_negative_zero.v" +} diff --git a/ivtest/vvp_tests/real_unary_minus_inf.json b/ivtest/vvp_tests/real_unary_minus_inf.json new file mode 100644 index 000000000..15f4203e7 --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_inf.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_inf.v" +} diff --git a/ivtest/vvp_tests/real_unary_minus_nan.json b/ivtest/vvp_tests/real_unary_minus_nan.json new file mode 100644 index 000000000..4dde327de --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_nan.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_nan.v" +} diff --git a/ivtest/vvp_tests/real_unary_minus_zero.json b/ivtest/vvp_tests/real_unary_minus_zero.json new file mode 100644 index 000000000..27bf853c9 --- /dev/null +++ b/ivtest/vvp_tests/real_unary_minus_zero.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "real_unary_minus_zero.v" +} diff --git a/ivtest/vvp_tests/sv_assign_pattern_auto_force_fail.json b/ivtest/vvp_tests/sv_assign_pattern_auto_force_fail.json new file mode 100644 index 000000000..29f301d70 --- /dev/null +++ b/ivtest/vvp_tests/sv_assign_pattern_auto_force_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_assign_pattern_auto_force_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_bad_member_lval_proc_fail.json b/ivtest/vvp_tests/sv_bad_member_lval_proc_fail.json new file mode 100644 index 000000000..dc312633a --- /dev/null +++ b/ivtest/vvp_tests/sv_bad_member_lval_proc_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_bad_member_lval_proc_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_call_chain_method1.json b/ivtest/vvp_tests/sv_call_chain_method1.json new file mode 100644 index 000000000..edd7b87fd --- /dev/null +++ b/ivtest/vvp_tests/sv_call_chain_method1.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_call_chain_method1.v", + "iverilog-args" : [ "-g2012" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_prop_class_name.json b/ivtest/vvp_tests/sv_class_prop_class_name.json new file mode 100644 index 000000000..4c7cfe9c8 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_class_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_class_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_prop_packed_dims.json b/ivtest/vvp_tests/sv_class_prop_packed_dims.json new file mode 100644 index 000000000..2697dc424 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_packed_dims.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_packed_dims.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_prop_type_name.json b/ivtest/vvp_tests/sv_class_prop_type_name.json new file mode 100644 index 000000000..e5543bb21 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_type_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_type_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_prop_wildcard_type_name.json b/ivtest/vvp_tests/sv_class_prop_wildcard_type_name.json new file mode 100644 index 000000000..451678584 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_prop_wildcard_type_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_prop_wildcard_type_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_queue_prop_methods.json b/ivtest/vvp_tests/sv_class_queue_prop_methods.json new file mode 100644 index 000000000..735de2f79 --- /dev/null +++ b/ivtest/vvp_tests/sv_class_queue_prop_methods.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_class_queue_prop_methods.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_class_task_expr_fail.json b/ivtest/vvp_tests/sv_class_task_expr_fail.json new file mode 100644 index 000000000..d3c18575f --- /dev/null +++ b/ivtest/vvp_tests/sv_class_task_expr_fail.json @@ -0,0 +1,9 @@ +{ + "type" : "CE", + "source" : "sv_class_task_expr_fail.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_lval_idx_part_invalid_base_down_fail.json b/ivtest/vvp_tests/sv_lval_idx_part_invalid_base_down_fail.json new file mode 100644 index 000000000..e04a3a978 --- /dev/null +++ b/ivtest/vvp_tests/sv_lval_idx_part_invalid_base_down_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_lval_idx_part_invalid_base_down_fail.v", + "iverilog-args" : [ "-g2001" ] +} diff --git a/ivtest/vvp_tests/sv_partsel_var_negative_packed.json b/ivtest/vvp_tests/sv_partsel_var_negative_packed.json new file mode 100644 index 000000000..0d0e5f9d2 --- /dev/null +++ b/ivtest/vvp_tests/sv_partsel_var_negative_packed.json @@ -0,0 +1,8 @@ +{ + "type" : "normal", + "source" : "sv_partsel_var_negative_packed.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "iverilog-args" : [ "-pallowsigned=1" ] + } +} diff --git a/ivtest/vvp_tests/sv_queue_ap_method.json b/ivtest/vvp_tests/sv_queue_ap_method.json new file mode 100644 index 000000000..1080087e9 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_ap_method.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_queue_ap_method.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Queues are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_queue_method_insert_too_few_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_insert_too_few_arg_fail.json new file mode 100644 index 000000000..98191069a --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_insert_too_few_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_insert_too_few_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_method_insert_too_many_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_insert_too_many_arg_fail.json new file mode 100644 index 000000000..751dc11d1 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_insert_too_many_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_insert_too_many_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_method_push_back_too_few_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_push_back_too_few_arg_fail.json new file mode 100644 index 000000000..e75cf2d2b --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_push_back_too_few_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_push_back_too_few_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json new file mode 100644 index 000000000..e66971bc9 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_push_back_too_many_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json new file mode 100644 index 000000000..c3118f197 --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_push_front_too_few_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json b/ivtest/vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json new file mode 100644 index 000000000..644c6c99a --- /dev/null +++ b/ivtest/vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_queue_method_push_front_too_many_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_string_method_substr_too_few_arg_fail.json b/ivtest/vvp_tests/sv_string_method_substr_too_few_arg_fail.json new file mode 100644 index 000000000..20453dfe5 --- /dev/null +++ b/ivtest/vvp_tests/sv_string_method_substr_too_few_arg_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "sv_string_method_substr_too_few_arg_fail.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_ams_name_fields.json b/ivtest/vvp_tests/sv_type_identifier_ams_name_fields.json new file mode 100644 index 000000000..9323ed119 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_ams_name_fields.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_ams_name_fields.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_attribute_name.json b/ivtest/vvp_tests/sv_type_identifier_attribute_name.json new file mode 100644 index 000000000..598982a44 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_attribute_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_attribute_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_attribute_target.json b/ivtest/vvp_tests/sv_type_identifier_attribute_target.json new file mode 100644 index 000000000..bb1ecb5f6 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_attribute_target.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_attribute_target.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_block_label_name.json b/ivtest/vvp_tests/sv_type_identifier_block_label_name.json new file mode 100644 index 000000000..badf56ebb --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_block_label_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_block_label_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_config_name.json b/ivtest/vvp_tests/sv_type_identifier_config_name.json new file mode 100644 index 000000000..f31e350a6 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_config_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_config_name.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_discipline_name.json b/ivtest/vvp_tests/sv_type_identifier_discipline_name.json new file mode 100644 index 000000000..1947092fb --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_discipline_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_discipline_name.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_discipline_nature_ref.json b/ivtest/vvp_tests/sv_type_identifier_discipline_nature_ref.json new file mode 100644 index 000000000..d740f86fa --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_discipline_nature_ref.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_discipline_nature_ref.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_enum_item_name.json b/ivtest/vvp_tests/sv_type_identifier_enum_item_name.json new file mode 100644 index 000000000..25adc3e46 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_enum_item_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_enum_item_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Enums are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_event_name.json b/ivtest/vvp_tests/sv_type_identifier_event_name.json new file mode 100644 index 000000000..c4bb339f3 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_event_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_event_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_for_name.json b/ivtest/vvp_tests/sv_type_identifier_for_name.json new file mode 100644 index 000000000..0b0e7b9a6 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_for_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_for_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_foreach_array_name.json b/ivtest/vvp_tests/sv_type_identifier_foreach_array_name.json new file mode 100644 index 000000000..b64ff4aea --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_foreach_array_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_foreach_array_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_foreach_name.json b/ivtest/vvp_tests/sv_type_identifier_foreach_name.json new file mode 100644 index 000000000..52463b1f0 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_foreach_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_foreach_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and foreach loops are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_fork_label_name.json b/ivtest/vvp_tests/sv_type_identifier_fork_label_name.json new file mode 100644 index 000000000..2aca16cd9 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_fork_label_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_fork_label_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_function_name.json b/ivtest/vvp_tests/sv_type_identifier_function_name.json new file mode 100644 index 000000000..4e5ae1920 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_function_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_function_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_generate_label_name.json b/ivtest/vvp_tests/sv_type_identifier_generate_label_name.json new file mode 100644 index 000000000..488dea150 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_generate_label_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_generate_label_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Named generate scopes are not translated by vlog95", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_genvar_name.json b/ivtest/vvp_tests/sv_type_identifier_genvar_name.json new file mode 100644 index 000000000..954ef7288 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_genvar_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_genvar_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and generate blocks are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_modport_name.json b/ivtest/vvp_tests/sv_type_identifier_modport_name.json new file mode 100644 index 000000000..c02a11338 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_modport_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_modport_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_modport_named_port.json b/ivtest/vvp_tests/sv_type_identifier_modport_named_port.json new file mode 100644 index 000000000..b3138f57d --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_modport_named_port.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_modport_named_port.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_module_name.json b/ivtest/vvp_tests/sv_type_identifier_module_name.json new file mode 100644 index 000000000..587f0bd54 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_module_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_module_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_named_constructor_argument.json b/ivtest/vvp_tests/sv_type_identifier_named_constructor_argument.json new file mode 100644 index 000000000..e50d8a5c7 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_named_constructor_argument.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_named_constructor_argument.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Class scopes and new operators are not translated", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_named_function_argument.json b/ivtest/vvp_tests/sv_type_identifier_named_function_argument.json new file mode 100644 index 000000000..7186b6525 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_named_function_argument.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_named_function_argument.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_named_parameter_value.json b/ivtest/vvp_tests/sv_type_identifier_named_parameter_value.json new file mode 100644 index 000000000..b3bf35a92 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_named_parameter_value.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_named_parameter_value.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_named_port_connection.json b/ivtest/vvp_tests/sv_type_identifier_named_port_connection.json new file mode 100644 index 000000000..48e05b779 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_named_port_connection.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_named_port_connection.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_named_task_argument.json b/ivtest/vvp_tests/sv_type_identifier_named_task_argument.json new file mode 100644 index 000000000..0f0d45766 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_named_task_argument.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_named_task_argument.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_nature_name.json b/ivtest/vvp_tests/sv_type_identifier_nature_name.json new file mode 100644 index 000000000..89c0d37ec --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_nature_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_nature_name.v", + "iverilog-args" : [ "-g2005-sv", "-gverilog-ams" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_net_name.json b/ivtest/vvp_tests/sv_type_identifier_net_name.json new file mode 100644 index 000000000..5b5789167 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_net_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_net_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and SystemVerilog net types are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_package_item.json b/ivtest/vvp_tests/sv_type_identifier_package_item.json new file mode 100644 index 000000000..8dc1e2178 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_package_item.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_package_item.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_package_name.json b/ivtest/vvp_tests/sv_type_identifier_package_name.json new file mode 100644 index 000000000..dd4076748 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_package_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_package_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json new file mode 100644 index 000000000..9f265426c --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_decl_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json new file mode 100644 index 000000000..91cf1e3aa --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_port_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json new file mode 100644 index 000000000..d51f1988e --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_type_decl_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json new file mode 100644 index 000000000..fe48a962a --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_type_param_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_port_name.json b/ivtest/vvp_tests/sv_type_identifier_port_name.json new file mode 100644 index 000000000..f94594bb3 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_port_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_port_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and ANSI ports are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_specparam_name.json b/ivtest/vvp_tests/sv_type_identifier_specparam_name.json new file mode 100644 index 000000000..741ed0c47 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_specparam_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_specparam_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json b/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json new file mode 100644 index 000000000..a8ed1e0fd --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_task_function_argument_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_task_function_argument_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and task/function arguments are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_task_name.json b/ivtest/vvp_tests/sv_type_identifier_task_name.json new file mode 100644 index 000000000..b95d47644 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_task_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_task_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Classes are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_type_identifier_udp_ansi_name.json b/ivtest/vvp_tests/sv_type_identifier_udp_ansi_name.json new file mode 100644 index 000000000..dd6b8e056 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_udp_ansi_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_udp_ansi_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_udp_name.json b/ivtest/vvp_tests/sv_type_identifier_udp_name.json new file mode 100644 index 000000000..8291d8798 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_udp_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_udp_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_variable_name.json b/ivtest/vvp_tests/sv_type_identifier_variable_name.json new file mode 100644 index 000000000..fde51c2a7 --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_variable_name.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_variable_name.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Typedefs and block/task scope are SystemVerilog", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/udp_ansi_initial_nonreg_fail.json b/ivtest/vvp_tests/udp_ansi_initial_nonreg_fail.json new file mode 100644 index 000000000..1a984c32f --- /dev/null +++ b/ivtest/vvp_tests/udp_ansi_initial_nonreg_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "udp_ansi_initial_nonreg_fail.v" +} diff --git a/ivtest/vvp_tests/udp_ansi_initial_reg.json b/ivtest/vvp_tests/udp_ansi_initial_reg.json new file mode 100644 index 000000000..5f72fea49 --- /dev/null +++ b/ivtest/vvp_tests/udp_ansi_initial_reg.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "udp_ansi_initial_reg.v" +} diff --git a/ivtest/vvp_tests/udp_empty_table_fail.json b/ivtest/vvp_tests/udp_empty_table_fail.json new file mode 100644 index 000000000..10abc07f9 --- /dev/null +++ b/ivtest/vvp_tests/udp_empty_table_fail.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "udp_empty_table_fail.v", + "gold" : "udp_empty_table_fail" +} diff --git a/ivtest/vvp_tests/udp_initial_nonreg_fail.json b/ivtest/vvp_tests/udp_initial_nonreg_fail.json new file mode 100644 index 000000000..735d978fd --- /dev/null +++ b/ivtest/vvp_tests/udp_initial_nonreg_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "udp_initial_nonreg_fail.v" +} diff --git a/ivtest/vvp_tests/udp_port_decl_conflict_fail.json b/ivtest/vvp_tests/udp_port_decl_conflict_fail.json new file mode 100644 index 000000000..56a5fdb42 --- /dev/null +++ b/ivtest/vvp_tests/udp_port_decl_conflict_fail.json @@ -0,0 +1,4 @@ +{ + "type" : "CE", + "source" : "udp_port_decl_conflict_fail.v" +} diff --git a/main.cc b/main.cc index 9ac47b4d6..644887ebb 100644 --- a/main.cc +++ b/main.cc @@ -1232,7 +1232,7 @@ int main(int argc, char*argv[]) if (pre_process_fail_count) { cerr << "Preprocessor failed with " << pre_process_fail_count - << " errors." << endl; + << " error(s)." << endl; return pre_process_fail_count; } diff --git a/net_scope.cc b/net_scope.cc index cd9e923d0..be9d1c4c6 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -535,7 +535,24 @@ NetFuncDef* NetScope::func_def() bool NetScope::in_func() const { - return (type_ == FUNC) ? true : false; + if (type_ == FUNC) + return true; + + if (type_ == BEGIN_END || type_ == FORK_JOIN || type_ == GENBLOCK) + return up_ ? up_->in_func() : false; + + return false; +} + +bool NetScope::in_final() const +{ + if (in_final_) + return true; + + if (type_ == BEGIN_END || type_ == FORK_JOIN || type_ == GENBLOCK) + return up_ ? up_->in_final() : false; + + return false; } const NetFuncDef* NetScope::func_def() const diff --git a/netlist.h b/netlist.h index 86bfb9b73..d485a5be8 100644 --- a/netlist.h +++ b/netlist.h @@ -1193,7 +1193,7 @@ class NetScope : public Definitions, public Attrib { /* Is this scope elaborating a final procedure? */ void in_final(bool in_final__) { in_final_ = in_final__; }; - bool in_final() const { return in_final_; }; + bool in_final() const; const NetTaskDef* task_def() const; const NetFuncDef* func_def() const; diff --git a/netmisc.cc b/netmisc.cc index a5af12d76..2ace3f59e 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -423,8 +423,10 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, unsigned min_wid = base->expr_width(); if ((sb < 0) && !base->has_sign()) min_wid += 1; - if (min_wid < num_bits(pcur->get_lsb())) min_wid = pcur->get_lsb(); - if (min_wid < num_bits(pcur->get_msb())) min_wid = pcur->get_msb(); + if (min_wid < num_bits(pcur->get_lsb())) + min_wid = num_bits(pcur->get_lsb()); + if (min_wid < num_bits(pcur->get_msb())) + min_wid = num_bits(pcur->get_msb()); base = pad_to_width(base, min_wid, *base); if ((sb < 0) && !base->has_sign()) { NetESelect *tmp = new NetESelect(base, 0 , min_wid); diff --git a/parse.y b/parse.y index 985afe40a..43dd95a6a 100644 --- a/parse.y +++ b/parse.y @@ -124,6 +124,45 @@ static void check_net_decl_assigns(const struct vlltype&loc, } } +static data_type_t *pform_make_parray_type(const struct vlltype&loc, + data_type_t *base, + std::list *pdims) +{ + if (!pdims) + return base; + + data_type_t *type = new parray_type_t(base, pdims); + FILE_NAME(type, loc); + + return type; +} + +template +static void set_type_id_range(T&value, data_type_t *type, char *id, + const YYLTYPE&loc, + std::list *ranges) +{ + value.type = type; + value.id = id; + value.lexical_pos = loc.lexical_pos; + value.first_line = loc.first_line; + value.first_column = loc.first_column; + value.last_line = loc.last_line; + value.last_column = loc.last_column; + value.ranges = ranges; +} + +template +static void delete_type_id_range(T&value) +{ + delete value.type; + delete[] value.id; + delete value.ranges; + value.type = nullptr; + value.id = nullptr; + value.ranges = nullptr; +} + /* The rules sometimes push attributes into a global context where sub-rules may grab them. This makes parser rules a little easier to write in some cases. */ @@ -169,25 +208,29 @@ static std::list*attributes_in_context = 0; static const struct str_pair_t pull_strength = { IVL_DR_PULL, IVL_DR_PULL }; static const struct str_pair_t str_strength = { IVL_DR_STRONG, IVL_DR_STRONG }; -static std::list* make_port_list(char*id, unsigned idn, - std::list*udims, - PExpr*expr) +static struct pform_port_list make_port_list(data_type_t *type, char*id, + unsigned idn, + std::list*udims, + PExpr*expr) { - std::list*tmp = new std::list; + struct pform_port_list list; + list.type = type; + list.ports = new std::list; pform_ident_t tmp_name = { lex_strings.make(id), idn }; - tmp->push_back(pform_port_t(tmp_name, udims, expr)); + list.ports->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; - return tmp; + return list; } -static std::list* make_port_list(list*tmp, - char*id, unsigned idn, - std::list*udims, - PExpr*expr) + +static struct pform_port_list make_port_list(struct pform_port_list list, + char*id, unsigned idn, + std::list*udims, + PExpr*expr) { pform_ident_t tmp_name = { lex_strings.make(id), idn }; - tmp->push_back(pform_port_t(tmp_name, udims, expr)); + list.ports->push_back(pform_port_t(tmp_name, udims, expr)); delete[]id; - return tmp; + return list; } static std::list* list_from_identifier(char*id, unsigned idn) @@ -206,6 +249,83 @@ static std::list* list_from_identifier(list*tmp, return tmp; } +static decl_assignment_t *pform_make_var_decl(const YYLTYPE&loc, char *id, + unsigned lexical_pos, + std::list*udims, + PExpr *init) +{ + if (init && pform_peek_scope()->var_init_needs_explicit_lifetime() && + var_lifetime == LexicalScope::INHERITED) { + cerr << loc << ": warning: Static variable initialization requires " + "explicit lifetime in this context." << endl; + warn_count += 1; + } + decl_assignment_t *decl = new decl_assignment_t; + decl->name = { lex_strings.make(id), lexical_pos }; + if (udims) { + decl->index = *udims; + delete udims; + } + decl->expr.reset(init); + delete[] id; + return decl; +} + +static decl_assignment_t *pform_make_var_decl(const YYLTYPE&loc, char *id, + std::list*udims, + PExpr *init) +{ + return pform_make_var_decl(loc, id, loc.lexical_pos, udims, init); +} + +static decl_assignment_t *pform_make_net_decl(const YYLTYPE&loc, char *id, + unsigned lexical_pos, + std::list*udims, + PExpr *init) +{ + decl_assignment_t *decl = new decl_assignment_t; + decl->name = { lex_strings.make(id), lexical_pos }; + if (udims) { + decl->index = *udims; + if (init) + pform_requires_sv(loc, "Assignment of net array during declaration"); + delete udims; + } + decl->expr.reset(init); + delete[] id; + return decl; +} + +static decl_assignment_t *pform_make_net_decl(const YYLTYPE&loc, char *id, + std::list*udims, + PExpr *init) +{ + return pform_make_net_decl(loc, id, loc.lexical_pos, udims, init); +} + +static void pform_set_parameter(const YYLTYPE&loc, char *id, unsigned lexical_pos, + bool is_local, bool is_type, + type_restrict_t type_restrict, + data_type_t*data_type, const list*udims, + PExpr*expr, LexicalScope::range_t*value_range) +{ + YYLTYPE id_loc = loc; + id_loc.lexical_pos = lexical_pos; + pform_set_parameter(id_loc, lex_strings.make(id), is_local, is_type, + type_restrict, data_type, udims, expr, value_range); + delete[] id; +} + +static void pform_set_parameter(const YYLTYPE&loc, char *id, + bool is_local, bool is_type, + type_restrict_t type_restrict, + data_type_t*data_type, const list*udims, + PExpr*expr, LexicalScope::range_t*value_range) +{ + pform_set_parameter(loc, id, loc.lexical_pos, is_local, is_type, + type_restrict, data_type, udims, expr, value_range); +} + template void append(vector&out, const std::vector&in) { for (size_t idx = 0 ; idx < in.size() ; idx += 1) @@ -427,14 +547,15 @@ static void port_declaration_context_init(void) } Module::port_t *module_declare_port(const YYLTYPE&loc, char *id, - NetNet::PortType port_type, + unsigned lexical_pos, + NetNet::PortType port_type, NetNet::Type net_type, data_type_t *data_type, std::list *unpacked_dims, PExpr *default_value, std::list *attributes) { - pform_ident_t name = { lex_strings.make(id), loc.lexical_pos }; + pform_ident_t name = { lex_strings.make(id), lexical_pos }; delete[] id; Module::port_t *port = pform_module_port_reference(loc, name.first); @@ -527,8 +648,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, std::list*perm_strings; std::list*identifiers; - - std::list*port_list; + struct pform_port_list port_list; std::vector* tf_ports; @@ -583,6 +703,11 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, decl_assignment_t*decl_assignment; std::list*decl_assignments; + struct { + data_type_t *type; + std::list *decl_assignments; + } decl_assignments_with_type; + struct_member_t*struct_member; std::list*struct_members; struct_type_t*struct_type; @@ -597,6 +722,17 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, typedef_t*type; } type_identifier; + struct { + data_type_t *type; + char *id; + unsigned lexical_pos; + int first_line; + int first_column; + int last_line; + int last_column; + std::list*ranges; + } type_id_range; + struct { data_type_t*type; std::list *args; @@ -743,11 +879,11 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt -%type event_variable label_opt class_declaration_endlabel_opt +%type event_variable label_opt %type block_identifier_opt %type identifier_name %type event_variable_list -%type list_of_identifiers +%type genvar_identifier_list list_of_identifiers %type loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers @@ -795,7 +931,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type timeskew_fullskew_opt_remain_active_flag %type assignment_pattern expression expression_opt expr_mintypmax -%type expr_primary_or_typename expr_primary +%type expr_primary_or_typename expr_primary call_chain_expr %type class_new dynamic_array_new %type net_decl_initializer_opt var_decl_initializer_opt initializer_opt %type inc_or_dec_expression inside_expression lpvalue @@ -807,12 +943,15 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type net_decl_assign variable_decl_assignment %type net_decl_assigns list_of_variable_decl_assignments +%type list_of_net_decl_assignments_with_type +%type list_of_variable_decl_assignments_with_type %type data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void -%type data_type_or_implicit_no_opt -%type simple_type_or_string let_formal_type -%type packed_array_data_type -%type ps_type_identifier +%type implicit_type +%type reg_prefixed_atomic_type simple_type_or_string let_formal_type +%type packed_array_data_type atomic_type + +%type ps_type_identifier ps_type_identifier_dim %type simple_packed_type %type class_scope %type struct_union_member @@ -833,7 +972,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type net_type net_type_opt net_type_or_var net_type_or_var_opt %type gatetype switchtype %type port_direction port_direction_opt -%type integer_vector_type +%type integer_vector_type integer_vector_type_no_reg %type parameter_value_opt %type event_expression_list @@ -877,6 +1016,15 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type compressed_operator %type forward_type forward_type_without_enum +%type data_type_or_implicit_plus_id_base +%type data_type_or_implicit_plus_id +%type data_type_or_implicit_plus_id_dim +%type data_type_or_implicit_or_void_plus_id +%type data_type_or_parameter_id_base +%type data_type_or_parameter_id_dim +%type partial_port_name_dim +%type partial_port_type_plus_id_dim +%type partial_port_typedef_plus_id_dim %token K_TAND %nonassoc K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -980,7 +1128,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */ { // Process a class. pform_end_class_declaration(@9); } - class_declaration_endlabel_opt + label_opt { // Wrap up the class. check_end_label(@11, "class", $4, $11); delete[] $4; @@ -999,14 +1147,6 @@ identifier_name | TYPE_IDENTIFIER { $$ = $1.text; } ; - /* The endlabel after a class declaration is a little tricky because - the class name is detected by the lexor as a TYPE_IDENTIFIER if it - does indeed match a name. */ -class_declaration_endlabel_opt - : ':' identifier_name { $$ = $2; } - | { $$ = 0; } - ; - /* This rule implements [ extends class_type ] in the class_declaration. It is not a rule of its own in the LRM. @@ -1059,11 +1199,11 @@ class_item /* IEEE1800-2005: A.1.8 */ /* IEEE1800-2017: A.1.9 Class items: Class properties... */ - | property_qualifier_opt data_type list_of_variable_decl_assignments ';' - { pform_class_property(@2, $1, $2, $3); } + | property_qualifier_opt list_of_variable_decl_assignments_with_type ';' + { pform_class_property(@2, $1, $2.type, $2.decl_assignments); } - | K_const class_item_qualifier_opt data_type list_of_variable_decl_assignments ';' - { pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3, $4); } + | K_const class_item_qualifier_opt list_of_variable_decl_assignments_with_type ';' + { pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3.type, $3.decl_assignments); } /* IEEEE1800-2017: A.1.9 Class items: class_item ::= { property_qualifier} data_declaration */ @@ -1099,11 +1239,6 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ - | property_qualifier_opt data_type error ';' - { yyerror(@3, "error: Errors in variable names after data type."); - yyerrok; - } - | property_qualifier_opt IDENTIFIER error ';' { yyerror(@3, "error: %s doesn't name a type.", $2); yyerrok; @@ -1332,13 +1467,13 @@ data_declaration /* IEEE1800-2005: A.2.1.3 */ $1, $2); var_lifetime = LexicalScope::INHERITED; } - | attribute_list_opt K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t *data_type = $5; + | attribute_list_opt K_const_opt K_var variable_lifetime_opt list_of_variable_decl_assignments_with_type ';' + { data_type_t*data_type = $5.type; if (!data_type) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); FILE_NAME(data_type, @3); } - pform_make_var(@3, $6, data_type, $1, $2); + pform_make_var(@3, $5.decl_assignments, data_type, $1, $2); var_lifetime = LexicalScope::INHERITED; } | attribute_list_opt K_event event_variable_list ';' @@ -1354,6 +1489,7 @@ package_scope } ; + // Type identifiers with and without attached packed dimensions. ps_type_identifier /* IEEE1800-2017: A.9.3 */ : TYPE_IDENTIFIER { pform_set_type_referenced(@1, $1.text); @@ -1369,17 +1505,33 @@ ps_type_identifier /* IEEE1800-2017: A.9.3 */ } ; +ps_type_identifier_dim /* IEEE1800-2017: A.9.3 */ + : TYPE_IDENTIFIER dimensions_opt + { pform_set_type_referenced(@1, $1.text); + data_type_t*tmp = new typeref_t($1.type); + FILE_NAME(tmp, @1); + delete[]$1.text; + $$ = pform_make_parray_type(@2, tmp, $2); + } + | package_scope TYPE_IDENTIFIER dimensions_opt + { lex_in_package_scope(nullptr); + data_type_t*tmp = new typeref_t($2.type, $1); + FILE_NAME(tmp, @2); + $$ = pform_make_parray_type(@3, tmp, $3); + delete[]$2.text; + } + ; + /* Data types that can have packed dimensions directly attached to it */ packed_array_data_type /* IEEE1800-2005: A.2.2.1 */ - : enum_data_type - { $$ = $1; } - | struct_data_type + : enum_data_type dimensions_opt + { $$ = pform_make_parray_type(@2, $1, $2); } + | struct_data_type dimensions_opt { if (!$1->packed_flag && !($1->union_flag && $1->soft_flag)) { yyerror(@1, "sorry: Unpacked structs not supported."); - } - $$ = $1; + } + $$ = pform_make_parray_type(@2, $1, $2); } - | ps_type_identifier ; simple_packed_type /* Integer and vector types */ @@ -1400,7 +1552,7 @@ simple_packed_type /* Integer and vector types */ } ; -data_type /* IEEE1800-2005: A.2.2.1 */ +atomic_type : simple_packed_type { $$ = $1; } @@ -1409,14 +1561,40 @@ data_type /* IEEE1800-2005: A.2.2.1 */ FILE_NAME(tmp, @1); $$ = tmp; } - | packed_array_data_type dimensions_opt - { if ($2) { - parray_type_t*tmp = new parray_type_t($1, $2); - FILE_NAME(tmp, @1); - $$ = tmp; - } else { - $$ = $1; - } + | packed_array_data_type { $$ = $1; } + | K_string + { string_type_t*tmp = new string_type_t; + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + +/* Data types allowed after the historical iverilog extension that permits an + extra leading `reg` in block declarations. Keep `reg` itself out of this + subset so ordinary `reg` declarations continue through the normal rules. */ +reg_prefixed_atomic_type + : integer_vector_type_no_reg unsigned_signed_opt dimensions_opt + { vector_type_t*tmp = new vector_type_t($1, $2, $3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | atom_type signed_unsigned_opt + { atom_type_t*tmp = new atom_type_t($1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_time unsigned_signed_opt + { atom_type_t*tmp = new atom_type_t(atom_type_t::TIME, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | packed_array_data_type + { $$ = $1; } | K_string { string_type_t*tmp = new string_type_t; @@ -1425,6 +1603,11 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; +data_type /* IEEE1800-2005: A.2.2.1 */ + : atomic_type { $$ = $1; } + | ps_type_identifier_dim { $$ = $1; } + ; + /* Data type or nothing, but not implicit */ data_type_opt : data_type { $$ = $1; } @@ -1436,6 +1619,11 @@ data_type_opt absent. The context may need that information to decide to resort to left context. */ +data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ + : data_type_opt { $$ = $1; } + | implicit_type { $$ = $1; } + ; + scalar_vector_opt /*IEEE1800-2005: optional support for packed array */ : K_vectored { /* Ignore */ } @@ -1445,14 +1633,8 @@ scalar_vector_opt /*IEEE1800-2005: optional support for packed array */ { /* Ignore */ } ; -data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ - : data_type_or_implicit_no_opt - | { $$ = nullptr; } - -data_type_or_implicit_no_opt - : data_type - { $$ = $1; } - | signing dimensions_opt +implicit_type + : signing dimensions_opt { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); tmp->implicit_flag = true; FILE_NAME(tmp, @1); @@ -1466,7 +1648,6 @@ data_type_or_implicit_no_opt } ; - data_type_or_implicit_or_void : data_type_or_implicit { $$ = $1; } @@ -1567,7 +1748,7 @@ description /* IEEE1800-2005: A.1.2 */ | package_declaration | discipline_declaration | package_item - | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' + | KK_attribute '(' identifier_name ',' STRING ',' STRING ')' { perm_string tmp3 = lex_strings.make($3); pform_set_type_attrib(tmp3, $5, $7); delete[] $3; @@ -1623,53 +1804,53 @@ for_step_opt definitions in the func_body to take on the scope of the function instead of the module. */ function_declaration /* IEEE1800-2005: A.2.6 */ - : K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';' + : K_function lifetime_opt data_type_or_implicit_or_void_plus_id ';' { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); + current_function = pform_push_function_scope(@1, $3.id, $2); } tf_item_list_opt statement_or_null_list_opt K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - current_function_set_statement($8? @8 : @4, $8); - pform_set_this_class(@4, current_function); + { current_function->set_ports($6); + current_function->set_return($3.type); + current_function_set_statement($7 ? @7 : @3, $7); + pform_set_this_class(@3, current_function); pform_pop_scope(); current_function = 0; } label_opt { // Last step: check any closing name. - check_end_label(@11, "function", $4, $11); - delete[]$4; + check_end_label(@10, "function", $3.id, $10); + delete[]$3.id; } - | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER + | K_function lifetime_opt data_type_or_implicit_or_void_plus_id { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); + current_function = pform_push_function_scope(@1, $3.id, $2); } '(' tf_port_list_opt ')' ';' block_item_decls_opt statement_or_null_list_opt K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - current_function_set_statement($11? @11 : @4, $11); - pform_set_this_class(@4, current_function); + { current_function->set_ports($6); + current_function->set_return($3.type); + current_function_set_statement($10 ? @10 : @3, $10); + pform_set_this_class(@3, current_function); pform_pop_scope(); current_function = 0; - if ($7 == 0) { - pform_requires_sv(@4, "Functions with no ports"); + if ($6 == 0) { + pform_requires_sv(@3, "Functions with no ports"); } } label_opt { // Last step: check any closing name. - check_end_label(@14, "function", $4, $14); - delete[]$4; + check_end_label(@13, "function", $3.id, $13); + delete[]$3.id; } /* Detect and recover from some errors. */ - | K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction + | K_function lifetime_opt data_type_or_implicit_or_void_plus_id error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -1681,34 +1862,34 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } label_opt { // Last step: check any closing name. - check_end_label(@8, "function", $4, $8); - delete[]$4; + check_end_label(@7, "function", $3.id, $7); + delete[]$3.id; } ; genvar_iteration /* IEEE1800-2012: A.4.2 */ - : IDENTIFIER '=' expression + : identifier_name '=' expression { $$.text = $1; $$.expr = $3; } - | IDENTIFIER compressed_operator expression + | identifier_name compressed_operator expression { $$.text = $1; $$.expr = pform_genvar_compressed(@1, $1, $2, $3);; } - | IDENTIFIER K_INCR + | identifier_name K_INCR { $$.text = $1; $$.expr = pform_genvar_inc_dec(@1, $1, true); } - | IDENTIFIER K_DECR + | identifier_name K_DECR { $$.text = $1; $$.expr = pform_genvar_inc_dec(@1, $1, false); } - | K_INCR IDENTIFIER + | K_INCR identifier_name { $$.text = $2; $$.expr = pform_genvar_inc_dec(@1, $2, true); } - | K_DECR IDENTIFIER + | K_DECR identifier_name { $$.text = $2; $$.expr = pform_genvar_inc_dec(@1, $2, false); } @@ -1772,7 +1953,13 @@ inside_expression /* IEEE1800-2005 A.8.3 */ integer_vector_type /* IEEE1800-2005: A.2.2.1 */ : K_reg { $$ = IVL_VT_LOGIC; } /* A synonym for logic. */ - | K_bit { $$ = IVL_VT_BOOL; } + | integer_vector_type_no_reg + { $$ = $1; + } + ; + +integer_vector_type_no_reg + : K_bit { $$ = IVL_VT_BOOL; } | K_logic { $$ = IVL_VT_LOGIC; } | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ ; @@ -1843,7 +2030,9 @@ loop_statement /* IEEE1800-2005: A.6.8 */ // statement in a synthetic named block. We can name the block // after the variable that we are creating, that identifier is // safe in the controlling scope. - | K_for '(' K_var_opt data_type IDENTIFIER '=' expression ';' expression_opt ';' for_step_opt ')' + | K_for '(' K_var_opt data_type identifier_name + // Make the loop variable symbol visible while parsing the rest of + // the header. { static unsigned for_counter = 0; char for_block_name [64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_for_loop%u", for_counter); @@ -1857,6 +2046,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ assign_list.push_back(tmp_assign); pform_make_var(@5, &assign_list, $4); } + '=' expression ';' expression_opt ';' for_step_opt ')' statement_or_null { pform_name_t tmp_hident; tmp_hident.push_back(name_component_t(lex_strings.make($5))); @@ -1864,8 +2054,8 @@ loop_statement /* IEEE1800-2005: A.6.8 */ PEIdent*tmp_ident = pform_new_ident(@5, tmp_hident); FILE_NAME(tmp_ident, @5); - check_for_loop(@1, $7, $9, $11); - PForStatement*tmp_for = new PForStatement(tmp_ident, $7, $9, $11, $14); + check_for_loop(@1, $8, $10, $12); + PForStatement*tmp_for = new PForStatement(tmp_ident, $8, $10, $12, $14); FILE_NAME(tmp_for, @1); pform_pop_scope(); @@ -1904,7 +2094,7 @@ loop_statement /* IEEE1800-2005: A.6.8 */ // When matching a foreach loop, implicitly create a named block // to hold the definitions for the index variables. - | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' + | K_foreach '(' identifier_name '[' loop_variables ']' ')' { static unsigned foreach_counter = 0; char for_block_name[64]; snprintf(for_block_name, sizeof for_block_name, "$ivl_foreach%u", foreach_counter); @@ -1956,12 +2146,24 @@ loop_statement /* IEEE1800-2005: A.6.8 */ yyerror(@1, "error: Error in do/while loop condition."); } - | K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null + | K_foreach '(' identifier_name '[' error ']' ')' statement_or_null { $$ = 0; yyerror(@4, "error: Errors in foreach loop variables list."); } ; +list_of_variable_decl_assignments_with_type /* IEEE1800-2005 A.2.3 */ + : data_type_or_implicit_plus_id_dim var_decl_initializer_opt + { std::list*tmp = new std::list; + tmp->push_back(pform_make_var_decl(@1, $1.id, $1.lexical_pos, $1.ranges, $2)); + $$.decl_assignments = tmp; + $$.type = $1.type; + } + | list_of_variable_decl_assignments_with_type ',' variable_decl_assignment + { $1.decl_assignments->push_back($3); + $$ = $1; + } + ; list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */ : variable_decl_assignment @@ -1988,29 +2190,14 @@ var_decl_initializer_opt ; variable_decl_assignment /* IEEE1800-2005 A.2.3 */ - : IDENTIFIER dimensions_opt var_decl_initializer_opt - { if ($3 && pform_peek_scope()->var_init_needs_explicit_lifetime() - && (var_lifetime == LexicalScope::INHERITED)) { - cerr << @1 << ": warning: Static variable initialization requires " - "explicit lifetime in this context." << endl; - warn_count += 1; - } - - decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = { lex_strings.make($1), @1.lexical_pos }; - if ($2) { - tmp->index = *$2; - delete $2; - } - tmp->expr.reset($3); - delete[]$1; - $$ = tmp; + : identifier_name dimensions_opt var_decl_initializer_opt + { $$ = pform_make_var_decl(@1, $1, $2, $3); } ; loop_variables /* IEEE1800-2005: A.6.8 */ - : loop_variables ',' IDENTIFIER + : loop_variables ',' identifier_name { std::list*tmp = $1; tmp->push_back(lex_strings.make($3)); delete[]$3; @@ -2021,7 +2208,7 @@ loop_variables /* IEEE1800-2005: A.6.8 */ tmp->push_back(perm_string()); $$ = tmp; } - | IDENTIFIER + | identifier_name { std::list*tmp = new std::list; tmp->push_back(lex_strings.make($1)); delete[]$1; @@ -2058,7 +2245,7 @@ modport_item_list ; modport_item - : IDENTIFIER + : identifier_name { pform_start_modport_item(@1, $1); } '(' modport_ports_list ')' { pform_end_modport_item(@1); } @@ -2077,7 +2264,7 @@ modport_ports_list | modport_ports_list ',' named_expression { if (last_modport_port.type == MP_SIMPLE) { pform_add_modport_port(@3, last_modport_port.direction, - $3->name, $3->parm); + $3->name, $3->parm); } else { yyerror(@3, "error: modport expression not allowed here."); } @@ -2087,7 +2274,7 @@ modport_ports_list { if (last_modport_port.type != MP_TF) yyerror(@3, "error: task/function declaration not allowed here."); } - | modport_ports_list ',' IDENTIFIER + | modport_ports_list ',' identifier_name { if (last_modport_port.type == MP_SIMPLE) { pform_add_modport_port(@3, last_modport_port.direction, lex_strings.make($3), 0); @@ -2101,7 +2288,7 @@ modport_ports_list ; modport_ports_declaration - : attribute_list_opt port_direction IDENTIFIER + : attribute_list_opt port_direction identifier_name { last_modport_port.type = MP_SIMPLE; last_modport_port.direction = $2; pform_add_modport_port(@3, $2, lex_strings.make($3), 0); @@ -2115,7 +2302,7 @@ modport_ports_declaration delete $3; delete $1; } - | attribute_list_opt import_export IDENTIFIER + | attribute_list_opt import_export identifier_name { last_modport_port.type = MP_TF; last_modport_port.is_import = $2; yyerror(@3, "sorry: modport task/function ports are not yet supported."); @@ -2128,7 +2315,7 @@ modport_ports_declaration yyerror(@3, "sorry: modport task/function ports are not yet supported."); delete $1; } - | attribute_list_opt K_clocking IDENTIFIER + | attribute_list_opt K_clocking identifier_name { last_modport_port.type = MP_CLOCKING; last_modport_port.direction = NetNet::NOT_A_PORT; yyerror(@3, "sorry: modport clocking declaration is not yet supported."); @@ -2169,7 +2356,7 @@ open_range_list /* IEEE1800-2005 A.2.11 */ ; package_declaration /* IEEE1800-2005 A.1.2 */ - : K_package lifetime_opt IDENTIFIER ';' + : K_package lifetime_opt identifier_name ';' { pform_start_package_declaration(@1, $3, $2); } timeunits_declaration_opt { pform_set_scope_timescale(@1); } @@ -2197,16 +2384,11 @@ package_import_declaration /* IEEE1800-2005 A.2.1.3 */ ; package_import_item - : package_scope IDENTIFIER + : package_scope identifier_name { lex_in_package_scope(0); pform_package_import(@1, $1, $2); delete[]$2; } - | package_scope TYPE_IDENTIFIER - { lex_in_package_scope(0); - pform_package_import(@1, $1, $2.text); - delete[]$2.text; - } | package_scope '*' { lex_in_package_scope(0); pform_package_import(@1, $1, 0); @@ -2224,14 +2406,10 @@ package_export_declaration /* IEEE1800-2017 A.2.1.3 */ ; package_export_item - : PACKAGE_IDENTIFIER K_SCOPE_RES IDENTIFIER + : PACKAGE_IDENTIFIER K_SCOPE_RES identifier_name { pform_package_export(@2, $1, $3); delete[] $3; } - | PACKAGE_IDENTIFIER K_SCOPE_RES TYPE_IDENTIFIER - { pform_package_export(@2, $1, $3.text); - delete[] $3.text; - } | PACKAGE_IDENTIFIER K_SCOPE_RES '*' { pform_package_export(@2, $1, nullptr); } @@ -2483,7 +2661,11 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */ task_declaration /* IEEE1800-2005: A.2.7 */ - : K_task lifetime_opt IDENTIFIER ';' + /* Tasks do not have a return type, so the leading identifier is always the + task name. Use identifier_name so a name tokenized as TYPE_IDENTIFIER can + still declare a task that shadows a visible type name. */ + + : K_task lifetime_opt identifier_name ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -2510,7 +2692,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task lifetime_opt IDENTIFIER '(' + | K_task lifetime_opt identifier_name '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -2539,7 +2721,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ delete[]$3; } - | K_task lifetime_opt IDENTIFIER error K_endtask + | K_task lifetime_opt identifier_name error K_endtask { if (current_task) { pform_pop_scope(); @@ -2560,11 +2742,137 @@ task_declaration /* IEEE1800-2005: A.2.7 */ tf_port_declaration /* IEEE1800-2005: A.2.7 */ - : port_direction K_var_opt data_type_or_implicit list_of_port_identifiers ';' - { $$ = pform_make_task_ports(@1, $1, $3, $4, true); + : port_direction K_var_opt list_of_port_identifiers ';' + { $$ = pform_make_task_ports(@1, $1, $3.type, $3.ports, true); } ; + // These rules only disambiguate declaration items that can be either an + // implicit declaration name or an explicit type followed by a name. Keep the + // bare `TYPE_IDENTIFIER dimensions_opt` case in the parent rule so a typedef + // name can be shadowed by an unpacked declaration name, while + // `ps_type_identifier_dim identifier_name` still parses a typedef with packed + // dimensions followed by a separate declaration name. +data_type_or_implicit_plus_id_base + : IDENTIFIER + { set_type_id_range($$, nullptr, $1, @1, nullptr); + } + | atomic_type identifier_name + { set_type_id_range($$, $1, $2, @2, nullptr); + } + | implicit_type identifier_name + { set_type_id_range($$, $1, $2, @2, nullptr); + } + | ps_type_identifier_dim identifier_name + { set_type_id_range($$, $1, $2, @2, nullptr); + } + ; + + // Function declarations have the same type/name ambiguity as other + // declarations. For `function T;`, T can be the function name even when the + // lexer returns TYPE_IDENTIFIER, while `function T f;` still uses T as the + // explicit return type. Unlike variable/net declarations, function names do + // not allow unpacked dimensions. +data_type_or_implicit_plus_id + : TYPE_IDENTIFIER + { set_type_id_range($$, nullptr, $1.text, @1, nullptr); + } + | data_type_or_implicit_plus_id_base + { $$ = $1; + } + ; + +data_type_or_implicit_plus_id_dim + : TYPE_IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1.text, @1, $2); + } + | data_type_or_implicit_plus_id_base dimensions_opt + { $$ = $1; + $$.ranges = $2; + } + ; + + // Parameter port lists can omit the `parameter` keyword, but the optional + // type in that form is a data_type, not data_type_or_implicit. Keep this + // separate from data_type_or_implicit_plus_id_dim so a bare typedef name can + // still be parsed as a parameter name while implicit types like `signed P` + // and `[3:0] P` are rejected. +data_type_or_parameter_id_base + : IDENTIFIER + { set_type_id_range($$, nullptr, $1, @1, nullptr); + } + | atomic_type identifier_name + { set_type_id_range($$, $1, $2, @2, nullptr); + } + | ps_type_identifier_dim identifier_name + { set_type_id_range($$, $1, $2, @2, nullptr); + } + ; + +data_type_or_parameter_id_dim + : TYPE_IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1.text, @1, $2); + } + | data_type_or_parameter_id_base dimensions_opt + { $$ = $1; + $$.ranges = $2; + } + ; + + // `void` is only an explicit return type. The following identifier is still a + // function name and may be tokenized as TYPE_IDENTIFIER when it shadows a + // visible type name. +data_type_or_implicit_or_void_plus_id + : data_type_or_implicit_plus_id + { $$ = $1; + } + | K_void identifier_name + { void_type_t*tmp = new void_type_t; + FILE_NAME(tmp, @1); + set_type_id_range($$, tmp, $2, @2, nullptr); + } + ; + + // Partial ANSI port declarations such as `input a, integer b` can redeclare + // the data type without repeating the direction. Keep this narrower than + // data_type_or_implicit_plus_id_dim so a bare identifier after a comma is + // still parsed as a continuation of the previous port declaration. +partial_port_type_plus_id_dim + : atomic_type identifier_name dimensions_opt + { set_type_id_range($$, $1, $2, @2, $3); + } + | implicit_type identifier_name dimensions_opt + { set_type_id_range($$, $1, $2, @2, $3); + } + ; + +partial_port_name_dim + : IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1, @1, $2); + } + | TYPE_IDENTIFIER dimensions_opt + { set_type_id_range($$, nullptr, $1.text, @1, $2); + } + ; + +partial_port_typedef_plus_id_dim + : TYPE_IDENTIFIER dimensions_opt identifier_name dimensions_opt + { pform_set_type_referenced(@1, $1.text); + data_type_t*tmp = new typeref_t($1.type); + FILE_NAME(tmp, @1); + delete[]$1.text; + tmp = pform_make_parray_type(@2, tmp, $2); + set_type_id_range($$, tmp, $3, @3, $4); + } + | package_scope TYPE_IDENTIFIER dimensions_opt identifier_name dimensions_opt + { lex_in_package_scope(nullptr); + data_type_t*tmp = new typeref_t($2.type, $1); + FILE_NAME(tmp, @2); + delete[]$2.text; + tmp = pform_make_parray_type(@3, tmp, $3); + set_type_id_range($$, tmp, $4, @4, $5); + } + ; /* These rules for tf_port_item are slightly expanded from the strict rules in the LRM to help with LALR parsing. @@ -2576,61 +2884,62 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */ tf_port_item /* IEEE1800-2005: A.2.7 */ - : port_direction_opt K_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt + : port_direction_opt K_var_opt data_type_or_implicit_plus_id_dim initializer_opt { std::vector*tmp; NetNet::PortType use_port_type = $1; - if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($3 == 0))) + if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || !$3.type)) use_port_type = port_declaration_context.port_type; - list* port_list = make_port_list($4, @4.lexical_pos, $5, 0); + struct pform_port_list port_list = make_port_list($3.type, $3.id, + $3.lexical_pos, + $3.ranges, nullptr); if (use_port_type == NetNet::PIMPLICIT) { yyerror(@1, "error: Missing task/function port direction."); use_port_type = NetNet::PINPUT; // for error recovery } - if (($3 == 0) && ($1==NetNet::PIMPLICIT)) { + if (!$3.type && ($1==NetNet::PIMPLICIT)) { // Detect special case this is an undecorated // identifier and we need to get the declaration from // left context. - if ($5 != 0) { - yyerror(@5, "internal error: How can there be an unpacked range here?\n"); - } - tmp = pform_make_task_ports(@4, use_port_type, + tmp = pform_make_task_ports(@3, use_port_type, port_declaration_context.data_type, - port_list); + port_list.ports); } else { // Otherwise, the decorations for this identifier // indicate the type. Save the type for any right // context that may come later. port_declaration_context.port_type = use_port_type; - if ($3 == 0) { - $3 = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME($3, @4); + if (!$3.type) { + $3.type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME($3.type, @3); } - port_declaration_context.data_type = $3; - tmp = pform_make_task_ports(@3, use_port_type, $3, port_list); + port_declaration_context.data_type = $3.type; + tmp = pform_make_task_ports(@3, use_port_type, $3.type, + port_list.ports); } $$ = tmp; - if ($6) { - pform_requires_sv(@6, "Task/function default argument"); + if ($4) { + pform_requires_sv(@4, "Task/function default argument"); assert(tmp->size()==1); - tmp->front().defe = $6; + tmp->front().defe = $4; } } /* Rules to match error cases... */ - | port_direction_opt K_var_opt data_type_or_implicit IDENTIFIER error - { yyerror(@3, "error: Error in task/function port item after port name %s.", $4); + | port_direction_opt K_var_opt data_type_or_implicit_plus_id_dim error + { yyerror(@3, "error: Error in task/function port item after port name %s.", $3.id); + delete_type_id_range($3); yyerrok; - $$ = 0; + $$ = nullptr; } ; tf_port_list /* IEEE1800-2005: A.2.7 */ : { port_declaration_context.port_type = gn_system_verilog() ? NetNet::PINPUT : NetNet::PIMPLICIT; - port_declaration_context.data_type = 0; + port_declaration_context.data_type = nullptr; } tf_port_item_list { $$ = $2; } @@ -2803,7 +3112,7 @@ attribute_list attribute - : IDENTIFIER initializer_opt + : identifier_name initializer_opt { named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); tmp->name = lex_strings.make($1); @@ -2825,13 +3134,13 @@ block_item_decl /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ - : K_const_opt K_var variable_lifetime_opt data_type_or_implicit list_of_variable_decl_assignments ';' - { data_type_t *data_type = $4; + : K_const_opt K_var variable_lifetime_opt list_of_variable_decl_assignments_with_type ';' + { data_type_t*data_type = $4.type; if (!data_type) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME(data_type, @2); } - pform_make_var(@2, $5, data_type, attributes_in_context, $1); + pform_make_var(@2, $4.decl_assignments, data_type, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } @@ -2840,8 +3149,8 @@ block_item_decl var_lifetime = LexicalScope::INHERITED; } - /* The extra `reg` is not valid (System)Verilog, this is a iverilog extension. */ - | K_const_opt variable_lifetime_opt K_reg data_type list_of_variable_decl_assignments ';' + /* The extra `reg` is not valid (System)Verilog, this is an iverilog extension. */ + | K_const_opt variable_lifetime_opt K_reg reg_prefixed_atomic_type list_of_variable_decl_assignments ';' { if ($4) pform_make_var(@4, $5, $4, attributes_in_context, $1); var_lifetime = LexicalScope::INHERITED; } @@ -2862,11 +3171,6 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - - | K_const_opt K_var variable_lifetime_opt data_type_or_implicit error ';' - { yyerror(@1, "error: Syntax error in variable list."); - yyerrok; - } | K_const_opt variable_lifetime_opt data_type error ';' { yyerror(@1, "error: Syntax error in variable list."); yyerrok; @@ -2954,13 +3258,8 @@ enum_base_type /* IEEE 1800-2012 A.2.2.1 */ : simple_packed_type { $$ = $1; } - | ps_type_identifier dimensions_opt - { if ($2) { - $$ = new parray_type_t($1, $2); - FILE_NAME($$, @1); - } else { - $$ = $1; - } + | ps_type_identifier_dim + { $$ = $1; } | { $$ = new atom_type_t(atom_type_t::INT, true); @@ -3001,20 +3300,23 @@ pos_neg_number } ; + /* Enum items are declaration names. Use identifier_name so an enum item can + shadow a visible type identifier without introducing a type/name + ambiguity. */ enum_name - : IDENTIFIER initializer_opt + : identifier_name initializer_opt { perm_string name = lex_strings.make($1); delete[]$1; $$ = make_named_number(@$, name, $2); } - | IDENTIFIER '[' pos_neg_number ']' initializer_opt + | identifier_name '[' pos_neg_number ']' initializer_opt { perm_string name = lex_strings.make($1); long count = check_enum_seq_value(@1, $3, false); $$ = make_named_numbers(@$, name, 0, count-1, $5); delete[]$1; delete $3; } - | IDENTIFIER '[' pos_neg_number ':' pos_neg_number ']' initializer_opt + | identifier_name '[' pos_neg_number ':' pos_neg_number ']' initializer_opt { perm_string name = lex_strings.make($1); $$ = make_named_numbers(@$, name, check_enum_seq_value(@1, $3, true), check_enum_seq_value(@1, $5, true), $7); @@ -3274,7 +3576,7 @@ delay_value_simple FILE_NAME($$, @1); } } - | IDENTIFIER + | identifier_name { PEIdent*tmp = new PEIdent(lex_strings.make($1), @1.lexical_pos); FILE_NAME(tmp, @1); $$ = tmp; @@ -3312,7 +3614,7 @@ delay_value_simple optional_semicolon : ';' | ; discipline_declaration - : K_discipline IDENTIFIER optional_semicolon + : K_discipline identifier_name optional_semicolon { pform_start_discipline($2); } discipline_items K_enddiscipline { pform_end_discipline(@1); delete[] $2; } @@ -3328,14 +3630,14 @@ discipline_item { pform_discipline_domain(@1, IVL_DIS_DISCRETE); } | K_domain K_continuous ';' { pform_discipline_domain(@1, IVL_DIS_CONTINUOUS); } - | K_potential IDENTIFIER ';' + | K_potential identifier_name ';' { pform_discipline_potential(@1, $2); delete[] $2; } - | K_flow IDENTIFIER ';' + | K_flow identifier_name ';' { pform_discipline_flow(@1, $2); delete[] $2; } ; nature_declaration - : K_nature IDENTIFIER optional_semicolon + : K_nature identifier_name optional_semicolon { pform_start_nature($2); } nature_items K_endnature @@ -3351,16 +3653,16 @@ nature_item : K_units '=' STRING ';' { delete[] $3; } | K_abstol '=' expression ';' - | K_access '=' IDENTIFIER ';' + | K_access '=' identifier_name ';' { pform_nature_access(@1, $3); delete[] $3; } - | K_idt_nature '=' IDENTIFIER ';' + | K_idt_nature '=' identifier_name ';' { delete[] $3; } - | K_ddt_nature '=' IDENTIFIER ';' + | K_ddt_nature '=' identifier_name ';' { delete[] $3; } ; config_declaration - : K_config IDENTIFIER ';' + : K_config identifier_name ';' K_design lib_cell_identifiers ';' list_of_config_rule_statements K_endconfig @@ -3527,9 +3829,9 @@ event_expression or explicit as a named branch. Elaboration will check that the function name really is a nature attribute identifier. */ branch_probe_expression - : IDENTIFIER '(' IDENTIFIER ',' IDENTIFIER ')' + : identifier_name '(' identifier_name ',' identifier_name ')' { $$ = pform_make_branch_probe_expression(@1, $1, $3, $5); } - | IDENTIFIER '(' IDENTIFIER ')' + | identifier_name '(' identifier_name ')' { $$ = pform_make_branch_probe_expression(@1, $1, $3); } ; @@ -3936,6 +4238,26 @@ expr_primary_or_typename ; + /* SystemVerilog: a().b() — call a function, then invoke a method on the + returned class handle. Extends with further ".id(args)" as needed. */ + +call_chain_expr + : hierarchy_identifier attribute_list_opt argument_list_parens + { PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3); + delete $1; + delete $2; + delete $3; + $$ = tmp; + } + | call_chain_expr '.' hierarchy_identifier attribute_list_opt argument_list_parens + { PECallFunction*tmp = pform_make_chained_call_function(@2, $1, *$3, *$5); + delete $3; + delete $4; + delete $5; + $$ = tmp; + } + ; + expr_primary : number { assert($1); @@ -3995,6 +4317,10 @@ expr_primary /* The hierarchy_identifier rule matches simple identifiers as well as indexed arrays and part selects */ + /* SV call chains get_c1().f() — must come before bare hierarchy_identifier + so `id (` is not reduced as PEIdent + error. */ + | call_chain_expr + { $$ = $1; } | hierarchy_identifier { PEIdent*tmp = pform_new_ident(@1, *$1); FILE_NAME(tmp, @1); @@ -4045,13 +4371,6 @@ expr_primary function call. If a system identifier, then a system function call. It can also be a call to a class method (function). */ - | hierarchy_identifier attribute_list_opt argument_list_parens - { PECallFunction*tmp = pform_make_call_function(@1, *$1, *$3); - delete $1; - delete $2; - delete $3; - $$ = tmp; - } | class_hierarchy_identifier argument_list_parens { PECallFunction*tmp = pform_make_call_function(@1, *$1, *$2); delete $1; @@ -4535,7 +4854,7 @@ hierarchy_identifier $$->push_back(name_component_t(lex_strings.make($1))); delete[]$1; } - | hierarchy_identifier '.' IDENTIFIER + | hierarchy_identifier '.' identifier_name { pform_name_t * tmp = $1; tmp->push_back(name_component_t(lex_strings.make($3))); delete[]$3; @@ -4603,17 +4922,24 @@ list_of_identifiers { $$ = list_from_identifier($1, $3, @3.lexical_pos); } ; +genvar_identifier_list + : identifier_name + { $$ = list_from_identifier($1, @1.lexical_pos); } + | genvar_identifier_list ',' identifier_name + { $$ = list_from_identifier($1, $3, @3.lexical_pos); } + ; + list_of_port_identifiers - : IDENTIFIER dimensions_opt - { $$ = make_port_list($1, @1.lexical_pos, $2, 0); } - | list_of_port_identifiers ',' IDENTIFIER dimensions_opt - { $$ = make_port_list($1, $3, @3.lexical_pos, $4, 0); } + : data_type_or_implicit_plus_id_dim + { $$ = make_port_list($1.type, $1.id, $1.lexical_pos, $1.ranges, nullptr); } + | list_of_port_identifiers ',' identifier_name dimensions_opt + { $$ = make_port_list($1, $3, @3.lexical_pos, $4, nullptr); } ; list_of_variable_port_identifiers - : IDENTIFIER dimensions_opt initializer_opt - { $$ = make_port_list($1, @1.lexical_pos, $2, $3); } - | list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt initializer_opt + : data_type_or_implicit_plus_id_dim initializer_opt + { $$ = make_port_list($1.type, $1.id, $1.lexical_pos, $1.ranges, $2); } + | list_of_variable_port_identifiers ',' identifier_name dimensions_opt initializer_opt { $$ = make_port_list($1, $3, @3.lexical_pos, $4, $5); } ; @@ -4658,23 +4984,41 @@ list_of_port_declarations tmp->push_back($3); $$ = tmp; } - | list_of_port_declarations ',' attribute_list_opt IDENTIFIER dimensions_opt initializer_opt + | list_of_port_declarations ',' attribute_list_opt partial_port_name_dim initializer_opt { std::vector *ports = $1; Module::port_t* port; if (port_declaration_context.port_type == NetNet::NOT_A_PORT) { yyerror(@4, "error: Incomplete interface port declaration."); - delete[]$4; + delete_type_id_range($4); delete $5; - delete $6; delete $3; port = 0; } else { - port = module_declare_port(@4, $4, + port = module_declare_port(@4, $4.id, $4.lexical_pos, port_declaration_context.port_type, port_declaration_context.port_net_type, port_declaration_context.data_type, - $5, $6, $3); + $4.ranges, $5, $3); + } + ports->push_back(port); + $$ = ports; + } + | list_of_port_declarations ',' attribute_list_opt partial_port_typedef_plus_id_dim initializer_opt + { std::vector *ports = $1; + + Module::port_t* port; + if (port_declaration_context.port_type == NetNet::NOT_A_PORT) { + yyerror(@4, "error: Incomplete interface port declaration."); + delete_type_id_range($4); + delete $5; + delete $3; + port = 0; + } else { + port = module_declare_port(@4, $4.id, $4.lexical_pos, + port_declaration_context.port_type, + NetNet::IMPLICIT, $4.type, + $4.ranges, $5, $3); } ports->push_back(port); $$ = ports; @@ -4688,29 +5032,32 @@ list_of_port_declarations // All of port direction, port kind and data type are optional, but at least // one has to be specified, so we need multiple rules. port_declaration - : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt - { $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1); + : attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit_plus_id_dim initializer_opt + { $$ = module_declare_port(@4, $4.id, $4.lexical_pos, + $2, $3, $4.type, $4.ranges, $5, $1); } - | attribute_list_opt INTERFACE_IDENTIFIER '.' IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER '.' identifier_name identifier_name dimensions_opt { $$ = module_declare_interface_port(@5, $2, $4, $5, $6, $1); } - | attribute_list_opt INTERFACE_IDENTIFIER IDENTIFIER dimensions_opt + | attribute_list_opt INTERFACE_IDENTIFIER identifier_name dimensions_opt { $$ = module_declare_interface_port(@3, $2, 0, $3, $4, $1); } - | attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt - { pform_requires_sv(@4, "Partial ANSI port declaration"); - $$ = module_declare_port(@4, $4, port_declaration_context.port_type, - $2, $3, $5, $6, $1); - } - | attribute_list_opt data_type_or_implicit_no_opt IDENTIFIER dimensions_opt initializer_opt + | attribute_list_opt net_type_or_var data_type_or_implicit_plus_id_dim initializer_opt { pform_requires_sv(@3, "Partial ANSI port declaration"); - $$ = module_declare_port(@3, $3, port_declaration_context.port_type, - NetNet::IMPLICIT, $2, $4, $5, $1); + $$ = module_declare_port(@3, $3.id, $3.lexical_pos, + port_declaration_context.port_type, + $2, $3.type, $3.ranges, $4, $1); } - | attribute_list_opt port_direction K_wreal IDENTIFIER + | attribute_list_opt partial_port_type_plus_id_dim initializer_opt + { pform_requires_sv(@2, "Partial ANSI port declaration"); + $$ = module_declare_port(@2, $2.id, $2.lexical_pos, + port_declaration_context.port_type, + NetNet::IMPLICIT, $2.type, $2.ranges, $3, $1); + } + | attribute_list_opt port_direction K_wreal identifier_name { real_type_t*real_type = new real_type_t(real_type_t::REAL); FILE_NAME(real_type, @3); - $$ = module_declare_port(@4, $4, $2, NetNet::WIRE, + $$ = module_declare_port(@4, $4, @4.lexical_pos, $2, NetNet::WIRE, real_type, nullptr, nullptr, $1); } ; @@ -4809,7 +5156,7 @@ cont_assign_list items, and finally an end marker. */ module - : attribute_list_opt module_start lifetime_opt IDENTIFIER + : attribute_list_opt module_start lifetime_opt identifier_name { pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1); port_declaration_context_init(); } module_package_import_list_opt @@ -4911,12 +5258,17 @@ module_end ; label_opt - : ':' IDENTIFIER { $$ = $2; } + : ':' identifier_name { $$ = $2; } | { $$ = 0; } ; module_attribute_foreign - : K_PSTAR IDENTIFIER K_integer IDENTIFIER '=' STRING ';' K_STARP { $$ = 0; } + : K_PSTAR identifier_name K_integer identifier_name '=' STRING ';' K_STARP + { delete[] $2; + delete[] $4; + delete[] $6; + $$ = 0; + } | { $$ = 0; } ; @@ -4960,38 +5312,27 @@ type_param ; module_parameter - : parameter param_type parameter_assign - | localparam param_type parameter_assign + : parameter parameter_assign_with_type + | localparam parameter_assign_with_type { pform_requires_sv(@1, "Local parameter in module parameter port list"); } ; module_parameter_port_list : module_parameter - | data_type_opt - { param_data_type = $1; - param_is_local = false; - param_is_type = false; - param_type_restrict = {}; - } - parameter_assign - { pform_requires_sv(@3, "Omitting initial `parameter` in parameter port " + | value_parameter_assign_without_parameter + { pform_requires_sv(@1, "Omitting initial `parameter` in parameter port " "list"); } | type_param { param_is_local = false; } parameter_assign | module_parameter_port_list ',' module_parameter - | module_parameter_port_list ',' data_type_opt - { if ($3) { - pform_requires_sv(@3, "Omitting `parameter`/`localparam` before " - "data type in parameter port list"); - param_data_type = $3; - param_is_type = false; - param_type_restrict = {}; - } + | module_parameter_port_list ',' parameter_assign + | module_parameter_port_list ',' value_parameter_assign_with_explicit_type + { pform_requires_sv(@3, "Omitting `parameter`/`localparam` before " + "data type in parameter port list"); } - parameter_assign | module_parameter_port_list ',' type_param parameter_assign ; @@ -5004,7 +5345,19 @@ module_item net_decl_assigns, which are = assignment declarations. */ - | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3_opt net_decl_assigns ';' + | attribute_list_opt net_type drive_strength_opt list_of_net_decl_assignments_with_type ';' + { data_type_t*data_type = $4.type; + pform_check_net_data_type(@2, $2, data_type); + check_net_decl_assigns(@4, $4.decl_assignments); + if (!data_type) { + data_type = new vector_type_t(IVL_VT_LOGIC, false, nullptr); + FILE_NAME(data_type, @2); + } + pform_makewire(@2, nullptr, $3, $4.decl_assignments, $2, data_type, $1); + delete $1; + } + + | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3 net_decl_assigns ';' { data_type_t*data_type = $4; pform_check_net_data_type(@2, $2, $4); check_net_decl_assigns(@6, $6); @@ -5038,12 +5391,12 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | attribute_list_opt port_direction net_type_or_var data_type_or_implicit list_of_port_identifiers ';' - { pform_module_define_port(@2, $5, $2, $3, $4, $1); } + | attribute_list_opt port_direction net_type_or_var list_of_port_identifiers ';' + { pform_module_define_port(@2, $4.ports, $2, $3, $4.type, $1); } | attribute_list_opt port_direction K_wreal list_of_port_identifiers ';' { real_type_t*real_type = new real_type_t(real_type_t::REAL); - pform_module_define_port(@2, $4, $2, NetNet::WIRE, real_type, $1); + pform_module_define_port(@2, $4.ports, $2, NetNet::WIRE, real_type, $1); } /* The next three rules handle port declarations that include a variable @@ -5052,33 +5405,33 @@ module_item and also handle incomplete port declarations, e.g. input signed [h:l] ; */ - | attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_inout list_of_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::PINOUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::PINOUT, use_type, $3.type, $1); } - | attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_input list_of_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::PINPUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::PINPUT, use_type, $3.type, $1); } - | attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';' - { NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE; - if (const vector_type_t*dtype = dynamic_cast ($3)) { + | attribute_list_opt K_output list_of_variable_port_identifiers ';' + { NetNet::Type use_type = $3.type ? NetNet::IMPLICIT : NetNet::NONE; + if (vector_type_t*dtype = dynamic_cast ($3.type)) { if (dtype->implicit_flag) use_type = NetNet::NONE; else @@ -5088,40 +5441,36 @@ module_item // output ports are implicitly (on the inside) // variables because "reg" is not valid syntax // here. - } else if ($3) { + } else if ($3.type) { use_type = NetNet::IMPLICIT_REG; } if (use_type == NetNet::NONE) - pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1); + pform_set_port_type(@2, $3.ports, NetNet::POUTPUT, $3.type, $1); else - pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1); + pform_module_define_port(@2, $3.ports, NetNet::POUTPUT, use_type, $3.type, $1); } - | attribute_list_opt port_direction net_type_or_var data_type_or_implicit error ';' + | attribute_list_opt port_direction net_type_or_var error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($4) delete $4; yyerrok; } - | attribute_list_opt K_inout data_type_or_implicit error ';' + | attribute_list_opt K_inout error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } - | attribute_list_opt K_input data_type_or_implicit error ';' + | attribute_list_opt K_input error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } - | attribute_list_opt K_output data_type_or_implicit error ';' + | attribute_list_opt K_output error ';' { yyerror(@2, "error: Invalid variable list in port declaration."); if ($1) delete $1; - if ($3) delete $3; yyerrok; } @@ -5290,10 +5639,10 @@ module_item | K_generate { check_in_gen_region(@1); } generate_item_list_opt K_endgenerate { in_gen_region = false; } - | K_genvar list_of_identifiers ';' + | K_genvar genvar_identifier_list ';' { pform_genvars(@1, $2); } - | K_for '(' K_genvar_opt IDENTIFIER '=' expression ';' + | K_for '(' K_genvar_opt identifier_name '=' expression ';' expression ';' genvar_iteration ')' { pform_start_generate_for(@2, $3, $4, $6, $8, $10.text, $10.expr); } @@ -5386,7 +5735,7 @@ module_item /* These rules are for the Icarus Verilog specific $attribute extensions. Then catch the parameters of the $attribute keyword. */ - | KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')' ';' + | KK_attribute '(' identifier_name ',' STRING ',' STRING ')' ';' { perm_string tmp3 = lex_strings.make($3); perm_string tmp5 = lex_strings.make($5); pform_set_attrib(tmp3, tmp5, $7); @@ -5479,7 +5828,7 @@ generate_item cerr << @1 << ": warning: Anachronistic use of begin/end to surround generate schemes." << endl; } } - | K_begin ':' IDENTIFIER + | K_begin ':' identifier_name { pform_start_generate_nblock(@1, $3); } generate_item_list_opt K_end { /* Detect and warn about anachronistic named begin/end use */ @@ -5532,19 +5881,22 @@ net_decl_initializer_opt | { $$ = 0; } ; +list_of_net_decl_assignments_with_type /* IEEE1800-2005 A.2.5 */ + : data_type_or_implicit_plus_id_dim net_decl_initializer_opt + { std::list*tmp = new std::list; + tmp->push_back(pform_make_net_decl(@1, $1.id, $1.lexical_pos, $1.ranges, $2)); + $$.decl_assignments = tmp; + $$.type = $1.type; + } + | list_of_net_decl_assignments_with_type ',' net_decl_assign + { $1.decl_assignments->push_back($3); + $$ = $1; + } + ; + net_decl_assign - : IDENTIFIER dimensions_opt net_decl_initializer_opt - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = { lex_strings.make($1), @1.lexical_pos }; - if ($2) { - tmp->index = *$2; - if ($3) - pform_requires_sv(@$, "Assignment of net array during declaration"); - delete $2; - } - tmp->expr.reset($3); - delete[]$1; - $$ = tmp; + : identifier_name dimensions_opt net_decl_initializer_opt + { $$ = pform_make_net_decl(@1, $1, $2, $3); } ; @@ -5594,19 +5946,6 @@ net_type_or_var_opt | K_var { $$ = NetNet::REG; } ; - /* The param_type rule is just the data_type_or_implicit rule wrapped - with an assignment to para_data_type with the figured data type. - This is used by parameter_assign, which is found to the right of - the param_type in various rules. */ - -param_type - : data_type_or_implicit - { param_is_type = false; - param_data_type = $1; - param_type_restrict = {}; - } - | type_param - parameter : K_parameter { param_is_local = false; } @@ -5618,7 +5957,7 @@ localparam ; parameter_declaration - : parameter_or_localparam param_type parameter_assign_list ';' + : parameter_or_localparam parameter_assign_list_with_type ';' parameter_or_localparam : parameter @@ -5630,9 +5969,76 @@ parameter_or_localparam handling code. localparams parse the same as parameters, they just behave differently when someone tries to override them. */ -parameter_assign_list - : parameter_assign - | parameter_assign_list ',' parameter_assign + // The first parameter assignment is parsed together with the optional type + // so `parameter T` can shadow a typedef name, while `parameter T p` still + // parses T as the parameter type. Continuations keep the previous type, so a + // bare typedef name after a comma is still a parameter name. +parameter_assign_list_with_type + : parameter_assign_with_type + | parameter_assign_list_with_type ',' parameter_assign + ; + +parameter_assign_with_type + : value_parameter_assign_with_type + | type_param parameter_assign + ; + +value_parameter_assign_with_type + : data_type_or_implicit_plus_id_dim initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1.type; + YYLTYPE id_loc = @1; + id_loc.first_line = $1.first_line; + id_loc.first_column = $1.first_column; + id_loc.last_line = $1.last_line; + id_loc.last_column = $1.last_column; + id_loc.lexical_pos = $1.lexical_pos; + pform_set_parameter(id_loc, $1.id, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $1.ranges, $2, $3); + } + ; + +value_parameter_assign_without_parameter + : data_type_or_parameter_id_dim initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1.type; + YYLTYPE id_loc = @1; + id_loc.first_line = $1.first_line; + id_loc.first_column = $1.first_column; + id_loc.last_line = $1.last_line; + id_loc.last_column = $1.last_column; + id_loc.lexical_pos = $1.lexical_pos; + pform_set_parameter(id_loc, $1.id, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $1.ranges, $2, $3); + } + ; + + // Parameter port lists allow an explicit type after a comma without + // repeating `parameter`, e.g. `#(parameter p = 1, int q = 2)`. Keep this + // narrower than value_parameter_assign_with_type so a bare typedef name + // after a comma remains a parameter name that inherits the previous type. The + // LRM allows data_type here, but not implicit_type. +value_parameter_assign_with_explicit_type + : atomic_type identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1; + pform_set_parameter(@2, $2, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $3, $4, $5); + } + | ps_type_identifier_dim identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1; + pform_set_parameter(@2, $2, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $3, $4, $5); + } ; parameter_assign @@ -5642,6 +6048,12 @@ parameter_assign param_data_type, $2, $3, $4); delete[]$1; } + | TYPE_IDENTIFIER dimensions_opt initializer_opt parameter_value_ranges_opt + { pform_set_parameter(@1, lex_strings.make($1.text), param_is_local, + param_is_type, param_type_restrict, + param_data_type, $2, $3, $4); + delete[]$1.text; + } ; parameter_value_ranges_opt : parameter_value_ranges { $$ = $1; } | { $$ = 0; } ; @@ -5736,7 +6148,7 @@ parameter_value_opt ; named_expression - : '.' IDENTIFIER '(' expression ')' + : '.' identifier_name '(' expression ')' { named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); tmp->name = lex_strings.make($2); @@ -5747,7 +6159,7 @@ named_expression named_expression_opt : named_expression - | '.' IDENTIFIER '(' ')' + | '.' identifier_name '(' ')' { named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); tmp->name = lex_strings.make($2); @@ -5795,7 +6207,7 @@ port references. The port_t object gets its PWire from the port_reference, but its name from the IDENTIFIER. */ - | '.' IDENTIFIER '(' port_reference ')' + | '.' identifier_name '(' port_reference ')' { Module::port_t*tmp = $4; tmp->name = lex_strings.make($2); delete[]$2; @@ -5815,7 +6227,7 @@ port /* This attaches a name to a port reference concatenation list so that parameter passing be name is possible. */ - | '.' IDENTIFIER '(' '{' port_reference_list '}' ')' + | '.' identifier_name '(' '{' port_reference_list '}' ')' { Module::port_t*tmp = $5; tmp->name = lex_strings.make($2); delete[]$2; @@ -5837,7 +6249,7 @@ port_name { delete $1; $$ = $2; } - | attribute_list_opt '.' IDENTIFIER '(' error ')' + | attribute_list_opt '.' identifier_name '(' error ')' { yyerror(@3, "error: Invalid port connection expression."); named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); @@ -5847,7 +6259,7 @@ port_name delete $1; $$ = tmp; } - | attribute_list_opt '.' IDENTIFIER + | attribute_list_opt '.' identifier_name { pform_requires_sv(@3, "Implicit named port connections"); named_pexpr_t*tmp = new named_pexpr_t; FILE_NAME(tmp, @$); @@ -5918,14 +6330,14 @@ port_conn_expression_list_with_nuls port_t object to pass it up to the module declaration code. */ port_reference - : IDENTIFIER + : identifier_name { Module::port_t*ptmp; perm_string name = lex_strings.make($1); ptmp = pform_module_port_reference(@1, name); delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' expression ':' expression ']' + | identifier_name '[' expression ':' expression ']' { index_component_t itmp; itmp.sel = index_component_t::SEL_PART; itmp.msb = $3; @@ -5948,7 +6360,7 @@ port_reference delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' expression ']' + | identifier_name '[' expression ']' { index_component_t itmp; itmp.sel = index_component_t::SEL_BIT; itmp.msb = $3; @@ -5970,7 +6382,7 @@ port_reference delete[]$1; $$ = ptmp; } - | IDENTIFIER '[' error ']' + | identifier_name '[' error ']' { yyerror(@1, "error: Invalid port bit select"); Module::port_t*ptmp = new Module::port_t; PEIdent*wtmp = new PEIdent(lex_strings.make($1), @1.lexical_pos); @@ -6015,7 +6427,7 @@ dimensions ; event_variable - : IDENTIFIER dimensions_opt + : identifier_name dimensions_opt { if ($2) { yyerror(@2, "sorry: event arrays are not supported."); delete $2; @@ -6340,13 +6752,13 @@ specify_simple_path ; specify_path_identifiers - : IDENTIFIER + : identifier_name { std::list*tmp = new std::list; tmp->push_back(lex_strings.make($1)); $$ = tmp; delete[]$1; } - | IDENTIFIER '[' expr_primary ']' + | identifier_name '[' expr_primary ']' { if (gn_specify_blocks_flag) { yywarn(@4, "warning: Bit selects are not currently supported " "in path declarations. The declaration " @@ -6357,7 +6769,7 @@ specify_path_identifiers $$ = tmp; delete[]$1; } - | IDENTIFIER '[' expr_primary polarity_operator expr_primary ']' + | identifier_name '[' expr_primary polarity_operator expr_primary ']' { if (gn_specify_blocks_flag) { yywarn(@4, "warning: Part selects are not currently supported " "in path declarations. The declaration " @@ -6368,13 +6780,13 @@ specify_path_identifiers $$ = tmp; delete[]$1; } - | specify_path_identifiers ',' IDENTIFIER + | specify_path_identifiers ',' identifier_name { std::list*tmp = $1; tmp->push_back(lex_strings.make($3)); $$ = tmp; delete[]$3; } - | specify_path_identifiers ',' IDENTIFIER '[' expr_primary ']' + | specify_path_identifiers ',' identifier_name '[' expr_primary ']' { if (gn_specify_blocks_flag) { yywarn(@4, "warning: Bit selects are not currently supported " "in path declarations. The declaration " @@ -6385,7 +6797,7 @@ specify_path_identifiers $$ = tmp; delete[]$3; } - | specify_path_identifiers ',' IDENTIFIER '[' expr_primary polarity_operator expr_primary ']' + | specify_path_identifiers ',' identifier_name '[' expr_primary polarity_operator expr_primary ']' { if (gn_specify_blocks_flag) { yywarn(@4, "warning: Part selects are not currently supported " "in path declarations. The declaration " @@ -6399,7 +6811,7 @@ specify_path_identifiers ; specparam - : IDENTIFIER '=' expr_mintypmax + : identifier_name '=' expr_mintypmax { pform_set_specparam(@1, lex_strings.make($1), specparam_active_range, $3); delete[]$1; } @@ -7296,7 +7708,7 @@ udp_sequ_entry ; udp_initial - : K_initial IDENTIFIER '=' number ';' + : K_initial identifier_name '=' number ';' { PExpr*etmp = new PENumber($4); PEIdent*itmp = new PEIdent(lex_strings.make($2), @2.lexical_pos); PAssign*atmp = new PAssign(itmp, etmp); @@ -7374,9 +7786,9 @@ udp_output_sym makes for these ports are scoped within the UDP, so there is no hierarchy involved. */ udp_port_decl - : K_input list_of_identifiers ';' + : K_input udp_port_list ';' { $$ = pform_make_udp_input_ports($2); } - | K_output IDENTIFIER ';' + | K_output identifier_name ';' { perm_string pname = lex_strings.make($2); PWire*pp = new PWire(pname, @2.lexical_pos, NetNet::IMPLICIT, NetNet::POUTPUT); vector*tmp = new std::vector(1); @@ -7384,7 +7796,7 @@ udp_port_decl $$ = tmp; delete[]$2; } - | K_reg IDENTIFIER ';' + | K_reg identifier_name ';' { perm_string pname = lex_strings.make($2); PWire*pp = new PWire(pname, @2.lexical_pos, NetNet::REG, NetNet::PIMPLICIT); vector*tmp = new std::vector(1); @@ -7392,7 +7804,7 @@ udp_port_decl $$ = tmp; delete[]$2; } - | K_output K_reg IDENTIFIER ';' + | K_output K_reg identifier_name ';' { perm_string pname = lex_strings.make($3); PWire*pp = new PWire(pname, @3.lexical_pos, NetNet::REG, NetNet::POUTPUT); vector*tmp = new std::vector(1); @@ -7417,9 +7829,9 @@ udp_port_decls ; udp_port_list - : IDENTIFIER + : identifier_name { $$ = list_from_identifier($1, @1.lexical_pos); } - | udp_port_list ',' IDENTIFIER + | udp_port_list ',' identifier_name { $$ = list_from_identifier($1, $3, @3.lexical_pos); } ; @@ -7428,9 +7840,9 @@ udp_reg_opt | { $$ = false; }; udp_input_declaration_list - : K_input IDENTIFIER + : K_input identifier_name { $$ = list_from_identifier($2, @2.lexical_pos); } - | udp_input_declaration_list ',' K_input IDENTIFIER + | udp_input_declaration_list ',' K_input identifier_name { $$ = list_from_identifier($1, $4, @4.lexical_pos); } ; @@ -7439,7 +7851,7 @@ udp_primitive format. The ports are simply names in the port list, and the declarations are in the body. */ - : K_primitive IDENTIFIER '(' udp_port_list ')' ';' + : K_primitive identifier_name '(' udp_port_list ')' ';' udp_port_decls udp_init_opt udp_body @@ -7453,8 +7865,8 @@ udp_primitive /* This is the syntax for IEEE1364-2001 format definitions. The port names and declarations are all in the parameter list. */ - | K_primitive IDENTIFIER - '(' K_output udp_reg_opt IDENTIFIER initializer_opt ',' + | K_primitive identifier_name + '(' K_output udp_reg_opt identifier_name initializer_opt ',' udp_input_declaration_list ')' ';' udp_body K_endprimitive label_opt diff --git a/pform.cc b/pform.cc index 0a62724e8..0f5b3578f 100644 --- a/pform.cc +++ b/pform.cc @@ -449,6 +449,11 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope) return scopex; } +static PGenerate* current_generate_scope() +{ + return lexical_scope == pform_cur_generate ? pform_cur_generate : nullptr; +} + static void add_local_symbol(LexicalScope*scope, perm_string name, PNamedItem*item) { assert(scope); @@ -585,12 +590,16 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) PScopeExtra*scopex = find_nearest_scopex(lexical_scope); ivl_assert(loc, scopex); - ivl_assert(loc, !pform_cur_generate); pform_set_scope_timescale(class_scope, scopex); - scopex->classes[name] = class_scope; - scopex->classes_lexical .push_back(class_scope); + if (auto generate_scope = current_generate_scope()) { + generate_scope->classes[name] = class_scope; + generate_scope->classes_lexical.push_back(class_scope); + } else { + scopex->classes[name] = class_scope; + scopex->classes_lexical.push_back(class_scope); + } lexical_scope = class_scope; return class_scope; @@ -632,9 +641,9 @@ PTask* pform_push_task_scope(const struct vlltype&loc, const char*name, pform_set_scope_timescale(task, scopex); - if (pform_cur_generate) { - add_local_symbol(pform_cur_generate, task_name, task); - pform_cur_generate->tasks[task_name] = task; + if (auto generate_scope = current_generate_scope()) { + add_local_symbol(generate_scope, task_name, task); + generate_scope->tasks[task_name] = task; } else { add_local_symbol(scopex, task_name, task); scopex->tasks[task_name] = task; @@ -667,9 +676,9 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name, pform_set_scope_timescale(func, scopex); - if (pform_cur_generate) { - add_local_symbol(pform_cur_generate, func_name, func); - pform_cur_generate->funcs[func_name] = func; + if (auto generate_scope = current_generate_scope()) { + add_local_symbol(generate_scope, func_name, func); + generate_scope->funcs[func_name] = func; } else { add_local_symbol(scopex, func_name, func); @@ -914,6 +923,22 @@ typedef_t* pform_test_type_identifier(const struct vlltype&loc, const char*txt) if (cur != cur_scope->typedefs.end()) return cur->second; + // If it is defined as something else in this scope, it is not a + // data type. + auto sym = cur_scope->local_symbols.find(name); + if (sym != cur_scope->local_symbols.end()) + return nullptr; + + // Class properties are tracked in the class type, not in + // local_symbols, but still shadow type names before lookup falls + // through to wildcard imports. + if (auto cur_class = dynamic_cast (cur_scope)) { + if (cur_class->type && + cur_class->type->properties.find(name) != + cur_class->type->properties.end()) + return nullptr; + } + PPackage*pkg = pform_find_potential_import(loc, cur_scope, name, false, false); if (pkg) { cur = pkg->typedefs.find(name); @@ -950,6 +975,24 @@ PECallFunction* pform_make_call_function(const struct vlltype&loc, return tmp; } +PECallFunction* pform_make_chained_call_function(const struct vlltype&loc, + PExpr*prefix, + const pform_name_t&method, + const list &parms) +{ + if (!gn_system_verilog()) { + pform_requires_sv(loc, "Chained calls like a().b()"); + delete prefix; + return new PECallFunction(method, parms); + } + + check_potential_imports(loc, method.front().name, true); + + PECallFunction*tmp = new PECallFunction(prefix, method, parms); + FILE_NAME(tmp, loc); + return tmp; +} + PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const list &parms) @@ -1922,11 +1965,25 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, ivl_assert(loc, (*decl)[idx]); if ((*decl)[idx]->get_port_type() != NetNet::PIMPLICIT) { bool rc = cur->set_port_type((*decl)[idx]->get_port_type()); - ivl_assert(loc, rc); + if (!rc) { + cerr << loc << ": error: " + << "Port " << port_name << " of primitive " + << name << " has conflicting port declarations." + << endl; + error_count += 1; + local_errors += 1; + } } if ((*decl)[idx]->get_wire_type() != NetNet::IMPLICIT) { bool rc = cur->set_wire_type((*decl)[idx]->get_wire_type()); - ivl_assert(loc, rc); + if (!rc) { + cerr << loc << ": error: " + << "Port " << port_name << " of primitive " + << name << " has conflicting data declarations." + << endl; + error_count += 1; + local_errors += 1; + } } } else { @@ -1934,6 +1991,14 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, } } + if (local_errors > 0) { + delete parms; + delete decl; + delete table; + delete init_expr; + return; + } + /* Put the parameters into a vector of wire descriptions. Look in the map for the definitions of the name. In this loop, @@ -2045,22 +2110,56 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, registered. Then save the initial value that I get. */ verinum::V init = verinum::Vx; if (init_expr) { - // XXXX - ivl_assert(loc, pins[0]->get_wire_type() == NetNet::REG); + if (pins[0]->get_wire_type() != NetNet::REG) { + cerr << init_expr->get_fileline() << ": error: " + << "Initial value for primitive " << name + << " requires a registered output port." << endl; + error_count += 1; + local_errors += 1; + } - const PAssign*pa = dynamic_cast(init_expr); - ivl_assert(*init_expr, pa); + auto*pa = dynamic_cast(init_expr); + if (!pa) { + cerr << init_expr->get_fileline() << ": error: " + << "Invalid initial statement for primitive " + << name << "." << endl; + error_count += 1; + local_errors += 1; + } - const PEIdent*id = dynamic_cast(pa->lval()); - ivl_assert(*init_expr, id); + if (pa) { + auto*id = dynamic_cast(pa->lval()); + if (!id) { + cerr << init_expr->get_fileline() << ": error: " + << "Invalid initial statement for primitive " + << name << "." << endl; + error_count += 1; + local_errors += 1; + } - // XXXX - //ivl_assert(*init_expr, id->name() == pins[0]->name()); + // XXXX + //ivl_assert(*init_expr, id->name() == pins[0]->name()); - const PENumber*np = dynamic_cast(pa->rval()); - ivl_assert(*init_expr, np); + auto*np = dynamic_cast(pa->rval()); + if (!np) { + cerr << init_expr->get_fileline() << ": error: " + << "Invalid initial value for primitive " + << name << "." << endl; + error_count += 1; + local_errors += 1; + } else { + init = np->value()[0]; + } + } + + if (local_errors > 0) { + delete parms; + delete decl; + delete table; + delete init_expr; + return; + } - init = np->value()[0]; } // Put the primitive into the primitives table @@ -2079,10 +2178,18 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, for (unsigned idx = 0 ; idx < pins.size() ; idx += 1) udp->ports[idx] = pins[idx]->basename(); - process_udp_table(udp, table, loc); - udp->initial = init; + if (table) { + process_udp_table(udp, table, loc); + udp->initial = init; - pform_primitives[name] = udp; + pform_primitives[name] = udp; + } else { + ostringstream msg; + msg << "error: Invalid table for UDP primitive " << name + << "."; + VLerror(loc, msg.str().c_str(), ""); + delete udp; + } } @@ -2126,20 +2233,31 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, registered. Then save the initial value that I get. */ verinum::V init = verinum::Vx; if (init_expr) { - // XXXX - ivl_assert(*init_expr, pins[0]->get_wire_type() == NetNet::REG); + bool local_errors = false; - const PAssign*pa = dynamic_cast(init_expr); - ivl_assert(*init_expr, pa); + if (pins[0]->get_wire_type() != NetNet::REG) { + cerr << init_expr->get_fileline() << ": error: " + << "Initial value for primitive " << name + << " requires a registered output port." << endl; + error_count += 1; + local_errors = true; + } - const PEIdent*id = dynamic_cast(pa->lval()); - ivl_assert(*init_expr, id); + auto*np = dynamic_cast(init_expr); + if (!np) { + cerr << init_expr->get_fileline() << ": error: " + << "Invalid initial value for primitive " + << name << "." << endl; + error_count += 1; + local_errors = true; + } - // XXXX - //ivl_assert(*init_expr, id->name() == pins[0]->name()); - - const PENumber*np = dynamic_cast(pa->rval()); - ivl_assert(*init_expr, np); + if (local_errors) { + delete parms; + delete table; + delete init_expr; + return; + } init = np->value()[0]; } @@ -2172,7 +2290,7 @@ void pform_make_udp(const struct vlltype&loc, perm_string name, } else { ostringstream msg; msg << "error: Invalid table for UDP primitive " << name - << "." << endl; + << "."; // Some compilers warn if there is just a single C string. VLerror(loc, msg.str().c_str(), ""); } diff --git a/pform.h b/pform.h index 610dd8390..598eb3988 100644 --- a/pform.h +++ b/pform.h @@ -333,6 +333,10 @@ extern void pform_set_type_referenced(const struct vlltype&loc, const char*name) extern PECallFunction* pform_make_call_function(const struct vlltype&loc, const pform_name_t&name, const std::list &parms); +extern PECallFunction* pform_make_chained_call_function(const struct vlltype&loc, + PExpr*prefix, + const pform_name_t&method, + const std::list &parms); extern PCallTask* pform_make_call_task(const struct vlltype&loc, const pform_name_t&name, const std::list &parms); diff --git a/pform_dump.cc b/pform_dump.cc index 94913eca6..49de3728f 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -421,6 +421,10 @@ void PEConcat::dump(ostream&out) const void PECallFunction::dump(ostream &out) const { + if (peek_chain_prefix()) { + peek_chain_prefix()->dump(out); + out << "."; + } out << path_ << "(" << parms_ << ")"; } diff --git a/pform_types.h b/pform_types.h index e16273cf6..021229e53 100644 --- a/pform_types.h +++ b/pform_types.h @@ -510,4 +510,9 @@ extern std::ostream& operator<< (std::ostream&out, const name_component_t&that); extern std::ostream& operator<< (std::ostream&out, const index_component_t&that); extern std::ostream& operator<< (std::ostream&out, const type_restrict_t& type); +struct pform_port_list { + std::list *ports; + data_type_t *type; +}; + #endif /* IVL_pform_types_H */ diff --git a/t-dll-api.cc b/t-dll-api.cc index 7a33018f8..4e586bb0d 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2026 Stephen Williams (steve@icarus.com) * Copyright CERN 2013 / Stephen Williams (steve@icarus.com) * Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch) * @@ -25,6 +25,7 @@ # include "discipline.h" # include "netclass.h" # include "netdarray.h" +# include "netqueue.h" # include "netenum.h" # include "netvector.h" # include @@ -3308,6 +3309,17 @@ extern "C" ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx) return class_type->get_prop_type(idx); } +extern "C" unsigned ivl_type_queue_max(ivl_type_t net) +{ + if (net == 0) return 0; + if (const netqueue_t*que = dynamic_cast(net)) { + long max_idx = que->max_idx(); + if (max_idx < 0) return 0; + return (unsigned)(max_idx + 1); + } + return 0; +} + extern "C" int ivl_type_signed(ivl_type_t net) { assert(net); diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 3b6a18623..22296de3e 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -26,7 +26,8 @@ ivl_parameter_t emitting_param = 0; /* - * Data type used to signify if a $signed or $unsigned should be emitted. + * Data type used to signify whether to emit $signed() or wrap the + * expression in a concatenation for an unsigned self-determined context. */ typedef enum expr_sign_e { NO_SIGN = 0, @@ -77,7 +78,7 @@ static expr_sign_t expr_get_binary_sign_type(ivl_expr_t expr) break; } - /* Check to see if a $signed() or $unsigned() is needed. */ + /* Check to see if the expression sign needs to be forced. */ if (expr_sign && ! opr_sign) rtn = NEED_SIGNED; if (! expr_sign && opr_sign) rtn = NEED_UNSIGNED; @@ -97,11 +98,11 @@ static expr_sign_t expr_get_select_sign_type(ivl_expr_t expr, ivl_expr_t oper1 = ivl_expr_oper1(expr); opr_sign = ivl_expr_signed(oper1); /* If the expression being padded is not a signal then don't - * skip a soft $unsigned() (from the binary operator). */ + * skip the soft unsigned context from the binary operator. */ if (ivl_expr_type(oper1) != IVL_EX_SIGNAL) can_skip_unsigned -= 1; } - /* Check to see if a $signed() or $unsigned() is needed. */ + /* Check to see if the expression sign needs to be forced. */ if (expr_sign && ! opr_sign) rtn = NEED_SIGNED; if (! expr_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED; @@ -115,7 +116,7 @@ static expr_sign_t expr_get_signal_sign_type(ivl_expr_t expr, int expr_sign = ivl_expr_signed(expr); expr_sign_t rtn = NO_SIGN; - /* Check to see if a $signed() or $unsigned() is needed. */ + /* Check to see if the expression sign needs to be forced. */ if (expr_sign && ! opr_sign) rtn = NEED_SIGNED; if (! expr_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED; @@ -210,10 +211,10 @@ static unsigned expr_is_binary_self_det(ivl_expr_t expr) } /* - * Determine if a $signed() or $unsigned() system function is needed to get + * Determine if $signed() or a single-element concatenation is needed to get * the expression sign information correct. can_skip_unsigned may be set for - * the binary/ternary operators if one of the operands will implicitly cast - * the expression to unsigned. See calc_can_skip_unsigned() for the details. + * the binary/ternary operators if one of the operands will implicitly make + * the expression unsigned. See calc_can_skip_unsigned() for the details. */ static expr_sign_t expr_get_sign_type(ivl_expr_t expr, unsigned wid, unsigned can_skip_unsigned, @@ -399,8 +400,8 @@ static unsigned calc_can_skip_unsigned(ivl_expr_t oper1, ivl_expr_t oper2) oper2_signed |= (ivl_expr_type(oper2) == IVL_EX_SELECT) && (! ivl_expr_oper2(oper2)) && (ivl_expr_signed(ivl_expr_oper1(oper2))); - /* If either operand is a hard unsigned skip adding an explicit - * $unsigned() since it will be added implicitly. */ + /* If either operand is hard unsigned, the operator result is already + * unsigned so skip adding an explicit unsigned context. */ return ! oper1_signed || ! oper2_signed; } @@ -1145,7 +1146,7 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, sign_type = expr_get_sign_type(expr, wid, can_skip_unsigned, is_full_prec); - /* Check to see if a $signed() or $unsigned() needs to be emitted + /* Check to see if a $signed() or concatenation needs to be emitted * before the expression. */ if (sign_type == NEED_SIGNED) { fprintf(vlog_out, "$signed("); @@ -1161,14 +1162,8 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, is_full_prec = 0; } if (sign_type == NEED_UNSIGNED) { - fprintf(vlog_out, "$unsigned("); - if (! allow_signed) { - fprintf(stderr, "%s:%u: vlog95 error: $unsigned() is not " - "supported.\n", - ivl_expr_file(expr), ivl_expr_lineno(expr)); - vlog_errors += 1; - } - /* A $unsigned() creates a self-determined context. */ + fprintf(vlog_out, "{"); + /* A `{x}` creates a self-determined context. */ wid = 0; /* It also clears the full precision flag. */ is_full_prec = 0; @@ -1276,6 +1271,15 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid, vlog_errors += 1; break; } - /* Close the $signed() or $unsigned() if need. */ - if (sign_type != NO_SIGN) fprintf(vlog_out, ")"); + /* Close the $signed() or concatenation if needed. */ + switch (sign_type) { + case NEED_SIGNED: + fprintf(vlog_out, ")"); + break; + case NEED_UNSIGNED: + fprintf(vlog_out, "}"); + break; + default: + break; + } } diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 93c18c266..f8950bb65 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -22,7 +22,8 @@ # include "vlog95_priv.h" /* - * Data type used to signify if a $signed or $unsigned should be emitted. + * Data type used to signify whether to emit $signed() or wrap the + * expression in a concatenation for an unsigned self-determined context. */ typedef enum lpm_sign_e { NO_SIGN = 0, @@ -119,7 +120,7 @@ static lpm_sign_t lpm_get_sign_type(ivl_lpm_t lpm, break; } - /* Check to see if a $signed() or $unsigned() is needed. */ + /* Check to see if the expression sign needs to be forced. */ if (lpm_sign && ! opr_sign) rtn = NEED_SIGNED; if (! lpm_sign && opr_sign && ! can_skip_unsigned) rtn = NEED_UNSIGNED; @@ -1173,7 +1174,7 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, unsigned sign_extend) { lpm_sign_t sign_type; - /* Check to see if a $signed() or $unsigned() needs to be emitted + /* Check to see if a $signed() or concatenation needs to be emitted * before the expression. */ sign_type = lpm_get_sign_type(lpm, 0); if (sign_type == NEED_SIGNED) { @@ -1185,14 +1186,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, vlog_errors += 1; } } + /* A concatenation creates a self-determined unsigned context */ if (sign_type == NEED_UNSIGNED) { - fprintf(vlog_out, "$unsigned("); - if (! allow_signed) { - fprintf(stderr, "%s:%u: vlog95 error: $unsigned() is not " - "supported.\n", - ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); - vlog_errors += 1; - } + fprintf(vlog_out, "{"); } switch (ivl_lpm_type(lpm)) { @@ -1472,8 +1468,17 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm, vlog_errors += 1; } - /* Close the $signed() or $unsigned() if needed. */ - if (sign_type != NO_SIGN) fprintf(vlog_out, ")"); + /* Close the $signed() or concatenation if needed. */ + switch (sign_type) { + case NEED_SIGNED: + fprintf(vlog_out, ")"); + break; + case NEED_UNSIGNED: + fprintf(vlog_out, "}"); + break; + default: + break; + } } static void emit_posedge_dff_prim(void) diff --git a/tgt-vvp/draw_class.c b/tgt-vvp/draw_class.c index afbc26d5c..f993dfc46 100644 --- a/tgt-vvp/draw_class.c +++ b/tgt-vvp/draw_class.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2026 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 @@ -28,7 +28,6 @@ static void show_prop_type_vector(ivl_type_t ptype) { ivl_variable_type_t data_type = ivl_type_base(ptype); unsigned packed_dimensions = ivl_type_packed_dimensions(ptype); - assert(packed_dimensions < 2); const char*signed_flag = ivl_type_signed(ptype)? "s" : ""; char code = data_type==IVL_VT_BOOL? 'b' : 'L'; @@ -37,12 +36,8 @@ static void show_prop_type_vector(ivl_type_t ptype) fprintf(vvp_out, "\"%s%c1\"", signed_flag, code); } else { - assert(packed_dimensions == 1); - assert(ivl_type_packed_lsb(ptype,0) == 0); - assert(ivl_type_packed_msb(ptype,0) >= 0); - fprintf(vvp_out, "\"%s%c%d\"", signed_flag, code, - ivl_type_packed_msb(ptype,0)+1); + ivl_type_packed_width(ptype)); } } @@ -63,6 +58,7 @@ static void show_prop_type(ivl_type_t ptype) show_prop_type_vector(ptype); break; case IVL_VT_DARRAY: + case IVL_VT_QUEUE: case IVL_VT_CLASS: fprintf(vvp_out, "\"o\""); if (packed_dimensions > 0) { diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index 16d793d73..ac729da53 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -83,10 +83,14 @@ static void draw_lpm_mux_nest(ivl_lpm_t net, const char*muxz) net, select_input); for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 2) { + /* draw_net_input() can emit helper statements, for example for + array words. Emit those before starting the .functor line. */ + const char*input0 = draw_net_input(ivl_lpm_data(net,idx+0)); + const char*input1 = draw_net_input(ivl_lpm_data(net,idx+1)); fprintf(vvp_out, "L_%p/0/%u .functor %s %u", net, idx/2, muxz, width); - fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx+0))); - fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx+1))); + fprintf(vvp_out, ", %s", input0); + fprintf(vvp_out, ", %s", input1); fprintf(vvp_out, ", L_%p/0s, C4<>;\n", net); } diff --git a/tgt-vvp/draw_substitute.c b/tgt-vvp/draw_substitute.c index 22d5c4223..72fd048c1 100644 --- a/tgt-vvp/draw_substitute.c +++ b/tgt-vvp/draw_substitute.c @@ -25,8 +25,13 @@ void draw_lpm_substitute(ivl_lpm_t net) { unsigned swidth = width_of_nexus(ivl_lpm_data(net,1)); + /* draw_net_input() can emit helper statements, for example for + array words. Emit those before starting the .substitute line. */ + const char*input0 = draw_net_input(ivl_lpm_data(net,0)); + const char*input1 = draw_net_input(ivl_lpm_data(net,1)); + fprintf(vvp_out, "L_%p .substitute %u, %u %u", net, ivl_lpm_width(net), ivl_lpm_base(net), swidth); - fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,0))); - fprintf(vvp_out, ", %s;\n", draw_net_input(ivl_lpm_data(net,1))); + fprintf(vvp_out, ", %s", input0); + fprintf(vvp_out, ", %s;\n", input1); } diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index a49ffb308..82587b25d 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2026 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 @@ -375,6 +375,20 @@ static void draw_vpi_taskfunc_args(const char*call_string, } break; + case IVL_EX_PROPERTY: + if (ivl_expr_oper1(expr) == 0 && + (ivl_expr_value(expr) == IVL_VT_QUEUE || + ivl_expr_value(expr) == IVL_VT_DARRAY)) { + ivl_signal_t clas = ivl_expr_signal(expr); + unsigned pidx = ivl_expr_property_idx(expr); + unsigned isq = ivl_expr_value(expr) == IVL_VT_QUEUE ? 1U : 0U; + snprintf(buffer, sizeof buffer, "&PQ", + clas, pidx, isq); + args[idx].text = strdup(buffer); + continue; + } + break; + case IVL_EX_SIGNAL: case IVL_EX_SELECT: args[idx].stack = vec4_stack_need; @@ -402,6 +416,10 @@ static void draw_vpi_taskfunc_args(const char*call_string, switch (ivl_expr_value(expr)) { case IVL_VT_LOGIC: case IVL_VT_BOOL: + case IVL_VT_QUEUE: + case IVL_VT_DARRAY: + /* Queue/darray element selects may still carry the + * container ivl_expr_value; evaluate as vec4 like logic. */ draw_eval_vec4(expr); args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u'; args[idx].str_flag = 0; @@ -433,6 +451,20 @@ static void draw_vpi_taskfunc_args(const char*call_string, buffer[0] = 0; break; default: + /* See eval_vec4.c:draw_eval_vec4 — indexed selects sometimes + * carry an unexpected ivl_expr_value (e.g. NO_TYPE). */ + if (ivl_expr_type(expr) == IVL_EX_SELECT && + ivl_expr_oper2(expr) != 0) { + draw_eval_vec4(expr); + args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u'; + args[idx].str_flag = 0; + args[idx].real_flag = 0; + args[idx].stack = vec4_stack_need; + args[idx].vec_wid = ivl_expr_width(expr); + vec4_stack_need += 1; + buffer[0] = 0; + break; + } fprintf(stderr, "%s:%u: Sorry, cannot generate code for argument %u.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), idx+1); fprintf(vvp_out, "\nXXXX Unexpected argument: call_string=<%s>, arg=%u, type=%d\n", diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index a61ab0f39..9712b7003 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2024 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2026 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 @@ -202,9 +202,9 @@ static void draw_realnum_real(ivl_expr_t expr) return; } - if (value < 0) { + if (signbit(value)) { sign = 0x4000; - value *= -1; + value = -value; } fract = frexp(value, &expo); @@ -277,6 +277,15 @@ static void real_ex_pop(ivl_expr_t expr) fb = "f"; arg = ivl_expr_parm(expr, 0); + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%qpop/prop/%s/r %u;\n", fb, pidx); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return; + } + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); fprintf(vvp_out, " %%qpop/%s/real v%p_0;\n", fb, ivl_expr_signal(arg)); @@ -453,9 +462,8 @@ static void draw_unary_real(ivl_expr_t expr) } if (ivl_expr_opcode(expr) == '-') { - fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n"); draw_eval_real(sube); - fprintf(vvp_out, " %%sub/wr;\n"); + fprintf(vvp_out, " %%neg/wr;\n"); return; } diff --git a/tgt-vvp/eval_string.c b/tgt-vvp/eval_string.c index 2624c43f4..25ab2a180 100644 --- a/tgt-vvp/eval_string.c +++ b/tgt-vvp/eval_string.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 2012-2026 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 @@ -167,6 +167,15 @@ static void string_ex_pop(ivl_expr_t expr) fb = "f"; arg = ivl_expr_parm(expr, 0); + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%qpop/prop/%s/str %u;\n", fb, pidx); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return; + } + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg)); diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 6bbbb0c0a..adc0fabfa 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2020 Stephen Williams (steve@icarus.com) + * Copyright (c) 2013-2026 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 @@ -462,6 +462,8 @@ static void draw_binary_vec4_logical(ivl_expr_t expr, char op) jmp_type = "1"; break; default: + opcode = ""; + jmp_type = ""; assert(0); break; } @@ -917,6 +919,29 @@ static void draw_property_vec4(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); unsigned pidx = ivl_expr_property_idx(expr); + /* Queue/dynamic-array property with index: index is oper1 (see + * dll_target::expr_property). */ + ivl_expr_t index_ex = ivl_expr_oper1(expr); + + if (index_ex) { + ivl_type_t cls_type = ivl_signal_net_type(sig); + ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx); + if (ptype) { + ivl_variable_type_t pbase = ivl_type_base(ptype); + if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) { + unsigned wid = ivl_expr_width(expr); + draw_eval_expr_into_integer(index_ex, 3); + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n", + pidx, wid); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + if (ivl_expr_value(expr) == IVL_VT_BOOL) { + fprintf(vvp_out, " %%cast2;\n"); + } + return; + } + } + } fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%prop/v %u;\n", pidx); @@ -948,7 +973,31 @@ static void draw_select_vec4(ivl_expr_t expr) return; } - if (ivl_expr_value(subexpr)==IVL_VT_DARRAY) { + /* Class property that is a queue or dynamic array: c.q[idx] */ + if (ivl_expr_type(subexpr) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(subexpr); + unsigned pidx = ivl_expr_property_idx(subexpr); + ivl_type_t cls_type = ivl_signal_net_type(clas); + ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx); + if (ptype) { + ivl_variable_type_t pbase = ivl_type_base(ptype); + if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) { + assert(base); + draw_eval_expr_into_integer(base, 3); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n", + pidx, wid); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + if (ivl_expr_value(expr) == IVL_VT_BOOL) { + fprintf(vvp_out, " %%cast2;\n"); + } + return; + } + } + } + + if (ivl_expr_value(subexpr) == IVL_VT_DARRAY || + ivl_expr_value(subexpr) == IVL_VT_QUEUE) { ivl_signal_t sig = ivl_expr_signal(subexpr); assert(sig); assert( (ivl_signal_data_type(sig)==IVL_VT_DARRAY) @@ -957,8 +1006,9 @@ static void draw_select_vec4(ivl_expr_t expr) assert(base); draw_eval_expr_into_integer(base, 3); fprintf(vvp_out, " %%load/dar/vec4 v%p_0;\n", sig); - if (ivl_expr_value(expr) == IVL_VT_BOOL) + if (ivl_expr_value(expr) == IVL_VT_BOOL) { fprintf(vvp_out, " %%cast2;\n"); + } return; } @@ -1011,12 +1061,23 @@ static void draw_darray_pop(ivl_expr_t expr) { const char*fb; - if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0) + if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0) { fb = "b"; - else + } else { fb = "f"; + } ivl_expr_t arg = ivl_expr_parm(expr, 0); + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%qpop/prop/%s/v %u, %u;\n", fb, pidx, + ivl_expr_width(expr)); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return; + } + assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); fprintf(vvp_out, " %%qpop/%s/v v%p_0, %u;\n", fb, ivl_expr_signal(arg), @@ -1049,6 +1110,18 @@ static void draw_sfunc_vec4(ivl_expr_t expr) return; } + if (strcmp(ivl_expr_name(expr), "$size")==0 && parm_count==1) { + ivl_expr_t arg = ivl_expr_parm(expr, 0); + if (ivl_expr_type(arg) == IVL_EX_PROPERTY) { + ivl_signal_t sig = ivl_expr_signal(arg); + unsigned pidx = ivl_expr_property_idx(arg); + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return; + } + } + draw_vpi_func_call(expr); } @@ -1357,7 +1430,10 @@ void draw_eval_vec4(ivl_expr_t expr) } assert(ivl_expr_value(expr) == IVL_VT_BOOL || - ivl_expr_value(expr) == IVL_VT_VECTOR); + ivl_expr_value(expr) == IVL_VT_VECTOR || + (ivl_expr_type(expr) == IVL_EX_SELECT && + ivl_expr_oper2(expr) != 0) || + ivl_expr_type(expr) == IVL_EX_PROPERTY); switch (ivl_expr_type(expr)) { case IVL_EX_BINARY: diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index ac0a92dd3..9e3d3a5b2 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2025 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2026 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 @@ -1319,10 +1319,6 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) if (ivl_type_base(prop_type) == IVL_VT_BOOL || ivl_type_base(prop_type) == IVL_VT_LOGIC) { - assert(ivl_type_packed_dimensions(prop_type) == 0 || - (ivl_type_packed_dimensions(prop_type) == 1 && - ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); - if (ivl_stmt_opcode(net) != 0) { fprintf(vvp_out, " %%prop/v %d;\n", prop_idx); } @@ -1364,15 +1360,16 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); - } else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) { + } else if (ivl_type_base(prop_type) == IVL_VT_DARRAY || + ivl_type_base(prop_type) == IVL_VT_QUEUE) { int idx = 0; - /* The property is a darray, and there is no mux - expression to the assignment is of an entire - array object. */ + /* The property is a darray or queue, and there is no mux + expression so the assignment is of an entire + array/queue object. */ errors += draw_eval_object(rval); - fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx); + fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY or QUEUE\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_CLASS) { diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 8382b94ab..d01611671 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -1663,6 +1663,24 @@ static int show_delete_method(ivl_statement_t net) return 1; ivl_expr_t parm = ivl_stmt_parm(net, 0); + if (ivl_expr_type(parm) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(parm); + unsigned pidx = ivl_expr_property_idx(parm); + ivl_type_t sig_type = ivl_signal_net_type(clas); + ivl_type_t queue_type = ivl_type_prop_type(sig_type, pidx); + assert(ivl_type_base(queue_type) == IVL_VT_QUEUE); + + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + if (parm_count == 2) { + draw_eval_expr_into_integer(ivl_stmt_parm(net, 1), 3); + fprintf(vvp_out, " %%delete/prop/elem %u;\n", pidx); + } else { + fprintf(vvp_out, " %%delete/prop/obj %u;\n", pidx); + } + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + return 0; + } + assert(ivl_expr_type(parm) == IVL_EX_SIGNAL); ivl_signal_t var = ivl_expr_signal(parm); @@ -1687,6 +1705,47 @@ static int show_insert_method(ivl_statement_t net) return 1; ivl_expr_t parm0 = ivl_stmt_parm(net,0); + if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(parm0); + unsigned pidx = ivl_expr_property_idx(parm0); + ivl_type_t sig_type = ivl_signal_net_type(clas); + ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx); + assert(ivl_type_base(var_type) == IVL_VT_QUEUE); + + int idx = allocate_word(); + assert(idx >= 0); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx, + ivl_type_queue_max(var_type)); + + ivl_type_t element_type = ivl_type_element(var_type); + + ivl_expr_t parm1 = ivl_stmt_parm(net,1); + draw_eval_expr_into_integer(parm1, 3); + ivl_expr_t parm2 = ivl_stmt_parm(net,2); + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + draw_eval_real(parm2); + fprintf(vvp_out, " %%qinsert/prop/r %u, %d;\n", + pidx, idx); + break; + case IVL_VT_STRING: + draw_eval_string(parm2); + fprintf(vvp_out, " %%qinsert/prop/str %u, %d;\n", + pidx, idx); + break; + default: + draw_eval_vec4(parm2); + fprintf(vvp_out, " %%qinsert/prop/v %u, %d, %u;\n", + pidx, idx, + ivl_type_packed_width(element_type)); + break; + } + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + clr_word(idx); + return 0; + } + assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL); ivl_signal_t var = ivl_expr_signal(parm0); ivl_type_t var_type = ivl_signal_net_type(var); @@ -1740,6 +1799,45 @@ static int show_push_frontback_method(ivl_statement_t net, bool is_front) return 1; ivl_expr_t parm0 = ivl_stmt_parm(net,0); + if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) { + ivl_signal_t clas = ivl_expr_signal(parm0); + unsigned pidx = ivl_expr_property_idx(parm0); + ivl_type_t sig_type = ivl_signal_net_type(clas); + ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx); + assert(ivl_type_base(var_type) == IVL_VT_QUEUE); + + int idx = allocate_word(); + assert(idx >= 0); + fprintf(vvp_out, " %%load/obj v%p_0;\n", clas); + fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx, + ivl_type_queue_max(var_type)); + + ivl_type_t element_type = ivl_type_element(var_type); + + ivl_expr_t parm1 = ivl_stmt_parm(net,1); + switch (ivl_type_base(element_type)) { + case IVL_VT_REAL: + draw_eval_real(parm1); + fprintf(vvp_out, " %%store/prop/%s/r %u, %d;\n", + type_code, pidx, idx); + break; + case IVL_VT_STRING: + draw_eval_string(parm1); + fprintf(vvp_out, " %%store/prop/%s/str %u, %d;\n", + type_code, pidx, idx); + break; + default: + draw_eval_vec4(parm1); + fprintf(vvp_out, " %%store/prop/%s/v %u, %d, %u;\n", + type_code, pidx, idx, + ivl_type_packed_width(element_type)); + break; + } + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + clr_word(idx); + return 0; + } + assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL); ivl_signal_t var = ivl_expr_signal(parm0); ivl_type_t var_type = ivl_signal_net_type(var); diff --git a/vpi/cppcheck.sup b/vpi/cppcheck.sup index c69de0859..026317cc9 100644 --- a/vpi/cppcheck.sup +++ b/vpi/cppcheck.sup @@ -287,73 +287,75 @@ syntaxError:lz4.c unusedStructMember:lz4.c // These functions are not used by Icarus // LZ4_versionNumber() -unusedFunction:lz4.c:746 -// LZ4_versionString() -unusedFunction:lz4.c:747 -// LZ4_sizeofState() unusedFunction:lz4.c:749 +// LZ4_versionString() +unusedFunction:lz4.c:750 +// LZ4_sizeofState() +unusedFunction:lz4.c:752 // LZ4_compress_fast_extState_fastReset() -unusedFunction:lz4.c:1411 +unusedFunction:lz4.c:1414 // LZ4_compress_destSize_extState() -unusedFunction:lz4.c:1494 +unusedFunction:lz4.c:1497 // LZ4_compress_destSize() -unusedFunction:lz4.c:1503 +unusedFunction:lz4.c:1506 // LZ4_resetStream_fast() -unusedFunction:lz4.c:1567 +unusedFunction:lz4.c:1570 // LZ4_resetStream() -unusedFunction:lz4.c:1572 +unusedFunction:lz4.c:1575 // LZ4_loadDict() -unusedFunction:lz4.c:1583 +unusedFunction:lz4.c:1648 +// LZ4_loadDictSlow() +unusedFunction:lz4.c:1653 // LZ4_attach_dictionary() -unusedFunction:lz4.c:1626 +unusedFunction:lz4.c:1658 // LZ4_compress_forceExtDict() -unusedFunction:lz4.c:1755 +unusedFunction:lz4.c:1787 // LZ4_saveDict() -unusedFunction:lz4.c:1782 +unusedFunction:lz4.c:1814 // LZ4_decompress_fast_withPrefix64k() -unusedFunction:lz4.c:2456 +unusedFunction:lz4.c:2496 // LZ4_createStreamDecode() -unusedFunction:lz4.c:2529 +unusedFunction:lz4.c:2569 // LZ4_freeStreamDecode() -unusedFunction:lz4.c:2535 -// LZ4_setStreamDecode() -unusedFunction:lz4.c:2549 -// LZ4_decoderRingBufferSize() unusedFunction:lz4.c:2575 +// LZ4_setStreamDecode() +unusedFunction:lz4.c:2589 +// LZ4_decoderRingBufferSize() +unusedFunction:lz4.c:2615 // LZ4_decompress_safe_continue() -unusedFunction:lz4.c:2591 -// LZ4_decompress_fast_continue() unusedFunction:lz4.c:2631 +// LZ4_decompress_fast_continue() +unusedFunction:lz4.c:2671 // LZ4_decompress_safe_usingDict() -unusedFunction:lz4.c:2679 +unusedFunction:lz4.c:2719 // LZ4_decompress_safe_partial_usingDict() -unusedFunction:lz4.c:2694 +unusedFunction:lz4.c:2734 // LZ4_decompress_fast_usingDict() -unusedFunction:lz4.c:2709 +unusedFunction:lz4.c:2749 // LZ4_compress_limitedOutput() -unusedFunction:lz4.c:2724 +unusedFunction:lz4.c:2764 // LZ4_compress() -unusedFunction:lz4.c:2728 -// LZ4_compress_limitedOutput_withState() -unusedFunction:lz4.c:2732 -// LZ4_compress_withState() -unusedFunction:lz4.c:2736 -// LZ4_compress_limitedOutput_continue() -unusedFunction:lz4.c:2740 -// LZ4_compress_continue() -unusedFunction:lz4.c:2744 -// LZ4_uncompress() -unusedFunction:lz4.c:2755 -// LZ4_uncompress_unknownOutputSize() -unusedFunction:lz4.c:2759 -// LZ4_sizeofStreamState() -unusedFunction:lz4.c:2766 -// LZ4_resetStreamState() unusedFunction:lz4.c:2768 -// LZ4_create() +// LZ4_compress_limitedOutput_withState() +unusedFunction:lz4.c:2772 +// LZ4_compress_withState() unusedFunction:lz4.c:2776 +// LZ4_compress_limitedOutput_continue() +unusedFunction:lz4.c:2780 +// LZ4_compress_continue() +unusedFunction:lz4.c:2784 +// LZ4_uncompress() +unusedFunction:lz4.c:2795 +// LZ4_uncompress_unknownOutputSize() +unusedFunction:lz4.c:2799 +// LZ4_sizeofStreamState() +unusedFunction:lz4.c:2806 +// LZ4_resetStreamState() +unusedFunction:lz4.c:2808 +// LZ4_create() +unusedFunction:lz4.c:2816 // LZ4_slideInputBuffer() -unusedFunction:lz4.c:2783 +unusedFunction:lz4.c:2823 // The routines in sys_random.c are exact copies from IEEE1364-2005 and // they have scope warnings that we need to ignore. diff --git a/vpi/libvpi.c b/vpi/libvpi.c index d82422586..d88254257 100644 --- a/vpi/libvpi.c +++ b/vpi/libvpi.c @@ -286,6 +286,11 @@ void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit) assert(vpip_routines); vpip_routines->format_strength(str, value, bit); } +char* vpip_format_pretty(vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->format_pretty(ref); +} void vpip_make_systf_system_defined(vpiHandle ref) { assert(vpip_routines); diff --git a/vpi/lz4.c b/vpi/lz4.c index 0a727596b..a2f7abee1 100644 --- a/vpi/lz4.c +++ b/vpi/lz4.c @@ -124,14 +124,17 @@ # include /* only present in VS2005+ */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 6237) /* disable: C6237: conditional expression is always 0 */ +# pragma warning(disable : 6239) /* disable: C6239: ( && ) always evaluates to the result of */ +# pragma warning(disable : 6240) /* disable: C6240: ( && ) always evaluates to the result of */ +# pragma warning(disable : 6326) /* disable: C6326: Potential comparison of a constant with another constant */ #endif /* _MSC_VER */ #ifndef LZ4_FORCE_INLINE -# ifdef _MSC_VER /* Visual Studio */ +# if defined (_MSC_VER) && !defined (__clang__) /* MSVC */ # define LZ4_FORCE_INLINE static __forceinline # else # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ -# ifdef __GNUC__ +# if defined (__GNUC__) || defined (__clang__) # define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) # else # define LZ4_FORCE_INLINE static inline @@ -430,7 +433,7 @@ static U16 LZ4_readLE16(const void* memPtr) return LZ4_read16(memPtr); } else { const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); + return (U16)((U16)p[0] | (p[1]<<8)); } } @@ -441,7 +444,7 @@ static U32 LZ4_readLE32(const void* memPtr) return LZ4_read32(memPtr); } else { const BYTE* p = (const BYTE*)memPtr; - return (U32)p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24); + return (U32)p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); } } #endif @@ -527,7 +530,7 @@ LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd) /* LZ4_memcpy_using_offset() presumes : * - dstEnd >= dstPtr + MINMATCH - * - there is at least 8 bytes available to write after dstEnd */ + * - there is at least 12 bytes available to write after dstEnd */ LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) { @@ -1118,7 +1121,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic_validated( goto _last_literals; } if (litLength >= RUN_MASK) { - int len = (int)(litLength - RUN_MASK); + unsigned len = litLength - RUN_MASK; *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; @@ -1579,8 +1582,11 @@ int LZ4_freeStream (LZ4_stream_t* LZ4_stream) #endif +typedef enum { _ld_fast, _ld_slow } LoadDict_mode_e; #define HASH_UNIT sizeof(reg_t) -int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +int LZ4_loadDict_internal(LZ4_stream_t* LZ4_dict, + const char* dictionary, int dictSize, + LoadDict_mode_e _ld) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; const tableType_t tableType = byU32; @@ -1616,13 +1622,39 @@ int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) while (p <= dictEnd-HASH_UNIT) { U32 const h = LZ4_hashPosition(p, tableType); + /* Note: overwriting => favors positions end of dictionary */ LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); p+=3; idx32+=3; } + if (_ld == _ld_slow) { + /* Fill hash table with additional references, to improve compression capability */ + p = dict->dictionary; + idx32 = dict->currentOffset - dict->dictSize; + while (p <= dictEnd-HASH_UNIT) { + U32 const h = LZ4_hashPosition(p, tableType); + U32 const limit = dict->currentOffset - 64 KB; + if (LZ4_getIndexOnHash(h, dict->hashTable, tableType) <= limit) { + /* Note: not overwriting => favors positions beginning of dictionary */ + LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); + } + p++; idx32++; + } + } + return (int)dict->dictSize; } +int LZ4_loadDict(LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ + return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_fast); +} + +int LZ4_loadDictSlow(LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) +{ + return LZ4_loadDict_internal(LZ4_dict, dictionary, dictSize, _ld_slow); +} + void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) { const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL : @@ -2042,7 +2074,7 @@ LZ4_decompress_generic( * note : fast loop may show a regression for some client arm chips. */ #if LZ4_FAST_DEC_LOOP if ((oend - op) < FASTLOOP_SAFE_DISTANCE) { - DEBUGLOG(6, "skip fast decode loop"); + DEBUGLOG(6, "move to safe decode loop"); goto safe_decode; } @@ -2054,6 +2086,7 @@ LZ4_decompress_generic( assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ + DEBUGLOG(7, "blockPos%6u: litLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length); /* decode literal length */ if (length == RUN_MASK) { @@ -2083,21 +2116,23 @@ LZ4_decompress_generic( /* get offset */ offset = LZ4_readLE16(ip); ip+=2; - DEBUGLOG(6, " offset = %zu", offset); + DEBUGLOG(6, "blockPos%6u: offset = %u", (unsigned)(op-(BYTE*)dst), (unsigned)offset); match = op - offset; assert(match <= op); /* overflow check */ /* get matchlength */ length = token & ML_MASK; + DEBUGLOG(7, " match length token = %u (len==%u)", (unsigned)length, (unsigned)length+MINMATCH); if (length == ML_MASK) { size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); if (addl == rvl_error) { - DEBUGLOG(6, "error reading long match length"); + DEBUGLOG(5, "error reading long match length"); goto _output_error; } length += addl; length += MINMATCH; + DEBUGLOG(7, " long match length == %u", (unsigned)length); if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; @@ -2105,6 +2140,7 @@ LZ4_decompress_generic( } else { length += MINMATCH; if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { + DEBUGLOG(7, "moving to safe_match_copy (ml==%u)", (unsigned)length); goto safe_match_copy; } @@ -2123,7 +2159,7 @@ LZ4_decompress_generic( } } } if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) { - DEBUGLOG(6, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match); + DEBUGLOG(5, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match); goto _output_error; } /* match starting within external dictionary */ @@ -2180,6 +2216,7 @@ LZ4_decompress_generic( assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ + DEBUGLOG(7, "blockPos%6u: litLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length); /* A two-stage shortcut for the most common case: * 1) If the literal length is 0..14, and there is enough space, @@ -2200,6 +2237,7 @@ LZ4_decompress_generic( /* The second stage: prepare for match copying, decode full info. * If it doesn't work out, the info won't be wasted. */ length = token & ML_MASK; /* match length */ + DEBUGLOG(7, "blockPos%6u: matchLength token = %u (len=%u)", (unsigned)(op-(BYTE*)dst), (unsigned)length, (unsigned)length + 4); offset = LZ4_readLE16(ip); ip += 2; match = op - offset; assert(match <= op); /* check overflow */ @@ -2272,9 +2310,10 @@ LZ4_decompress_generic( * so check that we exactly consume the input and don't overrun the output buffer. */ if ((ip+length != iend) || (cpy > oend)) { - DEBUGLOG(6, "should have been last run of literals") - DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); - DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend); + DEBUGLOG(5, "should have been last run of literals") + DEBUGLOG(5, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); + DEBUGLOG(5, "or cpy(%p) > (oend-MFLIMIT)(%p)", cpy, oend-MFLIMIT); + DEBUGLOG(5, "after writing %u bytes / %i bytes available", (unsigned)(op-(BYTE*)dst), outputSize); goto _output_error; } } @@ -2300,6 +2339,7 @@ LZ4_decompress_generic( /* get matchlength */ length = token & ML_MASK; + DEBUGLOG(7, "blockPos%6u: matchLength token = %u", (unsigned)(op-(BYTE*)dst), (unsigned)length); _copy_match: if (length == ML_MASK) { @@ -2389,7 +2429,7 @@ LZ4_decompress_generic( while (op < cpy) { *op++ = *match++; } } else { LZ4_memcpy(op, match, 8); - if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } + if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } } op = cpy; /* wildcopy correction */ } diff --git a/vpi/lz4.h b/vpi/lz4.h index 7a2dbfd4b..80e3e5ca0 100644 --- a/vpi/lz4.h +++ b/vpi/lz4.h @@ -129,8 +129,8 @@ extern "C" { /*------ Version ------*/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_MINOR 10 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) @@ -148,6 +148,7 @@ LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; **************************************/ /*! * LZ4_MEMORY_USAGE : + * Can be selected at compile time, by setting LZ4_MEMORY_USAGE. * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB) * Increasing memory usage improves compression ratio, generally at the cost of speed. * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality. @@ -157,6 +158,7 @@ LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; # define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #endif +/* These are absolute limits, they should not be changed by users */ #define LZ4_MEMORY_USAGE_MIN 10 #define LZ4_MEMORY_USAGE_DEFAULT 14 #define LZ4_MEMORY_USAGE_MAX 20 @@ -368,6 +370,51 @@ LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr); */ LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); +/*! LZ4_loadDictSlow() : v1.10.0+ + * Same as LZ4_loadDict(), + * but uses a bit more cpu to reference the dictionary content more thoroughly. + * This is expected to slightly improve compression ratio. + * The extra-cpu cost is likely worth it if the dictionary is re-used across multiple sessions. + * @return : loaded dictionary size, in bytes (note: only the last 64 KB are loaded) + */ +LZ4LIB_API int LZ4_loadDictSlow(LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); + +/*! LZ4_attach_dictionary() : stable since v1.10.0 + * + * This allows efficient re-use of a static dictionary multiple times. + * + * Rather than re-loading the dictionary buffer into a working context before + * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a + * working LZ4_stream_t, this function introduces a no-copy setup mechanism, + * in which the working stream references @dictionaryStream in-place. + * + * Several assumptions are made about the state of @dictionaryStream. + * Currently, only states which have been prepared by LZ4_loadDict() or + * LZ4_loadDictSlow() should be expected to work. + * + * Alternatively, the provided @dictionaryStream may be NULL, + * in which case any existing dictionary stream is unset. + * + * If a dictionary is provided, it replaces any pre-existing stream history. + * The dictionary contents are the only history that can be referenced and + * logically immediately precede the data compressed in the first subsequent + * compression call. + * + * The dictionary will only remain attached to the working stream through the + * first compression call, at the end of which it is cleared. + * @dictionaryStream stream (and source buffer) must remain in-place / accessible / unchanged + * through the completion of the compression session. + * + * Note: there is no equivalent LZ4_attach_*() method on the decompression side + * because there is no initialization cost, hence no need to share the cost across multiple sessions. + * To decompress LZ4 blocks using dictionary, attached or not, + * just employ the regular LZ4_setStreamDecode() for streaming, + * or the stateless LZ4_decompress_safe_usingDict() for one-shot decompression. + */ +LZ4LIB_API void +LZ4_attach_dictionary(LZ4_stream_t* workingStream, + const LZ4_stream_t* dictionaryStream); + /*! LZ4_compress_fast_continue() : * Compress 'src' content using data from previously compressed blocks, for better compression ratio. * 'dst' buffer must be already allocated. @@ -563,43 +610,12 @@ LZ4_decompress_safe_partial_usingDict(const char* src, char* dst, */ LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); -/*! LZ4_compress_destSize_extState() : +/*! LZ4_compress_destSize_extState() : introduced in v1.10.0 * Same as LZ4_compress_destSize(), but using an externally allocated state. * Also: exposes @acceleration */ int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration); -/*! LZ4_attach_dictionary() : - * This is an experimental API that allows - * efficient use of a static dictionary many times. - * - * Rather than re-loading the dictionary buffer into a working context before - * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a - * working LZ4_stream_t, this function introduces a no-copy setup mechanism, - * in which the working stream references the dictionary stream in-place. - * - * Several assumptions are made about the state of the dictionary stream. - * Currently, only streams which have been prepared by LZ4_loadDict() should - * be expected to work. - * - * Alternatively, the provided dictionaryStream may be NULL, - * in which case any existing dictionary stream is unset. - * - * If a dictionary is provided, it replaces any pre-existing stream history. - * The dictionary contents are the only history that can be referenced and - * logically immediately precede the data compressed in the first subsequent - * compression call. - * - * The dictionary will only remain attached to the working stream through the - * first compression call, at the end of which it is cleared. The dictionary - * stream (and source buffer) must remain in-place / accessible / unchanged - * through the completion of the first compression call on the stream. - */ -LZ4LIB_STATIC_API void -LZ4_attach_dictionary(LZ4_stream_t* workingStream, - const LZ4_stream_t* dictionaryStream); - - /*! In-place compression and decompression * * It's possible to have input and output sharing the same buffer, diff --git a/vpi/sys_display.c b/vpi/sys_display.c index d5b3f2923..6522d20ea 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -867,6 +867,35 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, * be a binary string (can contain NULLs). */ break; + case 'p': + case 'P': + *idx += 1; + if (plus != 0 || prec != -1) { + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); + } + if (*idx >= info->nitems) { + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); + } else { + char *pp = vpip_format_pretty(info->items[*idx]); + if (pp == 0) { + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); + } else { + char *cp = pp; + if (width == -1) width = 0; + size = strlen(cp) + 1; + if ((signed)size < (width+1)) size = width+1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); + if (ljust == 0) sprintf(result, "%*s", width, cp); + else sprintf(result, "%-*s", width, cp); + free(pp); + size = strlen(result) + 1; + } + } + break; + default: vpi_printf("WARNING: %s:%d: unknown format %s%s.\n", info->filename, info->lineno, info->name, fmtb); @@ -1215,6 +1244,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name, #endif case vpiClassVar: case vpiSysFuncCall: + case vpiRegArray: /* dynamic arrays, queues, SV array vars */ break; default: diff --git a/vpi_modules.cc b/vpi_modules.cc index 92c852c81..157c10f2e 100644 --- a/vpi_modules.cc +++ b/vpi_modules.cc @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include "config.h" #include "compiler.h" #include "vpi_user.h" @@ -128,6 +129,7 @@ s_vpi_vecval vpip_calc_clog2(vpiHandle) } void vpip_count_drivers(vpiHandle, unsigned, unsigned [4]) { } void vpip_format_strength(char*, s_vpi_value*, unsigned) { } +char* vpip_format_pretty(vpiHandle) { return strdup("invalid"); } void vpip_make_systf_system_defined(vpiHandle) { } void vpip_mcd_rawwrite(PLI_UINT32, const char*, size_t) { } void vpip_set_return_value(int) { } @@ -232,6 +234,7 @@ vpip_routines_s vpi_routines = { .calc_clog2 = vpip_calc_clog2, .count_drivers = vpip_count_drivers, .format_strength = vpip_format_strength, + .format_pretty = vpip_format_pretty, .make_systf_system_defined = vpip_make_systf_system_defined, .mcd_rawwrite = vpip_mcd_rawwrite, .set_return_value = vpip_set_return_value, diff --git a/vpi_user.h b/vpi_user.h index c347fe15e..9fcfd6342 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -641,6 +641,10 @@ extern DLLEXPORT void (*vlog_startup_routines[])(void); /* Format a scalar a la %v. The str points to a 4byte character buffer. The value must be a vpiStrengthVal. */ extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit); + /* Pretty-print a dynamic array or queue (including class property queues) + * for %p. Returns a malloc'd string, or NULL if the handle is not + * supported. Caller must free the returned pointer when non-NULL. */ +extern char* vpip_format_pretty(vpiHandle ref); /* Set the return value to return from the vvp run time. This is usually 0 or 1. This is the exit code that the vvp process returns, and in distinct from the finish_number that is an @@ -696,7 +700,7 @@ extern void vpip_count_drivers(vpiHandle ref, unsigned idx, */ // Increment the version number any time vpip_routines_s is changed. -static const PLI_UINT32 vpip_routines_version = 1; +static const PLI_UINT32 vpip_routines_version = 2; typedef struct { vpiHandle (*register_cb)(p_cb_data); @@ -737,6 +741,7 @@ typedef struct { s_vpi_vecval(*calc_clog2)(vpiHandle); void (*count_drivers)(vpiHandle, unsigned, unsigned [4]); void (*format_strength)(char*, s_vpi_value*, unsigned); + char* (*format_pretty)(vpiHandle); void (*make_systf_system_defined)(vpiHandle); void (*mcd_rawwrite)(PLI_UINT32, const char*, size_t); void (*set_return_value)(int); diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 9b7f0013f..32a6aa0a5 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -178,7 +178,7 @@ VVP_POSTBUILD = ln -sf vvp@EXEEXT@ vvp$(suffix)@EXEEXT@ VVP_CLEAN += vvp$(suffix)@EXEEXT@ endif -all: dep vvp@EXEEXT@ vvp.man +all: dep vvp@EXEEXT@ libvvp.pc vvp.man # ENV_VVP sets LD_LIBRARY_PATH by default to run vvp from the build tree check: all @@ -221,6 +221,10 @@ vvp@EXEEXT@: $(VVP_OBJ) $(VVP_DEPS) $(CXX) $(LDFLAGS) -o $@ $(VVP_OBJ) -L. $(VVP_LDFLAGS) $(LIBS) $(VVP_POSTBUILD) +libvvp.pc: $(srcdir)/libvvp.pc.in ../config.status + cd ..; ./config.status --file=vvp/$@ + + %.o: %.cc config.h | dep $(CXX) $(CPPFLAGS) -DIVL_SUFFIX='"$(suffix)"' $(MDIR1) $(MDIR2) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep/$*.d diff --git a/vvp/array.cc b/vvp/array.cc index 2e9317b4d..98809adb8 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -162,7 +162,7 @@ int __vpiArray::get_word_size() const /* For a net array we need to get the width from the first element. */ if (nets) { assert(vals4 == 0 && vals == 0); - struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(nets[0]); + const struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(nets[0]); assert(vsig); width = vpip_size(vsig); /* For a variable array we can get the width from vals_width. */ @@ -625,7 +625,7 @@ void __vpiArray::set_word(unsigned address, unsigned part_off, const vvp_vector4 // Select the word of the array that we affect. vpiHandle word = nets[address]; - struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); + const struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vsig->node->send_vec4_pv(val, part_off, vpip_size(vsig), 0); diff --git a/vvp/codes.h b/vvp/codes.h index 94a4f26b5..b15f51888 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -150,6 +150,7 @@ extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code); extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code); extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t code); +extern bool of_LOAD_PROP_DAR_VEC4(vthread_t thr, vvp_code_t code); extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code); extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code); extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code); @@ -164,6 +165,7 @@ extern bool of_MOD_WR(vthread_t thr, vvp_code_t code); extern bool of_MUL(vthread_t thr, vvp_code_t code); extern bool of_MULI(vthread_t thr, vvp_code_t code); extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); +extern bool of_NEG_WR(vthread_t thr, vvp_code_t code); extern bool of_NAND(vthread_t thr, vvp_code_t code); extern bool of_NANDR(vthread_t thr, vvp_code_t code); extern bool of_NEW_COBJ(vthread_t thr, vvp_code_t code); @@ -232,6 +234,24 @@ extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code); extern bool of_STORE_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QB_R(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QB_STR(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QB_V(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QF_R(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QF_STR(vthread_t thr, vvp_code_t code); +extern bool of_STORE_PROP_QF_V(vthread_t thr, vvp_code_t code); +extern bool of_QINSERT_PROP_R(vthread_t thr, vvp_code_t code); +extern bool of_QINSERT_PROP_STR(vthread_t thr, vvp_code_t code); +extern bool of_QINSERT_PROP_V(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_B_REAL(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_B_STR(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_B_V(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t code); +extern bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t code); +extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code); +extern bool of_DELETE_PROP_ELEM(vthread_t thr, vvp_code_t code); +extern bool of_DELETE_PROP_OBJ(vthread_t thr, vvp_code_t code); extern bool of_STORE_QB_R(vthread_t thr, vvp_code_t code); extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code); extern bool of_STORE_QB_V(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 7cfa13005..844367a7a 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -48,9 +48,13 @@ unsigned compile_errors = 0; /* * The opcode table lists all the code mnemonics, along with their - * opcode and operand types. The table is written sorted by mnemonic - * so that it can be searched by binary search. The opcode_compare - * function is a helper function for that lookup. + * opcode and operand types. The table must be sorted lexicographically + * by mnemonic string: compile_code() uses bsearch() on this array. + * If the order is wrong, lookup fails and the assembler reports + * "Invalid opcode" for otherwise valid instructions (e.g. class + * property queue ops must sort among all %delete*, %qpop*, %store* + * names, not grouped by feature). + * The opcode_compare function is a helper for that lookup. */ enum operand_e { @@ -151,6 +155,8 @@ static const struct opcode_table_s opcode_table[] = { { "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%delete/elem",of_DELETE_ELEM,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, { "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%delete/prop/elem", of_DELETE_PROP_ELEM, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%delete/prop/obj", of_DELETE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%delete/tail",of_DELETE_TAIL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, { "%disable", of_DISABLE, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, { "%disable/flow", of_DISABLE_FLOW, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, @@ -204,6 +210,7 @@ static const struct opcode_table_s opcode_table[] = { { "%load/dar/vec4",of_LOAD_DAR_VEC4,1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%load/obja", of_LOAD_OBJA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, + { "%load/prop/dar/vec4", of_LOAD_PROP_DAR_VEC4, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%load/real", of_LOAD_REAL, 1,{OA_VPI_PTR, OA_NONE, OA_NONE} }, { "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%load/stra", of_LOAD_STRA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, @@ -219,6 +226,7 @@ static const struct opcode_table_s opcode_table[] = { { "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nand", of_NAND, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%nand/r", of_NANDR, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%neg/wr", of_NEG_WR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%new/cobj", of_NEW_COBJ, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} }, { "%new/darray",of_NEW_DARRAY,2, {OA_BIT1, OA_STRING,OA_NONE} }, { "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }, @@ -241,6 +249,7 @@ static const struct opcode_table_s opcode_table[] = { { "%pow/s", of_POW_S, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%prop/queue/size", of_PROP_QUEUE_SIZE, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%prop/v", of_PROP_V, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, @@ -249,6 +258,9 @@ static const struct opcode_table_s opcode_table[] = { { "%pushi/vec4",of_PUSHI_VEC4,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%pushv/str", of_PUSHV_STR, 0,{OA_NONE, OA_NONE, OA_NONE} }, { "%putc/str/vec4",of_PUTC_STR_VEC4,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, + { "%qinsert/prop/r", of_QINSERT_PROP_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%qinsert/prop/str", of_QINSERT_PROP_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%qinsert/prop/v", of_QINSERT_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} }, { "%qinsert/real",of_QINSERT_REAL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, { "%qinsert/str", of_QINSERT_STR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, { "%qinsert/v", of_QINSERT_V, 3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, @@ -258,6 +270,12 @@ static const struct opcode_table_s opcode_table[] = { { "%qpop/f/real",of_QPOP_F_REAL,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, { "%qpop/f/str", of_QPOP_F_STR, 1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, { "%qpop/f/v", of_QPOP_F_V, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, + { "%qpop/prop/b/r", of_QPOP_PROP_B_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%qpop/prop/b/str", of_QPOP_PROP_B_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%qpop/prop/b/v", of_QPOP_PROP_B_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%qpop/prop/f/r", of_QPOP_PROP_F_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%qpop/prop/f/str", of_QPOP_PROP_F_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%qpop/prop/f/v", of_QPOP_PROP_F_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, @@ -282,6 +300,12 @@ static const struct opcode_table_s opcode_table[] = { { "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} }, { "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} }, { "%store/prop/obj",of_STORE_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%store/prop/qb/r", of_STORE_PROP_QB_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%store/prop/qb/str", of_STORE_PROP_QB_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%store/prop/qb/v", of_STORE_PROP_QB_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} }, + { "%store/prop/qf/r", of_STORE_PROP_QF_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%store/prop/qf/str", of_STORE_PROP_QF_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, + { "%store/prop/qf/v", of_STORE_PROP_QF_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} }, { "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%store/prop/v", of_STORE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} }, @@ -594,7 +618,7 @@ bool vpi_handle_resolv_list_s::resolve(bool mes) unsigned base, wid; size_t n = 0; char ss[32]; - if (2 == sscanf(label(), "W<%u,%[r]>%zn", &base, ss, &n) + if (2 == sscanf(label(), "W<%u,%31[r]>%zn", &base, ss, &n) && n == strlen(label())) { val.ptr = vpip_make_vthr_word(base, ss); @@ -606,7 +630,7 @@ bool vpi_handle_resolv_list_s::resolve(bool mes) val.ptr = vpip_make_vthr_str_stack(base); sym_set_value(sym_vpi, label(), val); - } else if (3 == sscanf(label(), "S<%u,vec4,%[su]%u>%zn", &base, ss, &wid, &n) + } else if (3 == sscanf(label(), "S<%u,vec4,%31[su]%u>%zn", &base, ss, &wid, &n) && n == strlen(label())) { bool signed_flag = false; diff --git a/vvp/compile.h b/vvp/compile.h index cccc2391a..a813db3b2 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -344,6 +344,10 @@ class resolv_list_s { */ extern void functor_ref_lookup(vvp_net_t**ref, char*lab); +extern vpiHandle vpip_make_prop_queue_ref(char* class_label, + unsigned prop_idx, + unsigned is_queue_flag); + /* * This function schedules a lookup of the labeled instruction. The * code points to a code structure that points to the instruction @@ -504,7 +508,7 @@ extern void compile_variable(char*label, char*name, int msb, int lsb, int vpi_type_code, bool signed_flag, bool local_flag); -extern void compile_var_real(char*label, char*name); +extern void compile_var_real(char*label, char*name, bool local_flag); extern void compile_var_string(char*label, char*name); extern void compile_var_darray(char*label, char*name, unsigned size); extern void compile_var_cobject(char*label, char*name); diff --git a/vvp/cppcheck.sup b/vvp/cppcheck.sup index 128d0ab86..75f282368 100644 --- a/vvp/cppcheck.sup +++ b/vvp/cppcheck.sup @@ -92,11 +92,11 @@ knownConditionTrueFalse:vthread.cc:3571 duplicateExpression:vpi_signal.cc:1207 // cppcheck does not relize this is deleted[] in the called routine -leakNoVarFunctionCall:compile.cc:452 +leakNoVarFunctionCall:compile.cc:476 // Yes, these are not currently initialized in the constructor // All are added after __vpiSysTaskCall is built -uninitMemberVar:vpi_priv.h:946 +uninitMemberVar:vpi_priv.h:967 // All are added after __vpiSignal is built uninitMemberVar:vpi_priv.h:394 // run_run_ptr is added after the event is built @@ -151,13 +151,13 @@ knownConditionTrueFalse:vpi_modules.cc:118 redundantAssignment:vpi_modules.cc:117 // cppcheck does not undestand the format types match -invalidScanfArgType_int:compile.cc:597 -invalidScanfArgType_int:compile.cc:603 -invalidScanfArgType_int:compile.cc:609 -invalidScanfArgType_int:vthread.cc:4541 -invalidScanfArgType_int:vthread.cc:4544 -invalidScanfArgType_int:vthread.cc:4547 -invalidScanfArgType_int:vthread.cc:4550 +invalidScanfArgType_int:compile.cc:621 +invalidScanfArgType_int:compile.cc:627 +invalidScanfArgType_int:compile.cc:633 +invalidScanfArgType_int:vthread.cc:4580 +invalidScanfArgType_int:vthread.cc:4583 +invalidScanfArgType_int:vthread.cc:4586 +invalidScanfArgType_int:vthread.cc:4589 // The new() operator is always used to allocate space for this class and // pool is defined there. diff --git a/vvp/island_tran.cc b/vvp/island_tran.cc index 5e8c793a2..511527f7e 100644 --- a/vvp/island_tran.cc +++ b/vvp/island_tran.cc @@ -196,7 +196,7 @@ void vvp_island_tran::count_drivers(vvp_island_port*port, unsigned bit_idx, void vvp_island_branch_tran::run_test_enabled() { - vvp_island_port*ep = en? dynamic_cast (en->fun) : NULL; + const vvp_island_port*ep = en? dynamic_cast (en->fun) : NULL; // If there is no ep port (no "enabled" input) then this is a // tran branch. Assume it is always enabled. @@ -243,7 +243,7 @@ void vvp_island_branch_tran::run_test_enabled() bool vvp_island_branch_tran::rerun_test_enabled() { - vvp_island_port*ep = en? dynamic_cast (en->fun) : NULL; + const vvp_island_port*ep = en? dynamic_cast (en->fun) : NULL; if (ep == 0) return false; diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 1a6ce88ef..122bcaf45 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -272,6 +272,7 @@ inline uint64_t strtouint64(const char*str, char**endptr, int base) "&A" { return K_A; } "&APV" { return K_APV; } +"&PQ" { return K_PQ; } "&PV" { return K_PV; } "%"[.$_/a-zA-Z0-9]+ { diff --git a/vvp/parse.y b/vvp/parse.y index bd8dba1bf..b8af4e50f 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -93,7 +93,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U %token K_NET8 K_NET8_2S K_NET8_2U K_NET8_S %token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV -%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR +%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PQ K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR %token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT %token K_RESOLV K_RTRAN K_RTRANIF0 K_RTRANIF1 %token K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS @@ -763,8 +763,8 @@ statement | T_LABEL K_VAR_2U local_flag T_STRING ',' signed_t_number signed_t_number ';' { compile_variable($1, $4, $6, $7, vpiIntVar, false, $3); } - | T_LABEL K_VAR_R T_STRING ',' signed_t_number signed_t_number ';' - { compile_var_real($1, $3); } + | T_LABEL K_VAR_R local_flag T_STRING ',' signed_t_number signed_t_number ';' + { compile_var_real($1, $4, $3); } | T_LABEL K_VAR_STR T_STRING ';' { compile_var_string($1, $3); } @@ -1122,6 +1122,8 @@ symbol_access { $$ = vpip_make_PV($3, $5, $7); } | K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>' { $$ = vpip_make_vthr_APV($3, $5, $7, $9); } + | K_PQ '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_prop_queue_ref($3, $5, $7); } ; /* functor operands can only be a list of symbols. */ diff --git a/vvp/vpi_bit.cc b/vvp/vpi_bit.cc index ad76f9a22..9b956861d 100644 --- a/vvp/vpi_bit.cc +++ b/vvp/vpi_bit.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020-2025 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2020-2026 Cary R. (cygcary@yahoo.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 @@ -57,6 +57,7 @@ static int bit_get_type(const __vpiBit*rfp) return vpiRegBit; } assert(0); + return 0; } static int bit_get(int code, vpiHandle ref) diff --git a/vvp/vpi_darray.cc b/vvp/vpi_darray.cc index db9b902c6..a81dcd6ba 100644 --- a/vvp/vpi_darray.cc +++ b/vvp/vpi_darray.cc @@ -22,6 +22,7 @@ # include "vpi_priv.h" # include "vvp_net_sig.h" # include "vvp_darray.h" +# include "vvp_cobject.h" # include "array_common.h" # include "schedule.h" #ifdef CHECK_WITH_VALGRIND @@ -294,41 +295,20 @@ vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net) } __vpiQueueVar::__vpiQueueVar(__vpiScope*sc, const char*na, vvp_net_t*ne) -: __vpiBaseVar(sc, na, ne) +: __vpiDarrayVar(sc, na, ne) { } -int __vpiQueueVar::get_type_code(void) const -{ return vpiArrayVar; } - - int __vpiQueueVar::vpi_get(int code) { - vvp_fun_signal_object*fun = dynamic_cast (get_net()->fun); - assert(fun); - vvp_object_t val = fun->get_object(); - const vvp_queue*aval = val.peek(); - switch (code) { case vpiArrayType: return vpiQueueArray; - case vpiSize: - if (aval == 0) - return 0; - else - return aval->get_size(); - default: - return 0; + return __vpiDarrayVar::vpi_get(code); } } -void __vpiQueueVar::vpi_get_value(p_vpi_value val) -{ - val->format = vpiSuppressVal; -} - - vpiHandle vpip_make_queue_var(const char*name, vvp_net_t*net) { __vpiScope*scope = vpip_peek_current_scope(); @@ -339,9 +319,94 @@ vpiHandle vpip_make_queue_var(const char*name, vvp_net_t*net) return obj; } +__vpiPropQueueRef::__vpiPropQueueRef(__vpiScope*scope, unsigned pidx, + bool is_queue) +: class_net_(0), prop_idx_(pidx), is_queue_(is_queue), scope_(scope) +{ +} + +int __vpiPropQueueRef::get_type_code(void) const +{ return vpiArrayVar; } + +static vvp_darray* get_live_darray_from_prop(vvp_net_t* class_net, unsigned pid) +{ + if (!class_net) return 0; + const vvp_fun_signal_object* fun = dynamic_cast(class_net->fun); + if (!fun) return 0; + vvp_object_t obj = fun->get_object(); + vvp_cobject* cobj = obj.peek(); + if (!cobj) return 0; + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + return qobj.peek(); +} + +int __vpiPropQueueRef::vpi_get(int code) +{ + const vvp_darray* aobj = get_live_darray_from_prop(class_net_, prop_idx_); + switch (code) { + case vpiArrayType: + return is_queue_ ? vpiQueueArray : vpiDynamicArray; + case vpiLeftRange: + return 0; + case vpiRightRange: + return aobj ? (int) (aobj->get_size() - 1) : 0; + case vpiSize: + return aobj ? (int) aobj->get_size() : 0; + default: + return 0; + } +} + +char* __vpiPropQueueRef::vpi_get_str(int code) +{ + if (code == vpiFile) { + return simple_set_rbuf_str(file_names[0]); + } + return generic_get_str(code, scope_, "prop_darray", NULL); +} + +void __vpiPropQueueRef::vpi_get_value(p_vpi_value val) +{ + val->format = vpiSuppressVal; +} + +vpiHandle vpip_make_prop_queue_ref(char* class_label, unsigned prop_idx, + unsigned is_queue_flag) +{ + __vpiPropQueueRef* obj = new __vpiPropQueueRef(vpip_peek_current_scope(), + prop_idx, + is_queue_flag != 0); + functor_ref_lookup(&obj->class_net_, class_label); + return obj; +} + +vvp_darray* vpip_vpi_darray_from_handle(vpiHandle ref) +{ + if (!ref) return 0; + + if (__vpiPropQueueRef* pr = dynamic_cast<__vpiPropQueueRef*>(ref)) { + return get_live_darray_from_prop(pr->class_net_, pr->prop_idx_); + } + + if (const __vpiDarrayVar* dv = dynamic_cast<__vpiDarrayVar*>(ref)) { + const vvp_fun_signal_object* fun = dynamic_cast(dv->get_net()->fun); + if (!fun) return 0; + vvp_object_t obj = fun->get_object(); + return obj.peek(); + } + + return 0; +} + #ifdef CHECK_WITH_VALGRIND void array_delete(vpiHandle item) { + if (__vpiPropQueueRef* pq = dynamic_cast<__vpiPropQueueRef*>(item)) { + delete pq; + return; + } + __vpiDarrayVar*dobj = dynamic_cast<__vpiDarrayVar*>(item); if (dobj) { if (dobj->vals_words) delete [] (dobj->vals_words-1); @@ -349,12 +414,6 @@ void array_delete(vpiHandle item) return; } - __vpiQueueVar*qobj = dynamic_cast<__vpiQueueVar*>(item); - if (qobj) { - delete qobj; - return; - } - fprintf(stderr, "Need support for deleting array type: %d\n", item->vpi_get(vpiArrayType)); assert(0); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index c3aabdfa9..efcebe052 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -128,7 +128,7 @@ struct vpip_string_chunk { char data[64*1024 - sizeof (struct vpip_string_chunk*)]; }; -unsigned vpip_size(__vpiSignal *sig) +unsigned vpip_size(const __vpiSignal *sig) { return abs(sig->msb.get_value() - sig->lsb.get_value()) + 1; } @@ -2098,6 +2098,7 @@ vpip_routines_s vpi_routines = { .calc_clog2 = vpip_calc_clog2, .count_drivers = vpip_count_drivers, .format_strength = vpip_format_strength, + .format_pretty = vpip_format_pretty, .make_systf_system_defined = vpip_make_systf_system_defined, .mcd_rawwrite = vpip_mcd_rawwrite, .set_return_value = vpip_set_return_value, diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 3b253c999..b0fc1e322 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -396,7 +396,7 @@ struct __vpiSignal : public __vpiHandle { static void*operator new[] (std::size_t size); static void operator delete[](void*); }; -extern unsigned vpip_size(__vpiSignal *sig); +extern unsigned vpip_size(const __vpiSignal *sig); extern __vpiScope* vpip_scope(__vpiSignal*sig); extern vpiHandle vpip_make_int2(const char*name, int msb, int lsb, @@ -870,18 +870,39 @@ class __vpiDarrayVar : public __vpiBaseVar, public __vpiArrayBase { extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net); -class __vpiQueueVar : public __vpiBaseVar { +class __vpiQueueVar : public __vpiDarrayVar { public: __vpiQueueVar(__vpiScope*scope, const char*name, vvp_net_t*net); - int get_type_code(void) const override; int vpi_get(int code) override; - void vpi_get_value(p_vpi_value val) override; }; extern vpiHandle vpip_make_queue_var(const char*name, vvp_net_t*net); +class __vpiPropQueueRef : public __vpiHandle { + + public: + explicit __vpiPropQueueRef(__vpiScope*scope, unsigned pidx, bool is_queue); + + int get_type_code(void) const override; + int vpi_get(int code) override; + char* vpi_get_str(int code) override; + void vpi_get_value(p_vpi_value val) override; + + vvp_net_t* class_net_; + unsigned prop_idx_; + bool is_queue_; + + private: + __vpiScope* scope_; +}; + +extern vpiHandle vpip_make_prop_queue_ref(char* class_label, + unsigned prop_idx, + unsigned is_queue_flag); +extern vvp_darray* vpip_vpi_darray_from_handle(vpiHandle ref); + class __vpiCobjectVar : public __vpiBaseVar { public: diff --git a/vvp/vpip_format.cc b/vvp/vpip_format.cc index 4d0b085f8..c7c09e296 100644 --- a/vvp/vpip_format.cc +++ b/vvp/vpip_format.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2026 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 @@ -18,7 +18,15 @@ */ # include "vpi_user.h" +# include "vpi_priv.h" +# include "vvp_darray.h" +# include "vvp_net_sig.h" # include +# include +# include +# include +# include +# include "ivl_alloc.h" static const char str_char1_table[257] = { ".HS1M222" "W3333333" /* 00 0F */ "L4444444" "44444444" /* 10 1F */ @@ -104,3 +112,60 @@ extern "C" void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit) assert(0); } } + +static char* vpip_format_pretty_string(const char*msg) +{ + return strdup(msg); +} + +static char* format_darray_pretty(vvp_darray* aobj) +{ + if (!aobj || aobj->get_size() == 0) return strdup("{}"); + + std::string out = "{"; + + for (size_t i = 0; i < aobj->get_size(); i += 1) { + if (i > 0) out += ", "; + if (dynamic_cast(aobj)) { + double d; + aobj->get_word((unsigned) i, d); + char buf[256]; + snprintf(buf, sizeof buf, "%g", d); + out += buf; + } else if (dynamic_cast(aobj)) { + std::string s; + aobj->get_word((unsigned) i, s); + out += "\""; + out += s; + out += "\""; + } else { + vvp_vector4_t v; + aobj->get_word((unsigned) i, v); + s_vpi_value val; + val.format = vpiDecStrVal; + vpip_vec4_get_value(v, v.size(), false, &val); + out += val.value.str; + } + } + + out += "}"; + return strdup(out.c_str()); +} + +extern "C" char* vpip_format_pretty(vpiHandle ref) +{ + if (!ref) { + return vpip_format_pretty_string("Handle is NULL"); + } + + if (dynamic_cast<__vpiPropQueueRef*>(ref) || + dynamic_cast<__vpiDarrayVar*>(ref)) { + vvp_darray* aobj = vpip_vpi_darray_from_handle(ref); + if (!aobj) { + return vpip_format_pretty_string("Object not found"); + } + return format_darray_pretty(aobj); + } + + return vpip_format_pretty_string("Unsupported object type"); +} diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 98cd41a99..8aa011dad 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3873,6 +3873,36 @@ bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t cp) return load_dar(thr, cp); } +/* + * %load/prop/dar/vec4 , ; + * Indexed read of queue/dynamic-array class property; object on stack, + * index in words[3] (same as %load/dar/vec4). + */ +bool of_LOAD_PROP_DAR_VEC4(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + unsigned wid = cp->bit_idx[0]; + int64_t adr = thr->words[3].w_int; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t pobj; + cobj->get_object(pid, pobj, 0); + vvp_darray*darray = pobj.peek(); + + vvp_vector4_t word; + if (darray && (adr >= 0) && (thr->flags[4] == BIT4_0)) { + darray->get_word(adr, word); + } else { + dq_default(word, wid); + } + + thr->push_vec4(word); + return true; +} + /* * %load/obj */ @@ -4288,6 +4318,15 @@ bool of_MOD_WR(vthread_t thr, vvp_code_t) return true; } +/* + * %neg/wr + */ +bool of_NEG_WR(vthread_t thr, vvp_code_t) +{ + thr->poke_real(0, -thr->peek_real(0)); + return true; +} + /* * %pad/s */ @@ -5888,6 +5927,292 @@ bool of_STORE_PROP_V(vthread_t thr, vvp_code_t cp) return store_prop(thr, cp, cp->bit_idx[0]); } +template +static QTYPE* get_queue_prop(vvp_cobject*cobj, size_t pid) +{ + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + QTYPE* queue = qobj.peek(); + if (queue == 0) { + queue = new QTYPE; + vvp_object_t val(queue); + cobj->set_object(pid, val, 0); + } + return queue; +} + +template +static bool store_prop_qb(vthread_t thr, vvp_code_t cp, unsigned wid) +{ + size_t pid = cp->number; + ELEM value; + unsigned max_size = thr->words[cp->bit_idx[0]].w_uint; + pop_value(thr, value, wid); + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + QTYPE* queue = get_queue_prop(cobj, pid); + assert(queue); + queue->push_back(value, max_size); + return true; +} + +template +static bool store_prop_qf(vthread_t thr, vvp_code_t cp, unsigned wid) +{ + size_t pid = cp->number; + ELEM value; + unsigned max_size = thr->words[cp->bit_idx[0]].w_uint; + pop_value(thr, value, wid); + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + QTYPE* queue = get_queue_prop(cobj, pid); + assert(queue); + queue->push_front(value, max_size); + return true; +} + +bool of_STORE_PROP_QB_R(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qb(thr, cp, 0); +} + +bool of_STORE_PROP_QB_STR(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qb(thr, cp, 0); +} + +bool of_STORE_PROP_QB_V(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qb(thr, cp, cp->bit_idx[1]); +} + +bool of_STORE_PROP_QF_R(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qf(thr, cp, 0); +} + +bool of_STORE_PROP_QF_STR(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qf(thr, cp, 0); +} + +bool of_STORE_PROP_QF_V(vthread_t thr, vvp_code_t cp) +{ + return store_prop_qf(thr, cp, cp->bit_idx[1]); +} + +template +static bool qinsert_prop(vthread_t thr, vvp_code_t cp, unsigned wid) +{ + int64_t idx = thr->words[3].w_int; + ELEM value; + size_t pid = cp->number; + pop_value(thr, value, wid); + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + QTYPE* queue = get_queue_prop(cobj, pid); + assert(queue); + if (idx < 0) { + cerr << thr->get_fileline() + << "Warning: cannot insert at a negative " + << get_queue_type(value) + << " index (" << idx << "). "; + print_queue_value(value); + cerr << " was not added." << endl; + } else if (thr->flags[4] != BIT4_0) { + cerr << thr->get_fileline() + << "Warning: cannot insert at an undefined " + << get_queue_type(value) << " index. "; + print_queue_value(value); + cerr << " was not added." << endl; + } else { + unsigned max_size = thr->words[cp->bit_idx[0]].w_int; + queue->insert(idx, value, max_size); + } + return true; +} + +bool of_QINSERT_PROP_R(vthread_t thr, vvp_code_t cp) +{ + return qinsert_prop(thr, cp, 0); +} + +bool of_QINSERT_PROP_STR(vthread_t thr, vvp_code_t cp) +{ + return qinsert_prop(thr, cp, 0); +} + +bool of_QINSERT_PROP_V(vthread_t thr, vvp_code_t cp) +{ + return qinsert_prop(thr, cp, cp->bit_idx[1]); +} + +template +static bool q_pop_prop(vthread_t thr, vvp_code_t cp, + void (*get_val_func)(vvp_queue*, ELEM&), + const char*loc, unsigned wid) +{ + size_t pid = cp->number; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + QTYPE* queue = get_queue_prop(cobj, pid); + assert(queue); + + size_t size = queue->get_size(); + + ELEM value; + if (size) { + get_val_func(queue, value); + } else { + dq_default(value, wid); + cerr << thr->get_fileline() + << "Warning: pop_" << loc << "() on empty " + << get_queue_type(value) << "." << endl; + } + + push_value(thr, value, wid); + return true; +} + +template +static bool qpop_b_prop(vthread_t thr, vvp_code_t cp, unsigned wid) +{ + return q_pop_prop(thr, cp, get_back_value, "back", wid); +} + +template +static bool qpop_f_prop(vthread_t thr, vvp_code_t cp, unsigned wid) +{ + return q_pop_prop(thr, cp, get_front_value, "front", wid); +} + +bool of_QPOP_PROP_B_REAL(vthread_t thr, vvp_code_t cp) +{ + return qpop_b_prop(thr, cp, 0); +} + +bool of_QPOP_PROP_B_STR(vthread_t thr, vvp_code_t cp) +{ + return qpop_b_prop(thr, cp, 0); +} + +bool of_QPOP_PROP_B_V(vthread_t thr, vvp_code_t cp) +{ + return qpop_b_prop(thr, cp, cp->bit_idx[0]); +} + +bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t cp) +{ + return qpop_f_prop(thr, cp, 0); +} + +bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t cp) +{ + return qpop_f_prop(thr, cp, 0); +} + +bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t cp) +{ + return qpop_f_prop(thr, cp, cp->bit_idx[0]); +} + +bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + const vvp_queue* queue = qobj.peek(); + + size_t sz = queue ? queue->get_size() : 0; + + vvp_vector4_t val(32, BIT4_0); + unsigned long ul = sz; + for (unsigned idx = 0; idx < 32; idx++) { + if (ul & 1UL) { + val.set_bit(idx, BIT4_1); + } else { + val.set_bit(idx, BIT4_0); + } + ul >>= 1; + } + thr->push_vec4(val); + return true; +} + +bool of_DELETE_PROP_ELEM(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + + int64_t idx_val = thr->words[3].w_int; + if (thr->flags[4] == BIT4_1) { + cerr << thr->get_fileline() + << "Warning: skipping queue delete() with undefined index." + << endl; + return true; + } + if (idx_val < 0) { + cerr << thr->get_fileline() + << "Warning: skipping queue delete() with negative index." + << endl; + return true; + } + size_t idx = idx_val; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + vvp_object_t qobj; + cobj->get_object(pid, qobj, 0); + vvp_queue* queue = qobj.peek(); + if (queue == 0) { + cerr << thr->get_fileline() + << "Warning: skipping delete(" << idx + << ") on empty queue." << endl; + } else { + size_t size = queue->get_size(); + if (idx >= size) { + cerr << thr->get_fileline() + << "Warning: skipping out of range delete(" << idx + << ") on queue of size " << size << "." << endl; + } else { + queue->erase(idx); + } + } + + return true; +} + +bool of_DELETE_PROP_OBJ(vthread_t thr, vvp_code_t cp) +{ + size_t pid = cp->number; + + vvp_object_t& top = thr->peek_object(); + vvp_cobject*cobj = top.peek(); + assert(cobj); + + cobj->set_object(pid, vvp_object_t(), 0); + + return true; +} + template static bool store_qb(vthread_t thr, vvp_code_t cp, unsigned wid=0) { diff --git a/vvp/vvp.def b/vvp/vvp.def index 1d1737c77..702103d60 100644 --- a/vvp/vvp.def +++ b/vvp/vvp.def @@ -43,6 +43,7 @@ vpi_vprintf vpip_calc_clog2 vpip_count_drivers vpip_format_strength +vpip_format_pretty vpip_make_systf_system_defined vpip_mcd_rawwrite vpip_set_return_value diff --git a/vvp/words.cc b/vvp/words.cc index 630c430b0..6291a7646 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -35,7 +35,8 @@ using namespace std; static void __compile_var_real(char*label, char*name, - vvp_array_t array, unsigned long array_addr) + vvp_array_t array, unsigned long array_addr, + bool local_flag) { vvp_net_t*net = new vvp_net_t; @@ -55,7 +56,8 @@ static void __compile_var_real(char*label, char*name, if (name) { assert(!array); - vpip_attach_to_current_scope(obj); + if (!local_flag) + vpip_attach_to_current_scope(obj); if (!vpip_peek_current_scope()->is_automatic()) schedule_init_vector(vvp_net_ptr_t(net,0), 0.0); } @@ -67,9 +69,9 @@ static void __compile_var_real(char*label, char*name, delete[] name; } -void compile_var_real(char*label, char*name) +void compile_var_real(char*label, char*name, bool local_flag) { - __compile_var_real(label, name, 0, 0); + __compile_var_real(label, name, 0, 0, local_flag); } void compile_var_string(char*label, char*name)