Merge branch 'v10-branch' of github.com:steveicarus/iverilog into v10-branch

This commit is contained in:
Stephen Williams 2016-10-14 10:31:58 -07:00
commit 5e41c86d01
85 changed files with 2227 additions and 859 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 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
@ -35,9 +35,6 @@ Module::Module(LexicalScope*parent, perm_string n)
program_block = false;
uc_drive = UCD_NONE;
timescale_warn_done = false;
time_unit = 0;
time_precision = 0;
time_from_timescale = false;
}
Module::~Module()

View File

@ -1,7 +1,7 @@
#ifndef IVL_Module_H
#define IVL_Module_H
/*
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 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
@ -121,10 +121,6 @@ class Module : public PScopeExtra, public LineInfo {
map<perm_string,PExpr*> attributes;
/* These are the timescale for this module. The default is
set by the `timescale directive. */
int time_unit, time_precision;
bool time_from_timescale;
bool timescale_warn_done;
/* The module has a list of generate schemes that appear in

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2012 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -137,7 +137,7 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
}
PECastSize::PECastSize(unsigned si, PExpr*b)
PECastSize::PECastSize(PExpr*si, PExpr*b)
: size_(si), base_(b)
{
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_PExpr_H
#define IVL_PExpr_H
/*
* Copyright (c) 1998-2014 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2016 Stephen Williams <steve@icarus.com>
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -971,7 +971,7 @@ class PECallFunction : public PExpr {
class PECastSize : public PExpr {
public:
explicit PECastSize(unsigned expr_wid, PExpr*base);
explicit PECastSize(PExpr*size, PExpr*base);
~PECastSize();
void dump(ostream &out) const;
@ -984,7 +984,7 @@ class PECastSize : public PExpr {
width_mode_t&mode);
private:
unsigned size_;
PExpr* size_;
PExpr* base_;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008,2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008,2016 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
@ -19,21 +19,9 @@
# include "PScope.h"
PScope::PScope(perm_string n, LexicalScope*parent)
: LexicalScope(parent), name_(n)
bool LexicalScope::var_init_needs_explicit_lifetime() const
{
}
PScope::PScope(perm_string n)
: LexicalScope(0), name_(n)
{
}
PScope::~PScope()
{
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
it != typedefs.end(); ++it)
delete it->second;
return false;
}
PWire* LexicalScope::wires_find(perm_string name)
@ -45,17 +33,26 @@ PWire* LexicalScope::wires_find(perm_string name)
return (*cur).second;
}
PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
: PScope(n, parent)
PScope::PScope(perm_string n, LexicalScope*parent)
: LexicalScope(parent), name_(n)
{
time_unit = 0;
time_precision = 0;
time_from_timescale = false;
}
PScopeExtra::PScopeExtra(perm_string n)
: PScope(n)
PScope::~PScope()
{
for(map<perm_string, data_type_t*>::iterator it = typedefs.begin();
it != typedefs.end(); ++it)
delete it->second;
}
PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent)
: PScope(n, parent)
{
}
PScopeExtra::~PScopeExtra()
{
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_PScope_H
#define IVL_PScope_H
/*
* Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2016 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
@ -36,6 +36,7 @@ class PProcess;
class PClass;
class PTask;
class PWire;
class Statement;
class Design;
class NetScope;
@ -52,10 +53,14 @@ class NetScope;
class LexicalScope {
public:
explicit LexicalScope(LexicalScope*parent) : parent_(parent) { }
enum lifetime_t { INHERITED, STATIC, AUTOMATIC };
explicit LexicalScope(LexicalScope*parent) : default_lifetime(INHERITED), parent_(parent) { }
// A virtual destructor is so that dynamic_cast can work.
virtual ~LexicalScope() { }
lifetime_t default_lifetime;
struct range_t {
// True if this is an exclude
bool exclude_flag;
@ -108,6 +113,9 @@ class LexicalScope {
// creating implicit nets.
map<perm_string,LineInfo*> genvars;
// Variable initializations in this scope
vector<Statement*> var_inits;
// Behaviors (processes) in this scope
list<PProcess*> behaviors;
list<AProcess*> analog_behaviors;
@ -117,6 +125,8 @@ class LexicalScope {
LexicalScope* parent_scope() const { return parent_; }
virtual bool var_init_needs_explicit_lifetime() const;
protected:
void dump_typedefs_(ostream&out, unsigned indent) const;
@ -130,6 +140,10 @@ class LexicalScope {
void dump_wires_(ostream&out, unsigned indent) const;
void dump_var_inits_(ostream&out, unsigned indent) const;
bool elaborate_var_inits_(Design*des, NetScope*scope) const;
private:
LexicalScope*parent_;
};
@ -145,12 +159,17 @@ class PScope : public LexicalScope {
// modules do not nest in Verilog, the parent must be nil for
// modules. Scopes for tasks and functions point to their
// containing module.
PScope(perm_string name, LexicalScope*parent);
PScope(perm_string name);
explicit PScope(perm_string name, LexicalScope*parent =0);
virtual ~PScope();
perm_string pscope_name() const { return name_; }
/* These are the timescale for this scope. The default is
set by the `timescale directive or, in SystemVerilog,
by timeunit and timeprecision statements. */
int time_unit, time_precision;
bool time_from_timescale;
protected:
bool elaborate_sig_wires_(Design*des, NetScope*scope) const;
@ -168,14 +187,13 @@ class PScope : public LexicalScope {
class PScopeExtra : public PScope {
public:
PScopeExtra(perm_string, LexicalScope*parent);
PScopeExtra(perm_string);
explicit PScopeExtra(perm_string, LexicalScope*parent =0);
~PScopeExtra();
/* Task definitions within this module */
std::map<perm_string,PTask*> tasks;
std::map<perm_string,PFunction*> funcs;
/* class definitions within this module. */
/* Class definitions within this module. */
std::map<perm_string,PClass*> classes;
/* This is the lexical order of the classes, and is used by
elaboration to choose an elaboration order. */

View File

@ -30,6 +30,11 @@ PTaskFunc::~PTaskFunc()
{
}
bool PTaskFunc::var_init_needs_explicit_lifetime() const
{
return default_lifetime == STATIC;
}
void PTaskFunc::set_ports(vector<pform_tf_port_t>*p)
{
assert(ports_ == 0);

View File

@ -41,6 +41,8 @@ class PTaskFunc : public PScope, public LineInfo {
PTaskFunc(perm_string name, LexicalScope*parent);
~PTaskFunc();
bool var_init_needs_explicit_lifetime() const;
void set_ports(std::vector<pform_tf_port_t>*p);
void set_this(class_type_t*use_type, PWire*this_wire);

View File

@ -115,6 +115,11 @@ PBlock::~PBlock()
delete list_[idx];
}
bool PBlock::var_init_needs_explicit_lifetime() const
{
return default_lifetime == STATIC;
}
PChainConstructor* PBlock::extract_chain_constructor()
{
if (list_.empty())

View File

@ -108,7 +108,8 @@ class PAssign_ : public Statement {
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width) const;
unsigned lv_width,
bool force_unsigned =false) const;
NetExpr* elaborate_rval_(Design*, NetScope*, ivl_type_t ntype) const;
NetExpr* elaborate_rval_obj_(Design*, NetScope*,
@ -182,6 +183,8 @@ class PBlock : public PScope, public Statement {
BL_TYPE bl_type() const { return bl_type_; }
bool var_init_needs_explicit_lifetime() const;
// This is only used if this block is the statement list for a
// constructor. We look for a PChainConstructor as the first
// statement, and if it is there, extract it.

View File

@ -1,7 +1,7 @@
#ifndef IVL_compiler_H
#define IVL_compiler_H
/*
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2016 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
@ -142,7 +142,8 @@ extern int build_library_index(const char*path, bool key_case_sensitive);
/* This is the generation of Verilog that the compiler is asked to
support. Then there are also more detailed controls for more
specific language features. */
specific language features. Note that the compiler often assumes
this is an ordered list. */
enum generation_t {
GN_VER1995 = 1,
GN_VER2001_NOCONFIG = 2,
@ -186,25 +187,24 @@ extern bool gn_strict_ca_eval_flag;
standard expression width rules. */
extern bool gn_strict_expr_width_flag;
/* If variables can be converted to uwires by a continuous assignment
(assuming no procedural assign, then return true. This will be true
for SystemVerilog */
static inline bool gn_var_can_be_uwire(void)
/* If this flag is true, then don't add a for-loop control variable
to an implicit event_expression list if it is only used inside the
loop. */
extern bool gn_shared_loop_index_flag;
static inline bool gn_system_verilog(void)
{
if (generation_flag == GN_VER2005_SV ||
generation_flag == GN_VER2009 ||
generation_flag == GN_VER2012)
if (generation_flag >= GN_VER2005_SV)
return true;
return false;
}
static inline bool gn_system_verilog(void)
/* If variables can be converted to uwires by a continuous assignment
(assuming no procedural assign), then return true. This will be true
for SystemVerilog */
static inline bool gn_var_can_be_uwire(void)
{
if (generation_flag == GN_VER2005_SV ||
generation_flag == GN_VER2009 ||
generation_flag == GN_VER2012)
return true;
return false;
return gn_system_verilog();
}
static inline bool gn_modules_nest(void)

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -124,7 +124,8 @@ int cmdfile_stack_ptr = 0;
"-c" { return TOK_Dc; }
"-f" { return TOK_Dc; }
/* Notice the -v flag. */
/* Notice the -l or -v flag. */
"-l" { return TOK_Dv; }
"-v" { return TOK_Dv; }
/* Notice the -y flag. */

View File

@ -1,14 +1,15 @@
.TH iverilog 1 "Aug 7th, 2015" "" "Version %M.%n%E"
.TH iverilog 1 "Oct 2nd, 2016" "" "Version %M.%n%E"
.SH NAME
iverilog - Icarus Verilog compiler
.SH SYNOPSIS
.B iverilog
[\-ESVv] [\-Bpath] [\-ccmdfile|\-fcmdfile] [\-Dmacro[=defn]]
[\-Pparameter=value] [\-pflag=value]
[\-dname] [\-g1995|\-g2001|\-g2005|\-g2005-sv|\-g2009|\-g2012|\-g<feature>]
[\-Pparameter=value] [\-pflag=value] [\-dname]
[\-g1995\:|\-g2001\:|\-g2005\:|\-g2005-sv\:|\-g2009\:|\-g2012\:|\-g<feature>]
[\-Iincludedir] [\-mmodule] [\-M[mode=]file] [\-Nfile] [\-ooutputfilename]
[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] sourcefile
[\-stopmodule] [\-ttype] [\-Tmin/typ/max] [\-Wclass] [\-ypath] [\-lfile]
sourcefile
.SH DESCRIPTION
.PP
@ -133,12 +134,29 @@ parameter assignment is evaluated as a lossless expression, as is any
expression containing an unsized constant number, and unsized constant
numbers are not truncated to integer width.
.TP 8
.B -gshared-loop-index\fI|\fP-gno-shared-loop-index
Enable or disable (default) the exclusion of for-loop control variables
from implicit event_expression lists. When enabled, if a for-loop control
variable (loop index) is only used inside the for-loop statement, the
compiler will not include it in an implicit event_expression list it
calculates for that statement or any enclosing statement. This allows
the same control variable to be used in multiple processes without risk
of entering an infinite loop caused by each process triggering all other
processes that use the same varaible. For strict compliance with the
standards, this behaviour should be disabled.
.TP 8
.B -I\fIincludedir\fP
Append directory \fIincludedir\fP to list of directories searched
for Verilog include files. The \fB\-I\fP switch may be used many times
to specify several directories to search, the directories are searched
in the order they appear on the command line.
.TP 8
.B -l\fIfile\fP
Add the specified file to the list of source files to be compiled,
but mark it as a library file. All modules contained within that
file will be treated as library modules, and only elaborated if
they are instantiated by other modules in the design.
.TP 8
.B -M\fIpath\fP
This is equivalent to \fB\-Mall=path\fP. Preserved for backwards
compatibility.
@ -402,6 +420,15 @@ A \fB\-c\fP or \fB\-f\fP token prefixes a command file, exactly like it
does on the command line. The cmdfile may be on the same line or the
next non-comment line.
.TP 8
.B -l\ \fIfile\fP -v\ \fIfile\fP
A \fB\-l\fP token prefixes a library file in the command file,
exactly like it does on the command line. The parameter to the \fB\-l\fP
flag may be on the same line or the next non-comment line. \fB\-v\fP is
an alias for \fB\-l\fP, provided for compatibility with other simulators.
Variables in the \fIfile\fP are substituted.
.TP 8
.B -y\ \fIlibdir\fP
A \fB\-y\fP token prefixes a library directory in the command file,
@ -532,7 +559,7 @@ Tips on using, debugging, and developing the compiler can be found at
.SH COPYRIGHT
.nf
Copyright \(co 2002\-2015 Stephen Williams
Copyright \(co 2002\-2016 Stephen Williams
This document can be freely redistributed according to the terms of the
GNU General Public License version 2.0

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2016 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
@ -44,7 +44,7 @@ const char HELP[] =
" [-M [mode=]depfile] [-m module]\n"
" [-N file] [-o filename] [-p flag=value]\n"
" [-s topmodule] [-t target] [-T min|typ|max]\n"
" [-W class] [-y dir] [-Y suf] source_file(s)\n"
" [-W class] [-y dir] [-Y suf] [-l file] source_file(s)\n"
"\n"
"See the man page for details.";
@ -128,6 +128,7 @@ const char*gen_icarus = "icarus-misc";
const char*gen_io_range_error = "io-range-error";
const char*gen_strict_ca_eval = "no-strict-ca-eval";
const char*gen_strict_expr_width = "no-strict-expr-width";
const char*gen_shared_loop_index = "no-shared-loop-index";
const char*gen_verilog_ams = "no-verilog-ams";
/* Boolean: true means use a default include dir, false means don't */
@ -730,6 +731,12 @@ static int process_generation(const char*name)
else if (strcmp(name,"no-strict-expr-width") == 0)
gen_strict_expr_width = "no-strict-expr-width";
else if (strcmp(name,"shared-loop-index") == 0)
gen_shared_loop_index = "shared-loop-index";
else if (strcmp(name,"no-shared-loop-index") == 0)
gen_shared_loop_index = "no-shared-loop-index";
else if (strcmp(name,"verilog-ams") == 0)
gen_verilog_ams = "verilog-ams";
@ -755,7 +762,8 @@ static int process_generation(const char*name)
" icarus-misc | no-icarus-misc\n"
" io-range-error | no-io-range-error\n"
" strict-ca-eval | no-strict-ca-eval\n"
" strict-expr-width | no-strict-expr-width\n");
" strict-expr-width | no-strict-expr-width\n"
" shared-loop-index | no-shared-loop-index\n");
return 1;
}
@ -920,7 +928,7 @@ int main(int argc, char **argv)
}
}
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hI:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) {
while ((opt = getopt(argc, argv, "B:c:D:d:Ef:g:hl:I:M:m:N:o:P:p:Ss:T:t:vVW:y:Y:")) != EOF) {
switch (opt) {
case 'B':
@ -975,6 +983,10 @@ int main(int argc, char **argv)
process_include_dir(optarg);
break;
case 'l':
process_file_name(optarg, 1);
break;
case 'M':
if (process_depfile(optarg) != 0)
return -1;
@ -1108,6 +1120,7 @@ int main(int argc, char **argv)
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);
fprintf(iconfig_file, "generation:%s\n", gen_strict_ca_eval);
fprintf(iconfig_file, "generation:%s\n", gen_strict_expr_width);
fprintf(iconfig_file, "generation:%s\n", gen_shared_loop_index);
fprintf(iconfig_file, "generation:%s\n", gen_verilog_ams);
fprintf(iconfig_file, "generation:%s\n", gen_icarus);
fprintf(iconfig_file, "warnings:%s\n", warning_flags);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -90,7 +90,7 @@ static NetBranch* find_existing_implicit_branch(NetNet*sig, NetNet*gnd)
NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
ivl_variable_type_t lv_type, unsigned lv_width,
PExpr*expr, bool need_const)
PExpr*expr, bool need_const, bool force_unsigned)
{
if (debug_elaborate) {
cerr << expr->get_fileline() << ": elaborate_rval_expr: "
@ -135,7 +135,7 @@ NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, ivl_type_t lv_net_type,
}
return elab_and_eval(des, scope, expr, context_wid, need_const,
false, lv_type);
false, lv_type, force_unsigned);
}
/*
@ -675,10 +675,7 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope,
NetExpr*tmp = new NetEBComp(op_, lp, rp);
tmp->set_line(*this);
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
unsigned PEBLogic::test_width(Design*, NetScope*, width_mode_t&)
@ -716,10 +713,7 @@ NetExpr*PEBLogic::elaborate_expr(Design*des, NetScope*scope,
NetExpr*tmp = new NetEBLogic(op_, lp, rp);
tmp->set_line(*this);
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
@ -1035,8 +1029,7 @@ NetExpr*PEBShift::elaborate_expr_leaf(Design*des, NetExpr*lp, NetExpr*rp,
tmp->set_line(*this);
tmp = new NetESelect(lp, tmp, 1);
tmp->set_line(*this);
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(true);
tmp = pad_to_width(tmp, expr_wid, true, *this);
delete rp;
return tmp;
@ -1414,23 +1407,7 @@ NetExpr*PECallFunction::cast_to_width_(NetExpr*expr, unsigned wid) const
<< " from expr_width()=" << expr->expr_width() << endl;
}
/* If the expression is a const, then replace it with a new
const. This is a more efficient result. */
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
tmp->cast_signed(signed_flag_);
if (wid != tmp->expr_width()) {
tmp = new NetEConst(verinum(tmp->value(), wid));
tmp->set_line(*this);
delete expr;
}
return tmp;
}
NetESelect*tmp = new NetESelect(expr, 0, wid);
tmp->cast_signed(signed_flag_);
tmp->set_line(*this);
return tmp;
return cast_to_width(expr, wid, signed_flag_, *this);
}
/*
@ -1606,10 +1583,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
if (missing_parms || parm_errors)
return 0;
NetExpr*tmp = pad_to_width(fun, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(fun, expr_wid, signed_flag_, *this);
}
NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
@ -1666,10 +1640,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
NetExpr*tmp = new NetEAccess(branch, nature);
tmp->set_line(*this);
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
/*
@ -2281,10 +2252,7 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
if(res->darray_type())
return func;
NetExpr*tmp = pad_to_width(func, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(func, expr_wid, signed_flag_, *this);
}
cerr << get_fileline() << ": internal error: Unable to locate "
@ -2521,22 +2489,54 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
{
expr_width_ = size_;
ivl_assert(*this, size_);
ivl_assert(*this, base_);
NetExpr*size_ex = elab_and_eval(des, scope, size_, -1, true);
NetEConst*size_ce = dynamic_cast<NetEConst*>(size_ex);
expr_width_ = size_ce ? size_ce->value().as_ulong() : 0;
delete size_ex;
if (expr_width_ == 0) {
cerr << get_fileline() << ": error: Cast size expression "
"must be constant and greater than zero." << endl;
des->errors += 1;
return 0;
}
width_mode_t tmp_mode = PExpr::SIZED;
base_->test_width(des, scope, tmp_mode);
return size_;
if (!type_is_vectorable(base_->expr_type())) {
cerr << get_fileline() << ": error: Cast base expression "
"must be a vector type." << endl;
des->errors += 1;
return 0;
}
expr_type_ = base_->expr_type();
min_width_ = expr_width_;
signed_flag_ = base_->has_sign();
return expr_width_;
}
NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
unsigned, unsigned) const
unsigned expr_wid, unsigned flags) const
{
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), NO_FLAGS);
NetESelect*sel = new NetESelect(sub, 0, size_);
sel->set_line(*this);
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
return sel;
ivl_assert(*this, size_);
ivl_assert(*this, base_);
NetExpr*sub = base_->elaborate_expr(des, scope, base_->expr_width(), flags);
// Perform the cast. The extension method (zero/sign), if needed,
// depends on the type of the base expression.
NetExpr*tmp = cast_to_width(sub, expr_width_, base_->has_sign(), *this);
// Pad up to the expression width. The extension method (zero/sign)
// depends on the type of enclosing expression.
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&wid)
@ -2851,8 +2851,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
return 0;
}
NetExpr*tmp = pad_to_width(concat, expr_wid, *this);
tmp->cast_signed(signed_flag_);
NetExpr*tmp = pad_to_width(concat, expr_wid, signed_flag_, *this);
concat_depth -= 1;
return tmp;
@ -3769,10 +3768,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
if (!tmp) return 0;
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
// If the identifier names a signal (a register or wire)
@ -3808,10 +3804,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
<< ", tmp=" << *tmp << endl;
}
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
// If the identifier is a named event
@ -3911,9 +3904,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
member_comp);
if (!tmp) return 0;
tmp = pad_to_width(tmp, expr_wid, *this);
tmp->cast_signed(signed_flag_);
return tmp;
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
}
if (net->class_type() != 0) {
@ -4492,7 +4483,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
<< "Elaborate parameter <" << path_
<< "> as enumeration constant." << *etmp << endl;
tmp = etmp->dup_expr();
tmp = pad_to_width(tmp, expr_wid, *this);
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
} else {
perm_string name = peek_tail_name(path_);
@ -6082,7 +6073,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
}
tmp->set_line(*this);
}
tmp = pad_to_width(tmp, expr_wid, *this);
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
break;
case '&': // Reduction AND
@ -6100,7 +6091,7 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
}
tmp = new NetEUReduce(op_, ip);
tmp->set_line(*this);
tmp = pad_to_width(tmp, expr_wid, *this);
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
break;
case '~':

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -138,6 +138,9 @@ NetAssign_* PEConcat::elaborate_lval(Design*des,
continue;
}
/* A concatenation is always unsigned. */
tmp->set_signed(false);
/* Link the new l-value to the previous one. */
NetAssign_*last = tmp;
while (last->more)
@ -287,13 +290,13 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
// We are processing the tail of a string of names. For
// example, the verilog may be "a.b.c", so we are processing
// example, the Verilog may be "a.b.c", so we are processing
// "c" at this point. (Note that if method_name is not nil,
// then this is "a.b.c.method" and "a.b.c" is a struct or class.)
const name_component_t&name_tail = path_.back();
// Use the last index to determine what kind of select
// (bit/part/etc) we are processing. For example, the verilog
// (bit/part/etc) we are processing. For example, the Verilog
// may be "a.b.c[1][2][<index>]". All but the last index must
// be simple expressions, only the <index> may be a part
// select etc., so look at it to determine how we will be
@ -399,6 +402,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
/* No select expressions. */
NetAssign_*lv = new NetAssign_(reg);
lv->set_signed(reg->get_signed());
return lv;
}
@ -687,20 +691,24 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
unsigned long lwid;
bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
ivl_assert(*this, rcl);
cerr << get_fileline() << ": warning: L-value packed array "
<< "select of " << reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
if (warn_ob_select) {
cerr << get_fileline()
<< ": warning: L-value packed array select of "
<< reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
}
lv->set_part(new NetEConst(verinum(verinum::Vx)), lwid);
return true;
// The index is undefined and this is a bit select.
} else {
cerr << get_fileline() << ": warning: L-value bit select of "
<< reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
if (warn_ob_select) {
cerr << get_fileline()
<< ": warning: L-value bit select of "
<< reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
}
lv->set_part(new NetEConst(verinum(verinum::Vx)), 1);
return true;
}
@ -797,12 +805,10 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
// Constant bit select that does something useful.
long loff = reg->sb_to_idx(prefix_indices,lsb);
if (loff < 0 || loff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": error: bit select "
if (warn_ob_select && (loff < 0 || loff >= (long)reg->vector_width())) {
cerr << get_fileline() << ": warning: bit select "
<< reg->name() << "[" <<lsb<<"]"
<< " is out of range." << endl;
des->errors += 1;
return 0;
}
if (reg->type()==NetNet::UNRESOLVED_WIRE) {
@ -868,10 +874,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
ivl_assert(*this, reg);
if (! parts_defined_flag) {
cerr << get_fileline() << ": warning: L-value part select of "
<< reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
if (warn_ob_select) {
cerr << get_fileline()
<< ": warning: L-value part select of "
<< reg->name();
if (reg->unpacked_dimensions() > 0) cerr << "[]";
cerr << " has an undefined index." << endl;
}
// Use a width of two here so we can distinguish between an
// undefined bit or part select.
lv->set_part(new NetEConst(verinum(verinum::Vx)), 2);
@ -934,11 +943,11 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
}
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
variable, then output a warning. Note that loff is
converted to normalized form so is relative the
variable pins. */
if (loff < 0 || moff >= (long)reg->vector_width()) {
if (warn_ob_select && (loff < 0 || moff >= (long)reg->vector_width())) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;

View File

@ -328,39 +328,66 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
return false;
}
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_fileline() << ": : Did you mean "
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
long tmp = midx_tmp;
midx_tmp = lidx_tmp;
lidx_tmp = tmp;
des->errors += 1;
}
if (prefix_indices.size()+1 < sig->packed_dims().size()) {
// Here we have a slice that doesn't have enough indices
// to get to a single slice. For example:
// wire [9:0][5:1] foo
// ... foo[4:3] ...
// Make this work by finding the indexed slices and
// creating a generated slice that spans the whole
// range.
long loff, moff;
unsigned long lwid, mwid;
bool lrc;
lrc = sig->sb_to_slice(prefix_indices, lsb, loff, lwid);
ivl_assert(*this, lrc);
lrc = sig->sb_to_slice(prefix_indices, msb, moff, mwid);
ivl_assert(*this, lrc);
ivl_assert(*this, lwid == mwid);
/* Warn about a part select that is out of range. */
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select "
<< sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
if (moff > loff) {
lidx = loff;
midx = moff + mwid - 1;
} else {
lidx = moff;
midx = loff + lwid - 1;
}
cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl;
}
/* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
return false;
}
} else {
long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
midx = midx_tmp;
lidx = lidx_tmp;
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_fileline() << ": : Did you mean "
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
long tmp = midx_tmp;
midx_tmp = lidx_tmp;
lidx_tmp = tmp;
des->errors += 1;
}
/* Warn about a part select that is out of range. */
if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
cerr << get_fileline() << ": warning: Part select "
<< sig->name();
if (sig->unpacked_dimensions() > 0) {
cerr << "[]";
}
cerr << "[" << msb << ":" << lsb
<< "] is out of range." << endl;
}
/* This is completely out side the signal so just skip it. */
if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) {
return false;
}
midx = midx_tmp;
lidx = lidx_tmp;
}
break;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -54,6 +54,15 @@
# include <cassert>
# include "ivl_assert.h"
void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope)
{
scope->time_unit(pscope->time_unit);
scope->time_precision(pscope->time_precision);
scope->time_from_timescale(pscope->time_from_timescale);
des->set_precision(pscope->time_precision);
}
typedef map<perm_string,LexicalScope::param_expr_t>::const_iterator mparm_it_t;
static void collect_parm_item_(Design*des, NetScope*scope, perm_string name,
@ -523,6 +532,7 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
class_scope->set_class_def(use_class);
use_class->set_class_scope(class_scope);
use_class->set_definition_scope(scope);
set_scope_timescale(des, class_scope, pclass);
// Collect the properties, elaborate them, and add them to the
// elaborated class definition.
@ -654,8 +664,10 @@ static void elaborate_scope_task(Design*des, NetScope*scope, PTask*task)
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);
if (scope==0)
if (scope==0) {
set_scope_timescale(des, task_scope, task);
des->add_root_task(task_scope, task);
}
if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_task: "
@ -719,8 +731,10 @@ static void elaborate_scope_func(Design*des, NetScope*scope, PFunction*task)
task_scope->is_auto(task->is_auto());
task_scope->set_line(task);
if (scope==0)
if (scope==0) {
set_scope_timescale(des, task_scope, task);
des->add_root_task(task_scope, task);
}
if (debug_scopes) {
cerr << task->get_fileline() << ": elaborate_scope_func: "
@ -1750,11 +1764,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
instances[idx] = my_scope;
// 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);
set_scope_timescale(des, my_scope, mod);
// Look for module parameter replacements. The "replace" map
// maps parameter name to replacement expression that is

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -1185,6 +1185,14 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
NetLogic*pull = 0;
if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Generate a SUPPLY pull for the ";
if (wtype == NetNet::SUPPLY0) cerr << "supply0";
else cerr << "supply1";
cerr << " net." << endl;
}
NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1)
? NetLogic::PULLUP
: NetLogic::PULLDOWN;
@ -1195,14 +1203,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
pull->pin(0).drive1(IVL_DR_SUPPLY);
des->add_node(pull);
wtype = NetNet::WIRE;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: "
<< "Generate a SUPPLY pull for the ";
if (wtype == NetNet::SUPPLY0) cerr << "supply0";
else cerr << "supply1";
cerr << " net." << endl;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2016 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
@ -17,11 +17,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "PExpr.h"
# include "pform_types.h"
# include "netlist.h"
# include "netclass.h"
# include "netdarray.h"
# include "netenum.h"
# include "netqueue.h"
# include "netparray.h"
# include "netscalar.h"
# include "netstruct.h"
@ -245,6 +247,16 @@ ivl_type_s* uarray_type_t::elaborate_type_raw(Design*des, NetScope*scope) const
return res;
}
// Special case: if the dimension is null:nil. this is a queue.
if (cur->second==0 && dynamic_cast<PENull*>(cur->first)) {
cerr << get_fileline() << ": sorry: "
<< "SV queues inside classes are not yet supported." << endl;
des->errors += 1;
ivl_type_s*res = new netqueue_t(btype);
return res;
}
vector<netrange_t> dimensions;
bool bad_range = evaluate_ranges(des, scope, dimensions, *dims);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -36,6 +36,7 @@
# include "PEvent.h"
# include "PGenerate.h"
# include "PPackage.h"
# include "PScope.h"
# include "PSpec.h"
# include "netlist.h"
# include "netenum.h"
@ -50,6 +51,9 @@
# include "ivl_assert.h"
// Implemented in elab_scope.cc
extern void set_scope_timescale(Design*des, NetScope*scope, PScope*pscope);
void PGate::elaborate(Design*, NetScope*) const
{
cerr << "internal error: what kind of gate? " <<
@ -787,7 +791,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
if (check_delay_count(des)) return;
NetExpr* rise_time, *fall_time, *decay_time;
eval_delays(des, scope, rise_time, fall_time, decay_time);
eval_delays(des, scope, rise_time, fall_time, decay_time, true);
struct attrib_list_t*attrib_list;
unsigned attrib_list_n = 0;
@ -1421,6 +1425,16 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
<< prts[0]->name() << " is coerced to inout." << endl;
}
if (!prts.empty() && (prts[0]->port_type() == NetNet::POUTPUT)
&& (prts[0]->type() != NetNet::REG)
&& prts[0]->pin(0).nexus()->has_floating_input()
&& pins[idx]->is_collapsible_net(des, scope)) {
prts[0]->port_type(NetNet::PINOUT);
cerr << pins[idx]->get_fileline() << ": warning: output port "
<< prts[0]->name() << " is coerced to inout." << endl;
}
// Elaborate the expression that connects to the
// module[s] port. sig is the thing outside the module
// that connects to the port.
@ -2000,7 +2014,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
PDelays tmp_del;
tmp_del.set_delays(overrides_, false);
tmp_del.eval_delays(des, scope, rise_expr, fall_expr,
decay_expr);
decay_expr, true);
}
}
@ -2325,7 +2339,8 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width) const
unsigned lv_width,
bool force_unsigned) const
{
ivl_assert(*this, rval_);
@ -2334,7 +2349,7 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
// should look into fixing calls to this method to pass a
// net_type instead of the separate lv_width/lv_type values.
NetExpr*rv = elaborate_rval_expr(des, scope, lv_net_type, lv_type, lv_width,
rval(), is_constant_);
rval(), is_constant_, force_unsigned);
if (!is_constant_ || !rv) return rv;
@ -2452,10 +2467,35 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0;
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(), count_lval_width(lv));
// Compressed assignments should behave identically to the
// equivalent uncompressed assignments. This means we need
// to take the type of the LHS into account when determining
// the type of the RHS expression.
bool force_unsigned;
switch (op_) {
case 'l':
case 'r':
case 'R':
// The right-hand operand of shift operations is
// self-determined.
force_unsigned = false;
break;
default:
force_unsigned = !lv->get_signed();
break;
}
NetExpr*rv = elaborate_rval_(des, scope, 0, lv->expr_type(),
count_lval_width(lv), force_unsigned);
if (rv == 0) return 0;
NetAssign*cur = new NetAssign(lv, op_, rv);
// The ivl_target API doesn't support signalling the type
// of a lval, so convert arithmetic shifts into logical
// shifts now if the lval is unsigned.
char op = op_;
if ((op == 'R') && !lv->get_signed())
op = 'r';
NetAssign*cur = new NetAssign(lv, op, rv);
cur->set_line(*this);
return cur;
@ -2868,14 +2908,27 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return 0;
}
assert(nscope);
elaborate_behaviors_(des, nscope);
}
NetBlock*cur = new NetBlock(type, nscope);
if (nscope) {
// Handle any variable initialization statements in this scope.
// For automatic scopes these statements need to be executed
// each time the block is entered, so add them to the main
// block. For static scopes, put them in a separate process
// that will be executed at the start of simulation.
if (nscope->is_auto()) {
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
NetProc*tmp = var_inits[idx]->elaborate(des, nscope);
if (tmp) cur->append(tmp);
}
} else {
elaborate_var_inits_(des, nscope);
}
}
if (nscope == 0)
nscope = scope;
@ -3778,7 +3831,9 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
expression that can be a target to a procedural
assignment, including a memory word. */
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
size_t parms_idx = use_this? idx-1 : idx;
NetNet*port = def->port(idx);
@ -3794,12 +3849,12 @@ NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
message. Note that the elaborate_lval method already
printed a detailed message for the latter case. */
NetAssign_*lv = 0;
if (idx < parms_.size() && parms_[idx]) {
lv = parms_[idx]->elaborate_lval(des, scope, false, false);
if (parms_idx < parms_.size() && parms_[parms_idx]) {
lv = parms_[parms_idx]->elaborate_lval(des, scope, false, false);
if (lv == 0) {
cerr << parms_[idx]->get_fileline() << ": error: "
cerr << parms_[parms_idx]->get_fileline() << ": error: "
<< "I give up on task port " << (idx+1)
<< " expression: " << *parms_[idx] << endl;
<< " expression: " << *parms_[parms_idx] << endl;
}
} else if (port->port_type() == NetNet::POUTPUT) {
// Output ports were skipped earlier, so
@ -4997,7 +5052,6 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
des->errors += 1;
return;
}
assert(def);
ivl_assert(*this, statement_);
@ -5010,6 +5064,31 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
return;
}
// Handle any variable initialization statements in this scope.
// For automatic functions, these statements need to be executed
// each time the function is called, so insert them at the start
// of the elaborated definition. For static functions, put them
// in a separate process that will be executed before the start
// of simulation.
if (is_auto_) {
// Get the NetBlock of the statement. If it is not a
// NetBlock then create one to wrap the initialization
// statements and the original statement.
NetBlock*blk = dynamic_cast<NetBlock*> (st);
if ((blk == 0) && (var_inits.size() > 0)) {
blk = new NetBlock(NetBlock::SEQU, scope);
blk->set_line(*this);
blk->append(st);
st = blk;
}
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
NetProc*tmp = var_inits[idx-1]->elaborate(des, scope);
if (tmp) blk->prepend(tmp);
}
} else {
elaborate_var_inits_(des, scope);
}
def->set_proc(st);
}
@ -5172,11 +5251,6 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
void PTask::elaborate(Design*des, NetScope*task) const
{
// Elaborate any processes that are part of this scope that
// aren't the definition itself. This can happen, for example,
// with variable initialization statements in this scope.
elaborate_behaviors_(des, task);
NetTaskDef*def = task->task_def();
assert(def);
@ -5195,6 +5269,31 @@ void PTask::elaborate(Design*des, NetScope*task) const
}
}
// Handle any variable initialization statements in this scope.
// For automatic tasks , these statements need to be executed
// each time the task is called, so insert them at the start
// of the elaborated definition. For static tasks, put them
// in a separate process that will be executed before the start
// of simulation.
if (is_auto_) {
// Get the NetBlock of the statement. If it is not a
// NetBlock then create one to wrap the initialization
// statements and the original statement.
NetBlock*blk = dynamic_cast<NetBlock*> (st);
if ((blk == 0) && (var_inits.size() > 0)) {
blk = new NetBlock(NetBlock::SEQU, task);
blk->set_line(*this);
blk->append(st);
st = blk;
}
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
NetProc*tmp = var_inits[idx-1]->elaborate(des, task);
if (tmp) blk->prepend(tmp);
}
} else {
elaborate_var_inits_(des, task);
}
def->set_proc(st);
}
@ -5651,6 +5750,10 @@ bool Module::elaborate(Design*des, NetScope*scope) const
(*gt)->elaborate(des, scope);
}
// Elaborate the variable initialization statements, making a
// single initial process out of them.
result_flag &= elaborate_var_inits_(des, scope);
// Elaborate the behaviors, making processes out of them. This
// involves scanning the PProcess* list, creating a NetProcTop
// for each process.
@ -5841,6 +5944,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; ++ cur )
(*cur)->elaborate(des, scope);
elaborate_var_inits_(des, scope);
typedef list<PProcess*>::const_iterator proc_it_t;
for (proc_it_t cur = behaviors.begin(); cur != behaviors.end(); ++ cur )
(*cur)->elaborate(des, scope);
@ -5876,6 +5981,44 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const
return result_flag;
}
bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const
{
if (var_inits.size() == 0)
return true;
NetProc*proc = 0;
if (var_inits.size() == 1) {
proc = var_inits[0]->elaborate(des, scope);
} else {
NetBlock*blk = new NetBlock(NetBlock::SEQU, 0);
bool flag = true;
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
NetProc*tmp = var_inits[idx]->elaborate(des, scope);
if (tmp)
blk->append(tmp);
else
flag = false;
}
if (flag) proc = blk;
}
if (proc == 0)
return false;
NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc);
if (const LineInfo*li = dynamic_cast<const LineInfo*>(this)) {
top->set_line(*li);
}
if (gn_system_verilog()) {
top->attribute(perm_string::literal("_ivl_schedule_init"),
verinum(1));
}
des->add_process(top);
scope->set_var_init(proc);
return true;
}
class elaborate_package_t : public elaborator_work_item_t {
public:
elaborate_package_t(Design*d, NetScope*scope, PPackage*p)
@ -6109,6 +6252,7 @@ Design* elaborate(list<perm_string>roots)
ivl_assert(*pac->second, pac->first == pac->second->pscope_name());
NetScope*scope = des->make_package_scope(pac->first);
scope->set_line(pac->second);
set_scope_timescale(des, scope, pac->second);
elaborator_work_item_t*es = new elaborate_package_t(des, scope, pac->second);
des->elaboration_work_list.push_back(es);
@ -6145,11 +6289,7 @@ Design* elaborate(list<perm_string>roots)
// Collect some basic properties of this scope from the
// Module definition.
scope->set_line(rmod);
scope->time_unit(rmod->time_unit);
scope->time_precision(rmod->time_precision);
scope->time_from_timescale(rmod->time_from_timescale);
des->set_precision(rmod->time_precision);
set_scope_timescale(des, scope, rmod);
// Save this scope, along with its definition, in the
// "root_elems" list for later passes.

View File

@ -507,7 +507,6 @@ int Design::emit(struct target_t*tgt) const
for (map<NetScope*,PTaskFunc*>::const_iterator scope = root_tasks_.begin()
; scope != root_tasks_.end() ; ++ scope) {
scope->first->emit_scope(tgt);
scope->first->emit_defs(tgt);
}
// enumerate package scopes
@ -521,7 +520,6 @@ int Design::emit(struct target_t*tgt) const
const NetScope*use_scope = cur->second->class_scope();
cur->second->emit_scope(tgt);
tgt->class_type(use_scope, cur->second);
cur->second->emit_defs(tgt);
}
// enumerate root scopes
@ -548,6 +546,12 @@ int Design::emit(struct target_t*tgt) const
// emit task and function definitions
bool tasks_rc = true;
for (map<NetScope*,PTaskFunc*>::const_iterator scope = root_tasks_.begin()
; scope != root_tasks_.end() ; ++ scope)
tasks_rc &= scope->first->emit_defs(tgt);
for (map<perm_string,netclass_t*>::const_iterator cur = classes_.begin()
; cur != classes_.end() ; ++cur)
tasks_rc &= cur->second->emit_defs(tgt);
for (map<perm_string,NetScope*>::const_iterator scope = packages_.begin()
; scope != packages_.end() ; ++ scope )
tasks_rc &= scope->second->emit_defs(tgt);

