mirror of
https://github.com/steveicarus/iverilog.git
synced 2026-08-26 07:46:31 +02:00
Compare commits
104
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afa2478801 | ||
|
|
79feb44f10 | ||
|
|
c03d76a0d7 | ||
|
|
a2dc1e0a29 | ||
|
|
6a1235ac28 | ||
|
|
7aebff2a86 | ||
|
|
b31124983a | ||
|
|
f256dfe16e | ||
|
|
7c152685dc | ||
|
|
5d86dd0bbd | ||
|
|
4f97321c75 | ||
|
|
d0f303463d | ||
|
|
35fe8fae00 | ||
|
|
2e95a740da | ||
|
|
2f4e5bf5b6 | ||
|
|
7e478cdeb8 | ||
|
|
2576543bb5 | ||
|
|
e453b347f4 | ||
|
|
f132e09475 | ||
|
|
2ee976d1c0 | ||
|
|
30570adf31 | ||
|
|
1c51ac4ac0 | ||
|
|
17a1358eb6 | ||
|
|
04a7f7054a | ||
|
|
e97a1ad610 | ||
|
|
e872310e4b | ||
|
|
95850ac112 | ||
|
|
d0e154b830 | ||
|
|
4010f6e710 | ||
|
|
d74f2fe38d | ||
|
|
db642e3850 | ||
|
|
523dff7ae7 | ||
|
|
db09f2fa7e | ||
|
|
c2061e8199 | ||
|
|
ff9166d4a5 | ||
|
|
73e2b297df | ||
|
|
6e5373c87e | ||
|
|
782bfab29e | ||
|
|
df15a0368c | ||
|
|
916f300448 | ||
|
|
7898f4e402 | ||
|
|
6f8bf90dc4 | ||
|
|
052870c0e5 | ||
|
|
1be1f65f33 | ||
|
|
fd6f017435 | ||
|
|
dfa6471227 | ||
|
|
a8f492776a | ||
|
|
6f0d98cf18 | ||
|
|
6f30813102 | ||
|
|
2fab3159dd | ||
|
|
f04fb0fc45 | ||
|
|
7a1180868a | ||
|
|
b2bdce98ab | ||
|
|
653e2661b2 | ||
|
|
9aa610f489 | ||
|
|
de7fff8ac6 | ||
|
|
2179797763 | ||
|
|
b5e9e44e07 | ||
|
|
5a0fe9ff83 | ||
|
|
f6fede5aae | ||
|
|
0fa3099ded | ||
|
|
6987d16bd3 | ||
|
|
5cc376ebd4 | ||
|
|
8190307dd3 | ||
|
|
3575f68c9f | ||
|
|
c1268d04fc | ||
|
|
ca756f3ec3 | ||
|
|
9af459f95b | ||
|
|
492b240304 | ||
|
|
d2106a3d3a | ||
|
|
cf2f4dd0af | ||
|
|
608c2574bd | ||
|
|
f17db21bf0 | ||
|
|
b26bdd3c19 | ||
|
|
6a9c5d8f7e | ||
|
|
e59f28d659 | ||
|
|
07ae300e0c | ||
|
|
4c5f24c7a7 | ||
|
|
be810c5ba6 | ||
|
|
5ec3b590bf | ||
|
|
88313670c0 | ||
|
|
f9f68236bc | ||
|
|
dadb3a68d3 | ||
|
|
6121c06f15 | ||
|
|
b289d740e2 | ||
|
|
ec266ff52e | ||
|
|
ec773fe8cf | ||
|
|
a412149e2c | ||
|
|
deb7b01717 | ||
|
|
6966c26f27 | ||
|
|
a5e3d06412 | ||
|
|
eb3dcc2786 | ||
|
|
c76e88cad5 | ||
|
|
f588656dd5 | ||
|
|
35e48fb7b7 | ||
|
|
a069b6dbe1 | ||
|
|
48f934abf7 | ||
|
|
2172c8a503 | ||
|
|
cbf96d73ee | ||
|
|
7166aea1d7 | ||
|
|
93b400c4d7 | ||
|
|
a506a18970 | ||
|
|
5b273178f5 | ||
|
|
cde87ed4a3 |
+33
-16
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.181 2007/05/24 04:07:11 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
# This version string is only used in the version message printed
|
||||
@@ -51,6 +48,9 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
LEX = @LEX@
|
||||
YACC = @YACC@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
GIT = @GIT@
|
||||
|
||||
CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@
|
||||
CXXFLAGS = -Wall @CXXFLAGS@
|
||||
@@ -65,7 +65,7 @@ all: dep version.h ivl@EXEEXT@
|
||||
|
||||
# In the windows world, the installer will need a dosify program to
|
||||
# dosify text files.
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
all: dep dosify.exe
|
||||
dosify.exe: dosify.c
|
||||
$(CC) -o dosify.exe dosify.c
|
||||
@@ -99,15 +99,15 @@ distclean: clean
|
||||
TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
|
||||
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
|
||||
O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||
O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \
|
||||
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
|
||||
elab_sig.o emit.o eval.o eval_attrib.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o net_assign.o \
|
||||
net_design.o net_event.o net_expr.o net_force.o net_func.o \
|
||||
net_link.o net_modulo.o net_nex_input.o net_nex_output.o \
|
||||
net_proc.o net_scope.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_dump.o pform_types.o \
|
||||
net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \
|
||||
parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \
|
||||
set_width.o symbol_search.o sync.o sys_funcs.o \
|
||||
verinum.o verireal.o target.o targets.o \
|
||||
Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \
|
||||
@@ -174,22 +174,28 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||
lexor_keyword.o: lexor_keyword.cc parse.h
|
||||
|
||||
lexor_keyword.cc: lexor_keyword.gperf
|
||||
gperf -o -i 7 -C -k 1-3,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
gperf -o -i 7 -C -k 1-4,$$ -L ANSI-C -H keyword_hash -N check_identifier -t $(srcdir)/lexor_keyword.gperf > lexor_keyword.cc || (rm -f lexor_keyword.cc ; false)
|
||||
|
||||
iverilog-vpi.ps: $(srcdir)/iverilog-vpi.man
|
||||
man -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
$(MAN) -t $(srcdir)/iverilog-vpi.man > iverilog-vpi.ps
|
||||
|
||||
iverilog-vpi.pdf: iverilog-vpi.ps
|
||||
ps2pdf iverilog-vpi.ps iverilog-vpi.pdf
|
||||
$(PS2PDF) iverilog-vpi.ps iverilog-vpi.pdf
|
||||
|
||||
# For VERSION_TAG in driver/main.c, first try git-describe, then look for a
|
||||
# version.h file in the source tree (included in snapshots and releases), and
|
||||
# finally use nothing.
|
||||
.PHONY: version.h
|
||||
# "true" and "false" in the next few lines are Unix shell command names
|
||||
ifeq ($(GIT),none)
|
||||
GIT_PRESENT = false
|
||||
else
|
||||
GIT_PRESENT = true
|
||||
endif
|
||||
version.h:
|
||||
@if test -d $(srcdir)/.git; then \
|
||||
@if $(GIT_PRESENT) && test -d $(srcdir)/.git; then \
|
||||
echo "Using git-describe for VERSION_TAG"; \
|
||||
tmp=`git --git-dir $(srcdir)/.git describe \
|
||||
tmp=`$(GIT) --git-dir $(srcdir)/.git describe \
|
||||
| sed -e 's;\(.*\);#define VERSION_TAG "\1";'`; \
|
||||
echo "$$tmp" | diff - $@ > /dev/null 2>&1 || echo "$$tmp" > $@ || exit 1; \
|
||||
elif test -r $(srcdir)/$@; then \
|
||||
@@ -200,10 +206,18 @@ version.h:
|
||||
echo '#define VERSION_TAG ""' > $@; \
|
||||
fi
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog-vpi.pdf $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: dep iverilog-vpi.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog-vpi.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
@@ -217,7 +231,7 @@ endif
|
||||
|
||||
XNF_INSTALL = $(libdir)/ivl/xnf.conf $(libdir)/ivl/xnf-s.conf
|
||||
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
install: all installdirs $(libdir)/ivl/ivl@EXEEXT@ $(libdir)/ivl/include/constants.vams $(libdir)/ivl/include/disciplines.vams $(includedir)/ivl_target.h $(includedir)/_pli_types.h $(includedir)/vpi_user.h $(includedir)/acc_user.h $(includedir)/veriuser.h $(WIN32_INSTALL) $(INSTALL_DOC)
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
@@ -231,6 +245,9 @@ $(libdir)/ivl/ivl@EXEEXT@: ./ivl@EXEEXT@
|
||||
$(libdir)/ivl/include/constants.vams: $(srcdir)/constants.vams
|
||||
$(INSTALL_DATA) $(srcdir)/constants.vams $@
|
||||
|
||||
$(libdir)/ivl/include/disciplines.vams: $(srcdir)/disciplines.vams
|
||||
$(INSTALL_DATA) $(srcdir)/disciplines.vams $@
|
||||
|
||||
$(libdir)/ivl/xnf-s.conf: $(srcdir)/xnf-s.conf
|
||||
$(INSTALL_DATA) $(srcdir)/xnf-s.conf $(DESTDIR)$(libdir)/ivl/xnf-s.conf
|
||||
|
||||
@@ -286,7 +303,7 @@ uninstall:
|
||||
for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done
|
||||
for dir in vpi ivlpp driver; \
|
||||
do (cd $$dir ; $(MAKE) $@); done
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams; \
|
||||
for f in xnf.conf xnf-s.conf ivl@EXEEXT@ include/constants.vams include/disciplines.vams; \
|
||||
do rm -f $(DESTDIR)$(libdir)/ivl/$$f; done
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl/include
|
||||
-rmdir $(DESTDIR)$(libdir)/ivl
|
||||
|
||||
@@ -75,16 +75,35 @@ class Module : public PScope, public LineInfo {
|
||||
|
||||
NetNet::Type default_nettype;
|
||||
|
||||
struct range_t {
|
||||
// True if this is an exclude
|
||||
bool exclude_flag;
|
||||
// lower bound
|
||||
// If low_open_flag is false and low_expr=0, then use -inf
|
||||
bool low_open_flag;
|
||||
PExpr*low_expr;
|
||||
// upper bound
|
||||
// If high_open_flag is false and high_expr=0, then use +inf
|
||||
bool high_open_flag;
|
||||
PExpr*high_expr;
|
||||
// Next range description in list
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* The module has parameters that are evaluated when the
|
||||
module is elaborated. During parsing, I put the parameters
|
||||
into this map. */
|
||||
struct param_expr_t {
|
||||
PExpr*expr;
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), msb(0), lsb(0), signed_flag(false), expr(0), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
PExpr*msb;
|
||||
PExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
// Value expression
|
||||
PExpr*expr;
|
||||
// If there are range constrants, list them here
|
||||
range_t*range;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
@@ -158,8 +177,7 @@ class Module : public PScope, public LineInfo {
|
||||
map<perm_string,PFunction*> funcs_;
|
||||
|
||||
static void elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno);
|
||||
Design*des, NetScope*scope);
|
||||
|
||||
private: // Not implemented
|
||||
Module(const Module&);
|
||||
|
||||
@@ -306,6 +306,11 @@ class PEIdent : public PExpr {
|
||||
private:
|
||||
// Common functions to calculate parts of part/bit selects.
|
||||
bool calculate_parts_(Design*, NetScope*, long&msb, long&lsb) const;
|
||||
NetExpr* calculate_up_do_base_(Design*, NetScope*) const;
|
||||
bool calculate_param_range_(Design*, NetScope*,
|
||||
const NetExpr*msb_ex, long&msb,
|
||||
const NetExpr*lsb_ex, long&lsb) const;
|
||||
|
||||
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
|
||||
|
||||
private:
|
||||
@@ -321,6 +326,18 @@ class PEIdent : public PExpr {
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_part_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_param_idx_up_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const;
|
||||
NetExpr*elaborate_expr_net(Design*des,
|
||||
NetScope*scope,
|
||||
NetNet*net,
|
||||
|
||||
@@ -30,7 +30,7 @@ PWire::PWire(perm_string n,
|
||||
signed_(false), isint_(false),
|
||||
port_msb_(0), port_lsb_(0), port_set_(false),
|
||||
net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0),
|
||||
lidx_(0), ridx_(0)
|
||||
lidx_(0), ridx_(0), discipline_(0)
|
||||
{
|
||||
if (t == NetNet::INTEGER) {
|
||||
type_ = NetNet::REG;
|
||||
@@ -135,19 +135,6 @@ bool PWire::get_isint() const
|
||||
return isint_;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since implicitly defined list of port declarations are no longer
|
||||
* considered fully defined we no longer need this routine to force
|
||||
* them to be fully defined.
|
||||
*
|
||||
void PWire::set_net_range()
|
||||
{
|
||||
net_msb_ = port_msb_;
|
||||
net_lsb_ = port_lsb_;
|
||||
net_set_ = true;
|
||||
}
|
||||
*/
|
||||
|
||||
void PWire::set_range(PExpr*m, PExpr*l, PWSRType type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -211,3 +198,13 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx)
|
||||
}
|
||||
}
|
||||
|
||||
void PWire::set_discipline(discipline_t*d)
|
||||
{
|
||||
assert(discipline_ == 0);
|
||||
discipline_ = d;
|
||||
}
|
||||
|
||||
discipline_t* PWire::get_discipline(void) const
|
||||
{
|
||||
return discipline_;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ class ostream;
|
||||
|
||||
class PExpr;
|
||||
class Design;
|
||||
class discipline_t;
|
||||
|
||||
/*
|
||||
* The different type of PWire::set_range() calls.
|
||||
@@ -78,10 +79,12 @@ class PWire : public LineInfo {
|
||||
ivl_variable_type_t get_data_type() const;
|
||||
|
||||
void set_range(PExpr*msb, PExpr*lsb, PWSRType type);
|
||||
void set_net_range();
|
||||
|
||||
void set_memory_idx(PExpr*ldx, PExpr*rdx);
|
||||
|
||||
void set_discipline(discipline_t*);
|
||||
discipline_t* get_discipline(void) const;
|
||||
|
||||
map<perm_string,PExpr*> attributes;
|
||||
|
||||
// Write myself to the specified stream.
|
||||
@@ -112,6 +115,8 @@ class PWire : public LineInfo {
|
||||
PExpr*lidx_;
|
||||
PExpr*ridx_;
|
||||
|
||||
discipline_t*discipline_;
|
||||
|
||||
private: // not implemented
|
||||
PWire(const PWire&);
|
||||
PWire& operator= (const PWire&);
|
||||
|
||||
+1
-1
@@ -16,4 +16,4 @@ do
|
||||
done
|
||||
|
||||
echo "Precompiling lexor_keyword.gperf"
|
||||
gperf -o -i 7 -C -k 1-3,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
gperf -o -i 7 -C -k 1-4,\$ -L ANSI-C -H keyword_hash -N check_identifier -t ./lexor_keyword.gperf > lexor_keyword.cc
|
||||
|
||||
+2
-5
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.13 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -63,7 +60,7 @@ dep:
|
||||
O = cadpli.o
|
||||
|
||||
SYSTEM_VPI_LDFLAGS = -L../vvp -lvpi
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ extern bool debug_scopes;
|
||||
extern bool debug_eval_tree;
|
||||
extern bool debug_elaborate;
|
||||
extern bool debug_synth2;
|
||||
extern bool debug_optimizer;
|
||||
|
||||
/* Path to a directory useful for finding subcomponents. */
|
||||
extern const char*basedir;
|
||||
|
||||
@@ -9,6 +9,9 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_PROGS(XGPERF,gperf,none)
|
||||
AC_CHECK_PROGS(MAN,man,none)
|
||||
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||
AC_CHECK_PROGS(GIT,git,none)
|
||||
if test "$XGPERF" = "none"
|
||||
then
|
||||
echo ""
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "functor.h"
|
||||
# include "compiler.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
@@ -828,6 +829,32 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj)
|
||||
count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the select input is constant, then replace with a BUFZ */
|
||||
flag = obj->pin_Sel().nexus()->drivers_constant();
|
||||
verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
|
||||
if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
|
||||
tmp->set_line(*obj);
|
||||
|
||||
if (debug_optimizer)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Replace binary MUX with constant select=" << sel_val
|
||||
<< " with a BUFZ to the selected input." << endl;
|
||||
|
||||
tmp->rise_time(obj->rise_time());
|
||||
tmp->fall_time(obj->fall_time());
|
||||
tmp->decay_time(obj->decay_time());
|
||||
|
||||
connect(tmp->pin(0), obj->pin_Result());
|
||||
if (sel_val == verinum::V1)
|
||||
connect(tmp->pin(1), obj->pin_Data(1));
|
||||
else
|
||||
connect(tmp->pin(1), obj->pin_Data(0));
|
||||
delete obj;
|
||||
des->add_node(tmp);
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+75
-9
@@ -88,6 +88,34 @@ ostream& operator << (ostream&o, ivl_variable_type_t val)
|
||||
return o;
|
||||
}
|
||||
|
||||
ostream& operator << (ostream&o, ivl_switch_type_t val)
|
||||
{
|
||||
switch (val) {
|
||||
case IVL_SW_TRAN:
|
||||
o << "tran";
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
o << "tranif0";
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
o << "tranif1";
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
o << "rtran";
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
o << "rtranif0";
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
o << "rtranif1";
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
o << "tran(VP)";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static inline void dump_scope_path(ostream&o, const NetScope*scope)
|
||||
{
|
||||
if (const NetScope*parent = scope->parent()) {
|
||||
@@ -493,9 +521,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
|
||||
case PV:
|
||||
pt = "PV";
|
||||
break;
|
||||
case BI:
|
||||
pt = "BI";
|
||||
break;
|
||||
}
|
||||
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
|
||||
<< name();
|
||||
@@ -611,6 +636,20 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
|
||||
o << setw(ind) << "" << "endtask" << endl;
|
||||
}
|
||||
|
||||
void NetTran::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << type_ << " " << name()
|
||||
<< " island " << island;
|
||||
if (type_ == IVL_SW_TRAN_VP) {
|
||||
o << " width=" << vector_width()
|
||||
<< " part=" << part_width()
|
||||
<< " offset=" << part_offset();
|
||||
}
|
||||
o << endl;
|
||||
dump_node_pins(o, ind+4);
|
||||
dump_obj_attr(o, ind+4);
|
||||
}
|
||||
|
||||
void NetUDP::dump_node(ostream&o, unsigned ind) const
|
||||
{
|
||||
o << setw(ind) << "" << "UDP (" << udp_name() << "): ";
|
||||
@@ -966,8 +1005,37 @@ void NetScope::dump(ostream&o) const
|
||||
o << "[" << *(*pp).second.msb
|
||||
<< ":" << *(*pp).second.lsb << "] ";
|
||||
|
||||
o << (*pp).first << " = " <<
|
||||
*(*pp).second.expr << ";" << endl;
|
||||
o << (*pp).first << " = " << *(*pp).second.expr;
|
||||
|
||||
for (range_t*ran = (*pp).second.range ; ran ; ran = ran->next) {
|
||||
if (ran->exclude_flag)
|
||||
o << " exclude ";
|
||||
else
|
||||
o << " from ";
|
||||
|
||||
if (ran->low_open_flag)
|
||||
o << "(";
|
||||
else
|
||||
o << "[";
|
||||
if (ran->low_expr)
|
||||
o << *ran->low_expr;
|
||||
else if (ran->low_open_flag==false)
|
||||
o << "-inf";
|
||||
else
|
||||
o << "<?>";
|
||||
if (ran->high_expr)
|
||||
o << ":" << *ran->high_expr;
|
||||
else if (ran->high_open_flag==false)
|
||||
o << ":inf";
|
||||
else
|
||||
o << ":<?>";
|
||||
if (ran->high_open_flag)
|
||||
o << ")";
|
||||
else
|
||||
o << "]";
|
||||
}
|
||||
|
||||
o << ";" << endl;
|
||||
}
|
||||
|
||||
for (pp = localparams.begin()
|
||||
@@ -1261,11 +1329,9 @@ void NetESignal::dump(ostream&o) const
|
||||
void NetEParam::dump(ostream&o) const
|
||||
{
|
||||
if (scope_ != 0)
|
||||
o << "<" << scope_path(scope_) << "." << name_ << ">";
|
||||
else if (name_)
|
||||
o << "<" << name_ << ">";
|
||||
o << "<" << scope_path(scope_) << "." << (*reference_).first << ">";
|
||||
else
|
||||
o << "<" "???" ">";
|
||||
o << "<" << (*reference_).first << ">";
|
||||
}
|
||||
|
||||
void NetETernary::dump(ostream&o) const
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "discipline.h"
|
||||
|
||||
nature_t::nature_t(perm_string name, perm_string access)
|
||||
: name_(name), access_(access)
|
||||
{
|
||||
}
|
||||
|
||||
nature_t::~nature_t()
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::discipline_t(perm_string name, ddomain_t domain,
|
||||
nature_t*pot, nature_t*flow)
|
||||
: name_(name), domain_(domain), potential_(pot), flow_(flow)
|
||||
{
|
||||
}
|
||||
|
||||
discipline_t::~discipline_t()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef __discipline_H
|
||||
#define __discipline_H
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams ([email protected])
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* The discipline types include the discipline, nature and other
|
||||
* related types for managing declared and used disciplines in a
|
||||
* Verilog-AMS program.
|
||||
*/
|
||||
|
||||
# include "StringHeap.h"
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include "LineInfo.h"
|
||||
|
||||
typedef enum { DD_NONE, DD_DISCRETE, DD_CONTINUOUS } ddomain_t;
|
||||
extern std::ostream& operator << (std::ostream&, ddomain_t);
|
||||
|
||||
class nature_t : public LineInfo {
|
||||
public:
|
||||
explicit nature_t(perm_string name, perm_string access);
|
||||
~nature_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
// Identifier for the access function for this nature
|
||||
perm_string access() const { return access_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
perm_string access_;
|
||||
};
|
||||
|
||||
class discipline_t : public LineInfo {
|
||||
public:
|
||||
explicit discipline_t (perm_string name, ddomain_t dom,
|
||||
nature_t*pot, nature_t*flow);
|
||||
~discipline_t();
|
||||
|
||||
perm_string name() const { return name_; }
|
||||
ddomain_t domain() const { return domain_; }
|
||||
const nature_t*potential() const { return potential_; }
|
||||
const nature_t*flow() const { return flow_; }
|
||||
|
||||
private:
|
||||
perm_string name_;
|
||||
ddomain_t domain_;
|
||||
nature_t*potential_;
|
||||
nature_t*flow_;
|
||||
|
||||
private: // not implemented
|
||||
discipline_t(const discipline_t&);
|
||||
discipline_t& operator = (const discipline_t&);
|
||||
};
|
||||
|
||||
extern map<perm_string,nature_t*> natures;
|
||||
extern map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
// Standard definitions for Verilog-AMS
|
||||
`ifdef DISCIPLINES_VAMS
|
||||
`else
|
||||
`define DISCIPLINES_VAMS 1
|
||||
|
||||
discipline \logic ;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
discipline ddiscrete;
|
||||
domain discrete;
|
||||
enddiscipline
|
||||
|
||||
nature Current;
|
||||
units = "A";
|
||||
access = I;
|
||||
idt_nature = Charge;
|
||||
`ifdef CURRENT_ABSTOL
|
||||
abstol = `CURRENT_ABSTOL
|
||||
`else
|
||||
abstol = 1e-12;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Charge;
|
||||
units = "coul";
|
||||
access = Q;
|
||||
ddt_nature = Current;
|
||||
`ifdef CHARGE_ABSTOL
|
||||
abstol = `CHARGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-14;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Voltage;
|
||||
units = "V";
|
||||
access = V;
|
||||
idt_nature = Flux;
|
||||
`ifdef VOLTAGE_ABSTOL
|
||||
abstol = `VOLTAGE_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-6;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
nature Flux;
|
||||
units = "Wb";
|
||||
access = Phi;
|
||||
ddt_nature = Voltage;
|
||||
`ifdef FLUX_ABSTOL
|
||||
abstol = `flux_ABSTOL;
|
||||
`else
|
||||
abstol = 1e-9;
|
||||
`endif
|
||||
endnature
|
||||
|
||||
discipline electrical;
|
||||
potential Voltage;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
discipline voltage;
|
||||
potential Voltage;
|
||||
enddiscipline
|
||||
|
||||
discipline current;
|
||||
flow Current;
|
||||
enddiscipline
|
||||
|
||||
`endif // !`ifdef DISCIPLINES_VAMS
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.7.2.1 2006/10/04 17:08:59 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.8.3
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: iverilog-vpi@EXEEXT@
|
||||
|
||||
check: all
|
||||
|
||||
clean:
|
||||
rm -f *.o config.h
|
||||
rm -f iverilog-vpi@EXEEXT@
|
||||
|
||||
+8
-8
@@ -336,6 +336,14 @@ static int parse(int argc, char *argv[])
|
||||
assignn(&gstr.pOUT, argv[idx],
|
||||
strlen(argv[idx])-strlen(dot_o_ext));
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --name option */
|
||||
else if (startsWith(name_option, argv[idx])) {
|
||||
assignn(&gstr.pOUT, argv[idx]+sizeof(name_option)-1,
|
||||
@@ -356,14 +364,6 @@ static int parse(int argc, char *argv[])
|
||||
append(&gstr.pDEFS, " ");
|
||||
append(&gstr.pDEFS, argv[idx]);
|
||||
}
|
||||
/* Check for the -mingw option */
|
||||
else if (startsWith(mingw_option, argv[idx]))
|
||||
assignn(&gstr.pMINGW, argv[idx]+sizeof(mingw_option)-1,
|
||||
strlen(argv[idx])-(sizeof(mingw_option)-1));
|
||||
/* Check for the -ivl option */
|
||||
else if (startsWith(ivl_option, argv[idx]))
|
||||
assignn(&gstr.pIVL, argv[idx]+sizeof(ivl_option)-1,
|
||||
strlen(argv[idx])-(sizeof(ivl_option)-1));
|
||||
/* Check for the --cflags option */
|
||||
else if (stricmp("--cflags", argv[idx]) == 0) {
|
||||
setup_ivl_environment();
|
||||
|
||||
+14
-7
@@ -16,9 +16,6 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.26 2007/02/06 05:07:31 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.9.devel
|
||||
@@ -41,6 +38,8 @@ CC = @CC@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
|
||||
CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@
|
||||
CFLAGS = -Wall @CFLAGS@
|
||||
@@ -76,15 +75,23 @@ cflexor.o: cflexor.c cfparse.h cfparse_misc.h globals.h
|
||||
cfparse.o: cfparse.c globals.h cfparse_misc.h
|
||||
|
||||
iverilog.ps: $(srcdir)/iverilog.man
|
||||
man -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
$(MAN) -t $(srcdir)/iverilog.man > iverilog.ps
|
||||
|
||||
iverilog.pdf: iverilog.ps
|
||||
ps2pdf iverilog.ps iverilog.pdf
|
||||
$(PS2PDF) iverilog.ps iverilog.pdf
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/iverilog.pdf $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: iverilog.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/iverilog.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
|
||||
@@ -327,6 +327,9 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||
remove(defines_path);
|
||||
remove(compiled_defines_path);
|
||||
}
|
||||
#ifdef __MINGW32__ /* MinGW just returns the exit status, so return it! */
|
||||
return rc;
|
||||
#else
|
||||
|
||||
if (rc != 0) {
|
||||
if (rc == 127) {
|
||||
@@ -342,6 +345,7 @@ static int t_default(char*cmd, unsigned ncmd)
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
+263
-105
@@ -716,6 +716,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
if (!rep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << rep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
concat_depth -= 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << rep->value().as_long()
|
||||
@@ -873,6 +882,51 @@ bool PEIdent::calculate_up_do_width_(Design*des, NetScope*scope,
|
||||
return flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we know that this is an indexed part select (up or down) this
|
||||
* method calculates the up/down base, as far at it can be calculated.
|
||||
*/
|
||||
NetExpr* PEIdent::calculate_up_do_base_(Design*des, NetScope*scope) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*tmp = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool PEIdent::calculate_param_range_(Design*des, NetScope*scope,
|
||||
const NetExpr*par_msb, long&par_msv,
|
||||
const NetExpr*par_lsb, long&par_lsv) const
|
||||
{
|
||||
if (par_msb == 0) {
|
||||
// If the parameter doesn't have an explicit range, then
|
||||
// just return range values of 0:0. The par_msv==0 is
|
||||
// correct. The par_msv is not necessarily correct, but
|
||||
// clients of this function don't need a correct value.
|
||||
ivl_assert(*this, par_lsb == 0);
|
||||
par_msv = 0;
|
||||
par_lsv = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
const NetEConst*tmp = dynamic_cast<const NetEConst*> (par_msb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_msv = tmp->value().as_long();
|
||||
|
||||
tmp = dynamic_cast<const NetEConst*> (par_lsb);
|
||||
ivl_assert(*this, tmp);
|
||||
|
||||
par_lsv = tmp->value().as_long();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned PEIdent::test_width(Design*des, NetScope*scope,
|
||||
unsigned min, unsigned lval,
|
||||
bool&unsized_flag) const
|
||||
@@ -1085,6 +1139,131 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static verinum param_part_select_bits(const verinum&par_val, long wid,
|
||||
long lsv, long par_lsv)
|
||||
{
|
||||
verinum result (verinum::Vx, wid, true);
|
||||
|
||||
for (long idx = 0 ; idx < wid ; idx += 1) {
|
||||
long off = idx + lsv - par_lsv;
|
||||
if (off < 0)
|
||||
result.set(idx, verinum::Vx);
|
||||
else if (off < (long)par_val.len())
|
||||
result.set(idx, par_val.get(off));
|
||||
else if (par_val.is_string()) // Pad strings with nulls.
|
||||
result.set(idx, verinum::V0);
|
||||
else if (par_val.has_len()) // Pad sized parameters with X
|
||||
result.set(idx, verinum::Vx);
|
||||
else // Unsized parameters are "infinite" width.
|
||||
result.set(idx, sign_bit(par_val));
|
||||
}
|
||||
|
||||
// If the input is a string, and the part select is working on
|
||||
// byte boundaries, then make the result into a string.
|
||||
if (par_val.is_string() && (labs(lsv-par_lsv)%8 == 0) && (wid%8 == 0))
|
||||
return result.as_string();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_part_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
long msv, lsv;
|
||||
bool flag = calculate_parts_(des, scope, msv, lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
long par_msv, par_lsv;
|
||||
flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
// Notice that the par_msv is not used is this function other
|
||||
// then for this test. It is used to tell the direction that
|
||||
// the bits are numbers, so that we can make sure the
|
||||
// direction matches the part select direction. After that,
|
||||
// we only need the par_lsv.
|
||||
if (msv>lsv && par_msv<par_lsv || msv<lsv && par_msv>=par_lsv) {
|
||||
cerr << get_fileline() << ": error: Part select "
|
||||
<< "[" << msv << ":" << lsv << "] is out of order." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << msv << ":" << lsv << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid, lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope,
|
||||
const NetExpr*par,
|
||||
NetScope*found_in,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
|
||||
long par_msv, par_lsv;
|
||||
bool flag = calculate_param_range_(des, scope, par_msb, par_msv, par_lsb, par_lsv);
|
||||
if (!flag)
|
||||
return 0;
|
||||
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
if (base == 0)
|
||||
return 0;
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
|
||||
const NetEConst*par_ex = dynamic_cast<const NetEConst*> (par);
|
||||
ivl_assert(*this, par_ex);
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: Calculate part select "
|
||||
<< "[" << *base << "+:" << wid << "] from range "
|
||||
<< "[" << par_msv << ":" << par_lsv << "]." << endl;
|
||||
|
||||
// Handle the special case that the base is constant. In this
|
||||
// case, just precalculate the entire constant result.
|
||||
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
|
||||
long lsv = base_c->value().as_long();
|
||||
|
||||
// Watch out for reversed bit numbering. We're making
|
||||
// the part select from LSB to MSB.
|
||||
if (par_msv < par_lsv)
|
||||
lsv = lsv - wid + 1;
|
||||
|
||||
verinum result = param_part_select_bits(par_ex->value(), wid,
|
||||
lsv, par_lsv);
|
||||
NetEConst*result_ex = new NetEConst(result);
|
||||
result_ex->set_line(*this);
|
||||
return result_ex;
|
||||
}
|
||||
|
||||
if ((par_msb < par_lsb) && (wid>1))
|
||||
base = make_add_expr(base, 1-(long)wid);
|
||||
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
tmp = new NetESelect(tmp, base, wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the case that the identifier is a parameter reference. The
|
||||
* parameter expression has already been located for us (as the par
|
||||
@@ -1097,84 +1276,29 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des,
|
||||
const NetExpr*par_msb,
|
||||
const NetExpr*par_lsb) const
|
||||
{
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
const name_component_t&name_tail = path_.back();
|
||||
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
|
||||
if (!name_tail.index.empty())
|
||||
use_sel = name_tail.index.back().sel;
|
||||
|
||||
if (use_sel == index_component_t::SEL_PART) {
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.msb);
|
||||
ivl_assert(*this, index_tail.lsb);
|
||||
// NOTE TO SELF: This is the way I want to see this code
|
||||
// structured. This closely follows the structure of the
|
||||
// elaborate_expr_net_ code, which splits all the various
|
||||
// selects to different methods.
|
||||
if (use_sel == index_component_t::SEL_PART)
|
||||
return elaborate_expr_param_part_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
/* If the identifier has a part select, we support
|
||||
it by pulling the right bits out and making a
|
||||
sized unsigned constant. This code assumes the
|
||||
lsb of a parameter is 0 and the msb is the
|
||||
width of the parameter. */
|
||||
if (use_sel == index_component_t::SEL_IDX_UP)
|
||||
return elaborate_expr_param_idx_up_(des, scope, par, found_in,
|
||||
par_msb, par_lsb);
|
||||
|
||||
verinum*lsn = index_tail.lsb->eval_const(des, scope);
|
||||
verinum*msn = index_tail.msb->eval_const(des, scope);
|
||||
if ((lsn == 0) || (msn == 0)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
"Part select expressions must be "
|
||||
"constant expressions." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
// NOTE TO SELF (continued): The code below should be
|
||||
// rewritten in the above format, as I get to it.
|
||||
|
||||
long lsb = lsn->as_long();
|
||||
long msb = msn->as_long();
|
||||
if ((lsb < 0) || (msb < lsb)) {
|
||||
cerr << get_fileline() << ": error: invalid part "
|
||||
<< "select: " << path_
|
||||
<< "["<<msb<<":"<<lsb<<"]" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
unsigned long ulsb=lsb;
|
||||
unsigned long umsb=msb;
|
||||
NetExpr*tmp = par->dup_expr();
|
||||
|
||||
NetEConst*le = dynamic_cast<NetEConst*>(tmp);
|
||||
assert(le);
|
||||
|
||||
verinum result (verinum::V0, msb-lsb+1, true);
|
||||
verinum exl = le->value();
|
||||
|
||||
/* Pull the bits from the parameter, one at a
|
||||
time. If the bit is within the range, simply
|
||||
copy it to the result. If the bit is outside
|
||||
the range, we sign extend signed unsized
|
||||
numbers, zero extend unsigned unsigned numbers,
|
||||
and X extend sized numbers. */
|
||||
for (unsigned long idx = ulsb ; idx <= umsb ; idx += 1) {
|
||||
if (idx < exl.len())
|
||||
result.set(idx-lsb, exl.get(idx));
|
||||
else if (exl.is_string())
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
else if (exl.has_len())
|
||||
result.set(idx-lsb, verinum::Vx);
|
||||
else if (exl.has_sign())
|
||||
result.set(idx-lsb, exl.get(exl.len()-1));
|
||||
else
|
||||
result.set(idx-lsb, verinum::V0);
|
||||
}
|
||||
|
||||
/* If the input is a string, and the part select
|
||||
is working on byte boundaries, then the result
|
||||
can be made into a string. */
|
||||
if (exl.is_string()
|
||||
&& (lsb%8 == 0)
|
||||
&& (result.len()%8 == 0))
|
||||
result = verinum(result.as_string());
|
||||
|
||||
delete tmp;
|
||||
tmp = new NetEConst(result);
|
||||
|
||||
} else if (use_sel == index_component_t::SEL_IDX_UP || use_sel == index_component_t::SEL_IDX_DO) {
|
||||
if (use_sel == index_component_t::SEL_IDX_DO) {
|
||||
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
@@ -1361,8 +1485,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope,
|
||||
// Special case: The index is out of range, so the value
|
||||
// of this expression is a 'bx vector the width of a word.
|
||||
if (!net->array_index_is_valid(addr)) {
|
||||
verinum xxx (verinum::Vx, net->vector_width());
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
NetEConst*resx = make_const_x(net->vector_width());
|
||||
resx->set_line(*this);
|
||||
delete word_index;
|
||||
return resx;
|
||||
@@ -1428,16 +1551,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
negative values. However, the width that they represent is
|
||||
unsigned. Remember that any order is possible,
|
||||
i.e., [1:0], [-4:6], etc. */
|
||||
unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv));
|
||||
if (wid > net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
ivl_assert(*this, wid <= net->vector_width());
|
||||
unsigned long wid = 1 + labs(msv-lsv);
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
@@ -1448,27 +1562,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
return net;
|
||||
}
|
||||
|
||||
|
||||
if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) {
|
||||
cerr << get_fileline() << ": error: part select ["
|
||||
<< msv << ":" << lsv << "] out of range." << endl;
|
||||
des->errors += 1;
|
||||
//delete lsn;
|
||||
//delete msn;
|
||||
return net;
|
||||
}
|
||||
long sb_lsb = net->sig()->sb_to_idx(lsv);
|
||||
long sb_msb = net->sig()->sb_to_idx(msv);
|
||||
|
||||
// If the part select covers exactly the entire
|
||||
// vector, then do not bother with it. Return the
|
||||
// signal itself.
|
||||
if (net->sig()->sb_to_idx(lsv) == 0 && wid == net->vector_width())
|
||||
if (sb_lsb == 0 && wid == net->vector_width())
|
||||
return net;
|
||||
|
||||
NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv)));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
// If the part select covers NONE of the vector, then return a
|
||||
// constant X.
|
||||
|
||||
return ss;
|
||||
if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) {
|
||||
NetEConst*tmp = make_const_x(wid);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the part select is entirely within the vector, then make
|
||||
// a simple part select.
|
||||
if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) {
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
// Now the hard stuff. The part select is falling off at least
|
||||
// one end. We're going to need a NetEConcat to mix the
|
||||
// selection with overrun.
|
||||
|
||||
NetEConst*bot = 0;
|
||||
if (sb_lsb < 0) {
|
||||
bot = make_const_x( 0-sb_lsb );
|
||||
bot->set_line(*this);
|
||||
sb_lsb = 0;
|
||||
}
|
||||
NetEConst*top = 0;
|
||||
if (sb_msb >= (signed)net->vector_width()) {
|
||||
top = make_const_x( 1+sb_msb-net->vector_width() );
|
||||
top->set_line(*this);
|
||||
sb_msb = net->vector_width()-1;
|
||||
}
|
||||
|
||||
unsigned concat_count = 1;
|
||||
if (bot) concat_count += 1;
|
||||
if (top) concat_count += 1;
|
||||
|
||||
NetEConcat*concat = new NetEConcat(concat_count);
|
||||
concat->set_line(*this);
|
||||
|
||||
if (bot) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, bot);
|
||||
}
|
||||
if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, net);
|
||||
} else {
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
ex->set_line(*this);
|
||||
NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb);
|
||||
ss->set_line(*this);
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, ss);
|
||||
}
|
||||
if (top) {
|
||||
concat_count -= 1;
|
||||
concat->set(concat_count, top);
|
||||
}
|
||||
ivl_assert(*this, concat_count==0);
|
||||
|
||||
return concat;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1477,14 +1643,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
||||
NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
|
||||
NetESignal*net, NetScope*found_in) const
|
||||
{
|
||||
const name_component_t&name_tail = path_.back();
|
||||
ivl_assert(*this, !name_tail.index.empty());
|
||||
|
||||
const index_component_t&index_tail = name_tail.index.back();
|
||||
ivl_assert(*this, index_tail.lsb != 0);
|
||||
ivl_assert(*this, index_tail.msb != 0);
|
||||
|
||||
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
|
||||
NetExpr*base = calculate_up_do_base_(des, scope);
|
||||
|
||||
unsigned long wid = 0;
|
||||
calculate_up_do_width_(des, scope, wid);
|
||||
@@ -1609,8 +1768,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
|
||||
/* The bit select is out of range of the
|
||||
vector. This is legal, but returns a
|
||||
constant 1'bx value. */
|
||||
verinum x (verinum::Vx);
|
||||
NetEConst*tmp = new NetEConst(x);
|
||||
NetEConst*tmp = make_const_x(1);
|
||||
tmp->set_line(*this);
|
||||
|
||||
cerr << get_fileline() << ": warning: Bit select ["
|
||||
|
||||
+69
-31
@@ -1578,6 +1578,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!erep->value().is_defined()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be undefined (" << erep->value()
|
||||
<< ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (erep->value().is_negative()) {
|
||||
cerr << get_fileline() << ": error: Concatenation repeat "
|
||||
<< "may not be negative (" << erep->value().as_long()
|
||||
@@ -2367,30 +2375,53 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
osig->local_flag(true);
|
||||
osig->set_line(*this);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
if (bidirectional_flag) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating tran(VP) "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetTran*ps = new NetTran(scope, scope->local_symbol(),
|
||||
osig->vector_width(), wid, off);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(0), osig->pin(0));
|
||||
connect(ps->pin(1), nets[idx]->pin(0));
|
||||
|
||||
ivl_assert(*this, wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": debug: Generating part selects "
|
||||
<< "to connect input l-value to subexpressions."
|
||||
<< endl;
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
ps->set_line(*this);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
}
|
||||
|
||||
NetPartSelect::dir_t part_dir = bidirectional_flag
|
||||
? NetPartSelect::BI
|
||||
: NetPartSelect::VP;
|
||||
|
||||
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
|
||||
unsigned wid = nets[idx]->vector_width();
|
||||
unsigned off = width - wid;
|
||||
NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
|
||||
des->add_node(ps);
|
||||
|
||||
connect(ps->pin(1), osig->pin(0));
|
||||
connect(ps->pin(0), nets[idx]->pin(0));
|
||||
|
||||
assert(wid <= width);
|
||||
width -= wid;
|
||||
}
|
||||
assert(width == 0);
|
||||
|
||||
osig->data_type(nets[0]->data_type());
|
||||
osig->local_flag(true);
|
||||
return osig;
|
||||
@@ -2743,11 +2774,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
/* If we are processing a tran or inout, then the
|
||||
partselect is bi-directional. Otherwise, it is a
|
||||
Part-to-Vector select. */
|
||||
NetPartSelect::dir_t part_dir;
|
||||
if (bidirectional_flag)
|
||||
part_dir = NetPartSelect::BI;
|
||||
else
|
||||
part_dir = NetPartSelect::PV;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
@@ -2764,11 +2790,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
subsig->local_flag(true);
|
||||
subsig->set_line(*this);
|
||||
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
part_dir);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
if (bidirectional_flag) {
|
||||
// Make a tran(VP)
|
||||
NetTran*sub = new NetTran(scope, scope->local_symbol(),
|
||||
sig->vector_width(),
|
||||
subnet_wid, lidx);
|
||||
sub->set_line(*this);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), sig->pin(0));
|
||||
connect(sub->pin(1), subsig->pin(0));
|
||||
|
||||
} else {
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
NetPartSelect::PV);
|
||||
des->add_node(sub);
|
||||
sub->set_line(*this);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
}
|
||||
sig = subsig;
|
||||
}
|
||||
|
||||
|
||||
+49
-15
@@ -22,6 +22,7 @@
|
||||
# include "netmisc.h"
|
||||
# include <cstring>
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
# include <stdio.h>
|
||||
|
||||
/*
|
||||
@@ -43,10 +44,10 @@
|
||||
# include "util.h"
|
||||
# include <typeinfo>
|
||||
# include <assert.h>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
Design*des, NetScope*scope,
|
||||
perm_string file, unsigned lineno)
|
||||
Design*des, NetScope*scope)
|
||||
{
|
||||
PExpr*ex = cur.expr;
|
||||
assert(ex);
|
||||
@@ -63,9 +64,11 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
parameter value is coerced to have the correct
|
||||
and defined width. */
|
||||
if (cur.msb) {
|
||||
assert(cur.lsb);
|
||||
msb = cur.msb ->elaborate_pexpr(des, scope);
|
||||
assert(msb);
|
||||
lsb = cur.lsb ->elaborate_pexpr(des, scope);
|
||||
assert(lsb);
|
||||
}
|
||||
|
||||
if (signed_flag) {
|
||||
@@ -81,8 +84,41 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur,
|
||||
signed_flag = val->has_sign();
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val,
|
||||
msb, lsb, signed_flag, file, lineno);
|
||||
NetScope::range_t*range_list = 0;
|
||||
for (Module::range_t*range = cur.range ; range ; range = range->next) {
|
||||
NetScope::range_t*tmp = new NetScope::range_t;
|
||||
tmp->exclude_flag = range->exclude_flag;
|
||||
tmp->low_open_flag = range->low_open_flag;
|
||||
tmp->high_open_flag = range->high_open_flag;
|
||||
|
||||
if (range->low_expr) {
|
||||
tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1);
|
||||
ivl_assert(*range->low_expr, tmp->low_expr);
|
||||
} else {
|
||||
tmp->low_expr = 0;
|
||||
}
|
||||
|
||||
if (range->high_expr && range->high_expr==range->low_expr) {
|
||||
// Detect the special case of a "point"
|
||||
// range. These are called out by setting the high
|
||||
// and low expression ranges to the same
|
||||
// expression. The exclude_flags should be false
|
||||
// in this case
|
||||
ivl_assert(*range->high_expr, tmp->low_open_flag==false && tmp->high_open_flag==false);
|
||||
tmp->high_expr = tmp->low_expr;
|
||||
|
||||
} else if (range->high_expr) {
|
||||
tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1);
|
||||
ivl_assert(*range->high_expr, tmp->high_expr);
|
||||
} else {
|
||||
tmp->high_expr = 0;
|
||||
}
|
||||
|
||||
tmp->next = range_list;
|
||||
range_list = tmp;
|
||||
}
|
||||
|
||||
val = scope->set_parameter(name, val, cur.type, msb, lsb, signed_flag, range_list, cur);
|
||||
assert(val);
|
||||
delete val;
|
||||
}
|
||||
@@ -120,8 +156,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
tmp->set_line(*((*cur).second.expr));
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
@@ -132,8 +168,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
if ((*cur).second.msb)
|
||||
tmp->cast_signed( (*cur).second.signed_flag );
|
||||
|
||||
scope->set_parameter((*cur).first, tmp, 0, 0, false,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
scope->set_parameter((*cur).first, tmp, (*cur).second.type,
|
||||
0, 0, false, 0, (*cur).second);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +181,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
}
|
||||
|
||||
/* run parameter replacements that were collected from the
|
||||
@@ -166,6 +201,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
<< "Replace " << (*cur).first
|
||||
<< " with expression " << *val
|
||||
<< " from " << val->get_fileline() << "." << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "Type=" << val->expr_type() << endl;
|
||||
}
|
||||
bool flag = scope->replace_parameter((*cur).first, val);
|
||||
if (! flag) {
|
||||
@@ -178,8 +215,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
||||
for (mparm_it_t cur = localparams.begin()
|
||||
; cur != localparams.end() ; cur ++) {
|
||||
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope,
|
||||
(*cur).second.file, (*cur).second.lineno);
|
||||
elaborate_parm_item_((*cur).first, (*cur).second, des, scope);
|
||||
}
|
||||
|
||||
// Run through the defparams for this module, elaborate the
|
||||
@@ -421,9 +457,7 @@ bool PGenerate::generate_scope_loop_(Design*des, NetScope*container)
|
||||
genvar_verinum);
|
||||
// The file and line information should really come
|
||||
// from the genvar statement, not the for loop.
|
||||
scope->set_localparam(loop_index, gp, get_file(),
|
||||
get_lineno());
|
||||
|
||||
scope->set_localparam(loop_index, gp, *this);
|
||||
if (debug_scopes)
|
||||
cerr << get_fileline() << ": debug: "
|
||||
<< "Create implicit localparam "
|
||||
|
||||
+101
-15
@@ -419,7 +419,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
/* Allocate all the netlist nodes for the gates. */
|
||||
NetLogic**cur = new NetLogic*[count];
|
||||
NetNode**cur = new NetNode*[count];
|
||||
assert(cur);
|
||||
|
||||
/* Calculate the gate delays from the delay expressions
|
||||
@@ -659,6 +659,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx] = new NetLogic(scope, inm, pin_count(),
|
||||
NetLogic::XOR, instance_width);
|
||||
break;
|
||||
case TRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN);
|
||||
}
|
||||
break;
|
||||
case RTRAN:
|
||||
if (pin_count() != 2) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtran device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0);
|
||||
}
|
||||
break;
|
||||
case RTRANIF0:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif0 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0);
|
||||
}
|
||||
break;
|
||||
case TRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "tranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1);
|
||||
}
|
||||
break;
|
||||
case RTRANIF1:
|
||||
if (pin_count() != 3) {
|
||||
cerr << get_fileline() << ": error: Pin count for "
|
||||
<< "rtranif1 device." << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
} else {
|
||||
cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cerr << get_fileline() << ": internal error: unhandled "
|
||||
"gate type." << endl;
|
||||
@@ -670,13 +731,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
cur[idx]->attribute(attrib_list[adx].key,
|
||||
attrib_list[adx].val);
|
||||
|
||||
cur[idx]->rise_time(rise_time);
|
||||
cur[idx]->fall_time(fall_time);
|
||||
cur[idx]->decay_time(decay_time);
|
||||
/* The logic devices have some uniform processing. Then
|
||||
all may have output delays and output drive strength. */
|
||||
if (NetLogic*log = dynamic_cast<NetLogic*> (cur[idx])) {
|
||||
log->rise_time(rise_time);
|
||||
log->fall_time(fall_time);
|
||||
log->decay_time(decay_time);
|
||||
|
||||
cur[idx]->pin(0).drive0(drive_type(strength0()));
|
||||
cur[idx]->pin(0).drive1(drive_type(strength1()));
|
||||
log->pin(0).drive0(drive_type(strength0()));
|
||||
log->pin(0).drive1(drive_type(strength1()));
|
||||
}
|
||||
|
||||
cur[idx]->set_line(*this);
|
||||
des->add_node(cur[idx]);
|
||||
}
|
||||
|
||||
@@ -798,6 +864,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// "cur" is an array of pointers, and we don't need it any more.
|
||||
delete[]cur;
|
||||
}
|
||||
|
||||
NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
@@ -812,6 +881,31 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
tmp->local_flag(true);
|
||||
tmp->set_line(*sig);
|
||||
|
||||
// Handle the special case of a bi-directional part
|
||||
// select. Create a NetTran(VP) instead of a uni-directional
|
||||
// NetPartSelect node.
|
||||
if (dir == NetNet::PINOUT) {
|
||||
unsigned wida = sig->vector_width();
|
||||
unsigned widb = tmp->vector_width();
|
||||
bool part_b = widb < wida;
|
||||
NetTran*node = new NetTran(scope, scope->local_symbol(),
|
||||
part_b? wida : widb,
|
||||
part_b? widb : wida,
|
||||
0);
|
||||
if (part_b) {
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
connect(node->pin(1), tmp->pin(0));
|
||||
} else {
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
connect(node->pin(1), sig->pin(0));
|
||||
}
|
||||
|
||||
node->set_line(*this);
|
||||
des->add_node(node);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetPartSelect*node = 0;
|
||||
|
||||
switch (dir) {
|
||||
@@ -840,15 +934,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
|
||||
break;
|
||||
|
||||
case NetNet::PINOUT:
|
||||
if (sig->vector_width() > tmp->vector_width()) {
|
||||
node = new NetPartSelect(sig, 0, tmp->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), tmp->pin(0));
|
||||
} else {
|
||||
node = new NetPartSelect(tmp, 0, sig->vector_width(),
|
||||
NetPartSelect::BI);
|
||||
connect(node->pin(0), sig->pin(0));
|
||||
}
|
||||
ivl_assert(*this, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -165,6 +165,11 @@ bool NetUserFunc::emit_node(struct target_t*tgt) const
|
||||
return tgt->net_function(this);
|
||||
}
|
||||
|
||||
bool NetTran::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->tran(this);
|
||||
}
|
||||
|
||||
bool NetBUFZ::emit_node(struct target_t*tgt) const
|
||||
{
|
||||
return tgt->bufz(this);
|
||||
|
||||
+12
-20
@@ -1171,17 +1171,9 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
}
|
||||
|
||||
assert(scope_);
|
||||
const NetExpr*expr_msb;
|
||||
const NetExpr*expr_lsb;
|
||||
const NetExpr*expr = scope_->get_parameter(name_, expr_msb, expr_lsb);
|
||||
if (expr == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to match "
|
||||
<< "parameter " << name_ << " in scope "
|
||||
<< scope_path(scope_) << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(expr);
|
||||
perm_string name = (*reference_).first;
|
||||
const NetExpr*expr = (*reference_).second.expr;
|
||||
ivl_assert(*this, expr);
|
||||
|
||||
NetExpr*nexpr = expr->dup_expr();
|
||||
assert(nexpr);
|
||||
@@ -1190,7 +1182,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
// return the constant value.
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(nexpr)) {
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1198,7 +1190,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(nexpr)) {
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
ptmp->set_line(*this);
|
||||
delete nexpr;
|
||||
return ptmp;
|
||||
@@ -1209,7 +1201,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
NetExpr*res = nexpr->eval_tree();
|
||||
if (res == 0) {
|
||||
cerr << get_fileline() << ": internal error: Unable to evaluate "
|
||||
<< "parameter " << name_ << " expression: "
|
||||
<< "parameter " << name << " expression: "
|
||||
<< *nexpr << endl;
|
||||
delete nexpr;
|
||||
return 0;
|
||||
@@ -1217,10 +1209,10 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
|
||||
// The result can be saved as the value of the parameter for
|
||||
// future reference, and return a copy to the caller.
|
||||
bool flag = scope_->replace_parameter(name_, res);
|
||||
bool flag = scope_->replace_parameter(name, res);
|
||||
if (!flag) {
|
||||
cerr << get_fileline() << ": internal error: Could not "
|
||||
<< "replace parameter expression for " << name_ << endl;
|
||||
<< "replace parameter expression for " << name << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1234,7 +1226,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetEConst*tmp = dynamic_cast<NetEConst*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1242,7 +1234,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verinum val = tmp->value();
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name_, val);
|
||||
NetEConstParam*ptmp = new NetEConstParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
@@ -1251,7 +1243,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
{ NetECReal*tmp = dynamic_cast<NetECReal*>(res);
|
||||
if (tmp == 0) {
|
||||
cerr << get_fileline() << ": internal error: parameter "
|
||||
<< name_ << " evaluates to incomprehensible "
|
||||
<< name << " evaluates to incomprehensible "
|
||||
<< *res << "." << endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -1259,7 +1251,7 @@ NetExpr* NetEParam::eval_tree(int prune_to_width)
|
||||
assert(tmp);
|
||||
|
||||
verireal val = tmp->value();
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name_, val);
|
||||
NetECRealParam*ptmp = new NetECRealParam(scope_, name, val);
|
||||
|
||||
return ptmp;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ ivl_file_table_index
|
||||
ivl_file_table_item
|
||||
ivl_file_table_size
|
||||
|
||||
ivl_island_flag_set
|
||||
ivl_island_flag_test
|
||||
|
||||
ivl_logic_attr
|
||||
ivl_logic_attr_cnt
|
||||
ivl_logic_attr_val
|
||||
@@ -115,6 +118,7 @@ ivl_nexus_ptr_pin
|
||||
ivl_nexus_ptr_lpm
|
||||
ivl_nexus_ptr_log
|
||||
ivl_nexus_ptr_sig
|
||||
ivl_nexus_ptr_switch
|
||||
|
||||
ivl_parameter_basename
|
||||
ivl_parameter_expr
|
||||
@@ -152,6 +156,8 @@ ivl_scope_port
|
||||
ivl_scope_ports
|
||||
ivl_scope_sigs
|
||||
ivl_scope_sig
|
||||
ivl_scope_switch
|
||||
ivl_scope_switches
|
||||
ivl_scope_time_precision
|
||||
ivl_scope_time_units
|
||||
ivl_scope_type
|
||||
@@ -216,6 +222,19 @@ ivl_stmt_parm_count
|
||||
ivl_stmt_rval
|
||||
ivl_stmt_sub_stmt
|
||||
|
||||
ivl_switch_a
|
||||
ivl_switch_b
|
||||
ivl_switch_basename
|
||||
ivl_switch_enable
|
||||
ivl_switch_file
|
||||
ivl_switch_island
|
||||
ivl_switch_lineno
|
||||
ivl_switch_offset
|
||||
ivl_switch_part
|
||||
ivl_switch_scope
|
||||
ivl_switch_type
|
||||
ivl_switch_width
|
||||
|
||||
ivl_udp_init
|
||||
ivl_udp_name
|
||||
ivl_udp_nin
|
||||
|
||||
+84
-1
@@ -80,6 +80,13 @@ _BEGIN_DECL
|
||||
* processes. Structural expressions are instead treated as logic
|
||||
* gates.
|
||||
*
|
||||
* ivl_island_t
|
||||
* Certain types of objects may belong to islands. The island that
|
||||
* they belong to is represented by the ivl_island_t cookie. To
|
||||
* know if object belong to the same island, it is sufficient to
|
||||
* compare island cookies. If a==b, then island a is the same as
|
||||
* island b.
|
||||
*
|
||||
* ivl_lpm_t
|
||||
* This object is the base class for all the various LPM type
|
||||
* device nodes. This object carries a few base properties
|
||||
@@ -123,6 +130,9 @@ _BEGIN_DECL
|
||||
* ivl_process_t object holds one of these, but a statement may in
|
||||
* turn contain other statements.
|
||||
*
|
||||
* ivl_switch_t
|
||||
* Switches are the tran/tranif devices in the design.
|
||||
*
|
||||
* -- A Note About Bit Sets --
|
||||
* Some objects hold a value as an array of bits. In these cases there
|
||||
* is some method that retrieves the width of the value and another
|
||||
@@ -143,6 +153,7 @@ typedef struct ivl_delaypath_s*ivl_delaypath_t;
|
||||
typedef struct ivl_design_s *ivl_design_t;
|
||||
typedef struct ivl_event_s *ivl_event_t;
|
||||
typedef struct ivl_expr_s *ivl_expr_t;
|
||||
typedef struct ivl_island_s *ivl_island_t;
|
||||
typedef struct ivl_lpm_s *ivl_lpm_t;
|
||||
typedef struct ivl_lval_s *ivl_lval_t;
|
||||
typedef struct ivl_net_const_s*ivl_net_const_t;
|
||||
@@ -155,6 +166,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
|
||||
typedef struct ivl_process_s *ivl_process_t;
|
||||
typedef struct ivl_scope_s *ivl_scope_t;
|
||||
typedef struct ivl_signal_s *ivl_signal_t;
|
||||
typedef struct ivl_switch_s *ivl_switch_t;
|
||||
typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */
|
||||
typedef struct ivl_statement_s*ivl_statement_t;
|
||||
|
||||
@@ -226,6 +238,17 @@ typedef enum ivl_logic_e {
|
||||
IVL_LO_UDP = 21
|
||||
} ivl_logic_t;
|
||||
|
||||
/* This is the type of a ivl_switch_t object */
|
||||
typedef enum ivl_switch_type_e {
|
||||
IVL_SW_TRAN = 0,
|
||||
IVL_SW_TRANIF0 = 1,
|
||||
IVL_SW_TRANIF1 = 2,
|
||||
IVL_SW_RTRAN = 3,
|
||||
IVL_SW_RTRANIF0 = 4,
|
||||
IVL_SW_RTRANIF1 = 5,
|
||||
IVL_SW_TRAN_VP = 6
|
||||
} ivl_switch_type_t;
|
||||
|
||||
/* This is the type of an LPM object. */
|
||||
typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_ABS = 32,
|
||||
@@ -243,7 +266,7 @@ typedef enum ivl_lpm_type_e {
|
||||
IVL_LPM_MOD = 13,
|
||||
IVL_LPM_MULT = 4,
|
||||
IVL_LPM_MUX = 5,
|
||||
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
|
||||
/* IVL_LPM_PART_BI= 28, / obsolete */
|
||||
IVL_LPM_PART_VP= 15, /* part select: vector to part */
|
||||
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
|
||||
IVL_LPM_POW = 31,
|
||||
@@ -699,6 +722,16 @@ extern unsigned ivl_file_table_index(const char *);
|
||||
extern unsigned ivl_file_table_size(void);
|
||||
|
||||
|
||||
/* ISLAND
|
||||
*
|
||||
* ivl_island_flag_set
|
||||
* ivl_island_flag_test
|
||||
* Allow the user to test or set a boolean flag associated with the
|
||||
* island.
|
||||
*/
|
||||
extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
|
||||
extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
|
||||
|
||||
/* LOGIC
|
||||
* These types and functions support manipulation of logic gates. The
|
||||
* ivl_logic_t enumeration identifies the various kinds of gates that
|
||||
@@ -1313,6 +1346,7 @@ extern unsigned ivl_nexus_ptr_pin(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_const_t ivl_nexus_ptr_con(ivl_nexus_ptr_t net);
|
||||
extern ivl_net_logic_t ivl_nexus_ptr_log(ivl_nexus_ptr_t net);
|
||||
extern ivl_lpm_t ivl_nexus_ptr_lpm(ivl_nexus_ptr_t net);
|
||||
extern ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net);
|
||||
extern ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net);
|
||||
|
||||
/* PARAMETER
|
||||
@@ -1501,6 +1535,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_sigs(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
|
||||
extern unsigned ivl_scope_switches(ivl_scope_t net);
|
||||
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
|
||||
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
|
||||
extern const char* ivl_scope_tname(ivl_scope_t net);
|
||||
extern int ivl_scope_time_precision(ivl_scope_t net);
|
||||
@@ -1826,6 +1862,53 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net);
|
||||
IVL_ST_WAIT, IVL_ST_WHILE */
|
||||
extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
|
||||
|
||||
/* SWITCHES
|
||||
*
|
||||
* The switches represent the tran devices in the design.
|
||||
*
|
||||
* FUNCTION SUMMARY
|
||||
*
|
||||
* ivl_switch_type
|
||||
* Return the enumerated value that is the type of the switch.
|
||||
*
|
||||
* ivl_switch_basename
|
||||
* This is the name given to the device in the source code.
|
||||
*
|
||||
* ivl_switch_a
|
||||
* ivl_switch_b
|
||||
* The a and b ports are the two ports of the switch.
|
||||
*
|
||||
* ivl_switch_enable
|
||||
* If the device has an enable (tranifX) then this is the enable
|
||||
* port.
|
||||
*
|
||||
* SEMANTIC NOTES
|
||||
* The a/b ports can be any type, but the types must exactly
|
||||
* match, including vector widths. The enable must be a scalar.
|
||||
*
|
||||
* The IVL_SW_TRAN_VP is an exception to the above. In this case,
|
||||
* the B side may be a different size, and the a side will have a
|
||||
* a fixed width. The unused bits are padded to Z on the A side.
|
||||
*/
|
||||
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
|
||||
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
|
||||
extern const char*ivl_switch_basename(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_a(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
|
||||
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
|
||||
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
|
||||
|
||||
/* These are only support for IVL_SW_TRAN_VP switches. */
|
||||
extern unsigned ivl_switch_width(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_part(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_offset(ivl_switch_t net);
|
||||
|
||||
/* Not implemented yet
|
||||
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
|
||||
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
|
||||
*** */
|
||||
extern const char* ivl_switch_file(ivl_switch_t net);
|
||||
extern unsigned ivl_switch_lineno(ivl_switch_t net);
|
||||
|
||||
#if defined(__MINGW32__) || defined (__CYGWIN32__)
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef __ivl_target_priv_H
|
||||
#define __ivl_target_H
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include <inttypes.h>
|
||||
|
||||
/*
|
||||
* This deader has declarations related to the ivl_target.h API that
|
||||
* are not to be exported outside of the core via the ivl_target.h
|
||||
* interface.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Information about islands. Connected branches within a net are
|
||||
* collected into islands. Branches that are purely ddiscrete do not
|
||||
* have disciplines and do not belong to islands.
|
||||
*/
|
||||
|
||||
class discipline_t;
|
||||
|
||||
struct ivl_island_s {
|
||||
discipline_t*discipline;
|
||||
// user accessible flags. They are initially false, always.
|
||||
vector<bool> flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1616,7 +1616,11 @@ static int load_next_input()
|
||||
static void do_dump_precompiled_defines(FILE* out, struct define_t* table)
|
||||
{
|
||||
if (!table->keyword)
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
fprintf(out, "%s:%d:%d:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#else
|
||||
fprintf(out, "%s:%d:%zd:%s\n", table->name, table->argc, strlen(table->value), table->value);
|
||||
#endif
|
||||
|
||||
if (table->left)
|
||||
do_dump_precompiled_defines(out, table->left);
|
||||
@@ -1741,6 +1745,7 @@ void reset_lexor(FILE* out, char* paths[])
|
||||
isp->ebs = 0;
|
||||
isp->next = 0;
|
||||
isp->lineno = 0;
|
||||
isp->stringify_flag = 0;
|
||||
|
||||
if (tail)
|
||||
tail->next = isp;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
# include <ctype.h>
|
||||
# include <string.h>
|
||||
# include "lexor_keyword.h"
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
|
||||
# define YY_USER_INIT reset_lexor();
|
||||
@@ -152,6 +153,7 @@ S [afpnumkKMGT]
|
||||
"->" { return K_TRIGGER; }
|
||||
"+:" { return K_PO_POS; }
|
||||
"-:" { return K_PO_NEG; }
|
||||
"<+" { return K_CONTRIBUTE; }
|
||||
|
||||
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
||||
and ")", but since I know that this is really ( * ), replace it
|
||||
@@ -230,6 +232,18 @@ S [afpnumkKMGT]
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this identifier names a discipline, then return this as
|
||||
a DISCIPLINE_IDENTIFIER and return the discipline as the
|
||||
value instead. */
|
||||
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
|
||||
perm_string tmp = lex_strings.make(yylval.text);
|
||||
map<perm_string,discipline_t*>::iterator cur = disciplines.find(tmp);
|
||||
if (cur != disciplines.end()) {
|
||||
yylval.discipline = (*cur).second;
|
||||
rc = DISCIPLINE_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
struct lexor_keyword { const char*name; int mask; int tokenType; };
|
||||
%%
|
||||
abs, GN_KEYWORDS_VAMS_2_3, K_abs
|
||||
abstol, GN_KEYWORDS_VAMS_2_3, K_abstol
|
||||
access, GN_KEYWORDS_VAMS_2_3, K_access
|
||||
acos, GN_KEYWORDS_VAMS_2_3, K_acos
|
||||
acosh, GN_KEYWORDS_VAMS_2_3, K_acosh
|
||||
always, GN_KEYWORDS_1364_1995, K_always
|
||||
analog, GN_KEYWORDS_VAMS_2_3, K_analog
|
||||
and, GN_KEYWORDS_1364_1995, K_and
|
||||
asin, GN_KEYWORDS_VAMS_2_3, K_asin
|
||||
asinh, GN_KEYWORDS_VAMS_2_3, K_asinh
|
||||
@@ -32,38 +35,51 @@ casex, GN_KEYWORDS_1364_1995, K_casex
|
||||
casez, GN_KEYWORDS_1364_1995, K_casez
|
||||
ceil, GN_KEYWORDS_VAMS_2_3, K_ceil
|
||||
cmos, GN_KEYWORDS_1364_1995, K_cmos
|
||||
continuous, GN_KEYWORDS_VAMS_2_3, K_continuous
|
||||
cos, GN_KEYWORDS_VAMS_2_3, K_cos
|
||||
cosh, GN_KEYWORDS_VAMS_2_3, K_cosh
|
||||
ddt_nature, GN_KEYWORDS_VAMS_2_3, K_ddt_nature
|
||||
deassign, GN_KEYWORDS_1364_1995, K_deassign
|
||||
default, GN_KEYWORDS_1364_1995, K_default
|
||||
defparam, GN_KEYWORDS_1364_1995, K_defparam
|
||||
disable, GN_KEYWORDS_1364_1995, K_disable
|
||||
discipline, GN_KEYWORDS_VAMS_2_3, K_discipline
|
||||
discrete, GN_KEYWORDS_VAMS_2_3, K_discrete
|
||||
domain, GN_KEYWORDS_VAMS_2_3, K_domain
|
||||
edge, GN_KEYWORDS_1364_1995, K_edge
|
||||
else, GN_KEYWORDS_1364_1995, K_else
|
||||
end, GN_KEYWORDS_1364_1995, K_end
|
||||
endcase, GN_KEYWORDS_1364_1995, K_endcase
|
||||
enddiscipline, GN_KEYWORDS_VAMS_2_3, K_enddiscipline
|
||||
endfunction, GN_KEYWORDS_1364_1995, K_endfunction
|
||||
endgenerate, GN_KEYWORDS_1364_1995, K_endgenerate
|
||||
endmodule, GN_KEYWORDS_1364_1995, K_endmodule
|
||||
endnature, GN_KEYWORDS_VAMS_2_3, K_endnature
|
||||
endprimitive, GN_KEYWORDS_1364_1995, K_endprimitive
|
||||
endspecify, GN_KEYWORDS_1364_1995, K_endspecify
|
||||
endtable, GN_KEYWORDS_1364_1995, K_endtable
|
||||
endtask, GN_KEYWORDS_1364_1995, K_endtask
|
||||
event, GN_KEYWORDS_1364_1995, K_event
|
||||
exclude, GN_KEYWORDS_VAMS_2_3, K_exclude
|
||||
exp, GN_KEYWORDS_VAMS_2_3, K_exp
|
||||
floor, GN_KEYWORDS_VAMS_2_3, K_floor
|
||||
flow, GN_KEYWORDS_VAMS_2_3, K_flow
|
||||
for, GN_KEYWORDS_1364_1995, K_for
|
||||
force, GN_KEYWORDS_1364_1995, K_force
|
||||
forever, GN_KEYWORDS_1364_1995, K_forever
|
||||
fork, GN_KEYWORDS_1364_1995, K_fork
|
||||
from, GN_KEYWORDS_VAMS_2_3, K_from
|
||||
function, GN_KEYWORDS_1364_1995, K_function
|
||||
generate, GN_KEYWORDS_1364_2001, K_generate
|
||||
genvar, GN_KEYWORDS_1364_2001, K_genvar
|
||||
ground, GN_KEYWORDS_VAMS_2_3, K_ground
|
||||
highz0, GN_KEYWORDS_1364_1995, K_highz0
|
||||
highz1, GN_KEYWORDS_1364_1995, K_highz1
|
||||
hypot, GN_KEYWORDS_VAMS_2_3, K_hypot
|
||||
idt_nature, GN_KEYWORDS_VAMS_2_3, K_idt_nature
|
||||
if, GN_KEYWORDS_1364_1995, K_if
|
||||
ifnone, GN_KEYWORDS_1364_1995, K_ifnone
|
||||
inf, GN_KEYWORDS_VAMS_2_3, K_inf
|
||||
initial, GN_KEYWORDS_1364_1995, K_initial
|
||||
inout, GN_KEYWORDS_1364_1995, K_inout
|
||||
input, GN_KEYWORDS_1364_1995, K_input
|
||||
@@ -80,6 +96,7 @@ medium, GN_KEYWORDS_1364_1995, K_medium
|
||||
min, GN_KEYWORDS_VAMS_2_3, K_min
|
||||
module, GN_KEYWORDS_1364_1995, K_module
|
||||
nand, GN_KEYWORDS_1364_1995, K_nand
|
||||
nature, GN_KEYWORDS_VAMS_2_3, K_nature
|
||||
negedge, GN_KEYWORDS_1364_1995, K_negedge
|
||||
nmos, GN_KEYWORDS_1364_1995, K_nmos
|
||||
nor, GN_KEYWORDS_1364_1995, K_nor
|
||||
@@ -91,6 +108,7 @@ output, GN_KEYWORDS_1364_1995, K_output
|
||||
parameter, GN_KEYWORDS_1364_1995, K_parameter
|
||||
pmos, GN_KEYWORDS_1364_1995, K_pmos
|
||||
posedge, GN_KEYWORDS_1364_1995, K_posedge
|
||||
potential, GN_KEYWORDS_VAMS_2_3, K_potential
|
||||
pow, GN_KEYWORDS_VAMS_2_3, K_pow
|
||||
primitive, GN_KEYWORDS_1364_1995, K_primitive
|
||||
pull0, GN_KEYWORDS_1364_1995, K_pull0
|
||||
@@ -116,6 +134,7 @@ small, GN_KEYWORDS_1364_1995, K_small
|
||||
specify, GN_KEYWORDS_1364_1995, K_specify
|
||||
specparam, GN_KEYWORDS_1364_1995, K_specparam
|
||||
sqrt, GN_KEYWORDS_VAMS_2_3, K_sqrt
|
||||
string, GN_KEYWORDS_VAMS_2_3, K_string
|
||||
strong0, GN_KEYWORDS_1364_1995, K_strong0
|
||||
strong1, GN_KEYWORDS_1364_1995, K_strong1
|
||||
supply0, GN_KEYWORDS_1364_1995, K_supply0
|
||||
@@ -134,6 +153,7 @@ tri1, GN_KEYWORDS_1364_1995, K_tri1
|
||||
triand, GN_KEYWORDS_1364_1995, K_triand
|
||||
trior, GN_KEYWORDS_1364_1995, K_trior
|
||||
trireg, GN_KEYWORDS_1364_1995, K_trireg
|
||||
units, GN_KEYWORDS_VAMS_2_3, K_units
|
||||
vectored, GN_KEYWORDS_1364_1995, K_vectored
|
||||
wait, GN_KEYWORDS_1364_1995, K_wait
|
||||
wand, GN_KEYWORDS_1364_1995, K_wand
|
||||
|
||||
@@ -57,6 +57,7 @@ const char NOTICE[] =
|
||||
# include "netlist.h"
|
||||
# include "target.h"
|
||||
# include "compiler.h"
|
||||
# include "discipline.h"
|
||||
|
||||
#if defined(__MINGW32__) && !defined(HAVE_GETOPT_H)
|
||||
extern "C" int getopt(int argc, char*argv[], const char*fmt);
|
||||
@@ -123,6 +124,8 @@ bool debug_scopes = false;
|
||||
bool debug_eval_tree = false;
|
||||
bool debug_elaborate = false;
|
||||
bool debug_synth2 = false;
|
||||
bool debug_optimizer = false;
|
||||
|
||||
/*
|
||||
* Verbose messages enabled.
|
||||
*/
|
||||
@@ -390,6 +393,9 @@ static void read_iconfig_file(const char*ipath)
|
||||
} else if (strcmp(cp,"synth2") == 0) {
|
||||
debug_synth2 = true;
|
||||
cerr << "debug: Enable synth2 debug" << endl;
|
||||
} else if (strcmp(cp,"optimizer") == 0) {
|
||||
debug_optimizer = true;
|
||||
cerr << "debug: Enable optimizer debug" << endl;
|
||||
} else {
|
||||
}
|
||||
|
||||
@@ -683,6 +689,16 @@ int main(int argc, char*argv[])
|
||||
|
||||
if (pf_path) {
|
||||
ofstream out (pf_path);
|
||||
out << "PFORM DUMP NATURES:" << endl;
|
||||
for (map<perm_string,nature_t*>::iterator cur = natures.begin()
|
||||
; cur != natures.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP DISCIPLINES:" << endl;
|
||||
for (map<perm_string,discipline_t*>::iterator cur = disciplines.begin()
|
||||
; cur != disciplines.end() ; cur ++ ) {
|
||||
pform_dump(out, (*cur).second);
|
||||
}
|
||||
out << "PFORM DUMP MODULES:" << endl;
|
||||
for (map<perm_string,Module*>::iterator mod = pform_modules.begin()
|
||||
; mod != pform_modules.end()
|
||||
@@ -809,6 +825,11 @@ int main(int argc, char*argv[])
|
||||
func(des);
|
||||
}
|
||||
|
||||
if (verbose_flag) {
|
||||
cout << "CALCULATING ISLANDS" << endl;
|
||||
}
|
||||
des->join_islands();
|
||||
|
||||
if (net_path) {
|
||||
if (verbose_flag)
|
||||
cerr<<" dumping netlist to " <<net_path<< "..." <<endl;
|
||||
|
||||
+283
-148
@@ -20,6 +20,7 @@
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
# include <cstdlib>
|
||||
|
||||
/*
|
||||
* This source file contains all the implementations of the Design
|
||||
@@ -31,6 +32,7 @@
|
||||
# include "compiler.h"
|
||||
# include "netmisc.h"
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
Design:: Design()
|
||||
: errors(0), nodes_(0), procs_(0), lcounter_(0)
|
||||
@@ -242,6 +244,260 @@ void Design::evaluate_parameters()
|
||||
(*scope)->evaluate_parameters(this);
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur)
|
||||
{
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
if ((*cur).second.msb) {
|
||||
eval_expr((*cur).second.msb);
|
||||
if (! eval_as_long(msb, (*cur).second.msb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.msb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
if ((*cur).second.lsb) {
|
||||
eval_expr((*cur).second.lsb);
|
||||
if (! eval_as_long(lsb, (*cur).second.lsb)) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *(*cur).second.lsb << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
eval_expr(expr);
|
||||
|
||||
/* The eval_expr may delete any replace the expr pointer, so the
|
||||
second.expr value cannot be relied on. Might as well replace
|
||||
it now with the expression that we evaluated. */
|
||||
(*cur).second.expr = expr;
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " << *expr << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
sure the value is set right. Note that if the
|
||||
parameter doesn't have an explicit range, then it
|
||||
will get the signedness from the expression itself. */
|
||||
if (range_flag) {
|
||||
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>(expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
expr = val;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no value ranges to test the value against,
|
||||
// then we are done.
|
||||
if ((*cur).second.range == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, (*cur).second.expr);
|
||||
ivl_assert(*(*cur).second.expr, val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
// If we already know that the value is
|
||||
// within a "from" range, then do not test
|
||||
// any more of the from ranges.
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, tmp);
|
||||
if (value_range->low_open_flag && value <= tmp->value())
|
||||
continue;
|
||||
else if (value < tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, tmp);
|
||||
if (value_range->high_open_flag && value >= tmp->value())
|
||||
continue;
|
||||
else if (value > tmp->value())
|
||||
continue;
|
||||
}
|
||||
|
||||
// Within the range. If this is a "from"
|
||||
// range, then set the from_flag and continue.
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// OH NO! In an excluded range. signal an error.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we found no from range that contains the
|
||||
// value, then report an error.
|
||||
if (! from_flag) {
|
||||
cerr << val->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameter_real_(Design*des, param_ref_t cur)
|
||||
{
|
||||
NetExpr*expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
NetECReal*res = 0;
|
||||
eval_expr(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (NetECReal*tmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
res = tmp;
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
|
||||
verireal val (tmp->value().as_long());
|
||||
res = new NetECReal(val);
|
||||
res->set_line(*tmp);
|
||||
} else {
|
||||
ivl_assert(*expr, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ivl_assert(*expr, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
(*cur).second.expr = res;
|
||||
double value = res->value().as_double();
|
||||
|
||||
bool from_flag = (*cur).second.range == 0? true : false;
|
||||
for (range_t*value_range = (*cur).second.range
|
||||
; value_range ; value_range = value_range->next) {
|
||||
|
||||
if (from_flag && value_range->exclude_flag==false)
|
||||
continue;
|
||||
|
||||
if (value_range->low_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->low_expr);
|
||||
ivl_assert(*value_range->low_expr, flag);
|
||||
if (value_range->low_open_flag && value <= tmp)
|
||||
continue;
|
||||
else if (value < tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->high_expr) {
|
||||
double tmp;
|
||||
bool flag = eval_as_double(tmp, value_range->high_expr);
|
||||
ivl_assert(*value_range->high_expr, flag);
|
||||
if (value_range->high_open_flag && value >= tmp)
|
||||
continue;
|
||||
else if (value > tmp)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value_range->exclude_flag == false) {
|
||||
from_flag = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// All the above tests failed, so we must have tripped
|
||||
// an exclude rule.
|
||||
from_flag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! from_flag) {
|
||||
cerr << res->get_fileline() << ": error: "
|
||||
<< "Parameter value " << value
|
||||
<< " is out of range for parameter " << (*cur).first
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void NetScope::evaluate_parameters(Design*des)
|
||||
{
|
||||
NetScope*cur = sub_;
|
||||
@@ -256,161 +512,29 @@ void NetScope::evaluate_parameters(Design*des)
|
||||
// scanning code. Now the parameter expression can be fully
|
||||
// evaluated, or it cannot be evaluated at all.
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator mparm_it_t;
|
||||
|
||||
for (mparm_it_t cur = parameters.begin()
|
||||
for (param_ref_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
bool range_flag = false;
|
||||
NetExpr*expr;
|
||||
|
||||
/* Evaluate the msb expression, if it is present. */
|
||||
expr = (*cur).second.msb;
|
||||
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate msb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.msb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
msb = tmp->value().as_long();
|
||||
range_flag = true;
|
||||
}
|
||||
|
||||
/* Evaluate the lsb expression, if it is present. */
|
||||
expr = (*cur).second.lsb;
|
||||
if (expr) {
|
||||
|
||||
NetEConst*tmp = dynamic_cast<NetEConst*>(expr);
|
||||
|
||||
if (! tmp) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate lsb expression "
|
||||
<< "for parameter " << (*cur).first << ": "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.lsb = nexpr;
|
||||
|
||||
tmp = dynamic_cast<NetEConst*>(nexpr);
|
||||
}
|
||||
|
||||
assert(tmp);
|
||||
lsb = tmp->value().as_long();
|
||||
|
||||
assert(range_flag);
|
||||
}
|
||||
|
||||
|
||||
/* Evaluate the parameter expression, if necessary. */
|
||||
expr = (*cur).second.expr;
|
||||
assert(expr);
|
||||
|
||||
switch (expr->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
if (! dynamic_cast<const NetECReal*>(expr)) {
|
||||
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate real parameter value: "
|
||||
<< *expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
switch ((*cur).second.type) {
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_LOGIC:
|
||||
evaluate_parameter_logic_(des, cur);
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if (! dynamic_cast<const NetEConst*>(expr)) {
|
||||
|
||||
// Try to evaluate the expression.
|
||||
NetExpr*nexpr = expr->eval_tree();
|
||||
if (nexpr == 0) {
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unable to evaluate parameter "
|
||||
<< (*cur).first
|
||||
<< " value: " <<
|
||||
*expr << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The evaluate worked, replace the old
|
||||
// expression with this constant value.
|
||||
assert(nexpr);
|
||||
delete expr;
|
||||
(*cur).second.expr = nexpr;
|
||||
}
|
||||
case IVL_VT_REAL:
|
||||
evaluate_parameter_real_(des, cur);
|
||||
break;
|
||||
|
||||
default:
|
||||
cerr << (*cur).second.expr->get_fileline()
|
||||
<< ": internal error: "
|
||||
<< "unhandled expression type?" << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the parameter has range information, then make
|
||||
sure the value is set right. Note that if the
|
||||
parameter doesn't have an explicit range, then it
|
||||
will get the signedness from the expression itself. */
|
||||
if (range_flag) {
|
||||
unsigned long wid = (msb >= lsb)? msb - lsb : lsb - msb;
|
||||
wid += 1;
|
||||
|
||||
NetEConst*val = dynamic_cast<NetEConst*>((*cur).second.expr);
|
||||
assert(val);
|
||||
|
||||
verinum value = val->value();
|
||||
|
||||
if (! (value.has_len()
|
||||
&& (value.len() == wid)
|
||||
&& (value.has_sign() == (*cur).second.signed_flag))) {
|
||||
|
||||
verinum tmp (value, wid);
|
||||
tmp.has_sign ( (*cur).second.signed_flag );
|
||||
delete val;
|
||||
val = new NetEConst(tmp);
|
||||
(*cur).second.expr = val;
|
||||
}
|
||||
cerr << (*cur).second.get_fileline() << ": internal error: "
|
||||
<< "Unexpected expression type " << (*cur).second.type
|
||||
<< "." << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Parameter name: " << (*cur).first << endl;
|
||||
cerr << (*cur).second.get_fileline() << ": : "
|
||||
<< "Expression is: " << *(*cur).second.expr << endl;
|
||||
ivl_assert((*cur).second, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,3 +677,14 @@ void Design::delete_process(NetProcTop*top)
|
||||
delete top;
|
||||
}
|
||||
|
||||
void Design::join_islands(void)
|
||||
{
|
||||
if (nodes_ == 0)
|
||||
return;
|
||||
|
||||
NetNode*cur = nodes_->node_next_;
|
||||
do {
|
||||
join_island(cur);
|
||||
cur = cur->node_next_;
|
||||
} while (cur != nodes_->node_next_);
|
||||
}
|
||||
|
||||
+12
-2
@@ -476,7 +476,12 @@ NetEParam::NetEParam()
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, perm_string n)
|
||||
: des_(d), scope_(s), name_(n)
|
||||
: des_(d), scope_(s), reference_(scope_->find_parameter(n))
|
||||
{
|
||||
}
|
||||
|
||||
NetEParam::NetEParam(Design*d, NetScope*s, ref_t ref)
|
||||
: des_(d), scope_(s), reference_(ref)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -489,9 +494,14 @@ bool NetEParam::has_width() const
|
||||
return false;
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEParam::expr_type() const
|
||||
{
|
||||
return (*reference_).second.type;
|
||||
}
|
||||
|
||||
NetEParam* NetEParam::dup_expr() const
|
||||
{
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, name_);
|
||||
NetEParam*tmp = new NetEParam(des_, scope_, reference_);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
+28
-6
@@ -22,7 +22,9 @@
|
||||
|
||||
# include "netlist.h"
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
/*
|
||||
* The NetScope class keeps a scope tree organized. Each node of the
|
||||
@@ -104,17 +106,24 @@ void NetScope::set_line(perm_string file, perm_string def_file,
|
||||
}
|
||||
|
||||
NetExpr* NetScope::set_parameter(perm_string key, NetExpr*expr,
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno)
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = parameters[key];
|
||||
NetExpr* res = ref.expr;
|
||||
ref.expr = expr;
|
||||
ref.type = type;
|
||||
ref.msb = msb;
|
||||
ref.lsb = lsb;
|
||||
ref.signed_flag = signed_flag;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
ivl_assert(file_line, ref.range == 0);
|
||||
ref.range = range_list;
|
||||
ref.set_line(file_line);
|
||||
|
||||
ivl_assert(file_line, type != IVL_VT_NO_TYPE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -160,7 +169,7 @@ bool NetScope::replace_parameter(perm_string key, NetExpr*expr)
|
||||
* used to add a genver to the local parameter list.
|
||||
*/
|
||||
NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
perm_string file, unsigned lineno)
|
||||
const LineInfo&file_line)
|
||||
{
|
||||
param_expr_t&ref = localparams[key];
|
||||
NetExpr* res = ref.expr;
|
||||
@@ -168,8 +177,7 @@ NetExpr* NetScope::set_localparam(perm_string key, NetExpr*expr,
|
||||
ref.msb = 0;
|
||||
ref.lsb = 0;
|
||||
ref.signed_flag = false;
|
||||
ref.file = file;
|
||||
ref.lineno = lineno;
|
||||
ref.set_line(file_line);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -202,6 +210,20 @@ const NetExpr* NetScope::get_parameter(const char* key,
|
||||
|
||||
return 0;
|
||||
}
|
||||
map<perm_string,NetScope::param_expr_t>::iterator NetScope::find_parameter(perm_string key)
|
||||
{
|
||||
map<perm_string,param_expr_t>::iterator idx;
|
||||
|
||||
idx = parameters.find(key);
|
||||
if (idx != parameters.end())
|
||||
return idx;
|
||||
|
||||
idx = localparams.find(perm_string::literal(key));
|
||||
if (idx != localparams.end())
|
||||
return idx;
|
||||
|
||||
return (map<perm_string,param_expr_t>::iterator) 0;
|
||||
}
|
||||
|
||||
NetScope::TYPE NetScope::type() const
|
||||
{
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
|
||||
# include <iostream>
|
||||
|
||||
# include <typeinfo>
|
||||
# include <cstdlib>
|
||||
# include "compiler.h"
|
||||
# include "netlist.h"
|
||||
# include "netmisc.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static bool has_enable(ivl_switch_type_t tt)
|
||||
{
|
||||
switch (tt) {
|
||||
case IVL_SW_TRANIF0:
|
||||
case IVL_SW_TRANIF1:
|
||||
case IVL_SW_RTRANIF0:
|
||||
case IVL_SW_RTRANIF1:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
|
||||
: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
if (pin_count() == 3) {
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
pin(2).set_name(perm_string::literal("E"), 0);
|
||||
}
|
||||
}
|
||||
|
||||
NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
|
||||
: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
|
||||
{
|
||||
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
|
||||
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
|
||||
}
|
||||
|
||||
NetTran::~NetTran()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned NetTran::vector_width() const
|
||||
{
|
||||
return wid_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_width() const
|
||||
{
|
||||
return part_;
|
||||
}
|
||||
|
||||
unsigned NetTran::part_offset() const
|
||||
{
|
||||
return off_;
|
||||
}
|
||||
|
||||
void join_island(NetObj*obj)
|
||||
{
|
||||
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
|
||||
|
||||
// If this is not even a branch, then stop now.
|
||||
if (branch == 0)
|
||||
return;
|
||||
|
||||
// If this is a branch, but already given to an island, then
|
||||
// stop.
|
||||
if (branch->island)
|
||||
return;
|
||||
|
||||
list<NetObj*> uncommitted_neighbors;
|
||||
|
||||
// Look for neighboring objects that might already be in
|
||||
// islands. If we find something, then join that island.
|
||||
for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
|
||||
Nexus*nex = obj->pin(idx).nexus();
|
||||
for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) {
|
||||
unsigned pin;
|
||||
NetObj*tmp;
|
||||
cur->cur_link(tmp, pin);
|
||||
|
||||
// Skip self.
|
||||
if (tmp == obj)
|
||||
continue;
|
||||
|
||||
// If tmb is not a branch, then skip it.
|
||||
IslandBranch*tmp_branch = dynamic_cast<IslandBranch*> (tmp);
|
||||
if (tmp_branch == 0)
|
||||
continue;
|
||||
|
||||
// If that is an uncommitted branch, then save
|
||||
// it. When I finally choose an island for self,
|
||||
// these branches will be scanned so tha they join
|
||||
// this island as well.
|
||||
if (tmp_branch->island == 0) {
|
||||
uncommitted_neighbors.push_back(tmp);
|
||||
continue;
|
||||
}
|
||||
|
||||
ivl_assert(*obj, branch->island==0 || branch->island==tmp_branch->island);
|
||||
|
||||
// We found an existing island to join. Join it
|
||||
// now. Keep scanning in order to find more neighbors.
|
||||
if (branch->island == 0) {
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Join brach to existing island." << endl;
|
||||
branch->island = tmp_branch->island;
|
||||
|
||||
} else if (branch->island != tmp_branch->island) {
|
||||
cerr << obj->get_fileline() << ": internal error: "
|
||||
<< "Oops, Found 2 neighboring islands." << endl;
|
||||
ivl_assert(*obj, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If after all that we did not find an idland to join, then
|
||||
// start the island not and join it.
|
||||
if (branch->island == 0) {
|
||||
branch->island = new ivl_island_s;
|
||||
branch->island->discipline = 0;
|
||||
if (debug_elaborate)
|
||||
cerr << obj->get_fileline() << ": debug: "
|
||||
<< "Create new island for this branch" << endl;
|
||||
}
|
||||
|
||||
// Now scan all the uncommitted neighbors I found. Calling
|
||||
// join_island() on them will cause them to notice me in the
|
||||
// process, and thus they will join my island. This process
|
||||
// will recurse until all the connected branches join this island.
|
||||
for (list<NetObj*>::iterator cur = uncommitted_neighbors.begin()
|
||||
; cur != uncommitted_neighbors.end() ; cur ++ ) {
|
||||
join_island(*cur);
|
||||
}
|
||||
}
|
||||
@@ -761,10 +761,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
}
|
||||
pin(0).set_name(perm_string::literal("Part"), 0);
|
||||
pin(1).set_name(perm_string::literal("Vect"), 0);
|
||||
@@ -787,10 +783,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel,
|
||||
pin(0).set_dir(Link::INPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::PASSIVE);
|
||||
pin(1).set_dir(Link::PASSIVE);
|
||||
break;
|
||||
}
|
||||
pin(2).set_dir(Link::INPUT);
|
||||
|
||||
|
||||
@@ -49,8 +49,10 @@ class ostream;
|
||||
class Design;
|
||||
class Link;
|
||||
class Nexus;
|
||||
class NetEvent;
|
||||
class NetNet;
|
||||
class NetNode;
|
||||
class NetObj;
|
||||
class NetProc;
|
||||
class NetProcTop;
|
||||
class NetRelease;
|
||||
@@ -60,6 +62,7 @@ class NetExpr;
|
||||
class NetESignal;
|
||||
class NetFuncDef;
|
||||
class NetRamDq;
|
||||
class NetTaskDef;
|
||||
class NetEvTrig;
|
||||
class NetEvWait;
|
||||
|
||||
@@ -69,6 +72,8 @@ struct functor_t;
|
||||
|
||||
ostream& operator << (ostream&o, ivl_variable_type_t val);
|
||||
|
||||
extern void join_island(NetObj*obj);
|
||||
|
||||
/* =========
|
||||
* A NetObj is anything that has any kind of behavior in the
|
||||
* netlist. Nodes can be gates, registers, etc. and are linked
|
||||
@@ -129,6 +134,20 @@ class NetObj : public Attrib, public virtual LineInfo {
|
||||
const NetExpr* delay3_;
|
||||
};
|
||||
|
||||
/*
|
||||
* Objects that can be island branches are derived from this. (It is
|
||||
* possible for an object to be a NetObj and an IslandBranch.) This is
|
||||
* used to collect island information about the node.
|
||||
*/
|
||||
|
||||
class IslandBranch {
|
||||
public:
|
||||
IslandBranch() : island(0) { }
|
||||
|
||||
public:
|
||||
struct ivl_island_s* island;
|
||||
};
|
||||
|
||||
class Link {
|
||||
|
||||
friend void connect(Link&, Link&);
|
||||
@@ -578,6 +597,234 @@ class NetNet : public NetObj {
|
||||
vector<class NetDelaySrc*> delay_paths_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* Parameters exist within a scope, and these methods allow
|
||||
one to manipulate the set. In these cases, the name is the
|
||||
*simple* name of the parameter, the hierarchy is implicit in
|
||||
the scope. The return value from set_parameter is the
|
||||
previous expression, if there was one. */
|
||||
|
||||
struct range_t;
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
ivl_variable_type_t type,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
NetScope::range_t*range_list,
|
||||
const LineInfo&file_line);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
const LineInfo&file_line);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
|
||||
public:
|
||||
struct range_t {
|
||||
bool exclude_flag;
|
||||
// Lower bound
|
||||
bool low_open_flag;
|
||||
NetExpr*low_expr;
|
||||
// Upper bound
|
||||
bool high_open_flag;
|
||||
NetExpr*high_expr;
|
||||
// Link to the next range specification
|
||||
struct range_t*next;
|
||||
};
|
||||
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t : public LineInfo {
|
||||
param_expr_t() : type(IVL_VT_NO_TYPE), range(0) { }
|
||||
// Type information
|
||||
ivl_variable_type_t type;
|
||||
bool signed_flag;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
// range constraints
|
||||
struct range_t*range;
|
||||
// Expression value
|
||||
NetExpr*expr;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
typedef map<perm_string,param_expr_t>::iterator param_ref_t;
|
||||
|
||||
param_ref_t find_parameter(perm_string name);
|
||||
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
void evaluate_parameter_logic_(Design*des, param_ref_t cur);
|
||||
void evaluate_parameter_real_(Design*des, param_ref_t cur);
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class implements the LPM_ABS component. The node has a single
|
||||
* input, a signe expression, that it converts to the absolute
|
||||
@@ -1129,6 +1376,33 @@ class NetSysFunc : public NetNode {
|
||||
const struct sfunc_return_type*def_;
|
||||
};
|
||||
|
||||
class NetTran : public NetNode, public IslandBranch {
|
||||
|
||||
public:
|
||||
// Tran devices other then TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
|
||||
// Create a TRAN_VP
|
||||
NetTran(NetScope*scope, perm_string n, unsigned wid,
|
||||
unsigned part, unsigned off);
|
||||
~NetTran();
|
||||
|
||||
ivl_switch_type_t type() const { return type_; }
|
||||
|
||||
// These are only used for IVL_SW_TRAN_PV
|
||||
unsigned vector_width() const;
|
||||
unsigned part_width() const;
|
||||
unsigned part_offset() const;
|
||||
|
||||
virtual void dump_node(ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
||||
private:
|
||||
ivl_switch_type_t type_;
|
||||
unsigned wid_;
|
||||
unsigned part_;
|
||||
unsigned off_;
|
||||
};
|
||||
|
||||
/* =========
|
||||
* There are cases where expressions need to be represented. The
|
||||
* NetExpr class is the root of a hierarchy that serves that purpose.
|
||||
@@ -1343,8 +1617,8 @@ class NetECRealParam : public NetECReal {
|
||||
* selector as the input.
|
||||
*
|
||||
* The NetPartSelect can be output from the signal (i.e. reading a
|
||||
* part), input into the signal, or bi-directional. The DIR method
|
||||
* gives the type of the node.
|
||||
* part) or input into the signal. The DIR method gives the type of
|
||||
* the node.
|
||||
*
|
||||
* VP (Vector-to-Part)
|
||||
* Output pin 0 is the part select, and input pin 1 is connected to
|
||||
@@ -1354,10 +1628,6 @@ class NetECRealParam : public NetECReal {
|
||||
* Output pin 1 is connected to the NetNet, and input pin 0 is the
|
||||
* part select. In this case, the node is driving the NetNet.
|
||||
*
|
||||
* BI (BI-directional)
|
||||
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
|
||||
* the ports are intended to be bi-directional.
|
||||
*
|
||||
* Note that whatever the direction that data is intended to flow,
|
||||
* pin-0 is the part select and pin-1 is connected to the NetNet.
|
||||
*/
|
||||
@@ -1365,7 +1635,7 @@ class NetPartSelect : public NetNode {
|
||||
|
||||
public:
|
||||
// enum for the device direction
|
||||
enum dir_t { VP, PV, BI };
|
||||
enum dir_t { VP, PV};
|
||||
|
||||
explicit NetPartSelect(NetNet*sig,
|
||||
unsigned off, unsigned wid, dir_t dir);
|
||||
@@ -3006,6 +3276,7 @@ class NetEParam : public NetExpr {
|
||||
virtual bool set_width(unsigned w, bool last_chance);
|
||||
virtual bool has_width() const;
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual NetExpr* eval_tree(int prune_to_width = -1);
|
||||
virtual NetEParam* dup_expr() const;
|
||||
|
||||
@@ -3014,7 +3285,10 @@ class NetEParam : public NetExpr {
|
||||
private:
|
||||
Design*des_;
|
||||
NetScope*scope_;
|
||||
perm_string name_;
|
||||
typedef map<perm_string,NetScope::param_expr_t>::iterator ref_t;
|
||||
ref_t reference_;
|
||||
|
||||
NetEParam(class Design*des, NetScope*scope, ref_t ref);
|
||||
};
|
||||
|
||||
|
||||
@@ -3287,206 +3561,6 @@ class NetESignal : public NetExpr {
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This object type is used to contain a logical scope within a
|
||||
* design. The scope doesn't represent any executable hardware, but is
|
||||
* just a handle that netlist processors can use to grab at the design.
|
||||
*/
|
||||
class NetScope : public Attrib {
|
||||
|
||||
public:
|
||||
enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
|
||||
|
||||
/* Create a new scope, and attach it to the given parent. The
|
||||
name is expected to have been permallocated. */
|
||||
NetScope(NetScope*up, const hname_t&name, TYPE t);
|
||||
~NetScope();
|
||||
|
||||
/* Rename the scope using the name generated by inserting as
|
||||
many pad characters as required between prefix and suffix
|
||||
to make the name unique in the parent scope. Return false
|
||||
if a unique name couldn't be generated. */
|
||||
bool auto_name(const char* prefix, char pad, const char* suffix);
|
||||
|
||||
/* Parameters exist within a scope, and these methods allow
|
||||
one to manipulate the set. In these cases, the name is the
|
||||
*simple* name of the parameter, the hierarchy is implicit in
|
||||
the scope. The return value from set_parameter is the
|
||||
previous expression, if there was one. */
|
||||
|
||||
NetExpr* set_parameter(perm_string name, NetExpr*val,
|
||||
NetExpr*msb, NetExpr*lsb, bool signed_flag,
|
||||
perm_string file, unsigned lineno);
|
||||
NetExpr* set_localparam(perm_string name, NetExpr*val,
|
||||
perm_string file, unsigned lineno);
|
||||
|
||||
const NetExpr*get_parameter(const char* name,
|
||||
const NetExpr*&msb,
|
||||
const NetExpr*&lsb) const;
|
||||
|
||||
/* These are used by defparam elaboration to replace the
|
||||
expression with a new expression, without affecting the
|
||||
range or signed_flag. Return false if the name does not
|
||||
exist. */
|
||||
bool replace_parameter(perm_string name, NetExpr*val);
|
||||
|
||||
/* These methods set or access events that live in this
|
||||
scope. */
|
||||
|
||||
void add_event(NetEvent*);
|
||||
void rem_event(NetEvent*);
|
||||
NetEvent*find_event(perm_string name);
|
||||
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
used to locate signals within a scope. */
|
||||
|
||||
void add_signal(NetNet*);
|
||||
void rem_signal(NetNet*);
|
||||
NetNet* find_signal(perm_string name);
|
||||
|
||||
/* The parent and child() methods allow users of NetScope
|
||||
objects to locate nearby scopes. */
|
||||
NetScope* parent();
|
||||
NetScope* child(const hname_t&name);
|
||||
const NetScope* parent() const;
|
||||
const NetScope* child(const hname_t&name) const;
|
||||
|
||||
TYPE type() const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_module_name(perm_string);
|
||||
|
||||
NetTaskDef* task_def();
|
||||
NetFuncDef* func_def();
|
||||
|
||||
void set_line(perm_string file, perm_string def_file,
|
||||
unsigned lineno, unsigned def_lineno);
|
||||
void set_line(perm_string file, unsigned lineno);
|
||||
void set_line(const LineInfo *info);
|
||||
perm_string get_file() const { return file_; };
|
||||
perm_string get_def_file() const { return def_file_; };
|
||||
unsigned get_lineno() const { return lineno_; };
|
||||
unsigned get_def_lineno() const { return def_lineno_; };
|
||||
|
||||
bool in_func();
|
||||
|
||||
const NetTaskDef* task_def() const;
|
||||
const NetFuncDef* func_def() const;
|
||||
|
||||
/* If the scope represents a module instance, the module_name
|
||||
is the name of the module itself. */
|
||||
perm_string module_name() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
unit and precision are given as power of 10, i.e., -3 is
|
||||
units of milliseconds.
|
||||
|
||||
If a NetScope is created with a parent scope, the new scope
|
||||
will initially inherit the unit and precision of the
|
||||
parent scope. */
|
||||
|
||||
void time_unit(int);
|
||||
void time_precision(int);
|
||||
|
||||
int time_unit() const;
|
||||
int time_precision() const;
|
||||
|
||||
void default_nettype(NetNet::Type);
|
||||
NetNet::Type default_nettype() const;
|
||||
|
||||
/* The fullname of the scope is the hierarchical name
|
||||
component (which includes the name and array index) whereas
|
||||
the basename is just my name. */
|
||||
perm_string basename() const;
|
||||
const hname_t& fullname() const { return name_; }
|
||||
|
||||
void run_defparams(class Design*);
|
||||
void evaluate_parameters(class Design*);
|
||||
|
||||
/* This method generates a non-hierarchical name that is
|
||||
guaranteed to be unique within this scope. */
|
||||
perm_string local_symbol();
|
||||
|
||||
void dump(ostream&) const;
|
||||
void emit_scope(struct target_t*tgt) const;
|
||||
bool emit_defs(struct target_t*tgt) const;
|
||||
|
||||
/* This method runs the functor on me. Recurse through the
|
||||
children of this node as well. */
|
||||
void run_functor(Design*des, functor_t*fun);
|
||||
|
||||
|
||||
/* This member is used during elaboration to pass defparam
|
||||
assignments from the scope pass to the parameter evaluation
|
||||
step. After that, it is not used. */
|
||||
|
||||
map<pform_name_t,NetExpr*>defparams;
|
||||
|
||||
public:
|
||||
/* After everything is all set up, the code generators like
|
||||
access to these things to make up the parameter lists. */
|
||||
struct param_expr_t {
|
||||
NetExpr*expr;
|
||||
NetExpr*msb;
|
||||
NetExpr*lsb;
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
bool signed_flag;
|
||||
};
|
||||
map<perm_string,param_expr_t>parameters;
|
||||
map<perm_string,param_expr_t>localparams;
|
||||
|
||||
struct spec_val_t {
|
||||
ivl_variable_type_t type;
|
||||
union {
|
||||
double real_val; // type == IVL_VT_REAL
|
||||
long integer; // type == IVL_VT_BOOL
|
||||
};
|
||||
};
|
||||
map<perm_string,spec_val_t>specparams;
|
||||
|
||||
/* Module instance arrays are collected here for access during
|
||||
the multiple elaboration passes. */
|
||||
typedef svector<NetScope*> scope_vec_t;
|
||||
map<perm_string, scope_vec_t>instance_arrays;
|
||||
|
||||
/* Loop generate uses this as scratch space during
|
||||
elaboration. Expression evaluation can use this to match
|
||||
names. */
|
||||
perm_string genvar_tmp;
|
||||
long genvar_tmp_val;
|
||||
|
||||
private:
|
||||
TYPE type_;
|
||||
hname_t name_;
|
||||
|
||||
perm_string file_;
|
||||
perm_string def_file_;
|
||||
unsigned lineno_;
|
||||
unsigned def_lineno_;
|
||||
|
||||
signed char time_unit_, time_prec_;
|
||||
NetNet::Type default_nettype_;
|
||||
|
||||
NetEvent *events_;
|
||||
NetNet *signals_;
|
||||
perm_string module_name_;
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
};
|
||||
|
||||
NetScope*up_;
|
||||
NetScope*sib_;
|
||||
NetScope*sub_;
|
||||
|
||||
unsigned lcounter_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This class contains an entire design. It includes processes and a
|
||||
* netlist, and can be passed around from function to function.
|
||||
@@ -3564,6 +3638,7 @@ class Design {
|
||||
// Iterate over the design...
|
||||
void dump(ostream&) const;
|
||||
void functor(struct functor_t*);
|
||||
void join_islands(void);
|
||||
int emit(struct target_t*) const;
|
||||
|
||||
// This is incremented by elaboration when an error is
|
||||
|
||||
+22
@@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr)
|
||||
return res;
|
||||
}
|
||||
|
||||
NetEConst* make_const_x(unsigned long wid)
|
||||
{
|
||||
verinum xxx (verinum::Vx, wid);
|
||||
NetEConst*resx = new NetEConst(xxx);
|
||||
return resx;
|
||||
}
|
||||
|
||||
NetExpr* condition_reduce(NetExpr*expr)
|
||||
{
|
||||
if (expr->expr_width() == 1)
|
||||
@@ -182,6 +189,21 @@ bool eval_as_long(long&value, NetExpr*expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eval_as_double(double&value, NetExpr*expr)
|
||||
{
|
||||
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr) ) {
|
||||
value = tmp->value().as_long();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NetECReal*rtmp = dynamic_cast<NetECReal*>(expr)) {
|
||||
value = rtmp->value().as_double();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path)
|
||||
{
|
||||
|
||||
@@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
|
||||
extern NetExpr*make_add_expr(NetExpr*expr, long val);
|
||||
extern NetExpr*make_sub_expr(long val, NetExpr*expr);
|
||||
|
||||
/*
|
||||
* Make a NetEConst object that contains only X bits.
|
||||
*/
|
||||
extern NetEConst*make_const_x(unsigned long wid);
|
||||
|
||||
/*
|
||||
* In some cases the lval is accessible as a pointer to the head of
|
||||
* a list of NetAssign_ objects. This function returns the width of
|
||||
@@ -138,6 +143,7 @@ void eval_expr(NetExpr*&expr, int prune_width =-1);
|
||||
* down to a constant) then return false and leave value unchanged.
|
||||
*/
|
||||
bool eval_as_long(long&value, NetExpr*expr);
|
||||
bool eval_as_double(double&value, NetExpr*expr);
|
||||
|
||||
extern std::list<hname_t> eval_scope_path(Design*des, NetScope*scope,
|
||||
const pform_name_t&path);
|
||||
|
||||
@@ -35,8 +35,9 @@ class PSpecPath;
|
||||
extern void lex_start_table();
|
||||
extern void lex_end_table();
|
||||
|
||||
static svector<PExpr*>* active_range = 0;
|
||||
static bool active_signed = false;
|
||||
static svector<PExpr*>* param_active_range = 0;
|
||||
static bool param_active_signed = false;
|
||||
static ivl_variable_type_t param_active_type = IVL_VT_LOGIC;
|
||||
|
||||
/* Port declaration lists use this structure for context. */
|
||||
static struct {
|
||||
@@ -94,12 +95,6 @@ static list<perm_string>* list_from_identifier(list<perm_string>*tmp, char*id)
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
static svector<PExpr*>* copy_range(svector<PExpr*>* orig)
|
||||
{
|
||||
svector<PExpr*>*copy = 0;
|
||||
@@ -147,6 +142,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
list<perm_string>*perm_strings;
|
||||
pform_name_t*pform_name;
|
||||
|
||||
discipline_t*discipline;
|
||||
|
||||
hname_t*hier;
|
||||
|
||||
list<string>*strings;
|
||||
@@ -160,6 +157,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
svector<lgate>*gates;
|
||||
|
||||
Module::port_t *mport;
|
||||
Module::range_t* value_range;
|
||||
svector<Module::port_t*>*mports;
|
||||
|
||||
named_pexpr_t*named_pexpr;
|
||||
@@ -196,40 +194,50 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
};
|
||||
|
||||
%token <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
|
||||
%token <discipline> DISCIPLINE_IDENTIFIER
|
||||
%token <text> PATHPULSE_IDENTIFIER
|
||||
%token <number> BASED_NUMBER DEC_NUMBER
|
||||
%token <realtime> REALTIME
|
||||
%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG
|
||||
/* K_CONTRIBUTE is <+, the contribution assign. */
|
||||
%token K_CONTRIBUTE
|
||||
%token K_PO_POS K_PO_NEG K_POW
|
||||
%token K_PSTAR K_STARP
|
||||
%token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER
|
||||
%token K_abs K_acos K_acosh K_asin K_asinh K_atan K_atanh K_atan2
|
||||
%token K_abs K_abstol K_access K_acos K_acosh K_asin K_analog K_asinh
|
||||
%token K_atan K_atanh K_atan2
|
||||
%token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case
|
||||
%token K_casex K_casez K_ceil K_cmos K_cos K_cosh
|
||||
%token K_deassign K_default K_defparam K_disable
|
||||
%token K_edge K_edge_descriptor
|
||||
%token K_else K_end K_endcase K_endfunction K_endgenerate K_endmodule
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event K_exp K_floor
|
||||
%token K_casex K_casez K_ceil K_cmos K_continuous K_cos K_cosh
|
||||
%token K_ddt_nature K_deassign K_default K_defparam K_disable K_discrete
|
||||
%token K_domain K_edge K_edge_descriptor K_discipline
|
||||
%token K_else K_end K_endcase K_enddiscipline K_endfunction K_endgenerate
|
||||
%token K_endmodule K_endnature
|
||||
%token K_endprimitive K_endspecify K_endtable K_endtask K_event
|
||||
%token K_exclude K_exp K_floor K_flow K_from
|
||||
%token K_for K_force K_forever K_fork K_function K_generate K_genvar
|
||||
%token K_highz0 K_highz1 K_hypot K_if K_ifnone
|
||||
%token K_ground K_highz0 K_highz1 K_hypot K_idt_nature K_if K_ifnone K_inf
|
||||
%token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam
|
||||
%token K_log K_logic K_macromodule K_max
|
||||
%token K_medium K_min K_module K_nand K_negedge K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_pow K_primitive
|
||||
%token K_medium K_min K_module K_nand K_nature K_negedge
|
||||
%token K_nmos K_nor K_not K_notif0
|
||||
%token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_potential
|
||||
%token K_pow K_primitive
|
||||
%token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime
|
||||
%token K_reg K_release K_repeat
|
||||
%token K_rnmos K_rpmos K_rtran K_rtranif0 K_rtranif1 K_scalared
|
||||
%token K_signed K_sin K_sinh K_small K_specify
|
||||
%token K_specparam K_sqrt K_strong0 K_strong1 K_supply0 K_supply1 K_table
|
||||
%token K_specparam K_sqrt K_string K_strong0 K_strong1 K_supply0 K_supply1
|
||||
%token K_table
|
||||
%token K_tan K_tanh K_task
|
||||
%token K_time K_tran K_tranif0 K_tranif1 K_tri K_tri0 K_tri1 K_triand
|
||||
%token K_trior K_trireg K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
%token K_trior K_trireg K_units K_vectored K_wait K_wand K_weak0 K_weak1
|
||||
%token K_while K_wire
|
||||
%token K_wone K_wor K_xnor K_xor
|
||||
%token K_Shold K_Speriod K_Srecovery K_Srecrem K_Ssetup K_Swidth K_Ssetuphold
|
||||
|
||||
%token KK_attribute
|
||||
|
||||
%type <flag> from_exclude
|
||||
%type <number> number
|
||||
%type <flag> signed_opt udp_reg_opt edge_operator
|
||||
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
|
||||
@@ -251,6 +259,9 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
%type <mport> port port_opt port_reference port_reference_list
|
||||
%type <mport> port_declaration
|
||||
%type <mports> list_of_ports module_port_list_opt list_of_port_declarations
|
||||
%type <value_range> parameter_value_range parameter_value_ranges
|
||||
%type <value_range> parameter_value_ranges_opt
|
||||
%type <expr> value_range_expression
|
||||
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
%type <wires> task_port_item task_port_decl task_port_decl_list
|
||||
@@ -312,10 +323,15 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2)
|
||||
%left K_POW
|
||||
%left UNARY_PREC
|
||||
|
||||
|
||||
/* to resolve dangling else ambiguity. */
|
||||
%nonassoc less_than_K_else
|
||||
%nonassoc K_else
|
||||
|
||||
/* to resolve exclude (... ambiguity */
|
||||
%nonassoc '('
|
||||
%nonassoc K_exclude
|
||||
|
||||
%%
|
||||
|
||||
/* A degenerate source file can be completely empty. */
|
||||
@@ -655,15 +671,71 @@ delay_value_simple
|
||||
;
|
||||
|
||||
description
|
||||
: module
|
||||
| udp_primitive
|
||||
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
|
||||
{ perm_string tmp3 = lex_strings.make($3);
|
||||
pform_set_type_attrib(tmp3, $5, $7);
|
||||
delete[]$3;
|
||||
delete $5;
|
||||
}
|
||||
;
|
||||
: module
|
||||
| udp_primitive
|
||||
| nature_declaration
|
||||
| discipline_declaration
|
||||
| KK_attribute '(' IDENTIFIER ',' STRING ',' STRING ')'
|
||||
{ perm_string tmp3 = lex_strings.make($3);
|
||||
pform_set_type_attrib(tmp3, $5, $7);
|
||||
delete[]$3;
|
||||
delete $5;
|
||||
}
|
||||
;
|
||||
|
||||
/* The discipline and nature declarations used to take no ';' after
|
||||
the identifier. The 2.3 LRM adds the ';', but since there are
|
||||
programs written to the 2.1 and 2.2 standard that don't, we
|
||||
choose to make the ';' optional in this context. */
|
||||
optional_semicolon : ';' | ;
|
||||
|
||||
discipline_declaration
|
||||
: K_discipline IDENTIFIER optional_semicolon
|
||||
{ pform_start_discipline($2); }
|
||||
discipline_items K_enddiscipline
|
||||
{ pform_end_discipline(@1); delete[] $2; }
|
||||
;
|
||||
|
||||
discipline_items
|
||||
: discipline_items discipline_item
|
||||
| discipline_item
|
||||
;
|
||||
|
||||
discipline_item
|
||||
: K_domain K_discrete ';'
|
||||
{ pform_discipline_domain(@1, DD_DISCRETE); }
|
||||
| K_domain K_continuous ';'
|
||||
{ pform_discipline_domain(@1, DD_CONTINUOUS); }
|
||||
| K_potential IDENTIFIER ';'
|
||||
{ pform_discipline_potential(@1, $2); delete[] $2; }
|
||||
| K_flow IDENTIFIER ';'
|
||||
{ pform_discipline_flow(@1, $2); delete[] $2; }
|
||||
;
|
||||
|
||||
nature_declaration
|
||||
: K_nature IDENTIFIER optional_semicolon
|
||||
{ pform_start_nature($2); }
|
||||
nature_items
|
||||
K_endnature
|
||||
{ pform_end_nature(@1); delete[] $2; }
|
||||
;
|
||||
|
||||
nature_items
|
||||
: nature_items nature_item
|
||||
| nature_item
|
||||
;
|
||||
|
||||
nature_item
|
||||
: K_units '=' STRING ';'
|
||||
{ delete[] $3; }
|
||||
| K_abstol '=' expression ';'
|
||||
| K_access '=' IDENTIFIER ';'
|
||||
{ pform_nature_access(@1, $3); delete[] $3; }
|
||||
| K_idt_nature '=' IDENTIFIER ';'
|
||||
{ delete[] $3; }
|
||||
| K_ddt_nature '=' IDENTIFIER ';'
|
||||
{ delete[] $3; }
|
||||
;
|
||||
|
||||
drive_strength
|
||||
: '(' dr_strength0 ',' dr_strength1 ')'
|
||||
@@ -773,6 +845,15 @@ event_expression
|
||||
}
|
||||
;
|
||||
|
||||
/* A branch probe expression applies a probe function (potential or
|
||||
flow) to a branch. The branch may be implicit as a pair of nets
|
||||
or explicit as a named branch. Elaboration will check that the
|
||||
function name really is a nature attribute identifier. */
|
||||
branch_probe_expression
|
||||
: IDENTIFIER '(' IDENTIFIER ',' IDENTIFIER ')'
|
||||
| IDENTIFIER '(' IDENTIFIER ')'
|
||||
;
|
||||
|
||||
expression
|
||||
: expr_primary
|
||||
{ $$ = $1; }
|
||||
@@ -1902,6 +1983,12 @@ module_item
|
||||
yyerrok;
|
||||
}
|
||||
|
||||
/* Maybe this is a discipline declaration? If so, then the lexor
|
||||
will see the discipline name as an identifier. We match it to the
|
||||
discipline or type name semantically. */
|
||||
| DISCIPLINE_IDENTIFIER list_of_identifiers ';'
|
||||
{ pform_attach_discipline(@1, $1, $2); }
|
||||
|
||||
/* block_item_decl rule is shared with task blocks and named
|
||||
begin/end. */
|
||||
|
||||
@@ -1981,16 +2068,16 @@ module_item
|
||||
|
||||
/* Always and initial items are behavioral processes. */
|
||||
|
||||
| attribute_list_opt K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS,
|
||||
$3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_initial statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL,
|
||||
$3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_always statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
| attribute_list_opt K_initial statement
|
||||
{ PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $3, $1);
|
||||
FILE_NAME(tmp, @2);
|
||||
}
|
||||
|
||||
| attribute_list_opt K_analog analog_statement
|
||||
|
||||
/* The task declaration rule matches the task declaration
|
||||
header, then pushes the function scope. This causes the
|
||||
@@ -2275,23 +2362,48 @@ var_type
|
||||
generates a type (optional) and a list of assignments. */
|
||||
|
||||
parameter_assign_decl
|
||||
: parameter_assign_list
|
||||
| range { active_range = $1; active_signed = false; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_signed range { active_range = $2; active_signed = true; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_integer { active_range = 0; active_signed = true; }
|
||||
parameter_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
;
|
||||
: parameter_assign_list
|
||||
| range
|
||||
{ param_active_range = $1;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_signed range
|
||||
{ param_active_range = $2;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_integer
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_real
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_REAL;
|
||||
}
|
||||
parameter_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
;
|
||||
|
||||
parameter_assign_list
|
||||
: parameter_assign
|
||||
@@ -2299,22 +2411,44 @@ parameter_assign_list
|
||||
;
|
||||
|
||||
parameter_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be a constant expression.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
} else {
|
||||
pform_set_parameter(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp,
|
||||
@1.text, @1.first_line);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
: IDENTIFIER '=' expression parameter_value_ranges_opt
|
||||
{ PExpr*tmp = $3;
|
||||
pform_set_parameter(@1, lex_strings.make($1), param_active_type,
|
||||
param_active_signed, param_active_range, tmp, $4);
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
|
||||
parameter_value_ranges_opt : parameter_value_ranges { $$ = $1; } | { $$ = 0; } ;
|
||||
|
||||
parameter_value_ranges
|
||||
: parameter_value_ranges parameter_value_range
|
||||
{ $$ = $2; $$->next = $1; }
|
||||
| parameter_value_range
|
||||
{ $$ = $1; $$->next = 0; }
|
||||
;
|
||||
|
||||
parameter_value_range
|
||||
: from_exclude '[' value_range_expression ':' value_range_expression ']'
|
||||
{ $$ = pform_parameter_value_range($1, false, $3, false, $5); }
|
||||
| from_exclude '[' value_range_expression ':' value_range_expression ')'
|
||||
{ $$ = pform_parameter_value_range($1, false, $3, true, $5); }
|
||||
| from_exclude '(' value_range_expression ':' value_range_expression ']'
|
||||
{ $$ = pform_parameter_value_range($1, true, $3, false, $5); }
|
||||
| from_exclude '(' value_range_expression ':' value_range_expression ')'
|
||||
{ $$ = pform_parameter_value_range($1, true, $3, true, $5); }
|
||||
| K_exclude expression
|
||||
{ $$ = pform_parameter_value_range(true, false, $2, false, $2); }
|
||||
;
|
||||
|
||||
value_range_expression
|
||||
: expression { $$ = $1; }
|
||||
| K_inf { $$ = 0; }
|
||||
| '+' K_inf { $$ = 0; }
|
||||
| '-' K_inf { $$ = 0; }
|
||||
;
|
||||
|
||||
from_exclude : K_from { $$ = false; } | K_exclude { $$ = true; } ;
|
||||
|
||||
/* Localparam assignments and assignment lists are broken into
|
||||
separate BNF so that I can call slightly different parameter
|
||||
@@ -2322,41 +2456,59 @@ parameter_assign
|
||||
behave differently when someone tries to override them. */
|
||||
|
||||
localparam_assign
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
if (!pform_expression_is_constant(tmp)) {
|
||||
yyerror(@3, "error: parameter value "
|
||||
"must be constant.");
|
||||
delete tmp;
|
||||
tmp = 0;
|
||||
} else {
|
||||
pform_set_localparam(lex_strings.make($1),
|
||||
active_signed,
|
||||
active_range, tmp,
|
||||
@1.text, @1.first_line);
|
||||
}
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
: IDENTIFIER '=' expression
|
||||
{ PExpr*tmp = $3;
|
||||
pform_set_localparam(@1, lex_strings.make($1),
|
||||
param_active_type,
|
||||
param_active_signed,
|
||||
param_active_range, tmp);
|
||||
delete[]$1;
|
||||
}
|
||||
;
|
||||
|
||||
localparam_assign_decl
|
||||
: localparam_assign_list
|
||||
| range { active_range = $1; active_signed = false; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_signed range { active_range = $2; active_signed = true; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
| K_integer { active_range = 0; active_signed = true; }
|
||||
localparam_assign_list
|
||||
{ active_range = 0;
|
||||
active_signed = false;
|
||||
}
|
||||
;
|
||||
: localparam_assign_list
|
||||
| range
|
||||
{ param_active_range = $1;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_NO_TYPE;
|
||||
}
|
||||
| K_signed range
|
||||
{ param_active_range = $2;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_integer
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
| K_real
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = true;
|
||||
param_active_type = IVL_VT_REAL;
|
||||
}
|
||||
localparam_assign_list
|
||||
{ param_active_range = 0;
|
||||
param_active_signed = false;
|
||||
param_active_type = IVL_VT_LOGIC;
|
||||
}
|
||||
;
|
||||
|
||||
localparam_assign_list
|
||||
: localparam_assign
|
||||
@@ -3492,6 +3644,12 @@ statement_or_null
|
||||
| ';' { $$ = 0; }
|
||||
;
|
||||
|
||||
|
||||
analog_statement
|
||||
: branch_probe_expression K_CONTRIBUTE expression ';'
|
||||
{ yyerror(@1, "sorry: Analog contribution statements not supported."); }
|
||||
;
|
||||
|
||||
/* Task items are, other than the statement, task port items and
|
||||
other block items. */
|
||||
task_item
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#endif
|
||||
|
||||
# include <list>
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
|
||||
/*
|
||||
@@ -39,6 +40,13 @@ struct vlltype {
|
||||
};
|
||||
# define YYLTYPE struct vlltype
|
||||
|
||||
class LineInfo;
|
||||
inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/* This for compatibility with new and older bison versions. */
|
||||
#ifndef yylloc
|
||||
# define yylloc VLlloc
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <list>
|
||||
# include <map>
|
||||
# include <assert.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
|
||||
# include "ivl_assert.h"
|
||||
|
||||
|
||||
map<perm_string,Module*> pform_modules;
|
||||
map<perm_string,PUdp*> pform_primitives;
|
||||
|
||||
@@ -82,12 +82,6 @@ static inline void FILE_NAME(LineInfo*obj, const char*file, unsigned lineno)
|
||||
obj->set_file(filename_strings.make(file));
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where)
|
||||
{
|
||||
tmp->set_lineno(where.first_line);
|
||||
tmp->set_file(filename_strings.make(where.text));
|
||||
}
|
||||
|
||||
/*
|
||||
* The lexical_scope keeps track of the current lexical scope that is
|
||||
* being parsed. The lexical scope may stack, so the current scope may
|
||||
@@ -137,7 +131,7 @@ PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt)
|
||||
return block;
|
||||
}
|
||||
|
||||
static PWire*get_wire_in_scope(perm_string name)
|
||||
PWire*pform_get_wire_in_scope(perm_string name)
|
||||
{
|
||||
/* Note that if we are processing a generate, then the
|
||||
scope depth will be empty because generate schemes
|
||||
@@ -925,7 +919,7 @@ static void pform_set_net_range(perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
PWSRType rt)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror("error: name is not a valid net.");
|
||||
return;
|
||||
@@ -1344,7 +1338,7 @@ void pform_makewire(const vlltype&li, perm_string name,
|
||||
ivl_variable_type_t dt,
|
||||
svector<named_pexpr_t*>*attr)
|
||||
{
|
||||
PWire*cur = get_wire_in_scope(name);
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
|
||||
// If this is not implicit ("implicit" meaning we don't know
|
||||
// what the type is yet) then set the type now.
|
||||
@@ -1458,7 +1452,7 @@ void pform_makewire(const vlltype&li,
|
||||
SR_NET);
|
||||
}
|
||||
|
||||
PWire*cur = get_wire_in_scope(first->name);
|
||||
PWire*cur = pform_get_wire_in_scope(first->name);
|
||||
if (cur != 0) {
|
||||
PEIdent*lval = new PEIdent(first->name);
|
||||
FILE_NAME(lval, li.text, li.first_line);
|
||||
@@ -1640,50 +1634,76 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r)
|
||||
cur->set_memory_idx(l, r);
|
||||
}
|
||||
|
||||
void pform_set_parameter(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr)
|
||||
{
|
||||
// Detect +-inf and make the the *_open flags false to force
|
||||
// the range interpretation as inf.
|
||||
if (low_expr == 0) low_open = false;
|
||||
if (hig_expr == 0) hig_open = false;
|
||||
|
||||
Module::range_t*tmp = new Module::range_t;
|
||||
tmp->exclude_flag = exclude_flag;
|
||||
tmp->low_open_flag = low_open;
|
||||
tmp->low_expr = low_expr;
|
||||
tmp->high_open_flag = hig_open;
|
||||
tmp->high_expr = hig_expr;
|
||||
tmp->next = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr,
|
||||
Module::range_t*value_range)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->parameters[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->parameters[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->parameters[name].msb = (*range)[0];
|
||||
pform_cur_module->parameters[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->parameters[name].msb = 0;
|
||||
pform_cur_module->parameters[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->parameters[name].signed_flag = signed_flag;
|
||||
pform_cur_module->parameters[name].file = filename_strings.make(file);
|
||||
pform_cur_module->parameters[name].lineno = lineno;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = value_range;
|
||||
|
||||
pform_cur_module->param_names.push_back(name);
|
||||
}
|
||||
|
||||
void pform_set_localparam(perm_string name, bool signed_flag,
|
||||
svector<PExpr*>*range, PExpr*expr,
|
||||
const char*file, unsigned lineno)
|
||||
void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name, ivl_variable_type_t type,
|
||||
bool signed_flag, svector<PExpr*>*range, PExpr*expr)
|
||||
{
|
||||
assert(expr);
|
||||
pform_cur_module->localparams[name].expr = expr;
|
||||
Module::param_expr_t&parm = pform_cur_module->localparams[name];
|
||||
FILE_NAME(&parm, loc);
|
||||
|
||||
parm.expr = expr;
|
||||
|
||||
parm.type = type;
|
||||
if (range) {
|
||||
assert(range->count() == 2);
|
||||
assert((*range)[0]);
|
||||
assert((*range)[1]);
|
||||
pform_cur_module->localparams[name].msb = (*range)[0];
|
||||
pform_cur_module->localparams[name].lsb = (*range)[1];
|
||||
parm.msb = (*range)[0];
|
||||
parm.lsb = (*range)[1];
|
||||
} else {
|
||||
pform_cur_module->localparams[name].msb = 0;
|
||||
pform_cur_module->localparams[name].lsb = 0;
|
||||
parm.msb = 0;
|
||||
parm.lsb = 0;
|
||||
}
|
||||
pform_cur_module->localparams[name].signed_flag = signed_flag;
|
||||
pform_cur_module->localparams[name].file = filename_strings.make(file);
|
||||
pform_cur_module->localparams[name].lineno = lineno;
|
||||
parm.signed_flag = signed_flag;
|
||||
parm.range = 0;
|
||||
}
|
||||
|
||||
void pform_set_specparam(perm_string name, PExpr*expr)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
# include "PUdp.h"
|
||||
# include "PWire.h"
|
||||
# include "verinum.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <list>
|
||||
@@ -115,11 +116,19 @@ struct lgate {
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
|
||||
/* The lexor calls this function to change the default nettype. */
|
||||
extern void pform_set_default_nettype(NetNet::Type net,
|
||||
const char*file,
|
||||
unsigned lineno);
|
||||
|
||||
/*
|
||||
* Look for the given wire in the current lexical scope. If the wire
|
||||
* (including variables of any type) cannot be found in the current
|
||||
* scope, then return 0.
|
||||
*/
|
||||
extern PWire* pform_get_wire_in_scope(perm_string name);
|
||||
|
||||
/*
|
||||
* The parser uses startmodule and endmodule together to build up a
|
||||
* module as it parses it. The startmodule tells the pform code that a
|
||||
@@ -257,16 +266,22 @@ extern void pform_set_attrib(perm_string name, perm_string key,
|
||||
extern void pform_set_type_attrib(perm_string name, const string&key,
|
||||
char*value);
|
||||
|
||||
extern void pform_set_parameter(perm_string name,
|
||||
extern Module::range_t* pform_parameter_value_range(bool exclude_flag,
|
||||
bool low_open, PExpr*low_expr,
|
||||
bool hig_open, PExpr*hig_expr);
|
||||
|
||||
extern void pform_set_parameter(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
extern void pform_set_localparam(perm_string name,
|
||||
PExpr*expr, Module::range_t*value_range);
|
||||
extern void pform_set_localparam(const struct vlltype&loc,
|
||||
perm_string name,
|
||||
ivl_variable_type_t type,
|
||||
bool signed_flag,
|
||||
svector<PExpr*>*range,
|
||||
PExpr*expr,
|
||||
const char*file, unsigned lineno);
|
||||
PExpr*expr);
|
||||
extern void pform_set_defparam(const pform_name_t&name, PExpr*expr);
|
||||
|
||||
/*
|
||||
@@ -350,4 +365,28 @@ extern void pform_dump(ostream&out, Module*mod);
|
||||
*/
|
||||
extern void pform_error_nested_modules();
|
||||
|
||||
/* ** pform_discipline.cc
|
||||
* Functions for handling the parse of natures and disciplines. These
|
||||
* functions are in pform_disciplines.cc
|
||||
*/
|
||||
class discipline_t;
|
||||
|
||||
extern void pform_start_nature(const char*name);
|
||||
extern void pform_end_nature(const struct vlltype&loc);
|
||||
|
||||
extern void pform_nature_access(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_start_discipline(const char*name);
|
||||
extern void pform_end_discipline(const struct vlltype&loc);
|
||||
|
||||
extern void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain);
|
||||
extern void pform_discipline_potential(const struct vlltype&loc, const char*name);
|
||||
extern void pform_discipline_flow(const struct vlltype&loc, const char*name);
|
||||
|
||||
extern void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names);
|
||||
|
||||
extern void pform_dump(ostream&out, const nature_t*);
|
||||
extern void pform_dump(ostream&out, const discipline_t*);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "config.h"
|
||||
# include "compiler.h"
|
||||
# include "pform.h"
|
||||
# include "parse_misc.h"
|
||||
# include "discipline.h"
|
||||
|
||||
map<perm_string,nature_t*> natures;
|
||||
map<perm_string,discipline_t*> disciplines;
|
||||
|
||||
static perm_string nature_name = perm_string::perm_string();
|
||||
static perm_string nature_access = perm_string::perm_string();
|
||||
|
||||
void pform_start_nature(const char*name)
|
||||
{
|
||||
nature_name = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_nature_access(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many access names for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
nature_access = lex_strings.make(name);
|
||||
}
|
||||
|
||||
void pform_end_nature(const struct vlltype&loc)
|
||||
{
|
||||
// The nature access function is required. If it is missing,
|
||||
// then signal an error. For a temporary expedient, we can set
|
||||
// the nature name as the access function, but don't expect it
|
||||
// to work.
|
||||
if (! nature_access) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Missing access name for nature "
|
||||
<< nature_name << "." << endl;
|
||||
error_count += 1;
|
||||
nature_access = nature_name;
|
||||
}
|
||||
|
||||
nature_t*tmp = new nature_t(nature_name, nature_access);
|
||||
natures[nature_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
nature_name = perm_string::perm_string();
|
||||
nature_access = perm_string::perm_string();
|
||||
}
|
||||
|
||||
|
||||
static perm_string discipline_name;
|
||||
static ddomain_t discipline_domain = DD_NONE;
|
||||
static nature_t* discipline_potential = 0;
|
||||
static nature_t* discipline_flow = 0;
|
||||
|
||||
void pform_start_discipline(const char*name)
|
||||
{
|
||||
discipline_name = lex_strings.make(name);
|
||||
discipline_domain = DD_NONE;
|
||||
}
|
||||
|
||||
void pform_discipline_domain(const struct vlltype&loc, ddomain_t use_domain)
|
||||
{
|
||||
assert(use_domain != DD_NONE);
|
||||
|
||||
if (discipline_domain != DD_NONE) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many domain attributes for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
discipline_domain = use_domain;
|
||||
}
|
||||
|
||||
void pform_discipline_potential(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_potential) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many potential natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_potential = natures[key];
|
||||
|
||||
if (discipline_potential == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_discipline_flow(const struct vlltype&loc, const char*name)
|
||||
{
|
||||
if (discipline_flow) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "Too many flow natures for discipline "
|
||||
<< discipline_name << "." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
perm_string key = lex_strings.make(name);
|
||||
discipline_flow = natures[key];
|
||||
|
||||
if (discipline_flow == 0) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "nature " << key << " is not declared." << endl;
|
||||
error_count += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void pform_end_discipline(const struct vlltype&loc)
|
||||
{
|
||||
// If the domain is not otherwise specified, then take it to
|
||||
// be continuous if potential or flow natures are given.
|
||||
if (discipline_domain == DD_NONE && (discipline_potential||discipline_flow))
|
||||
discipline_domain = DD_CONTINUOUS;
|
||||
|
||||
discipline_t*tmp = new discipline_t(discipline_name, discipline_domain,
|
||||
discipline_potential, discipline_flow);
|
||||
disciplines[discipline_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
/* Clear the static variables for the next item. */
|
||||
discipline_name = perm_string::perm_string();
|
||||
discipline_domain = DD_NONE;
|
||||
discipline_potential = 0;
|
||||
discipline_flow = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The parser uses this function to attach a discipline to a wire. The
|
||||
* wire may be declared by now, or will be declared further later. If
|
||||
* it is already declared, we just attach the discipline. If it is not
|
||||
* declared yet, then this is the declaration and we create the signal
|
||||
* in the current lexical scope.
|
||||
*/
|
||||
void pform_attach_discipline(const struct vlltype&loc,
|
||||
discipline_t*discipline, list<perm_string>*names)
|
||||
{
|
||||
for (list<perm_string>::iterator cur = names->begin()
|
||||
; cur != names->end() ; cur ++ ) {
|
||||
|
||||
PWire* cur_net = pform_get_wire_in_scope(*cur);
|
||||
if (cur_net == 0) {
|
||||
/* Not declared yet, declare it now. */
|
||||
pform_makewire(loc, *cur, NetNet::WIRE,
|
||||
NetNet::NOT_A_PORT, IVL_VT_REAL, 0);
|
||||
cur_net = pform_get_wire_in_scope(*cur);
|
||||
assert(cur_net);
|
||||
}
|
||||
|
||||
if (discipline_t*tmp = cur_net->get_discipline()) {
|
||||
cerr << loc.text << ":" << loc.first_line << ": error: "
|
||||
<< "discipline " << discipline->name()
|
||||
<< " cannot override existing discipline " << tmp->name()
|
||||
<< " on net " << cur_net->basename() << endl;
|
||||
error_count += 1;
|
||||
|
||||
} else {
|
||||
cur_net->set_discipline(discipline);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
-3
@@ -29,6 +29,7 @@
|
||||
# include "PEvent.h"
|
||||
# include "PGenerate.h"
|
||||
# include "PSpec.h"
|
||||
# include "discipline.h"
|
||||
# include <iostream>
|
||||
# include <iomanip>
|
||||
# include <typeinfo>
|
||||
@@ -128,6 +129,26 @@ ostream& operator<< (ostream&o, const pform_name_t&that)
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream&out, ddomain_t dom)
|
||||
{
|
||||
switch (dom) {
|
||||
case DD_NONE:
|
||||
out << "no-domain";
|
||||
break;
|
||||
case DD_DISCRETE:
|
||||
out << "discrete";
|
||||
break;
|
||||
case DD_CONTINUOUS:
|
||||
out << "continuous";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void PExpr::dump(ostream&out) const
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
@@ -300,6 +321,10 @@ void PWire::dump(ostream&out, unsigned ind) const
|
||||
out << " signed";
|
||||
}
|
||||
|
||||
if (discipline_) {
|
||||
out << " discipline<" << discipline_->name() << ">";
|
||||
}
|
||||
|
||||
if (port_set_) {
|
||||
if (port_msb_ == 0) {
|
||||
out << " port<scalar>";
|
||||
@@ -969,7 +994,7 @@ void Module::dump(ostream&out) const
|
||||
typedef map<pform_name_t,PExpr*>::const_iterator parm_hiter_t;
|
||||
for (parm_iter_t cur = parameters.begin()
|
||||
; cur != parameters.end() ; cur ++) {
|
||||
out << " parameter ";
|
||||
out << " parameter " << (*cur).second.type << " ";
|
||||
if ((*cur).second.signed_flag)
|
||||
out << "signed ";
|
||||
if ((*cur).second.msb)
|
||||
@@ -977,9 +1002,38 @@ void Module::dump(ostream&out) const
|
||||
<< *(*cur).second.lsb << "] ";
|
||||
out << (*cur).first << " = ";
|
||||
if ((*cur).second.expr)
|
||||
out << *(*cur).second.expr << ";" << endl;
|
||||
out << *(*cur).second.expr;
|
||||
else
|
||||
out << "/* ERROR */;" << endl;
|
||||
out << "/* ERROR */";
|
||||
for (Module::range_t*tmp = (*cur).second.range
|
||||
; tmp ; tmp = tmp->next) {
|
||||
if (tmp->exclude_flag)
|
||||
out << " exclude ";
|
||||
else
|
||||
out << " from ";
|
||||
if (tmp->low_open_flag)
|
||||
out << "(";
|
||||
else
|
||||
out << "[";
|
||||
if (tmp->low_expr)
|
||||
out << *(tmp->low_expr);
|
||||
else if (tmp->low_open_flag==false)
|
||||
out << "-inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
out << ":";
|
||||
if (tmp->high_expr)
|
||||
out << *(tmp->high_expr);
|
||||
else if (tmp->high_open_flag==false)
|
||||
out << "inf";
|
||||
else
|
||||
out << "<nil>";
|
||||
if (tmp->high_open_flag)
|
||||
out << ")";
|
||||
else
|
||||
out << "]";
|
||||
}
|
||||
out << ";" << endl;
|
||||
}
|
||||
|
||||
for (parm_iter_t cur = localparams.begin()
|
||||
@@ -1123,3 +1177,21 @@ void PUdp::dump(ostream&out) const
|
||||
|
||||
out << "endprimitive" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const nature_t*nat)
|
||||
{
|
||||
out << "nature " << nat->name() << endl;
|
||||
out << " access " << nat->access() << ";" << endl;
|
||||
out << "endnature" << endl;
|
||||
}
|
||||
|
||||
void pform_dump(std::ostream&out, const discipline_t*dis)
|
||||
{
|
||||
out << "discipline " << dis->name() << endl;
|
||||
out << " domain " << dis->domain() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->potential())
|
||||
out << " potential " << tmp->name() << ";" << endl;
|
||||
if (const nature_t*tmp = dis->flow())
|
||||
out << " flow " << tmp->name() << ";" << endl;
|
||||
out << "enddiscipline" << endl;
|
||||
}
|
||||
|
||||
+104
-4
@@ -555,6 +555,28 @@ extern "C" unsigned ivl_file_table_size()
|
||||
return fn_vector.size();
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
|
||||
{
|
||||
if (flag >= net->flags.size()) {
|
||||
if (value == 0)
|
||||
return 0;
|
||||
else
|
||||
net->flags.resize(flag+1, false);
|
||||
}
|
||||
|
||||
int old_flag = net->flags[flag];
|
||||
net->flags[flag] = value != 0;
|
||||
return old_flag;
|
||||
}
|
||||
|
||||
extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
|
||||
{
|
||||
if (flag >= net->flags.size())
|
||||
return 0;
|
||||
else
|
||||
return net->flags[flag];
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_logic_attr(ivl_net_logic_t net, const char*key)
|
||||
{
|
||||
assert(net);
|
||||
@@ -782,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
|
||||
switch (net->type) {
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.base;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -918,7 +939,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx <= 1);
|
||||
if (idx == 0)
|
||||
return net->u_.part.a;
|
||||
@@ -1061,7 +1081,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx == 0);
|
||||
return net->u_.part.q;
|
||||
|
||||
@@ -1157,7 +1176,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
||||
return 0;
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.signed_flag;
|
||||
case IVL_LPM_REPEAT:
|
||||
return 0;
|
||||
@@ -1338,6 +1356,15 @@ extern "C" ivl_signal_t ivl_nexus_ptr_sig(ivl_nexus_ptr_t net)
|
||||
return net->l.sig;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_nexus_ptr_switch(ivl_nexus_ptr_t net)
|
||||
{
|
||||
if (net == 0)
|
||||
return 0;
|
||||
if (net->type_ != __NEXUS_PTR_SWI)
|
||||
return 0;
|
||||
return net->l.swi;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_parameter_basename(ivl_parameter_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -1627,6 +1654,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
|
||||
return net->sigs_[idx];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->switches.size();
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx)
|
||||
{
|
||||
assert(net);
|
||||
assert(idx < net->switches.size());
|
||||
return net->switches[idx];
|
||||
}
|
||||
|
||||
extern "C" int ivl_scope_time_precision(ivl_scope_t net)
|
||||
{
|
||||
assert(net);
|
||||
@@ -2143,3 +2183,63 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" const char*ivl_switch_basename(ivl_switch_t net)
|
||||
{
|
||||
return net->name;
|
||||
}
|
||||
|
||||
extern "C" ivl_scope_t ivl_switch_scope(ivl_switch_t net)
|
||||
{
|
||||
return net->scope;
|
||||
}
|
||||
|
||||
extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net)
|
||||
{
|
||||
return net->type;
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[0];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[1];
|
||||
}
|
||||
|
||||
extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
|
||||
{
|
||||
return net->pins[2];
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_width(ivl_switch_t net)
|
||||
{
|
||||
return net->width;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_part(ivl_switch_t net)
|
||||
{
|
||||
return net->part;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
|
||||
{
|
||||
return net->offset;
|
||||
}
|
||||
|
||||
extern "C" const char* ivl_switch_file(ivl_switch_t net)
|
||||
{
|
||||
return net->file;
|
||||
}
|
||||
|
||||
extern "C" ivl_island_t ivl_switch_island(ivl_switch_t net)
|
||||
{
|
||||
return net->island;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_switch_lineno(ivl_switch_t net)
|
||||
{
|
||||
return net->lineno;
|
||||
}
|
||||
|
||||
@@ -380,6 +380,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin,
|
||||
nex->ptrs_[top-1].l.lpm= net;
|
||||
}
|
||||
|
||||
static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin)
|
||||
{
|
||||
unsigned top = nex->nptr_ + 1;
|
||||
nex->ptrs_ = (struct ivl_nexus_ptr_s*)
|
||||
realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s));
|
||||
nex->nptr_ = top;
|
||||
|
||||
nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI;
|
||||
nex->ptrs_[top-1].drive0 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].drive1 = IVL_DR_HiZ;
|
||||
nex->ptrs_[top-1].pin_ = pin;
|
||||
nex->ptrs_[top-1].l.swi= net;
|
||||
}
|
||||
|
||||
void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net)
|
||||
{
|
||||
@@ -431,6 +444,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net)
|
||||
{
|
||||
scope->switches.push_back(net);
|
||||
}
|
||||
|
||||
ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope,
|
||||
const char*name)
|
||||
{
|
||||
@@ -470,8 +488,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
cur_par->file = (*cur_pit).second.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -484,8 +502,8 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net)
|
||||
ivl_parameter_t cur_par = scope->param_ + idx;
|
||||
cur_par->basename = (*cur_pit).first;
|
||||
cur_par->scope = scope;
|
||||
cur_par->file = (*cur_pit).second.file;
|
||||
cur_par->lineno = (*cur_pit).second.lineno;
|
||||
cur_par->file = (*cur_pit).second.get_file();
|
||||
cur_par->lineno = (*cur_pit).second.get_lineno();
|
||||
|
||||
NetExpr*etmp = (*cur_pit).second.expr;
|
||||
make_scope_param_expr(cur_par, etmp);
|
||||
@@ -621,6 +639,13 @@ int dll_target::end_design(const Design*)
|
||||
return rc;
|
||||
}
|
||||
|
||||
void dll_target::switch_attributes(struct ivl_switch_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
obj->nattr = net->attr_cnt();
|
||||
obj->attr = fill_in_attributes(net);
|
||||
}
|
||||
|
||||
void dll_target::logic_attributes(struct ivl_net_logic_s *obj,
|
||||
const NetNode*net)
|
||||
{
|
||||
@@ -1008,6 +1033,56 @@ void dll_target::logic(const NetLogic*net)
|
||||
scope_add_logic(scope, obj);
|
||||
}
|
||||
|
||||
bool dll_target::tran(const NetTran*net)
|
||||
{
|
||||
struct ivl_switch_s*obj = new struct ivl_switch_s;
|
||||
obj->type = net->type();
|
||||
obj->width = 0;
|
||||
obj->part = 0;
|
||||
obj->offset = 0;
|
||||
obj->name = net->name();
|
||||
obj->scope = find_scope(des_, net->scope());
|
||||
obj->island = net->island;
|
||||
assert(obj->scope);
|
||||
assert(obj->island);
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[0] = nex->t_cookie();
|
||||
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[1] = nex->t_cookie();
|
||||
|
||||
nexus_switch_add(obj->pins[0], obj, 0);
|
||||
nexus_switch_add(obj->pins[1], obj, 1);
|
||||
|
||||
if (net->pin_count() > 2) {
|
||||
nex = net->pin(2).nexus();
|
||||
assert(nex->t_cookie());
|
||||
obj->pins[2] = nex->t_cookie();
|
||||
nexus_switch_add(obj->pins[2], obj, 2);
|
||||
} else {
|
||||
obj->pins[2] = 0;
|
||||
}
|
||||
|
||||
if (obj->type == IVL_SW_TRAN_VP) {
|
||||
obj->width = net->vector_width();
|
||||
obj->part = net->part_width();
|
||||
obj->offset= net->part_offset();
|
||||
}
|
||||
|
||||
obj->file = net->get_file();
|
||||
obj->lineno = net->get_lineno();
|
||||
|
||||
switch_attributes(obj, net);
|
||||
scope_add_switch(obj->scope, obj);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dll_target::sign_extend(const NetSignExtend*net)
|
||||
{
|
||||
struct ivl_lpm_s*obj = new struct ivl_lpm_s;
|
||||
@@ -1930,9 +2005,6 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
case NetPartSelect::PV:
|
||||
obj->type = IVL_LPM_PART_PV;
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
obj->type = IVL_LPM_PART_BI;
|
||||
break;
|
||||
}
|
||||
obj->name = net->name(); // NetPartSelect names are permallocated.
|
||||
assert(net->scope());
|
||||
@@ -1986,35 +2058,12 @@ bool dll_target::part_select(const NetPartSelect*net)
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
/* For now, handle this exactly the same as a PV */
|
||||
|
||||
/* NetPartSelect:pin(0) is the output pin. */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.q = nex->t_cookie();
|
||||
|
||||
/* NetPartSelect:pin(1) is the input pin. */
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.a = nex->t_cookie();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
|
||||
/* If the device is a PART_BI, then the "input" is also a
|
||||
strength aware output, so attach it to the nexus with
|
||||
strong driver. */
|
||||
if (obj->type == IVL_LPM_PART_BI)
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
else
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
/* The select input is optional. */
|
||||
if (obj->u_.part.s)
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
|
||||
# include "target.h"
|
||||
# include "ivl_target.h"
|
||||
# include "ivl_target_priv.h"
|
||||
# include "StringHeap.h"
|
||||
# include "netlist.h"
|
||||
# include <vector>
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#include <windows.h>
|
||||
@@ -67,6 +69,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
bool bufz(const NetBUFZ*);
|
||||
void event(const NetEvent*);
|
||||
void logic(const NetLogic*);
|
||||
bool tran(const NetTran*);
|
||||
bool ureduce(const NetUReduce*);
|
||||
void net_case_cmp(const NetCaseCmp*);
|
||||
void udp(const NetUDP*);
|
||||
@@ -146,6 +149,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
||||
ivl_scope_t lookup_scope_(const NetScope*scope);
|
||||
|
||||
ivl_attribute_s* fill_in_attributes(const Attrib*net);
|
||||
void switch_attributes(struct ivl_switch_s *obj, const NetNode*net);
|
||||
void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net);
|
||||
|
||||
private:
|
||||
@@ -445,6 +449,23 @@ struct ivl_net_logic_s {
|
||||
ivl_expr_t delay[3];
|
||||
};
|
||||
|
||||
struct ivl_switch_s {
|
||||
ivl_switch_type_t type;
|
||||
unsigned width;
|
||||
unsigned part;
|
||||
unsigned offset;
|
||||
|
||||
perm_string name;
|
||||
ivl_scope_t scope;
|
||||
ivl_island_t island;
|
||||
|
||||
struct ivl_attribute_s*attr;
|
||||
unsigned nattr;
|
||||
|
||||
ivl_nexus_t pins[3];
|
||||
perm_string file;
|
||||
unsigned lineno;
|
||||
};
|
||||
|
||||
/*
|
||||
* UDP definition.
|
||||
@@ -481,12 +502,14 @@ struct ivl_nexus_ptr_s {
|
||||
ivl_net_logic_t log; /* type 1 */
|
||||
ivl_net_const_t con; /* type 2 */
|
||||
ivl_lpm_t lpm; /* type 3 */
|
||||
ivl_switch_t swi; /* type 4 */
|
||||
} l;
|
||||
};
|
||||
# define __NEXUS_PTR_SIG 0
|
||||
# define __NEXUS_PTR_LOG 1
|
||||
# define __NEXUS_PTR_CON 2
|
||||
# define __NEXUS_PTR_LPM 3
|
||||
# define __NEXUS_PTR_SWI 4
|
||||
|
||||
/*
|
||||
* NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator.
|
||||
@@ -567,6 +590,8 @@ struct ivl_scope_s {
|
||||
unsigned ports;
|
||||
ivl_signal_t*port;
|
||||
|
||||
std::vector<ivl_switch_t>switches;
|
||||
|
||||
signed int time_precision :8;
|
||||
signed int time_units :8;
|
||||
|
||||
@@ -730,4 +755,10 @@ static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info)
|
||||
scope->def_lineno = info->get_def_lineno();
|
||||
}
|
||||
|
||||
static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info)
|
||||
{
|
||||
net->file = info->get_file();
|
||||
net->lineno = info->get_lineno();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,6 +61,13 @@ void target_t::logic(const NetLogic*)
|
||||
"Unhandled logic gate" << endl;
|
||||
}
|
||||
|
||||
bool target_t::tran(const NetTran*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
<< "TRAN devices not supported." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool target_t::bufz(const NetBUFZ*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
|
||||
@@ -86,6 +86,7 @@ struct target_t {
|
||||
|
||||
/* Output a gate (called for each gate) */
|
||||
virtual void logic(const NetLogic*);
|
||||
virtual bool tran(const NetTran*);
|
||||
virtual bool ureduce(const NetUReduce*); /* unary reduction operator */
|
||||
virtual bool bufz(const NetBUFZ*);
|
||||
virtual void udp(const NetUDP*);
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.11 2004/02/10 19:25:01 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep null.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
|
||||
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.20 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -44,6 +41,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep stub.tgt
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
@@ -51,7 +50,7 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = stub.o expression.o statement.o
|
||||
O = stub.o expression.o statement.o switches.o
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
TGTLDFLAGS=-L.. -livl
|
||||
|
||||
@@ -35,6 +35,15 @@ extern FILE*out;
|
||||
*/
|
||||
extern int stub_errors;
|
||||
|
||||
/*
|
||||
* This function finds the vector width of a signal. It relies on the
|
||||
* assumption that all the signal inputs to the nexus have the same
|
||||
* width. The ivl_target API should assert that condition.
|
||||
*/
|
||||
extern unsigned width_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* Show the details of the expression.
|
||||
*/
|
||||
@@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind);
|
||||
*/
|
||||
extern void show_statement(ivl_statement_t net, unsigned ind);
|
||||
|
||||
extern void show_switch(ivl_switch_t net);
|
||||
|
||||
/*
|
||||
*/
|
||||
extern const char*data_type_string(ivl_variable_type_t vtype);
|
||||
|
||||
@@ -288,7 +288,7 @@ void show_statement(ivl_statement_t net, unsigned ind)
|
||||
break;
|
||||
|
||||
case IVL_ST_DELAY:
|
||||
fprintf(out, "%*s#%llu\n", ind, "", ivl_stmt_delay_val(net));
|
||||
fprintf(out, "%*s#%" PRIu64 "\n", ind, "", ivl_stmt_delay_val(net));
|
||||
show_statement(ivl_stmt_sub_stmt(net), ind+2);
|
||||
break;
|
||||
|
||||
|
||||
+9
-37
@@ -555,38 +555,6 @@ static void show_lpm_part(ivl_lpm_t net)
|
||||
}
|
||||
}
|
||||
|
||||
static void show_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
ivl_nexus_t port_p = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t port_v = ivl_lpm_data(net,0);
|
||||
|
||||
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
|
||||
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
|
||||
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
|
||||
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
|
||||
width_of_nexus(port_v));
|
||||
|
||||
|
||||
/* The data(0) port must be large enough for the part select. */
|
||||
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
|
||||
fprintf(out, " ERROR: Part select is out of range."
|
||||
" Data nexus width=%u, width+base=%u\n",
|
||||
width_of_nexus(ivl_lpm_data(net,0)), width+base);
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
/* The Q vector must be exactly the width of the part select. */
|
||||
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
|
||||
fprintf(out, " ERROR: Part select input mismatch."
|
||||
" Nexus width=%u, expect width=%u\n",
|
||||
width_of_nexus(ivl_lpm_q(net,0)), width);
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The reduction operators have similar characteristics and are
|
||||
* displayed here.
|
||||
@@ -905,11 +873,6 @@ static void show_lpm(ivl_lpm_t net)
|
||||
show_lpm_part(net);
|
||||
break;
|
||||
|
||||
/* The BI part select is slightly special. */
|
||||
case IVL_LPM_PART_BI:
|
||||
show_lpm_part_bi(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_REPEAT:
|
||||
show_lpm_repeat(net);
|
||||
break;
|
||||
@@ -1059,6 +1022,7 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_net_logic_t log;
|
||||
ivl_lpm_t lpm;
|
||||
ivl_signal_t sig;
|
||||
ivl_switch_t swt;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
const char*dr0 = str_tab[ivl_nexus_ptr_drive0(ptr)];
|
||||
@@ -1092,6 +1056,11 @@ static void show_nexus_details(ivl_signal_t net, ivl_nexus_t nex)
|
||||
ivl_scope_name(ivl_lpm_scope(lpm)),
|
||||
ivl_lpm_basename(lpm), dr0, dr1);
|
||||
|
||||
} else if ((swt = ivl_nexus_ptr_switch(ptr))) {
|
||||
fprintf(out, " SWITCH %s.%s\n",
|
||||
ivl_scope_name(ivl_switch_scope(swt)),
|
||||
ivl_switch_basename(swt));
|
||||
|
||||
} else if ((con = ivl_nexus_ptr_con(ptr))) {
|
||||
signal_nexus_const(net, ptr, con);
|
||||
|
||||
@@ -1478,6 +1447,9 @@ static int show_scope(ivl_scope_t net, void*x)
|
||||
for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1)
|
||||
show_lpm(ivl_scope_lpm(net, idx));
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1)
|
||||
show_switch(ivl_scope_switch(net, idx));
|
||||
|
||||
switch (ivl_scope_type(net)) {
|
||||
case IVL_SCT_FUNCTION:
|
||||
case IVL_SCT_TASK:
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
# include "config.h"
|
||||
# include "priv.h"
|
||||
# include <stdlib.h>
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
void show_switch(ivl_switch_t net)
|
||||
{
|
||||
const char*name = ivl_switch_basename(net);
|
||||
int has_enable = 0;
|
||||
|
||||
switch (ivl_switch_type(net)) {
|
||||
case IVL_SW_TRAN:
|
||||
fprintf(out, " tran %s", name);
|
||||
break;
|
||||
case IVL_SW_RTRAN:
|
||||
fprintf(out, " rtran %s", name);
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
fprintf(out, " tranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF0:
|
||||
fprintf(out, " rtranif0 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
fprintf(out, " tranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_RTRANIF1:
|
||||
fprintf(out, " rtranif1 %s", name);
|
||||
has_enable = 1;
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
fprintf(out, " tran(VP wid=%u, part=%u, off=%u) %s",
|
||||
ivl_switch_width(net), ivl_switch_part(net),
|
||||
ivl_switch_offset(net), name);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, " island=%p\n", ivl_switch_island(net));
|
||||
|
||||
ivl_nexus_t nexa = ivl_switch_a(net);
|
||||
const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
|
||||
ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
|
||||
|
||||
ivl_nexus_t nexb = ivl_switch_b(net);
|
||||
nex_name = nexb? ivl_nexus_name(nexb) : "";
|
||||
ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
|
||||
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
|
||||
|
||||
/* The A/B pins of the switch must be present, and must match. */
|
||||
if (nex_type_a == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " A: ERROR: Type missing for pin A\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_b == IVL_VT_NO_TYPE) {
|
||||
fprintf(out, " B: ERROR: Type missing for pin B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (nex_type_a != nex_type_b) {
|
||||
fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n");
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
|
||||
/* The TRAN_VP nodes are special in that the specific
|
||||
width matters for each port and should be exactly
|
||||
right for both. */
|
||||
if (width_of_nexus(nexa) != ivl_switch_width(net)) {
|
||||
fprintf(out, " A: ERROR: part vector nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexa), ivl_switch_width(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (width_of_nexus(nexb) != ivl_switch_part(net)) {
|
||||
fprintf(out, " B: ERROR: part select nexus "
|
||||
"width=%u, expecting width=%u\n",
|
||||
width_of_nexus(nexb), ivl_switch_part(net));
|
||||
stub_errors += 1;
|
||||
}
|
||||
} else {
|
||||
/* All other TRAN nodes will have matching vector
|
||||
widths, but the actual value doesn't matter. */
|
||||
if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
|
||||
fprintf(out, " A/B: ERROR: Width of ports don't match"
|
||||
": A=%u, B=%u\n",
|
||||
width_of_nexus(nexa), width_of_nexus(nexb));
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_enable) {
|
||||
ivl_nexus_t nexe = ivl_switch_enable(net);
|
||||
nex_name = nexe? ivl_nexus_name(nexe) : "";
|
||||
fprintf(out, " E: %s\n", nex_name);
|
||||
if (width_of_nexus(nexe) != 1) {
|
||||
fprintf(out, " E: ERROR: Nexus width is %u\n",
|
||||
width_of_nexus(nexe));
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -51,7 +51,8 @@ dep:
|
||||
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
|
||||
mv $*.d dep
|
||||
|
||||
O = vvp.o draw_mux.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \
|
||||
O = vvp.o draw_mux.o draw_net_input.o draw_switch.o draw_ufunc.o draw_vpi.o \
|
||||
eval_bool.o eval_expr.o \
|
||||
eval_real.o modpath.o vector.o \
|
||||
vvp_process.o vvp_scope.o
|
||||
|
||||
|
||||
@@ -0,0 +1,687 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# include <math.h>
|
||||
# include <string.h>
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
ivl_signal_type_t out = IVL_SIT_TRI;
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_signal_type_t stype;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
stype = ivl_signal_type(sig);
|
||||
if (stype == IVL_SIT_REG)
|
||||
continue;
|
||||
if (stype == IVL_SIT_TRI)
|
||||
continue;
|
||||
if (stype == IVL_SIT_NONE)
|
||||
continue;
|
||||
out = stype;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void draw_C4_repeated_constant(char bit_char, unsigned width)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
fprintf(vvp_out, "C4<");
|
||||
for (idx = 0 ; idx < width ; idx += 1)
|
||||
fprintf(vvp_out, "%c", bit_char);
|
||||
|
||||
fprintf(vvp_out, ">");
|
||||
}
|
||||
|
||||
static char* draw_C4_to_string(ivl_net_const_t cptr)
|
||||
{
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
size_t result_len = 5 + ivl_const_width(cptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
char bitchar = bits[ivl_const_width(cptr)-idx-1];
|
||||
*dp++ = bitchar;
|
||||
assert((dp - result) < result_len);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_C8_to_string(ivl_net_const_t cptr,
|
||||
ivl_drive_t dr0, ivl_drive_t dr1)
|
||||
{
|
||||
size_t nresult = 5 + 3*ivl_const_width(cptr);
|
||||
char*result = malloc(nresult);
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
char dr0c = "01234567"[dr0];
|
||||
char dr1c = "01234567"[dr1];
|
||||
char*dp = result;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
switch (bits[ivl_const_width(cptr)-idx-1]) {
|
||||
case '0':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr0c;
|
||||
*dp++ = '0';
|
||||
break;
|
||||
case '1':
|
||||
*dp++ = dr1c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = '1';
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = 'x';
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
*dp++ = '0';
|
||||
*dp++ = '0';
|
||||
*dp++ = 'z';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(dp - result < nresult);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct vvp_nexus_data*new_nexus_data()
|
||||
{
|
||||
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
|
||||
return data;
|
||||
}
|
||||
|
||||
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
|
||||
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
|
||||
if (log != 0) {
|
||||
/* These logic gates are able to generate unusual
|
||||
strength values and so their outputs are considered
|
||||
strength aware. */
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_PMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_NMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_CMOS)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a nexus, look for a signal that has module delay
|
||||
* paths. Return that signal. (There should be no more than 1.) If we
|
||||
* don't find any, then return nil.
|
||||
*/
|
||||
static ivl_signal_t find_modpath(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
if (ivl_signal_npath(sig) == 0)
|
||||
continue;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void str_repeat(char*buf, const char*str, unsigned rpt)
|
||||
{
|
||||
unsigned idx;
|
||||
size_t len = strlen(str);
|
||||
for (idx = 0 ; idx < rpt ; idx += 1) {
|
||||
strcpy(buf, str);
|
||||
buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes a nexus and looks for an input functor. It then
|
||||
* draws to the output a string that represents that functor. What we
|
||||
* are trying to do here is find the input to the net that is attached
|
||||
* to this nexus.
|
||||
*/
|
||||
|
||||
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
|
||||
ivl_net_const_t cptr;
|
||||
ivl_net_logic_t lptr;
|
||||
ivl_signal_t sptr;
|
||||
ivl_lpm_t lpm;
|
||||
|
||||
lptr = ivl_nexus_ptr_log(nptr);
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
|
||||
do {
|
||||
if (! can_elide_bufz(lptr, nptr))
|
||||
break;
|
||||
|
||||
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
|
||||
} while(0);
|
||||
|
||||
/* If this is a pulldown device, then there is a single pin
|
||||
that drives a constant value to the entire width of the
|
||||
vector. The driver normally drives a pull0 value, so a C8<>
|
||||
constant is appropriate, but if the drive is really strong,
|
||||
then we can draw a C4<> constant instead. */
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
|
||||
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "0", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 3*ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '0';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
|
||||
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = 5 + ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "1", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 5 + 3*ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '1';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (nptr_pin == 0)) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lptr);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
sptr = ivl_nexus_ptr_sig(nptr);
|
||||
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
|
||||
char tmp[128];
|
||||
/* Input is a .var. This device may be a non-zero pin
|
||||
because it may be an array of reg vectors. */
|
||||
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
|
||||
|
||||
if (ivl_signal_array_count(sptr) > 1) {
|
||||
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
|
||||
sptr, nptr_pin, sptr, nptr_pin);
|
||||
}
|
||||
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
cptr = ivl_nexus_ptr_con(nptr);
|
||||
if (cptr) {
|
||||
/* Constants should have exactly 1 pin, with a literal value. */
|
||||
assert(nptr_pin == 0);
|
||||
char *result = 0;
|
||||
|
||||
switch (ivl_const_type(cptr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
|
||||
|
||||
result = draw_C4_to_string(cptr);
|
||||
|
||||
} else {
|
||||
result = draw_C8_to_string(cptr,
|
||||
ivl_nexus_ptr_drive0(nptr),
|
||||
ivl_nexus_ptr_drive1(nptr));
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
result = draw_Cr_to_string(ivl_const_real(cptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
|
||||
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
|
||||
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
|
||||
|
||||
/* We have a delayed constant, so we need to build some code. */
|
||||
if (d_rise != 0) {
|
||||
assert(number_is_immediate(d_rise, 64));
|
||||
assert(number_is_immediate(d_fall, 64));
|
||||
assert(number_is_immediate(d_decay, 64));
|
||||
|
||||
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||
cptr, get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise), cptr);
|
||||
|
||||
free(result);
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lpm = ivl_nexus_ptr_lpm(nptr);
|
||||
if (lpm) switch (ivl_lpm_type(lpm)) {
|
||||
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CONCAT:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_RE_AND:
|
||||
case IVL_LPM_RE_OR:
|
||||
case IVL_LPM_RE_XOR:
|
||||
case IVL_LPM_RE_NAND:
|
||||
case IVL_LPM_RE_NOR:
|
||||
case IVL_LPM_RE_XNOR:
|
||||
case IVL_LPM_SFUNC:
|
||||
case IVL_LPM_SHIFTL:
|
||||
case IVL_LPM_SHIFTR:
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_MUX:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_UFUNC:
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
|
||||
case IVL_LPM_REPEAT:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
fprintf(stderr, "internal error: no input to nexus %s\n",
|
||||
ivl_nexus_name(nex));
|
||||
assert(0);
|
||||
return strdup("C<z>");
|
||||
}
|
||||
|
||||
static char* draw_island_port(ivl_island_t island,
|
||||
ivl_nexus_t nex, const char*src)
|
||||
{
|
||||
char result[64];
|
||||
if (ivl_island_flag_test(island,0) == 0) {
|
||||
fprintf(vvp_out, "I%p .island tran;\n", island);
|
||||
ivl_island_flag_set(island,0,1);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "p%p .port I%p, %s;\n", nex, island, src);
|
||||
snprintf(result, sizeof result, "p%p", nex);
|
||||
|
||||
return strdup(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function draws the input to a net into a string. What that
|
||||
* means is that it returns a static string that can be used to
|
||||
* represent a resolved driver to a nexus. If there are multiple
|
||||
* drivers to the nexus, then it writes out the resolver declarations
|
||||
* needed to perform strength resolution.
|
||||
*
|
||||
* The string that this returns is malloced, and that means that the
|
||||
* caller must free the string or store it permanently. This function
|
||||
* does *not* check for a previously calculated string. Use the
|
||||
* draw_net_input for the general case.
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
|
||||
char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data)
|
||||
{
|
||||
ivl_island_t island = 0;
|
||||
ivl_signal_type_t res;
|
||||
char result[512];
|
||||
unsigned idx;
|
||||
int level;
|
||||
unsigned ndrivers = 0;
|
||||
static ivl_nexus_ptr_t *drivers = 0x0;
|
||||
static unsigned adrivers = 0;
|
||||
|
||||
const char*resolv_type;
|
||||
|
||||
char*nex_private = 0;
|
||||
|
||||
/* Accumulate nex_data flags. */
|
||||
int nex_flags = 0;
|
||||
|
||||
res = signal_type_of_nexus(nex);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
resolv_type = "tri0";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
resolv_type = "tri1";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRIAND:
|
||||
resolv_type = "triand";
|
||||
break;
|
||||
case IVL_SIT_TRIOR:
|
||||
resolv_type = "trior";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
|
||||
assert(0);
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_lpm_t lpm_tmp;
|
||||
ivl_switch_t sw = 0;
|
||||
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
/* If this object is part of an island, then we'll be
|
||||
making a port. Save the island cookie. */
|
||||
if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
|
||||
island = ivl_switch_island(sw);
|
||||
}
|
||||
|
||||
/* If we are supposed to skip LPM_PART_BI data pins,
|
||||
check that this driver is that. */
|
||||
if ((omit_flags&OMIT_PART_BI_DATA)
|
||||
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
|
||||
&& (nex == ivl_lpm_data(lpm_tmp,0)))
|
||||
continue;
|
||||
|
||||
if (nptr == omit_ptr)
|
||||
continue;
|
||||
|
||||
/* Skip input only pins. */
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
|
||||
continue;
|
||||
|
||||
/* Mark the strength-aware flag if the driver can
|
||||
generate values other than the standard "6"
|
||||
strength. */
|
||||
if (nexus_drive_is_strength_aware(nptr))
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
|
||||
/* Save this driver. */
|
||||
if (ndrivers >= adrivers) {
|
||||
adrivers += 4;
|
||||
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
|
||||
assert(drivers);
|
||||
}
|
||||
drivers[ndrivers] = nptr;
|
||||
ndrivers += 1;
|
||||
}
|
||||
|
||||
/* If the caller is collecting nexus information, then save
|
||||
the nexus driver count in the nex_data. */
|
||||
if (nex_data) {
|
||||
nex_data->drivers_count = ndrivers;
|
||||
nex_data->flags |= nex_flags;
|
||||
}
|
||||
|
||||
/* If the nexus has no drivers, then send a constant HiZ into
|
||||
the net. */
|
||||
if (ndrivers == 0) {
|
||||
unsigned idx, wid = width_of_nexus(nex);
|
||||
char*tmp = malloc(wid + 5);
|
||||
nex_private = tmp;
|
||||
strcpy(tmp, "C4<");
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = 'z';
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '1';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
*tmp++ = '>';
|
||||
*tmp = 0;
|
||||
if (island) {
|
||||
char*tmp = draw_island_port(island, nex, nex_private);
|
||||
free(nex_private);
|
||||
nex_private = tmp;
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
||||
/* If the nexus has exactly one driver, then simply draw
|
||||
it. Note that this will *not* work if the nexus is not a
|
||||
TRI type nexus. */
|
||||
if (ndrivers == 1 && res == IVL_SIT_TRI) {
|
||||
ivl_signal_t path_sig = find_modpath(nex);
|
||||
if (path_sig) {
|
||||
char*nex_str = draw_net_input_drive(nex, drivers[0]);
|
||||
char modpath_label[64];
|
||||
snprintf(modpath_label, sizeof modpath_label,
|
||||
"V_%p/m", path_sig);
|
||||
nex_private = strdup(modpath_label);
|
||||
draw_modpath(path_sig, nex_str);
|
||||
|
||||
} else {
|
||||
nex_private = draw_net_input_drive(nex, drivers[0]);
|
||||
}
|
||||
if (island) {
|
||||
char*tmp = draw_island_port(island, nex, nex_private);
|
||||
free(nex_private);
|
||||
nex_private = tmp;
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
level = 0;
|
||||
while (ndrivers) {
|
||||
unsigned int inst;
|
||||
for (inst = 0; inst < ndrivers; inst += 4) {
|
||||
if (ndrivers > 4)
|
||||
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
|
||||
nex, level, inst);
|
||||
else
|
||||
fprintf(vvp_out, "RS_%p .resolv %s",
|
||||
nex, resolv_type);
|
||||
|
||||
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
|
||||
if (level) {
|
||||
fprintf(vvp_out, ", RS_%p/%d/%d",
|
||||
nex, level - 1, idx*4);
|
||||
} else {
|
||||
char*drive = draw_net_input_drive(nex, drivers[idx]);
|
||||
fprintf(vvp_out, ", %s", drive);
|
||||
free(drive);
|
||||
}
|
||||
}
|
||||
for ( ; idx < inst+4 ; idx += 1) {
|
||||
fprintf(vvp_out, ", ");
|
||||
draw_C4_repeated_constant('z',width_of_nexus(nex));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
if (ndrivers > 4)
|
||||
ndrivers = (ndrivers+3) / 4;
|
||||
else
|
||||
ndrivers = 0;
|
||||
level += 1;
|
||||
}
|
||||
|
||||
snprintf(result, sizeof result, "RS_%p", nex);
|
||||
|
||||
if (island)
|
||||
nex_private = draw_island_port(island, nex, result);
|
||||
else
|
||||
nex_private = strdup(result);
|
||||
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a cached description of the nexus input, or create one if this
|
||||
* nexus has not been cached yet. This is a wrapper for the common
|
||||
* case call to draw_net_input_x.
|
||||
*/
|
||||
const char*draw_net_input(ivl_nexus_t nex)
|
||||
{
|
||||
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
|
||||
ivl_nexus_get_private(nex);
|
||||
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
if (nex_data && nex_data->net_input)
|
||||
return nex_data->net_input;
|
||||
|
||||
if (nex_data == 0) {
|
||||
nex_data = new_nexus_data();
|
||||
ivl_nexus_set_private(nex, nex_data);
|
||||
}
|
||||
|
||||
assert(nex_data->net_input == 0);
|
||||
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
|
||||
|
||||
return nex_data->net_input;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
# include "vvp_priv.h"
|
||||
# include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
static void draw_tran_island(ivl_island_t island)
|
||||
{
|
||||
fprintf(vvp_out, "I%p .island tran;\n", island);
|
||||
ivl_island_flag_set(island, 0, 1);
|
||||
}
|
||||
|
||||
void draw_switch_in_scope(ivl_switch_t sw)
|
||||
{
|
||||
ivl_island_t island = ivl_switch_island(sw);
|
||||
if (ivl_island_flag_test(island, 0) == 0)
|
||||
draw_tran_island(island);
|
||||
|
||||
ivl_nexus_t nex_a = ivl_switch_a(sw);
|
||||
assert(nex_a);
|
||||
const char*str_a = draw_net_input(nex_a);
|
||||
|
||||
ivl_nexus_t nex_b = ivl_switch_b(sw);
|
||||
assert(nex_b);
|
||||
const char*str_b = draw_net_input(nex_b);
|
||||
|
||||
ivl_nexus_t enable = ivl_switch_enable(sw);
|
||||
const char*str_e = 0;
|
||||
if (enable)
|
||||
str_e = draw_net_input(enable);
|
||||
|
||||
|
||||
switch (ivl_switch_type(sw)) {
|
||||
case IVL_SW_TRAN:
|
||||
fprintf(vvp_out, " .tran");
|
||||
break;
|
||||
case IVL_SW_TRANIF0:
|
||||
fprintf(vvp_out, " .tranif0");
|
||||
break;
|
||||
case IVL_SW_TRANIF1:
|
||||
fprintf(vvp_out, " .tranif1");
|
||||
break;
|
||||
case IVL_SW_TRAN_VP:
|
||||
fprintf(vvp_out, " .tranvp %u %u %u,",
|
||||
ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw));
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n",
|
||||
ivl_switch_file(sw), ivl_switch_lineno(sw));
|
||||
vvp_errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " I%p, %s %s", island, str_a, str_b);
|
||||
if (enable)
|
||||
fprintf(vvp_out, ", %s", str_e);
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
+124
-4
@@ -25,6 +25,86 @@
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check to see if the expression (number) can be correctly represented
|
||||
* with a long variable.
|
||||
*/
|
||||
static int is_constant_number(ivl_expr_t ex)
|
||||
{
|
||||
/* Make sure this matches the return type of constant_number(). */
|
||||
unsigned lim_wid = 8*sizeof(long);
|
||||
const char*bits;
|
||||
char pad_bit = '0';
|
||||
unsigned idx;
|
||||
unsigned nbits = ivl_expr_width(ex);
|
||||
|
||||
if (ivl_expr_type(ex) != IVL_EX_NUMBER
|
||||
&& ivl_expr_type(ex) != IVL_EX_ULONG)
|
||||
return 0;
|
||||
|
||||
bits = ivl_expr_bits(ex);
|
||||
|
||||
/* For unsigned values the effective MSB and on must be '0'. */
|
||||
if (!ivl_expr_signed(ex)) lim_wid -= 1;
|
||||
|
||||
/* For negative values the pad bit is '1'. */
|
||||
if (ivl_expr_signed(ex) && bits[nbits-1]=='1') {
|
||||
pad_bit = '1';
|
||||
}
|
||||
|
||||
/* For the number to fit in the variable all the upper bits must
|
||||
* match the pad bits. */
|
||||
for (idx = lim_wid ; idx < nbits ; idx += 1) {
|
||||
if (bits[idx] != pad_bit) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the expression (number) to a long value.
|
||||
*/
|
||||
static long get_constant_number(ivl_expr_t ex)
|
||||
{
|
||||
long rtn = 0;
|
||||
|
||||
switch (ivl_expr_type(ex)) {
|
||||
case IVL_EX_ULONG:
|
||||
rtn = (signed)ivl_expr_value(ex);
|
||||
break;
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned idx;
|
||||
const char*bits = ivl_expr_bits(ex);
|
||||
unsigned nbits = ivl_expr_width(ex);
|
||||
char pad_bit = bits[nbits-1];
|
||||
/* Define all the bits in the long (negative numbers). */
|
||||
for (idx = 0 ; idx < 8*sizeof(long) ; idx += 1) {
|
||||
char bit;
|
||||
if (idx < nbits) bit = bits[idx];
|
||||
else bit = pad_bit;
|
||||
switch (bit) {
|
||||
case '0':
|
||||
break;
|
||||
case '1':
|
||||
rtn |= 1 << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
static const char* magic_sfuncs[] = {
|
||||
"$time",
|
||||
"$stime",
|
||||
@@ -205,14 +285,54 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
||||
word_ex = 0;
|
||||
}
|
||||
}
|
||||
if (word_ex)
|
||||
break;
|
||||
|
||||
snprintf(buffer, sizeof buffer, "&A<v%p, %u>", sig, use_word);
|
||||
if (word_ex) {
|
||||
struct vector_info av;
|
||||
av = draw_eval_expr(word_ex, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&A<v%p, T<%u,%u,u>>", sig, av.base, av.wid);
|
||||
args[idx].vec = av;
|
||||
args[idx].vec_flag = 1;
|
||||
} else {
|
||||
snprintf(buffer, sizeof buffer,
|
||||
"&A<v%p, %u>", sig, use_word);
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
case IVL_EX_SELECT: {
|
||||
ivl_expr_t vexpr = ivl_expr_oper1(expr);
|
||||
assert(vexpr);
|
||||
|
||||
/* This code is only for signals. */
|
||||
if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break;
|
||||
|
||||
/* The signal is part of an array. */
|
||||
/* Add &APV<> code here when it is finished. */
|
||||
if (ivl_expr_oper1(vexpr)) break;
|
||||
|
||||
ivl_expr_t bexpr = ivl_expr_oper2(expr);
|
||||
assert(bexpr);
|
||||
|
||||
/* This is a constant bit/part select. */
|
||||
if (is_constant_number(bexpr)) {
|
||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
get_constant_number(bexpr),
|
||||
ivl_expr_width(expr));
|
||||
/* This is an indexed bit/part select. */
|
||||
} else {
|
||||
struct vector_info rv;
|
||||
rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
|
||||
snprintf(buffer, sizeof buffer, "&PV<v%p_0, %u %u, %u>",
|
||||
ivl_expr_signal(vexpr),
|
||||
rv.base, rv.wid,
|
||||
ivl_expr_width(expr));
|
||||
}
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Everything else will need to be evaluated and
|
||||
passed as a constant to the vpi task. */
|
||||
default:
|
||||
|
||||
+111
-35
@@ -92,7 +92,8 @@ unsigned long get_number_immediate(ivl_expr_t ex)
|
||||
case '0':
|
||||
break;
|
||||
case '1':
|
||||
imm |= 1 << idx;
|
||||
assert(idx < 8*sizeof(imm));
|
||||
imm |= 1UL << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -909,12 +910,43 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
|
||||
return lv;
|
||||
}
|
||||
|
||||
static struct vector_info draw_logic_immediate(ivl_expr_t exp,
|
||||
ivl_expr_t le,
|
||||
ivl_expr_t re,
|
||||
unsigned wid)
|
||||
{
|
||||
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||
unsigned long imm = get_number_immediate(re);
|
||||
|
||||
assert(lv.base >= 4);
|
||||
|
||||
switch (ivl_expr_opcode(exp)) {
|
||||
|
||||
case '&':
|
||||
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
|
||||
unsigned wid)
|
||||
{
|
||||
ivl_expr_t le = ivl_expr_oper1(exp);
|
||||
ivl_expr_t re = ivl_expr_oper2(exp);
|
||||
|
||||
if (ivl_expr_opcode(exp) == '&') {
|
||||
if (number_is_immediate(re, IMM_WID) && !number_is_unknown(re))
|
||||
return draw_logic_immediate(exp, le, re, wid);
|
||||
if (number_is_immediate(le, IMM_WID) && !number_is_unknown(le))
|
||||
return draw_logic_immediate(exp, re, le, wid);
|
||||
}
|
||||
|
||||
struct vector_info lv;
|
||||
struct vector_info rv;
|
||||
|
||||
@@ -1166,23 +1198,50 @@ static struct vector_info draw_add_immediate(ivl_expr_t le,
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
|
||||
/* Now generate enough %addi instructions to add the entire
|
||||
immediate value to the destination. The adds are done 16
|
||||
bits at a time, but 17 bits are done to push the carry into
|
||||
the higher bits if needed. */
|
||||
{ unsigned base;
|
||||
for (base = 0 ; base < lv.wid ; base += 16) {
|
||||
unsigned long tmp = imm & 0xffffUL;
|
||||
unsigned add_wid = lv.wid - base;
|
||||
/* This shouldn't generally happen, because the elaborator
|
||||
should take care of simple constant propagation like this,
|
||||
but it doesn't have to and it is easy to catch here. */
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
imm >>= 16;
|
||||
switch (lv.base) {
|
||||
case 0: /* Left expression is 0. */
|
||||
lv.base = allocate_vector(wid);
|
||||
if (lv.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of addition.\n",
|
||||
ivl_expr_file(re), ivl_expr_lineno(re), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
|
||||
fprintf(vvp_out, " %%addi %u, %lu, %u;\n",
|
||||
lv.base+base, tmp, add_wid);
|
||||
case 1: /* Left expression is 1...1 (i.e. -1) */
|
||||
imm -= 1;
|
||||
if (imm == 0) {
|
||||
lv.base = 0;
|
||||
} else {
|
||||
lv.base = allocate_vector(wid);
|
||||
if (lv.base == 0) {
|
||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
||||
"Unable to allocate %u thread bits "
|
||||
"for result of addition.\n",
|
||||
ivl_expr_file(re), ivl_expr_lineno(re), wid);
|
||||
vvp_errors += 1;
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
||||
}
|
||||
break;
|
||||
|
||||
if (imm == 0)
|
||||
break;
|
||||
}
|
||||
case 2: /* Left expression is X or Z */
|
||||
case 3:
|
||||
lv.base = 2;
|
||||
break;
|
||||
|
||||
default: /* The regular case. */
|
||||
fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
}
|
||||
|
||||
return lv;
|
||||
@@ -1203,7 +1262,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
||||
assert(lv.wid == wid);
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
assert( (imm & ~0xffff) == 0 );
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
switch (lv.base) {
|
||||
case 0:
|
||||
@@ -1217,21 +1277,21 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
|
||||
lv.base = tmp;
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
return lv;
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
lv.base = 2;
|
||||
return lv;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
@@ -1246,8 +1306,10 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le,
|
||||
assert(lv.wid == wid);
|
||||
|
||||
imm = get_number_immediate(re);
|
||||
if (imm == 0)
|
||||
return lv;
|
||||
|
||||
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
||||
|
||||
return lv;
|
||||
}
|
||||
@@ -1299,13 +1361,13 @@ static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
||||
if ((ivl_expr_opcode(exp) == '-')
|
||||
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
||||
&& (! number_is_unknown(re))
|
||||
&& number_is_immediate(re, 16))
|
||||
&& number_is_immediate(re, IMM_WID))
|
||||
return draw_sub_immediate(le, re, wid);
|
||||
|
||||
if ((ivl_expr_opcode(exp) == '*')
|
||||
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
||||
&& (! number_is_unknown(re))
|
||||
&& number_is_immediate(re, 16))
|
||||
&& number_is_immediate(re, IMM_WID))
|
||||
return draw_mul_immediate(le, re, wid);
|
||||
|
||||
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
||||
@@ -1612,9 +1674,9 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
||||
vvp_errors += 1;
|
||||
}
|
||||
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
|
||||
int val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid);
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID)) {
|
||||
unsigned long val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1836,8 +1898,8 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
||||
idx = 0;
|
||||
while (idx < nwid) {
|
||||
unsigned bits;
|
||||
unsigned trans = 16;
|
||||
if (nwid-idx < 16)
|
||||
unsigned trans = IMM_WID;
|
||||
if (nwid-idx < trans)
|
||||
trans = nwid-idx;
|
||||
|
||||
bits = *p;
|
||||
@@ -1845,6 +1907,14 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
||||
if (trans > 8) {
|
||||
bits |= *p << 8;
|
||||
p -= 1;
|
||||
if (trans > 16) {
|
||||
bits |= *p << 16;
|
||||
p -= 1;
|
||||
if (trans > 24) {
|
||||
bits |= *p << 24;
|
||||
p -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans);
|
||||
|
||||
@@ -1881,8 +1951,14 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
|
||||
res.base+idx, res.base+swid-1);
|
||||
|
||||
} else {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
res.base+swid, res.wid-swid);
|
||||
unsigned base = res.base+swid;
|
||||
unsigned count = res.wid-swid;
|
||||
/* The %movi is faster for larger widths, but for very
|
||||
small counts, the %mov is faster. */
|
||||
if (count > 4)
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n", base, count);
|
||||
else
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2086,7 +2162,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube,
|
||||
|
||||
for (idx = 0 ; idx < res.wid ; idx += 1) {
|
||||
if (idx >= bit_wid) {
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u; Pad from %u to %u\n",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u; Pad from %u to %u\n",
|
||||
res.base+idx, res.wid-idx,
|
||||
ivl_expr_width(sube), wid);
|
||||
break;
|
||||
@@ -2410,7 +2486,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
||||
tmp.base+res.wid, tmp.wid-res.wid);
|
||||
clr_vector(res);
|
||||
res = tmp;
|
||||
@@ -2460,7 +2536,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
||||
assert(res.base);
|
||||
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
||||
tmp.base, res.base, res.wid);
|
||||
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
||||
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
||||
tmp.base+res.wid, tmp.wid-res.wid);
|
||||
clr_vector(res);
|
||||
res = tmp;
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
# include <stdlib.h>
|
||||
# include <assert.h>
|
||||
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static ivl_signal_t find_path_source_port(ivl_delaypath_t path)
|
||||
{
|
||||
int idx;
|
||||
|
||||
+40
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef __vvp_priv_H
|
||||
#define __vvp_priv_H
|
||||
/*
|
||||
* Copyright (c) 2001-2005 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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
|
||||
@@ -39,12 +39,20 @@ struct vector_info {
|
||||
unsigned wid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convenient constants...
|
||||
*/
|
||||
/* Width limit for typical immediate arguments. */
|
||||
# define IMM_WID 32
|
||||
|
||||
/*
|
||||
* Mangle all non-symbol characters in an identifier, quotes in names
|
||||
*/
|
||||
extern const char *vvp_mangle_id(const char *);
|
||||
extern const char *vvp_mangle_name(const char *);
|
||||
|
||||
extern char* draw_Cr_to_string(double value);
|
||||
|
||||
/*
|
||||
* This generates a string from a signal that uniquely identifies
|
||||
* that signal with letters that can be used in a label.
|
||||
@@ -59,6 +67,8 @@ extern const char* vvp_signal_label(ivl_signal_t sig);
|
||||
extern unsigned width_of_nexus(ivl_nexus_t nex);
|
||||
extern ivl_variable_type_t data_type_of_nexus(ivl_nexus_t nex);
|
||||
|
||||
extern int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr);
|
||||
|
||||
/*
|
||||
* This function draws a process (initial or always) into the output
|
||||
* file. It normally returns 0, but returns !0 of there is some sort
|
||||
@@ -104,6 +114,24 @@ extern struct vector_info draw_vpi_func_call(ivl_expr_t exp,
|
||||
unsigned wid);
|
||||
extern int draw_vpi_rfunc_call(ivl_expr_t exp);
|
||||
|
||||
/*
|
||||
* Switches (tran)
|
||||
*/
|
||||
extern void draw_switch_in_scope(ivl_switch_t sw);
|
||||
|
||||
/* Draw_net_input and friends uses this. */
|
||||
struct vvp_nexus_data {
|
||||
/* draw_net_input uses this */
|
||||
const char*net_input;
|
||||
unsigned drivers_count;
|
||||
int flags;
|
||||
/* draw_net_in_scope uses these to identify the controlling word. */
|
||||
ivl_signal_t net;
|
||||
unsigned net_word;
|
||||
};
|
||||
#define VVP_NEXUS_DATA_STR 0x0001
|
||||
|
||||
|
||||
/*
|
||||
* Given a nexus, draw a string that represents the functor output
|
||||
* that feeds the nexus. This function can be used to get the input to
|
||||
@@ -114,6 +142,17 @@ extern int draw_vpi_rfunc_call(ivl_expr_t exp);
|
||||
*/
|
||||
extern const char* draw_net_input(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* See draw_net_input.c for details on draw_net_input_x. (It would be
|
||||
* nice if this can be made private.)
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
struct vvp_nexus_data;
|
||||
extern char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data);
|
||||
|
||||
/*
|
||||
* This function is different from draw_net_input in that it will
|
||||
* return a reference to a net as its first choice. This reference
|
||||
|
||||
+14
-731
@@ -27,24 +27,11 @@
|
||||
# include <inttypes.h>
|
||||
# include <assert.h>
|
||||
|
||||
struct vvp_nexus_data {
|
||||
/* draw_net_input uses this */
|
||||
const char*net_input;
|
||||
unsigned drivers_count;
|
||||
int flags;
|
||||
/* draw_net_in_scope uses these to identify the controlling word. */
|
||||
ivl_signal_t net;
|
||||
unsigned net_word;
|
||||
};
|
||||
#define VVP_NEXUS_DATA_STR 0x0001
|
||||
#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
static struct vvp_nexus_data*new_nexus_data()
|
||||
{
|
||||
struct vvp_nexus_data*data = calloc(1, sizeof(struct vvp_nexus_data));
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Escape non-symbol characters in ids, and quotes in strings.
|
||||
*/
|
||||
@@ -143,27 +130,6 @@ const char *vvp_mangle_name(const char *id)
|
||||
return out;
|
||||
}
|
||||
|
||||
static void draw_C4_repeated_constant(char bit_char, unsigned width)
|
||||
{
|
||||
unsigned idx;
|
||||
|
||||
fprintf(vvp_out, "C4<");
|
||||
for (idx = 0 ; idx < width ; idx += 1)
|
||||
fprintf(vvp_out, "%c", bit_char);
|
||||
|
||||
fprintf(vvp_out, ">");
|
||||
}
|
||||
|
||||
static void str_repeat(char*buf, const char*str, unsigned rpt)
|
||||
{
|
||||
unsigned idx;
|
||||
size_t len = strlen(str);
|
||||
for (idx = 0 ; idx < rpt ; idx += 1) {
|
||||
strcpy(buf, str);
|
||||
buf += len;
|
||||
}
|
||||
}
|
||||
|
||||
/* REMOVE ME: vvp_signal_label should not be used. DEAD CODE
|
||||
* Given a signal, generate a string name that is suitable for use as
|
||||
* a label. The only rule is that the same signal will always have the
|
||||
@@ -194,31 +160,6 @@ ivl_signal_t signal_of_nexus(ivl_nexus_t nex, unsigned*word)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_signal_type_t signal_type_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
ivl_signal_type_t out = IVL_SIT_TRI;
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_signal_type_t stype;
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex, idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
|
||||
stype = ivl_signal_type(sig);
|
||||
if (stype == IVL_SIT_REG)
|
||||
continue;
|
||||
if (stype == IVL_SIT_TRI)
|
||||
continue;
|
||||
if (stype == IVL_SIT_NONE)
|
||||
continue;
|
||||
out = stype;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned width_of_nexus(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
@@ -328,7 +269,7 @@ const char*drive_string(ivl_drive_t drive)
|
||||
* gate will be generated for this node. Otherwise, the code generator
|
||||
* will connect its input to its output and skip the gate.
|
||||
*/
|
||||
static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
ivl_nexus_t in_n;
|
||||
unsigned idx;
|
||||
@@ -376,100 +317,7 @@ static int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a nexus, look for a signal that has module delay
|
||||
* paths. Return that signal. (There should be no more than 1.) If we
|
||||
* don't find any, then return nil.
|
||||
*/
|
||||
static ivl_signal_t find_modpath(ivl_nexus_t nex)
|
||||
{
|
||||
unsigned idx;
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_nexus_ptr_t ptr = ivl_nexus_ptr(nex,idx);
|
||||
ivl_signal_t sig = ivl_nexus_ptr_sig(ptr);
|
||||
if (sig == 0)
|
||||
continue;
|
||||
if (ivl_signal_npath(sig) == 0)
|
||||
continue;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char* draw_C4_to_string(ivl_net_const_t cptr)
|
||||
{
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
size_t result_len = 5 + ivl_const_width(cptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
char bitchar = bits[ivl_const_width(cptr)-idx-1];
|
||||
*dp++ = bitchar;
|
||||
assert((dp - result) < result_len);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_C8_to_string(ivl_net_const_t cptr,
|
||||
ivl_drive_t dr0, ivl_drive_t dr1)
|
||||
{
|
||||
size_t nresult = 5 + 3*ivl_const_width(cptr);
|
||||
char*result = malloc(nresult);
|
||||
const char*bits = ivl_const_bits(cptr);
|
||||
unsigned idx;
|
||||
|
||||
char dr0c = "01234567"[dr0];
|
||||
char dr1c = "01234567"[dr1];
|
||||
char*dp = result;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
|
||||
for (idx = 0 ; idx < ivl_const_width(cptr) ; idx += 1) {
|
||||
switch (bits[ivl_const_width(cptr)-idx-1]) {
|
||||
case '0':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr0c;
|
||||
*dp++ = '0';
|
||||
break;
|
||||
case '1':
|
||||
*dp++ = dr1c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = '1';
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
*dp++ = dr0c;
|
||||
*dp++ = dr1c;
|
||||
*dp++ = 'x';
|
||||
break;
|
||||
case 'z':
|
||||
case 'Z':
|
||||
*dp++ = '0';
|
||||
*dp++ = '0';
|
||||
*dp++ = 'z';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
assert(dp - result < nresult);
|
||||
}
|
||||
|
||||
strcpy(dp, ">");
|
||||
return result;
|
||||
}
|
||||
|
||||
static char* draw_Cr_to_string(double value)
|
||||
char* draw_Cr_to_string(double value)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
@@ -504,488 +352,6 @@ static char* draw_Cr_to_string(double value)
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function takes a nexus and looks for an input functor. It then
|
||||
* draws to the output a string that represents that functor. What we
|
||||
* are trying to do here is find the input to the net that is attached
|
||||
* to this nexus.
|
||||
*/
|
||||
|
||||
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
|
||||
ivl_net_const_t cptr;
|
||||
ivl_net_logic_t lptr;
|
||||
ivl_signal_t sptr;
|
||||
ivl_lpm_t lpm;
|
||||
|
||||
lptr = ivl_nexus_ptr_log(nptr);
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_BUFZ) && (nptr_pin == 0))
|
||||
do {
|
||||
if (! can_elide_bufz(lptr, nptr))
|
||||
break;
|
||||
|
||||
return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
|
||||
} while(0);
|
||||
|
||||
/* If this is a pulldown device, then there is a single pin
|
||||
that drives a constant value to the entire width of the
|
||||
vector. The driver normally drives a pull0 value, so a C8<>
|
||||
constant is appropriate, but if the drive is really strong,
|
||||
then we can draw a C4<> constant instead. */
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
|
||||
if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "0", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 3*ivl_logic_width(lptr) + 5;
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '0';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
|
||||
if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
|
||||
size_t result_len = 5 + ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
strcpy(dp, "C4<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, "1", ivl_logic_width(lptr));
|
||||
dp += ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
} else {
|
||||
char val[4];
|
||||
size_t result_len = 5 + 3*ivl_logic_width(lptr);
|
||||
char*result = malloc(result_len);
|
||||
char*dp = result;
|
||||
|
||||
val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
|
||||
val[1] = val[0];
|
||||
val[2] = '1';
|
||||
val[3] = 0;
|
||||
|
||||
strcpy(dp, "C8<");
|
||||
dp += strlen(dp);
|
||||
str_repeat(dp, val, ivl_logic_width(lptr));
|
||||
dp += 3*ivl_logic_width(lptr);
|
||||
*dp++ = '>';
|
||||
*dp = 0;
|
||||
assert((dp-result) <= result_len);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (lptr && (nptr_pin == 0)) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lptr);
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
sptr = ivl_nexus_ptr_sig(nptr);
|
||||
if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
|
||||
char tmp[128];
|
||||
/* Input is a .var. This device may be a non-zero pin
|
||||
because it may be an array of reg vectors. */
|
||||
snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);
|
||||
|
||||
if (ivl_signal_array_count(sptr) > 1) {
|
||||
fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
|
||||
sptr, nptr_pin, sptr, nptr_pin);
|
||||
}
|
||||
|
||||
return strdup(tmp);
|
||||
}
|
||||
|
||||
cptr = ivl_nexus_ptr_con(nptr);
|
||||
if (cptr) {
|
||||
/* Constants should have exactly 1 pin, with a literal value. */
|
||||
assert(nptr_pin == 0);
|
||||
char *result = 0;
|
||||
|
||||
switch (ivl_const_type(cptr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {
|
||||
|
||||
result = draw_C4_to_string(cptr);
|
||||
|
||||
} else {
|
||||
result = draw_C8_to_string(cptr,
|
||||
ivl_nexus_ptr_drive0(nptr),
|
||||
ivl_nexus_ptr_drive1(nptr));
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_VT_REAL:
|
||||
result = draw_Cr_to_string(ivl_const_real(cptr));
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
ivl_expr_t d_rise = ivl_const_delay(cptr, 0);
|
||||
ivl_expr_t d_fall = ivl_const_delay(cptr, 1);
|
||||
ivl_expr_t d_decay = ivl_const_delay(cptr, 2);
|
||||
|
||||
/* We have a delayed constant, so we need to build some code. */
|
||||
if (d_rise != 0) {
|
||||
assert(number_is_immediate(d_rise, 64));
|
||||
assert(number_is_immediate(d_fall, 64));
|
||||
assert(number_is_immediate(d_decay, 64));
|
||||
|
||||
fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, "
|
||||
"C4<0>, C4<0>, C4<0>;\n", cptr, result);
|
||||
|
||||
fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
|
||||
cptr, get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise),
|
||||
get_number_immediate(d_rise), cptr);
|
||||
|
||||
free(result);
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", cptr);
|
||||
result = strdup(tmp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
lpm = ivl_nexus_ptr_lpm(nptr);
|
||||
if (lpm) switch (ivl_lpm_type(lpm)) {
|
||||
|
||||
case IVL_LPM_FF:
|
||||
case IVL_LPM_ABS:
|
||||
case IVL_LPM_ADD:
|
||||
case IVL_LPM_ARRAY:
|
||||
case IVL_LPM_CONCAT:
|
||||
case IVL_LPM_CMP_EEQ:
|
||||
case IVL_LPM_CMP_EQ:
|
||||
case IVL_LPM_CMP_GE:
|
||||
case IVL_LPM_CMP_GT:
|
||||
case IVL_LPM_CMP_NE:
|
||||
case IVL_LPM_CMP_NEE:
|
||||
case IVL_LPM_RE_AND:
|
||||
case IVL_LPM_RE_OR:
|
||||
case IVL_LPM_RE_XOR:
|
||||
case IVL_LPM_RE_NAND:
|
||||
case IVL_LPM_RE_NOR:
|
||||
case IVL_LPM_RE_XNOR:
|
||||
case IVL_LPM_SFUNC:
|
||||
case IVL_LPM_SHIFTL:
|
||||
case IVL_LPM_SHIFTR:
|
||||
case IVL_LPM_SIGN_EXT:
|
||||
case IVL_LPM_SUB:
|
||||
case IVL_LPM_MULT:
|
||||
case IVL_LPM_MUX:
|
||||
case IVL_LPM_POW:
|
||||
case IVL_LPM_DIVIDE:
|
||||
case IVL_LPM_MOD:
|
||||
case IVL_LPM_UFUNC:
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
|
||||
case IVL_LPM_REPEAT:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
|
||||
return strdup(tmp);
|
||||
} else if (ivl_lpm_data(lpm,0) == nex) {
|
||||
char tmp[128];
|
||||
snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
|
||||
return strdup(tmp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "internal error: no input to nexus %s\n",
|
||||
ivl_nexus_name(nex));
|
||||
assert(0);
|
||||
return strdup("C<z>");
|
||||
}
|
||||
|
||||
static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
if (ivl_nexus_ptr_drive0(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
if (ivl_nexus_ptr_drive1(nptr) != IVL_DR_STRONG)
|
||||
return 1;
|
||||
|
||||
ivl_net_logic_t log = ivl_nexus_ptr_log(nptr);
|
||||
if (log != 0) {
|
||||
/* These logic gates are able to generate unusual
|
||||
strength values and so their outputs are considered
|
||||
strength aware. */
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF0)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_BUFIF1)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_PMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_NMOS)
|
||||
return 1;
|
||||
if (ivl_logic_type(log) == IVL_LO_CMOS)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function draws the input to a net into a string. What that
|
||||
* means is that it returns a static string that can be used to
|
||||
* represent a resolved driver to a nexus. If there are multiple
|
||||
* drivers to the nexus, then it writes out the resolver declarations
|
||||
* needed to perform strength resolution.
|
||||
*
|
||||
* The string that this returns is malloced, and that means that the
|
||||
* caller must free the string or store it permanently. This function
|
||||
* does *not* check for a previously calculated string. Use the
|
||||
* draw_net_input for the general case.
|
||||
*/
|
||||
/* Omit LPMPART_BI device pin-data(0) drivers. */
|
||||
# define OMIT_PART_BI_DATA 0x0001
|
||||
|
||||
static char* draw_net_input_x(ivl_nexus_t nex,
|
||||
ivl_nexus_ptr_t omit_ptr, int omit_flags,
|
||||
struct vvp_nexus_data*nex_data)
|
||||
{
|
||||
ivl_signal_type_t res;
|
||||
char result[512];
|
||||
unsigned idx;
|
||||
int level;
|
||||
unsigned ndrivers = 0;
|
||||
static ivl_nexus_ptr_t *drivers = 0x0;
|
||||
static unsigned adrivers = 0;
|
||||
|
||||
const char*resolv_type;
|
||||
|
||||
char*nex_private = 0;
|
||||
|
||||
/* Accumulate nex_data flags. */
|
||||
int nex_flags = 0;
|
||||
|
||||
res = signal_type_of_nexus(nex);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
resolv_type = "tri0";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
resolv_type = "tri1";
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
break;
|
||||
case IVL_SIT_TRIAND:
|
||||
resolv_type = "triand";
|
||||
break;
|
||||
case IVL_SIT_TRIOR:
|
||||
resolv_type = "trior";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "vvp.tgt: Unsupported signal type: %u\n", res);
|
||||
assert(0);
|
||||
resolv_type = "tri";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_lpm_t lpm_tmp;
|
||||
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
/* If we are supposed to skip LPM_PART_BI data pins,
|
||||
check that this driver is that. */
|
||||
if ((omit_flags&OMIT_PART_BI_DATA)
|
||||
&& (lpm_tmp = ivl_nexus_ptr_lpm(nptr))
|
||||
&& (nex == ivl_lpm_data(lpm_tmp,0)))
|
||||
continue;
|
||||
|
||||
if (nptr == omit_ptr)
|
||||
continue;
|
||||
|
||||
/* Skip input only pins. */
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
|
||||
continue;
|
||||
|
||||
/* Mark the strength-aware flag if the driver can
|
||||
generate values other than the standard "6"
|
||||
strength. */
|
||||
if (nexus_drive_is_strength_aware(nptr))
|
||||
nex_flags |= VVP_NEXUS_DATA_STR;
|
||||
|
||||
/* Save this driver. */
|
||||
if (ndrivers >= adrivers) {
|
||||
adrivers += 4;
|
||||
drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
|
||||
assert(drivers);
|
||||
}
|
||||
drivers[ndrivers] = nptr;
|
||||
ndrivers += 1;
|
||||
}
|
||||
|
||||
/* If the caller is collecting nexus information, then save
|
||||
the nexus driver count in the nex_data. */
|
||||
if (nex_data) {
|
||||
nex_data->drivers_count = ndrivers;
|
||||
nex_data->flags |= nex_flags;
|
||||
}
|
||||
|
||||
/* If the nexus has no drivers, then send a constant HiZ into
|
||||
the net. */
|
||||
if (ndrivers == 0) {
|
||||
unsigned idx, wid = width_of_nexus(nex);
|
||||
char*tmp = malloc(wid + 5);
|
||||
nex_private = tmp;
|
||||
strcpy(tmp, "C4<");
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = 'z';
|
||||
break;
|
||||
case IVL_SIT_TRI0:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '0';
|
||||
break;
|
||||
case IVL_SIT_TRI1:
|
||||
for (idx = 0 ; idx < wid ; idx += 1)
|
||||
*tmp++ = '1';
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
*tmp++ = '>';
|
||||
*tmp = 0;
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
||||
/* If the nexus has exactly one driver, then simply draw
|
||||
it. Note that this will *not* work if the nexus is not a
|
||||
TRI type nexus. */
|
||||
if (ndrivers == 1 && res == IVL_SIT_TRI) {
|
||||
ivl_signal_t path_sig = find_modpath(nex);
|
||||
if (path_sig) {
|
||||
char*nex_str = draw_net_input_drive(nex, drivers[0]);
|
||||
char modpath_label[64];
|
||||
snprintf(modpath_label, sizeof modpath_label,
|
||||
"V_%p/m", path_sig);
|
||||
nex_private = strdup(modpath_label);
|
||||
draw_modpath(path_sig, nex_str);
|
||||
|
||||
} else {
|
||||
nex_private = draw_net_input_drive(nex, drivers[0]);
|
||||
}
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
level = 0;
|
||||
while (ndrivers) {
|
||||
unsigned int inst;
|
||||
for (inst = 0; inst < ndrivers; inst += 4) {
|
||||
if (ndrivers > 4)
|
||||
fprintf(vvp_out, "RS_%p/%d/%d .resolv tri",
|
||||
nex, level, inst);
|
||||
else
|
||||
fprintf(vvp_out, "RS_%p .resolv %s",
|
||||
nex, resolv_type);
|
||||
|
||||
for (idx = inst; idx < ndrivers && idx < inst+4; idx += 1) {
|
||||
if (level) {
|
||||
fprintf(vvp_out, ", RS_%p/%d/%d",
|
||||
nex, level - 1, idx*4);
|
||||
} else {
|
||||
char*drive = draw_net_input_drive(nex, drivers[idx]);
|
||||
fprintf(vvp_out, ", %s", drive);
|
||||
free(drive);
|
||||
}
|
||||
}
|
||||
for ( ; idx < inst+4 ; idx += 1) {
|
||||
fprintf(vvp_out, ", ");
|
||||
draw_C4_repeated_constant('z',width_of_nexus(nex));
|
||||
}
|
||||
|
||||
fprintf(vvp_out, ";\n");
|
||||
}
|
||||
if (ndrivers > 4)
|
||||
ndrivers = (ndrivers+3) / 4;
|
||||
else
|
||||
ndrivers = 0;
|
||||
level += 1;
|
||||
}
|
||||
|
||||
sprintf(result, "RS_%p", nex);
|
||||
nex_private = strdup(result);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a cached description of the nexus input, or create one if this
|
||||
* nexus has not been cached yet. This is a wrapper for the common
|
||||
* case call to draw_net_input_x.
|
||||
*/
|
||||
const char*draw_net_input(ivl_nexus_t nex)
|
||||
{
|
||||
struct vvp_nexus_data*nex_data = (struct vvp_nexus_data*)
|
||||
ivl_nexus_get_private(nex);
|
||||
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
if (nex_data && nex_data->net_input)
|
||||
return nex_data->net_input;
|
||||
|
||||
if (nex_data == 0) {
|
||||
nex_data = new_nexus_data();
|
||||
ivl_nexus_set_private(nex, nex_data);
|
||||
}
|
||||
|
||||
assert(nex_data->net_input == 0);
|
||||
nex_data->net_input = draw_net_input_x(nex, 0, 0, nex_data);
|
||||
|
||||
return nex_data->net_input;
|
||||
}
|
||||
|
||||
const char*draw_input_from_net(ivl_nexus_t nex)
|
||||
{
|
||||
static char result[32];
|
||||
@@ -1767,7 +1133,11 @@ static void draw_lpm_add(ivl_lpm_t net)
|
||||
type = "pow.s";
|
||||
if (width > 8*sizeof(long)) {
|
||||
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Signed power "
|
||||
#ifdef __MINGW32__ /* MinGW does not know about z. */
|
||||
"result must be no more than %u bits.\n",
|
||||
#else
|
||||
"result must be no more than %zu bits.\n",
|
||||
#endif
|
||||
ivl_lpm_file(net), ivl_lpm_lineno(net),
|
||||
8*sizeof(long));
|
||||
exit(1);
|
||||
@@ -2241,94 +1611,6 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
|
||||
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the drawing of a bi-directional part select. The two ports
|
||||
* are simultaneously input and output. A simple minded connect of the
|
||||
* input to the output causes a functor cycle which will lock into an
|
||||
* X value, so something special is needed.
|
||||
*
|
||||
* NOTE: The inputs of the tran device at this point need to be from
|
||||
* all the drivers of the nexus *except* the tran itself. This
|
||||
* function will draw three labels that can be linked:
|
||||
*
|
||||
* The ivl_lpm_q of a part(bi) may be a smaller vector then the
|
||||
* ivl_lpm_data, the tran acts like a forward part select in that
|
||||
* way.
|
||||
*
|
||||
* The device creates these nodes:
|
||||
*
|
||||
* - L_%p/i
|
||||
* This is the Q port of the tran resolved and padded to the maximum
|
||||
* width of the tran. The tran itself is not included in the
|
||||
* resolution of this port.
|
||||
*
|
||||
* - L_%p/V
|
||||
* This is the Q and D parts resolved together, still without the tran
|
||||
* driving anything.
|
||||
*
|
||||
* - L_%p/P
|
||||
* This is the /V node part-selected back to the dimensions of the Q
|
||||
* side.
|
||||
*/
|
||||
static void draw_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
|
||||
|
||||
unsigned idx;
|
||||
ivl_nexus_t nex;
|
||||
ivl_nexus_ptr_t ptr = 0;
|
||||
|
||||
char*p_str;
|
||||
char*v_str;
|
||||
|
||||
/* It seems implausible that the two inputs of a tran will be
|
||||
connected together. So assert that this is so to simplify
|
||||
the code to look for the nexus_ptr_t objects. */
|
||||
assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
|
||||
|
||||
nex = ivl_lpm_q(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
assert(ptr != 0);
|
||||
p_str = draw_net_input_x(nex, ptr, 0, 0);
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
|
||||
|
||||
/* Pad the part-sized input out to a common width...
|
||||
The /i label is the Q side of the tran, resolved except for
|
||||
the tran itself and padded (with z) to the larger width. */
|
||||
fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
|
||||
net, p_str, base, width, signal_width);
|
||||
|
||||
/* Resolve together the two halves of the tran...
|
||||
The /V label is the ports of the tran (now the same width)
|
||||
resolved together. Neither input to this resolver includes
|
||||
the tran itself. */
|
||||
fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
|
||||
net, net, v_str);
|
||||
|
||||
/* The full-width side is created by the tran device, all we
|
||||
have left to to is take a part select of that for the
|
||||
smaller output, and this becomes the part select output of
|
||||
the BI device. */
|
||||
fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
|
||||
net, base, width);
|
||||
|
||||
free(p_str);
|
||||
free(v_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw unary reduction devices.
|
||||
*/
|
||||
@@ -2375,10 +1657,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
||||
draw_lpm_array(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
draw_lpm_part_bi(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
draw_lpm_part(net);
|
||||
return;
|
||||
@@ -2561,6 +1839,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
||||
draw_lpm_in_scope(lpm);
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) {
|
||||
ivl_switch_t sw = ivl_scope_switch(net, idx);
|
||||
draw_switch_in_scope(sw);
|
||||
}
|
||||
|
||||
if (ivl_scope_type(net) == IVL_SCT_TASK)
|
||||
draw_task_definition(net);
|
||||
|
||||
|
||||
+1
-15
@@ -564,25 +564,11 @@ ostream& operator<< (ostream&o, const verinum&v)
|
||||
output. */
|
||||
if (v.has_len()) {
|
||||
o << v.len();
|
||||
if (v.has_sign())
|
||||
o << "'sb";
|
||||
else
|
||||
o << "'b";
|
||||
|
||||
if (v.len() == 0) {
|
||||
o << "0";
|
||||
return o;
|
||||
}
|
||||
|
||||
for (unsigned idx = v.len() ; idx > 0 ; idx -= 1)
|
||||
o << v[idx-1];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/* If the number is fully defined (no x or z) then print it
|
||||
out as a decimal number. */
|
||||
if (v.is_defined() && v.len() < sizeof(long)) {
|
||||
if (v.is_defined() && v.len() < 8*sizeof(long)) {
|
||||
if (v.has_sign())
|
||||
o << "'sd" << v.as_long();
|
||||
else
|
||||
|
||||
+6
-6
@@ -16,12 +16,9 @@
|
||||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.61 2007/02/06 05:07:32 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
||||
VERSION = 0.0
|
||||
VERSION = 0.9.devel
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -48,6 +45,8 @@ LDFLAGS = @LDFLAGS@
|
||||
|
||||
all: dep system.vpi va_math.vpi $(ALL32)
|
||||
|
||||
check: all
|
||||
|
||||
dep:
|
||||
mkdir dep
|
||||
|
||||
@@ -60,7 +59,8 @@ O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
|
||||
sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
|
||||
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
|
||||
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
|
||||
mt19937int.o priv.o sdf_lexor.o sdf_parse.o stringheap.o
|
||||
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
|
||||
vams_simparam.o
|
||||
|
||||
ifeq (@HAVE_LIBZ@,yes)
|
||||
ifeq (@HAVE_LIBBZ2@,yes)
|
||||
@@ -75,7 +75,7 @@ V = va_math.o
|
||||
LIBS = @LIBS@
|
||||
SYSTEM_VPI_LDFLAGS = $(LIBS)
|
||||
VA_MATH_LDFLAGS =
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
SYSTEM_VPI_LDFLAGS += @EXTRALIBS@
|
||||
VA_MATH_LDFLAGS += @EXTRALIBS@
|
||||
endif
|
||||
|
||||
+10
-18
@@ -60,16 +60,6 @@ struct strobe_cb_info {
|
||||
unsigned mcd;
|
||||
};
|
||||
|
||||
int is_constant(vpiHandle obj)
|
||||
{
|
||||
if (vpi_get(vpiType, obj) == vpiConstant)
|
||||
return vpiConstant;
|
||||
if (vpi_get(vpiType, obj) == vpiParameter)
|
||||
return vpiParameter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The number of decimal digits needed to represent a
|
||||
// nr_bits binary number is floor(nr_bits*log_10(2))+1,
|
||||
// where log_10(2) = 0.30102999566398.... and I approximate
|
||||
@@ -665,7 +655,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_constant(argv[idx])
|
||||
if (is_constant_obj(argv[idx])
|
||||
&& (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) {
|
||||
|
||||
value.format = vpiRealVal;
|
||||
@@ -827,6 +817,7 @@ static void do_display(unsigned int mcd, struct strobe_cb_info*info)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiPartSelect:
|
||||
do_display_numeric(mcd, info, item);
|
||||
break;
|
||||
|
||||
@@ -1118,11 +1109,16 @@ static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name)
|
||||
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
|
||||
|
||||
switch (vpi_get(vpiType, monitor_info.items[idx])) {
|
||||
case vpiMemoryWord:
|
||||
/*
|
||||
* We only support constant selections. Make this
|
||||
* better when we add a real compiletf routine.
|
||||
*/
|
||||
assert(vpi_get(vpiConstantSelect, monitor_info.items[idx]));
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiRealVar:
|
||||
case vpiMemoryWord:
|
||||
/* Monitoring reg and net values involves setting
|
||||
a callback for value changes. Pass the storage
|
||||
pointer for the callback itself as user_data so
|
||||
@@ -1836,6 +1832,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info)
|
||||
case vpiReg:
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiPartSelect:
|
||||
width = get_numeric(&result, info, item);
|
||||
rtn = realloc(rtn, (size+width)*sizeof(char));
|
||||
memcpy(rtn+size-1, result, width);
|
||||
@@ -2185,12 +2182,7 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx)
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, sys);
|
||||
vpiHandle scope;
|
||||
if (!argv) {
|
||||
vpiHandle parent = vpi_handle(vpiScope, sys);
|
||||
scope = NULL; /* fallback value if parent is NULL */
|
||||
while (parent) {
|
||||
scope = parent;
|
||||
parent = vpi_handle(vpiScope, scope);
|
||||
}
|
||||
scope = sys_func_module(sys);
|
||||
} else {
|
||||
scope = vpi_scan(argv);
|
||||
vpi_free_object(argv);
|
||||
|
||||
+2
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 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
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_fileio.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include "sys_priv.h"
|
||||
@@ -60,7 +57,7 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! is_constant(item)) {
|
||||
if (! is_constant_obj(item)) {
|
||||
vpi_printf("ERROR: %s mode argument must be a constant\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
@@ -918,4 +915,3 @@ void sys_fileio_register()
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+9
-81
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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
|
||||
@@ -16,44 +16,11 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_finish.c,v 1.11 2007/04/09 22:49:33 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <string.h>
|
||||
|
||||
static PLI_INT32 sys_finish_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
|
||||
/* The argument is optional. */
|
||||
if (argv == 0) return 0;
|
||||
arg = vpi_scan(argv);
|
||||
|
||||
/* A string diagnostic message level makes no sense. */
|
||||
if (vpi_get(vpiType, arg) == vpiConstant &&
|
||||
vpi_get(vpiConstType, arg) == vpiStringConst) {
|
||||
vpi_printf("Error: %s does not take a string argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These functions take at most one argument (diagnostic message). */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
vpi_printf("Error: %s takes at most one argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vpi_scan returning 0 (NULL) has already freed argv. */
|
||||
return 0;
|
||||
}
|
||||
#include "vpi_config.h"
|
||||
#include "vpi_user.h"
|
||||
#include "sys_priv.h"
|
||||
#include <string.h>
|
||||
|
||||
static PLI_INT32 sys_finish_calltf(PLI_BYTE8 *name)
|
||||
{
|
||||
@@ -88,55 +55,16 @@ void sys_finish_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$finish";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = sys_finish_compiletf;
|
||||
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = (PLI_BYTE8*)"$finish";
|
||||
tf_data.user_data = "$finish";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$stop";
|
||||
tf_data.calltf = sys_finish_calltf;
|
||||
tf_data.compiletf = sys_finish_compiletf;
|
||||
tf_data.compiletf = sys_one_opt_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = (PLI_BYTE8*)"$stop";
|
||||
tf_data.user_data = "$stop";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_finish.c,v $
|
||||
* Revision 1.11 2007/04/09 22:49:33 steve
|
||||
* More strict use of PLI_BYTE8 type.
|
||||
*
|
||||
* Revision 1.10 2006/10/30 22:45:37 steve
|
||||
* Updates for Cygwin portability (pr1585922)
|
||||
*
|
||||
* Revision 1.9 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
* Revision 1.8 2003/02/21 03:24:03 steve
|
||||
* Make the $stop system task really vpiStop.
|
||||
*
|
||||
* Revision 1.7 2002/08/12 01:35:04 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.6 2001/07/25 03:10:50 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.5 2001/01/01 19:33:44 steve
|
||||
* Add $stop that does a finish.
|
||||
*
|
||||
* Revision 1.4 2000/02/23 02:56:56 steve
|
||||
* Macintosh compilers do not support ident.
|
||||
*
|
||||
* Revision 1.3 1999/08/28 02:10:44 steve
|
||||
* Call the right vpiFinish code.
|
||||
*
|
||||
* Revision 1.2 1999/08/19 02:51:03 steve
|
||||
* Add vpi_sim_control
|
||||
*
|
||||
* Revision 1.1 1999/08/15 01:23:56 steve
|
||||
* Convert vvm to implement system tasks with vpi.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+19
-27
@@ -16,38 +16,32 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "vpi_config.h"
|
||||
#include <assert.h>
|
||||
#include <vpi_user.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
|
||||
/*
|
||||
* Routine to return the width in bits of a CPU word (long).
|
||||
*/
|
||||
static PLI_INT32 vvp_cpu_wordsize_calltf(PLI_BYTE8* ud)
|
||||
static PLI_INT32 finish_and_return_calltf(PLI_BYTE8* name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
(void) ud; /* Not used! */
|
||||
(void) name; /* Not used! */
|
||||
|
||||
/* Calculate the result */
|
||||
/* Get the return value. */
|
||||
arg = vpi_scan(argv);
|
||||
vpi_free_object(argv);
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 8*sizeof(long);
|
||||
vpi_get_value(arg, &val);
|
||||
|
||||
/* Return the result */
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
/* Set the return value. */
|
||||
vpip_set_return_value(val.value.integer);
|
||||
|
||||
/* Now finish. */
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 size_32(PLI_BYTE8* ud)
|
||||
{
|
||||
(void) ud; /* Not used! */
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
@@ -55,13 +49,11 @@ void sys_special_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
/* Register the single argument functions. */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = vvp_cpu_wordsize_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = size_32;
|
||||
tf_data.tfname = "$vvp_cpu_wordsize";
|
||||
tf_data.user_data = 0;
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.calltf = finish_and_return_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$finish_and_return";
|
||||
tf_data.user_data = "$finish_and_return";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
+28
-55
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2008 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
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_lxt.c,v 1.28 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
# include "lxt_write.h"
|
||||
@@ -324,9 +321,9 @@ inline static int install_dumpvars_callback(void)
|
||||
return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "LXT warning:" " $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("LXT warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -431,22 +428,23 @@ static void *close_dumpfile(void)
|
||||
return (dump_file = NULL);
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.lxt");
|
||||
|
||||
dump_file = lt_init(dump_path);
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "LXT Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
int prec = vpi_get(vpiTimePrecision, 0);
|
||||
|
||||
vpi_mcd_printf(1, "LXT info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
|
||||
assert(prec >= -15);
|
||||
lt_set_timescale(dump_file, prec);
|
||||
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "LXT warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("LXT warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "LXT warning: Overriding dump file %s with"
|
||||
" %s\n", dump_path, path);
|
||||
vpi_printf("LXT warning: Overriding dump file %s with %s\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -542,16 +540,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -644,18 +635,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"LXT info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("LXT info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&lxt_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "LXT warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("LXT warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -674,8 +663,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT warning: $dumpvars: Unsupported parameter"
|
||||
" type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("LXT warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -684,7 +673,6 @@ static int draw_scope(vpiHandle item)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
// char *type; // Not needed, see below.
|
||||
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope)
|
||||
@@ -693,20 +681,6 @@ static int draw_scope(vpiHandle item)
|
||||
depth = 1 + draw_scope(scope);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
#if 0 /* The type information is not needed by the LXT dumper. */
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
case vpiNamedBegin: type = "begin"; break;
|
||||
case vpiTask: type = "task"; break;
|
||||
case vpiFunction: type = "function"; break;
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
push_scope(name);
|
||||
|
||||
return depth;
|
||||
@@ -721,7 +695,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -784,7 +758,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -800,7 +774,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -808,7 +782,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -816,7 +790,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -824,7 +798,7 @@ void sys_lxt_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -837,4 +811,3 @@ void sys_lxt_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+28
-55
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2004 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 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
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_lxt2.c,v 1.10 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
# include "lxt2_write.h"
|
||||
@@ -322,9 +319,9 @@ inline static int install_dumpvars_callback(void)
|
||||
if (dumpvars_status == 1) return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("LXT2 warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -429,22 +426,23 @@ static void *close_dumpfile(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.lx2");
|
||||
|
||||
dump_file = lxt2_wr_init(dump_path);
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "LXT2 Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT2 Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
int prec = vpi_get(vpiTimePrecision, 0);
|
||||
|
||||
vpi_mcd_printf(1, "LXT2 info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("LXT2 info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
|
||||
assert(prec >= -15);
|
||||
lxt2_wr_set_timescale(dump_file, prec);
|
||||
@@ -468,9 +466,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("LXT2 warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,8 +478,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "LXT2 warning: Overriding dump file %s with"
|
||||
" %s.\n", dump_path, path);
|
||||
vpi_printf("LXT2 warning: Overriding dump file %s with %s.\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -548,16 +546,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -657,18 +648,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"LXT2 info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("LXT2 info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&lxt_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&lxt_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "LXT2 warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("LXT2 warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -687,8 +676,8 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT2 warning: $dumpvars: Unsupported parameter"
|
||||
" type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("LXT2 warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -697,7 +686,6 @@ static int draw_scope(vpiHandle item)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
// char *type; // Not needed, see below.
|
||||
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope) return 0;
|
||||
@@ -705,20 +693,6 @@ static int draw_scope(vpiHandle item)
|
||||
depth = 1 + draw_scope(scope);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
#if 0 /* The type information is not needed by the LXT2 dumper. */
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiNamedBegin: type = "begin"; break;
|
||||
case vpiTask: type = "task"; break;
|
||||
case vpiFunction: type = "function"; break;
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "LXT2 Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
push_scope(name);
|
||||
|
||||
return depth;
|
||||
@@ -733,7 +707,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -799,7 +773,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -815,7 +789,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -823,7 +797,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -831,7 +805,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -839,7 +813,7 @@ void sys_lxt2_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -852,4 +826,3 @@ void sys_lxt2_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+237
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
* General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
|
||||
{
|
||||
PLI_UINT64 tmp;
|
||||
|
||||
tmp = time->high;
|
||||
tmp <<= 32;
|
||||
tmp |= (PLI_UINT64) time->low;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument is a constant value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_constant_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
rtn = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument supports has a numeric value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_numeric_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
/* These cannot be a string constant. */
|
||||
if (vpi_get(vpiConstType, obj) != vpiStringConst) rtn = 1;
|
||||
break;
|
||||
|
||||
/* These can have a valid numeric value. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiPartSelect:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
rtn = 1;;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This routine returns 1 if the argument supports a valid string value,
|
||||
* otherwise it returns 0.
|
||||
*/
|
||||
unsigned is_string_obj(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
unsigned rtn = 0;
|
||||
|
||||
switch(vpi_get(vpiType, obj)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter: {
|
||||
/* These must be a string or binary constant. */
|
||||
PLI_INT32 ctype = vpi_get(vpiConstType, obj);
|
||||
if (ctype == vpiStringConst || ctype == vpiBinaryConst) rtn = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* These can have a valid string value. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiPartSelect:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
rtn = 1;;
|
||||
break;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find the enclosing module.
|
||||
*/
|
||||
vpiHandle sys_func_module(vpiHandle obj)
|
||||
{
|
||||
assert(obj);
|
||||
|
||||
while (vpi_get(vpiType, obj) != vpiModule) {
|
||||
obj = vpi_handle(vpiScope, obj);
|
||||
assert(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard compiletf routines.
|
||||
*/
|
||||
|
||||
/* For system functions that do not take an argument. */
|
||||
PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* Make sure there are no arguments. */
|
||||
if (argv != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 0;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s does not take an argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For system functions that take a single numeric argument. */
|
||||
PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* Check that there is an argument and that it is numeric. */
|
||||
if (argv == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s requires a single numeric argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Make sure there are no extra arguments. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For system functions that take a single optional numeric argument. */
|
||||
PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* The argument is optional so just return if none are found. */
|
||||
if (argv == 0) return 0;
|
||||
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Make sure there are no extra arguments. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s %s takes a single numeric argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+16
-9
@@ -1,7 +1,7 @@
|
||||
#ifndef __vpi_sys_priv_H
|
||||
#define __vpi_sys_priv_H
|
||||
/*
|
||||
* Copyright (c) 2002 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,12 +18,9 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_priv.h,v 1.8 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
# include "vpi_user.h"
|
||||
#include "vpi_config.h"
|
||||
#include "vpi_user.h"
|
||||
|
||||
/*
|
||||
* Context structure for PRNG in mt19937int.c
|
||||
@@ -36,9 +33,6 @@ struct context_s {
|
||||
extern void sgenrand(struct context_s *context, unsigned long seed);
|
||||
extern unsigned long genrand(struct context_s *context);
|
||||
|
||||
|
||||
extern int is_constant(vpiHandle obj);
|
||||
|
||||
extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time);
|
||||
|
||||
struct timeformat_info_s {
|
||||
@@ -50,4 +44,17 @@ struct timeformat_info_s {
|
||||
|
||||
extern struct timeformat_info_s timeformat_info;
|
||||
|
||||
extern unsigned is_constant_obj(vpiHandle obj);
|
||||
extern unsigned is_numeric_obj(vpiHandle obj);
|
||||
extern unsigned is_string_obj(vpiHandle obj);
|
||||
|
||||
extern vpiHandle sys_func_module(vpiHandle obj);
|
||||
|
||||
/*
|
||||
* The standard compiletf routines.
|
||||
*/
|
||||
extern PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,6 +38,7 @@ extern void sys_time_register();
|
||||
extern void sys_vcd_register();
|
||||
extern void sys_vcdoff_register();
|
||||
extern void sys_special_register();
|
||||
extern void vams_simparam_register();
|
||||
|
||||
#ifdef HAVE_LIBZ
|
||||
#ifdef HAVE_LIBBZ2
|
||||
@@ -180,5 +181,6 @@ void (*vlog_startup_routines[])() = {
|
||||
sys_lxt_or_vcd_register,
|
||||
sys_sdf_register,
|
||||
sys_special_register,
|
||||
vams_simparam_register,
|
||||
0
|
||||
};
|
||||
|
||||
+37
-102
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2008 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
|
||||
@@ -16,36 +16,14 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_time.c,v 1.12 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
#include "vpi_config.h"
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include <string.h>
|
||||
# include <math.h>
|
||||
# include <assert.h>
|
||||
|
||||
static vpiHandle module_of_function(vpiHandle obj)
|
||||
{
|
||||
while (vpi_get(vpiType, obj) != vpiModule) {
|
||||
obj = vpi_handle(vpiScope, obj);
|
||||
assert(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_time_sizetf(PLI_BYTE8*x)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_stime_sizetf(PLI_BYTE8*x)
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
#include "vpi_user.h"
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <sys_priv.h>
|
||||
|
||||
static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
@@ -60,7 +38,7 @@ static PLI_INT32 sys_time_calltf(PLI_BYTE8*name)
|
||||
call_handle = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(call_handle);
|
||||
|
||||
mod = module_of_function(call_handle);
|
||||
mod = sys_func_module(call_handle);
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
@@ -113,7 +91,7 @@ static PLI_INT32 sys_realtime_calltf(PLI_BYTE8*name)
|
||||
call_handle = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(call_handle);
|
||||
|
||||
mod = module_of_function(call_handle);
|
||||
mod = sys_func_module(call_handle);
|
||||
|
||||
now.type = vpiSimTime;
|
||||
vpi_get_time(0, &now);
|
||||
@@ -134,82 +112,39 @@ void sys_time_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$time";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_time_sizetf;
|
||||
tf_data.user_data = "$time";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$time";
|
||||
tf_data.sysfunctype = vpiTimeFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$time";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$realtime";
|
||||
tf_data.calltf = sys_realtime_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$realtime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$realtime";
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = sys_realtime_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$realtime";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$stime";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_stime_sizetf;
|
||||
tf_data.user_data = "$stime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$stime";
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$stime";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$simtime";
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = 0;
|
||||
tf_data.sizetf = sys_time_sizetf;
|
||||
tf_data.user_data = "$simtime";
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.tfname = "$simtime";
|
||||
tf_data.sysfunctype = vpiTimeFunc;
|
||||
tf_data.calltf = sys_time_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$simtime";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* $Log: sys_time.c,v $
|
||||
* Revision 1.12 2007/03/14 04:05:51 steve
|
||||
* VPI tasks take PLI_BYTE* by the standard.
|
||||
*
|
||||
* Revision 1.11 2006/10/30 22:45:37 steve
|
||||
* Updates for Cygwin portability (pr1585922)
|
||||
*
|
||||
* Revision 1.10 2004/01/21 01:22:53 steve
|
||||
* Give the vip directory its own configure and vpi_config.h
|
||||
*
|
||||
* Revision 1.9 2003/06/18 00:54:28 steve
|
||||
* Account for all 64 bits in results of $time.
|
||||
*
|
||||
* Revision 1.8 2003/02/07 02:44:25 steve
|
||||
* Properly round inter time values from $time.
|
||||
*
|
||||
* Revision 1.7 2003/01/28 04:41:55 steve
|
||||
* Use more precise pow function to scale time by units.
|
||||
*
|
||||
* Revision 1.6 2003/01/27 00:14:37 steve
|
||||
* Support in various contexts the $realtime
|
||||
* system task.
|
||||
*
|
||||
* Revision 1.5 2002/12/21 00:55:58 steve
|
||||
* The $time system task returns the integer time
|
||||
* scaled to the local units. Change the internal
|
||||
* implementation of vpiSystemTime the $time functions
|
||||
* to properly account for this. Also add $simtime
|
||||
* to get the simulation time.
|
||||
*
|
||||
* Revision 1.4 2002/08/12 01:35:05 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.3 2002/01/11 05:20:59 steve
|
||||
* Add the stime system function.
|
||||
*
|
||||
* Revision 1.2 2001/07/25 03:10:50 steve
|
||||
* Create a config.h.in file to hold all the config
|
||||
* junk, and support gcc 3.0. (Stephan Boettcher)
|
||||
*
|
||||
* Revision 1.1 2000/11/01 03:19:36 steve
|
||||
* Add the general $time system function.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
+37
-49
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1999-2008 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
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_vcd.c,v 1.58 2007/03/14 04:05:51 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
|
||||
@@ -269,9 +266,9 @@ inline static int install_dumpvars_callback(void)
|
||||
if (dumpvars_status == 1) return 0;
|
||||
|
||||
if (dumpvars_status == 2) {
|
||||
vpi_mcd_printf(1, "VCD warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
vpi_printf("VCD warning: $dumpvars ignored, previously"
|
||||
" called at simtime %" PLI_UINT64_FMT "\n",
|
||||
dumpvars_time);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -374,15 +371,16 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void open_dumpfile(void)
|
||||
static void open_dumpfile(vpiHandle callh)
|
||||
{
|
||||
if (dump_path == 0) dump_path = strdup("dump.vcd");
|
||||
|
||||
dump_file = fopen(dump_path, "w");
|
||||
|
||||
if (dump_file == 0) {
|
||||
vpi_mcd_printf(1, "VCD Error: Unable to open %s for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("VCD Error: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("Unable to open %s for output.\n", dump_path);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return;
|
||||
} else {
|
||||
@@ -391,8 +389,7 @@ static void open_dumpfile(void)
|
||||
unsigned udx = 0;
|
||||
time_t walltime;
|
||||
|
||||
vpi_mcd_printf(1, "VCD info: dumpfile %s opened for output.\n",
|
||||
dump_path);
|
||||
vpi_printf("VCD info: dumpfile %s opened for output.\n", dump_path);
|
||||
|
||||
time(&walltime);
|
||||
|
||||
@@ -428,9 +425,9 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
|
||||
/* $dumpfile must be called before $dumpvars starts! */
|
||||
if (dumpvars_status != 0) {
|
||||
vpi_mcd_printf(1, "VCD warning: %s called after $dumpvars started"
|
||||
",\n using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
vpi_printf("VCD warning: %s called after $dumpvars started,\n"
|
||||
" using existing file (%s).\n",
|
||||
name, dump_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -440,8 +437,8 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
|
||||
path = strdup(value.value.str);
|
||||
|
||||
if (dump_path) {
|
||||
vpi_mcd_printf(1, "VCD warning: Overriding dump file %s with"
|
||||
" %s\n", dump_path, path);
|
||||
vpi_printf("VCD warning: Overriding dump file %s with %s\n",
|
||||
dump_path, path);
|
||||
free(dump_path);
|
||||
}
|
||||
dump_path = path;
|
||||
@@ -502,16 +499,9 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
|
||||
case vpiMemory:
|
||||
/* don't know how to watch memories. */
|
||||
break;
|
||||
|
||||
case vpiNamedEvent:
|
||||
/* There is nothing in named events to dump. */
|
||||
break;
|
||||
|
||||
case vpiNet: type = "wire"; if(0){
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiTimeVar:
|
||||
case vpiReg: type = "reg"; }
|
||||
|
||||
@@ -635,18 +625,16 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
vpi_get_str(vpiFullName, item);
|
||||
|
||||
#if 0
|
||||
vpi_mcd_printf(1,
|
||||
"VCD info:"
|
||||
" scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
vpi_printf("VCD info: scanning scope %s, %u levels\n",
|
||||
fullname, depth);
|
||||
#endif
|
||||
nskip = 0 != vcd_names_search(&vcd_tab, fullname);
|
||||
|
||||
if (!nskip)
|
||||
vcd_names_add(&vcd_tab, fullname);
|
||||
else
|
||||
vpi_mcd_printf(1, "VCD warning: ignoring signals in"
|
||||
" previously scanned scope %s\n", fullname);
|
||||
vpi_printf("VCD warning: ignoring signals in "
|
||||
"previously scanned scope %s\n", fullname);
|
||||
|
||||
name = vpi_get_str(vpiName, item);
|
||||
|
||||
@@ -665,12 +653,12 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_mcd_printf(1, "VCD warning: $dumpvars: Unsupported parameter "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("VCD warning: $dumpvars: Unsupported parameter "
|
||||
"type (%s)\n", vpi_get_str(vpiType, item));
|
||||
}
|
||||
}
|
||||
|
||||
static int draw_scope(vpiHandle item)
|
||||
static int draw_scope(vpiHandle item, vpiHandle callh)
|
||||
{
|
||||
int depth;
|
||||
const char *name;
|
||||
@@ -679,7 +667,7 @@ static int draw_scope(vpiHandle item)
|
||||
vpiHandle scope = vpi_handle(vpiScope, item);
|
||||
if (!scope) return 0;
|
||||
|
||||
depth = 1 + draw_scope(scope);
|
||||
depth = 1 + draw_scope(scope, callh);
|
||||
name = vpi_get_str(vpiName, scope);
|
||||
|
||||
switch (vpi_get(vpiType, scope)) {
|
||||
@@ -689,8 +677,9 @@ static int draw_scope(vpiHandle item)
|
||||
case vpiNamedFork: type = "fork"; break;
|
||||
case vpiModule: type = "module"; break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "VCD Error: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get(vpiType, item));
|
||||
vpi_printf("VCD Error: %s line %d: $dumpvars: Unsupported scope "
|
||||
"type (%d)\n", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh), vpi_get(vpiType, item));
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -708,7 +697,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
unsigned depth = 0;
|
||||
|
||||
if (dump_file == 0) {
|
||||
open_dumpfile();
|
||||
open_dumpfile(callh);
|
||||
if (dump_file == 0) return 0;
|
||||
}
|
||||
|
||||
@@ -739,23 +728,23 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
* been included. */
|
||||
switch (vpi_get(vpiType, item)) {
|
||||
case vpiIntegerVar:
|
||||
/* What about MemoryWord? */
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
scname = vpi_get_str(vpiFullName, vpi_handle(vpiScope, item));
|
||||
if (vcd_names_search(&vcd_tab, scname)) {
|
||||
vpi_mcd_printf(1, "VCD warning: skipping signal %s, "
|
||||
"it was previously included.\n",
|
||||
vpi_get_str(vpiFullName, item));
|
||||
vpi_printf("VCD warning: skipping signal %s, "
|
||||
"it was previously included.\n",
|
||||
vpi_get_str(vpiFullName, item));
|
||||
continue;
|
||||
} else {
|
||||
add_var = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int dep = draw_scope(item);
|
||||
int dep = draw_scope(item, callh);
|
||||
|
||||
scan_item(depth, item, 0);
|
||||
|
||||
@@ -782,7 +771,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dumpall_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -798,7 +787,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dumpflush_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -806,7 +795,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dumplimit_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -814,7 +803,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dumpoff_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -822,7 +811,7 @@ void sys_vcd_register()
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dumpon_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -835,4 +824,3 @@ void sys_vcd_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+14
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 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
|
||||
@@ -16,9 +16,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: sys_vcdoff.c,v 1.5 2007/03/14 04:05:52 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "sys_priv.h"
|
||||
|
||||
@@ -40,7 +37,7 @@
|
||||
|
||||
static int dump_flag = 0;
|
||||
|
||||
static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
|
||||
static PLI_INT32 sys_dummy_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -48,7 +45,7 @@ static PLI_INT32 sys_dump_calltf(PLI_BYTE8*name)
|
||||
static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
|
||||
{
|
||||
if (dump_flag == 0) {
|
||||
vpi_mcd_printf(1, "VCD info: dumping is suppressed.\n");
|
||||
vpi_printf("VCD info: dumping is suppressed.\n");
|
||||
dump_flag = 1;
|
||||
}
|
||||
|
||||
@@ -63,15 +60,15 @@ void sys_vcdoff_register()
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpall";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpall_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpall";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpfile";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_dumpfile_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpfile";
|
||||
@@ -79,32 +76,32 @@ void sys_vcdoff_register()
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpflush";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpflush_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumplimit";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumplimit_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_one_numeric_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumplimit";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpoff";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpoff_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpoff";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$dumpon";
|
||||
tf_data.calltf = sys_dump_calltf;
|
||||
tf_data.compiletf = sys_dumpon_compiletf;
|
||||
tf_data.calltf = sys_dummy_calltf;
|
||||
tf_data.compiletf = sys_no_arg_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$dumpon";
|
||||
vpi_register_systf(&tf_data);
|
||||
@@ -117,4 +114,3 @@ void sys_vcdoff_register()
|
||||
tf_data.user_data = "$dumpvars";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -14,4 +14,6 @@ $dist_poisson vpiSysFuncInt
|
||||
$dist_chi_square vpiSysFuncInt
|
||||
$dist_t vpiSysFuncInt
|
||||
$dist_erlang vpiSysFuncInt
|
||||
$vvp_cpu_wordsize vpiSysFuncInt
|
||||
|
||||
$simparam vpiSysFuncReal
|
||||
$simparam$str vpiSysFuncSized 1024 unsigned
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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
|
||||
* 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 <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <vpi_user.h>
|
||||
#include "sys_priv.h"
|
||||
|
||||
/* Once we have real string objects replace this with a dynamic string. */
|
||||
#define MAX_STRING_RESULT 1024
|
||||
|
||||
|
||||
/*
|
||||
* Check that the routines are called with the correct arguments.
|
||||
*/
|
||||
static PLI_INT32 simparam_compiletf(PLI_BYTE8* name_ext)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
assert(callh != 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
|
||||
/* We must have at least one argument. */
|
||||
if (argv == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("$simparam%s requires a string argument.\n", name_ext);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The first argument must be a string. */
|
||||
arg = vpi_scan(argv);
|
||||
if (! is_string_obj(arg)) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("The first argument to $simparam%s must be a string.\n",
|
||||
name_ext);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* The second argument (default value) is optional. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg == 0) return 0;
|
||||
|
||||
/* For the string version the default must also be a string. */
|
||||
if (strcmp(name_ext, "$str") == 0) {
|
||||
if (! is_string_obj(arg)) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("When provided, the second argument to $simparam%s"
|
||||
"must be a string.\n", name_ext);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
/* For the rest the default must be numeric. */
|
||||
} else {
|
||||
if (! is_numeric_obj(arg)) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("When provided, the second argument to $simparam%s"
|
||||
"must be numeric.\n", name_ext);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* We can only have two argument. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
vpi_printf("%s $simparam%s takes at most two arguments.\n",
|
||||
msg, name_ext);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 simparam_calltf(PLI_BYTE8* name_ext)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
char *param;
|
||||
unsigned have_def_val = 0;
|
||||
double retval, defval = 0.0;
|
||||
|
||||
/* Get the parameter we are looking for. */
|
||||
arg = vpi_scan(argv);
|
||||
val.format = vpiStringVal;
|
||||
vpi_get_value(arg, &val);
|
||||
param = strdup(val.value.str);
|
||||
|
||||
/* See if there is a default value. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
vpi_free_object(argv);
|
||||
have_def_val = 1;
|
||||
val.format = vpiRealVal;
|
||||
vpi_get_value(arg, &val);
|
||||
defval = val.value.real;
|
||||
}
|
||||
|
||||
/* Now check the various things we can return. */
|
||||
if (strcmp(param, "gdev") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "gmin") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "imax") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "imelt") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "iteration") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "scale") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "shrink") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "simulatorSubversion") == 0) {
|
||||
retval = 0.0;
|
||||
} else if (strcmp(param, "simulatorVersion") == 0) {
|
||||
retval = 0.9;
|
||||
} else if (strcmp(param, "sourceScaleFactor") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "tnom") == 0) {
|
||||
retval = 0.0; /* Nothing for now. */
|
||||
} else if (strcmp(param, "timeUnit") == 0) {
|
||||
retval = pow(10, vpi_get(vpiTimeUnit, sys_func_module(callh)));
|
||||
} else if (strcmp(param, "timePrecision") == 0) {
|
||||
retval = pow(10, vpi_get(vpiTimePrecision, sys_func_module(callh)));
|
||||
} else if (strcmp(param, "CPUWordSize") == 0) {
|
||||
retval = 8.0*sizeof(long);
|
||||
} else {
|
||||
if (! have_def_val) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
|
||||
name_ext, param);
|
||||
}
|
||||
retval = defval;
|
||||
}
|
||||
|
||||
free(param);
|
||||
|
||||
/* Return the value to the system. */
|
||||
val.format = vpiRealVal;
|
||||
val.value.real = retval;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 simparam_str_calltf(PLI_BYTE8* name_ext)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle arg;
|
||||
s_vpi_value val;
|
||||
char *param;
|
||||
char *retval, *defval = NULL;
|
||||
|
||||
/* Get the parameter we are looking for. */
|
||||
arg = vpi_scan(argv);
|
||||
val.format = vpiStringVal;
|
||||
vpi_get_value(arg, &val);
|
||||
param = strdup(val.value.str);
|
||||
|
||||
/* See if there is a default value. */
|
||||
arg = vpi_scan(argv);
|
||||
if (arg != 0) {
|
||||
vpi_free_object(argv);
|
||||
val.format = vpiStringVal;
|
||||
vpi_get_value(arg, &val);
|
||||
defval = strdup(val.value.str);
|
||||
}
|
||||
|
||||
/* Now check the various things we can return. */
|
||||
/* For now we limit the result to 1024 characters. */
|
||||
if (strcmp(param, "analysis_name") == 0) {
|
||||
retval = strdup("N/A"); /* Nothing for now. */
|
||||
} else if (strcmp(param, "analysis_type") == 0) {
|
||||
retval = strdup("N/A"); /* Nothing for now. */
|
||||
} else if (strcmp(param, "cwd") == 0) {
|
||||
char path [MAX_STRING_RESULT];
|
||||
char *ptr = getcwd(path, MAX_STRING_RESULT);
|
||||
if (ptr == NULL) {
|
||||
ptr = strcpy(path, "<error getting the cwd, "
|
||||
"is it too long?>");
|
||||
}
|
||||
retval = strdup(path);
|
||||
} else if (strcmp(param, "module") == 0) {
|
||||
retval = strdup(vpi_get_str(vpiDefName, sys_func_module(callh)));
|
||||
} else if (strcmp(param, "instance") == 0) {
|
||||
retval = strdup(vpi_get_str(vpiFullName, sys_func_module(callh)));
|
||||
} else if (strcmp(param, "path") == 0) {
|
||||
retval = strdup(vpi_get_str(vpiFullName,
|
||||
vpi_handle(vpiScope,callh)));
|
||||
} else {
|
||||
if (defval == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("$simparam%s unknown parameter name \"%s\".\n",
|
||||
name_ext, param);
|
||||
defval = strdup("<error>");
|
||||
}
|
||||
retval = defval;
|
||||
}
|
||||
|
||||
free(param);
|
||||
|
||||
/* Return the value to the system. */
|
||||
val.format = vpiStringVal;
|
||||
val.value.str = retval;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
free(retval);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 simparam_str_sizetf(PLI_BYTE8* name_ext)
|
||||
{
|
||||
(void) name_ext; //* Not used! */
|
||||
|
||||
return MAX_STRING_RESULT; // 128 characters max!
|
||||
}
|
||||
|
||||
/*
|
||||
* Register the function with Verilog.
|
||||
*/
|
||||
void vams_simparam_register(void)
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiRealFunc;
|
||||
tf_data.calltf = simparam_calltf;
|
||||
tf_data.compiletf = simparam_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.tfname = "$simparam";
|
||||
tf_data.user_data = "";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiSizedFunc; /* What should this be? */
|
||||
tf_data.calltf = simparam_str_calltf;
|
||||
tf_data.compiletf = simparam_compiletf;
|
||||
tf_data.sizetf = simparam_str_sizetf; /* Only 128 characters! */
|
||||
tf_data.tfname = "$simparam$str";
|
||||
tf_data.user_data = "$str";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
+50
-173
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 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
|
||||
@@ -16,21 +16,19 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vcd_priv.c,v 1.6 2004/10/04 01:10:58 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vpi_config.h"
|
||||
# include "vcd_priv.h"
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
# include <assert.h>
|
||||
#include "vpi_config.h"
|
||||
#include "vcd_priv.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
# include <ctype.h>
|
||||
# include "stringheap.h"
|
||||
#include <ctype.h>
|
||||
#include "stringheap.h"
|
||||
#include <sys_priv.h>
|
||||
|
||||
int is_escaped_id(const char *name)
|
||||
{
|
||||
@@ -188,92 +186,12 @@ void set_nexus_ident(int nex, const char *id)
|
||||
vcd_ids[ihash(nex)] = bucket;
|
||||
}
|
||||
|
||||
/* This is used by the compiletf routines to check if an argument
|
||||
* is numeric. */
|
||||
static void check_numeric_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
|
||||
{
|
||||
assert(arg);
|
||||
|
||||
switch (vpi_get(vpiType, arg)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
/* String constants are invalid numeric values. */
|
||||
if (vpi_get(vpiConstType, arg) == vpiStringConst) {
|
||||
vpi_mcd_printf(1, msg, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
/* These have valid numeric values. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiRealVar:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Anything else is not a numeric value. */
|
||||
vpi_mcd_printf(1, msg, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This is used by the compiletf routines to check if an argument
|
||||
* is a string value. */
|
||||
static void check_string_arg(vpiHandle arg, char *msg, PLI_BYTE8 *name)
|
||||
{
|
||||
assert(arg);
|
||||
PLI_INT32 ctype = 0;
|
||||
|
||||
switch (vpi_get(vpiType, arg)) {
|
||||
case vpiConstant:
|
||||
case vpiParameter:
|
||||
/* These must be a string or binary constant. */
|
||||
ctype = vpi_get(vpiConstType, arg);
|
||||
if (ctype != vpiStringConst && ctype != vpiBinaryConst) {
|
||||
vpi_mcd_printf(1, msg, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
/* These have valid string values. */
|
||||
case vpiIntegerVar:
|
||||
case vpiMemoryWord:
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
case vpiTimeVar:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Anything else is not a string. */
|
||||
vpi_mcd_printf(1, msg, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the compiletf routines are all the same they are located here,
|
||||
* so we only need a single copy.
|
||||
* so we only need a single copy. Some are generic enough they can use
|
||||
* the ones in sys_priv.c (no arg, one numeric arg.
|
||||
*/
|
||||
|
||||
/* $dumpall does not take an argument. */
|
||||
PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
if (argv != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* $dumpfile takes a single string argument. */
|
||||
PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
@@ -282,84 +200,32 @@ PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name)
|
||||
|
||||
/* Check that there is an argument and that it is a string. */
|
||||
if (argv == 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s requires a single string argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
check_string_arg(vpi_scan(argv), "ERROR: %s's argument must be a"
|
||||
" string.\n", name);
|
||||
if (! is_string_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be a string.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Check that there is only a single argument. */
|
||||
/* Make sure there are no extra arguments. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
char msg [64];
|
||||
snprintf(msg, 64, "ERROR: %s line %d:",
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
|
||||
return 0;
|
||||
}
|
||||
unsigned argc = 1;
|
||||
while (vpi_scan(argv)) argc += 1;
|
||||
|
||||
/* $dumpflush does not take an argument. */
|
||||
PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
if (argv != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* $dumplimit takes a single numeric argument. */
|
||||
PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/* Check that there is an argument and that it is numeric. */
|
||||
if (argv == 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s requires an argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
check_numeric_arg(vpi_scan(argv), "ERROR: %s's argument must be"
|
||||
" numeric.\n", name);
|
||||
|
||||
/* Check that there is only a single argument. */
|
||||
if (vpi_scan(argv) != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s takes a single argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* $dumpoff does not take an argument. */
|
||||
PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
if (argv != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* $dumpon does not take an argument. */
|
||||
PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
if (argv != 0) {
|
||||
vpi_mcd_printf(1, "ERROR: %s does not take an argument.\n", name);
|
||||
vpi_printf("%s %s takes a single string argument.\n", msg, name);
|
||||
vpi_printf("%*s Found %u extra argument%s.\n",
|
||||
strlen(msg), " ", argc, argc == 1 ? "" : "s");
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
@@ -374,16 +240,27 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
|
||||
vpiHandle arg;
|
||||
|
||||
/* No arguments is OK, dump everything. */
|
||||
if (argv == 0)
|
||||
return 0;
|
||||
if (argv == 0) return 0;
|
||||
|
||||
/* The first argument is the numeric level. */
|
||||
check_numeric_arg(vpi_scan(argv), "ERROR: %s's first argument must be"
|
||||
" numeric.\n", name);
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* The rest of the arguments are either a module or a variable. */
|
||||
while ((arg=vpi_scan(argv)) != NULL) {
|
||||
switch(vpi_get(vpiType, arg)) {
|
||||
case vpiMemoryWord:
|
||||
if (vpi_get(vpiConstantSelect, arg) == 0) {
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s cannot dump a non-constant select %s.\n", name,
|
||||
vpi_get_str(vpiType, arg));
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
/* The module types. */
|
||||
case vpiModule:
|
||||
case vpiTask:
|
||||
@@ -393,18 +270,18 @@ PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name)
|
||||
/* The variable types. */
|
||||
case vpiNet:
|
||||
case vpiReg:
|
||||
case vpiMemoryWord:
|
||||
case vpiIntegerVar:
|
||||
case vpiTimeVar:
|
||||
case vpiRealVar:
|
||||
break;
|
||||
default:
|
||||
vpi_mcd_printf(1, "ERROR: %s cannot dump a %s.\n",
|
||||
name, vpi_get_str(vpiType, arg));
|
||||
vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s cannot dump a %s.\n", name,
|
||||
vpi_get_str(vpiType, arg));
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-9
@@ -1,7 +1,7 @@
|
||||
#ifndef __vcd_priv_H
|
||||
#define __vcd_priv_H
|
||||
/*
|
||||
* Copyright (c) 2003 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
@@ -18,9 +18,6 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vcd_priv.h,v 1.2 2003/02/13 18:13:28 steve Exp $"
|
||||
#endif
|
||||
|
||||
#include "vpi_user.h"
|
||||
|
||||
@@ -47,12 +44,7 @@ extern const char*find_nexus_ident(int nex);
|
||||
extern void set_nexus_ident(int nex, const char *id);
|
||||
|
||||
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
|
||||
extern PLI_INT32 sys_dumpall_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumpfile_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumpflush_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumplimit_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumpoff_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumpon_compiletf(PLI_BYTE8 *name);
|
||||
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
|
||||
|
||||
#endif
|
||||
|
||||
+5
-2
@@ -279,6 +279,7 @@ typedef struct t_vpi_delay {
|
||||
#define vpiNamedFork 35
|
||||
#define vpiNet 36
|
||||
#define vpiParameter 41
|
||||
#define vpiPartSelect 42
|
||||
#define vpiPathTerm 43
|
||||
#define vpiRealVar 47
|
||||
#define vpiReg 48
|
||||
@@ -297,6 +298,7 @@ typedef struct t_vpi_delay {
|
||||
#define vpiModPathIn 95
|
||||
#define vpiModPathOut 96
|
||||
#define vpiVariables 100
|
||||
#define vpiExpr 102
|
||||
|
||||
#define vpiCallback 1000
|
||||
|
||||
@@ -346,8 +348,8 @@ typedef struct t_vpi_delay {
|
||||
# define vpiSysFuncReal vpiRealFunc
|
||||
# define vpiSysFuncTime vpiTimeFunc
|
||||
# define vpiSysFuncSized vpiSizedFunc
|
||||
#define vpiSigned 65
|
||||
#define vpiExpr 102
|
||||
#define vpiConstantSelect 53
|
||||
#define vpiSigned 65
|
||||
/* IVL private properties */
|
||||
#define _vpiNexusId 0x1000000
|
||||
|
||||
@@ -563,6 +565,7 @@ extern DLLEXPORT void (*vlog_startup_routines[])();
|
||||
/* Format a scalar a la %v. The str points to a 4byte character
|
||||
buffer. The value must be a vpiStrengthVal. */
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||
extern void vpip_set_return_value(int value);
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
|
||||
+14
-4
@@ -43,6 +43,8 @@ INSTALL_DATA = @INSTALL_DATA@
|
||||
RANLIB = @RANLIB@
|
||||
LEX = @LEX@
|
||||
YACC = @YACC@
|
||||
MAN = @MAN@
|
||||
PS2PDF = @PS2PDF@
|
||||
|
||||
CPPFLAGS = @ident_support@ -I. -I.. -I $(srcdir) -I$(srcdir)/.. @CPPFLAGS@ @DEFS@
|
||||
CXXFLAGS = -Wall @CXXFLAGS@
|
||||
@@ -77,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
||||
concat.o \
|
||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||
ufunc.o codes.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \
|
||||
event.o logic.o delay.o words.o $V
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
@@ -133,12 +135,20 @@ lexor.cc: $(srcdir)/lexor.lex
|
||||
$(LEX) -s -olexor.cc $(srcdir)/lexor.lex
|
||||
|
||||
vvp.pdf: $(srcdir)/vvp.man
|
||||
man -t $(srcdir)/vvp.man | ps2pdf - vvp.pdf
|
||||
$(MAN) -t $(srcdir)/vvp.man | $(PS2PDF) - vvp.pdf
|
||||
|
||||
ifeq (@MING32@,yes)
|
||||
ifeq (@MINGW32@,yes)
|
||||
ifeq ($(MAN),none)
|
||||
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||
else
|
||||
ifeq ($(PS2PDF),none)
|
||||
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||
else
|
||||
INSTALL_DOC = $(prefix)/vvp.pdf $(mandir)/man1/vvp.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
all: vvp.pdf
|
||||
endif
|
||||
endif
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
else
|
||||
INSTALL_DOC = $(mandir)/man1/vvp.1
|
||||
INSTALL_DOCDIR = $(mandir)/man1
|
||||
|
||||
+41
-76
@@ -386,82 +386,6 @@ at <src>.
|
||||
|
||||
<label> .array "name", <src> ;
|
||||
|
||||
MEMORY STATEMENTS:
|
||||
|
||||
Memories are arrays of words, each word a vvp_vector4_t vector of the
|
||||
same width. The memory is canonically addressed as a 1-dimensional
|
||||
array of words, although indices are stored with the memory for
|
||||
calculating a canonical address from a multi-dimensional address.
|
||||
|
||||
Three types of memory statement perform (1) creation of a memory, (2)
|
||||
connecting a read port to an existing memory, and (3) initializing the
|
||||
memory's contents.
|
||||
|
||||
<label> .mem "name", <msb>,<lsb>, <last>,<first> ... ;
|
||||
|
||||
The pair of numbers <msb>,<lsb> defines the word width. The pair
|
||||
<last>,<first> defines the address range. Multiple address ranges are
|
||||
allowed for multidimensional indexing. This statement creates the
|
||||
memory array and makes it available to procedural code.
|
||||
|
||||
Procedural access to the memory references the memory as single array
|
||||
of words, with the base address==0, and the last address the size (in
|
||||
words) of the memory -1. It is up to the compiler to convert Verilog
|
||||
index sets to a canonical address. The multi-dimensional index set is
|
||||
available for VPI use.
|
||||
|
||||
Structural read access is implemented in terms of address and data
|
||||
ports. The addresses applied to the address port are expected to be
|
||||
in canonical form.
|
||||
|
||||
A read port is a functor that takes a single input, the read address,
|
||||
and outputs the word value at the given (canonical) address.
|
||||
|
||||
<label> .mem/port <memid>, <address> ;
|
||||
|
||||
<label> identifies the vector of output functors, to allow connections
|
||||
to the data output. <memid> is the label of the memory.
|
||||
|
||||
Any address input change, or any change in the addressed memory
|
||||
contents, is immediately propagated to the port output.
|
||||
|
||||
A write port is a superset of a read port. It is a 4-input functor
|
||||
that accepts the word address, an event input, a write enable input,
|
||||
and the data input.
|
||||
|
||||
<label> .mem/port <memid>, <address>, <event>, <we>, <data> ;
|
||||
|
||||
<event> is an event functor that triggers a write, if the <we> input
|
||||
is true. <data> is the input that connect to the data input
|
||||
port. For asynchronous transparent write operation, connect
|
||||
<event> to C4<z>, the RAM will transparently follow any changes on
|
||||
address and data lines, while <we> is true.
|
||||
|
||||
There is no Verilog construct that calls for a structural write port
|
||||
to a memory, but synthesis may ask for lpm_ram_d[pq] objects.
|
||||
|
||||
To initialize a memory, use:
|
||||
|
||||
.mem/init <memid> <start>, val , val ... ;
|
||||
|
||||
<memid> is the label of the memory, and the <start> is the start
|
||||
address (canonical) of the first word to be initialized. The start
|
||||
address allows multiple statements be used to initialize words of a
|
||||
memory.
|
||||
|
||||
The values are one per word.
|
||||
|
||||
Procedural access to the memory employs an index register to address a
|
||||
bit location in the memory, via the commands:
|
||||
|
||||
%load/m <bit>, <memid> ;
|
||||
%set/m <memid>, <bit> ;
|
||||
%assign/m <memid>, <delay>, <bit> ;
|
||||
|
||||
The memory bit is addressed by index register 3. The value of
|
||||
register 3 is the index in the memory's bit space, where each data
|
||||
word occupies a multiple of four bits.
|
||||
|
||||
|
||||
EVENT STATEMENTS
|
||||
|
||||
@@ -830,6 +754,47 @@ by the fork atomically joins that scope. Once the transient thread
|
||||
joins the scope, it stays there until it ends. Threads never change
|
||||
scopes, not even transient threads.
|
||||
|
||||
VPI TASK/FUNCTION CALLS
|
||||
|
||||
Threads call vpi tasks with the %vpi_call or %vpi_func
|
||||
instructions. The formats are:
|
||||
|
||||
%vpi_call <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_func <file-index> <lineno> <name>, <args>... ;
|
||||
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
|
||||
|
||||
The <file-index> is an index into the string table. The indexed string
|
||||
is the source code file name where this call appears. The <lineno> is
|
||||
the line number from the source code where this task/function appears.
|
||||
|
||||
The <name> is a string that is the name of the system
|
||||
task/function. For example, "$display", $strobe", etc. This name is
|
||||
looked up and compared with the registered system tasks/functions.
|
||||
|
||||
The <args>... is a comma (",") separated list of arguments. These are
|
||||
made available to the VPI code as vpi handles.
|
||||
|
||||
* The &A<> argument
|
||||
|
||||
The &A<> argument is a reference to the word of a variable array. The
|
||||
syntax is:
|
||||
|
||||
&A '<' <symbol> , <number> '>'
|
||||
|
||||
The <symbol> is the label for a variable array, and the <number> is
|
||||
the cannonical word index as an unsigned integer.
|
||||
|
||||
* The T<> argument
|
||||
|
||||
This is the catch-all for arguments that are not otherwise
|
||||
handled. This references the bits directly in the thread. The format
|
||||
is:
|
||||
|
||||
T '<' <base>, <wid>, <su> '>'
|
||||
|
||||
The <base> and <wid> are the base of a vector value in the thread and
|
||||
the width of the vector. The <su> is 's' or 'u' for signed or unsigned.
|
||||
|
||||
TRUTH TABLES
|
||||
|
||||
The logic that a functor represents is expressed as a truth table. The
|
||||
|
||||
+191
-24
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2008 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
|
||||
@@ -30,7 +30,7 @@
|
||||
# include "compile.h"
|
||||
# include <assert.h>
|
||||
|
||||
static symbol_table_t array_table =0;
|
||||
static symbol_map_s<struct __vpiArray>* array_table =0;
|
||||
|
||||
class vvp_fun_arrayport;
|
||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||
@@ -40,8 +40,8 @@ vvp_array_t array_find(const char*label)
|
||||
if (array_table == 0)
|
||||
return 0;
|
||||
|
||||
symbol_value_t v = sym_get_value(array_table, label);
|
||||
return (vvp_array_t)v.ptr;
|
||||
vvp_array_t v = array_table->sym_get_value(label);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -55,6 +55,8 @@ struct __vpiArray {
|
||||
unsigned array_count;
|
||||
struct __vpiDecConst first_addr;
|
||||
struct __vpiDecConst last_addr;
|
||||
struct __vpiDecConst msb;
|
||||
struct __vpiDecConst lsb;
|
||||
// If this is a net array, nets lists the handles.
|
||||
vpiHandle*nets;
|
||||
// If this is a var array, then these are used instead of nets.
|
||||
@@ -81,7 +83,25 @@ struct __vpiArrayIndex {
|
||||
struct __vpiArrayVthrA {
|
||||
struct __vpiHandle base;
|
||||
struct __vpiArray*array;
|
||||
// If wid==0, then address is the address into the array.
|
||||
unsigned address;
|
||||
// If wid >0, then the address is the base and wid the vector
|
||||
// width of the index to pull from the thread.
|
||||
unsigned wid;
|
||||
|
||||
unsigned get_address() const
|
||||
{
|
||||
if (wid == 0)
|
||||
return address;
|
||||
vvp_vector4_t tmp (wid);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, address+idx);
|
||||
tmp.set_bit(idx, bit);
|
||||
}
|
||||
unsigned long val;
|
||||
vector4_to_value(tmp, val);
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -121,12 +141,16 @@ static vpiHandle array_index_scan(vpiHandle ref, int);
|
||||
static int array_index_free_object(vpiHandle ref);
|
||||
|
||||
static int vpi_array_var_word_get(int code, vpiHandle);
|
||||
static char*vpi_array_var_word_get_str(int code, vpiHandle);
|
||||
static void vpi_array_var_word_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle, p_vpi_value, int);
|
||||
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref);
|
||||
|
||||
static int vpi_array_vthr_A_get(int code, vpiHandle);
|
||||
static char*vpi_array_vthr_A_get_str(int code, vpiHandle);
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle, p_vpi_value);
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle, p_vpi_value, int);
|
||||
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref);
|
||||
|
||||
static const struct __vpirt vpip_arraymem_rt = {
|
||||
vpiMemory,
|
||||
@@ -169,10 +193,10 @@ static const struct __vpirt vpip_array_index_rt = {
|
||||
static const struct __vpirt vpip_array_var_word_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_var_word_get,
|
||||
0,
|
||||
&vpi_array_var_word_get_str,
|
||||
&vpi_array_var_word_get_value,
|
||||
&vpi_array_var_word_put_value,
|
||||
0,
|
||||
&vpi_array_var_word_get_handle,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
@@ -181,10 +205,10 @@ static const struct __vpirt vpip_array_var_word_rt = {
|
||||
static const struct __vpirt vpip_array_vthr_A_rt = {
|
||||
vpiMemoryWord,
|
||||
&vpi_array_vthr_A_get,
|
||||
0,
|
||||
&vpi_array_vthr_A_get_str,
|
||||
&vpi_array_vthr_A_get_value,
|
||||
&vpi_array_vthr_A_put_value,
|
||||
0,
|
||||
&vpi_array_vthr_A_get_handle,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
@@ -340,11 +364,34 @@ static int vpi_array_var_word_get(int code, vpiHandle ref)
|
||||
case vpiSize:
|
||||
return (int) parent->vals_width;
|
||||
|
||||
case vpiLeftRange:
|
||||
return parent->msb.value;
|
||||
|
||||
case vpiRightRange:
|
||||
return parent->lsb.value;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char*vpi_array_var_word_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
|
||||
char sidx [64];
|
||||
snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value);
|
||||
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
|
||||
}
|
||||
|
||||
static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
@@ -352,9 +399,14 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value)
|
||||
|
||||
assert(obj);
|
||||
unsigned index = decode_array_word_pointer(obj, parent);
|
||||
unsigned width = parent->vals_width;
|
||||
|
||||
vpip_vec4_get_value(parent->vals[index], parent->vals_width,
|
||||
false, value);
|
||||
/* If we don't have a value yet just return X. */
|
||||
if (parent->vals[index].size() == 0) {
|
||||
vpip_vec4_get_value(vvp_vector4_t(width), width, false, value);
|
||||
} else {
|
||||
vpip_vec4_get_value(parent->vals[index], width, false, value);
|
||||
}
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int flags)
|
||||
@@ -370,6 +422,35 @@ static vpiHandle vpi_array_var_word_put_value(vpiHandle ref, p_vpi_value vp, int
|
||||
return ref;
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayWord*obj = array_var_word_from_handle(ref);
|
||||
struct __vpiArray*parent;
|
||||
|
||||
assert(obj);
|
||||
decode_array_word_pointer(obj, parent);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiIndex:
|
||||
break; // Not implemented!
|
||||
|
||||
case vpiLeftRange:
|
||||
return &parent->msb.base;
|
||||
|
||||
case vpiRightRange:
|
||||
return &parent->lsb.base;
|
||||
|
||||
case vpiParent:
|
||||
return &parent->base;
|
||||
|
||||
case vpiScope:
|
||||
return &parent->scope->base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \
|
||||
(struct __vpiArrayIterator*)ref)
|
||||
|
||||
@@ -453,13 +534,39 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref)
|
||||
return 0; // Not implemented for now!
|
||||
|
||||
case vpiSize:
|
||||
assert(parent->vals);
|
||||
return parent->vals_width;
|
||||
|
||||
case vpiLeftRange:
|
||||
return parent->msb.value;
|
||||
|
||||
case vpiRightRange:
|
||||
return parent->lsb.value;
|
||||
|
||||
// For now &A<> is only a constant select. This will need
|
||||
// to be changed when it supports variable selection.
|
||||
case vpiConstantSelect:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
if (code == vpiFile) { // Not implemented for now!
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
|
||||
char sidx [64];
|
||||
snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value);
|
||||
return generic_get_str(code, &parent->scope->base, parent->name, sidx);
|
||||
}
|
||||
|
||||
static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
@@ -467,11 +574,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value value)
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
assert(parent);
|
||||
assert(parent->vals);
|
||||
assert(obj->address < parent->array_count);
|
||||
|
||||
vpip_vec4_get_value(parent->vals[obj->address],
|
||||
parent->vals_width, false, value);
|
||||
unsigned index = obj->get_address();
|
||||
vvp_vector4_t tmp = array_get_word(parent, index);
|
||||
vpip_vec4_get_value(tmp, parent->vals_width, false, value);
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
@@ -480,10 +586,10 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
unsigned index = obj->address;
|
||||
unsigned index = obj->get_address();
|
||||
|
||||
assert(parent);
|
||||
assert(obj->address < parent->array_count);
|
||||
assert(index < parent->array_count);
|
||||
|
||||
vvp_vector4_t val = vec4_from_vpi_value(vp, parent->vals_width);
|
||||
array_set_word(parent, index, 0, val);
|
||||
@@ -491,6 +597,32 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int)
|
||||
return ref;
|
||||
}
|
||||
|
||||
static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref);
|
||||
assert(obj);
|
||||
struct __vpiArray*parent = obj->array;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiIndex:
|
||||
break; // Not implemented!
|
||||
|
||||
case vpiLeftRange:
|
||||
return &parent->msb.base;
|
||||
|
||||
case vpiRightRange:
|
||||
return &parent->lsb.base;
|
||||
|
||||
case vpiParent:
|
||||
return &parent->base;
|
||||
|
||||
case vpiScope:
|
||||
return &parent->scope->base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void array_set_word(vvp_array_t arr,
|
||||
unsigned address,
|
||||
@@ -596,6 +728,8 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
obj->nets = 0;
|
||||
obj->vals = 0;
|
||||
obj->vals_width = 0;
|
||||
vpip_make_dec_const(&obj->msb, 0);
|
||||
vpip_make_dec_const(&obj->lsb, 0);
|
||||
obj->vals_words = 0;
|
||||
|
||||
// Initialize (clear) the read-ports list.
|
||||
@@ -604,12 +738,10 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
||||
|
||||
/* Add this symbol to the array_symbols table for later lookup. */
|
||||
if (!array_table)
|
||||
array_table = new_symbol_table();
|
||||
array_table = new symbol_map_s<struct __vpiArray>;
|
||||
|
||||
assert(!array_find(label));
|
||||
symbol_value_t v;
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
array_table->sym_set_value(label, obj);
|
||||
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
@@ -656,6 +788,8 @@ void compile_var_array(char*label, char*name, int last, int first,
|
||||
/* Make the words. */
|
||||
arr->vals = new vvp_vector4_t[arr->array_count];
|
||||
arr->vals_width = labs(msb-lsb) + 1;
|
||||
vpip_make_dec_const(&arr->msb, msb);
|
||||
vpip_make_dec_const(&arr->lsb, lsb);
|
||||
|
||||
free(label);
|
||||
free(name);
|
||||
@@ -909,9 +1043,7 @@ void compile_array_alias(char*label, char*name, char*src)
|
||||
|
||||
assert(array_table);
|
||||
assert(!array_find(label));
|
||||
symbol_value_t v;
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
array_table->sym_set_value(label, obj);
|
||||
|
||||
compile_vpi_symbol(label, &obj->base);
|
||||
vpip_attach_to_current_scope(&obj->base);
|
||||
@@ -930,9 +1062,44 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
||||
|
||||
obj->array = array_find(label);
|
||||
assert(obj->array);
|
||||
free(label);
|
||||
|
||||
obj->address = addr;
|
||||
obj->wid = 0;
|
||||
assert(addr < obj->array->array_count);
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_vthr_A(char*label, char*symbol)
|
||||
{
|
||||
struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*)
|
||||
malloc(sizeof (struct __vpiArrayVthrA));
|
||||
|
||||
obj->base.vpi_type = &vpip_array_vthr_A_rt;
|
||||
|
||||
obj->array = array_find(label);
|
||||
assert(obj->array);
|
||||
free(label);
|
||||
|
||||
unsigned base;
|
||||
unsigned wid;
|
||||
char sflag;
|
||||
int rc = sscanf(symbol, "T<%u,%u,%c>", &base, &wid, &sflag);
|
||||
assert(rc == 3);
|
||||
free(symbol);
|
||||
|
||||
obj->address = base;
|
||||
obj->wid = wid;
|
||||
assert(sflag == 'u');
|
||||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
void compile_array_cleanup(void)
|
||||
{
|
||||
if (array_table) {
|
||||
delete array_table;
|
||||
array_table = 0;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -37,6 +37,7 @@ extern bool of_ADD(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADD_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ADDI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_AND(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ANDI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ANDR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code);
|
||||
@@ -167,7 +168,7 @@ struct vvp_code_s {
|
||||
};
|
||||
|
||||
union {
|
||||
unsigned bit_idx[2];
|
||||
uint32_t bit_idx[2];
|
||||
vvp_net_t *net2;
|
||||
vvp_code_t cptr2;
|
||||
struct ufunc_core*ufunc_core_ptr;
|
||||
|
||||
+7
-4
@@ -85,6 +85,7 @@ const static struct opcode_table_s opcode_table[] = {
|
||||
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%andi", of_ANDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
|
||||
{ "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
|
||||
@@ -644,6 +645,8 @@ void compile_cleanup(void)
|
||||
delete_symbol_table(sym_functors);
|
||||
sym_functors = 0;
|
||||
|
||||
compile_island_cleanup();
|
||||
|
||||
if (verbose_flag) {
|
||||
fprintf(stderr, " ... Compiletf functions\n");
|
||||
fflush(stderr);
|
||||
@@ -1396,16 +1399,16 @@ void compile_resolver(char*label, char*type, unsigned argc, struct symb_s*argv)
|
||||
vvp_net_fun_t* obj = 0;
|
||||
|
||||
if (strcmp(type,"tri") == 0) {
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0));
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0));
|
||||
|
||||
} else if (strncmp(type,"tri$",4) == 0) {
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0), strdup(type+4));
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_Z, 0,0), strdup(type+4));
|
||||
|
||||
} else if (strcmp(type,"tri0") == 0) {
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5));
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_0, 5,5));
|
||||
|
||||
} else if (strcmp(type,"tri1") == 0) {
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5));
|
||||
obj = new resolv_functor(vvp_scalar_t(BIT4_1, 5,5));
|
||||
|
||||
} else if (strcmp(type,"triand") == 0) {
|
||||
obj = new resolv_triand;
|
||||
|
||||
@@ -335,6 +335,8 @@ extern void compile_array_port(char*label, char*name, char*addr);
|
||||
/* Index is a constant address */
|
||||
extern void compile_array_port(char*label, char*name, long addr);
|
||||
|
||||
extern void compile_array_cleanup(void);
|
||||
|
||||
/*
|
||||
* Compile the .ufunc statement.
|
||||
*/
|
||||
@@ -451,4 +453,16 @@ extern void compile_aliasw(char*label, char*array_symbol,
|
||||
unsigned long array_addr, int msb, int lsb,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
|
||||
extern void compile_island(char*label, char*type);
|
||||
extern void compile_island_port(char*label, char*island, char*src);
|
||||
extern void compile_island_import(char*label, char*island, char*src);
|
||||
extern void compile_island_export(char*label, char*island);
|
||||
|
||||
extern void compile_island_tranif(int sense, char*island,
|
||||
char*ba, char*bb, char*src);
|
||||
extern void compile_island_tranvp(char*island, char*ba, char*bb,
|
||||
unsigned width, unsigned part, unsigned off);
|
||||
|
||||
extern void compile_island_cleanup(void);
|
||||
|
||||
#endif
|
||||
|
||||
+62
-16
@@ -20,6 +20,7 @@
|
||||
|
||||
# include "compile.h"
|
||||
# include "vvp_net.h"
|
||||
# include "schedule.h"
|
||||
# include <stdlib.h>
|
||||
# include <iostream>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
@@ -27,18 +28,43 @@
|
||||
#endif
|
||||
# include <assert.h>
|
||||
|
||||
# define SCHEDULE_OUTPUT 0
|
||||
|
||||
/* vvp_fun_concat
|
||||
* This node function creates vectors (vvp_vector4_t) from the
|
||||
* concatenation of the inputs. The inputs (4) may be vector or
|
||||
* vector8 objects, but they are reduced to vector4 values and
|
||||
* strength information lost.
|
||||
*
|
||||
* The expected widths of the input vectors must be given up front so
|
||||
* that the positions in the output vector (and also the size of the
|
||||
* output vector) can be worked out. The input vectors must match the
|
||||
* expected width.
|
||||
*/
|
||||
class vvp_fun_concat : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
public:
|
||||
vvp_fun_concat(unsigned w0, unsigned w1,
|
||||
unsigned w2, unsigned w3);
|
||||
~vvp_fun_concat();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
vvp_net_t*net_;
|
||||
vvp_vector4_t input_[4];
|
||||
};
|
||||
|
||||
|
||||
vvp_fun_concat::vvp_fun_concat(unsigned w0, unsigned w1,
|
||||
unsigned w2, unsigned w3)
|
||||
: val_(w0+w1+w2+w3)
|
||||
: net_(0)
|
||||
{
|
||||
wid_[0] = w0;
|
||||
wid_[1] = w1;
|
||||
wid_[2] = w2;
|
||||
wid_[3] = w3;
|
||||
|
||||
for (unsigned idx = 0 ; idx < val_.size() ; idx += 1)
|
||||
val_.set_bit(idx, BIT4_X);
|
||||
input_[0] = vvp_vector4_t(w0);
|
||||
input_[1] = vvp_vector4_t(w1);
|
||||
input_[2] = vvp_vector4_t(w2);
|
||||
input_[3] = vvp_vector4_t(w3);
|
||||
}
|
||||
|
||||
vvp_fun_concat::~vvp_fun_concat()
|
||||
@@ -49,22 +75,42 @@ void vvp_fun_concat::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
{
|
||||
unsigned pdx = port.port();
|
||||
|
||||
if (bit.size() != wid_[pdx]) {
|
||||
if (bit.size() != input_[pdx].size()) {
|
||||
cerr << "internal error: port " << pdx
|
||||
<< " expects wid=" << wid_[pdx]
|
||||
<< " expects wid=" << input_[pdx].size()
|
||||
<< ", got wid=" << bit.size() << endl;
|
||||
assert(0);
|
||||
}
|
||||
|
||||
unsigned off = 0;
|
||||
for (unsigned idx = 0 ; idx < pdx ; idx += 1)
|
||||
off += wid_[idx];
|
||||
if (input_[pdx] .eeq(bit))
|
||||
return;
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid_[pdx] ; idx += 1) {
|
||||
val_.set_bit(off+idx, bit.value(idx));
|
||||
input_[pdx] = bit;
|
||||
|
||||
if (net_ == 0) {
|
||||
net_ = port.ptr();
|
||||
if (SCHEDULE_OUTPUT)
|
||||
schedule_generic(this, 0, false);
|
||||
else
|
||||
run_run();
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_concat::run_run()
|
||||
{
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 0;
|
||||
|
||||
unsigned off = 0;
|
||||
unsigned owid = input_[0].size() + input_[1].size() + input_[2].size() + input_[3].size();
|
||||
|
||||
vvp_vector4_t res (owid);
|
||||
for (unsigned idx = 0 ; idx < 4 && (off<owid) ; idx += 1) {
|
||||
res.set_vec(off, input_[idx]);
|
||||
off += input_[idx].size();
|
||||
}
|
||||
|
||||
vvp_send_vec4(port.ptr()->out, val_);
|
||||
vvp_send_vec4(ptr->out, res);
|
||||
}
|
||||
|
||||
void compile_concat(char*label, unsigned w0, unsigned w1,
|
||||
|
||||
@@ -5,6 +5,8 @@ AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_RANLIB
|
||||
AC_CHECK_TOOL(STRIP, strip, true)
|
||||
AC_CHECK_PROGS(MAN,man,none)
|
||||
AC_CHECK_PROGS(PS2PDF,ps2pdf,none)
|
||||
|
||||
AC_EXEEXT
|
||||
AC_SUBST(EXEEXT)
|
||||
|
||||
+1
-1
@@ -242,7 +242,7 @@ void vvp_fun_delay::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit)
|
||||
void vvp_fun_delay::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit)
|
||||
{
|
||||
assert(port.port() == 0);
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
~vvp_fun_delay();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
|
||||
void recv_real(vvp_net_ptr_t port, double bit);
|
||||
//void recv_long(vvp_net_ptr_t port, long bit);
|
||||
|
||||
|
||||
+15
-5
@@ -124,8 +124,11 @@
|
||||
".dff" { return K_DFF; }
|
||||
".event" { return K_EVENT; }
|
||||
".event/or" { return K_EVENT_OR; }
|
||||
".export" { return K_EXPORT; }
|
||||
".extend/s" { return K_EXTEND_S; }
|
||||
".functor" { return K_FUNCTOR; }
|
||||
".import" { return K_IMPORT; }
|
||||
".island" { return K_ISLAND; }
|
||||
".modpath" { return K_MODPATH; }
|
||||
".net" { return K_NET; }
|
||||
".net8" { return K_NET8; }
|
||||
@@ -138,6 +141,7 @@
|
||||
".part" { return K_PART; }
|
||||
".part/pv" { return K_PART_PV; }
|
||||
".part/v" { return K_PART_V; }
|
||||
".port" { return K_PORT; }
|
||||
".reduce/and" { return K_REDUCE_AND; }
|
||||
".reduce/or" { return K_REDUCE_OR; }
|
||||
".reduce/xor" { return K_REDUCE_XOR; }
|
||||
@@ -153,6 +157,10 @@
|
||||
".shift/rs" { return K_SHIFTRS; }
|
||||
".thread" { return K_THREAD; }
|
||||
".timescale" { return K_TIMESCALE; }
|
||||
".tran" { return K_TRAN; }
|
||||
".tranif0" { return K_TRANIF0; }
|
||||
".tranif1" { return K_TRANIF1; }
|
||||
".tranvp" { return K_TRANVP; }
|
||||
".ufunc" { return K_UFUNC; }
|
||||
".var" { return K_VAR; }
|
||||
".var/real" { return K_VAR_R; }
|
||||
@@ -173,22 +181,24 @@
|
||||
"%disable" { return K_disable; }
|
||||
"%fork" { return K_fork; }
|
||||
|
||||
/* Handle the specialized variable access functions. */
|
||||
|
||||
"&A" { return K_A; }
|
||||
"&PV" { return K_PV; }
|
||||
|
||||
"%"[.$_/a-zA-Z0-9]+ {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_INSTR; }
|
||||
|
||||
[0-9][0-9]* {
|
||||
yylval.numb = strtol(yytext, 0, 0);
|
||||
yylval.numb = strtoul(yytext, 0, 0);
|
||||
return T_NUMBER; }
|
||||
|
||||
"0x"[0-9a-fA-F]+ {
|
||||
yylval.numb = strtol(yytext, 0, 0);
|
||||
yylval.numb = strtoul(yytext, 0, 0);
|
||||
return T_NUMBER; }
|
||||
|
||||
|
||||
"&A" { return K_A; }
|
||||
|
||||
/* Handle some specialized constant/literals as symbols. */
|
||||
|
||||
"C4<"[01xz]*">" {
|
||||
|
||||
+5
-37
@@ -140,7 +140,6 @@ void vvp_fun_eeq::run_run()
|
||||
|
||||
vvp_fun_buf::vvp_fun_buf()
|
||||
{
|
||||
net_ = 0;
|
||||
count_functors_logic += 1;
|
||||
}
|
||||
|
||||
@@ -157,25 +156,12 @@ void vvp_fun_buf::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
if (ptr.port() != 0)
|
||||
return;
|
||||
|
||||
if (input_ .eeq( bit ))
|
||||
if (input_ .eq_xz( bit ))
|
||||
return;
|
||||
|
||||
input_ = bit;
|
||||
|
||||
if (net_ == 0) {
|
||||
net_ = ptr.ptr();
|
||||
schedule_generic(this, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_fun_buf::run_run()
|
||||
{
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 0;
|
||||
|
||||
vvp_vector4_t tmp (input_);
|
||||
tmp.change_z2x();
|
||||
vvp_send_vec4(ptr->out, tmp);
|
||||
input_.change_z2x();
|
||||
vvp_send_vec4(ptr.ptr()->out, input_);
|
||||
}
|
||||
|
||||
vvp_fun_bufz::vvp_fun_bufz()
|
||||
@@ -394,7 +380,6 @@ void vvp_fun_muxz::run_run()
|
||||
|
||||
vvp_fun_not::vvp_fun_not()
|
||||
{
|
||||
net_ = 0;
|
||||
count_functors_logic += 1;
|
||||
}
|
||||
|
||||
@@ -411,30 +396,13 @@ void vvp_fun_not::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
if (ptr.port() != 0)
|
||||
return;
|
||||
|
||||
if (input_ .eeq( bit ))
|
||||
if (input_ .eq_xz( bit ))
|
||||
return;
|
||||
|
||||
input_ = bit;
|
||||
if (net_ == 0) {
|
||||
net_ = ptr.ptr();
|
||||
schedule_generic(this, 0, false);
|
||||
}
|
||||
vvp_send_vec4(ptr.ptr()->out, ~input_);
|
||||
}
|
||||
|
||||
void vvp_fun_not::run_run()
|
||||
{
|
||||
vvp_net_t*ptr = net_;
|
||||
net_ = 0;
|
||||
|
||||
vvp_vector4_t result (input_);
|
||||
|
||||
for (unsigned idx = 0 ; idx < result.size() ; idx += 1) {
|
||||
vvp_bit4_t bitbit = ~ result.value(idx);
|
||||
result.set_bit(idx, bitbit);
|
||||
}
|
||||
|
||||
vvp_send_vec4(ptr->out, result);
|
||||
}
|
||||
|
||||
vvp_fun_or::vvp_fun_or(unsigned wid, bool invert)
|
||||
: vvp_fun_boolean_(wid), invert_(invert)
|
||||
|
||||
+2
-10
@@ -69,7 +69,7 @@ class vvp_fun_eeq : public vvp_fun_boolean_ {
|
||||
* The retransmitted vector has all Z values changed to X, just like
|
||||
* the buf(Q,D) gate in Verilog.
|
||||
*/
|
||||
class vvp_fun_buf: public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
class vvp_fun_buf: public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_buf();
|
||||
@@ -77,12 +77,8 @@ class vvp_fun_buf: public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
|
||||
private:
|
||||
vvp_vector4_t input_;
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -152,7 +148,7 @@ class vvp_fun_muxr : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
sel_type select_;
|
||||
};
|
||||
|
||||
class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
class vvp_fun_not: public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_fun_not();
|
||||
@@ -160,12 +156,8 @@ class vvp_fun_not: public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t p, const vvp_vector4_t&bit);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
|
||||
private:
|
||||
vvp_vector4_t input_;
|
||||
vvp_net_t*net_;
|
||||
};
|
||||
|
||||
class vvp_fun_or : public vvp_fun_boolean_ {
|
||||
|
||||
+14
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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
|
||||
@@ -66,6 +66,12 @@ extern "C" long int lround(double x)
|
||||
#endif
|
||||
|
||||
bool verbose_flag = false;
|
||||
static int vvp_return_value = 0;
|
||||
|
||||
void vpip_set_return_value(int value)
|
||||
{
|
||||
vvp_return_value = value;
|
||||
}
|
||||
|
||||
static char log_buffer[4096];
|
||||
|
||||
@@ -273,9 +279,11 @@ int main(int argc, char*argv[])
|
||||
vpi_mcd_printf(1, " %8lu bufif\n", count_functors_bufif);
|
||||
vpi_mcd_printf(1, " %8lu resolv\n",count_functors_resolv);
|
||||
vpi_mcd_printf(1, " %8lu signals\n", count_functors_sig);
|
||||
vpi_mcd_printf(1, " ... %8lu opcodes (%lu bytes)\n",
|
||||
vpi_mcd_printf(1, " ... %8lu opcodes (%zu bytes)\n",
|
||||
count_opcodes, (unsigned long)size_opcodes);
|
||||
vpi_mcd_printf(1, " ... %8lu nets\n", count_vpi_nets);
|
||||
vpi_mcd_printf(1, " ... %8lu vvp_nets (%zu bytes)\n",
|
||||
count_vvp_nets, size_vvp_nets);
|
||||
vpi_mcd_printf(1, " ... %8lu memories\n", count_vpi_memories);
|
||||
vpi_mcd_printf(1, " ... %8lu scopes\n", count_vpi_scopes);
|
||||
}
|
||||
@@ -293,18 +301,16 @@ int main(int argc, char*argv[])
|
||||
my_getrusage(cycles+2);
|
||||
print_rusage(cycles+2, cycles+1);
|
||||
|
||||
vpi_mcd_printf(1, "Event counts: (event pool = %lu)\n",
|
||||
count_event_pool);
|
||||
vpi_mcd_printf(1, "Event counts:\n");
|
||||
vpi_mcd_printf(1, " %8lu time steps (pool=%lu)\n",
|
||||
count_time_events, count_time_pool);
|
||||
vpi_mcd_printf(1, " %8lu thread schedule events\n",
|
||||
count_thread_events);
|
||||
vpi_mcd_printf(1, " %8lu propagation events\n",
|
||||
count_prop_events);
|
||||
vpi_mcd_printf(1, " %8lu assign events\n",
|
||||
count_assign_events);
|
||||
vpi_mcd_printf(1, " %8lu other events\n",
|
||||
count_gen_events);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return vvp_return_value;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -33,7 +33,7 @@ void vvp_fun_pmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
|
||||
/* Data input is processed through eh recv_vec8 method,
|
||||
because the strength must be preserved. */
|
||||
if (ptr.port() == 0) {
|
||||
vvp_vector8_t tmp = bit;
|
||||
vvp_vector8_t tmp = vvp_vector8_t(bit,6,6);
|
||||
recv_vec8(ptr, tmp);
|
||||
return;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ vvp_fun_pmos::vvp_fun_pmos(bool enable_invert)
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_pmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
||||
void vvp_fun_pmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
|
||||
{
|
||||
if (ptr.port() == 1) {
|
||||
recv_vec4(ptr, reduce4(bit));
|
||||
@@ -105,7 +105,7 @@ vvp_fun_rpmos::vvp_fun_rpmos(bool enable_invert)
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
||||
void vvp_fun_rpmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
|
||||
{
|
||||
if (ptr.port() == 1) {
|
||||
recv_vec4(ptr, reduce4(bit));
|
||||
@@ -133,7 +133,7 @@ void vvp_fun_cmos_::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t &bit)
|
||||
/* Data input is processed through the recv_vec8 method,
|
||||
because the strength must be preserved. */
|
||||
if (ptr.port() == 0) {
|
||||
vvp_vector8_t tmp = bit;
|
||||
vvp_vector8_t tmp = vvp_vector8_t(bit,6,6);
|
||||
recv_vec8(ptr, tmp);
|
||||
return;
|
||||
}
|
||||
@@ -187,7 +187,7 @@ vvp_fun_cmos::vvp_fun_cmos()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_cmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
||||
void vvp_fun_cmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
|
||||
{
|
||||
if (ptr.port() == 1 || ptr.port() == 2) {
|
||||
recv_vec4(ptr, reduce4(bit));
|
||||
@@ -206,7 +206,7 @@ vvp_fun_rcmos::vvp_fun_rcmos()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_rcmos::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
|
||||
void vvp_fun_rcmos::recv_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&bit)
|
||||
{
|
||||
if (ptr.port() == 1) {
|
||||
recv_vec4(ptr, reduce4(bit));
|
||||
|
||||
+4
-4
@@ -66,7 +66,7 @@ class vvp_fun_pmos : public vvp_fun_pmos_ {
|
||||
public:
|
||||
explicit vvp_fun_pmos(bool enable_invert);
|
||||
|
||||
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -79,7 +79,7 @@ class vvp_fun_rpmos : public vvp_fun_pmos_ {
|
||||
public:
|
||||
explicit vvp_fun_rpmos(bool enable_invert);
|
||||
|
||||
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -121,14 +121,14 @@ class vvp_fun_cmos : public vvp_fun_cmos_ {
|
||||
public:
|
||||
explicit vvp_fun_cmos();
|
||||
|
||||
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
|
||||
};
|
||||
|
||||
class vvp_fun_rcmos : public vvp_fun_cmos_ {
|
||||
public:
|
||||
explicit vvp_fun_rcmos();
|
||||
|
||||
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
|
||||
void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t&bit);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+2
-34
@@ -80,20 +80,6 @@ is given by the <delayx> value. This should not be 0, 1 or 3, of course,
|
||||
since these registers contain the vector width, base part select and
|
||||
word address.
|
||||
|
||||
* %assign/mv <memory-label>, <delay>, <bit> (DEPRECATED)
|
||||
|
||||
the %assign/mv instruction assigns a vector value to a word in the
|
||||
labeled memory. The <delay> is the delay in simulation time to the
|
||||
assignment (0 for non-blocking assignment) and the <bit> is the base
|
||||
of the vector to write.
|
||||
|
||||
The width of the word is retrieved from index register 0.
|
||||
|
||||
The base of a part select is retrieved from index register 1.
|
||||
|
||||
The address of the word in the memory is from index register 3. The
|
||||
address is canonical form.
|
||||
|
||||
* %assign/v0 <var-label>, <delay>, <bit>
|
||||
* %assign/v0/d <var-label>, <delayx>, <bit>
|
||||
|
||||
@@ -443,12 +429,6 @@ This instruction is similar to %load/av, but it loads only a single
|
||||
bit, and the <index> is the selector for the bit to use. If <index> is
|
||||
out of range, then x is loaded.
|
||||
|
||||
* %load/mv <bit>, <memory-label>, <wid>
|
||||
|
||||
this instruction loads a word from the specified memory. The word
|
||||
address is in index register 3. The width should match the width of
|
||||
the memory word.
|
||||
|
||||
* %load/nx <bit>, <vpi-label>, <idx>
|
||||
|
||||
This instruction load a value from a .net object bit. Since .net
|
||||
@@ -531,7 +511,8 @@ is one of the 4 constant bits, the effect is to replicate the value
|
||||
into the destination vector. This is useful for filling a vector.
|
||||
|
||||
The %movi variant moves a binary value, LSB first, into the
|
||||
destination vector.
|
||||
destination vector. The immediate value is up to 32bits, padded with
|
||||
zeros to fillout the width.
|
||||
|
||||
* %mul <bit-l>, <bit-r>, <wid>
|
||||
|
||||
@@ -667,19 +648,6 @@ width is implied from the <wid> that is the argument. This is the part
|
||||
The address (in canonical form) is precalculated and loaded into index
|
||||
register 3. This is the address of the word within the array.
|
||||
|
||||
* %set/mv <memory-label>, <bit>, <wid>
|
||||
|
||||
This sets a thread vector to a memory word. The <memory-label>
|
||||
addresses a memory device, and the <bit>,<wid> describe a vector to be
|
||||
written. Index register 3 contains the address of the word within the
|
||||
memory.
|
||||
|
||||
The base of a part select is retrieved from index register 1.
|
||||
|
||||
The address (in canonical form) is precalculated and loaded into index
|
||||
register 3.
|
||||
|
||||
|
||||
* %set/wr <vpi-label>, <bit>
|
||||
|
||||
This instruction writes a real word to the specified VPI-like object.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user