diff --git a/Module.h b/Module.h index d62da62d6..f5fb524fd 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef __Module_H #define __Module_H /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009 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 @@ -105,6 +105,7 @@ class Module : public PScope, public LineInfo { /* These are the timescale for this module. The default is set by the `timescale directive. */ int time_unit, time_precision; + bool time_from_timescale; /* Task definitions within this module */ map tasks; diff --git a/PDelays.cc b/PDelays.cc index 85c6e42ac..06729fe3d 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2009 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 @@ -26,6 +26,11 @@ # include "verinum.h" # include "netmisc.h" +bool dly_used_no_timescale = false; +bool dly_used_timescale = false; +bool display_ts_dly_warning = true; + + PDelays::PDelays() { delete_flag_ = true; @@ -62,10 +67,23 @@ void PDelays::set_delays(const svector*del, bool df) static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr) { - NetExpr*dex = expr->elaborate_expr(des, scope, -1, false); eval_expr(dex); + /* Print a warning if we find default and `timescale based + * delays in the design, since this is likely an error. */ + if (scope->time_from_timescale()) dly_used_timescale = true; + else dly_used_no_timescale = true; + + if (display_ts_dly_warning && + dly_used_no_timescale && dly_used_timescale) { + cerr << "warning: Found both default and " + "`timescale based delays. Use" << endl; + cerr << " -Wtimescale to find the " + "module(s) with no `timescale." << endl; + display_ts_dly_warning = false; + } + /* If the delay expression is a real constant or vector constant, then evaluate it, scale it to the local time units, and return an adjusted value. */ diff --git a/PWire.cc b/PWire.cc index da424e6d4..4ad7fb391 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2009 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 @@ -29,8 +29,8 @@ PWire::PWire(perm_string n, : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), port_msb_(0), port_lsb_(0), port_set_(false), - net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0), - lidx_(0), ridx_(0), discipline_(0) + net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), + error_cnt_(0), lidx_(0), ridx_(0), discipline_(0) { if (t == NetNet::INTEGER) { type_ = NetNet::REG; @@ -135,7 +135,12 @@ bool PWire::get_isint() const return isint_; } -void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) +bool PWire::get_scalar() const +{ + return is_scalar_; +} + +void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) { switch (type) { case SR_PORT: @@ -147,6 +152,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) port_msb_ = m; port_lsb_ = l; port_set_ = true; + is_scalar_ = is_scalar; } return; @@ -159,6 +165,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) net_msb_ = m; net_lsb_ = l; net_set_ = true; + is_scalar_ = is_scalar; } return; @@ -181,6 +188,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) net_msb_ = m; net_lsb_ = l; net_set_ = true; + is_scalar_ = is_scalar; } return; } diff --git a/PWire.h b/PWire.h index 697fd732e..d87738e08 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef __PWire_H #define __PWire_H /* - * Copyright (c) 1998-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009 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 @@ -70,11 +70,12 @@ class PWire : public LineInfo { void set_signed(bool flag); bool get_signed() const; bool get_isint() const; + bool get_scalar() const; bool set_data_type(ivl_variable_type_t dt); ivl_variable_type_t get_data_type() const; - void set_range(PExpr*msb, PExpr*lsb, PWSRType type); + void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar); void set_memory_idx(PExpr*ldx, PExpr*rdx); @@ -104,6 +105,7 @@ class PWire : public LineInfo { PExpr*net_msb_; PExpr*net_lsb_; bool net_set_; + bool is_scalar_; unsigned error_cnt_; // If this wire is actually a memory, these indices will give diff --git a/driver/iverilog.man b/driver/iverilog.man index 23139fbfb..05245a5b9 100644 --- a/driver/iverilog.man +++ b/driver/iverilog.man @@ -1,4 +1,4 @@ -.TH iverilog 1 "February 4th, 2009" "" "Version 0.9.devel" +.TH iverilog 1 "April 17th, 2009" "" "Version 0.10.devel" .SH NAME iverilog - Icarus Verilog compiler @@ -100,7 +100,7 @@ The standards requires that a vectored port have matching ranges for its port declaration as well as any net/register declaration. It was common practice in the past to only specify the range for the net/register declaration and some tools still allow this. By default any mismatch is -reported as a error. Using \fI-gno-io-range-error\fP will produce a +reported as a error. Using \fB-gno-io-range-error\fP will produce a warning instead of a fatal error for the case of a vectored net/register and a scalar port declaration. .TP 8 @@ -250,7 +250,7 @@ after a \fB-Wall\fP argument to suppress isolated warning types. .TP 8 .B all -This enables all supported warning categories. +This enables the implicit, portbind and timescale warning categories. .TP 8 .B implicit diff --git a/elab_expr.cc b/elab_expr.cc index b54fbdb09..3eeb7a0a0 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1617,7 +1617,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, } if (tmp->expr_type() == IVL_VT_REAL) { - cerr << tmp->get_fileline() << ": error: concatenation " + cerr << tmp->get_fileline() << ": error: Concatenation " << "repeat expression can not be REAL." << endl; des->errors += 1; return 0; @@ -1627,7 +1627,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, if (rep == 0) { cerr << get_fileline() << ": error: " - "concatenation repeat expression cannot be evaluated." + "Concatenation repeat expression cannot be evaluated." << endl; cerr << get_fileline() << ": : The expression is: " << *tmp << endl; @@ -1688,7 +1688,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, if (ex->expr_type() == IVL_VT_REAL) { cerr << ex->get_fileline() << ": error: " - << "concatenation operand can not be real: " + << "Concatenation operand can not be real: " << *parms_[idx] << endl; des->errors += 1; continue; @@ -1696,8 +1696,8 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, if (! ex->has_width()) { cerr << ex->get_fileline() << ": error: " - << "concatenation operand has indefinite width: " - << *ex << endl; + << "Concatenation operand \"" << *parms_[idx] + << "\" has indefinite width." << endl; des->errors += 1; continue; } @@ -2642,11 +2642,13 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, if (name_tail.index.size() > 1) word_sel = name_tail.index.back().sel; - if (res->expr_type() == IVL_VT_REAL && + if (net->get_scalar() && word_sel != index_component_t::SEL_NONE) { - cerr << get_fileline() << ": error: " - << "can not select part of real array word: " - << net->name() <<"[" << *word_index << "]" << endl; + cerr << get_fileline() << ": error: can not select part of "; + if (res->expr_type() == IVL_VT_REAL) cerr << "real"; + else cerr << "scalar"; + cerr << " array word: " << net->name() + <<"[" << *word_index << "]" << endl; des->errors += 1; delete res; return 0; @@ -2946,10 +2948,12 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, if (! path_.back().index.empty()) use_sel = path_.back().index.back().sel; - if (node->expr_type() == IVL_VT_REAL && + if (net->get_scalar() && use_sel != index_component_t::SEL_NONE) { - cerr << get_fileline() << ": error: " - << "can not select part of real: " << net->name() << endl; + cerr << get_fileline() << ": error: can not select part of "; + if (node->expr_type() == IVL_VT_REAL) cerr << "real: "; + else cerr << "scalar: "; + cerr << net->name() << endl; des->errors += 1; return 0; } diff --git a/elab_lval.cc b/elab_lval.cc index 63f0c40c2..7478eab8c 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -199,10 +199,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return elaborate_lval_net_word_(des, scope, reg); // This must be after the array word elaboration above! - if (reg->data_type() == IVL_VT_REAL && + if (reg->get_scalar() && use_sel != index_component_t::SEL_NONE) { - cerr << get_fileline() << ": error: " - << "can not select part of real: " << reg->name() << endl; + cerr << get_fileline() << ": error: can not select part of "; + if (reg->data_type() == IVL_VT_REAL) cerr << "real: "; + else cerr << "scalar: "; + cerr << reg->name() << endl; des->errors += 1; return 0; } @@ -301,12 +303,13 @@ NetAssign_* PEIdent::elaborate_lval_net_word_(Design*des, if (name_tail.index.size() > 1) use_sel = name_tail.index.back().sel; - if (reg->data_type() == IVL_VT_REAL && + if (reg->get_scalar() && use_sel != index_component_t::SEL_NONE) { - perm_string name = peek_tail_name(path_); - cerr << get_fileline() << ": error: " - << "can not select part of real array word: " - << reg->name() << "[" << *word << "]" << endl; + cerr << get_fileline() << ": error: can not select part of "; + if (reg->data_type() == IVL_VT_REAL) cerr << "real"; + else cerr << "scalar"; + cerr << " array word: " << reg->name() + << "[" << *word << "]" << endl; des->errors += 1; return 0; } diff --git a/elab_net.cc b/elab_net.cc index 40cbc7383..143674c6e 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -466,10 +466,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, /* The array has a part/bit select at the end. */ if (name_tail.index.size() > sig->array_dimensions()) { - if (sig->data_type() == IVL_VT_REAL) { + if (sig->get_scalar()) { cerr << get_fileline() << ": error: " - << "can not select part of real array word: " - << sig->name() << "[" << widx_val << "]" << endl; + << "can not select part of "; + if (sig->data_type() == IVL_VT_REAL) cerr << "real"; + else cerr << "scalar"; + cerr << " array word: " << sig->name() + << "[" << widx_val << "]" << endl; des->errors += 1; return 0; } @@ -489,10 +492,12 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, lidx = lidx_tmp; } } else if (!name_tail.index.empty()) { - if (sig->data_type() == IVL_VT_REAL) { + if (sig->get_scalar()) { cerr << get_fileline() << ": error: " - << "can not select part of real: " - << sig->name() << endl; + << "can not select part of "; + if (sig->data_type() == IVL_VT_REAL) cerr << "real: "; + else cerr << "scalar: "; + cerr << sig->name() << endl; des->errors += 1; return 0; } diff --git a/elab_scope.cc b/elab_scope.cc index 03bb3664a..b9b7f9e42 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1062,6 +1062,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s // Set time units and precision. my_scope->time_unit(mod->time_unit); my_scope->time_precision(mod->time_precision); + my_scope->time_from_timescale(mod->time_from_timescale); des->set_precision(mod->time_precision); // Look for module parameter replacements. The "replace" map diff --git a/elab_sig.cc b/elab_sig.cc index 1b26ca920..c4310a745 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -599,9 +599,11 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const } ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum); + ret_sig->set_scalar(false); } else { ret_sig = new NetNet(scope, fname, NetNet::REG); + ret_sig->set_scalar(true); } ret_sig->set_line(*this); ret_sig->set_signed(return_type_.type == PTF_REG_S); @@ -614,6 +616,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->set_line(*this); ret_sig->set_signed(true); ret_sig->set_isint(true); + ret_sig->set_scalar(false); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_LOGIC); break; @@ -623,6 +626,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->set_line(*this); ret_sig->set_signed(false); ret_sig->set_isint(false); + ret_sig->set_scalar(false); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_LOGIC); break; @@ -633,6 +637,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->set_line(*this); ret_sig->set_signed(true); ret_sig->set_isint(false); + ret_sig->set_scalar(true); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_REAL); break; @@ -850,10 +855,15 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const { NetNet::Type wtype = type_; - if (wtype == NetNet::IMPLICIT) + bool is_implicit_scalar = false; + if (wtype == NetNet::IMPLICIT) { wtype = NetNet::WIRE; - if (wtype == NetNet::IMPLICIT_REG) + is_implicit_scalar = true; + } + if (wtype == NetNet::IMPLICIT_REG) { wtype = NetNet::REG; + is_implicit_scalar = true; + } unsigned wid = 1; long lsb = 0, msb = 0; @@ -902,6 +912,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const delete texpr; nmsb = pmsb; nlsb = plsb; + /* An implicit port can have a range so note that here. */ + is_implicit_scalar = false; } if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); if (port_msb_ == 0) assert(port_lsb_ == 0); @@ -1095,8 +1107,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create signal " - << wtype << " ["< 0) { cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; } @@ -1126,6 +1141,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig->port_type(port_type_); sig->set_signed(get_signed()); sig->set_isint(get_isint()); + if (is_implicit_scalar) sig->set_scalar(true); + else sig->set_scalar(get_scalar()); if (ivl_discipline_t dis = get_discipline()) { sig->set_discipline(dis); diff --git a/elaborate.cc b/elaborate.cc index 44ee64ab2..e5674c474 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1827,6 +1827,20 @@ static NetExpr*elaborate_delay_expr(PExpr*expr, Design*des, NetScope*scope) probe_expr_width(des, scope, expr); NetExpr*dex = elab_and_eval(des, scope, expr, -1); + /* Print a warning if we find default and `timescale based + * delays in the design, since this is likely an error. */ + if (scope->time_from_timescale()) dly_used_timescale = true; + else dly_used_no_timescale = true; + + if (display_ts_dly_warning && + dly_used_no_timescale && dly_used_timescale) { + cerr << "warning: Found both default and " + "`timescale based delays. Use" << endl; + cerr << " -Wtimescale to find the " + "module(s) with no `timescale." << endl; + display_ts_dly_warning = false; + } + /* If the delay expression is a real constant or vector constant, then evaluate it, scale it to the local time units, and return an adjusted NetEConst. */ @@ -3737,6 +3751,19 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const if (ndelays > 12) ndelays = 12; + /* Print a warning if we find default and `timescale based + * delays in the design, since this is likely an error. */ + if (scope->time_from_timescale()) dly_used_timescale = true; + else dly_used_no_timescale = true; + + if (display_ts_dly_warning && + dly_used_no_timescale && dly_used_timescale) { + cerr << "warning: Found both default and " + "`timescale based delays. Use" << endl; + cerr << " -Wtimescale to find the " + "module(s) with no `timescale." << endl; + display_ts_dly_warning = false; + } int shift = scope->time_unit() - des->get_precision(); /* Elaborate the delay values themselves. Remember to scale @@ -4301,6 +4328,7 @@ Design* elaborate(listroots) scope->set_line(rmod); scope->time_unit(rmod->time_unit); scope->time_precision(rmod->time_precision); + scope->time_from_timescale(rmod->time_from_timescale); scope->default_nettype(rmod->default_nettype); des->set_precision(rmod->time_precision); diff --git a/iverilog-vpi.man b/iverilog-vpi.man index 5cfd082ba..50ea7f4c2 100644 --- a/iverilog-vpi.man +++ b/iverilog-vpi.man @@ -1,4 +1,4 @@ -.TH iverilog-vpi 1 "November 19th, 2008" "" "Version 0.9.devel" +.TH iverilog-vpi 1 "April 17th, 2009" "" "Version 0.10.devel" .SH NAME iverilog-vpi - Compile front end for VPI modules diff --git a/net_scope.cc b/net_scope.cc index ed9853f1a..e446ced91 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2009 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 @@ -46,12 +46,14 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t) default_nettype_ = up->default_nettype(); time_unit_ = up->time_unit(); time_prec_ = up->time_precision(); + time_from_timescale_ = up->time_from_timescale(); sib_ = up_->sub_; up_->sub_ = this; } else { default_nettype_ = NetNet::NONE; time_unit_ = 0; time_prec_ = 0; + time_from_timescale_ = false; assert(t == MODULE); } @@ -295,6 +297,11 @@ void NetScope::time_precision(int val) time_prec_ = val; } +void NetScope::time_from_timescale(bool val) +{ + time_from_timescale_ = val; +} + int NetScope::time_unit() const { return time_unit_; @@ -305,6 +312,11 @@ int NetScope::time_precision() const return time_prec_; } +bool NetScope::time_from_timescale() const +{ + return time_from_timescale_; +} + void NetScope::default_nettype(NetNet::Type nt) { default_nettype_ = nt; diff --git a/netlist.cc b/netlist.cc index d76b6d443..4a69c5e80 100644 --- a/netlist.cc +++ b/netlist.cc @@ -491,8 +491,8 @@ const Link& NetDelaySrc::condit_pin() const NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), - signed_(false), isint_(false), discipline_(0), msb_(npins-1), lsb_(0), - dimensions_(0), + signed_(false), isint_(false), is_scalar_(false), + discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0), s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0) { assert(s); @@ -544,7 +544,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, long ms, long ls) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), - isint_(false), discipline_(0), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0), + isint_(false), is_scalar_(false), discipline_(0), msb_(ms), lsb_(ls), + dimensions_(0), s0_(0), e0_(0), local_flag_(false), eref_count_(0), lref_count_(0) { assert(s); @@ -594,7 +595,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - discipline_(0), msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e), + is_scalar_(false), discipline_(0), msb_(ms), lsb_(ls), + dimensions_(1), s0_(array_s), e0_(array_e), local_flag_(false), eref_count_(0), lref_count_(0) { ivl_assert(*this, s); @@ -727,6 +729,16 @@ void NetNet::set_isint(bool flag) isint_ = flag; } +bool NetNet::get_scalar() const +{ + return is_scalar_; +} + +void NetNet::set_scalar(bool flag) +{ + is_scalar_ = flag; +} + ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index 256c68ebe..8375aad00 100644 --- a/netlist.h +++ b/netlist.h @@ -581,6 +581,9 @@ class NetNet : public NetObj { bool get_isint() const; void set_isint(bool); + bool get_scalar() const; + void set_scalar(bool); + /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); @@ -650,6 +653,7 @@ class NetNet : public NetObj { ivl_variable_type_t data_type_; bool signed_; bool isint_; // original type of integer + bool is_scalar_; ivl_discipline_t discipline_; long msb_, lsb_; @@ -773,9 +777,11 @@ class NetScope : public Attrib { void time_unit(int); void time_precision(int); + void time_from_timescale(bool); int time_unit() const; int time_precision() const; + bool time_from_timescale() const; void default_nettype(NetNet::Type); NetNet::Type default_nettype() const; @@ -883,6 +889,7 @@ class NetScope : public Attrib { unsigned def_lineno_; signed char time_unit_, time_prec_; + bool time_from_timescale_; NetNet::Type default_nettype_; NetEvent *events_; diff --git a/netmisc.h b/netmisc.h index 8a72b8b9e..5617a8255 100644 --- a/netmisc.h +++ b/netmisc.h @@ -231,4 +231,8 @@ const char *human_readable_op(const char op, bool unary = false); enum const_bool { C_NON, C_0, C_1, C_X }; const_bool const_logical(const NetExpr*expr); +extern bool dly_used_no_timescale; +extern bool dly_used_timescale; +extern bool display_ts_dly_warning; + #endif diff --git a/pform.cc b/pform.cc index 898af8ca3..eee85f1ad 100644 --- a/pform.cc +++ b/pform.cc @@ -342,6 +342,9 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, pform_cur_module = new Module(lex_name); pform_cur_module->time_unit = pform_time_unit; pform_cur_module->time_precision = pform_time_prec; + /* If we have a timescale file then the time information is from + * a timescale directive. */ + pform_cur_module->time_from_timescale = pform_timescale_file != 0; pform_cur_module->default_nettype = pform_default_nettype; FILE_NAME(pform_cur_module, file, lineno); @@ -1028,13 +1031,13 @@ static void pform_set_net_range(perm_string name, if (range == 0) { /* This is the special case that we really mean a scalar. Set a fake range. */ - cur->set_range(0, 0, rt); + cur->set_range(0, 0, rt, true); } else { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); - cur->set_range((*range)[0], (*range)[1], rt); + cur->set_range((*range)[0], (*range)[1], rt, false); } cur->set_signed(signed_flag); @@ -1396,14 +1399,16 @@ void pform_module_define_port(const struct vlltype&li, if (range == 0) { cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : - SR_BOTH); + SR_BOTH, + true); } else { assert(range->count() == 2); assert((*range)[0]); assert((*range)[1]); cur->set_range((*range)[0], (*range)[1], - (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, + false); } if (attr) { @@ -1483,7 +1488,7 @@ void pform_makewire(const vlltype&li, perm_string name, << " to " << dt << "." << endl; } ivl_assert(*cur, flag); - cur->set_range(0, 0, SR_NET); + cur->set_range(0, 0, SR_NET, true); cur->set_signed(true); break; default: @@ -1673,7 +1678,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, /* If there is a range involved, it needs to be set. */ if (range) - curw->set_range((*range)[0], (*range)[1], SR_PORT); + curw->set_range((*range)[0], (*range)[1], SR_PORT, false); svector*tmp = new svector(*res, curw); @@ -1933,7 +1938,7 @@ static void pform_set_reg_integer(perm_string name) cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET); + SR_NET, false); cur->set_signed(true); } @@ -1964,7 +1969,7 @@ static void pform_set_reg_time(perm_string name) cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET); + SR_NET, false); } void pform_set_reg_time(list*names) diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index 84aba600b..74e4456ad 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -64,6 +64,21 @@ static PLI_INT32 function_not_implemented_compiletf(PLI_BYTE8* name) return 0; } +/* + * This is used to warn the user that the specified optional system + * task/function is not available (from Annex C 1364-2005). + */ +static PLI_INT32 missing_optional_compiletf(PLI_BYTE8* name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + + vpi_printf("%s:%d: SORRY: %s() is not available in Icarus verilog.\n", + vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh), + name); + vpi_control(vpiFinish, 1); + return 0; +} + /* * Register the function with Verilog. */ @@ -217,4 +232,83 @@ void sys_special_register(void) tf_data.tfname = "$ferror"; tf_data.user_data = "$ferror"; vpi_register_systf(&tf_data); + + /* The following optional system tasks/functions are not implemented + * in Icarus Verilog (from Annex C 1364-2005). */ + tf_data.type = vpiSysTask; + tf_data.calltf = 0; + tf_data.sizetf = 0; + tf_data.compiletf = missing_optional_compiletf; + + tf_data.tfname = "$input"; + tf_data.user_data = "$input"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$key"; + tf_data.user_data = "$key"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$nokey"; + tf_data.user_data = "$nokey"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$list"; + tf_data.user_data = "$list"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$log"; + tf_data.user_data = "$log"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$nolog"; + tf_data.user_data = "$nolog"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$save"; + tf_data.user_data = "$save"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$restart"; + tf_data.user_data = "$restart"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$incsave"; + tf_data.user_data = "$incsave"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$scope"; + tf_data.user_data = "$scope"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$showscopes"; + tf_data.user_data = "$showscopes"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$showvars"; + tf_data.user_data = "$showvars"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$sreadmemb"; + tf_data.user_data = "$sreadmemb"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$sreadmemh"; + tf_data.user_data = "$sreadmemh"; + vpi_register_systf(&tf_data); + + /* Optional functions. */ + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + + tf_data.tfname = "$countdrivers"; + tf_data.user_data = "$countdrivers"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$getpattern"; + tf_data.user_data = "$getpattern"; + vpi_register_systf(&tf_data); + + tf_data.tfname = "$scale"; + tf_data.user_data = "$scale"; + vpi_register_systf(&tf_data); } diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index cb50d8a69..10311c203 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -551,8 +551,15 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) switch (vpi_get(vpiType, item)) { case vpiNet: type = "wire"; if(0){ - case vpiIntegerVar: case vpiMemoryWord: + if (vpi_get(vpiConstantSelect, item) == 0) { + /* Turn a non-constant array word select into a + * constant word select. */ + vpiHandle array = vpi_handle(vpiParent, item); + PLI_INT32 index = vpi_get(vpiIndex, item); + item = vpi_handle_by_index(array, index); + } + case vpiIntegerVar: case vpiTimeVar: case vpiReg: type = "reg"; } diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index e31f8995a..e4776dc1e 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -563,8 +563,15 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) switch (vpi_get(vpiType, item)) { case vpiNet: type = "wire"; if(0){ - case vpiIntegerVar: case vpiMemoryWord: + if (vpi_get(vpiConstantSelect, item) == 0) { + /* Turn a non-constant array word select into a + * constant word select. */ + vpiHandle array = vpi_handle(vpiParent, item); + PLI_INT32 index = vpi_get(vpiIndex, item); + item = vpi_handle_by_index(array, index); + } + case vpiIntegerVar: case vpiTimeVar: case vpiReg: type = "reg"; } diff --git a/vpi/sys_readmem.c b/vpi/sys_readmem.c index 9d25d09a2..9adc062b9 100644 --- a/vpi/sys_readmem.c +++ b/vpi/sys_readmem.c @@ -27,6 +27,10 @@ # include # include # include "sys_readmem_lex.h" +# include + +char **search_list = NULL; +unsigned sl_count = 0; static void get_mem_params(vpiHandle argv, vpiHandle callh, char *name, char **fname, vpiHandle *mitem, @@ -291,8 +295,18 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) &start_addr, &stop_addr, &addr_incr, &min_addr, &max_addr)) return 0; - /* Open the data file. */ + /* Open the data file. */ file = fopen(fname, "r"); + /* Check to see if we have other directories to look for this file. */ + if (file == 0 && sl_count > 0 && fname[0] != '/') { + unsigned idx; + char path[4096]; + + for (idx = 0; idx < sl_count; idx += 1) { + snprintf(path, 4096, "%s/%s", search_list[idx], fname); + if ((file = fopen(path, "r"))) break; + } + } if (file == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -391,6 +405,102 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) return 0; } +static PLI_INT32 free_readmempath(p_cb_data cb_data) +{ + unsigned idx; + for(idx = 0; idx < sl_count; idx += 1) { + free(search_list[idx]); + } + free(search_list); + search_list = NULL; + sl_count = 0; + return 0; +} + +static PLI_INT32 sys_readmempath_calltf(PLI_BYTE8*name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle paths = vpi_scan(argv); + s_vpi_value val; + unsigned len, idx; + char *path; + + vpi_free_object(argv); + + /* Get the search path string. */ + val.format = vpiStringVal; + vpi_get_value(paths, &val); + + /* Verify that we have a string and that it is not NULL. */ + if (val.format != vpiStringVal || !*(val.value.str)) { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's argument (%s) is not a valid string.\n", + name, vpi_get_str(vpiType, paths)); + return 0; + } + + /* + * Verify that the search path is composed of only printable + * characters. + */ + len = strlen(val.value.str); + for (idx = 0; idx < len; idx++) { + if (! isprint(val.value.str[idx])) { + char msg [64]; + char *esc_path = as_escaped(val.value.str); + snprintf(msg, 64, "WARNING: %s:%d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s %s's argument contains non-printable " + "characters.\n", msg, name); + vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", esc_path); + free(esc_path); + return 0; + } + } + + /* Clear the old list before creating the new list. */ + free_readmempath(NULL); + + /* + * Break the string into individual paths and add them to the list. + * Print a warning if the path is not valid. + */ + for (path = strtok(val.value.str, ":"); path; path = strtok(NULL, ":")) { + int res; + struct stat sb; + + /* Warn the user if the path is not valid. */ + res = stat(path, &sb); + if (res == 0) { + if (!S_ISDIR(sb.st_mode)) { + vpi_printf("WARNING: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's path element \"%s\" is not a " + "directory!\n", name, path); + continue; + } + } else { + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s could not find directory \"%s\"!\n", + name, path); + continue; + } + + /* Add a valid search path element to the list. */ + sl_count += 1; + search_list = (char **) realloc(search_list, + sizeof(char **)*sl_count); + search_list[sl_count-1] = strdup(path); + } + + return 0; +} + static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name) { int addr; @@ -455,6 +565,7 @@ static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name) void sys_readmem_register() { s_vpi_systf_data tf_data; + s_cb_data cb_data; tf_data.type = vpiSysTask; tf_data.tfname = "$readmemh"; @@ -472,6 +583,14 @@ void sys_readmem_register() tf_data.user_data = "$readmemb"; vpi_register_systf(&tf_data); + tf_data.type = vpiSysTask; + tf_data.tfname = "$readmempath"; + tf_data.calltf = sys_readmempath_calltf; + tf_data.compiletf = sys_one_string_arg_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$readmempath"; + vpi_register_systf(&tf_data); + tf_data.type = vpiSysTask; tf_data.tfname = "$writememh"; tf_data.calltf = sys_writemem_calltf; @@ -487,4 +606,10 @@ void sys_readmem_register() tf_data.sizetf = 0; tf_data.user_data = "$writememb"; vpi_register_systf(&tf_data); + + cb_data.reason = cbEndOfSimulation; + cb_data.time = 0; + cb_data.cb_rtn = free_readmempath; + cb_data.user_data = "system"; + vpi_register_cb(&cb_data); } diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index bcb678826..8f2b1d531 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -519,8 +519,15 @@ static void scan_item(unsigned depth, vpiHandle item, int skip) switch (vpi_get(vpiType, item)) { case vpiNet: type = "wire"; if(0){ - case vpiIntegerVar: case vpiMemoryWord: + if (vpi_get(vpiConstantSelect, item) == 0) { + /* Turn a non-constant array word select into a + * constant word select. */ + vpiHandle array = vpi_handle(vpiParent, item); + PLI_INT32 index = vpi_get(vpiIndex, item); + item = vpi_handle_by_index(array, index); + } + case vpiIntegerVar: case vpiTimeVar: case vpiReg: type = "reg"; } diff --git a/vpi/vcd_priv.c b/vpi/vcd_priv.c index 4418dbb49..e3e2c6af0 100644 --- a/vpi/vcd_priv.c +++ b/vpi/vcd_priv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2009 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 @@ -246,6 +246,16 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name) while ((arg=vpi_scan(argv)) != NULL) { switch(vpi_get(vpiType, arg)) { case vpiMemoryWord: +/* + * We need to allow non-constant selects to support the following: + * + * for (lp = 0; lp < max ; lp = lp + 1) $dumpvars(0, array[lp]); + * + * We need to do a direct callback on the selected element vs using + * the &A<> structure. The later will not give us what we want. + * This is implemented in the calltf routine. + */ +#if 0 if (vpi_get(vpiConstantSelect, arg) == 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); @@ -253,6 +263,7 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name) vpi_get_str(vpiType, arg)); vpi_control(vpiFinish, 1); } +#endif /* The module types. */ case vpiModule: case vpiTask: diff --git a/vvp/array.cc b/vvp/array.cc index 9bab08a85..5b8522f71 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -675,6 +675,9 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) case vpiRightRange: return parent->lsb.value; + case vpiIndex: + return (int)obj->get_address() + parent->first_addr.value; + case vpiAutomatic: return (int) parent->scope->is_automatic; diff --git a/vvp/stop.cc b/vvp/stop.cc index b20230fd8..0b6aad7a3 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -457,8 +457,13 @@ static void invoke_command(char*txt) if (argc > 0) { if (argv[0][0] == '$') { - cmd_call(argc, argv); - + if (strcmp(argv[0], "$stop") == 0) { + printf("The simulator is already stopped!\n"); + } else if (strcmp(argv[0], "$finish") == 0){ + cmd_finish(argc, argv); + } else { + cmd_call(argc, argv); + } } else { unsigned idx; for (idx = 0 ; cmd_table[idx].name ; idx += 1) @@ -483,6 +488,9 @@ void stop_handler(int rc) } vpi_mcd_printf(1,"** VVP Stop(%d) **\n", rc); + vpi_mcd_printf(1,"** Flushing output streams.\n"); + invoke_command("$fflush"); + invoke_command("$dumpflush"); vpi_mcd_printf(1,"** Current simulation time is %" TIME_FMT_U " ticks.\n", schedule_simtime()); diff --git a/vvp/vvp.man b/vvp/vvp.man index 3cb2d8ffc..c680c91cb 100644 --- a/vvp/vvp.man +++ b/vvp/vvp.man @@ -1,4 +1,4 @@ -.TH vvp 1 "November 19th, 2008" "" "Version 0.9.devel" +.TH vvp 1 "April 17th, 2009" "" "Version 0.10.devel" .SH NAME vvp - Icarus Verilog vvp runtime engine