View File

@ -1,7 +1,7 @@
%option prefix="yy"
%{
/*
* Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2016 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
@ -148,18 +148,38 @@ static void ifdef_leave(void)
free(cur);
}
#define YY_INPUT(buf,result,max_size) do { \
if (istack->file) { \
size_t rc = fread(buf, 1, max_size, istack->file); \
result = (rc == 0) ? YY_NULL : rc; \
} else { \
if (*istack->str == 0) \
result = YY_NULL; \
else { \
buf[0] = *istack->str++; \
result = 1; \
} \
} \
#define YY_INPUT(buf,result,max_size) do { \
if (istack->file) { \
size_t rc = fread(buf, 1, max_size, istack->file); \
result = (rc == 0) ? YY_NULL : rc; \
} else { \
/* We are expanding a macro. Handle the SV macro escape \
sequences. There doesn't seem to be any good reason \
not to allow them in traditional Verilog as well. */ \
while ((istack->str[0] == '`') && \
(istack->str[1] == '`')) { \
istack->str += 2; \
} \
if (*istack->str == 0) { \
result = YY_NULL; \
} else if ((istack->str[0] == '`') && \
(istack->str[1] == '"')) { \
istack->str += 2; \
buf[0] = '"'; \
result = 1; \
} else if ((istack->str[0] == '`') && \
(istack->str[1] == '\\')&& \
(istack->str[2] == '`') && \
(istack->str[3] == '"')) { \
istack->str += 4; \
buf[0] = '\\'; \
buf[1] = '"'; \
result = 2; \
} else { \
buf[0] = *istack->str++; \
result = 1; \
} \
} \
} while (0)
static int comment_enter = 0;
@ -242,12 +262,6 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
if (macro_needs_args(yytext+1)) yy_push_state(MA_START); else do_expand(0);
}
/* `" overrides the usual lexical meaning of " and `\`" indicates
that the expansion should include the escape sequence \".
*/
`\" { fputc('"', yyout); }
`\\`\" { fprintf(yyout, "\\\""); }
/* Strings do not contain preprocessor directives, but can expand
* macros. If that happens, they get expanded in the context of the
* string.
@ -514,29 +528,19 @@ keywords (include|define|undef|ifdef|ifndef|else|elseif|endif)
do_expand(0);
}
/* Stringified version of macro expansion. If the sequence `` is
* encountered inside a macro definition, we use the SystemVerilog
* handling of ignoring it so that identifiers can be constructed
* from arguments. If istack->file is NULL, we are reading text
* produced from a macro, so use SystemVerilog's handling;
* otherwise, use the special Icarus handling.
*/
/* Stringified version of macro expansion. This is an Icarus extension.
When expanding macro text, the SV usage of `` takes precedence. */
``[a-zA-Z_][a-zA-Z0-9_$]* {
if (istack->file == NULL)
fprintf(yyout, "%s", yytext+2);
else {
assert(do_expand_stringify_flag == 0);
do_expand_stringify_flag = 1;
fputc('"', yyout);
if (macro_needs_args(yytext+2))
yy_push_state(MA_START);
else
do_expand(0);
}
assert(istack->file);
assert(do_expand_stringify_flag == 0);
do_expand_stringify_flag = 1;
fputc('"', yyout);
if (macro_needs_args(yytext+2))
yy_push_state(MA_START);
else
do_expand(0);
}
`` { if (istack->file != NULL) ECHO; }
<MA_START>\( { BEGIN(MA_ADD); macro_start_args(); }
<MA_START>{W} {}

View File

@ -453,7 +453,7 @@ TU [munpf]
return BASED_NUMBER;
}
\'[01xzXZ] {
if (generation_flag < GN_VER2005_SV) {
if (!gn_system_verilog()) {
cerr << yylloc.text << ":" << yylloc.first_line << ": warning: "
<< "Using SystemVerilog 'N bit vector. Use at least "
<< "-g2005-sv to remove this warning." << endl;
@ -479,7 +479,7 @@ TU [munpf]
/* This rule handles scaled time values for SystemVerilog. */
[0-9][0-9_]*(\.[0-9][0-9_]*)?{TU}?s {
if(generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) {
if (gn_system_verilog()) {
yylval.text = strdupnew(yytext);
return TIME_LITERAL;
} else REJECT; }
@ -857,7 +857,7 @@ verinum*make_unsized_binary(const char*txt)
ptr += 1;
}
assert((tolower(*ptr) == 'b') || (generation_flag >= GN_VER2005_SV));
assert((tolower(*ptr) == 'b') || gn_system_verilog());
if (tolower(*ptr) == 'b') {
ptr += 1;
} else {

View File

@ -108,6 +108,7 @@ bool gn_assertions_flag = true;
bool gn_io_range_error_flag = true;
bool gn_strict_ca_eval_flag = false;
bool gn_strict_expr_width_flag = false;
bool gn_shared_loop_index_flag = false;
bool gn_verilog_ams_flag = false;
/*
@ -344,6 +345,12 @@ static void process_generation_flag(const char*gen)
} else if (strcmp(gen,"no-strict-expr-width") == 0) {
gn_strict_expr_width_flag = false;
} else if (strcmp(gen,"shared-loop-index") == 0) {
gn_shared_loop_index_flag = true;
} else if (strcmp(gen,"no-shared-loop-index") == 0) {
gn_shared_loop_index_flag = false;
} else {
}
}
@ -1111,7 +1118,7 @@ int main(int argc, char*argv[])
/* Decide if we are going to allow system functions to be called
* as tasks. */
if (generation_flag >= GN_VER2005_SV) {
if (gn_system_verilog()) {
def_sfunc_as_task = IVL_SFUNC_AS_TASK_WARNING;
}

View File

@ -43,6 +43,8 @@ NetAssign_::NetAssign_(NetAssign_*n)
: nest_(n), sig_(0), word_(0), base_(0), sel_type_(IVL_SEL_OTHER)
{
more = 0;
signed_ = false;
turn_sig_to_wire_on_release_ = false;
}
NetAssign_::NetAssign_(NetNet*s)
@ -51,6 +53,7 @@ NetAssign_::NetAssign_(NetNet*s)
lwid_ = sig_->vector_width();
sig_->incr_lref();
more = 0;
signed_ = false;
turn_sig_to_wire_on_release_ = false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2016 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
@ -88,6 +88,10 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
// fills in the context_map with local variables held by the scope.
scope()->evaluate_function_find_locals(loc, context_map);
// Execute any variable initialization statements.
if (const NetProc*init_proc = scope()->var_init())
init_proc->evaluate_function(loc, context_map);
if (debug_eval_tree && proc_==0) {
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Function " << scope_path(scope())
@ -209,6 +213,98 @@ bool NetProc::evaluate_function(const LineInfo&,
return false;
}
void NetAssign::eval_func_lval_op_real_(const LineInfo&loc,
verireal&lv, verireal&rv) const
{
switch (op_) {
case '+':
lv = lv + rv;
break;
case '-':
lv = lv - rv;
break;
case '*':
lv = lv * rv;
break;
case '/':
lv = lv / rv;
break;
case '%':
lv = lv % rv;
break;
default:
cerr << "Illegal assignment operator: "
<< human_readable_op(op_) << endl;
ivl_assert(loc, 0);
}
}
void NetAssign::eval_func_lval_op_(const LineInfo&loc,
verinum&lv, verinum&rv) const
{
unsigned lv_width = lv.len();
bool lv_sign = lv.has_sign();
switch (op_) {
case 'l':
case 'R':
// The left operand is self-determined.
break;
case 'r':
// The left operand is self-determined, but we need to
// cast it to unsigned to get a logical shift.
lv.has_sign(false);
break;
default:
// The left operand must be cast to the expression type/size
lv.has_sign(rv.has_sign());
lv = cast_to_width(lv, rv.len());
}
switch (op_) {
case '+':
lv = lv + rv;
break;
case '-':
lv = lv - rv;
break;
case '*':
lv = lv * rv;
break;
case '/':
lv = lv / rv;
break;
case '%':
lv = lv % rv;
break;
case '&':
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
lv.set(idx, lv[idx] & rv[idx]);
break;
case '|':
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
lv.set(idx, lv[idx] | rv[idx]);
break;
case '^':
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
lv.set(idx, lv[idx] ^ rv[idx]);
break;
case 'l':
lv = lv << rv.as_unsigned();
break;
case 'r':
lv = lv >> rv.as_unsigned();
break;
case 'R':
lv = lv >> rv.as_unsigned();
break;
default:
cerr << "Illegal assignment operator: "
<< human_readable_op(op_) << endl;
ivl_assert(loc, 0);
}
lv = cast_to_width(lv, lv_width);
lv.has_sign(lv_sign);
}
bool NetAssign::eval_func_lval_(const LineInfo&loc,
map<perm_string,LocalVar>&context_map,
const NetAssign_*lval, NetExpr*rval_result) const
@ -269,18 +365,55 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
ivl_assert(loc, base + lval->lwidth() <= old_lval->expr_width());
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
ivl_assert(loc, lval_const);
verinum lval_v = lval_const->value();
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
verinum rval_v = cast_to_width(rval_const->value(), lval->lwidth());
ivl_assert(loc, rval_const);
verinum rval_v = rval_const->value();
for (unsigned idx = 0 ; idx < rval_v.len() ; idx += 1)
lval_v.set(idx+base, rval_v[idx]);
verinum lpart(verinum::Vx, lval->lwidth());
if (op_) {
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
lpart.set(idx, lval_v[base+idx]);
eval_func_lval_op_(loc, lpart, rval_v);
} else {
lpart = cast_to_width(rval_v, lval->lwidth());
}
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
lval_v.set(idx+base, lpart[idx]);
delete base_result;
delete rval_result;
rval_result = new NetEConst(lval_v);
} else {
rval_result = fix_assign_value(lval->sig(), rval_result);
if (op_ == 0) {
rval_result = fix_assign_value(lval->sig(), rval_result);
} else if (dynamic_cast<NetECReal*>(rval_result)) {
NetECReal*lval_const = dynamic_cast<NetECReal*>(old_lval);
ivl_assert(loc, lval_const);
verireal lval_r = lval_const->value();
NetECReal*rval_const = dynamic_cast<NetECReal*>(rval_result);
ivl_assert(loc, rval_const);
verireal rval_r = rval_const->value();
eval_func_lval_op_real_(loc, lval_r, rval_r);
delete rval_result;
rval_result = new NetECReal(lval_r);
} else {
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
ivl_assert(loc, lval_const);
verinum lval_v = lval_const->value();
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
ivl_assert(loc, rval_const);
verinum rval_v = rval_const->value();
eval_func_lval_op_(loc, lval_v, rval_v);
delete rval_result;
rval_result = new NetEConst(lval_v);
}
}
if (old_lval)
@ -318,6 +451,13 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
ivl_assert(*this, rval_const);
if (op_) {
cerr << get_fileline() << ": sorry: Assignment operators "
"inside a constant function are not currently "
"supported if the LHS is a concatenation." << endl;
return false;
}
verinum rval_full = rval_const->value();
delete rval_result;
@ -369,6 +509,10 @@ bool NetBlock::evaluate_function(const LineInfo&loc,
// Now collect the new locals.
subscope_->evaluate_function_find_locals(loc, local_context_map);
use_local_context_map = true;
// Execute any variable initialization statements.
if (const NetProc*init_proc = subscope_->var_init())
init_proc->evaluate_function(loc, local_context_map);
}
// Now use the local context map if there is any local

View File

@ -311,6 +311,20 @@ void Nexus::count_io(unsigned&inp, unsigned&out) const
}
}
bool Nexus::has_floating_input() const
{
bool found_input = false;
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {
if (cur->get_dir() == Link::OUTPUT)
return false;
if (cur->get_dir() == Link::INPUT)
found_input = true;
}
return found_input;
}
bool Nexus::drivers_present() const
{
for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2016 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
@ -427,6 +427,15 @@ NexusSet* NetForLoop::nex_input(bool rem_out)
result->add(*tmp);
delete tmp;
if (gn_shared_loop_index_flag) {
tmp = new NexusSet();
for (unsigned idx = 0 ; idx < index_->pin_count() ; idx += 1)
tmp->add(index_->pin(idx).nexus(), 0, index_->vector_width());
result->rem(*tmp);
delete tmp;
}
return result;
}

View File

@ -56,6 +56,17 @@ void NetBlock::append(NetProc*cur)
}
}
void NetBlock::prepend(NetProc*cur)
{
if (last_ == 0) {
last_ = cur;
cur->next_ = cur;
} else {
cur->next_ = last_->next_;
last_->next_ = cur;
}
}
const NetProc* NetBlock::proc_first() const
{
if (last_ == 0)

View File

@ -139,6 +139,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
time_from_timescale_ = false;
}
var_init_ = 0;
switch (t) {
case NetScope::TASK:
task_ = 0;

View File

@ -557,7 +557,7 @@ void NetNet::calculate_slice_widths_from_packed_dims_(void)
ivl_assert(*this, ! slice_wids_.empty());
slice_wids_[0] = netrange_width(slice_dims_);
vector<netrange_t>::const_iterator cur = slice_dims_.begin();
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1) {
for (size_t idx = 1 ; idx < slice_wids_.size() ; idx += 1, cur++) {
slice_wids_[idx] = slice_wids_[idx-1] / cur->width();
}
}

View File

@ -388,6 +388,10 @@ class Nexus {
is a variable, but also if this is a net with a force. */
bool assign_lval() const;
/* This method returns true if there are any inputs
attached to this nexus but no drivers. */
bool has_floating_input() const;
/* This method returns true if there are any drivers
(including variables) attached to this nexus. */
bool drivers_present() const;
@ -713,7 +717,7 @@ class NetNet : public NetObj, public PortType {
/* This method returns a reference to the packed dimensions
for the vector. These are arranged as a list where the
first range in the list (front) is the left-most range in
the verilog declaration. These packed dims are compressed
the Verilog declaration. These packed dims are compressed
to represent the dimensions of all the subtypes. */
const std::vector<netrange_t>& packed_dims() const { return slice_dims_; }
@ -1020,6 +1024,13 @@ class NetScope : public Definitions, public Attrib {
TYPE type() const;
void print_type(ostream&) const;
// This provides a link to the variable initialisation process
// for use when evaluating a constant function. Note this is
// only used for static functions - the variable initialization
// for automatic functions is included in the function definition.
void set_var_init(const NetProc*proc) { var_init_ = proc; }
const NetProc* var_init() const { return var_init_; }
void set_task_def(NetTaskDef*);
void set_func_def(NetFuncDef*);
void set_class_def(netclass_t*);
@ -1250,6 +1261,8 @@ class NetScope : public Definitions, public Attrib {
vector<PortInfo> ports_;
const NetProc*var_init_;
union {
NetTaskDef*task_;
NetFuncDef*func_;
@ -2732,6 +2745,12 @@ class NetAssign_ {
void set_property(const perm_string&name);
inline perm_string get_property(void) const { return member_; }
// Determine if the assigned object is signed or unsigned.
// This is used when determining the expression type for
// a compressed assignment statement.
bool get_signed() const { return signed_; }
void set_signed(bool flag) { signed_ = flag; }
// Get the width of the r-value that this node expects. This
// method accounts for the presence of the mux, so it is not
// necessarily the same as the pin_count().
@ -2782,6 +2801,7 @@ class NetAssign_ {
// member/property if signal is a class.
perm_string member_;
bool signed_;
bool turn_sig_to_wire_on_release_;
// indexed part select base
NetExpr*base_;
@ -2849,6 +2869,8 @@ class NetAssign : public NetAssignBase {
map<perm_string,LocalVar>&ctx) const;
private:
void eval_func_lval_op_real_(const LineInfo&loc, verireal&lv, verireal&rv) const;
void eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const;
bool eval_func_lval_(const LineInfo&loc, map<perm_string,LocalVar>&ctx,
const NetAssign_*lval, NetExpr*rval_result) const;
@ -2895,6 +2917,7 @@ class NetBlock : public NetProc {
NetScope* subscope() const { return subscope_; }
void append(NetProc*);
void prepend(NetProc*);
const NetProc*proc_first() const;
const NetProc*proc_next(const NetProc*cur) const;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -203,7 +203,7 @@ static NetExpr* make_add_expr(NetExpr*expr, long val)
}
verinum val_v (val, expr->expr_width());
val_v.has_sign(true);
val_v.has_sign(expr->has_sign());
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
@ -236,7 +236,7 @@ static NetExpr* make_add_expr(const LineInfo*loc, NetExpr*expr1, NetExpr*expr2)
static NetExpr* make_sub_expr(long val, NetExpr*expr)
{
verinum val_v (val, expr->expr_width());
val_v.has_sign(true);
val_v.has_sign(expr->has_sign());
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
@ -249,7 +249,26 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
}
/*
* Multiple an existing expression by a signed positive number.
* Subtract a signed constant from an existing expression.
*/
static NetExpr* make_sub_expr(NetExpr*expr, long val)
{
verinum val_v (val, expr->expr_width());
val_v.has_sign(expr->has_sign());
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
NetEBAdd*res = new NetEBAdd('-', expr, val_c, expr->expr_width(),
expr->has_sign());
res->set_line(*expr);
return res;
}
/*
* Multiply an existing expression by a signed positive number.
* This does a lossless multiply, so the arguments will need to be
* sized to match the output size.
*/
@ -258,7 +277,7 @@ static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
const unsigned val_wid = ceil(log2((double)val)) ;
unsigned use_wid = expr->expr_width() + val_wid;
verinum val_v (val, use_wid);
val_v.has_sign(true);
val_v.has_sign(expr->has_sign());
NetEConst*val_c = new NetEConst(val_v);
val_c->set_line(*expr);
@ -434,17 +453,41 @@ NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
-- pcur;
}
long sb;
if (pcur->get_msb() >= pcur->get_lsb())
sb = pcur->get_lsb();
else
sb = pcur->get_msb();
long sb = min(pcur->get_lsb(), pcur->get_msb());
long loff;
reg->sb_to_slice(indices, sb, loff, lwid);
base = make_mult_expr(base, lwid);
base = make_add_expr(base, loff);
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();
base = pad_to_width(base, min_wid, *base);
if ((sb < 0) && !base->has_sign()) {
NetESelect *tmp = new NetESelect(base, 0 , min_wid);
tmp->set_line(*base);
tmp->cast_signed(true);
base = tmp;
}
if (pcur->get_msb() >= pcur->get_lsb()) {
if (pcur->get_lsb() != 0)
base = make_sub_expr(base, pcur->get_lsb());
base = make_mult_expr(base, lwid);
min_wid = base->expr_width();
if (min_wid < num_bits(loff)) min_wid = num_bits(loff);
if (loff != 0) min_wid += 1;
base = pad_to_width(base, min_wid, *base);
base = make_add_expr(base, loff);
} else {
if (pcur->get_msb() != 0)
base = make_sub_expr(base, pcur->get_msb());
base = make_mult_expr(base, lwid);
min_wid = base->expr_width();
if (min_wid < num_bits(loff)) min_wid = num_bits(loff);
if (loff != 0) min_wid += 1;
base = pad_to_width(base, min_wid, *base);
base = make_sub_expr(loff, base);
}
return base;
}
@ -802,9 +845,10 @@ NetExpr* condition_reduce(NetExpr*expr)
}
static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
int context_width, bool need_const, bool annotatable,
bool force_expand,
ivl_variable_type_t cast_type)
int context_width, bool need_const,
bool annotatable, bool force_expand,
ivl_variable_type_t cast_type,
bool force_unsigned)
{
PExpr::width_mode_t mode = PExpr::SIZED;
if ((context_width == -2) && !gn_strict_expr_width_flag)
@ -824,6 +868,11 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
if ((pe->expr_type() != IVL_VT_REAL) && (expr_width < pos_context_width))
expr_width = pos_context_width;
// If this is the RHS of a compressed assignment, the LHS also
// affects the expression type (signed/unsigned).
if (force_unsigned)
pe->cast_signed(false);
if (debug_elaborate) {
cerr << pe->get_fileline() << ": elab_and_eval: test_width of "
<< *pe << endl;
@ -910,15 +959,16 @@ static NetExpr* do_elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
int context_width, bool need_const, bool annotatable,
ivl_variable_type_t cast_type)
ivl_variable_type_t cast_type, bool force_unsigned)
{
return do_elab_and_eval(des, scope, pe, context_width,
need_const, annotatable, false, cast_type);
need_const, annotatable, false,
cast_type, force_unsigned);
}
/*
* This variant of elab_and_eval does the expression losslessly, no
* matter what the generation of verilog. This is in support of
* matter what the generation of Verilog. This is in support of
* certain special contexts, notably index expressions.
*/
NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
@ -926,7 +976,8 @@ NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope, PExpr*pe,
ivl_variable_type_t cast_type)
{
return do_elab_and_eval(des, scope, pe, context_width,
need_const, annotatable, true, cast_type);
need_const, annotatable, true,
cast_type, false);
}
NetExpr* elab_and_eval(Design*des, NetScope*scope, PExpr*pe,
@ -1404,7 +1455,7 @@ bool evaluate_index_prefix(Design*des, NetScope*scope,
return false;
}
prefix_indices .push_back(tmp);
prefix_indices.push_back(tmp);
delete texpr;
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_netmisc_H
#define IVL_netmisc_H
/*
* Copyright (c) 1999-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2016 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
@ -60,12 +60,32 @@ inline NetScope* symbol_search(const LineInfo*li,
}
/*
* This function transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
* This function transforms an expression by either zero or sign extending
* the high bits until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide enough.
* The extension method and the returned expression type is determined by
* signed_flag.
*/
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info);
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info);
/*
* This version determines the extension method from the base expression type.
*/
inline NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
{
return pad_to_width(expr, wid, expr->has_sign(), info);
}
/*
* This function transforms an expression by either zero or sign extending
* or discarding the high bits until the expression has the desired width.
* This may mean not transforming the expression at all, if it is already
* the correct width. The extension method (if needed) and the returned
* expression type is determined by signed_flag.
*/
extern NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info);
extern NetNet*pad_to_width(Design*des, NetNet*n, unsigned w,
const LineInfo&info);
@ -258,7 +278,8 @@ extern NetExpr* elab_and_eval(Design*des, NetScope*scope,
PExpr*pe, int context_width,
bool need_const =false,
bool annotatable =false,
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE);
ivl_variable_type_t cast_type =IVL_VT_NO_TYPE,
bool force_unsigned =false);
extern NetExpr* elab_and_eval_lossless(Design*des, NetScope*scope,
PExpr*pe, int context_width,
@ -297,7 +318,8 @@ extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope,
ivl_type_t lv_net_type,
ivl_variable_type_t lv_type,
unsigned lv_width, PExpr*expr,
bool need_const =false);
bool need_const =false,
bool force_unsigned =false);
extern bool evaluate_ranges(Design*des, NetScope*scope,
std::vector<netrange_t>&llist,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2016 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
@ -147,13 +147,12 @@ bool prefix_to_slice(const std::vector<netrange_t>&dims,
do {
-- icur;
acc_wid *= pcur->width();
-- pcur;
if (pcur->get_msb() >= pcur->get_lsb())
acc_off += (*icur - pcur->get_lsb()) * acc_wid;
else
acc_off += (pcur->get_lsb() - *icur) * acc_wid;
-- pcur;
} while (icur != prefix.begin());
// Got our final offset.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2016 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
@ -24,21 +24,20 @@
# include "netmisc.h"
/*
* This function transforms an expression by padding the high bits
* with V0 until the expression has the desired width. This may mean
* not transforming the expression at all, if it is already wide
* enough.
*/
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
NetExpr*pad_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info)
{
if (wid <= expr->expr_width())
if (wid <= expr->expr_width()) {
expr->cast_signed(signed_flag);
return expr;
}
/* If the expression is a const, then replace it with a wider
const. This is a more efficient result. */
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verinum oval = pad_to_width(tmp->value(), wid);
verinum oval = tmp->value();
oval.has_sign(signed_flag);
oval = pad_to_width(oval, wid);
tmp = new NetEConst(oval);
tmp->set_line(info);
delete expr;
@ -46,8 +45,30 @@ NetExpr*pad_to_width(NetExpr*expr, unsigned wid, const LineInfo&info)
}
NetESelect*tmp = new NetESelect(expr, 0, wid);
tmp->cast_signed(signed_flag);
tmp->set_line(info);
tmp->cast_signed(expr->has_sign());
return tmp;
}
NetExpr*cast_to_width(NetExpr*expr, unsigned wid, bool signed_flag,
const LineInfo&info)
{
/* If the expression is a const, then replace it with a new
const. This is a more efficient result. */
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
tmp->cast_signed(signed_flag);
if (wid != tmp->expr_width()) {
tmp = new NetEConst(verinum(tmp->value(), wid));
tmp->set_line(info);
delete expr;
}
return tmp;
}
NetESelect*tmp = new NetESelect(expr, 0, wid);
tmp->cast_signed(signed_flag);
tmp->set_line(info);
return tmp;
}

370
parse.y
View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -65,6 +65,10 @@ static PTask* current_task = 0;
static PFunction* current_function = 0;
static stack<PBlock*> current_block_stack;
/* The variable declaration rules need to know if a lifetime has been
specified. */
static LexicalScope::lifetime_t var_lifetime;
static pform_name_t* pform_create_this(void)
{
name_component_t name (perm_string::literal("@"));
@ -131,17 +135,17 @@ static list<named_pexpr_t>*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 list<pair<perm_string,PExpr*> >* make_port_list(char*id, PExpr*expr)
static list<pform_port_t>* make_port_list(char*id, list<pform_range_t>*udims, PExpr*expr)
{
list<pair<perm_string,PExpr*> >*tmp = new list<pair<perm_string,PExpr*> >;
tmp->push_back(make_pair(lex_strings.make(id), expr));
list<pform_port_t>*tmp = new list<pform_port_t>;
tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr));
delete[]id;
return tmp;
}
static list<pair<perm_string,PExpr*> >* make_port_list(list<pair<perm_string, PExpr*> >*tmp,
char*id, PExpr*expr)
static list<pform_port_t>* make_port_list(list<pform_port_t>*tmp,
char*id, list<pform_range_t>*udims, PExpr*expr)
{
tmp->push_back(make_pair(lex_strings.make(id), expr));
tmp->push_back(pform_port_t(lex_strings.make(id), udims, expr));
delete[]id;
return tmp;
}
@ -370,7 +374,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
char*text;
list<perm_string>*perm_strings;
list<pair<perm_string,PExpr*> >*port_list;
list<pform_port_t>*port_list;
vector<pform_tf_port_t>* tf_ports;
@ -452,6 +456,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
PSpecPath* specpath;
list<index_component_t> *dimensions;
LexicalScope::lifetime_t lifetime;
};
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL
@ -560,7 +566,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <number> number pos_neg_number
%type <flag> signing unsigned_signed_opt signed_unsigned_opt
%type <flag> import_export
%type <flag> K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt
%type <flag> K_packed_opt K_reg_opt K_static_opt K_virtual_opt
%type <flag> udp_reg_opt edge_operator
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym
@ -576,7 +582,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <text> register_variable net_variable event_variable endlabel_opt class_declaration_endlabel_opt
%type <perm_strings> register_variable_list net_variable_list event_variable_list
%type <perm_strings> list_of_identifiers loop_variables
%type <port_list> list_of_port_identifiers
%type <port_list> list_of_port_identifiers list_of_variable_port_identifiers
%type <net_decl_assign> net_decl_assign net_decl_assigns
@ -607,7 +613,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <gates> gate_instance_list
%type <pform_name> hierarchy_identifier implicit_class_handle
%type <expr> assignment_pattern expression expr_primary expr_mintypmax
%type <expr> assignment_pattern expression expr_mintypmax
%type <expr> expr_primary_or_typename expr_primary
%type <expr> class_new dynamic_array_new
%type <expr> inc_or_dec_expression inside_expression lpvalue
%type <expr> branch_probe_expression streaming_concatenation
@ -635,7 +642,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <ranges> variable_dimension
%type <ranges> dimensions_opt dimensions
%type <nettype> net_type var_type net_type_opt
%type <nettype> net_type net_type_opt
%type <gatetype> gatetype switchtype
%type <porttype> port_direction port_direction_opt
%type <vartype> bit_logic bit_logic_opt
@ -664,6 +671,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <int_val> atom2_type
%type <int_val> module_start module_end
%type <lifetime> lifetime lifetime_opt
%token K_TAND
%right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ
%right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ
@ -723,17 +732,17 @@ block_identifier_opt /* */
;
class_declaration /* IEEE1800-2005: A.1.2 */
: K_virtual_opt K_class class_identifier class_declaration_extends_opt ';'
{ pform_start_class_declaration(@2, $3, $4.type, $4.exprs); }
: K_virtual_opt K_class lifetime_opt class_identifier class_declaration_extends_opt ';'
{ pform_start_class_declaration(@2, $4, $5.type, $5.exprs, $3); }
class_items_opt K_endclass
{ // Process a class.
pform_end_class_declaration(@8);
pform_end_class_declaration(@9);
}
class_declaration_endlabel_opt
{ // Wrap up the class.
if ($10 && $3 && $3->name != $10) {
yyerror(@10, "error: Class end label doesn't match class name.");
delete[]$10;
if ($11 && $4 && $4->name != $11) {
yyerror(@11, "error: Class end label doesn't match class name.");
delete[]$11;
}
}
;
@ -1193,7 +1202,7 @@ for_step /* IEEE1800-2005: A.6.8 */
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 K_automatic_opt data_type_or_implicit_or_void IDENTIFIER ';'
: K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER ';'
{ assert(current_function == 0);
current_function = pform_push_function_scope(@1, $4, $2);
}
@ -1214,7 +1223,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
"function name");
}
if (! gn_system_verilog()) {
yyerror(@11, "error: Function end label require "
yyerror(@11, "error: Function end labels require "
"SystemVerilog.");
}
delete[]$11;
@ -1222,7 +1231,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
delete[]$4;
}
| K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER
| K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER
{ assert(current_function == 0);
current_function = pform_push_function_scope(@1, $4, $2);
}
@ -1258,7 +1267,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */
/* Detect and recover from some errors. */
| K_function K_automatic_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction
| K_function lifetime_opt data_type_or_implicit_or_void IDENTIFIER error K_endfunction
{ /* */
if (current_function) {
pform_pop_scope();
@ -1364,6 +1373,16 @@ jump_statement /* IEEE1800-2005: A.6.5 */
}
;
lifetime /* IEEE1800-2005: A.2.1.3 */
: K_automatic { $$ = LexicalScope::AUTOMATIC; }
| K_static { $$ = LexicalScope::STATIC; }
;
lifetime_opt /* IEEE1800-2005: A.2.1.3 */
: lifetime { $$ = $1; }
| { $$ = LexicalScope::INHERITED; }
;
/* Loop statements are kinds of statements. */
loop_statement /* IEEE1800-2005: A.6.8 */
@ -1703,20 +1722,20 @@ open_range_list /* IEEE1800-2005 A.2.11 */
;
package_declaration /* IEEE1800-2005 A.1.2 */
: K_package IDENTIFIER ';'
{ pform_start_package_declaration(@1, $2);
: K_package lifetime_opt IDENTIFIER ';'
{ pform_start_package_declaration(@1, $3, $2);
}
package_item_list_opt
K_endpackage endlabel_opt
{ pform_end_package_declaration(@1);
// If an end label is present make sure it match the package name.
if ($7) {
if (strcmp($2,$7) != 0) {
yyerror(@7, "error: End label doesn't match package name");
if ($8) {
if (strcmp($3,$8) != 0) {
yyerror(@8, "error: End label doesn't match package name");
}
delete[]$7;
delete[]$8;
}
delete[]$2;
delete[]$3;
}
;
@ -1895,7 +1914,7 @@ streaming_concatenation /* IEEE1800-2005: A.8.1 */
task_declaration /* IEEE1800-2005: A.2.7 */
: K_task K_automatic_opt IDENTIFIER ';'
: K_task lifetime_opt IDENTIFIER ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -1908,7 +1927,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
pform_pop_scope();
current_task = 0;
if ($7 && $7->size() > 1 && !gn_system_verilog()) {
yyerror(@7, "error: Task body with multiple statements requres SystemVerilog.");
yyerror(@7, "error: Task body with multiple statements requires SystemVerilog.");
}
delete $7;
}
@ -1931,7 +1950,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
delete[]$3;
}
| K_task K_automatic_opt IDENTIFIER '('
| K_task lifetime_opt IDENTIFIER '('
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -1965,7 +1984,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
delete[]$3;
}
| K_task K_automatic_opt IDENTIFIER '(' ')' ';'
| K_task lifetime_opt IDENTIFIER '(' ')' ';'
{ assert(current_task == 0);
current_task = pform_push_task_scope(@1, $3, $2);
}
@ -1982,7 +2001,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
pform_pop_scope();
current_task = 0;
if ($9->size() > 1 && !gn_system_verilog()) {
yyerror(@9, "error: Task body with multiple statements requres SystemVerilog.");
yyerror(@9, "error: Task body with multiple statements requires SystemVerilog.");
}
delete $9;
}
@ -2005,7 +2024,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
delete[]$3;
}
| K_task K_automatic_opt IDENTIFIER error K_endtask
| K_task lifetime_opt IDENTIFIER error K_endtask
{
assert(current_task == 0);
}
@ -2213,7 +2232,7 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
}
| '[' expression ']'
{ // SystemVerilog canonical range
if (generation_flag < GN_VER2005_SV) {
if (!gn_system_verilog()) {
warn_count += 1;
cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. "
<< "Use at least -g2005-sv to remove this warning." << endl;
@ -2243,6 +2262,19 @@ variable_dimension /* IEEE1800-2005: A.2.5 */
}
;
variable_lifetime
: lifetime
{ if (!gn_system_verilog()) {
yyerror(@1, "error: overriding the default variable lifetime "
"requires SystemVerilog.");
} else if ($1 != pform_peek_scope()->default_lifetime) {
yyerror(@1, "sorry: overriding the default variable lifetime "
"is not yet supported.");
}
var_lifetime = $1;
}
;
/* Verilog-2001 supports attribute lists, which can be attached to a
variety of different objects. The syntax inside the (* *) is a
comma separated list of names or names with assigned values. */
@ -2317,10 +2349,20 @@ block_item_decl
{ if ($1) pform_set_data_type(@1, $1, $2, NetNet::REG, attributes_in_context);
}
| variable_lifetime data_type register_variable_list ';'
{ if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context);
var_lifetime = LexicalScope::INHERITED;
}
| K_reg data_type register_variable_list ';'
{ if ($2) pform_set_data_type(@2, $2, $3, NetNet::REG, attributes_in_context);
}
| variable_lifetime K_reg data_type register_variable_list ';'
{ if ($3) pform_set_data_type(@3, $3, $4, NetNet::REG, attributes_in_context);
var_lifetime = LexicalScope::INHERITED;
}
| K_event event_variable_list ';'
{ if ($2) pform_make_events($2, @1.text, @1.first_line);
}
@ -3033,7 +3075,7 @@ branch_probe_expression
;
expression
: expr_primary
: expr_primary_or_typename
{ $$ = $1; }
| inc_or_dec_expression
{ $$ = $1; }
@ -3328,6 +3370,20 @@ expression_list_proper
}
;
expr_primary_or_typename
: expr_primary
/* There are a few special cases (notably $bits argument) where the
expression may be a type name. Let the elaborator sort this out. */
| TYPE_IDENTIFIER
{ PETypename*tmp = new PETypename($1.type);
FILE_NAME(tmp,@1);
$$ = tmp;
delete[]$1.text;
}
;
expr_primary
: number
{ assert($1);
@ -3369,15 +3425,6 @@ expr_primary
delete[]$1;
}
/* There are a few special cases (notably $bits argument) where the
expression may be a type name. Let the elaborator sort this out. */
| TYPE_IDENTIFIER
{ PETypename*tmp = new PETypename($1.type);
FILE_NAME(tmp,@1);
$$ = tmp;
delete[]$1.text;
}
/* The hierarchy_identifier rule matches simple identifiers as well as
indexed arrays and part selects */
@ -3681,12 +3728,11 @@ expr_primary
/* Cast expressions are primaries */
| DEC_NUMBER '\'' '(' expression ')'
| expr_primary '\'' '(' expression ')'
{ PExpr*base = $4;
if (gn_system_verilog()) {
PECastSize*tmp = new PECastSize($1->as_ulong(), base);
PECastSize*tmp = new PECastSize($1, base);
FILE_NAME(tmp, @1);
delete $1;
$$ = tmp;
} else {
yyerror(@1, "error: Size cast requires SystemVerilog.");
@ -4002,14 +4048,21 @@ list_of_identifiers
;
list_of_port_identifiers
: IDENTIFIER
{ $$ = make_port_list($1, 0); }
| IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3); }
| list_of_port_identifiers ',' IDENTIFIER
{ $$ = make_port_list($1, $3, 0); }
| list_of_port_identifiers ',' IDENTIFIER '=' expression
{ $$ = make_port_list($1, $3, $5); }
: IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $2, 0); }
| list_of_port_identifiers ',' IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $3, $4, 0); }
;
list_of_variable_port_identifiers
: IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $2, 0); }
| IDENTIFIER dimensions_opt '=' expression
{ $$ = make_port_list($1, $2, $4); }
| list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt
{ $$ = make_port_list($1, $3, $4, 0); }
| list_of_variable_port_identifiers ',' IDENTIFIER dimensions_opt '=' expression
{ $$ = make_port_list($1, $3, $4, $6); }
;
@ -4218,7 +4271,7 @@ port_declaration
port_declaration_context.port_net_type = use_type;
port_declaration_context.data_type = $4;
pform_make_reginit(@5, name, $7);
pform_make_var_init(@5, name, $7);
delete[]$5;
$$ = ptmp;
@ -4372,13 +4425,13 @@ local_timeunit_prec_decl2
items, and finally an end marker. */
module
: attribute_list_opt module_start IDENTIFIER
{ pform_startmodule(@2, $3, $2==K_program, $2==K_interface, $1); }
: attribute_list_opt module_start lifetime_opt IDENTIFIER
{ pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1); }
module_package_import_list_opt
module_parameter_port_list_opt
module_port_list_opt
module_attribute_foreign ';'
{ pform_module_set_ports($7); }
{ pform_module_set_ports($8); }
local_timeunit_prec_decl_opt
{ have_timeunit_decl = true; // Every thing past here is
have_timeprec_decl = true; // a check!
@ -4404,22 +4457,22 @@ module
}
// Check that program/endprogram and module/endmodule
// keywords match.
if ($2 != $14) {
if ($2 != $15) {
switch ($2) {
case K_module:
yyerror(@14, "error: module not closed by endmodule.");
yyerror(@15, "error: module not closed by endmodule.");
break;
case K_program:
yyerror(@14, "error: program not closed by endprogram.");
yyerror(@15, "error: program not closed by endprogram.");
break;
case K_interface:
yyerror(@14, "error: interface not closed by endinterface.");
yyerror(@15, "error: interface not closed by endinterface.");
break;
default:
break;
}
}
pform_endmodule($3, in_celldefine, ucd);
pform_endmodule($4, in_celldefine, ucd);
have_timeunit_decl = false; // We will allow decls again.
have_timeprec_decl = false;
}
@ -4429,19 +4482,19 @@ module
// endlabel_opt but still have the pform_endmodule() called
// early enough that the lexor can know we are outside the
// module.
if ($16) {
if (strcmp($3,$16) != 0) {
if ($17) {
if (strcmp($4,$17) != 0) {
switch ($2) {
case K_module:
yyerror(@16, "error: End label doesn't match "
yyerror(@17, "error: End label doesn't match "
"module name.");
break;
case K_program:
yyerror(@16, "error: End label doesn't match "
yyerror(@17, "error: End label doesn't match "
"program name.");
break;
case K_interface:
yyerror(@16, "error: End label doesn't match "
yyerror(@17, "error: End label doesn't match "
"interface name.");
break;
default:
@ -4452,9 +4505,9 @@ module
yyerror(@8, "error: Module end labels require "
"SystemVerilog.");
}
delete[]$16;
delete[]$17;
}
delete[]$3;
delete[]$4;
}
;
@ -4597,58 +4650,102 @@ module_item
delete $4;
}
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt list_of_identifiers ';'
{ pform_set_port_type(@2, $6, $4, $3, $2, $1); }
/* The next two rules handle Verilog 2001 statements of the form:
/* The next two rules handle port declarations that include a net type, e.g.
input wire signed [h:l] <list>;
This creates the wire and sets the port type all at once. */
| attribute_list_opt port_direction net_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); }
| attribute_list_opt port_direction net_type data_type_or_implicit list_of_port_identifiers ';'
{ pform_module_define_port(@2, $5, $2, $3, $4, $1); }
| attribute_list_opt K_output var_type unsigned_signed_opt dimensions_opt list_of_port_identifiers ';'
{ list<pair<perm_string,PExpr*> >::const_iterator pp;
list<perm_string>*tmp = new list<perm_string>;
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
tmp->push_back((*pp).first);
| 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);
}
/* The next three rules handle port declarations that include a variable
type, e.g.
output reg signed [h:l] <list>;
and also handle incomplete port declarations, e.g.
input signed [h:l] <list>;
*/
| attribute_list_opt K_inout data_type_or_implicit list_of_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
}
pform_makewire(@2, $5, $4, tmp, $3, NetNet::POUTPUT,
IVL_VT_NO_TYPE, $1, SR_BOTH);
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
if ((*pp).second) {
pform_make_reginit(@2, (*pp).first, (*pp).second);
}
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::PINOUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::PINOUT, use_type, $3, $1);
}
| attribute_list_opt K_input data_type_or_implicit list_of_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
}
delete $6;
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::PINPUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::PINPUT, use_type, $3, $1);
}
| attribute_list_opt port_direction K_wreal list_of_identifiers ';'
{ pform_makewire(@2, 0, true, $4, NetNet::WIRE, $2,
IVL_VT_REAL, $1, SR_BOTH);
| attribute_list_opt K_output data_type_or_implicit list_of_variable_port_identifiers ';'
{ NetNet::Type use_type = $3 ? NetNet::IMPLICIT : NetNet::NONE;
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($3)) {
if (dtype->implicit_flag)
use_type = NetNet::NONE;
else if (dtype->reg_flag)
use_type = NetNet::REG;
else
use_type = NetNet::IMPLICIT_REG;
// The SystemVerilog types that can show up as
// output ports are implicitly (on the inside)
// variables because "reg" is not valid syntax
// here.
} else if (dynamic_cast<atom2_type_t*> ($3)) {
use_type = NetNet::IMPLICIT_REG;
} else if (dynamic_cast<struct_type_t*> ($3)) {
use_type = NetNet::IMPLICIT_REG;
} else if (enum_type_t*etype = dynamic_cast<enum_type_t*> ($3)) {
if(etype->base_type == IVL_VT_LOGIC)
use_type = NetNet::IMPLICIT_REG;
}
if (use_type == NetNet::NONE)
pform_set_port_type(@2, $4, NetNet::POUTPUT, $3, $1);
else
pform_module_define_port(@2, $4, NetNet::POUTPUT, use_type, $3, $1);
}
/* var_type declaration (reg variables) cannot be input or output,
because the port declaration implies an external driver, which
cannot be attached to a reg. These rules catch that error early. */
| attribute_list_opt K_input var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT,
IVL_VT_NO_TYPE, $1);
yyerror(@3, "error: reg variables cannot be inputs.");
}
| attribute_list_opt K_inout var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT,
IVL_VT_NO_TYPE, $1);
yyerror(@3, "error: reg variables cannot be inouts.");
}
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';'
| attribute_list_opt port_direction net_type data_type_or_implicit error ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($4) delete $4;
if ($5) delete $5;
yyerrok;
}
| attribute_list_opt K_inout data_type_or_implicit 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 ';'
{ 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 ';'
{ yyerror(@2, "error: Invalid variable list in port declaration.");
if ($1) delete $1;
if ($3) delete $3;
yyerrok;
}
@ -5048,10 +5145,6 @@ net_type
| K_uwire { $$ = NetNet::UNRESOLVED_WIRE; }
;
var_type
: K_reg { $$ = NetNet::REG; }
;
param_type
: bit_logic_opt unsigned_signed_opt dimensions_opt
{ param_active_range = $3;
@ -5477,11 +5570,17 @@ register_variable
$$ = $1;
}
| IDENTIFIER dimensions_opt '=' expression
{ perm_string name = lex_strings.make($1);
{ if (pform_peek_scope()->var_init_needs_explicit_lifetime()
&& (var_lifetime == LexicalScope::INHERITED)) {
cerr << @3 << ": warning: Static variable initialization requires "
"explicit lifetime in this context." << endl;
warn_count += 1;
}
perm_string name = lex_strings.make($1);
pform_makewire(@1, name, NetNet::REG,
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
pform_set_reg_idx(name, $2);
pform_make_reginit(@1, name, $4);
pform_make_var_init(@1, name, $4);
$$ = $1;
}
;
@ -5734,7 +5833,23 @@ specify_path_identifiers
delete[]$1;
}
| IDENTIFIER '[' expr_primary ']'
{ list<perm_string>*tmp = new list<perm_string>;
{ if (gn_specify_blocks_flag) {
yywarn(@4, "Bit selects are not currently supported "
"in path declarations. The declaration "
"will be applied to the whole vector.");
}
list<perm_string>*tmp = new list<perm_string>;
tmp->push_back(lex_strings.make($1));
$$ = tmp;
delete[]$1;
}
| IDENTIFIER '[' expr_primary polarity_operator expr_primary ']'
{ if (gn_specify_blocks_flag) {
yywarn(@4, "Part selects are not currently supported "
"in path declarations. The declaration "
"will be applied to the whole vector.");
}
list<perm_string>*tmp = new list<perm_string>;
tmp->push_back(lex_strings.make($1));
$$ = tmp;
delete[]$1;
@ -5746,7 +5861,23 @@ specify_path_identifiers
delete[]$3;
}
| specify_path_identifiers ',' IDENTIFIER '[' expr_primary ']'
{ list<perm_string>*tmp = $1;
{ if (gn_specify_blocks_flag) {
yywarn(@4, "Bit selects are not currently supported "
"in path declarations. The declaration "
"will be applied to the whole vector.");
}
list<perm_string>*tmp = $1;
tmp->push_back(lex_strings.make($3));
$$ = tmp;
delete[]$3;
}
| specify_path_identifiers ',' IDENTIFIER '[' expr_primary polarity_operator expr_primary ']'
{ if (gn_specify_blocks_flag) {
yywarn(@4, "Part selects are not currently supported "
"in path declarations. The declaration "
"will be applied to the whole vector.");
}
list<perm_string>*tmp = $1;
tmp->push_back(lex_strings.make($3));
$$ = tmp;
delete[]$3;
@ -6777,7 +6908,6 @@ udp_primitive
presence is significant. This is a fairly common pattern so
collect those rules here. */
K_automatic_opt: K_automatic { $$ = true; } | { $$ = false; } ;
K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ;
K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ;
K_static_opt : K_static { $$ = true; } | { $$ = false; } ;

230
pform.cc
View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -312,12 +312,29 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
*/
static LexicalScope* lexical_scope = 0;
LexicalScope* pform_peek_scope(void)
{
assert(lexical_scope);
return lexical_scope;
}
void pform_pop_scope()
{
assert(lexical_scope);
lexical_scope = lexical_scope->parent_scope();
}
static LexicalScope::lifetime_t find_lifetime(LexicalScope::lifetime_t lifetime)
{
if (lifetime != LexicalScope::INHERITED)
return lifetime;
if (lexical_scope != 0)
return lexical_scope->default_lifetime;
return LexicalScope::STATIC;
}
static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
{
PScopeExtra*scopex = dynamic_cast<PScopeExtra*> (scope);
@ -328,17 +345,37 @@ static PScopeExtra* find_nearest_scopex(LexicalScope*scope)
return scopex;
}
LexicalScope* pform_peek_scope(void)
/*
* Set the local time unit/precision to the global value.
*/
static void pform_set_scope_timescale(PScope*scope, const struct vlltype&loc)
{
assert(lexical_scope);
return lexical_scope;
scope->time_unit = pform_time_unit;
scope->time_precision = pform_time_prec;
/* If we have a timescale file then the time information is from
* a timescale directive. */
scope->time_from_timescale = pform_timescale_file != 0;
if (warn_timescale && (lexical_scope == 0) && pform_timescale_file
&& (strcmp(pform_timescale_file, loc.text) != 0)) {
cerr << loc.get_fileline() << ": warning: "
<< "timescale for " << scope->pscope_name()
<< " inherited from another file." << endl;
cerr << pform_timescale_file << ":" << pform_timescale_line
<< ": ...: The inherited timescale is here." << endl;
}
}
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime)
{
PClass*class_scope = new PClass(name, lexical_scope);
class_scope->default_lifetime = find_lifetime(lifetime);
FILE_NAME(class_scope, loc);
pform_set_scope_timescale(class_scope, loc);
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
assert(!pform_cur_generate);
@ -364,22 +401,33 @@ PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name)
return class_scope;
}
PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name)
PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime)
{
PPackage*pkg_scope = new PPackage(name, lexical_scope);
pkg_scope->default_lifetime = find_lifetime(lifetime);
FILE_NAME(pkg_scope, loc);
pform_set_scope_timescale(pkg_scope, loc);
lexical_scope = pkg_scope;
return pkg_scope;
}
PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
PTask* pform_push_task_scope(const struct vlltype&loc, char*name,
LexicalScope::lifetime_t lifetime)
{
perm_string task_name = lex_strings.make(name);
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
PTask*task = new PTask(task_name, lexical_scope, is_auto);
task->default_lifetime = default_lifetime;
FILE_NAME(task, loc);
pform_set_scope_timescale(task, loc);
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
if ((scopex == 0) && !gn_system_verilog()) {
cerr << task->get_fileline() << ": error: task declarations "
@ -424,15 +472,21 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto)
}
PFunction* pform_push_function_scope(const struct vlltype&loc, const char*name,
bool is_auto)
LexicalScope::lifetime_t lifetime)
{
perm_string func_name = lex_strings.make(name);
LexicalScope::lifetime_t default_lifetime = find_lifetime(lifetime);
bool is_auto = default_lifetime == LexicalScope::AUTOMATIC;
PFunction*func = new PFunction(func_name, lexical_scope, is_auto);
func->default_lifetime = default_lifetime;
FILE_NAME(func, loc);
pform_set_scope_timescale(func, loc);
PScopeExtra*scopex = find_nearest_scopex(lexical_scope);
if ((scopex == 0) && (generation_flag < GN_VER2005_SV)) {
if ((scopex == 0) && !gn_system_verilog()) {
cerr << func->get_fileline() << ": error: function declarations "
"must be contained within a module." << endl;
error_count += 1;
@ -489,6 +543,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
}
PBlock*block = new PBlock(block_name, lexical_scope, bt);
block->default_lifetime = find_lifetime(LexicalScope::INHERITED);
lexical_scope = block;
return block;
@ -1041,7 +1096,10 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check)
int pform_get_timeunit()
{
return pform_cur_module.front()->time_unit;
if (pform_cur_module.empty())
return pform_time_unit;
else
return pform_cur_module.front()->time_unit;
}
void pform_set_timeprecision(const char*txt, bool in_module, bool only_check)
@ -1131,6 +1189,7 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val,
void pform_startmodule(const struct vlltype&loc, const char*name,
bool program_block, bool is_interface,
LexicalScope::lifetime_t lifetime,
list<named_pexpr_t>*attr)
{
if (! pform_cur_module.empty() && !gn_system_verilog()) {
@ -1139,6 +1198,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
error_count += 1;
}
if (lifetime != LexicalScope::INHERITED && !gn_system_verilog()) {
cerr << loc << ": error: Default subroutine lifetimes "
"require SystemVerilog." << endl;
error_count += 1;
}
if (gn_system_verilog() && ! pform_cur_module.empty()) {
if (pform_cur_module.front()->program_block) {
cerr << loc << ": error: module, program, or interface "
@ -1158,17 +1223,14 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
Module*cur_module = new Module(lexical_scope, lex_name);
cur_module->program_block = program_block;
cur_module->is_interface = is_interface;
/* Set the local time unit/precision to the global value. */
cur_module->time_unit = pform_time_unit;
cur_module->time_precision = pform_time_prec;
cur_module->default_lifetime = find_lifetime(lifetime);
FILE_NAME(cur_module, loc);
pform_set_scope_timescale(cur_module, loc);
tu_local_flag = tu_global_flag;
tp_local_flag = tp_global_flag;
/* If we have a timescale file then the time information is from
* a timescale directive. */
cur_module->time_from_timescale = pform_timescale_file != 0;
FILE_NAME(cur_module, loc);
cur_module->library_flag = pform_library_flag;
pform_cur_module.push_front(cur_module);
@ -1179,15 +1241,6 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
zero. That's just the way it is, thanks to the standard. */
scope_generate_counter = 1;
if (warn_timescale && pform_timescale_file
&& (strcmp(pform_timescale_file,loc.text) != 0)) {
cerr << cur_module->get_fileline() << ": warning: "
<< "timescale for " << name
<< " inherited from another file." << endl;
cerr << pform_timescale_file << ":" << pform_timescale_line
<< ": ...: The inherited timescale is here." << endl;
}
pform_bind_attributes(cur_module->attributes, attr);
}
@ -1199,7 +1252,7 @@ void pform_startmodule(const struct vlltype&loc, const char*name,
void pform_check_timeunit_prec()
{
assert(! pform_cur_module.empty());
if ((generation_flag & (GN_VER2005_SV | GN_VER2009 | GN_VER2012)) &&
if (gn_system_verilog() &&
(pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) {
VLerror("error: a timeprecision is missing or is too large!");
} else assert(pform_cur_module.front()->time_unit >=
@ -1905,6 +1958,7 @@ static void pform_set_net_range(perm_string name,
VLerror("error: name is not a valid net.");
return;
}
// If this is not implicit ("implicit" meaning we don't
// know what the type is yet) then set the type now.
if (net_type != NetNet::IMPLICIT && net_type != NetNet::NONE) {
@ -2248,23 +2302,30 @@ void pform_make_pgassign_list(list<PExpr*>*alist,
}
/*
* this function makes the initial assignment to a register as given
* in the source. It handles the case where a reg variable is assigned
* where it it declared:
* This function makes the initial assignment to a variable as given
* in the source. It handles the case where a variable is assigned
* where it is declared, e.g.
*
* reg foo = <expr>;
*
* This is equivalent to the combination of statements:
* In Verilog-2001 this is only supported at the module level, and is
* equivalent to the combination of statements:
*
* reg foo;
* initial foo = <expr>;
*
* and that is how it is parsed. This syntax is not part of the
* IEEE1364-1995 standard, but is approved by OVI as enhancement
* BTF-B14.
* In SystemVerilog, variable initializations are allowed in any scope.
* For static variables, initializations are performed before the start
* of simulation. For automatic variables, initializations are performed
* each time the enclosing block is entered. Here we store the variable
* assignments in the current scope, and later elaboration creates an
* initialization block that will be executed at the appropriate time.
*
* This syntax is not part of the IEEE1364-1995 standard, but is
* approved by OVI as enhancement BTF-B14.
*/
void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr)
void pform_make_var_init(const struct vlltype&li,
perm_string name, PExpr*expr)
{
if (! pform_at_module_level() && !gn_system_verilog()) {
VLerror(li, "error: variable declaration assignments are only "
@ -2275,7 +2336,7 @@ void pform_make_reginit(const struct vlltype&li,
PWire*cur = pform_get_wire_in_scope(name);
if (cur == 0) {
VLerror(li, "internal error: reginit to non-register?");
VLerror(li, "internal error: var_init to non-register?");
delete expr;
return;
}
@ -2284,10 +2345,8 @@ void pform_make_reginit(const struct vlltype&li,
FILE_NAME(lval, li);
PAssign*ass = new PAssign(lval, expr, true);
FILE_NAME(ass, li);
PProcess*top = new PProcess(IVL_PR_INITIAL, ass);
FILE_NAME(top, li);
pform_put_behavior_in_scope(top);
lexical_scope->var_inits.push_back(ass);
}
/*
@ -2305,7 +2364,8 @@ void pform_module_define_port(const struct vlltype&li,
NetNet::PortType port_kind,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr)
list<named_pexpr_t>*attr,
bool keep_attr)
{
struct_type_t*struct_type = 0;
ivl_variable_type_t data_type = IVL_VT_NO_TYPE;
@ -2394,10 +2454,37 @@ void pform_module_define_port(const struct vlltype&li,
cur->set_unpacked_idx(*urange);
}
pform_bind_attributes(cur->attributes, attr);
pform_bind_attributes(cur->attributes, attr, keep_attr);
pform_put_wire_in_scope(name, cur);
}
void pform_module_define_port(const struct vlltype&li,
list<pform_port_t>*ports,
NetNet::PortType port_kind,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr)
{
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
data_type_t*use_type = vtype;
if (cur->udims)
use_type = new uarray_type_t(vtype, cur->udims);
pform_module_define_port(li, cur->name, port_kind, type, use_type,
attr, true);
if (cur->udims)
delete use_type;
if (cur->expr)
pform_make_var_init(li, cur->name, cur->expr);
}
delete ports;
delete attr;
}
/*
* This function makes a single signal (a wire, a reg, etc) as
* requested by the parser. The name is unscoped, so I attach the
@ -2591,7 +2678,7 @@ void pform_makewire(const struct vlltype&li,
NetNet::Type type,
data_type_t*data_type)
{
if ((lexical_scope == 0) && (generation_flag < GN_VER2005_SV)) {
if ((lexical_scope == 0) && !gn_system_verilog()) {
VLerror(li, "error: variable declarations must be contained within a module.");
return;
}
@ -2896,7 +2983,7 @@ void pform_set_parameter(const struct vlltype&loc,
LexicalScope::range_t*value_range)
{
LexicalScope*scope = lexical_scope;
if ((scope == 0) && (generation_flag < GN_VER2005_SV)) {
if ((scope == 0) && !gn_system_verilog()) {
VLerror(loc, "error: parameter declarations must be contained within a module.");
return;
}
@ -2971,7 +3058,7 @@ void pform_set_localparam(const struct vlltype&loc,
bool signed_flag, list<pform_range_t>*range, PExpr*expr)
{
LexicalScope*scope = lexical_scope;
if ((scope == 0) && (generation_flag < GN_VER2005_SV)) {
if ((scope == 0) && !gn_system_verilog()) {
VLerror(loc, "error: localparam declarations must be contained within a module.");
return;
}
@ -3200,24 +3287,53 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt,
}
void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<pform_range_t>*range,
bool signed_flag,
list<pform_port_t>*ports,
NetNet::PortType pt,
data_type_t*dt,
list<named_pexpr_t>*attr)
{
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string txt = *cur;
pform_set_port_type(txt, pt, li.text, li.first_line);
pform_set_net_range(txt, NetNet::NONE, range, signed_flag, IVL_VT_NO_TYPE,
SR_PORT, attr);
list<pform_range_t>*range = 0;
bool signed_flag = false;
if (vector_type_t*vt = dynamic_cast<vector_type_t*> (dt)) {
assert(vt->implicit_flag);
range = vt->pdims.get();
signed_flag = vt->signed_flag;
} else {
assert(dt == 0);
}
delete names;
delete range;
bool have_init_expr = false;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
pform_set_port_type(cur->name, pt, li.text, li.first_line);
pform_set_net_range(cur->name, NetNet::NONE, range, signed_flag,
IVL_VT_NO_TYPE, SR_PORT, attr);
if (cur->udims) {
cerr << li.text << ":" << li.first_line << ": warning: "
<< "Array dimensions in incomplete port declarations "
<< "are currently ignored." << endl;
cerr << li.text << ":" << li.first_line << ": : "
<< "The dimensions specified in the net or variable "
<< "declaration will be used." << endl;
delete cur->udims;
}
if (cur->expr) {
have_init_expr = true;
delete cur->expr;
}
}
if (have_init_expr) {
cerr << li.text << ":" << li.first_line << ": error: "
<< "Incomplete port declarations cannot be initialized."
<< endl;
error_count += 1;
}
delete ports;
delete dt;
delete attr;
}

53
pform.h
View File

@ -1,7 +1,7 @@
#ifndef IVL_pform_H
#define IVL_pform_H
/*
* Copyright (c) 1998-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 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
@ -163,18 +163,26 @@ extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_ty
*/
extern void pform_startmodule(const struct vlltype&loc, const char*name,
bool program_block, bool is_interface,
LexicalScope::lifetime_t lifetime,
list<named_pexpr_t>*attr);
extern void pform_check_timeunit_prec();
extern void pform_module_set_ports(vector<Module::port_t*>*);
/* This function is used to support the port definition in a
port_definition_list. In this case, we have everything needed to
define the port, all in one place. */
/* These functions are used when we have a complete port definition, either
in an ansi style or non-ansi style declaration. In this case, we have
everything needed to define the port, all in one place. */
extern void pform_module_define_port(const struct vlltype&li,
perm_string name,
NetNet::PortType,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr,
bool keep_attr =false);
extern void pform_module_define_port(const struct vlltype&li,
list<pform_port_t>*ports,
NetNet::PortType,
NetNet::Type type,
data_type_t*vtype,
list<named_pexpr_t>*attr);
extern Module::port_t* pform_module_port_reference(perm_string name,
@ -186,7 +194,8 @@ extern void pform_endmodule(const char*, bool inside_celldefine,
extern void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
std::list<PExpr*>*base_exprs);
std::list<PExpr*>*base_exprs,
LexicalScope::lifetime_t lifetime);
extern void pform_class_property(const struct vlltype&loc,
property_qualifier_t pq,
data_type_t*data_type,
@ -211,7 +220,8 @@ extern void pform_make_udp(perm_string name,
* Package related functions.
*/
extern void pform_start_package_declaration(const struct vlltype&loc,
const char*type);
const char*type,
LexicalScope::lifetime_t lifetime);
extern void pform_end_package_declaration(const struct vlltype&loc);
extern void pform_package_import(const struct vlltype&loc,
PPackage*pkg, const char*ident);
@ -246,13 +256,20 @@ extern void pform_pop_scope();
*/
extern LexicalScope* pform_peek_scope();
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name);
extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime);
extern PFunction*pform_push_constructor_scope(const struct vlltype&loc);
extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name);
extern PPackage* pform_push_package_scope(const struct vlltype&loc, perm_string name,
LexicalScope::lifetime_t lifetime);
extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name,
bool is_auto);
LexicalScope::lifetime_t lifetime);
extern PFunction*pform_push_function_scope(const struct vlltype&loc, const char*name,
bool is_auto);
LexicalScope::lifetime_t lifetime);
extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt);
extern void pform_put_behavior_in_scope(AProcess*proc);
@ -351,17 +368,17 @@ extern void pform_makewire(const struct vlltype&li,
list<perm_string>*names,
list<named_pexpr_t>*attr);
extern void pform_make_reginit(const struct vlltype&li,
perm_string name, PExpr*expr);
extern void pform_make_var_init(const struct vlltype&li,
perm_string name, PExpr*expr);
/* Look up the names of the wires, and set the port type,
i.e. input, output or inout. If the wire does not exist, create
it. The second form takes a single name. */
/* This function is used when we have an incomplete port definition in
a non-ansi style declaration. Look up the names of the wires, and set
the port type, i.e. input, output or inout, and, if specified, the
range and signedness. If the wire does not exist, create it. */
extern void pform_set_port_type(const struct vlltype&li,
list<perm_string>*names,
list<pform_range_t>*range,
bool signed_flag,
list<pform_port_t>*ports,
NetNet::PortType,
data_type_t*dt,
list<named_pexpr_t>*attr);
extern void pform_set_reg_idx(perm_string name,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2016 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
@ -318,7 +318,7 @@ void PECallFunction::dump(ostream &out) const
void PECastSize::dump(ostream &out) const
{
out << size_ << "'(";
out << *size_ << "'(";
base_->dump(out);
out << ")";
}
@ -789,6 +789,8 @@ void PBlock::dump(ostream&out, unsigned ind) const
dump_events_(out, ind+2);
dump_wires_(out, ind+2);
dump_var_inits_(out, ind+2);
}
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
@ -1030,6 +1032,8 @@ void PFunction::dump(ostream&out, unsigned ind) const
dump_wires_(out, ind+2);
dump_var_inits_(out, ind+2);
if (statement_)
statement_->dump(out, ind+2);
else
@ -1072,6 +1076,8 @@ void PTask::dump(ostream&out, unsigned ind) const
dump_wires_(out, ind+2);
dump_var_inits_(out, ind+2);
if (statement_)
statement_->dump(out, ind+2);
else
@ -1269,6 +1275,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
(*idx)->dump(out, indent+2);
}
dump_var_inits_(out, indent+2);
for (list<PProcess*>::const_iterator idx = behaviors.begin()
; idx != behaviors.end() ; ++ idx ) {
(*idx)->dump(out, indent+2);
@ -1408,6 +1416,14 @@ void LexicalScope::dump_wires_(ostream&out, unsigned indent) const
}
}
void LexicalScope::dump_var_inits_(ostream&out, unsigned indent) const
{
// Iterate through and display all the register initializations.
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
var_inits[idx]->dump(out, indent);
}
}
void PScopeExtra::dump_classes_(ostream&out, unsigned indent) const
{
// Dump the task definitions.
@ -1564,6 +1580,7 @@ void Module::dump(ostream&out) const
(*gate)->dump(out);
}
dump_var_inits_(out, 4);
for (list<PProcess*>::const_iterator behav = behaviors.begin()
; behav != behaviors.end() ; ++ behav ) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2016 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
@ -35,12 +35,13 @@ map<perm_string,PPackage*> pform_packages;
static PPackage*pform_cur_package = 0;
void pform_start_package_declaration(const struct vlltype&loc, const char*name)
void pform_start_package_declaration(const struct vlltype&loc, const char*name,
LexicalScope::lifetime_t lifetime)
{
ivl_assert(loc, pform_cur_package == 0);
perm_string use_name = lex_strings.make(name);
PPackage*pkg_scope = pform_push_package_scope(loc, use_name);
PPackage*pkg_scope = pform_push_package_scope(loc, use_name, lifetime);
FILE_NAME(pkg_scope, loc);
pform_cur_package = pkg_scope;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2012-2016 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
@ -36,9 +36,13 @@ static PClass*pform_cur_class = 0;
* if present, are the "exprs" that would be passed to a chained
* constructor.
*/
void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type, data_type_t*base_type, list<PExpr*>*base_exprs)
void pform_start_class_declaration(const struct vlltype&loc,
class_type_t*type,
data_type_t*base_type,
list<PExpr*>*base_exprs,
LexicalScope::lifetime_t lifetime)
{
PClass*class_scope = pform_push_class_scope(loc, type->name);
PClass*class_scope = pform_push_class_scope(loc, type->name, lifetime);
class_scope->type = type;
assert(pform_cur_class == 0);
pform_cur_class = class_scope;
@ -75,6 +79,7 @@ void pform_class_property(const struct vlltype&loc,
if (! curp->index.empty()) {
list<pform_range_t>*pd = new list<pform_range_t> (curp->index);
use_type = new uarray_type_t(use_type, pd);
FILE_NAME(use_type, loc);
}
pform_cur_class->type->properties[curp->name]
@ -127,7 +132,7 @@ void pform_set_constructor_return(PFunction*net)
PFunction*pform_push_constructor_scope(const struct vlltype&loc)
{
assert(pform_cur_class);
PFunction*func = pform_push_function_scope(loc, "new", true);
PFunction*func = pform_push_function_scope(loc, "new", LexicalScope::AUTOMATIC);
return func;
}
@ -138,7 +143,7 @@ void pform_end_class_declaration(const struct vlltype&loc)
// If there were initializer statements, then collect them
// into an implicit constructor function.
if (! pform_cur_class->type->initialize.empty()) {
PFunction*func = pform_push_function_scope(loc, "new@", true);
PFunction*func = pform_push_function_scope(loc, "new@", LexicalScope::AUTOMATIC);
func->set_ports(0);
pform_set_constructor_return(func);
pform_set_this_class(loc, func);

View File

@ -1,7 +1,7 @@
#ifndef IVL_pform_types_H
#define IVL_pform_types_H
/*
* Copyright (c) 2007-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2007-2016 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
@ -72,6 +72,21 @@ typedef named<PExpr*> named_pexpr_t;
*/
typedef std::pair<PExpr*,PExpr*> pform_range_t;
/*
* The pform_port_t holds the name and optional unpacked dimensions
* and initialization expression for a single port in a list of port
* declarations.
*/
struct pform_port_t {
pform_port_t(perm_string n, list<pform_range_t>*ud, PExpr*e)
: name(n), udims(ud), expr(e) { }
~pform_port_t() { }
perm_string name;
list<pform_range_t>*udims;
PExpr*expr;
};
/*
* Semantic NOTES:
* - The SEL_BIT is a single expression. This might me a bit select

View File

@ -565,7 +565,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
// The minimum selector width is the number of inputs that
// are selected, rounded up to the nearest power of 2.
unsigned sel_need = ceil(log2(max_guard_value + 1));
unsigned sel_need = max(ceil(log2(max_guard_value + 1)), 1.0);
// If the sel_width can select more than just the explicit
// guard values, and there is a default statement, then adjust

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2011-2016 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -747,7 +747,9 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD)
* This function traverses the scope tree looking for the enclosing module
* scope. When it is found the module scope is returned. As far as this
* translation is concerned a package is a special form of a module
* definition and a class is also a top level scope.
* definition and a class is also a top level scope. In SystemVerilog,
* tasks and functions can also be top level scopes - we create a wrapper
* module for these later.
*/
ivl_scope_t get_module_scope(ivl_scope_t scope)
{
@ -756,6 +758,12 @@ ivl_scope_t get_module_scope(ivl_scope_t scope)
(ivl_scope_type(scope) != IVL_SCT_PACKAGE) &&
(ivl_scope_type(scope) != IVL_SCT_CLASS)) {
ivl_scope_t pscope = ivl_scope_parent(scope);
if (pscope == 0) {
if (ivl_scope_type(scope) == IVL_SCT_TASK)
break;
if (ivl_scope_type(scope) == IVL_SCT_FUNCTION)
break;
}
assert(pscope);
scope = pscope;
}
@ -872,7 +880,8 @@ void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope)
/* Check to see if this is a root scope task or function. */
if (ivl_scope_parent(call_scope) == 0) {
fprintf(vlog_out, "ivl_root_scope.");
fprintf(vlog_out, "ivl_root_scope_%s.",
ivl_scope_basename(call_scope));
mod_scope = 0;
call_mod_scope = 0;
} else {
@ -938,3 +947,30 @@ void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb)
break;
}
}
const char*get_time_const(int time_value)
{
switch (time_value) {
case 2: return "100s";
case 1: return "10s";
case 0: return "1s";
case -1: return "100ms";
case -2: return "10ms";
case -3: return "1ms";
case -4: return "100us";
case -5: return "10us";
case -6: return "1us";
case -7: return "100ns";
case -8: return "10ns";
case -9: return "1ns";
case -10: return "100ps";
case -11: return "10ps";
case -12: return "1ps";
case -13: return "100fs";
case -14: return "10fs";
case -15: return "1fs";
default:
fprintf(stderr, "Invalid time constant value %d.\n", time_value);
return "N/A";
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2015 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -24,33 +24,6 @@
const char *func_rtn_name = 0;
static const char*get_time_const(int time_value)
{
switch (time_value) {
case 2: return "100s";
case 1: return "10s";
case 0: return "1s";
case -1: return "100ms";
case -2: return "10ms";
case -3: return "1ms";
case -4: return "100us";
case -5: return "10us";
case -6: return "1us";
case -7: return "100ns";
case -8: return "10ns";
case -9: return "1ns";
case -10: return "100ps";
case -11: return "10ps";
case -12: return "1ps";
case -13: return "100fs";
case -14: return "10fs";
case -15: return "1fs";
default:
fprintf(stderr, "Invalid time constant value %d.\n", time_value);
return "N/A";
}
}
static void emit_func_return(ivl_signal_t sig)
{
if (ivl_signal_dimensions(sig) > 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010-2013 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
*
* This program 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,6 @@ int target_design(ivl_design_t des)
{
ivl_scope_t *roots;
unsigned nroots, idx;
unsigned has_root_scope = 0;
const char*path = ivl_design_flag(des, "-o");
/* Set the indent spacing with the -pspacing flag passed to iverilog
* (e.g. -pspacing=4). The default is 2 spaces. */
@ -190,23 +189,27 @@ int target_design(ivl_design_t des)
switch(ivl_scope_type(roots[idx])) {
case IVL_SCT_FUNCTION:
case IVL_SCT_TASK:
if (! has_root_scope) {
fprintf(vlog_out, "module ivl_root_scope;\n");
indent += indent_incr;
has_root_scope = 1;
}
/* Create a separate module for each task/function.
This allows us to handle different timescales. */
fprintf(vlog_out, "\n`timescale %s/%s\n",
get_time_const(ivl_scope_time_units(roots[idx])),
get_time_const(ivl_scope_time_precision(roots[idx])));
fprintf(vlog_out, "module ivl_root_scope_%s;\n",
ivl_scope_basename(roots[idx]));
indent += indent_incr;
/* Say this task/function has a parent so the
* definition is emitted correctly. */
emit_scope(roots[idx], roots[idx]);
indent -= indent_incr;
assert(indent == 0);
fprintf(vlog_out, "endmodule /* ivl_root_scope_%p */\n",
roots[idx]);
break;
default:
break;
}
}
if (has_root_scope) {
indent -= indent_incr;
assert(indent == 0);
fprintf(vlog_out, "endmodule /* ivl_root_scope */\n");
}
/* Emit the rest of the scope objects. */
for (idx = 0; idx < nroots; idx += 1) emit_scope(roots[idx], 0);

