Merge branch 'v10-branch' of github.com:steveicarus/iverilog into v10-branch
This commit is contained in:
commit
5e41c86d01
|
|
@ -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()
|
||||
|
|
|
|||
6
Module.h
6
Module.h
|
|
@ -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
|
||||
|
|
|
|||
4
PExpr.cc
4
PExpr.cc
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
6
PExpr.h
6
PExpr.h
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
37
PScope.cc
37
PScope.cc
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
32
PScope.h
32
PScope.h
|
|
@ -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. */
|
||||
|
|
|
|||
5
PTask.cc
5
PTask.cc
|
|
@ -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);
|
||||
|
|
|
|||
2
PTask.h
2
PTask.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
30
compiler.h
30
compiler.h
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
121
elab_expr.cc
121
elab_expr.cc
|
|
@ -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 '~':
|
||||
|
|
|
|||
55
elab_lval.cc
55
elab_lval.cc
|
|
@ -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;
|
||||
|
|
|
|||
87
elab_net.cc
87
elab_net.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
18
elab_sig.cc
18
elab_sig.cc
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
14
elab_type.cc
14
elab_type.cc
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
192
elaborate.cc
192
elaborate.cc
|
|
@ -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.
|
||||
|
|
|
|||
8
emit.cc
8
emit.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} {}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
9
main.cc
9
main.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
154
net_func_eval.cc
154
net_func_eval.cc
|
|
@ -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
|
||||
|
|
|
|||
14
net_link.cc
14
net_link.cc
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
11
net_proc.cc
11
net_proc.cc
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
25
netlist.h
25
netlist.h
|
|
@ -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;
|
||||
|
|
|
|||
93
netmisc.cc
93
netmisc.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
38
netmisc.h
38
netmisc.h
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
370
parse.y
|
|
@ -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
230
pform.cc
|
|
@ -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
53
pform.h
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 ) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
119
vpi/fstapi.c
119
vpi/fstapi.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
39
vvp/arith.cc
39
vvp/arith.cc
|
|
@ -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)
|
||||
|
|
|
|||
18
vvp/arith.h
18
vvp/arith.h
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
15
vvp/delay.cc
15
vvp/delay.cc
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
28
vvp/npmos.cc
28
vvp/npmos.cc
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
14
vvp/npmos.h
14
vvp/npmos.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
17
vvp/part.cc
17
vvp/part.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* |
|
||||
|
|
|
|||
Loading…
Reference in New Issue