View File

@ -1,7 +1,7 @@
#ifndef IVL_vlog95_priv_H
#define IVL_vlog95_priv_H
/*
* Copyright (C) 2010-2014 Cary R. (cygcary@yahoo.com)
* Copyright (C) 2010-2016 Cary R. (cygcary@yahoo.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -145,6 +145,11 @@ extern char * get_package_name(ivl_scope_t scope);
*/
extern void get_sig_msb_lsb(ivl_signal_t sig, int *msb, int *lsb);
/*
* Convert a timescale value to a string.
*/
extern const char*get_time_const(int time_value);
/*
* Cleanup functions.
*/

View File

@ -47,8 +47,8 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CC@ @CFLAGS@
LDFLAGS = @LDFLAGS@
O = vvp.o draw_class.o draw_enum.o draw_mux.o draw_substitute.o draw_net_input.o \
draw_switch.o draw_ufunc.o draw_vpi.o \
O = vvp.o draw_class.o draw_delay.o draw_enum.o draw_mux.o draw_net_input.o \
draw_substitute.o draw_switch.o draw_ufunc.o draw_vpi.o \
eval_bool.o \
eval_condit.o \
eval_expr.o eval_object.o eval_real.o eval_string.o \

127
tgt-vvp/draw_delay.c Normal file
View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2016 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vvp_priv.h"
# include <assert.h>
# include <stdlib.h>
# include <string.h>
/*
* This function draws a BUFT to drive a constant delay value.
*/
static char* draw_const_net(void*ptr, char*suffix, uint64_t value)
{
char tmp[64];
char c4_value[69];
unsigned idx;
c4_value[0] = 'C';
c4_value[1] = '4';
c4_value[2] = '<';
for (idx = 0; idx < 64; idx += 1) {
c4_value[66-idx] = (value & 1) ? '1' : '0';
value >>= 1;
}
c4_value[67] = '>';
c4_value[68] = 0;
/* Make the constant an argument to a BUFT, which is
what we use to drive the value. */
fprintf(vvp_out, "L_%p/%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
ptr, suffix, c4_value);
snprintf(tmp, sizeof tmp, "L_%p/%s", ptr, suffix);
return strdup(tmp);
}
/*
* Draw the appropriate delay statement.
*/
void draw_delay(void*ptr, unsigned wid, const char*input, ivl_expr_t rise_exp,
ivl_expr_t fall_exp, ivl_expr_t decay_exp)
{
char tmp[64];
if (input == 0) {
snprintf(tmp, sizeof tmp, "L_%p/d", ptr);
input = tmp;
}
/* If the delays are all constants then process them here. */
if (number_is_immediate(rise_exp, 64, 0) &&
number_is_immediate(fall_exp, 64, 0) &&
number_is_immediate(decay_exp, 64, 0)) {
assert(! number_is_unknown(rise_exp));
assert(! number_is_unknown(fall_exp));
assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, "L_%p .delay %u "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
ptr, wid,
get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp),
input);
/* For a variable delay we indicate only two delays by setting the
* decay time to zero. */
} else {
char*rise_const = 0;
char*fall_const = 0;
char*decay_const = 0;
const char*rise_str;
const char*fall_str;
const char*decay_str;
if (number_is_immediate(rise_exp, 64, 0)) {
uint64_t value = get_number_immediate64(rise_exp);
rise_str = rise_const = draw_const_net(ptr, "tr", value);
} else {
ivl_signal_t sig = ivl_expr_signal(rise_exp);
assert(sig && ivl_signal_dimensions(sig) == 0);
rise_str = draw_net_input(ivl_signal_nex(sig,0));
}
if (number_is_immediate(fall_exp, 64, 0)) {
uint64_t value = get_number_immediate64(fall_exp);
fall_str = fall_const = draw_const_net(ptr, "tf", value);
} else {
ivl_signal_t sig = ivl_expr_signal(fall_exp);
assert(sig && ivl_signal_dimensions(sig) == 0);
fall_str = draw_net_input(ivl_signal_nex(sig,0));
}
if (decay_exp == 0) {
decay_str = "0";
} else if (number_is_immediate(decay_exp, 64, 0)) {
uint64_t value = get_number_immediate64(decay_exp);
decay_str = decay_const = draw_const_net(ptr, "td", value);
} else {
ivl_signal_t sig = ivl_expr_signal(decay_exp);
assert(sig && ivl_signal_dimensions(sig) == 0);
decay_str = draw_net_input(ivl_signal_nex(sig,0));
}
fprintf(vvp_out, "L_%p .delay %u %s, %s, %s, %s;\n",
ptr, wid, input, rise_str, fall_str, decay_str);
free(rise_const);
free(fall_const);
free(decay_const);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2016 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
@ -51,44 +51,8 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
if (data_type_of_nexus(ivl_lpm_q(net)) == IVL_VT_REAL)
dly_width = 0;
draw_delay(net, dly_width, 0, d_rise, d_fall, d_decay);
dly = "/d";
if (number_is_immediate(d_rise, 64, 0) &&
number_is_immediate(d_fall, 64, 0) &&
number_is_immediate(d_decay, 64, 0)) {
assert( ! number_is_unknown(d_rise));
assert( ! number_is_unknown(d_fall));
assert( ! number_is_unknown(d_decay));
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
net, dly_width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), net);
} else {
ivl_signal_t sig;
// We do not currently support calculating the decay from
// the rise and fall variable delays.
assert(d_decay != 0);
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
net, dly_width, net);
sig = ivl_expr_signal(d_rise);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(d_fall);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(d_decay);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0;\n", sig);
}
}
input[0] = draw_net_input(ivl_lpm_data(net,0));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -330,9 +330,11 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
cptr = ivl_nexus_ptr_con(nptr);
if (cptr) {
char tmp[64];
char *result = 0;
ivl_expr_t d_rise, d_fall, d_decay;
unsigned dly_width = 0;
char *dly;
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
@ -368,68 +370,17 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
d_fall = ivl_const_delay(cptr, 1);
d_decay = ivl_const_delay(cptr, 2);
/* We have a delayed constant, so we need to build some code. */
dly = "";
if (d_rise != 0) {
char tmp[128];
fprintf(vvp_out, "L_%p/d .functor BUFT 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
free(result);
/* Is this a fixed or variable delay? */
if (number_is_immediate(d_rise, 64, 0) &&
number_is_immediate(d_fall, 64, 0) &&
number_is_immediate(d_decay, 64, 0)) {
assert(! number_is_unknown(d_rise));
assert(! number_is_unknown(d_fall));
assert(! number_is_unknown(d_decay));
fprintf(vvp_out, "L_%p .delay %u "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
cptr, dly_width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), cptr);
} else {
ivl_signal_t sig;
// We do not currently support calculating the decay
// from the rise and fall variable delays.
assert(d_decay != 0);
assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
cptr, dly_width, cptr);
sig = ivl_expr_signal(d_rise);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(d_fall);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0", sig);
sig = ivl_expr_signal(d_decay);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", v%p_0;\n", sig);
}
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
} else {
char tmp[64];
fprintf(vvp_out, "L_%p .functor BUFT 1, %s, "
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
free(result);
snprintf(tmp, sizeof tmp, "L_%p", cptr);
result = strdup(tmp);
draw_delay(cptr, dly_width, 0, d_rise, d_fall, d_decay);
dly = "/d";
}
fprintf(vvp_out, "L_%p%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
cptr, dly, result);
free(result);
return result;
snprintf(tmp, sizeof tmp, "L_%p", cptr);
return strdup(tmp);
}
lpm = ivl_nexus_ptr_lpm(nptr);
@ -711,6 +662,8 @@ static void draw_net_input_x(ivl_nexus_t nex,
tmp += strlen(tmp);
switch (res) {
case IVL_SIT_TRI:
case IVL_SIT_TRIAND:
case IVL_SIT_TRIOR:
case IVL_SIT_UWIRE:
for (jdx = 0 ; jdx < wid ; jdx += 1)
*tmp++ = 'z';

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2010,2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2016 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
@ -38,18 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw)
ivl_expr_t fall_exp = ivl_switch_delay(sw, 1);
ivl_expr_t decay_exp= ivl_switch_delay(sw, 2);
if ((rise_exp || fall_exp || decay_exp) &&
(!number_is_immediate(rise_exp, 64, 0) ||
number_is_unknown(rise_exp) ||
!number_is_immediate(fall_exp, 64, 0) ||
number_is_unknown(fall_exp) ||
!number_is_immediate(decay_exp, 64, 0) ||
number_is_unknown(decay_exp))) {
fprintf(stderr, "%s:%u: error: Invalid tranif delay expression.\n",
ivl_switch_file(sw), ivl_switch_lineno(sw));
vvp_errors += 1;
}
island = ivl_switch_island(sw);
if (ivl_island_flag_test(island, 0) == 0)
draw_tran_island(island);
@ -67,24 +55,18 @@ void draw_switch_in_scope(ivl_switch_t sw)
char str_e_buf[4 + 2*sizeof(void*)];
if (enable && rise_exp) {
assert(fall_exp && decay_exp);
/* If the enable has a delay, then generate a .delay
node to delay the input by the specified amount. Do
the delay outside of the island so that the island
processing doesn't have to deal with it. */
const char*raw = draw_net_input(enable);
draw_delay(sw, 1, raw, rise_exp, fall_exp, decay_exp);
snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw);
str_e = str_e_buf;
fprintf(vvp_out, "%s/d .delay 1 "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n",
str_e, get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), raw);
fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e);
fprintf(vvp_out, "%s .import I%p, L_%p;\n", str_e, island, sw);
} else if (enable) {
str_e = draw_island_net_input(island, enable);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2016 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
@ -183,17 +183,17 @@ static void get_vec_from_lval(ivl_statement_t net, struct vec_slice_info*slices)
unsigned wid = ivl_stmt_lwidth(net);
cur_bit = 0;
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
for (lidx = ivl_stmt_lvals(net) ; lidx > 0 ; lidx -= 1) {
ivl_lval_t lval;
unsigned bit_limit = wid - cur_bit;
lval = ivl_stmt_lval(net, lidx);
lval = ivl_stmt_lval(net, lidx-1);
if (bit_limit > ivl_lval_width(lval))
bit_limit = ivl_lval_width(lval);
get_vec_from_lval_slice(lval, slices+lidx, bit_limit);
if (lidx > 0) {
get_vec_from_lval_slice(lval, slices+lidx-1, bit_limit);
if (cur_bit > 0) {
fprintf(vvp_out, " %%concat/vec4;\n");
}
@ -555,28 +555,130 @@ static int show_stmt_assign_vector(ivl_statement_t net)
return 0;
}
/*
* This function assigns a value to a real variable. This is destined
* for /dev/null when typed ivl_signal_t takes over all the real
* variable support.
*/
static int show_stmt_assign_sig_real(ivl_statement_t net)
enum real_lval_type_e {
REAL_NO_TYPE = 0,
REAL_SIMPLE_WORD,
REAL_MEMORY_WORD_STATIC,
REAL_MEMORY_WORD_DYNAMIC
};
struct real_lval_info {
enum real_lval_type_e type;
union {
struct {
unsigned long use_word;
} simple_word;
struct {
unsigned long use_word;
} memory_word_static;
struct {
/* Index reg that holds the memory word index */
int word_idx_reg;
/* Stored x/non-x flag */
unsigned x_flag;
} memory_word_dynamic;
} u_;
};
static void get_real_from_lval(ivl_lval_t lval, struct real_lval_info*slice)
{
ivl_signal_t sig = ivl_lval_sig(lval);
ivl_expr_t word_ix = ivl_lval_idx(lval);
unsigned long use_word = 0;
/* If the word index is a constant expression, then evaluate
it to select the word, and pay no further heed to the
expression itself. */
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
assert(! number_is_unknown(word_ix));
use_word = get_number_immediate(word_ix);
word_ix = 0;
}
if (ivl_signal_dimensions(sig)==0 && word_ix==0) {
slice->type = REAL_SIMPLE_WORD;
slice->u_.simple_word.use_word = use_word;
fprintf(vvp_out, " %%load/real v%p_%lu;\n", sig, use_word);
} else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {
slice->type = REAL_MEMORY_WORD_STATIC;
slice->u_.memory_word_static.use_word = use_word;
if (use_word < ivl_signal_array_count(sig)) {
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
use_word);
fprintf(vvp_out, " %%load/reala v%p, 3;\n", sig);
} else {
fprintf(vvp_out, " %%pushi/real 0, 0;\n");
}
} else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {
slice->type = REAL_MEMORY_WORD_DYNAMIC;
slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
slice->u_.memory_word_dynamic.x_flag = allocate_flag();
draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg);
fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.memory_word_dynamic.x_flag);
fprintf(vvp_out, " %%load/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
} else {
assert(0);
}
}
static void put_real_to_lval(ivl_lval_t lval, struct real_lval_info*slice)
{
ivl_signal_t sig = ivl_lval_sig(lval);
switch (slice->type) {
default:
fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type);
assert(0);
break;
case REAL_SIMPLE_WORD:
fprintf(vvp_out, " %%store/real v%p_%lu;\n",
sig, slice->u_.simple_word.use_word);
break;
case REAL_MEMORY_WORD_STATIC:
if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) {
int word_idx = allocate_word();
fprintf(vvp_out," %%flag_set/imm 4, 0;\n");
fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word);
fprintf(vvp_out," %%store/reala v%p, %d;\n", sig, word_idx);
clr_word(word_idx);
} else {
fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word);
}
break;
case REAL_MEMORY_WORD_DYNAMIC:
fprintf(vvp_out, " %%flag_mov 4, %u;\n", slice->u_.memory_word_dynamic.x_flag);
fprintf(vvp_out, " %%store/reala v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);
clr_word(slice->u_.memory_word_dynamic.word_idx_reg);
clr_flag(slice->u_.memory_word_dynamic.x_flag);
break;
}
}
static void store_real_to_lval(ivl_lval_t lval)
{
ivl_lval_t lval;
ivl_signal_t var;
assert(ivl_stmt_opcode(net) == 0);
draw_eval_real(ivl_stmt_rval(net));
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
var = ivl_lval_sig(lval);
assert(var != 0);
if (ivl_signal_dimensions(var) == 0) {
fprintf(vvp_out, " %%store/real v%p_0;\n", var);
return 0;
return;
}
// For now, only support 1-dimensional arrays.
@ -612,7 +714,66 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
}
clr_word(word_ix);
}
/*
* This function assigns a value to a real variable. This is destined
* for /dev/null when typed ivl_signal_t takes over all the real
* variable support.
*/
static int show_stmt_assign_sig_real(ivl_statement_t net)
{
struct real_lval_info*slice = 0;
ivl_lval_t lval;
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
/* If this is a compressed assignment, then get the contents
of the l-value. We need this value as part of the r-value
calculation. */
if (ivl_stmt_opcode(net) != 0) {
fprintf(vvp_out, " ; show_stmt_assign_real: Get l-value for compressed %c= operand\n", ivl_stmt_opcode(net));
slice = calloc(1, sizeof(struct real_lval_info));
get_real_from_lval(lval, slice);
}
draw_eval_real(ivl_stmt_rval(net));
switch (ivl_stmt_opcode(net)) {
case 0:
store_real_to_lval(lval);
if (slice) free(slice);
return 0;
case '+':
fprintf(vvp_out, " %%add/wr;\n");
break;
case '-':
fprintf(vvp_out, " %%sub/wr;\n");
break;
case '*':
fprintf(vvp_out, " %%mul/wr;\n");
break;
case '/':
fprintf(vvp_out, " %%div/wr;\n");
break;
case '%':
fprintf(vvp_out, " %%mod/wr;\n");
break;
default:
fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net));
assert(0);
break;
}
put_real_to_lval(lval, slice);
free(slice);
return 0;
}

View File

@ -256,6 +256,13 @@ extern void show_stmt_file_line(ivl_statement_t net, const char*desc);
extern int test_immediate_vec4_ok(ivl_expr_t expr);
extern void draw_immediate_vec4(ivl_expr_t expr, const char*opcode);
/*
* Draw a delay statement.
*/
extern void draw_delay(void*ptr, unsigned wid, const char*input,
ivl_expr_t rise_exp, ivl_expr_t fall_exp,
ivl_expr_t decay_exp);
/*
* These functions manage word register allocation.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -225,6 +225,15 @@ static void assign_to_lvector(ivl_lval_t lval,
const unsigned long use_word = 0;
if (ivl_signal_type(sig) == IVL_SIT_UWIRE) {
fprintf(stderr, "%s:%u: tgt-vvp sorry: V10 does not support "
"mixed continuous and non-blocking assignments to "
"different parts of the same vector (%s).\n",
ivl_signal_file(sig), ivl_signal_lineno(sig),
ivl_signal_basename(sig));
vvp_errors += 1;
}
// Detect the case that this is actually a non-blocking assign
// to an array word. In that case, run off somewhere else to
// deal with it.
@ -2298,6 +2307,7 @@ int draw_process(ivl_process_t net, void*x)
ivl_scope_t scope = ivl_process_scope(net);
ivl_statement_t stmt = ivl_process_stmt(net);
int init_flag = 0;
int push_flag = 0;
(void)x; /* Parameter is not used. */
@ -2306,6 +2316,12 @@ int draw_process(ivl_process_t net, void*x)
ivl_attribute_t attr = ivl_process_attr_val(net, idx);
if (strcmp(attr->key, "_ivl_schedule_init") == 0) {
init_flag = 1;
}
if (strcmp(attr->key, "_ivl_schedule_push") == 0) {
push_flag = 1;
@ -2349,7 +2365,9 @@ int draw_process(ivl_process_t net, void*x)
case IVL_PR_INITIAL:
case IVL_PR_ALWAYS:
if (push_flag) {
if (init_flag) {
fprintf(vvp_out, " .thread T_%u, $init;\n", thread_count);
} else if (push_flag) {
fprintf(vvp_out, " .thread T_%u, $push;\n", thread_count);
} else {
fprintf(vvp_out, " .thread T_%u;\n", thread_count);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -669,7 +669,7 @@ static void draw_net_in_scope(ivl_signal_t sig)
swapped ? last : first );
}
fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, "
fprintf(vvp_out, "v%p_%u .net%s v%p %u, %d %d, "
"v%p_%u; Alias to %s\n", sig, iword,
datatype_flag, sig, iword, msb, lsb,
nex_data->net, nex_data->net_word,
@ -717,7 +717,7 @@ static unsigned need_delay(ivl_net_logic_t lptr)
/*
* Draw the appropriate delay statement. Returns zero if there is not a delay.
*/
static void draw_delay(ivl_net_logic_t lptr)
static void draw_logic_delay(ivl_net_logic_t lptr)
{
ivl_expr_t rise_exp = ivl_logic_delay(lptr, 0);
ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1);
@ -730,49 +730,7 @@ static void draw_delay(ivl_net_logic_t lptr)
delay_wid = 0;
}
/* If the delays are all constants then process them here. */
if (number_is_immediate(rise_exp, 64, 0) &&
number_is_immediate(fall_exp, 64, 0) &&
number_is_immediate(decay_exp, 64, 0)) {
assert(! number_is_unknown(rise_exp));
assert(! number_is_unknown(fall_exp));
assert(! number_is_unknown(decay_exp));
fprintf(vvp_out, "L_%p .delay %u "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
lptr, delay_wid,
get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), lptr);
/* For a variable delay we indicate only two delays by setting the
* decay time to zero. */
} else {
ivl_signal_t sig;
assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert((decay_exp == 0) ||
(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL));
fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, delay_wid, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
sig = ivl_expr_signal(fall_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s", draw_net_input(ivl_signal_nex(sig,0)));
if (decay_exp) {
sig = ivl_expr_signal(decay_exp);
assert(ivl_signal_dimensions(sig) == 0);
fprintf(vvp_out, ", %s;\n",
draw_net_input(ivl_signal_nex(sig,0)));
} else {
fprintf(vvp_out, ", 0;\n");
}
}
draw_delay(lptr, delay_wid, 0, rise_exp, fall_exp, decay_exp);
}
static void draw_udp_def(ivl_udp_t udp)
@ -908,7 +866,7 @@ static void draw_udp_in_scope(ivl_net_logic_t lptr)
fprintf(vvp_out, ";\n");
/* Generate a delay when needed. */
if (need_delay_flag) draw_delay(lptr);
if (need_delay_flag) draw_logic_delay(lptr);
}
static void draw_logic_in_scope(ivl_net_logic_t lptr)
@ -1112,7 +1070,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
free(input_strings);
/* Generate a delay when needed. */
if (need_delay_flag) draw_delay(lptr);
if (need_delay_flag) draw_logic_delay(lptr);
}
static void draw_event_in_scope(ivl_event_t obj)
@ -1312,20 +1270,8 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net, ivl_variable_type_t dt)
const char*dly = "";
if (d_rise != 0) {
assert(number_is_immediate(d_rise, 64, 0));
assert(number_is_immediate(d_fall, 64, 0));
assert(number_is_immediate(d_decay, 64, 0));
assert(! number_is_unknown(d_rise));
assert(! number_is_unknown(d_fall));
assert(! number_is_unknown(d_decay));
draw_delay(net, width, 0, d_rise, d_fall, d_decay);
dly = "/d";
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ")"
" L_%p/d;\n", net, width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), net);
}
return dly;

View File

@ -3074,6 +3074,7 @@ uint32_t *rvat_chain_table_lengths;
uint64_t rvat_vc_maxhandle;
off_t rvat_vc_start;
uint32_t *rvat_sig_offs;
int rvat_packtype;
uint32_t rvat_chain_len;
unsigned char *rvat_chain_mem;
@ -5886,6 +5887,7 @@ if(frame_uclen == frame_clen)
xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f);
xc->rvat_vc_start = ftello(xc->f); /* points to '!' character */
xc->rvat_packtype = fgetc(xc->f);
#ifdef FST_DEBUG
fprintf(stderr, "\tframe_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
@ -5910,37 +5912,84 @@ xc->rvat_chain_table_lengths = calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t
pnt = chain_cmem;
idx = 0;
pval = 0;
do
if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
{
int skiplen;
uint64_t val = fstGetVarint32(pnt, &skiplen);
if(!val)
{
pnt += skiplen;
val = fstGetVarint32(pnt, &skiplen);
xc->rvat_chain_table[idx] = 0;
xc->rvat_chain_table_lengths[idx] = -val;
idx++;
}
else
if(val&1)
{
pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
pidx = idx++;
}
else
{
fstHandle loopcnt = val >> 1;
for(i=0;i<loopcnt;i++)
uint32_t prev_alias = 0;
do {
int skiplen;
if(*pnt & 0x01)
{
xc->rvat_chain_table[idx++] = 0;
int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
if(shval > 0)
{
pval = xc->rvat_chain_table[idx] = pval + shval;
if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
pidx = idx++;
}
else if(shval < 0)
{
xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
xc->rvat_chain_table_lengths[idx] = prev_alias = shval; /* because during this loop iter would give stale data! */
idx++;
}
else
{
xc->rvat_chain_table[idx] = 0; /* need to explicitly zero as calloc above might not run */
xc->rvat_chain_table_lengths[idx] = prev_alias; /* because during this loop iter would give stale data! */
idx++;
}
}
}
pnt += skiplen;
} while (pnt != (chain_cmem + chain_clen));
else
{
uint64_t val = fstGetVarint32(pnt, &skiplen);
fstHandle loopcnt = val >> 1;
for(i=0;i<loopcnt;i++)
{
xc->rvat_chain_table[idx++] = 0;
}
}
pnt += skiplen;
} while (pnt != (chain_cmem + chain_clen));
}
else
{
do
{
int skiplen;
uint64_t val = fstGetVarint32(pnt, &skiplen);
if(!val)
{
pnt += skiplen;
val = fstGetVarint32(pnt, &skiplen);
xc->rvat_chain_table[idx] = 0;
xc->rvat_chain_table_lengths[idx] = -val;
idx++;
}
else
if(val&1)
{
pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
pidx = idx++;
}
else
{
fstHandle loopcnt = val >> 1;
for(i=0;i<loopcnt;i++)
{
xc->rvat_chain_table[idx++] = 0;
}
}
pnt += skiplen;
} while (pnt != (chain_cmem + chain_clen));
}
free(chain_cmem);
xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start;
@ -6004,10 +6053,20 @@ if(!xc->rvat_chain_mem)
unsigned char *mc = malloc(xc->rvat_chain_table_lengths[facidx]);
unsigned long destlen = xc->rvat_chain_len;
unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx];
int rc;
int rc = Z_OK;
fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f);
rc = uncompress(mu, &destlen, mc, sourcelen);
switch(xc->rvat_packtype)
{
case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
break;
case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
break;
default: rc = uncompress(mu, &destlen, mc, sourcelen);
break;
}
free(mc);
if(rc != Z_OK)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2012 Tony Bybell.
* Copyright (c) 2003-2016 Tony Bybell.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -1029,12 +1029,12 @@ for(i=len;i>0;i--)
if(!i)
{
sprintf(tname, "%s_%03d.lxt", lt->lxtname, ++lt->break_number);
sprintf(tname, "%s_%03u.lxt", lt->lxtname, ++lt->break_number);
}
else
{
memcpy(tname, lt->lxtname, i);
sprintf(tname+i, "_%03d.lxt", ++lt->break_number);
sprintf(tname+i, "_%03u.lxt", ++lt->break_number);
}
f2 = fopen(tname, "wb");

View File

@ -1971,12 +1971,7 @@ static PLI_INT32 sys_printtimescale_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
item = vpi_scan(argv);
vpi_free_object(argv);
}
if (vpi_get(vpiType, item) != vpiModule) {
scope = vpi_handle(vpiModule, item);
} else {
scope = item;
}
scope = sys_func_module(item);
vpi_printf("Time scale of (%s) is ", vpi_get_str(vpiFullName, item));
vpi_printf("%s / ", pts_convert(vpi_get(vpiTimeUnit, scope)));

View File

@ -60,7 +60,7 @@ static PLI_INT32 missing_optional_compiletf(ICARUS_VPI_CONST PLI_BYTE8* name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpi_printf("SORRY: %s:%d: %s() is not available in Icarus verilog.\n",
vpi_printf("SORRY: %s:%d: %s() is not available in Icarus Verilog.\n",
vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh),
name);
vpi_control(vpiFinish, 1);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2016 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
@ -229,15 +229,18 @@ unsigned is_string_obj(vpiHandle obj)
/*
* Find the enclosing module.
* Find the enclosing module. If there is no enclosing module (which can be
* the case in SystemVerilog), return the highest enclosing scope.
*/
vpiHandle sys_func_module(vpiHandle obj)
{
assert(obj);
while (vpi_get(vpiType, obj) != vpiModule) {
obj = vpi_handle(vpiScope, obj);
assert(obj);
vpiHandle scope = vpi_handle(vpiScope, obj);
if (scope == 0)
break;
obj = scope;
}
return obj;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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,13 +26,13 @@
# include <cmath>
vvp_arith_::vvp_arith_(unsigned wid)
: wid_(wid), x_val_(wid)
: wid_(wid), op_a_(wid), op_b_(wid), x_val_(wid)
{
for (unsigned idx = 0 ; idx < wid ; idx += 1)
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
op_a_ .set_bit(idx, BIT4_Z);
op_b_ .set_bit(idx, BIT4_Z);
x_val_.set_bit(idx, BIT4_X);
op_a_ = x_val_;
op_b_ = x_val_;
}
}
void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit)
@ -51,6 +51,12 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit)
}
}
void vvp_arith_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
vvp_arith_abs::vvp_arith_abs()
{
@ -82,6 +88,13 @@ void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
ptr.ptr()->send_vec4(out, 0);
}
void vvp_arith_abs::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t)
{
@ -121,6 +134,13 @@ void vvp_arith_cast_real::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
ptr.ptr()->send_real(val, 0);
}
void vvp_arith_cast_real::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
vvp_arith_cast_vec2::vvp_arith_cast_vec2(unsigned wid)
: wid_(wid)
{
@ -143,6 +163,13 @@ void vvp_arith_cast_vec2::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
ptr.ptr()->send_vec4(vector2_to_vector4(tmp,wid_), 0);
}
void vvp_arith_cast_vec2::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
// Division
vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag)

View File

@ -1,7 +1,7 @@
#ifndef IVL_arith_H
#define IVL_arith_H
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -37,6 +37,10 @@ class vvp_arith_ : public vvp_net_fun_t {
public:
explicit vvp_arith_(unsigned wid);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
protected:
void dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit);
@ -59,6 +63,10 @@ class vvp_arith_abs : public vvp_net_fun_t {
void recv_real(vvp_net_ptr_t ptr, double bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
};
@ -82,6 +90,10 @@ class vvp_arith_cast_real : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
bool signed_;
};
@ -96,6 +108,10 @@ class vvp_arith_cast_vec2 : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
unsigned wid_;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -81,3 +81,10 @@ void vvp_fun_bufif::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
ptr.ptr()->send_vec8(out);
}
void vvp_fun_bufif::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}

View File

@ -1,7 +1,7 @@
#ifndef IVL_bufif_H
#define IVL_bufif_H
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -40,6 +40,10 @@ class vvp_fun_bufif : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
vvp_vector4_t bit_;
vvp_vector4_t en_;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -1935,7 +1935,9 @@ void compile_thread(char*start_sym, char*flag)
vthread_t thr = vthread_new(pc, vpip_peek_current_scope());
if (flag && (strcmp(flag,"$final") == 0))
if (flag && (strcmp(flag,"$init") == 0))
schedule_init_vthread(thr);
else if (flag && (strcmp(flag,"$final") == 0))
schedule_final_vthread(thr);
else
schedule_vthread(thr, 0, push_flag);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2014 Stephen Williams <steve@icarus.com>
* Copyright (c) 2005-2016 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
@ -332,6 +332,13 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
}
}
void vvp_fun_delay::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
/* See the recv_vec4 comment above. */
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
@ -397,6 +404,12 @@ void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
}
}
void vvp_fun_delay::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
recv_vec8_pv_(ptr, bit, base, wid, vwid);
}
void vvp_fun_delay::recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t)
{

View File

@ -1,7 +1,7 @@
#ifndef IVL_delay_H
#define IVL_delay_H
/*
* Copyright 2005-2014 Stephen Williams
* Copyright 2005-2016 Stephen Williams
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -99,6 +99,12 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s {
vvp_context_t);
//void recv_long(vvp_net_ptr_t port, long bit);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
private:
virtual void run_run();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2016 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
@ -103,6 +103,13 @@ void vvp_dff::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
}
}
void vvp_dff::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
/*
* The recv_async functions respond to the asynchronous
* set/clear input by propagating the desired output.

View File

@ -1,7 +1,7 @@
#ifndef IVL_dff_H
#define IVL_dff_H
/*
* Copyright (c) 2005-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2016 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
@ -44,6 +44,10 @@ class vvp_dff : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
virtual void recv_async(vvp_net_ptr_t port);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2010 Stephen Williams <steve@icarus.com>
* Copyright (c) 2005-2016 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
@ -51,3 +51,10 @@ void vvp_fun_extend_signed::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bi
port.ptr()->send_vec4(res, 0);
}
void vvp_fun_extend_signed::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2016 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
@ -43,6 +43,19 @@ void vvp_fun_pmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
generate_output_(ptr);
}
void vvp_fun_pmos_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
void vvp_fun_pmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
recv_vec8_pv_(ptr, bit, base, wid, vwid);
}
void vvp_fun_pmos_::generate_output_(vvp_net_ptr_t ptr)
{
vvp_vector8_t out (bit_.size());
@ -147,7 +160,18 @@ void vvp_fun_cmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t &bit,
generate_output_(ptr);
}
#include <iostream>
void vvp_fun_cmos_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
void vvp_fun_cmos_::recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
recv_vec8_pv_(ptr, bit, base, wid, vwid);
}
void vvp_fun_cmos_::generate_output_(vvp_net_ptr_t ptr)
{

View File

@ -1,7 +1,7 @@
#ifndef IVL_npmos_H
#define IVL_npmos_H
/*
* Copyright (c) 2005-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2016 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
@ -51,6 +51,12 @@ class vvp_fun_pmos_ : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
protected:
void generate_output_(vvp_net_ptr_t port);
@ -108,6 +114,12 @@ class vvp_fun_cmos_ : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t &bit,
vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
void recv_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
protected:
void generate_output_(vvp_net_ptr_t port);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2016 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
@ -208,6 +208,21 @@ void vvp_fun_part_pv::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
port.ptr()->send_vec4_pv(bit, base_, wid_, vwid_, context);
}
void vvp_fun_part_pv::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
assert(port.port() == 0);
assert(bit.size() == wid);
assert(base + wid <= vwid);
assert(vwid == wid_);
vvp_vector4_t tmp(wid_, BIT4_Z);
tmp.set_vec(base, bit);
port.ptr()->send_vec4_pv(tmp, base_, wid_, vwid_, ctx);
}
void vvp_fun_part_pv::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
{
assert(port.port() == 0);

View File

@ -109,6 +109,10 @@ class vvp_fun_part_pv : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned, unsigned, unsigned,
vvp_context_t);
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
private:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -760,6 +760,16 @@ void schedule_vthread(vthread_t thr, vvp_time64_t delay, bool push_flag)
}
}
void schedule_init_vthread(vthread_t thr)
{
struct vthread_event_s*cur = new vthread_event_s;
cur->thr = thr;
vthread_mark_scheduled(thr);
schedule_init_event(cur);
}
void schedule_final_vthread(vthread_t thr)
{
struct vthread_event_s*cur = new vthread_event_s;
@ -939,6 +949,10 @@ extern void vpiStartOfSim();
extern void vpiPostsim();
extern void vpiNextSimTime(void);
static bool sim_at_rosync = false;
bool schedule_at_rosync(void)
{ return sim_at_rosync; }
/*
* The scheduler uses this function to drain the rosync events of the
* current time. The ctim object is still in the event queue, because
@ -951,6 +965,7 @@ extern void vpiNextSimTime(void);
*/
static void run_rosync(struct event_time_s*ctim)
{
sim_at_rosync = true;
while (ctim->rosync) {
struct event_s*cur = ctim->rosync->next;
if (cur->next == cur) {
@ -962,6 +977,7 @@ static void run_rosync(struct event_time_s*ctim)
cur->run_run();
delete cur;
}
sim_at_rosync = false;
while (ctim->del_thr) {
struct event_s*cur = ctim->del_thr->next;

View File

@ -1,7 +1,7 @@
#ifndef IVL_schedule_H
#define IVL_schedule_H
/*
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -35,6 +35,8 @@
extern void schedule_vthread(vthread_t thr, vvp_time64_t delay,
bool push_flag =false);
extern void schedule_init_vthread(vthread_t thr);
extern void schedule_final_vthread(vthread_t thr);
/*
@ -153,6 +155,13 @@ extern void schedule_simulate(void);
*/
extern vvp_time64_t schedule_simtime(void);
/*
* Indicate that the simulator is running the rosync callbacks. This is
* used to prevent the callbacks from performing any write operations
* in the current simulation time slot.
*/
extern bool schedule_at_rosync(void);
/*
* This function is the equivalent of the $finish system task. It
* tells the simulator that simulation is done, the current thread

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
* Copyright (c) 2016 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
@ -32,6 +32,10 @@ class vvp_fun_substitute : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_context_t);
void recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx);
private:
unsigned wid_;
unsigned soff_;
@ -77,6 +81,13 @@ void vvp_fun_substitute::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
port.ptr()->send_vec4(val_, 0);
}
void vvp_fun_substitute::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
void compile_substitute(char*label, unsigned width,
unsigned soff, unsigned swidth,
unsigned argc, struct symb_s*argv)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2008-2016 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
@ -1067,13 +1067,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
vvp_time64_t dly;
int scale;
if (vpi_get(vpiAutomatic, obj)) {
fprintf(stderr, "vpi error: cannot put a value with "
"a delay on automatically allocated "
"variable '%s'\n",
vpi_get_str(vpiName, obj));
return 0;
}
if (vpi_get(vpiAutomatic, obj)) {
fprintf(stderr, "VPI error: cannot put a value with "
"a delay on automatically allocated "
"variable '%s'.\n",
vpi_get_str(vpiName, obj));
return 0;
}
assert(when != 0);
@ -1095,6 +1095,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
break;
}
if ((dly == 0) && schedule_at_rosync()) {
fprintf(stderr, "VPI error: attempted to put a value to "
"variable '%s' during a read-only synch "
"callback.\n", vpi_get_str(vpiName, obj));
return 0;
}
vpip_put_value_event*put = new vpip_put_value_event;
put->handle = obj;
put->value = *vp;
@ -1132,6 +1139,13 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
return 0;
}
if (schedule_at_rosync()) {
fprintf(stderr, "VPI error: attempted to put a value to "
"variable '%s' during a read-only synch "
"callback.\n", vpi_get_str(vpiName, obj));
return 0;
}
obj->vpi_put_value(vp, flags);
return 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2016 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
@ -1409,6 +1409,9 @@ static vpiHandle PV_get_handle(int code, vpiHandle ref)
case vpiParent:
return rfp->parent;
case vpiScope:
return vpi_handle(vpiScope, rfp->parent);
case vpiModule:
return vpi_handle(vpiModule, rfp->parent);
}

View File

@ -3249,6 +3249,31 @@ void vvp_net_fun_t::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&,
assert(0);
}
void vvp_net_fun_t::recv_vec4_pv_(vvp_net_ptr_t p, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
{
// The majority of functors don't normally expect to receive part
// values, because the primary operands of an expression will be
// extended to the expression width. But in the case that a primary
// operand is a wire that is only partly driven by a single driver,
// the part value driven onto the wire propagates directly to the
// inputs of any functors connected to that wire. In this case we
// know that the remaining bits are undriven, so can simply build
// the full width value from the part we have received.
//
// Note that this case is almost certainly a bug in the user's
// code, but we still need to handle it correctly. See GitHub
// issue #99 and br_gh99*.v in the test suite for examples.
assert(bit.size() == wid);
assert(base + wid <= vwid);
vvp_vector4_t tmp(vwid, BIT4_Z);
tmp.set_vec(base, bit);
recv_vec4(p, tmp, 0);
}
void vvp_net_fun_t::recv_vec4_pv(vvp_net_ptr_t, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t)
@ -3264,6 +3289,19 @@ void vvp_net_fun_t::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
recv_vec4(port, reduce4(bit), 0);
}
void vvp_net_fun_t::recv_vec8_pv_(vvp_net_ptr_t p, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
// This is the strength-aware version of recv_vec4_pv_.
assert(bit.size() == wid);
assert(base + wid <= vwid);
vvp_vector8_t tmp(vwid);
tmp.set_vec(base, bit);
recv_vec8(p, tmp);
}
void vvp_net_fun_t::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
@ -3331,6 +3369,12 @@ void vvp_fun_drive::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
port.ptr()->send_vec8(vvp_vector8_t(bit, drive0_, drive1_));
}
void vvp_fun_drive::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
/* **** vvp_wide_fun_* methods **** */
@ -3426,6 +3470,13 @@ void vvp_wide_fun_t::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
core_->dispatch_vec4_from_input_(pidx, bit);
}
void vvp_wide_fun_t::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t ctx)
{
recv_vec4_pv_(ptr, bit, base, wid, vwid, ctx);
}
void vvp_wide_fun_t::recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t)
{

View File

@ -1,7 +1,7 @@
#ifndef IVL_vvp_net_H
#define IVL_vvp_net_H
/*
* Copyright (c) 2004-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2016 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
@ -1230,6 +1230,13 @@ class vvp_net_fun_t {
// do something about it.
virtual void force_flag(bool run_now);
protected:
void recv_vec4_pv_(vvp_net_ptr_t p, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
void recv_vec8_pv_(vvp_net_ptr_t p, const vvp_vector8_t&bit,
unsigned base, unsigned wid, unsigned vwid);
public: // These objects are only permallocated.
static void* operator new(std::size_t size) { return heap_.alloc(size); }
static void operator delete(void*); // not implemented
@ -1470,6 +1477,9 @@ class vvp_fun_drive : public vvp_net_fun_t {
vvp_context_t context);
//void recv_long(vvp_net_ptr_t port, long bit);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
private:
unsigned char drive0_;
unsigned char drive1_;
@ -1490,6 +1500,9 @@ class vvp_fun_extend_signed : public vvp_net_fun_t {
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t);
private:
unsigned width_;
};
@ -1571,6 +1584,10 @@ class vvp_wide_fun_t : public vvp_net_fun_t {
void recv_real(vvp_net_ptr_t port, double bit,
vvp_context_t context);
void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid,
vvp_context_t context);
private:
vvp_wide_fun_core*core_;
unsigned port_base_;

View File

@ -393,7 +393,7 @@ class vvp_fun_signal_object_aa : public vvp_fun_signal_object, public automatic_
/* vvp_wire
* The vvp_wire is different from vvp_variable objects in that it
* exists only as a filter. The vvp_wire class tree is for
* implementing verilog wires/nets (as opposed to regs/variables).
* implementing Verilog wires/nets (as opposed to regs/variables).
*
* vvp_vpi_callback
* |