diff --git a/Makefile.in b/Makefile.in index 6fb8b38d1..b5fc3d3d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,23 @@ # SHELL = /bin/sh +# Normally, the "make" will build all the files only by dependencies. +# The MODE, however, can control your rebuild intentions. The proper way +# to use the MODE is on the make command like, this this: +# +# make MODE=XXXX all +# +# The possible MODE= values are: +# +# regular +# Build as normal +# +# full +# Do some extra builds. in particular: +# Build version.h again, even if it already exists. +# +MODE=regular + # This version string is only used in the version message printed # by the compiler. It reflects the assigned version number for the # product as a whole. Most components also print the CVS Name: token @@ -52,15 +69,15 @@ MAN = @MAN@ PS2PDF = @PS2PDF@ GIT = @GIT@ -CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@ +CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ CXXFLAGS = -Wall @CXXFLAGS@ PICFLAGS = @PICFLAG@ LDFLAGS = @rdynamic@ @LDFLAGS@ all: dep version.h ivl@EXEEXT@ - for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done + for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) VERSION=$(VERSION) $@); done for dir in ivlpp ; \ - do (cd $$dir ; $(MAKE) $@); done + do (cd $$dir ; $(MAKE) VERSION=$(VERSION) $@); done cd driver ; $(MAKE) VERSION=$(VERSION) $@ # In the windows world, the installer will need a dosify program to @@ -110,7 +127,7 @@ net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \ parse.o parse_misc.o pform.o pform_analog.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 \ +verinum.o verireal.o target.o \ Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \ PExpr.o PGate.o PGenerate.o PScope.o PSpec.o \ PTask.o PUdp.o PFunction.o PWire.o Statement.o AStatement.o StringHeap.o \ @@ -186,7 +203,9 @@ iverilog-vpi.pdf: iverilog-vpi.ps # 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. +ifeq ($(MODE),full) .PHONY: version.h +endif # "true" and "false" in the next few lines are Unix shell command names ifeq ($(GIT),none) GIT_PRESENT = false diff --git a/Module.h b/Module.h index 162761e88..e05aa244e 100644 --- a/Module.h +++ b/Module.h @@ -76,40 +76,6 @@ 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 : 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; - bool signed_flag; - // Value expression - PExpr*expr; - // If there are range constraints, list them here - range_t*range; - }; - mapparameters; - maplocalparams; - - /* specparams are simpler then other params, in that they have no type information. They are merely constant expressions. */ diff --git a/PDelays.cc b/PDelays.cc index c547a2c08..e39a57122 100644 --- a/PDelays.cc +++ b/PDelays.cc @@ -101,7 +101,7 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr) return dex; } -static NetExpr* make_delay_nets(Design*des, NetExpr*expr) +static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr) { if (dynamic_cast (expr)) return expr; @@ -109,7 +109,7 @@ static NetExpr* make_delay_nets(Design*des, NetExpr*expr) if (dynamic_cast (expr)) return expr; - NetNet*sig = expr->synthesize(des); + NetNet*sig = expr->synthesize(des, scope); if (sig == 0) { cerr << expr->get_fileline() << ": error: Expression " << *expr << " is not suitable for delay expression." << endl; @@ -132,17 +132,17 @@ void PDelays::eval_delays(Design*des, NetScope*scope, if (delay_[0]) { rise_time = calculate_val(des, scope, delay_[0]); if (as_nets_flag) - rise_time = make_delay_nets(des, rise_time); + rise_time = make_delay_nets(des, scope, rise_time); if (delay_[1]) { fall_time = calculate_val(des, scope, delay_[1]); if (as_nets_flag) - fall_time = make_delay_nets(des, fall_time); + fall_time = make_delay_nets(des, scope, fall_time); if (delay_[2]) { decay_time = calculate_val(des, scope, delay_[2]); if (as_nets_flag) - decay_time = make_delay_nets(des, decay_time); + decay_time = make_delay_nets(des, scope, decay_time); } else { if (rise_time < fall_time) diff --git a/PExpr.h b/PExpr.h index b2a4f9a9a..a3da795a3 100644 --- a/PExpr.h +++ b/PExpr.h @@ -36,9 +36,6 @@ class NetScope; * The PExpr class hierarchy supports the description of * expressions. The parser can generate expression objects from the * source, possibly reducing things that it knows how to reduce. - * - * The elaborate_net method is used by structural elaboration to build - * up a netlist interpretation of the expression. */ class PExpr : public LineInfo { @@ -53,7 +50,7 @@ class PExpr : public LineInfo { // be. It is used by elaboration of assignments to figure out // the width of the expression. // - // The "min" is the width of the local context, so it the + // The "min" is the width of the local context, so is the // minimum width that this function should return. Initially // this is the same as the lval width. // @@ -66,12 +63,16 @@ class PExpr : public LineInfo { // the subexpression should not make l-value related // optimizations. // + // The expr_type is an output argument that gives the + // calculated type for the expression. + // // The unsigned_flag is set to true if the expression is // unsized and therefore expandable. This happens if a // sub-expression is an unsized literal. Some expressions make // special use of that. virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; // During the elaborate_sig phase, we may need to scan @@ -98,17 +99,6 @@ class PExpr : public LineInfo { // evaluation of parameters. virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; - // This method elaborate the expression as gates, for use in a - // continuous assign or other wholly structural context. - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG) - const; - // This method elaborates the expression as gates, but // restricted for use as l-values of continuous assignments. virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; @@ -163,13 +153,6 @@ class PEConcat : public PExpr { virtual bool elaborate_sig(Design*des, NetScope*scope) const; virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const; @@ -232,18 +215,14 @@ class PEFNumber : public PExpr { /* A PEFNumber is a constant, so this returns true. */ virtual bool is_constant(Module*) const; + virtual unsigned test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual void dump(ostream&) const; private: @@ -264,6 +243,7 @@ class PEIdent : public PExpr { virtual void dump(ostream&) const; virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -278,15 +258,6 @@ class PEIdent : public PExpr { NetScope*scope, bool is_force) const; - // Structural r-values are OK. - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -321,12 +292,13 @@ class PEIdent : public PExpr { index_component_t::ctype_t) const; private: - NetExpr*elaborate_expr_param(Design*des, - NetScope*scope, - const NetExpr*par, - NetScope*found, - const NetExpr*par_msb, - const NetExpr*par_lsb) const; + NetExpr*elaborate_expr_param_(Design*des, + NetScope*scope, + const NetExpr*par, + NetScope*found, + const NetExpr*par_msb, + const NetExpr*par_lsb, + int expr_wid) const; NetExpr*elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, @@ -366,38 +338,6 @@ class PEIdent : public PExpr { NetESignal*net, NetScope*found) const; - public: - - NetNet* elaborate_net_array_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - - NetNet* elaborate_net_net_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elaborate_net_net_idx_up_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elaborate_net_bitmux_(Design*des, NetScope*scope, - NetNet*sig, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - private: NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, bool bidirectional_flag) const; @@ -406,8 +346,6 @@ class PEIdent : public PExpr { bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig, long&midx, long&lidx) const; - NetNet*process_select_(Design*des, NetScope*scope, NetNet*sig) const; - }; class PENumber : public PExpr { @@ -421,15 +359,9 @@ class PENumber : public PExpr { virtual void dump(ostream&) const; virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -464,15 +396,9 @@ class PEString : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; virtual NetEConst*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -492,15 +418,13 @@ class PEUnary : public PExpr { virtual void dump(ostream&out) const; + virtual unsigned test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const; + virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -508,32 +432,6 @@ class PEUnary : public PExpr { virtual bool is_constant(Module*) const; - private: - NetNet* elab_net_uminus_const_logic_(Design*des, NetScope*scope, - NetEConst*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elab_net_uminus_const_real_(Design*des, NetScope*scope, - NetECReal*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elab_net_unary_real_(Design*des, NetScope*scope, - NetExpr*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - private: char op_; PExpr*expr_; @@ -551,17 +449,11 @@ class PEBinary : public PExpr { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -575,54 +467,15 @@ class PEBinary : public PExpr { NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_bits_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_div_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_mult_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; + static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp); - private: - NetNet* elaborate_net_add_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_bit_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_cmp_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_div_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_mod_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_log_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_mul_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_pow_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_shift_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; }; /* @@ -637,6 +490,7 @@ class PEBComp : public PEBinary { virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&flag) const; NetExpr* elaborate_expr(Design*des, NetScope*scope, @@ -650,7 +504,11 @@ class PEBShift : public PEBinary { ~PEBShift(); virtual unsigned test_width(Design*des, NetScope*scope, - unsigned min, unsigned lval, bool&flag) const; + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&flag) const; + virtual NetExpr*elaborate_expr(Design*des, NetScope*, + int expr_width, bool sys_task_arg) const; }; /* @@ -668,18 +526,12 @@ class PETernary : public PExpr { virtual void dump(ostream&out) const; virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual NetETernary*elaborate_expr(Design*des, NetScope*, + virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; @@ -712,19 +564,13 @@ class PECallFunction : public PExpr { virtual void dump(ostream &) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; virtual unsigned test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; private: @@ -735,15 +581,9 @@ class PECallFunction : public PExpr { NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetExpr* elaborate_access_func_(Design*des, NetScope*scope, int expr_wid) const; - NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const; }; diff --git a/PGate.h b/PGate.h index 78d637ead..e9f447451 100644 --- a/PGate.h +++ b/PGate.h @@ -167,8 +167,16 @@ class PGBuiltin : public PGate { virtual bool elaborate_sig(Design*des, NetScope*scope) const; private: - Type type_; + unsigned calculate_array_count_(Design*, NetScope*, + long&high, long&low) const; + unsigned calculate_output_count_(void) const; + + NetNode* create_gate_for_output_(Design*, NetScope*, + perm_string gate_name, + unsigned instance_width) const; + + Type type_; PExpr*msb_; PExpr*lsb_; }; @@ -239,7 +247,7 @@ class PGModule : public PGate { NetNet*resize_net_to_port_(Design*des, NetScope*scope, NetNet*sig, unsigned port_wid, - NetNet::PortType dir) const; + NetNet::PortType dir, bool as_signed) const; }; #endif diff --git a/PGenerate.h b/PGenerate.h index d88115533..a9af52120 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -78,8 +78,6 @@ class PGenerate : public LineInfo, public LexicalScope { list gates; void add_gate(PGate*); - list behaviors; - // Tasks instantiated within this scheme. map tasks; mapfuncs; diff --git a/PScope.h b/PScope.h index 545b502f3..c2749ac9f 100644 --- a/PScope.h +++ b/PScope.h @@ -19,11 +19,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +# include "LineInfo.h" # include "StringHeap.h" # include "pform_types.h" +# include "ivl_target.h" # include class PEvent; +class PExpr; class AProcess; class PProcess; class PWire; @@ -36,7 +39,7 @@ class NetScope; * represents lexical scope. For example, a module, a function/task, a * named block is derived from a PScope. * - * NOTE: This is note the same concept as the "scope" of an elaborated + * NOTE: This is not the same concept as the "scope" of an elaborated * hierarchy. That is represented by NetScope objects after elaboration. */ @@ -47,7 +50,43 @@ class LexicalScope { // A virtual destructor is so that dynamic_cast can work. virtual ~LexicalScope() { } - // Nets an variables (wires) in the scope + 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 scope has parameters that are evaluated when the scope + is elaborated. During parsing, I put the parameters into + this map. */ + 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; + bool signed_flag; + // Value expression + PExpr*expr; + // If there are range constraints, list them here + range_t*range; + }; + mapparameters; + maplocalparams; + + // Named events in the scope. + mapevents; + + // Nets and variables (wires) in the scope mapwires; PWire* wires_find(perm_string name); @@ -55,6 +94,15 @@ class LexicalScope { list behaviors; list analog_behaviors; + protected: + void dump_parameters_(ostream&out, unsigned indent) const; + + void dump_localparams_(ostream&out, unsigned indent) const; + + void dump_events_(ostream&out, unsigned indent) const; + + void dump_wires_(ostream&out, unsigned indent) const; + private: }; @@ -76,12 +124,7 @@ class PScope : public LexicalScope { perm_string pscope_name() const { return name_; } PScope* pscope_parent() { return parent_; } - // Named events in the scope. - mapevents; - protected: - void dump_wires_(ostream&out, unsigned indent) const; - bool elaborate_sig_wires_(Design*des, NetScope*scope) const; bool elaborate_behaviors_(Design*des, NetScope*scope) const; diff --git a/Statement.h b/Statement.h index 10def60d2..d817ff7a2 100644 --- a/Statement.h +++ b/Statement.h @@ -103,6 +103,8 @@ class PAssign_ : public Statement { protected: NetAssign_* elaborate_lval(Design*, NetScope*scope) const; + NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width, + ivl_variable_type_t type) const; PExpr* delay_; PEventStatement*event_; diff --git a/cadpli/ivl_dlfcn.h b/cadpli/ivl_dlfcn.h index 9bfab8284..59d4bd9fb 100644 --- a/cadpli/ivl_dlfcn.h +++ b/cadpli/ivl_dlfcn.h @@ -35,16 +35,16 @@ typedef shl_t ivl_dll_t; #endif #if defined(__MINGW32__) -static inline ivl_dll_t ivl_dlopen(const char *name) +static __inline__ ivl_dll_t ivl_dlopen(const char *name) { return (void *)LoadLibrary(name); } -static inline void *ivl_dlsym(ivl_dll_t dll, const char *nm) +static __inline__ void *ivl_dlsym(ivl_dll_t dll, const char *nm) { return (void *)GetProcAddress((HINSTANCE)dll,nm);} -static inline void ivl_dlclose(ivl_dll_t dll) +static __inline__ void ivl_dlclose(ivl_dll_t dll) { (void)FreeLibrary((HINSTANCE)dll);} -static inline const char *dlerror(void) +static __inline__ const char *dlerror(void) { static char msg[256]; unsigned long err = GetLastError(); @@ -61,10 +61,10 @@ static inline const char *dlerror(void) } #elif defined(HAVE_DLFCN_H) -static inline ivl_dll_t ivl_dlopen(const char*name) +static __inline__ ivl_dll_t ivl_dlopen(const char*name) { return dlopen(name,RTLD_LAZY); } -static inline void* ivl_dlsym(ivl_dll_t dll, const char*nm) +static __inline__ void* ivl_dlsym(ivl_dll_t dll, const char*nm) { void*sym = dlsym(dll, nm); /* Not found? try without the leading _ */ @@ -73,24 +73,24 @@ static inline void* ivl_dlsym(ivl_dll_t dll, const char*nm) return sym; } -static inline void ivl_dlclose(ivl_dll_t dll) +static __inline__ void ivl_dlclose(ivl_dll_t dll) { dlclose(dll); } #elif defined(HAVE_DL_H) -static inline ivl_dll_t ivl_dlopen(const char*name) +static __inline__ ivl_dll_t ivl_dlopen(const char*name) { return shl_load(name, BIND_IMMEDIATE, 0); } -static inline void* ivl_dlsym(ivl_dll_t dll, const char*nm) +static __inline__ void* ivl_dlsym(ivl_dll_t dll, const char*nm) { void*sym; int rc = shl_findsym(&dll, nm, TYPE_PROCEDURE, &sym); return (rc == 0) ? sym : 0; } -static inline void ivl_dlclose(ivl_dll_t dll) +static __inline__ void ivl_dlclose(ivl_dll_t dll) { shl_unload(dll); } -static inline const char*dlerror(void) +static __inline__ const char*dlerror(void) { return strerror( errno ); } #endif diff --git a/config.h.in b/config.h.in index 4bdc087e3..091c1e3c4 100644 --- a/config.h.in +++ b/config.h.in @@ -93,4 +93,4 @@ * junk, and support gcc 3.0. (Stephan Boettcher) * */ -#endif // __config_H +#endif /* __config_H */ diff --git a/configure.in b/configure.in index 1a975b173..5443f69ec 100644 --- a/configure.in +++ b/configure.in @@ -124,4 +124,4 @@ AX_CPP_IDENT # XXX disable tgt-fpga for the moment AC_CONFIG_SUBDIRS(vvp vpi tgt-stub tgt-null tgt-vvp tgt-vhdl libveriuser cadpli) -AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile tgt-vhdl/Makefile) +AC_OUTPUT(Makefile ivlpp/Makefile driver/Makefile driver-vpi/Makefile tgt-null/Makefile tgt-verilog/Makefile tgt-pal/Makefile) diff --git a/design_dump.cc b/design_dump.cc index 25e61d04e..5f1dcd91b 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -241,11 +241,14 @@ void NetNode::dump_node(ostream&o, unsigned ind) const /* This is the generic dumping of all the signals connected to each pin of the object. The "this" object is not printed, only the signals connected to this. */ -void NetPins::dump_node_pins(ostream&o, unsigned ind) const +void NetPins::dump_node_pins(ostream&o, unsigned ind, const char**pin_names) const { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - o << setw(ind) << "" << idx << " " << pin(idx).get_name() - << "<" << pin(idx).get_inst() << ">"; + o << setw(ind) << "" << idx; + if (pin_names && pin_names[idx]) + o << " " << pin_names[idx]; + else + o << " pin" << idx; switch (pin(idx).get_dir()) { case Link::PASSIVE: @@ -294,7 +297,14 @@ void NetAddSub::dump_node(ostream&o, unsigned ind) const o << setw(ind) << "" << "Adder (NetAddSub): " << name() << " width=" << width() << " pin_count=" << pin_count() << endl; - dump_node_pins(o, ind+4); + static const char* pin_names[] = { + "Cout ", + "DataA ", + "DataB ", + "Result" + }; + + dump_node_pins(o, ind+4, pin_names); dump_obj_attr(o, ind+4); } @@ -567,8 +577,14 @@ void NetReplicate::dump_node(ostream&o, unsigned ind) const void NetSignExtend::dump_node(ostream&o, unsigned ind) const { - o << setw(ind) << "" << "NetSignExtend: " - << name() << " output width=" << width_ << endl; + o << setw(ind) << "" << "NetSignExtend: " << name(); + if (rise_time()) + o << " #(" << *rise_time() + << "," << *fall_time() + << "," << *decay_time() << ")"; + else + o << " #(.,.,.)"; + o << " output width=" << width_ << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -702,6 +718,11 @@ void NetProcTop::dump(ostream&o, unsigned ind) const statement_->dump(o, ind+2); } +void NetAlloc::dump(ostream&o, unsigned ind) const +{ + o << setw(ind) << "// allocate storage : " << scope_path(scope_) << endl; +} + void NetAssign_::dump_lval(ostream&o) const { if (sig_) { @@ -753,6 +774,11 @@ void NetAssignNB::dump(ostream&o, unsigned ind) const if (const NetExpr*de = get_delay()) o << "#(" << *de << ") "; + if (count_) + o << "repeat(" << *count_ << ") "; + if (event_) { + o << *event_; + } o << *rval() << ";" << endl; @@ -897,6 +923,25 @@ void NetEvWait::dump(ostream&o, unsigned ind) const o << setw(ind+2) << "" << "/* noop */ ;" << endl; } +ostream& operator << (ostream&out, const NetEvWait&obj) +{ + obj.dump_inline(out); + return out; +} + +void NetEvWait::dump_inline(ostream&o) const +{ + o << "@("; + + if (nevents() > 0) + o << event(0)->name(); + + for (unsigned idx = 1 ; idx < nevents() ; idx += 1) + o << " or " << event(idx)->name(); + + o << ") "; +} + void NetForce::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "force "; @@ -910,6 +955,11 @@ void NetForever::dump(ostream&o, unsigned ind) const statement_->dump(o, ind+2); } +void NetFree::dump(ostream&o, unsigned ind) const +{ + o << setw(ind) << "// free storage : " << scope_path(scope_) << endl; +} + void NetFuncDef::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "function definition for " << scope_path(scope_) << endl; diff --git a/driver/main.c b/driver/main.c index 932197e82..fbd8de4df 100644 --- a/driver/main.c +++ b/driver/main.c @@ -51,6 +51,7 @@ const char HELP[] = #include #include #include +#include #include #include @@ -259,18 +260,104 @@ static const char*my_tempfile(const char*str, FILE**fout) return pathbuf; } +static int t_version_only(void) +{ + remove(source_path); + + fflush(0); + snprintf(tmp, sizeof tmp, "%s%civlpp -V", pbase, sep); + system(tmp); + + fflush(0); + snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", pbase, sep, + iconfig_path, iconfig_common_path); + system(tmp); + + if ( ! getenv("IVERILOG_ICONFIG")) { + remove(iconfig_path); + remove(defines_path); + remove(compiled_defines_path); + } + + return 0; +} + +static void build_preprocess_command(int e_flag) +{ + snprintf(tmp, sizeof tmp, "%s%civlpp %s%s -F%s -f%s -p%s ", + pbase,sep, verbose_flag?" -v":"", + e_flag?"":" -L", defines_path, source_path, + compiled_defines_path); +} + +static int t_preprocess_only(void) +{ + int rc; + char*cmd; + unsigned ncmd; + + build_preprocess_command(1); + + ncmd = strlen(tmp); + cmd = malloc(ncmd+1); + strcpy(cmd, tmp); + + if (strcmp(opath,"-") != 0) { + snprintf(tmp, sizeof tmp, " > %s", opath); + cmd = realloc(cmd, ncmd+strlen(tmp)+1); + strcpy(cmd+ncmd, tmp); + ncmd += strlen(tmp); + } + + if (verbose_flag) + printf("preprocess: %s\n", cmd); + + rc = system(cmd); + remove(source_path); + + if ( ! getenv("IVERILOG_ICONFIG")) { + remove(iconfig_path); + remove(defines_path); + remove(compiled_defines_path); + } + + if (rc != 0) { + if (WIFEXITED(rc)) { + fprintf(stderr, "errors preprocessing Verilog program.\n"); + return WEXITSTATUS(rc); + } + + fprintf(stderr, "Command signaled: %s\n", cmd); + free(cmd); + return -1; + } + + return 0; +} + /* * This is the default target type. It looks up the bits that are * needed to run the command from the configuration file (which is * already parsed for us) so we can handle must of the generic cases. */ -static int t_default(char*cmd, unsigned ncmd) +static int t_compile() { unsigned rc; + + /* Start by building the preprocess command line. */ + build_preprocess_command(0); + + size_t ncmd = strlen(tmp); + char*cmd = malloc(ncmd + 1); + strcpy(cmd, tmp); + #ifdef __MINGW32__ unsigned ncmd_start = ncmd; +#else + int rtn; #endif + /* Build the ivl command and pipe it to the preprocessor. */ snprintf(tmp, sizeof tmp, " | %s/ivl", base); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); @@ -331,7 +418,7 @@ static int t_default(char*cmd, unsigned ncmd) free(cmd); return rc; #else - int rtn = 0; + rtn = 0; if (rc != 0) { if (rc == 127) { fprintf(stderr, "Failed to execute: %s\n", cmd); @@ -533,8 +620,6 @@ void add_sft_file(const char *module) int main(int argc, char **argv) { - char*cmd; - unsigned ncmd; int e_flag = 0; int version_flag = 0; int opt, idx, rc; @@ -748,9 +833,6 @@ int main(int argc, char **argv) printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); printf("Copyright 1998-2008 Stephen Williams\n"); puts(NOTICE); - - if (version_flag) - return 0; } /* Make a common conf file path to reflect the target. */ @@ -833,61 +915,11 @@ int main(int argc, char **argv) fclose(defines_file); defines_file = 0; - if (source_count == 0) { + if (source_count == 0 && !version_flag) { fprintf(stderr, "%s: no source files.\n\n%s\n", argv[0], HELP); return 1; } - - /* Start building the preprocess command line. */ - - sprintf(tmp, "%s%civlpp %s%s -F%s -f%s -p%s ", pbase,sep, - verbose_flag?" -v":"", - e_flag?"":" -L", defines_path, source_path, - compiled_defines_path); - - ncmd = strlen(tmp); - cmd = malloc(ncmd + 1); - strcpy(cmd, tmp); - - /* If the -E flag was given on the command line, then all we - do is run the preprocessor and put the output where the - user wants it. */ - if (e_flag) { - int rc; - if (strcmp(opath,"-") != 0) { - sprintf(tmp, " > %s", opath); - cmd = realloc(cmd, ncmd+strlen(tmp)+1); - strcpy(cmd+ncmd, tmp); - ncmd += strlen(tmp); - } - - if (verbose_flag) - printf("preprocess: %s\n", cmd); - - rc = system(cmd); - remove(source_path); - fclose(iconfig_file); - if ( ! getenv("IVERILOG_ICONFIG")) { - remove(iconfig_path); - remove(defines_path); - remove(compiled_defines_path); - } - - if (rc != 0) { - if (WIFEXITED(rc)) { - fprintf(stderr, "errors preprocessing Verilog program.\n"); - return WEXITSTATUS(rc); - } - - fprintf(stderr, "Command signaled: %s\n", cmd); - free(cmd); - return -1; - } - - return 0; - } - fprintf(iconfig_file, "iwidth:%u\n", integer_width); /* Write the preprocessor command needed to preprocess a @@ -899,5 +931,16 @@ int main(int argc, char **argv) /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); - return t_default(cmd, ncmd); + /* If we're only here for the version output, then we're done. */ + if (version_flag) + return t_version_only(); + + /* If the -E flag was given on the command line, then all we + do is run the preprocessor and put the output where the + user wants it. */ + if (e_flag) + return t_preprocess_only(); + + /* Otherwise, this is a full compile. */ + return t_compile(); } diff --git a/elab_expr.cc b/elab_expr.cc index ee7cbc444..f54d9a47a 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -21,6 +21,7 @@ # include # include # include +# include # include "compiler.h" # include "pform.h" @@ -30,12 +31,66 @@ # include "util.h" # include "ivl_assert.h" +bool type_is_vectorable(ivl_variable_type_t type) +{ + switch (type) { + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + return true; + default: + return false; + } +} + +NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, + ivl_variable_type_t data_type_lv, int expr_wid_lv, + const PExpr*expr) +{ + int expr_wid = 0; + bool unsized_flag = false; + ivl_variable_type_t rval_type = IVL_VT_NO_TYPE; + + switch (data_type_lv) { + case IVL_VT_REAL: + unsized_flag = true; + expr_wid = -2; + expr_wid_lv = -1; + break; + case IVL_VT_BOOL: + case IVL_VT_LOGIC: + /* Find out what the r-value width is going to be. We + guess it will be the l-value width, but it may turn + out to be something else based on self-determined + widths inside. */ + expr_wid = expr->test_width(des, scope, expr_wid_lv, expr_wid_lv, rval_type, unsized_flag); + + if (debug_elaborate) { + cerr << expr->get_fileline() << ": debug: r-value tested " + << "width is " << expr_wid + << ", min=" << expr_wid_lv + << ", unsized_flag=" << (unsized_flag?"true":"false") << endl; + } + + break; + case IVL_VT_VOID: + case IVL_VT_NO_TYPE: + ivl_assert(*expr, 0); + expr_wid = -2; + expr_wid_lv = -1; + break; + } + + NetExpr*result = elab_and_eval(des, scope, expr, expr_wid, expr_wid_lv); + return result; +} + /* * The default behavior for the test_width method is to just return the * minimum width that is passed in. */ unsigned PExpr::test_width(Design*des, NetScope*scope, - unsigned min, unsigned lval, bool&) const + unsigned min, unsigned lval, + ivl_variable_type_t&, bool&) const { if (debug_elaborate) { cerr << get_fileline() << ": debug: test_width defaults to " @@ -56,20 +111,38 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const } unsigned PEBinary::test_width(Design*des, NetScope*scope, - unsigned min, unsigned lval, bool&unsized_flag) const + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const { - bool flag_left = false; - bool flag_right = false; - unsigned wid_left = left_->test_width(des,scope, min, lval, flag_left); - unsigned wid_right = right_->test_width(des,scope, min, lval, flag_right); + ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE; + ivl_variable_type_t expr_type_right= IVL_VT_NO_TYPE; + + bool flag_left = unsized_flag; + unsigned wid_left = left_->test_width(des,scope, min, 0, expr_type_left, flag_left); + + bool flag_right = flag_left; + unsigned wid_right = right_->test_width(des,scope, min, 0, expr_type_right, flag_right); + + if (flag_right && !flag_left) { + flag_left = flag_right; + wid_left = left_->test_width(des, scope, min, 0, expr_type_right, flag_right); + } if (flag_left || flag_right) unsized_flag = true; + if (expr_type_left == IVL_VT_REAL || expr_type_right == IVL_VT_REAL) + expr_type = IVL_VT_REAL; + else if (expr_type_left==IVL_VT_LOGIC || expr_type_right==IVL_VT_LOGIC) + expr_type = IVL_VT_LOGIC; + else + expr_type = IVL_VT_BOOL; + switch (op_) { case '+': case '-': - if (unsized_flag) { + if (unsized_flag && type_is_vectorable(expr_type)) { wid_left += 1; wid_right += 1; } @@ -81,6 +154,16 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, min = lval; break; + case 'l': // << Should be handled by PEBShift + case '<': // < Should be handled by PEBComp + case '>': // > Should be handled by PEBComp + case 'e': // == Should be handled by PEBComp + case 'E': // === Should be handled by PEBComp + case 'L': // <= Should be handled by PEBComp + case 'G': // >= Should be handled by PEBComp + case 'n': // != Should be handled by PEBComp + case 'N': // !== Should be handled by PEBComp + ivl_assert(*this, 0); default: if (wid_left > min) min = wid_left; @@ -111,6 +194,24 @@ NetExpr* PEBinary::elaborate_expr(Design*des, NetScope*scope, return 0; } + // Handle the special case that one of the operands is a real + // value and the other is a vector type. In that case, + // re-elaborate the vectorable argument as self-determined + // lossless. + if (lp->expr_type()==IVL_VT_REAL + && type_is_vectorable(rp->expr_type()) + && expr_wid != -2) { + delete rp; + rp = right_->elaborate_expr(des, scope, -2, false); + } + + if (rp->expr_type()==IVL_VT_REAL + && type_is_vectorable(lp->expr_type()) + && expr_wid != -2) { + delete lp; + lp = left_->elaborate_expr(des, scope, -2, false); + } + NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid); return tmp; } @@ -148,8 +249,8 @@ NetExpr* PEBinary::elaborate_eval_expr_base_(Design*des, * the correct NetEBinary object and connect the parameters. */ NetExpr* PEBinary::elaborate_expr_base_(Design*des, - NetExpr*lp, NetExpr*rp, - int expr_wid) const + NetExpr*lp, NetExpr*rp, + int expr_wid) const { bool flag; @@ -180,83 +281,21 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, break; case '*': - tmp = new NetEBMult(op_, lp, rp); - tmp->set_line(*this); + tmp = elaborate_expr_base_mult_(des, lp, rp, expr_wid); break; case '%': - /* The % operator does not support real arguments in - baseline Verilog. But we allow it in our extended - form of Verilog. */ - if (! gn_icarus_misc_flag) { - if (lp->expr_type()==IVL_VT_REAL || - rp->expr_type()==IVL_VT_REAL) { - cerr << get_fileline() << ": error: Modulus operator " - "may not have REAL operands." << endl; - des->errors += 1; - } - } - /* Fall through to handle the % with the / operator. */ case '/': - tmp = new NetEBDiv(op_, lp, rp); - tmp->set_line(*this); + tmp = elaborate_expr_base_div_(des, lp, rp, expr_wid); break; case 'l': // << - if (NetEConst*lpc = dynamic_cast (lp)) { - if (NetEConst*rpc = dynamic_cast (rp)) { - // Handle the super-special case that both - // operands are constants. Precalculate the - // entire value here. - verinum lpval = lpc->value(); - unsigned shift = rpc->value().as_ulong(); - verinum result = lpc->value() << shift; - // If the l-value has explicit size, or - // there is a context determined size, use that. - if (lpval.has_len() || expr_wid > 0) { - int use_len = lpval.len(); - if (expr_wid < use_len) - use_len = expr_wid; - result = verinum(result, lpval.len()); - } - - tmp = new NetEConst(result); - if (debug_elaborate) - cerr << get_fileline() << ": debug: " - << "Precalculate " << *this - << " to constant " << *tmp << endl; - - } else { - // Handle the special case that the left - // operand is constant. If it is unsized, we - // may have to expand it to an integer width. - verinum lpval = lpc->value(); - if (lpval.len() < integer_width && !lpval.has_len()) { - lpval = verinum(lpval, integer_width); - lpc = new NetEConst(lpval); - lpc->set_line(*lp); - } - - tmp = new NetEBShift(op_, lpc, rp); - if (debug_elaborate) - cerr << get_fileline() << ": debug: " - << "Adjust " << *this - << " to this " << *tmp - << " to allow for integer widths." << endl; - } - - } else { - // Left side is not constant, so handle it the - // default way. - tmp = new NetEBShift(op_, lp, rp); - } - tmp->set_line(*this); + tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid); break; case 'r': // >> case 'R': // >>> - tmp = new NetEBShift(op_, lp, rp); - tmp->set_line(*this); + tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid); break; case '^': @@ -265,17 +304,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, case 'O': // NOR (~|) case 'A': // NAND (~&) case 'X': - tmp = new NetEBBits(op_, lp, rp); - tmp->set_line(*this); + tmp = elaborate_expr_base_bits_(des, lp, rp, expr_wid); break; case '+': case '-': - tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false); - if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL - || tmp->expr_type() == IVL_VT_LOGIC)) - tmp->set_width(expr_wid); - tmp->set_line(*this); + tmp = elaborate_expr_base_add_(des, lp, rp, expr_wid); break; case 'E': /* === */ @@ -323,8 +357,349 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, return tmp; } -unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const +NetExpr* PEBinary::elaborate_expr_base_bits_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const { + // If either of the arguments is unsigned, then process both + // of them as unsigned. This only impacts the padding that is + // done to get the operands to the expr_wid. + if (! lp->has_sign()) + rp->cast_signed(false); + if (! rp->has_sign()) + lp->cast_signed(false); + + if (expr_wid > 0) { + if (type_is_vectorable(lp->expr_type())) + lp = pad_to_width(lp, expr_wid); + if (type_is_vectorable(rp->expr_type())) + rp = pad_to_width(rp, expr_wid); + } + + NetEBBits*tmp = new NetEBBits(op_, lp, rp); + tmp->set_line(*this); + + return tmp; +} + +NetExpr* PEBinary::elaborate_expr_base_div_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + /* The % operator does not support real arguments in + baseline Verilog. But we allow it in our extended + form of Verilog. */ + if (op_ == '%' && ! gn_icarus_misc_flag) { + if (lp->expr_type()==IVL_VT_REAL || + rp->expr_type()==IVL_VT_REAL) { + cerr << get_fileline() << ": error: Modulus operator " + "may not have REAL operands." << endl; + des->errors += 1; + } + } + + NetEBDiv*tmp = new NetEBDiv(op_, lp, rp); + tmp->set_line(*this); + + return tmp; +} + +NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + NetExpr*tmp; + + long use_wid = lp->expr_width(); + if (expr_wid > 0) + use_wid = expr_wid; + + if (use_wid == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Oops, left expression width is not known, " + << "so expression width is not known. Punt." << endl; + tmp = new NetEBShift(op_, lp, rp); + tmp->set_line(*this); + return tmp; + } + + // If the left expression is constant, then there are some + // special cases we can work with. If the left expression is + // not constant, but the right expression is constant, then + // there are some other interesting cases. But if neither are + // constant, then there is the general case. + + if (NetEConst*lpc = dynamic_cast (lp)) { + if (NetEConst*rpc = dynamic_cast (rp)) { + // Handle the super-special case that both + // operands are constants. Precalculate the + // entire value here. + verinum lpval = lpc->value(); + unsigned shift = rpc->value().as_ulong(); + verinum result = lpc->value() << shift; + // If the l-value has explicit size, or + // there is a context determined size, use that. + if (lpval.has_len() || expr_wid > 0) { + int use_len = lpval.len(); + if (expr_wid > 0 && expr_wid > use_len) + use_len = expr_wid; + result = verinum(result, use_len); + } + + tmp = new NetEConst(result); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Precalculate " << *lpc << " << " << shift + << " to constant " << *tmp + << " (expr_wid=" << expr_wid << ")" << endl; + + } else { + // Handle the special case that the left + // operand is constant. If it is unsized, we + // may have to expand it to an integer width. + verinum lpval = lpc->value(); + if (lpval.len() < integer_width && !lpval.has_len()) { + lpval = verinum(lpval, integer_width); + lpc = new NetEConst(lpval); + lpc->set_line(*lp); + } + + tmp = new NetEBShift(op_, lpc, rp); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Adjust " << *this + << " to this " << *tmp + << " to allow for integer widths." << endl; + } + + } else if (NetEConst*rpc = dynamic_cast (rp)) { + long shift = rpc->value().as_long(); + long use_wid = lp->expr_width(); + if (expr_wid > 0) + use_wid = expr_wid; + + if (shift >= use_wid || (-shift) >= (long)lp->expr_width()) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Value left-shifted " << shift + << " beyond width of " << use_wid + << ". Elaborate as constant zero." << endl; + + tmp = make_const_0(use_wid); + + } else { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Left shift expression by constant " + << shift << " bits. (use_wid=" << use_wid << ")" << endl; + lp = pad_to_width(lp, use_wid); + tmp = new NetEBShift(op_, lp, rp); + } + + } else { + // Left side is not constant, so handle it the + // default way. + if (expr_wid >= 0) + lp = pad_to_width(lp, expr_wid); + tmp = new NetEBShift(op_, lp, rp); + } + + tmp->set_line(*this); + return tmp; +} + +NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + NetExpr*tmp; + + long use_wid = lp->expr_width(); + if (expr_wid > 0) + use_wid = expr_wid; + + if (use_wid == 0) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Oops, left expression width is not known, " + << "so expression width is not known. Punt." << endl; + tmp = new NetEBShift(op_, lp, rp); + tmp->set_line(*this); + return tmp; + } + + if (NetEConst*rpc = dynamic_cast (rp)) { + long shift = rpc->value().as_long(); + + // Detect the special cases that the shifted + // unsigned expression is completely shifted away to + // zero. + if ((op_=='r' || (lp->has_sign()==false)) + && shift >= (long)lp->expr_width()) { + // Special case that the value is unsigned + // shifted completely away. + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Value right-shifted " << shift + << " beyond width of " << lp->expr_width() + << ". Elaborate as constant zero." << endl; + + tmp = make_const_0(use_wid); + tmp->set_line(*this); + return tmp; + + } + + if (shift >= (long)lp->expr_width()) { + // Signed right shift. + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Value signed-right-shifted " << shift + << " beyond width of " << lp->expr_width() + << ". Elaborate as replicated top bit." << endl; + + ivl_assert(*this, lp->expr_width() > 0); + ivl_assert(*this, use_wid > 0); + + tmp = new NetEConst(verinum(lp->expr_width()-1)); + tmp->set_line(*this); + tmp = new NetESelect(lp, tmp, 1); + tmp->cast_signed(true); + tmp->set_line(*this); + tmp = pad_to_width(tmp, use_wid); + tmp->set_line(*this); + return tmp; + + } else if (shift >= 0) { + // Signed right shift. + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Value signed-right-shifted " << shift + << " beyond width of " << lp->expr_width() + << "." << endl; + + tmp = new NetEConst(verinum(shift)); + tmp->set_line(*this); + long tmp_wid = lp->expr_width() - shift; + if (tmp_wid > use_wid) + tmp_wid = use_wid; + + ivl_assert(*this, tmp_wid > 0); + ivl_assert(*this, use_wid > 0); + + tmp = new NetESelect(lp, tmp, tmp_wid); + tmp->set_line(*this); + tmp->cast_signed(lp->has_sign() && op_=='R'); + tmp = pad_to_width(tmp, use_wid); + tmp->set_line(*this); + return tmp; + + } else if ((0-shift) >= use_wid) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Value signed-right-shifted " << shift + << " beyond width of " << use_wid + << "." << endl; + + tmp = make_const_0(use_wid); + tmp->set_line(*this); + return tmp; + } + } + + // Falback, handle the general case. + if (expr_wid > 0) + lp = pad_to_width(lp, expr_wid); + tmp = new NetEBShift(op_, lp, rp); + tmp->set_line(*this); + return tmp; +} + +NetExpr* PEBinary::elaborate_expr_base_mult_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + // First, Make sure that signed arguments are padded to the + // width of the output. This is necessary for 2s complement + // multiplication to come out right. + if (expr_wid > 0) { + if (lp->has_sign() && lp->expr_type() != IVL_VT_REAL) + lp = pad_to_width(lp, expr_wid); + if (rp->has_sign() && rp->expr_type() != IVL_VT_REAL) + rp = pad_to_width(rp, expr_wid); + } + + // Keep constants on the right side. + if (dynamic_cast(lp)) { + NetExpr*tmp = lp; + lp = rp; + rp = tmp; + } + + // Handle a few special case multiplies against constants. + if (NetEConst*rp_const = dynamic_cast (rp)) { + verinum rp_val = rp_const->value(); + + int use_wid = expr_wid; + if (use_wid < 0) + use_wid = max(rp->expr_width(), lp->expr_width()); + + if (! rp_val.is_defined()) { + NetEConst*tmp = make_const_x(use_wid); + return tmp; + } + + if (rp_val.is_zero()) { + NetEConst*tmp = make_const_0(use_wid); + return tmp; + } + } + + // Multiply will guess a width that is the sum of the + // widths of the operand. If that sum is too small, then + // pad one of the arguments enough that the sum is the + // desired width. + if (expr_wid > (long)(lp->expr_width() + rp->expr_width())) + lp = pad_to_width(lp, expr_wid - rp->expr_width()); + + NetEBMult*tmp = new NetEBMult(op_, lp, rp); + tmp->set_line(*this); + + if (expr_wid > 0) + tmp->set_width(expr_wid, false); + + return tmp; +} + +NetExpr* PEBinary::elaborate_expr_base_add_(Design*des, + NetExpr*lp, NetExpr*rp, + int expr_wid) const +{ + NetExpr*tmp; + bool use_lossless_flag = expr_wid == -2; + + // If this expression is not vectorable, then do NOT pass the + // lossless flag to the NetEBAdd constructor. For non- + // vectorable, lossless is implicit. + if (! type_is_vectorable(lp->expr_type())) + use_lossless_flag = false; + if (! type_is_vectorable(rp->expr_type())) + use_lossless_flag = false; + + tmp = new NetEBAdd(op_, lp, rp, use_lossless_flag); + if (expr_wid > 0 && type_is_vectorable(tmp->expr_type())) + tmp->set_width(expr_wid); + + tmp->set_line(*this); + return tmp; +} + +unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, + ivl_variable_type_t&expr_type, + bool&) const +{ + expr_type = IVL_VT_LOGIC; return 1; } @@ -335,12 +710,14 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, assert(right_); bool unsized_flag = false; - unsigned left_width = left_->test_width(des, scope, 0, 0, unsized_flag); + ivl_variable_type_t left_type = IVL_VT_NO_TYPE; + unsigned left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag); bool save_flag = unsized_flag; - unsigned right_width = right_->test_width(des, scope, 0, 0, unsized_flag); + ivl_variable_type_t right_type = IVL_VT_NO_TYPE; + unsigned right_width = right_->test_width(des, scope, 0, 0, right_type, unsized_flag); if (save_flag != unsized_flag) - left_width = left_->test_width(des, scope, 0, 0, unsized_flag); + left_width = left_->test_width(des, scope, 0, 0, left_type, unsized_flag); /* Width of operands is self-determined. */ int use_wid = left_width; @@ -369,18 +746,54 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, } unsigned PEBShift::test_width(Design*des, NetScope*scope, - unsigned min, unsigned lval, bool&unsized_flag) const + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const { - unsigned wid_left = left_->test_width(des,scope,min, 0, unsized_flag); + unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type, unsized_flag); // The right expression is self-determined and has no impact // on the expression size that is generated. + if (wid_left < min) + wid_left = min; + if (wid_left < lval) + wid_left = lval; + + if (unsized_flag && wid_left < integer_width) { + wid_left = integer_width; + + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Test width of unsized left shift" + << " is padded to compiler integer width=" << wid_left + << endl; + } + return wid_left; } +NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, + int expr_wid, bool sys_task_arg) const +{ + assert(left_); + assert(right_); + + NetExpr*lp = left_->elaborate_expr(des, scope, expr_wid, false); + NetExpr*rp = right_->elaborate_expr(des, scope, -1, false); + if ((lp == 0) || (rp == 0)) { + delete lp; + delete rp; + return 0; + } + + NetExpr*tmp = elaborate_eval_expr_base_(des, lp, rp, expr_wid); + return tmp; +} + unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const { perm_string name = peek_tail_name(path_); @@ -389,7 +802,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, PExpr*expr = parms_[0]; if (expr == 0) return 0; - unsigned wid = expr->test_width(des, scope, min, lval, unsized_flag); + unsigned wid = expr->test_width(des, scope, min, lval, expr_type, unsized_flag); if (debug_elaborate) cerr << get_fileline() << ": debug: test_width" << " of $signed/$unsigned returns test_width" @@ -397,20 +810,54 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, return wid; } + if (name=="$sizeof" || name=="$bits") { + if (debug_elaborate) + cerr << get_fileline() << ": debug: test_width" + << " of $sizeof/$bits returns test_width" + << " of compiler integer." << endl; + + expr_type = IVL_VT_BOOL; + return integer_width; + } + + if (name=="$is_signed") { + if (debug_elaborate) + cerr << get_fileline() << ": debug: test_width" + << " of $is_signed returns test_width" + << " of 1." << endl; + + expr_type = IVL_VT_BOOL; + return 1; + } + + /* Get the return type of the system function by looking it up + in the sfunc_table. */ + const struct sfunc_return_type*sfunc_info + = lookup_sys_func(peek_tail_name(path_)); + + expr_type = sfunc_info->type; + unsigned wid = sfunc_info->wid; + if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "of system function " << name - << " returns 32 always?" << endl; - return 32; + << " returns wid=" << wid + << ", type=" << expr_type << "." << endl; + + return wid; } unsigned PECallFunction::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const { if (peek_tail_name(path_)[0] == '$') - return test_width_sfunc_(des, scope, min, lval, unsized_flag); + return test_width_sfunc_(des, scope, min, lval, expr_type, unsized_flag); + // The width of user defined functions depends only on the + // width of the return value. The arguments are entirely + // self-determined. NetFuncDef*def = des->find_function(scope, path_); if (def == 0) { if (debug_elaborate) @@ -424,10 +871,16 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, assert(dscope); if (NetNet*res = dscope->find_signal(dscope->basename())) { + expr_type = res->data_type(); if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "of function returns width " << res->vector_width() + << ", type=" << expr_type << "." << endl; + + if (! type_is_vectorable(expr_type)) + unsized_flag = true; + return res->vector_width(); } @@ -695,13 +1148,15 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, for (unsigned idx = 0 ; idx < parms.count() ; idx += 1) { PExpr*tmp = parms_[idx]; if (tmp) { - int argwid = def->port(idx)->vector_width(); - parms[idx] = elab_and_eval(des, scope, tmp, argwid); + parms[idx] = elaborate_rval_expr(des, scope, + def->port(idx)->data_type(), + def->port(idx)->vector_width(), + tmp); if (debug_elaborate) cerr << get_fileline() << ": debug:" << " function " << path_ << " arg " << (idx+1) - << " argwid=" << argwid + << " argwid=" << parms[idx]->expr_width() << ": " << *parms[idx] << endl; } else { @@ -847,6 +1302,23 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, return tmp; } +/* + * Floating point literals are not vectorable. It's not particularly + * clear what to do about an actual width to return, but whatever the + * width, it is unsigned. + * + * Absent any better idea, we call all real valued results a width of 1. + */ +unsigned PEFNumber::test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const +{ + expr_type = IVL_VT_REAL; + unsized_flag = true; + return 1; +} + NetExpr* PEFNumber::elaborate_expr(Design*des, NetScope*scope, int, bool) const { NetECReal*tmp = new NetECReal(*value_); @@ -985,6 +1457,7 @@ bool PEIdent::calculate_param_range_(Design*des, NetScope*scope, unsigned PEIdent::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const { NetNet* net = 0; @@ -995,36 +1468,73 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, symbol_search(des, scope, path_, net, par, eve, ex1, ex2); - if (net != 0) { - 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 there is a part/bit select expression, then process it + // here. This constrains the results no matter what kind the + // name is. - unsigned use_width = net->vector_width(); - switch (use_sel) { - case index_component_t::SEL_NONE: - break; - case index_component_t::SEL_PART: - { long msb, lsb; - calculate_parts_(des, scope, msb, lsb); - use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb)); - break; - } - case index_component_t::SEL_IDX_UP: - case index_component_t::SEL_IDX_DO: - { unsigned long tmp = 0; - calculate_up_do_width_(des, scope, tmp); - use_width = tmp; - break; - } - case index_component_t::SEL_BIT: - use_width = 1; - break; - default: - ivl_assert(*this, 0); + 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; + + unsigned use_width = UINT_MAX; + switch (use_sel) { + case index_component_t::SEL_NONE: + break; + case index_component_t::SEL_PART: + { long msb, lsb; + calculate_parts_(des, scope, msb, lsb); + use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb)); + break; + } + case index_component_t::SEL_IDX_UP: + case index_component_t::SEL_IDX_DO: + { unsigned long tmp = 0; + calculate_up_do_width_(des, scope, tmp); + use_width = tmp; + break; + } + case index_component_t::SEL_BIT: + use_width = 1; + break; + default: + ivl_assert(*this, 0); + } + + if (use_width != UINT_MAX) + return max(use_width, min); + + // The width of a signal expression is the width of the signal. + if (net != 0) { + expr_type = net->data_type(); + return max(net->vector_width(), (unsigned long)min); + } + + // The width of a parameter name is the width of the range for + // the parameter name, if a range is declared. Otherwise, the + // width is undefined. + if (par != 0) { + expr_type = par->expr_type(); + if (ex1) { + ivl_assert(*this, ex2); + const NetEConst*ex1_const = dynamic_cast (ex1); + const NetEConst*ex2_const = dynamic_cast (ex2); + ivl_assert(*this, ex1_const && ex2_const); + + long msb = ex1_const->value().as_long(); + long lsb = ex2_const->value().as_long(); + if (msb >= lsb) + return msb - lsb + 1; + else + return lsb - msb + 1; } - return use_width; + + // This is a parameter. If it is sized (meaning it was + // declared with range expresions) then the range + // expressions would have been caught above. So if we + // got there there we know this is an unsized constant. + unsized_flag = true; + return par->expr_width(); } return min; @@ -1059,7 +1569,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // If the identifier name is a parameter name, then return // a reference to the parameter expression. if (par != 0) - return elaborate_expr_param(des, scope, par, found_in, ex1, ex2); + return elaborate_expr_param_(des, scope, par, found_in, ex1, ex2, expr_wid); // If the identifier names a signal (a register or wire) @@ -1123,6 +1633,22 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, } } + if (error_implicit==false + && sys_task_arg==false + && path_.size()==1 + && scope->default_nettype() != NetNet::NONE) { + NetNet::Type nettype = scope->default_nettype(); + net = new NetNet(scope, peek_tail_name(path_), nettype, 1); + net->data_type(IVL_VT_LOGIC); + net->set_line(*this); + if (warn_implicit) { + cerr << get_fileline() << ": warning: implicit " + "definition of wire " << scope_path(scope) + << "." << peek_tail_name(path_) << "." << endl; + } + return elaborate_expr_net(des, scope, net, scope, sys_task_arg); + } + // At this point we've exhausted all the possibilities that // are not scopes. If this is not a system task argument, then // it cannot be a scope name, so give up. @@ -1325,12 +1851,13 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, * parameter expression has already been located for us (as the par * argument) so we just need to process the sub-expression. */ -NetExpr* PEIdent::elaborate_expr_param(Design*des, - NetScope*scope, - const NetExpr*par, - NetScope*found_in, - const NetExpr*par_msb, - const NetExpr*par_lsb) const +NetExpr* PEIdent::elaborate_expr_param_(Design*des, + NetScope*scope, + const NetExpr*par, + NetScope*found_in, + const NetExpr*par_msb, + const NetExpr*par_lsb, + int expr_wid) const { const name_component_t&name_tail = path_.back(); index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; @@ -1486,6 +2013,9 @@ NetExpr* PEIdent::elaborate_expr_param(Design*des, NetEConstParam*ptmp = new NetEConstParam(found_in, name, ctmp->value()); + if (expr_wid > 0) + ptmp->set_width((unsigned)expr_wid); + if (debug_elaborate) cerr << get_fileline() << ": debug: " << "Elaborate parameter <" << name @@ -1860,8 +2390,11 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, } unsigned PENumber::test_width(Design*, NetScope*, - unsigned min, unsigned lval, bool&unsized_flag) const + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const { + expr_type = IVL_VT_LOGIC; unsigned use_wid = value_->len(); if (min > use_wid) use_wid = min; @@ -1869,6 +2402,9 @@ unsigned PENumber::test_width(Design*, NetScope*, if (! value_->has_len()) unsized_flag = true; + if (lval > 0 && lval < use_wid) + use_wid = lval; + return use_wid; } @@ -1884,6 +2420,11 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, // the self-determined size. if (expr_width > 0) { tvalue = pad_to_width(tvalue, expr_width); + if (tvalue.len() > (unsigned)expr_width) { + verinum tmp (tvalue, expr_width); + tmp.has_sign(tvalue.has_sign()); + tvalue = tmp; + } } NetEConst*tmp = new NetEConst(tvalue); @@ -1893,8 +2434,10 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, unsigned PEString::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&unsized_flag) const { + expr_type = IVL_VT_BOOL; unsigned use_wid = text_? 8*strlen(text_) : 0; if (min > use_wid) use_wid = min; @@ -1912,15 +2455,39 @@ NetEConst* PEString::elaborate_expr(Design*des, NetScope*, unsigned PETernary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, bool&flag) const { - unsigned tru_wid = tru_->test_width(des, scope, min, lval, flag); - unsigned fal_wid = fal_->test_width(des, scope, min, lval, flag); + ivl_variable_type_t tru_type = IVL_VT_NO_TYPE; + unsigned tru_wid = tru_->test_width(des, scope, min, lval, tru_type,flag); + + bool initial_flag = flag; + ivl_variable_type_t fal_type = IVL_VT_NO_TYPE; + unsigned fal_wid = fal_->test_width(des, scope, min, lval, fal_type,flag); + + // If the false clause is unsized, then try again with the + // true clause, because it might choose a different width if + // it is in an unsized context. + if (initial_flag == false && flag == true) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "False clause is unsized, so retest width of true clause." + << endl; + tru_wid = tru_->test_width(des, scope, max(min,fal_wid), lval, tru_type, flag); + } + + if (tru_type == IVL_VT_REAL || fal_type == IVL_VT_REAL) + expr_type = IVL_VT_REAL; + else if (tru_type == IVL_VT_LOGIC || fal_type == IVL_VT_LOGIC) + expr_type = IVL_VT_LOGIC; + else + expr_type = tru_type; + return max(tru_wid,fal_wid); } -static bool test_ternary_operand_compat(ivl_variable_type_t l, - ivl_variable_type_t r) +bool NetETernary::test_operand_compat(ivl_variable_type_t l, + ivl_variable_type_t r) { if (l == IVL_VT_LOGIC && r == IVL_VT_BOOL) return true; @@ -1943,43 +2510,86 @@ static bool test_ternary_operand_compat(ivl_variable_type_t l, * parsed so I can presume that they exist, and call elaboration * methods. If any elaboration fails, then give up and return 0. */ -NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, +NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { assert(expr_); assert(tru_); assert(fal_); + int use_wid = expr_wid >= 0? expr_wid : 0; + if (expr_wid < 0) { - bool flag = false; - unsigned tru_wid = tru_->test_width(des, scope, 0, 0, flag); - unsigned fal_wid = fal_->test_width(des, scope, 0, 0, flag); - expr_wid = max(tru_wid, fal_wid); + bool flag = expr_wid == -2; + ivl_variable_type_t expr_type = IVL_VT_NO_TYPE; + use_wid = this->test_width(des, scope, 0, 0, expr_type, flag); if (debug_elaborate) cerr << get_fileline() << ": debug: " - << "Self-sized ternary chooses wid="<< expr_wid - << " from " < 0); + NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid); + return pad_to_width(tru, use_wid); + } + + // Condition is constant FALSE, so we only need the + // false clause. + if (cval.get(0) == verinum::V0) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: Short-circuit " + "elaborate FALSE clause of ternary." + << endl; + ivl_assert(*this, use_wid > 0); + NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid); + return pad_to_width(fal, use_wid); + } + + // X and Z conditions need to blend both results, so we + // can't short-circuit. + } + + NetExpr*tru = elab_and_eval(des, scope, tru_, use_wid); if (tru == 0) { delete con; return 0; } - NetExpr*fal = fal_->elaborate_expr(des, scope, expr_wid, false); + NetExpr*fal = elab_and_eval(des, scope, fal_, use_wid); if (fal == 0) { delete con; delete tru; return 0; } - if (! test_ternary_operand_compat(tru->expr_type(), fal->expr_type())) { + if (! NetETernary::test_operand_compat(tru->expr_type(), fal->expr_type())) { cerr << get_fileline() << ": error: Data types " << tru->expr_type() << " and " << fal->expr_type() << " of ternary" @@ -1990,14 +2600,48 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, /* Whatever the width we choose for the ternary operator, we need to make sure the operands match. */ - tru = pad_to_width(tru, expr_wid); - fal = pad_to_width(fal, expr_wid); + tru = pad_to_width(tru, use_wid); + fal = pad_to_width(fal, use_wid); NetETernary*res = new NetETernary(con, tru, fal); res->set_line(*this); return res; } +unsigned PEUnary::test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag) const +{ + switch (op_) { + case '!': + case '&': + case '|': // Reduction OR + case '^': // Reduction XOR + case 'A': // Reduction NAND (~&) + case 'N': // Reduction NOR (~|) + case 'X': // Reduction NXOR (~^) + expr_type = IVL_VT_LOGIC; + return 1; + } + + unsigned test_wid = expr_->test_width(des, scope, min, lval, expr_type, unsized_flag); + switch (op_) { + // For these operators, the act of padding to the + // minimum width can have an important impact on the + // calculation. So don't let the tested width be less + // then the tested width. + case '-': + case '+': + if (test_wid < min) + test_wid = min; + break; + } + + return test_wid; +} + + NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { @@ -2033,8 +2677,20 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, val = pad_to_width(val, expr_wid); /* When taking the - of a number, extend it one - bit to accommodate a possible sign bit. */ - verinum zero (verinum::V0, val.len()+1, val.has_len()); + bit to accommodate a possible sign bit. + + NOTE: This may not be correct! The test_width + is supposed to detect the special case that we + want to do lossless self-determined + expressions, and the function that calls + elaborate_expr should account for that in the + expr_wid argument. */ + unsigned use_len = val.len(); + if (expr_wid < 0) + use_len += 1; + + /* Calculate unary minus as 0-val */ + verinum zero (verinum::V0, use_len, val.has_len()); zero.has_sign(val.has_sign()); verinum nval = zero - val; @@ -2055,6 +2711,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, delete ip; } else { + if (expr_wid > 0) + ip = pad_to_width(ip, expr_wid); tmp = new NetEUnary(op_, ip); tmp->set_line(*this); } diff --git a/elab_net.cc b/elab_net.cc index 23dd1e1f7..a51dd059c 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -29,2310 +29,6 @@ # include # include "ivl_assert.h" -/* - * This is a state flag that determines whether an elaborate_net must - * report an error when it encounters an unsized number. Normally, it - * is fine to make an unsized number as small as it can be, but there - * are a few cases where the size must be fully self-determined. For - * example, within a {...} (concatenation) operator. - */ -static bool must_be_self_determined_flag = false; - -NetNet* PExpr::elaborate_net(Design*des, NetScope*scope, unsigned, - const NetExpr*, - const NetExpr*, - const NetExpr*, - Link::strength_t, - Link::strength_t) const -{ - cerr << get_fileline() << ": error: Unable to elaborate `" - << *this << "' as gates." << endl; - return 0; -} - -/* - * Elaborating binary operations generally involves elaborating the - * left and right expressions, then making an output wire and - * connecting the lot together with the right kind of gate. - */ -NetNet* PEBinary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - switch (op_) { - case '*': - return elaborate_net_mul_(des, scope, width, rise, fall, decay); - case '%': - return elaborate_net_mod_(des, scope, width, rise, fall, decay); - case '/': - return elaborate_net_div_(des, scope, width, rise, fall, decay); - case 'p': // ** - return elaborate_net_pow_(des, scope, width, rise, fall, decay); - case '+': - case '-': - return elaborate_net_add_(des, scope, width, rise, fall, decay); - case '|': // Bitwise OR - case '&': - case '^': - case 'A': // Bitwise NAND (~&) - case 'O': // Bitwise NOR (~|) - case 'X': // Exclusive NOR - return elaborate_net_bit_(des, scope, width, rise, fall, decay); - case 'E': // === (case equals) - case 'e': // == - case 'N': // !== (case not-equals) - case 'n': // != - case '<': - case '>': - case 'L': // <= - case 'G': // >= - return elaborate_net_cmp_(des, scope, width, rise, fall, decay); - case 'a': // && (logical and) - case 'o': // || (logical or) - return elaborate_net_log_(des, scope, width, rise, fall, decay); - case 'l': // << - case 'r': // >> - case 'R': // >>> - return elaborate_net_shift_(des, scope, width, rise, fall, decay); - } - - /* This is an undefined operator, but we may as well check the - arguments since we are here. */ - NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0); - if (lsig == 0) { - cerr << get_fileline() << ": error: Cannot elaborate "; - left_->dump(cerr); - cerr << endl; - } - if (rsig == 0) { - cerr << get_fileline() << ": error: Cannot elaborate "; - right_->dump(cerr); - cerr << endl; - } - - /* We can only get here with an undefined operator. */ - cerr << get_fileline() << ": internal error: unsupported" - " combinational operator (" << op_ << ")." << endl; - des->errors += 1; - - return 0; -} - -/* - * Elaborate the structural +/- as an AddSub object. Connect DataA and - * DataB to the parameters, and connect the output signal to the - * Result. In this context, the device is a combinational adder with - * fixed direction, so leave Add_Sub unconnected and set the - * LPM_Direction property. - */ -NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - NetNet*osig; - - unsigned width = lsig->vector_width(); - if (rsig->vector_width() > lsig->vector_width()) - width = rsig->vector_width(); - - - /* The owidth is the output width of the lpm_add_sub - device. If the desired width is greater than the width of - the operands, then widen the adder and let code below pad - the operands. */ - unsigned owidth = width; - switch (op_) { - case '+': - if (lwidth > owidth) { - owidth = lwidth; - width = lwidth; - } - break; - case '-': - if (lwidth > owidth) { - owidth = lwidth; - width = lwidth; - } - break; - default: - assert(0); - } - - bool expr_signed = lsig->get_signed() && rsig->get_signed(); - - // Pad out the operands, if necessary, the match the width of - // the adder device. - if (lsig->vector_width() < width) { - if (expr_signed) - lsig = pad_to_width_signed(des, lsig, width); - else - lsig = pad_to_width(des, lsig, width); - } - - if (rsig->vector_width() < width) { - if (expr_signed) - rsig = pad_to_width_signed(des, rsig, width); - else - rsig = pad_to_width(des, rsig, width); - } - - // Check that the argument types match. - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of add/sub " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // Make the adder as wide as the widest operand - osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - osig->data_type(lsig->data_type()); - osig->set_signed(expr_signed); - osig->local_flag(true); - osig->set_line(*this); - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate NetAddSub " - << "width=" << width << " lwidth=" << lwidth - << endl; - } - NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), width); - - // Connect the adder to the various parts. - connect(lsig->pin(0), adder->pin_DataA()); - connect(rsig->pin(0), adder->pin_DataB()); - connect(osig->pin(0), adder->pin_Result()); -#ifdef XXXX - if (owidth > width) - connect(osig->pin(width), adder->pin_Cout()); -#endif - NetNode*gate = adder; - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - gate->attribute(perm_string::literal("LPM_Direction"), - verinum(op_ == '+' ? "ADD" : "SUB")); - - return osig; -} - -/* - * Elaborate various bitwise logic operators. These are all similar in - * that they take operants of equal width, and each bit does not - * affect any other bits. Also common about all this is how bit widths - * of the operands are handled, when they do not match. - */ -NetNet* PEBinary::elaborate_net_bit_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - if (lsig->vector_width() < rsig->vector_width()) - lsig = pad_to_width(des, lsig, rsig->vector_width()); - if (rsig->vector_width() < lsig->vector_width()) - rsig = pad_to_width(des, rsig, lsig->vector_width()); - - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Types of " - << "operands of " << op_ << " do not match: " - << lsig->data_type() << " vs. " << rsig->data_type() - << endl; - des->errors += 1; - return 0; - } - - /* The types match here and real is not supported. */ - if (lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: " << human_readable_op(op_) - << " operator may not have REAL operands." << endl; - des->errors += 1; - return 0; - } - - if (lsig->vector_width() != rsig->vector_width()) { - cerr << get_fileline() << ": internal error: lsig width (" - << lsig->vector_width() << ") != rsig pin width (" - << rsig->vector_width() << ")." << endl; - des->errors += 1; - return 0; - } - - assert(lsig->vector_width() == rsig->vector_width()); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, - lsig->vector_width()); - osig->local_flag(true); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - - NetLogic::TYPE gtype=NetLogic::AND; - switch (op_) { - case '^': gtype = NetLogic::XOR; break; // XOR - case 'X': gtype = NetLogic::XNOR; break; // XNOR - case '&': gtype = NetLogic::AND; break; // AND - case 'A': gtype = NetLogic::NAND; break; // NAND (~&) - case '|': gtype = NetLogic::OR; break; // Bitwise OR - case 'O': gtype = NetLogic::NOR; break; // Bitwise NOR - default: assert(0); - } - - NetLogic*gate = new NetLogic(scope, scope->local_symbol(), - 3, gtype, osig->vector_width()); - gate->set_line(*this); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - return osig; -} - -/* - * This function attempts to handle the special case of == or != - * compare to a constant value. The caller has determined already that - * one of the operands is a NetEConst, and has already elaborated the - * other. - */ -static NetNet* compare_eq_constant(Design*des, NetScope*scope, - NetNet*lsig, NetEConst*rexp, - char op_code, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) -{ - if (op_code != 'e' && op_code != 'n') - return 0; - - verinum val = rexp->value(); - - /* Abandon special case if there are x or z bits in the - constant. We can't get the right behavior out of - OR/NOR in this case. */ - if (! val.is_defined()) - return 0; - - if (val.len() < lsig->vector_width()) - val = verinum(val, lsig->vector_width()); - - /* Look for the very special case that we know the compare - results a priori due to different high bits, that are - constant pad in the signal. */ - if (val.len() > lsig->vector_width()) { - unsigned idx = lsig->vector_width(); - verinum::V lpad = verinum::V0; - - while (idx < val.len()) { - if (val.get(idx) != lpad) { - verinum oval (op_code == 'e' - ? verinum::V0 - : verinum::V1, - 1); - NetEConst*ogate = new NetEConst(oval); - NetNet*osig = ogate->synthesize(des); - osig->data_type(lsig->data_type()); - osig->set_line(*lsig); - osig->rise_time(rise); - osig->fall_time(fall); - osig->decay_time(decay); - delete ogate; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Equality replaced with " - << oval << " due to high pad mismatch" - << endl; - - return osig; - } - - idx +=1; - } - } - - unsigned zeros = 0; - unsigned ones = 0; - for (unsigned idx = 0 ; idx < lsig->vector_width() ; idx += 1) { - if (val.get(idx) == verinum::V0) - zeros += 1; - if (val.get(idx) == verinum::V1) - ones += 1; - } - - /* Handle the special case that the gate is a compare that can - be replaces with a reduction AND or NOR. */ - - if (ones == 0 || zeros == 0) { - NetUReduce::TYPE type; - - if (zeros > 0) { - type = op_code == 'e'? NetUReduce::NOR : NetUReduce::OR; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Replace net==" << val << " equality with " - << zeros << "-input reduction [N]OR gate." << endl; - - } else { - type = op_code == 'e'? NetUReduce::AND : NetUReduce::NAND; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Replace net==" << val << " equality with " - << ones << "-input reduction AND gate." << endl; - } - - NetUReduce*red = new NetUReduce(scope, scope->local_symbol(), - type, zeros+ones); - des->add_node(red); - red->set_line(*lsig); - red->rise_time(rise); - red->fall_time(fall); - red->decay_time(decay); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 0, 0); - tmp->data_type(lsig->data_type()); - tmp->local_flag(true); - tmp->set_line(*lsig); - - connect(red->pin(1), lsig->pin(0)); - connect(red->pin(0), tmp->pin(0)); - return tmp; - } - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Give up trying to replace net==" << val - << " equality with " - << ones << "-input AND and " - << zeros << "-input NOR gates." << endl; - - return 0; -} - -/* - * Elaborate the various binary comparison operators. The comparison - * operators return a single bit result, no matter what, so the left - * and right values can have their own size. The only restriction is - * that they have the same size. - */ -NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - /* Elaborate the operands of the compare first as expressions - (so that the eval_tree method can reduce constant - expressions, including parameters) then turn those results - into synthesized nets. */ - NetExpr*lexp = elab_and_eval(des, scope, left_, -1), - *rexp = elab_and_eval(des, scope, right_, -1); - - if (lexp == 0 || rexp == 0) return 0; - - bool real_arg = true; - if (lexp->expr_type() != IVL_VT_REAL && - rexp->expr_type() != IVL_VT_REAL) { - /* Choose the operand width to be the width of the widest - self-determined operand. */ - unsigned operand_width = lexp->expr_width(); - if (rexp->expr_width() > operand_width) - operand_width = rexp->expr_width(); - - lexp->set_width(operand_width); - lexp = pad_to_width(lexp, operand_width); - rexp->set_width(operand_width); - rexp = pad_to_width(rexp, operand_width); - - real_arg = false; - } - - NetNet*lsig = 0; - NetNet*rsig = 0; - - /* Handle the special case that the right or left - sub-expression is a constant value. The compare_eq_constant - function will return an elaborated result if it can make - use of the situation, or 0 if it cannot. */ - if (NetEConst*tmp = dynamic_cast(rexp)) { - - lsig = lexp->synthesize(des); - if (lsig == 0) return 0; - delete lexp; - lexp = 0; - - if (real_arg) { - verireal vrl(tmp->value().as_double()); - NetECReal rlval(vrl); - rsig = rlval.synthesize(des); - delete rexp; - rexp = 0; - } else { - NetNet*osig = compare_eq_constant(des, scope, - lsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete rexp; - return osig; - } - } - } - - if (NetEConst*tmp = dynamic_cast(lexp)) { - - rsig = rexp->synthesize(des); - if (rsig == 0) return 0; - delete rexp; - rexp = 0; - - if (real_arg) { - verireal vrl(tmp->value().as_double()); - NetECReal rlval(vrl); - lsig = rlval.synthesize(des); - delete lexp; - lexp = 0; - } else { - NetNet*osig = compare_eq_constant(des, scope, - rsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete lexp; - return osig; - } - } - } - - if (lsig == 0) { - lsig = lexp->synthesize(des); - if (lsig == 0) return 0; - delete lexp; - } - - if (rsig == 0) { - rsig = rexp->synthesize(des); - if (rsig == 0) return 0; - delete rexp; - } - - unsigned dwidth = lsig->vector_width(); - if (rsig->vector_width() > dwidth) dwidth = rsig->vector_width(); - - /* Operands of binary compare need to be padded to equal - size. Figure the pad bit needed to extend the narrowest - vector. */ - if (!real_arg && lsig->vector_width() < dwidth) - lsig = pad_to_width(des, lsig, dwidth); - if (!real_arg && rsig->vector_width() < dwidth) - rsig = pad_to_width(des, rsig, dwidth); - - /* For now the runtime cannot convert a vec4 to a real value. */ - if (real_arg && (rsig->data_type() != IVL_VT_REAL || - lsig->data_type() != IVL_VT_REAL)) { - cerr << get_fileline() << ": sorry: comparing bit based signals " - "and real values is not supported." << endl; - des->errors += 1; - return 0; - } - - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); - osig->data_type(IVL_VT_LOGIC); - osig->set_line(*this); - osig->local_flag(true); - - NetNode*gate; - - switch (op_) { - case '<': - case '>': - case 'L': - case 'G': { - NetCompare*cmp = new - NetCompare(scope, scope->local_symbol(), dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - - switch (op_) { - case '<': - connect(cmp->pin_ALB(), osig->pin(0)); - break; - case '>': - connect(cmp->pin_AGB(), osig->pin(0)); - break; - case 'L': - connect(cmp->pin_ALEB(), osig->pin(0)); - break; - case 'G': - connect(cmp->pin_AGEB(), osig->pin(0)); - break; - } - /* If both operands are signed, then do a signed - compare. */ - if (lsig->get_signed() && rsig->get_signed()) - cmp->set_signed(true); - - gate = cmp; - break; - } - - case 'E': // Case equals (===) - if (real_arg) { - cerr << get_fileline() << ": error: Case equality may not " - "have real operands." << endl; - des->errors += 1; - return 0; - } - gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, true); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - - case 'N': // Case equals (!==) - if (real_arg) { - cerr << get_fileline() << ": error: Case inequality may not " - "have real operands." << endl; - des->errors += 1; - return 0; - } - gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, false); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - - case 'e': // == - - /* Handle the special case of single bit compare with a - single XNOR gate. This is easy and direct. */ - if (dwidth == 1 && !real_arg){ - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::XNOR, 1); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - } - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate net == gate." - << endl; - } - - /* Oh well, do the general case with a NetCompare. */ - { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(), - dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - connect(cmp->pin_AEB(), osig->pin(0)); - gate = cmp; - } - break; - - case 'n': // != - - /* Handle the special case of single bit compare with a - single XOR gate. This is easy and direct. */ - if (dwidth == 1 && lsig->data_type() != IVL_VT_REAL && - rsig->data_type() != IVL_VT_REAL) { - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::XOR, 1); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - } - - /* Oh well, do the general case with a NetCompare. */ - { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(), - dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - connect(cmp->pin_ANEB(), osig->pin(0)); - gate = cmp; - } - break; - - default: - assert(0); - } - - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - return osig; -} - -/* - * Elaborate a divider gate. This function create a NetDivide gate - * which has exactly the right sized DataA, DataB and Result ports. If - * the l-value is wider then the result, then pad. - */ -NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - // Check the l-value width. If it is unspecified, then use the - // largest operand width as the l-value width. Restrict the - // result width to the width of the largest operand, because - // there is no value is excess divider. - - unsigned rwidth = lwidth; - - // If either operand is IVL_VT_REAL, then cast the other to - // IVL_VT_REAL so that the division can become IVL_VT_REAL. - - if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) { - if (lsig->data_type() != IVL_VT_REAL) - lsig = cast_to_real(des, scope, lsig); - if (rsig->data_type() != IVL_VT_REAL) - rsig = cast_to_real(des, scope, rsig); - } - - if (rwidth == 0) { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - - lwidth = rwidth; - } - - if ((rwidth > lsig->vector_width()) && (rwidth > rsig->vector_width())) { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - } - - /* The arguments of a divide must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of divide " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // Create a device with the calculated dimensions. - NetDivide*div = new NetDivide(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - div->set_line(*this); - div->rise_time(rise); - div->fall_time(fall); - div->decay_time(decay); - des->add_node(div); - - div->set_signed(lsig->get_signed() && rsig->get_signed()); - - // Connect the left and right inputs of the divider to the - // nets that are the left and right expressions. - - connect(div->pin_DataA(), lsig->pin(0)); - connect(div->pin_DataB(), rsig->pin(0)); - - - // Make an output signal that is the width of the l-value. - // Due to above calculation of rwidth, we know that the result - // will be no more than the l-value, so it is safe to connect - // all the result pins to the osig. - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - osig->local_flag(true); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - osig->set_signed(div->get_signed()); - - connect(div->pin_Result(), osig->pin(0)); - - - return osig; -} - -/* - * Elaborate a modulo gate. - */ -NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a modulus must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of modulus " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - /* The % operator does not support real arguments in baseline - Verilog. But we allow it in our extended form of Verilog. */ - if (gn_icarus_misc_flag==false && lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: Modulus operator may not " - "have REAL operands." << endl; - des->errors += 1; - return 0; - } - - /* rwidth is result width. */ - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - lwidth = 1; - rwidth = 1; - } else { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - - lwidth = rwidth; - } - } - - NetModulo*mod = new NetModulo(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - mod->set_line(*this); - mod->rise_time(rise); - mod->fall_time(fall); - mod->decay_time(decay); - des->add_node(mod); - - connect(mod->pin_DataA(), lsig->pin(0)); - connect(mod->pin_DataB(), rsig->pin(0)); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - - connect(mod->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - if (rsig->data_type() == IVL_VT_REAL || - lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": sorry: " << human_readable_op(op_) - << " is currently unsupported for real values." << endl; - des->errors += 1; - return 0; - } - - NetLogic*gate; - switch (op_) { - case 'a': - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::AND, 1); - break; - case 'o': - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::OR, 1); - break; - default: - assert(0); - } - - // The first OR gate returns 1 if the left value is true... - if (lsig->vector_width() > 1) { - NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - lsig->vector_width()); - connect(gate_tmp->pin(1), lsig->pin(0)); - connect(gate->pin(1), gate_tmp->pin(0)); - - /* The reduced logical value is a new nexus, create a - temporary signal to represent it. */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(gate->pin(1), tmp->pin(0)); - - des->add_node(gate_tmp); - - } else { - connect(gate->pin(1), lsig->pin(0)); - } - - // The second OR gate returns 1 if the right value is true... - if (rsig->vector_width() > 1) { - NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - rsig->vector_width()); - connect(gate_tmp->pin(1), rsig->pin(0)); - connect(gate->pin(2), gate_tmp->pin(0)); - - /* The reduced logical value is a new nexus, create a - temporary signal to represent it. */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(gate->pin(2), tmp->pin(0)); - - des->add_node(gate_tmp); - - } else { - connect(gate->pin(2), rsig->pin(0)); - } - - // The output is the AND/OR of the two logic values. - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); - osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); - connect(gate->pin(0), osig->pin(0)); - - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - return osig; -} - -NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - verinum*lnum = left_->eval_const(des, scope); - verinum*rnum = right_->eval_const(des, scope); - - /* Detect and handle the special case that both the operands - of the multiply are constant expressions. Evaluate the - value and make this a simple constant. */ - if (lnum && rnum) { - verinum prod = *lnum * *rnum; - if (lwidth == 0) - lwidth = prod.len(); - - verinum res (verinum::V0, lwidth); - for (unsigned idx = 0 - ; idx < prod.len() && idx < lwidth - ; idx += 1) { - res.set(idx, prod.get(idx)); - } - - NetConst*odev = new NetConst(scope, scope->local_symbol(), res); - des->add_node(odev); - odev->rise_time(rise); - odev->fall_time(fall); - odev->decay_time(decay); - odev->set_line(*this); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - osig->set_line(*this); - osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); - - connect(odev->pin(0), osig->pin(0)); - - return osig; - } - - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a multiply must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of multiply " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // The mult is signed if both its operands are signed. - bool arith_is_signed = lsig->get_signed() && rsig->get_signed(); - - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - rwidth = 1; - lwidth = 1; - } else { - rwidth = lsig->vector_width() + rsig->vector_width(); - lwidth = rwidth; - } - } - - if (arith_is_signed) { - lsig = pad_to_width_signed(des, lsig, rwidth); - rsig = pad_to_width_signed(des, rsig, rwidth); - } - - NetMult*mult = new NetMult(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - mult->set_line(*this); - mult->rise_time(rise); - mult->fall_time(fall); - mult->decay_time(decay); - des->add_node(mult); - - mult->set_signed( arith_is_signed ); - - connect(mult->pin_DataA(), lsig->pin(0)); - connect(mult->pin_DataB(), rsig->pin(0)); - - /* Make a signal to carry the output from the multiply. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - connect(mult->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a power must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of power " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - /* The power is signed if either of its operands are signed. */ - bool arith_is_signed = lsig->get_signed() || rsig->get_signed(); - - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - rwidth = 1; - lwidth = 1; - } else { - /* This is incorrect! a * (2^b - 1) is close. */ - rwidth = lsig->vector_width() + rsig->vector_width(); - lwidth = rwidth; - } - } - - if (arith_is_signed) { - lsig = pad_to_width_signed(des, lsig, rwidth); - rsig = pad_to_width_signed(des, rsig, rwidth); - } - - NetPow*powr = new NetPow(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - powr->set_line(*this); - powr->rise_time(rise); - powr->fall_time(fall); - powr->decay_time(decay); - des->add_node(powr); - - powr->set_signed( arith_is_signed ); - - connect(powr->pin_DataA(), lsig->pin(0)); - connect(powr->pin_DataB(), rsig->pin(0)); - - /* Make a signal to carry the output from the power. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - connect(powr->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0) return 0; - - /* Cannot shift a real value. */ - if (lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: shift operators (" - << human_readable_op(op_) - << ") cannot shift a real value." << endl; - des->errors += 1; - return 0; - } - - if (lsig->vector_width() > lwidth) - lwidth = lsig->vector_width(); - - bool right_flag = op_ == 'r' || op_ == 'R'; - bool signed_flag = op_ == 'R'; - - /* Handle the special case of a constant shift amount. There - is no reason in this case to create a gate at all, just - connect the lsig to the osig with the bit positions - shifted. Use a NetPartSelect to select the parts of the - left expression that survive the shift, and a NetConcat to - concatenate a constant for padding. */ - if (verinum*rval = right_->eval_const(des, scope)) { - assert(rval->is_defined()); - unsigned dist = rval->as_ulong(); - - /* Very special case: constant 0 shift. Simply return - the left signal again. */ - if (dist == 0) return lsig; - - /* The construction that I'm making will ultimately - connect its output to the osig here. This will be the - result that I return from this function. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, lwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - - - /* Make the constant zero's that I'm going to pad to the - top or bottom of the left expression. Attach a signal - to its output so that I don't have to worry about it - later. If the left expression is less than the - desired width (and we are doing right shifts) then we - can combine the expression padding with the distance - padding to reduce nodes. */ - unsigned pad_width = dist; - unsigned part_width = lwidth - dist; - if (op_ == 'r' || op_ == 'R') { - if (lsig->vector_width() < lwidth) { - pad_width += lwidth - lsig->vector_width(); - part_width -= lwidth - lsig->vector_width(); - } - } else { - - /* The left net must be the same width as the - result. The part select that I'm about to make relies - on that. */ - lsig = pad_to_width(des, lsig, lwidth); - - } - - NetNet*zero = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, pad_width); - zero->data_type( lsig->data_type() ); - zero->local_flag(true); - zero->set_line(*this); - - /* Padding bits are zero in most cases, but copies of - * the sign bit in the case of a signed right shift */ - if (op_ == 'R') { - NetPartSelect*sign_bit - = new NetPartSelect(lsig, lsig->vector_width()-1, - 1, NetPartSelect::VP); - des->add_node(sign_bit); - NetReplicate*sign_pad - = new NetReplicate(scope, scope->local_symbol(), - pad_width, pad_width); - des->add_node(sign_pad); - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - tmp->data_type( lsig->data_type() ); - tmp->local_flag(true); - tmp->set_line(*this); - connect(sign_bit->pin(0), tmp->pin(0)); - connect(sign_bit->pin(0), sign_pad->pin(1)); - - connect(zero->pin(0), sign_pad->pin(0)); - - } else { - NetConst*zero_c = new NetConst(scope, scope->local_symbol(), - verinum(verinum::V0, pad_width)); - des->add_node(zero_c); - connect(zero->pin(0), zero_c->pin(0)); - } - - /* If all data bits get shifted away, connect the zero or - * padding bits directly to output, and stop before building the - * concatenation. */ - if (dist >= lwidth) { - connect(osig->pin(0), zero->pin(0)); - return osig; - } - - /* Make a concatenation operator that will join the - part-selected right expression at the pad values. */ - NetConcat*cc = new NetConcat(scope, scope->local_symbol(), - lwidth, 2); - cc->set_line(*this); - des->add_node(cc); - connect(cc->pin(0), osig->pin(0)); - - /* Make the part select of the left expression and - connect it to the LSB or MSB of the concatenation, - depending on the direction of the shift. */ - NetPartSelect*part; - - switch (op_) { - case 'l': // Left shift === {lsig, zero} - part = new NetPartSelect(lsig, 0, part_width, - NetPartSelect::VP); - connect(cc->pin(1), zero->pin(0)); - connect(cc->pin(2), part->pin(0)); - break; - case 'R': - case 'r': // right-shift === {zero, lsig} - part = new NetPartSelect(lsig, dist, part_width, - NetPartSelect::VP); - connect(cc->pin(1), part->pin(0)); - connect(cc->pin(2), zero->pin(0)); - break; - default: - assert(0); - } - - part->set_line(*this); - part->rise_time(rise); - part->fall_time(fall); - part->decay_time(decay); - des->add_node(part); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate shift " - << "(" << op_ << ") as concatenation of " - << pad_width << " zeros with " << part_width - << " bits of expression." << endl; - } - - /* Attach a signal to the part select output (NetConcat - input) */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_width); - tmp->data_type( lsig->data_type() ); - tmp->local_flag(true); - tmp->set_line(*this); - connect(part->pin(0), tmp->pin(0)); - - return osig; - } - - // Calculate the number of useful bits for the shift amount, - // and elaborate the right_ expression as the shift amount. - unsigned dwid = 0; - while ((1U << dwid) < lwidth) - dwid += 1; - - NetNet*rsig = right_->elaborate_net(des, scope, dwid, 0, 0, 0); - - if (rsig == 0) return 0; - - /* You cannot shift a value by a real amount. */ - if (rsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: shift operators " - "cannot shift by a real value." << endl; - des->errors += 1; - return 0; - } - - // Make the shift device itself, and the output - // NetNet. Connect the Result output pins to the osig signal - NetCLShift*gate = new NetCLShift(scope, scope->local_symbol(), - lwidth, rsig->vector_width(), - right_flag, signed_flag); - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, lwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - osig->set_signed(signed_flag); - - connect(osig->pin(0), gate->pin_Result()); - - // Connect the lsig (the left expression) to the Data input, - // and pad it if necessary. The lwidth is the width of the - // NetCLShift gate, and the D input must match. - if (lsig->vector_width() < lwidth) - lsig = pad_to_width(des, lsig, lwidth); - - assert(lsig->vector_width() <= lwidth); - connect(lsig->pin(0), gate->pin_Data()); - - // Connect the rsig (the shift amount expression) to the - // Distance input. - connect(rsig->pin(0), gate->pin_Distance()); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "Elaborate LPM_SHIFT: width="<width() - << ", swidth="<< gate->width_dist() << endl; - } - - return osig; -} - -/* - * This method elaborates a call to a function in the context of a - * continuous assignment. The definition of the function contains a - * list of the ports, and an output port. The NetEUFunc that I create - * here has a port for all the input ports and the output port. The - * ports are connected by pins. - */ -NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - unsigned errors = 0; - unsigned func_pins = 0; - - if (path_.front().name[0] == '$') - return elaborate_net_sfunc_(des, scope, - width, rise, fall, decay, - drive0, drive1); - - - /* Look up the function definition. */ - NetFuncDef*def = des->find_function(scope, path_); - if (def == 0) { - cerr << get_fileline() << ": error: No function " << path_ << - " in this context (" << scope_path(scope) << ")." << endl; - des->errors += 1; - return 0; - } - - NetScope*dscope = def->scope(); - assert(dscope); - - /* This must be a function that returns a signal. */ - assert(def->return_sig()); - - /* check the validity of the parameters. */ - if (! check_call_matches_definition_(des, dscope)) - return 0; - - /* Elaborate all the parameters of the function call, - and collect the resulting NetNet objects. All the - parameters take on the size of the target port. */ - - svector eparms (def->port_count()); - for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) { - const NetNet* port_reg = def->port(idx); - NetNet*tmp = parms_[idx]->elaborate_net(des, scope, - port_reg->vector_width(), - 0, 0, 0, - Link::STRONG, - Link::STRONG); - if (tmp == 0) { - cerr << get_fileline() << ": error: Unable to elaborate " - << "port " << idx << " of call to " << path_ << - "." << endl; - errors += 1; - des->errors += 1; - continue; - } - - func_pins += tmp->pin_count(); - eparms[idx] = tmp; - } - - if (errors > 0) return 0; - - NetUserFunc*net = new NetUserFunc(scope, - scope->local_symbol(), - dscope); - net->set_line(*this); - net->rise_time(rise); - net->fall_time(fall); - net->decay_time(decay); - des->add_node(net); - - /* Create an output signal and connect it to the output pins - of the function net. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, - def->return_sig()->vector_width()); - osig->local_flag(true); - osig->data_type(def->return_sig()->data_type()); - - connect(net->pin(0), osig->pin(0)); - - /* Connect the parameter pins to the parameter expressions. */ - for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) { - const NetNet* port = def->port(idx); - NetNet*cur = eparms[idx]; - - NetNet*tmp = pad_to_width(des, cur, port->vector_width()); - - connect(net->pin(idx+1), tmp->pin(0)); - } - - return osig; -} - -NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - perm_string name = peek_tail_name(path_); - - /* Handle the special case that the function call is to - $signed. This takes a single expression argument, and - forces it to be a signed result. Otherwise, it is as if the - $signed did not exist. */ - if (strcmp(name, "$signed") == 0) { - if ((parms_.size() != 1) || (parms_[0] == 0)) { - cerr << get_fileline() << ": error: The $signed() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } - - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(true); - return sub; - } - - /* handle $unsigned like $signed */ - if (strcmp(name, "$unsigned") == 0) { - if ((parms_.size() != 1) || (parms_[0] == 0)) { - cerr << get_fileline() << ": error: The $unsigned() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } - - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(false); - return sub; - } - - const struct sfunc_return_type*def = lookup_sys_func(name); - - /* We cannot use the default value for system functions in a - * continuous assignment since the function name is NULL. */ - if (def == 0 || def->name == 0) { - cerr << get_fileline() << ": error: System function " - << peek_tail_name(path_) << " not defined in system " - "table or SFT file(s)." << endl; - des->errors += 1; - return 0; - } - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Net system function " - << name << " returns " << def->type << endl; - } - - NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(), - def, 1+parms_.size()); - net->set_line(*this); - net->rise_time(rise); - net->fall_time(fall); - net->decay_time(decay); - des->add_node(net); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, def->wid); - osig->local_flag(true); - osig->set_signed(def->type==IVL_VT_REAL? true : false); - osig->data_type(def->type); - osig->set_line(*this); - - connect(net->pin(0), osig->pin(0)); - - unsigned errors = 0; - for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { - NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0, - 0, 0, 0, - Link::STRONG, Link::STRONG); - if (tmp == 0) { - cerr << get_fileline() << ": error: Unable to elaborate " - << "port " << idx << " of call to " << path_ << - "." << endl; - errors += 1; - des->errors += 1; - continue; - } - - connect(net->pin(1+idx), tmp->pin(0)); - } - - if (errors > 0) return 0; - - return osig; -} - - -/* - * The concatenation operator, as a net, is a wide signal that is - * connected to all the pins of the elaborated expression nets. - */ -NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope, - unsigned, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - svectornets (parms_.count()); - unsigned vector_width = 0; - unsigned errors = 0; - unsigned repeat = 1; - - /* The repeat expression must evaluate to a compile-time - constant. This is used to generate the width of the - concatenation. */ - if (repeat_) { - NetExpr*etmp = elab_and_eval(des, scope, repeat_, -1); - assert(etmp); - NetEConst*erep = dynamic_cast(etmp); - - if (erep == 0) { - cerr << get_fileline() << ": error: Unable to " - << "evaluate constant repeat expression." << endl; - des->errors += 1; - 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() - << ")." << endl; - des->errors += 1; - return 0; - } - - repeat = erep->value().as_ulong(); - delete etmp; - - if (repeat == 0) { - cerr << get_fileline() << ": error: Concatenation repeat " - "may not be zero." - << endl; - des->errors += 1; - return 0; - } - } - - if (debug_elaborate) { - cerr << get_fileline() <<": debug: PEConcat concatenation repeat=" - << repeat << "." << endl; - } - - /* The operands of the concatenation must contain all - self-determined arguments. Set this flag to force an error - message if this is not the case. */ - const bool save_flag = must_be_self_determined_flag; - must_be_self_determined_flag = true; - - /* Elaborate the operands of the concatenation. */ - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - - if (parms_[idx] == 0) { - cerr << get_fileline() << ": error: Empty expressions " - << "not allowed in concatenations." << endl; - errors += 1; - continue; - } - - /* Look for the special case of an unsized number in a - concatenation expression. Mark this as an error, but - allow elaboration to continue to see if I can find - more errors. */ - - if (PENumber*tmp = dynamic_cast(parms_[idx])) { - if (tmp->value().has_len() == false) { - cerr << get_fileline() << ": error: Number " - << tmp->value() << " with indefinite size" - << " in concatenation." << endl; - errors += 1; - } - } - - nets[idx] = parms_[idx]->elaborate_net(des, scope, 0, 0, 0, 0); - if (nets[idx] == 0) - errors += 1; - else - vector_width += nets[idx]->vector_width(); - } - - must_be_self_determined_flag = save_flag; - - /* If any of the sub expressions failed to elaborate, then - delete all those that did and abort myself. */ - if (errors) { - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - if (nets[idx]) delete nets[idx]; - } - des->errors += errors; - return 0; - } - - if (debug_elaborate) { - cerr << get_fileline() <<": debug: PEConcat concat collected " - << "width=" << vector_width << ", repeat=" << repeat - << " of " << nets.count() << " expressions." << endl; - } - - NetConcat*dev = new NetConcat(scope, scope->local_symbol(), - vector_width*repeat, - nets.count()*repeat); - dev->set_line(*this); - dev->rise_time(rise); - dev->fall_time(fall); - dev->decay_time(decay); - des->add_node(dev); - - /* Make the temporary signal that connects to all the - operands, and connect it up. Scan the operands of the - concat operator from least significant to most significant, - which is opposite from how they are given in the list. - - Allow for a repeat count other than 1 by repeating the - connect loop as many times as necessary. */ - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, vector_width * repeat); - osig->data_type(IVL_VT_LOGIC); - - connect(dev->pin(0), osig->pin(0)); - - unsigned cur_pin = 1; - for (unsigned rpt = 0; rpt < repeat ; rpt += 1) { - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - NetNet*cur = nets[nets.count()-idx-1]; - connect(dev->pin(cur_pin++), cur->pin(0)); - } - } - - osig->local_flag(true); - return osig; -} - -/* - * This private method handles the special case that we have a - * non-constant bit-select of an identifier. We already know that the - * signal that is represented is "sig". - */ -NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope, - NetNet*sig, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) 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.sel == index_component_t::SEL_BIT); - ivl_assert(*this, index_tail.msb != 0); - ivl_assert(*this, index_tail.lsb == 0); - - /* Elaborate the selector. */ - NetNet*sel; - - if (sig->msb() < sig->lsb()) { - NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1, false); - sel_expr = make_sub_expr(sig->lsb(), sel_expr); - eval_expr(sel_expr); - - sel = sel_expr->synthesize(des); - - } else if (sig->lsb() != 0) { - NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1,false); - sel_expr = make_add_expr(sel_expr, - sig->lsb()); - eval_expr(sel_expr); - - sel = sel_expr->synthesize(des); - - } else { - sel = index_tail.msb->elaborate_net(des, scope, 0, 0, 0, 0); - } - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create NetPartSelect " - << "using signal " << sel->name() << " as selector" - << endl; - } - - /* Create a part select that takes a non-constant offset and a - width of 1. */ - NetPartSelect*mux = new NetPartSelect(sig, sel, 1); - des->add_node(mux); - mux->set_line(*this); - - NetNet*out = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - out->data_type(sig->data_type()); - - connect(out->pin(0), mux->pin(0)); - return out; -} - -NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - ivl_assert(*this, scope); - - const name_component_t&name_tail = path_.back(); - - NetNet* sig = 0; - const NetExpr*par = 0; - NetEvent* eve = 0; - - const NetExpr*id_msb; - const NetExpr*id_lsb; - symbol_search(des, scope, path_, sig, par, eve, id_msb, id_lsb); - - /* If this is a parameter name, then create a constant node - that connects to a signal with the correct name. */ - if (par != 0) { - - // Detect and handle the special case that we have a - // real valued parameter. Return a NetLiteral and a - // properly typed net. - if (const NetECReal*pc = dynamic_cast(par)) { - NetLiteral*tmp = new NetLiteral(scope, scope->local_symbol(), - pc->value()); - des->add_node(tmp); - tmp->set_line(*par); - sig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT); - sig->set_line(*tmp); - sig->data_type(tmp->data_type()); - sig->local_flag(true); - - connect(tmp->pin(0), sig->pin(0)); - return sig; - } - - const NetEConst*pc = dynamic_cast(par); - if (pc == 0) { - cerr << get_fileline() << ": internal error: " - << "Non-consant parameter value?: " << *par << endl; - cerr << get_fileline() << ": : " - << "Expression type is " << par->expr_type() << endl; - } - ivl_assert(*this, pc); - verinum pvalue = pc->value(); - - /* If the parameter has declared dimensions, then apply - those to the dimensions of the net that we create. */ - long msb = pvalue.len()-1; - long lsb = 0; - if (id_msb || id_lsb) { - assert(id_msb && id_lsb); - const NetEConst*tmp = dynamic_cast(id_msb); - ivl_assert(*this, tmp); - msb = tmp->value().as_long(); - - tmp = dynamic_cast(id_lsb); - ivl_assert(*this, tmp); - lsb = tmp->value().as_long(); - } - - /* If the constant is smaller than its defined width extend - the value. If needed this will be padded later to fit - the real signal width. */ - unsigned pwidth = msb > lsb ? msb - lsb : lsb - msb; - if (pwidth > pvalue.len()) { - verinum tmp ((uint64_t)0, pwidth); - for (unsigned idx = 0 ; idx < pvalue.len() ; idx += 1) - tmp.set(idx, pvalue.get(idx)); - - pvalue = tmp; - } - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, msb, lsb); - sig->set_line(*this); - sig->data_type(IVL_VT_LOGIC); - sig->local_flag(true); - NetConst*cp = new NetConst(scope, scope->local_symbol(), - pvalue); - cp->set_line(*this); - des->add_node(cp); - for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) - connect(sig->pin(idx), cp->pin(idx)); - } - - /* Check for the error case that the name is not found, and it - is hierarchical. We can't just create a name in another - scope, it's just not allowed. */ - if (sig == 0 && path_.size() != 1) { - cerr << get_fileline() << ": error: The hierarchical name " - << path_ << " is undefined in " - << scope_path(scope) << "." << endl; - - pform_name_t tmp_path = path_; - tmp_path.pop_back(); - - list stmp_path = eval_scope_path(des, scope, tmp_path); - NetScope*tmp_scope = des->find_scope(scope, stmp_path); - if (tmp_scope == 0) { - cerr << get_fileline() << ": : I can't even find " - << "the scope " << tmp_path << "." << endl; - } - - des->errors += 1; - return 0; - } - - /* Fallback, this may be an implicitly declared net. */ - if (sig == 0) { - NetNet::Type nettype = scope->default_nettype(); - sig = new NetNet(scope, name_tail.name, - nettype, 1); - sig->data_type(IVL_VT_LOGIC); - - if (error_implicit || (nettype == NetNet::NONE)) { - cerr << get_fileline() << ": error: " - << scope_path(scope) << "." << name_tail.name - << " not defined in this scope." << endl; - des->errors += 1; - - } else if (warn_implicit) { - cerr << get_fileline() << ": warning: implicit " - "definition of wire " << scope_path(scope) - << "." << name_tail.name << "." << endl; - } - } - - ivl_assert(*this, sig); - - /* Handle the case that this is an array elsewhere. */ - if (sig->array_dimensions() > 0) { - if (name_tail.index.size() == 0) { - cerr << get_fileline() << ": error: Array " << sig->name() - << " cannot be used here without an index." << endl; - des->errors += 1; - return 0; - } - - return elaborate_net_array_(des, scope, sig, lwidth, - rise, fall, decay, - drive0, drive1); - } - - return elaborate_net_net_(des, scope, sig, lwidth, - rise, fall, decay, drive0, drive1); - -} - -NetNet* PEIdent::process_select_(Design*des, NetScope*scope, - NetNet*sig) const -{ - - // If there are more index items then there are array - // dimensions, then treat them as word part selects. For - // example, if this is a memory array, then array dimensions - // is the first and part select the remainder. - long midx, lidx; - if (! eval_part_select_(des, scope, sig, midx, lidx)) - return sig; - - ivl_assert(*this, lidx >= 0); - unsigned part_count = midx-lidx+1; - - // Maybe this is a full-width constant part select? If - // so, do nothing. - if (part_count == sig->vector_width()) - return sig; - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select" - << " of word from " << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), ps->pin(0)); - - return tmp; -} - -NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - 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; - - switch (use_sel) { - case index_component_t::SEL_IDX_UP: - case index_component_t::SEL_IDX_DO: - return elaborate_net_net_idx_up_(des, scope, sig, lwidth, - rise, fall, decay, drive0, drive1); - - default: - break; - } - - /* Catch the case of a non-constant bit select. That should be - handled elsewhere. */ - if (use_sel == index_component_t::SEL_BIT) { - const index_component_t&index_tail = name_tail.index.back(); - - verinum*mval = index_tail.msb->eval_const(des, scope); - if (mval == 0) { - return elaborate_net_bitmux_(des, scope, sig, rise, - fall, decay, drive0, drive1); - } - - delete mval; - } - - long midx, lidx; - if (! eval_part_select_(des, scope, sig, midx, lidx)) - return 0; - - unsigned part_count = midx-lidx+1; - unsigned output_width = part_count; - - /* Detect and handle the special case that the entire part - select is outside the range of the signal. Return a - constant xxx. */ - if (midx < 0 || lidx >= (long)sig->vector_width()) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - verinum xxx (verinum::Vx, part_count); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), con->pin(0)); - return tmp; - } - - NetNet*below = 0; - if (lidx < 0) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - unsigned xxx_wid = 0-lidx; - verinum xxx (verinum::Vx, xxx_wid); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - below = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, xxx_wid); - below->data_type( sig->data_type() ); - below->local_flag(true); - connect(below->pin(0), con->pin(0)); - - lidx = 0; - part_count = midx-lidx+1; - } - - NetNet*above = 0; - if (midx >= (long)sig->vector_width()) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - unsigned xxx_wid = midx - sig->vector_width() + 1; - verinum xxx (verinum::Vx, xxx_wid); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - above = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, xxx_wid); - above->data_type( sig->data_type() ); - above->local_flag(true); - connect(above->pin(0), con->pin(0)); - - midx = sig->vector_width()-1; - part_count = midx-lidx+1; - } - - ivl_assert(*this, lidx >= 0); - if (part_count != sig->vector_width()) { - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select " - << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), ps->pin(0)); - - sig = tmp; - } - - unsigned segment_count = 1; - if (below) segment_count += 1; - if (above) segment_count += 1; - if (segment_count > 1) { - NetConcat*cc = new NetConcat(scope, scope->local_symbol(), - output_width, segment_count); - cc->set_line(*sig); - des->add_node(cc); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, output_width); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), cc->pin(0)); - - unsigned pdx = 1; - if (below) { - connect(cc->pin(pdx), below->pin(0)); - pdx += 1; - } - connect(cc->pin(pdx), sig->pin(0)); - pdx += 1; - if (above) { - connect(cc->pin(pdx), above->pin(0)); - pdx += 1; - } - ivl_assert(*sig, segment_count == pdx-1); - - sig = tmp; - } - - return sig; -} - -NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) 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); - - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); - - bool down_flag = name_tail.index.back().sel==index_component_t::SEL_IDX_DO; - - // Handle the special case that the base is constant as - // well. In this case it can be converted to a conventional - // part select. - if (NetEConst*base_c = dynamic_cast (base)) { - long lsv = base_c->value().as_long(); - - // convert from -: to +: form. - if (down_flag) lsv -= (wid-1); - - // If the part select covers exactly the entire - // vector, then do not bother with it. Return the - // signal itself. - if (sig->sb_to_idx(lsv) == 0 && wid == sig->vector_width()) - return sig; - - NetPartSelect*sel = new NetPartSelect(sig, sig->sb_to_idx(lsv), - wid, NetPartSelect::VP); - sel->set_line(*this); - des->add_node(sel); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); - tmp->set_line(*this); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sel->pin(0)); - - delete base; - return tmp; - } - - if (sig->msb() > sig->lsb()) { - long offset = sig->lsb(); - if (down_flag) - offset += (wid-1); - if (offset != 0) - base = make_add_expr(base, 0-offset); - } else { - long vwid = sig->lsb() - sig->msb() + 1; - long offset = sig->msb(); - if (down_flag) - offset += (wid-1); - base = make_sub_expr(vwid-offset-wid, base); - } - - NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des), wid); - sel->set_line(*this); - des->add_node(sel); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); - tmp->set_line(*this); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sel->pin(0)); - - delete base; - return tmp; -} - -NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - const name_component_t&name_tail = path_.back(); - ivl_assert(*this, name_tail.index.size() >= 1); - const index_component_t&index_head = name_tail.index.front(); - ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); - ivl_assert(*this, index_head.msb != 0); - ivl_assert(*this, index_head.lsb == 0); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: elaborate array " - << name_tail.name << " with index " << index_head << endl; - - NetExpr*index_ex = elab_and_eval(des, scope, index_head.msb, -1); - if (index_ex == 0) - return 0; - - if (NetEConst*index_co = dynamic_cast (index_ex)) { - long index = index_co->value().as_long(); - - if (!sig->array_index_is_valid(index)) { - // Oops! The index is a constant known to be - // outside the array. Change the expression to a - // constant X vector. - verinum xxx (verinum::Vx, sig->vector_width()); - NetConst*con_n = new NetConst(scope, scope->local_symbol(), xxx); - des->add_node(con_n); - con_n->set_line(*index_co); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), con_n->pin(0)); - return tmp; - } - - assert(sig->array_index_is_valid(index)); - index = sig->array_index_to_address(index); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate word " - << index << " of " << sig->name() << endl; - } - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sig->pin(index)); - - // If there are more indices then needed to get to the - // word, then there is a part/bit select for the word. - if (name_tail.index.size() > sig->array_dimensions()) - tmp = process_select_(des, scope, tmp); - - return tmp; - } - - unsigned selwid = index_ex->expr_width(); - - NetArrayDq*mux = new NetArrayDq(scope, scope->local_symbol(), - sig, selwid); - mux->set_line(*this); - des->add_node(mux); - - // Adjust the expression to calculate the canonical offset? - if (long array_base = sig->array_first()) { - index_ex = make_add_expr(index_ex, 0-array_base); - } - - NetNet*index_net = index_ex->synthesize(des); - connect(mux->pin_Address(), index_net->pin(0)); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), mux->pin_Result()); -#if 0 - - // If there are more index items then there are array - // dimensions, then treat them as word part selects. For - // example, if this is a memory array, then array dimensions - // is 1 and - unsigned midx, lidx; - if (eval_part_select_(des, scope, sig, midx, lidx)) do { - - unsigned part_count = midx-lidx+1; - - // Maybe this is a full-width constant part select? If - // so, do nothing. - if (part_count == sig->vector_width()) - break; - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select" - << " of word from " << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp2->data_type( tmp->data_type() ); - tmp2->local_flag(true); - connect(tmp2->pin(0), ps->pin(0)); - - tmp = tmp2; - } while (0); -#else - if (name_tail.index.size() > sig->array_dimensions()) - tmp = process_select_(des, scope, tmp); - -#endif - return tmp; -} - /* * The concatenation is also OK an an l-value. This method elaborates * it as a structural l-value. The return values is the *input* net of @@ -2468,42 +164,6 @@ NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const return elaborate_lnet_common_(des, scope, true); } -/* - * Elaborate a number as a NetConst object. - */ -NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate real literal node, " - << "value=" << value() << "." << endl; - } - - NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value()); - obj->set_line(*this); - obj->rise_time(rise); - obj->fall_time(fall); - obj->decay_time(decay); - obj->pin(0).drive0(drive0); - obj->pin(0).drive1(drive1); - des->add_node(obj); - - NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1); - net->data_type(IVL_VT_REAL); - net->set_signed(true); - net->local_flag(true); - net->set_line(*this); - - connect(obj->pin(0), net->pin(0)); - - return net; -} - /* * A private method to create an implicit net. */ @@ -2791,6 +451,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, sig->type(), sig->vector_width()); tmp->set_line(*this); tmp->local_flag(true); + tmp->data_type( sig->data_type() ); connect(sig->pin(widx), tmp->pin(0)); sig = tmp; } @@ -2929,781 +590,3 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const return sig; } -/* - * Elaborate a number as a NetConst object. - * - * The code assumes that the result is IVL_VT_LOGIC. - */ -NetNet* PENumber::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - NetNet *net; - NetConst *con; - - /* If we are constrained by a l-value size, then just make a - number constant with the correct size and set as many bits - in that constant as make sense. Pad excess with - zeros. Also, assume that numbers are meant to be logic - type. */ - if (lwidth > 0) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - net->set_signed(value_->has_sign()); - - verinum num = pad_to_width(*value_, lwidth); - if (num.len() > lwidth) - num = verinum(num, lwidth); - - con = new NetConst(scope, scope->local_symbol(), num); - - /* If the number has a length, then use that to size the - number. Generate a constant object of exactly the user - specified size. */ - } else if (value_->has_len()) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, value_->len()); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - net->set_signed(value_->has_sign()); - con = new NetConst(scope, scope->local_symbol(), - *value_); - - /* None of the above tight constraints are present, so make a - plausible choice for the width. Try to reduce the width as - much as possible by eliminating high zeros of unsigned - numbers. */ - } else { - - if (must_be_self_determined_flag) { - cerr << get_fileline() << ": error: No idea how wide to " - << "make the unsized constant " << *value_ << "." << endl; - des->errors += 1; - } - - unsigned width = value_->len(); - - if (value_->has_sign() && (value_->get(width-1) == verinum::V0)) { - - /* If the number is signed, but known to be positive, - then reduce it down as if it were unsigned. */ - while (width > 1) { - if (value_->get(width-1) != verinum::V0) - break; - width -= 1; - - } - - } else if (value_->has_sign() == false) { - while ( (width > 1) && (value_->get(width-1) == verinum::V0)) - width -= 1; - } - - verinum num (verinum::V0, width); - for (unsigned idx = 0 ; idx < width ; idx += 1) - num.set(idx, value_->get(idx)); - - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - con = new NetConst(scope, scope->local_symbol(), num); - } - - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - connect(con->pin(0), net->pin(0)); - - des->add_node(con); - return net; -} - -/* - * A string is a NetEConst node that is made of the ASCII bits of the - * string instead of the bits of a number. In fact, a string is just - * another numeric notation. - */ -NetNet* PEString::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - unsigned strbits = strlen(text_) * 8; - NetNet*net; - - /* If we are constrained by a l-value size, then just make a - number constant with the correct size and set as many bits - in that constant as make sense. Pad excess with zeros. */ - if (lwidth > 0) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - - } else { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, strbits); - } - net->data_type(IVL_VT_BOOL); - net->local_flag(true); - - /* Make a verinum that is filled with the 0 pad. */ - verinum num(verinum::V0, net->vector_width()); - - unsigned idx; - for (idx = 0 ; idx < num.len() && idx < strbits; idx += 1) { - char byte = text_[strbits/8 - 1 - idx/8]; - char mask = 1<<(idx%8); - num.set(idx, (byte & mask)? verinum::V1 : verinum::V0); - } - - NetConst*con = new NetConst(scope, scope->local_symbol(), num); - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - connect(con->pin(0), net->pin(0)); - - return net; -} - -/* Common processing for the case when a single argument is always - * selected in a ternary operator. */ -static void process_single_ternary(Design*des, const PExpr*base, - unsigned width, NetNet*&sig) -{ - /* We must have a type for the signal. */ - if (sig->data_type() == IVL_VT_NO_TYPE) { - cerr << base->get_fileline() << ": internal error: constant " - << "selected ternary clause has NO TYPE." << endl; - des->errors += 1; - sig = 0; - } - - /* Use the signal width if one is not provided. - * Pad or crop as needed. */ - if (width == 0) width = sig->vector_width(); - - if (sig->vector_width() < width) sig = pad_to_width(des, sig, width); - - if (width < sig->vector_width()) sig = crop_to_width(des, sig, width); - - sig->set_line(*base); -} - -/* - * Elaborate the ternary operator in a netlist by creating a LPM_MUX - * with width matching the result, size == 2 and 1 select input. These - * expressions come from code like: - * - * res = test ? a : b; - * - * The res has the width requested of this method, and the a and b - * expressions have their own similar widths. The test expression is - * only a single bit wide. The output from this function is a NetNet - * object the width of the expression and connected to the - * Result pins of the LPM_MUX device. Any width not covered by the - * width of the mux is padded with a NetConst device. - */ -NetNet* PETernary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - NetNet *expr_sig, *tru_sig, *fal_sig; - - NetExpr*expr = elab_and_eval(des, scope, expr_, 0); - if (expr == 0) return 0; - - /* If we have a constant conditional we can avoid some steps. */ - switch (const_logical(expr)) { - case C_0: - fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0); - if (fal_sig == 0) return 0; - process_single_ternary(des, this, width, fal_sig); - return fal_sig; - break; - - case C_1: - tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0); - if (tru_sig == 0) return 0; - process_single_ternary(des, this, width, tru_sig); - return tru_sig; - break; - - default: - tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0); - fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0); - /* We should really see if these are constant values and - * mix them as needed so we can omit the MUX? below, but - * since this is a very uncommon case, I'm going to pass - * on this for now. */ - break; - } - expr_sig = expr->synthesize(des); - - if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0; - - /* The type of the true and false expressions must - match. These become the type of the resulting - expression. */ - - ivl_variable_type_t expr_type = tru_sig->data_type(); - - if (tru_sig->data_type() != fal_sig->data_type()) { - cerr << get_fileline() << ": error: True and False clauses of" - << " ternary expression have different types." << endl; - cerr << get_fileline() << ": : True clause is " - << tru_sig->data_type() << ", false clause is " - << fal_sig->data_type() << "." << endl; - - des->errors += 1; - expr_type = IVL_VT_NO_TYPE; - return 0; - - } else if (expr_type == IVL_VT_NO_TYPE) { - cerr << get_fileline() << ": internal error: True and false " - << "clauses of ternary both have NO TYPE." << endl; - des->errors += 1; - return 0; - } - - /* The natural width of the expression is the width of the - largest condition. Normally they should be the same size, - but if we do not get a size from the context, or the - expressions resist, we need to cope. */ - unsigned iwidth = tru_sig->vector_width(); - if (fal_sig->vector_width() > iwidth) iwidth = fal_sig->vector_width(); - - /* If the width is not passed from the context, then take the - widest result as our width. */ - if (width == 0) width = iwidth; - - /* If the expression has width, then generate a boolean result - by connecting an OR gate to calculate the truth value of - the result. In the end, the result needs to be a single bit. */ - if (expr_sig->vector_width() > 1) { - NetUReduce*log = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - expr_sig->vector_width()); - log->set_line(*this); - des->add_node(log); - connect(log->pin(1), expr_sig->pin(0)); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(log->pin(0), tmp->pin(0)); - - expr_sig = tmp; - } - - assert(expr_sig->vector_width() == 1); - - /* This is the width of the LPM_MUX device that I'm about to - create. It may be smaller then the desired output, but I'll - handle padding below. Note that in principle the - alternatives should be padded to the output width first, - but it is more efficient to pad them only just enough to - prevent loss, and do the finished padding later. - - Create a NetNet object wide enough to hold the - result. Also, pad the result values (if necessary) so that - the mux inputs can be fully connected. */ - - unsigned dwidth = (iwidth > width)? width : iwidth; - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, dwidth); - sig->data_type(expr_type); - sig->local_flag(true); - - if (fal_sig->vector_width() < dwidth) - fal_sig = pad_to_width(des, fal_sig, dwidth); - - if (tru_sig->vector_width() < dwidth) - tru_sig = pad_to_width(des, tru_sig, dwidth); - - if (dwidth < fal_sig->vector_width()) - fal_sig = crop_to_width(des, fal_sig, dwidth); - - if (dwidth < tru_sig->vector_width()) - tru_sig = crop_to_width(des, tru_sig, dwidth); - - /* Make the device and connect its outputs to the osig and - inputs to the tru and false case nets. Also connect the - selector bit to the sel input. - - The inputs are the 0 (false) connected to fal_sig and 1 - (true) connected to tru_sig. */ - - NetMux*mux = new NetMux(scope, scope->local_symbol(), dwidth, 2, 1); - connect(mux->pin_Sel(), expr_sig->pin(0)); - - /* Connect the data inputs. */ - connect(mux->pin_Data(0), fal_sig->pin(0)); - connect(mux->pin_Data(1), tru_sig->pin(0)); - - /* If there are non-zero output delays, then create bufz - devices to carry the propagation delays. Otherwise, just - connect the result to the output. */ - if (rise || fall || decay) { - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, dwidth); - tmp->data_type(expr_type); - tmp->local_flag(true); - - NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), dwidth); - tmpz->rise_time(rise); - tmpz->fall_time(fall); - tmpz->decay_time(decay); - tmpz->pin(0).drive0(drive0); - tmpz->pin(0).drive1(drive1); - - connect(mux->pin_Result(), tmp->pin(0)); - connect(tmp->pin(0), tmpz->pin(1)); - connect(sig->pin(0), tmpz->pin(0)); - - des->add_node(tmpz); - } else { - connect(mux->pin_Result(), sig->pin(0)); - } - - /* If the MUX device result is too narrow to fill out the - desired result, pad with zeros... */ - assert(dwidth <= width); - - des->add_node(mux); - - /* If the MUX device results is too narrow to fill out the - desired result, then pad it. It is OK to have a too-narrow - result here because the dwidth choice is >= the width of - both alternatives. Thus, padding here is equivalent to - padding inside, and is cheaper. */ - if (dwidth < width) - sig = pad_to_width(des, sig, width); - - return sig; -} - -NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - // Some unary operands allow the operand to be - // self-determined, and some do not. - unsigned owidth = 0; - switch (op_) { - case '~': - case '-': - owidth = width; - break; - } - - NetExpr*expr = elab_and_eval(des, scope, expr_, owidth); - if (expr == 0) return 0; - - NetNet* sig = 0; - NetLogic*gate; - - - // Handle the special case of a 2's complement of a constant - // value. This can be reduced to a no-op on a precalculated - // result. - if (op_ == '-') { - if (NetEConst*tmp = dynamic_cast(expr)) { - return elab_net_uminus_const_logic_(des, scope, tmp, - width, rise, fall, decay, - drive0, drive1); - } - - if (NetECReal*tmp = dynamic_cast(expr)) { - return elab_net_uminus_const_real_(des, scope, tmp, - width, rise, fall, decay, - drive0, drive1); - } - } - - // Handle the case that the expression is real-valued. - if (expr->expr_type() == IVL_VT_REAL) { - return elab_net_unary_real_(des, scope, expr, - width, rise, fall, decay, - drive0, drive1); - } - - NetNet* sub_sig = expr->synthesize(des); - - if (sub_sig == 0) return 0; - - delete expr; - expr = 0; - - bool reduction=false; - NetUReduce::TYPE rtype = NetUReduce::NONE; - - switch (op_) { - case '~': // Bitwise NOT - sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, - sub_sig->vector_width()); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - gate = new NetLogic(scope, scope->local_symbol(), - 2, NetLogic::NOT, sub_sig->vector_width()); - gate->set_line(*this); - des->add_node(gate); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - - connect(gate->pin(1), sub_sig->pin(0)); - connect(gate->pin(0), sig->pin(0)); - break; - - case 'm': // abs(sub_sig) - // If this expression is self determined, get its width - // from the sub_expression. - if (owidth == 0) - owidth = sub_sig->vector_width(); - - if (sub_sig->vector_width() < owidth) - sub_sig = pad_to_width(des, sub_sig, owidth); - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - sig->set_line(*this); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - { NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width()); - tmp->set_line(*this); - des->add_node(tmp); - tmp->rise_time(rise); - tmp->fall_time(fall); - tmp->decay_time(decay); - - connect(tmp->pin(1), sub_sig->pin(0)); - connect(tmp->pin(0), sig->pin(0)); - } - break; - - case 'N': // Reduction NOR - case '!': // Reduction NOT - reduction=true; rtype = NetUReduce::NOR; break; - case '&': // Reduction AND - reduction=true; rtype = NetUReduce::AND; break; - case '|': // Reduction OR - reduction=true; rtype = NetUReduce::OR; break; - case '^': // Reduction XOR - reduction=true; rtype = NetUReduce::XOR; break; - case 'A': // Reduction NAND (~&) - reduction=true; rtype = NetUReduce::NAND; break; - case 'X': // Reduction XNOR (~^) - reduction=true; rtype = NetUReduce::XNOR; break; - - case '-': // Unary 2's complement. - // If this expression is self determined, get its width - // from the sub_expression. - if (owidth == 0) - owidth = sub_sig->vector_width(); - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - if (sub_sig->vector_width() < owidth) - sub_sig = pad_to_width(des, sub_sig, owidth); - - switch (sub_sig->vector_width()) { - case 0: - assert(0); - break; - - case 1: - gate = new NetLogic(scope, scope->local_symbol(), - 2, NetLogic::BUF, 1); - connect(gate->pin(0), sig->pin(0)); - connect(gate->pin(1), sub_sig->pin(0)); - des->add_node(gate); - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - break; - - default: - NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), - sig->vector_width()); - sub->attribute(perm_string::literal("LPM_Direction"), - verinum("SUB")); - sub->set_line(*this); - sub->rise_time(rise); - sub->fall_time(fall); - sub->decay_time(decay); - des->add_node(sub); - - connect(sig->pin(0), sub->pin_Result()); - connect(sub_sig->pin(0), sub->pin_DataB()); - - verinum tmp_num (verinum::V0, sub->width(), true); - NetConst*tmp_con = new NetConst(scope, - scope->local_symbol(), - tmp_num); - des->add_node(tmp_con); - - NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, - sub_sig->vector_width()); - tmp_sig->data_type(sub_sig->data_type()); - tmp_sig->local_flag(true); - - connect(tmp_sig->pin(0), sub->pin_DataA()); - connect(tmp_sig->pin(0), tmp_con->pin(0)); - break; - } - break; - - default: - cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl; - sig = 0; - } - - if (reduction) { - NetUReduce*rgate; - - // The output of a reduction operator is 1 bit - sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - rgate = new NetUReduce(scope, scope->local_symbol(), - rtype, sub_sig->vector_width()); - rgate->set_line(*this); - connect(rgate->pin(0), sig->pin(0)); - connect(rgate->pin(1), sub_sig->pin(0)); - - des->add_node(rgate); - rgate->rise_time(rise); - rgate->fall_time(fall); - rgate->decay_time(decay); - } - - return sig; -} - -NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope, - NetEConst*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - verinum val = expr->value(); - - if (width == 0) - width = val.len(); - - assert(width > 0); - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, width); - sig->data_type(IVL_VT_LOGIC); - sig->local_flag(true); - sig->set_line(*this); - - /* Take the 2s complement by taking the 1s complement - and adding 1. */ - verinum tmp (v_not(val), width); - verinum one (1UL, width); - tmp = verinum(tmp + one, width); - tmp.has_sign(val.has_sign()); - - NetConst*con = new NetConst(scope, scope->local_symbol(), tmp); - - connect(con->pin(0), sig->pin(0)); - - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Replace expression " - << *this << " with constant " << tmp << "."<value(); - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, width); - sig->data_type(IVL_VT_REAL); - sig->set_signed(true); - sig->local_flag(true); - sig->set_line(*this); - - NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), -val); - - connect(con->pin(0), sig->pin(0)); - - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Replace expression " - << *this << " with constant " << con->value_real() << "."<synthesize(des); - - if (sub_sig == 0) return 0; - delete expr; - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - sig->data_type(IVL_VT_REAL); - sig->set_signed(true); - sig->local_flag(true); - sig->set_line(*this); - - switch (op_) { - - default: - cerr << get_fileline() << ": internal error: Unhandled UNARY " - << op_ << " expression with real values." << endl; - des->errors += 1; - break; - case '~': - cerr << get_fileline() << ": error: bit-wise negation (" - << human_readable_op(op_) - << ") may not have a REAL operand." << endl; - des->errors += 1; - break; - case '&': - case 'A': - case '|': - case 'N': - case '^': - case 'X': - cerr << get_fileline() << ": error: reduction operator (" - << human_readable_op(op_) - << ") may not have a REAL operand." << endl; - des->errors += 1; - break; - case '!': - cerr << get_fileline() << ": sorry: ! is currently unsupported" - " for real values." << endl; - des->errors += 1; - break; - - case 'm': { // abs() - NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1); - tmp->set_line(*this); - tmp->rise_time(rise); - tmp->fall_time(fall); - tmp->decay_time(decay); - des->add_node(tmp); - - connect(tmp->pin(0), sig->pin(0)); - connect(tmp->pin(1), sub_sig->pin(0)); - break; - } - - case '-': - NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1); - sub->attribute(perm_string::literal("LPM_Direction"), - verinum("SUB")); - sub->set_line(*this); - sub->rise_time(rise); - sub->fall_time(fall); - sub->decay_time(decay); - des->add_node(sub); - connect(sig->pin(0), sub->pin_Result()); - connect(sub_sig->pin(0), sub->pin_DataB()); - - NetLiteral*tmp_con = new NetLiteral(scope, scope->local_symbol(), - verireal(0.0)); - tmp_con->set_line(*this); - des->add_node(tmp_con); - - NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - tmp_sig->data_type(IVL_VT_REAL); - tmp_sig->set_signed(true); - tmp_sig->local_flag(true); - tmp_sig->set_line(*this); - - connect(tmp_sig->pin(0), sub->pin_DataA()); - connect(tmp_sig->pin(0), tmp_con->pin(0)); - break; - } - - return sig; -} diff --git a/elab_pexpr.cc b/elab_pexpr.cc index 5244a9e2d..79f69c852 100644 --- a/elab_pexpr.cc +++ b/elab_pexpr.cc @@ -268,66 +268,57 @@ NetExpr*PEUnary::elaborate_pexpr (Design*des, NetScope*scope) const return tmp; } -/* Reuse these routines from eval_tree.cc. */ -NetExpr* evaluate_clog2(NetExpr*arg); -NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name); -NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name); -NetExpr* evaluate_abs(NetExpr*arg); -NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name); - NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const { /* Only $clog2 and the builtin mathematical functions can * be a constant system function. */ - perm_string name = peek_tail_name(path_); - if (name[0] == '$' && (generation_flag >= GN_VER2005 || - gn_icarus_misc_flag || gn_verilog_ams_flag)) { - if (name == "$clog2" || - name == "$ln" || - name == "$log10" || - name == "$exp" || - name == "$sqrt" || - name == "$floor" || - name == "$ceil" || - name == "$sin" || - name == "$cos" || - name == "$tan" || - name == "$asin" || - name == "$acos" || - name == "$atan" || - name == "$sinh" || - name == "$cosh" || - name == "$tanh" || - name == "$asinh" || - name == "$acosh" || - name == "$atanh") { + perm_string nm = peek_tail_name(path_); + if (nm[0] == '$' && (generation_flag >= GN_VER2005 || + gn_icarus_misc_flag || gn_verilog_ams_flag)) { + if (nm == "$clog2" || + nm == "$ln" || + nm == "$log10" || + nm == "$exp" || + nm == "$sqrt" || + nm == "$floor" || + nm == "$ceil" || + nm == "$sin" || + nm == "$cos" || + nm == "$tan" || + nm == "$asin" || + nm == "$acos" || + nm == "$atan" || + nm == "$sinh" || + nm == "$cosh" || + nm == "$tanh" || + nm == "$asinh" || + nm == "$acosh" || + nm == "$atanh") { if (parms_.size() != 1 || parms_[0] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes a single argument." << endl; des->errors += 1; return 0; } NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope); if (arg == 0) return 0; - eval_expr(arg); - NetExpr*rtn; - if (peek_tail_name(path_) == "$clog2") { - rtn = evaluate_clog2(arg); + NetESFunc*rtn; + if (nm == "$clog2") { + rtn = new NetESFunc(nm, IVL_VT_BOOL, integer_width, 1); } else { - rtn = evaluate_math_one_arg(arg, name.str()); - } - delete arg; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; + rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1); } + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg); + return rtn; } - if (name == "$pow" || - name == "$atan2" || - name == "$hypot") { + if (nm == "$pow" || + nm == "$atan2" || + nm == "$hypot") { if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; des->errors += 1; return 0; @@ -335,45 +326,44 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope); NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope); if (arg0 == 0 || arg1 == 0) return 0; - eval_expr(arg0); - eval_expr(arg1); - NetExpr*rtn = evaluate_math_two_args(arg0, arg1, name.str()); - delete arg0; - delete arg1; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; - } + NetESFunc*rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 2); + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg0); + rtn->parm(1, arg1); + return rtn; } /* These are only available with verilog-ams or icarus-misc. */ if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && - (name == "$log" || name == "$abs")) { + (nm == "$log" || nm == "$abs")) { if (parms_.size() != 1 || parms_[0] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes a single argument." << endl; des->errors += 1; return 0; } NetExpr*arg = parms_[0]->elaborate_pexpr(des, scope); if (arg == 0) return 0; - eval_expr(arg); - NetExpr*rtn; - if (peek_tail_name(path_) == "$log") { - rtn = evaluate_math_one_arg(arg, name.str()); + NetESFunc*rtn; + if (nm == "$log") { + rtn = new NetESFunc(nm, IVL_VT_REAL, 1, 1); } else { - rtn = evaluate_abs(arg); - } - delete arg; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; + /* This can return either a real or an arbitrary + * width vector, so set things to fail if this + * does not get replaced with a constant during + * elaboration. */ + rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 1); } + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg); + return rtn; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && - (name == "$min" || name == "$max")) { + (nm == "$min" || nm == "$max")) { if (parms_.size() != 2 || parms_[0] == 0 || parms_[1] == 0) { - cerr << get_fileline() << ": error: " << name + cerr << get_fileline() << ": error: " << nm << " takes two arguments." << endl; des->errors += 1; return 0; @@ -381,15 +371,13 @@ NetExpr* PECallFunction::elaborate_pexpr(Design*des, NetScope*scope) const NetExpr*arg0 = parms_[0]->elaborate_pexpr(des, scope); NetExpr*arg1 = parms_[1]->elaborate_pexpr(des, scope); if (arg0 == 0 || arg1 == 0) return 0; - eval_expr(arg0); - eval_expr(arg1); - NetExpr*rtn = evaluate_min_max(arg0, arg1, name.str()); - delete arg0; - delete arg1; - if (rtn != 0) { - rtn->set_line(*this); - return rtn; - } + /* See $log above for why this has no type or width. */ + NetESFunc*rtn = new NetESFunc(nm, IVL_VT_NO_TYPE, 0, 2); + rtn->set_line(*this); + rtn->cast_signed(true); + rtn->parm(0, arg0); + rtn->parm(1, arg1); + return rtn; } cerr << get_fileline() << ": error: this is not a constant " diff --git a/elab_scope.cc b/elab_scope.cc index a356ff349..3529129df 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -46,8 +46,42 @@ # include # include "ivl_assert.h" -void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, - Design*des, NetScope*scope) +typedef map::const_iterator mparm_it_t; + +static void collect_scope_parameters_(NetScope*scope, + const map¶meters) +{ + for (mparm_it_t cur = parameters.begin() + ; cur != parameters.end() ; cur ++) { + + NetEParam*tmp = new NetEParam; + tmp->set_line(*((*cur).second.expr)); + tmp->cast_signed( (*cur).second.signed_flag ); + + scope->set_parameter((*cur).first, tmp, (*cur).second.type, + 0, 0, false, 0, (*cur).second); + } +} + +static void collect_scope_localparams_(NetScope*scope, + const map&localparams) +{ + for (mparm_it_t cur = localparams.begin() + ; cur != localparams.end() ; cur ++) { + + NetEParam*tmp = new NetEParam; + tmp->set_line(*((*cur).second.expr)); + if ((*cur).second.msb) + tmp->cast_signed( (*cur).second.signed_flag ); + + scope->set_parameter((*cur).first, tmp, (*cur).second.type, + 0, 0, false, 0, (*cur).second); + } +} + +static void elaborate_parm_item_(perm_string name, + const LexicalScope::param_expr_t&cur, + Design*des, NetScope*scope) { PExpr*ex = cur.expr; assert(ex); @@ -72,7 +106,7 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, } NetScope::range_t*range_list = 0; - for (Module::range_t*range = cur.range ; range ; range = range->next) { + for (LexicalScope::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; @@ -131,6 +165,66 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, delete val; } +static void elaborate_scope_parameters_(Design*des, NetScope*scope, + const map¶meters) +{ + for (mparm_it_t cur = parameters.begin() + ; cur != parameters.end() ; cur ++) { + + elaborate_parm_item_((*cur).first, (*cur).second, des, scope); + } +} + +static void elaborate_scope_localparams_(Design*des, NetScope*scope, + const map&localparams) +{ + for (mparm_it_t cur = localparams.begin() + ; cur != localparams.end() ; cur ++) { + + elaborate_parm_item_((*cur).first, (*cur).second, des, scope); + } +} + +static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, + const Module::replace_t&replacements) +{ + for (Module::replace_t::const_iterator cur = replacements.begin() + ; cur != replacements.end() ; cur ++) { + + NetExpr*val = (*cur).second; + if (val == 0) { + cerr << loc.get_fileline() << ": internal error: " + << "Missing expression in parameter replacement for " + << (*cur).first; + } + assert(val); + if (debug_scopes) { + cerr << loc.get_fileline() << ": debug: " + << "Replace " << (*cur).first + << " with expression " << *val + << " from " << val->get_fileline() << "." << endl; + cerr << loc.get_fileline() << ": : " + << "Type=" << val->expr_type() << endl; + } + bool flag = scope->replace_parameter((*cur).first, val); + if (! flag) { + cerr << val->get_fileline() << ": warning: parameter " + << (*cur).first << " not found in " + << scope_path(scope) << "." << endl; + } + } +} + +static void elaborate_scope_events_(Design*des, NetScope*scope, + const map&events) +{ + for (map::const_iterator et = events.begin() + ; et != events.end() ; et ++ ) { + + (*et).second->elaborate_scope(des, scope); + } +} + static void elaborate_scope_tasks(Design*des, NetScope*scope, const LineInfo&loc, const map&tasks) @@ -242,79 +336,25 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // the pform and just place a NetEParam placeholder in the // place of the elaborated expression. - typedef map::const_iterator mparm_it_t; + // Scan the parameters in the module, and create stub parameter + // entries in the scope for the parameter names. - // This loop scans the parameters in the module, and creates - // stub parameter entries in the scope for the parameter name. - - for (mparm_it_t cur = parameters.begin() - ; cur != parameters.end() ; cur ++) { - - NetEParam*tmp = new NetEParam; - tmp->set_line(*((*cur).second.expr)); - tmp->cast_signed( (*cur).second.signed_flag ); - - scope->set_parameter((*cur).first, tmp, (*cur).second.type, - 0, 0, false, 0, (*cur).second); - } - - for (mparm_it_t cur = localparams.begin() - ; cur != localparams.end() ; cur ++) { - - NetEParam*tmp = new NetEParam; - tmp->set_line(*((*cur).second.expr)); - if ((*cur).second.msb) - tmp->cast_signed( (*cur).second.signed_flag ); - - scope->set_parameter((*cur).first, tmp, (*cur).second.type, - 0, 0, false, 0, (*cur).second); - } + collect_scope_parameters_(scope, parameters); + collect_scope_localparams_(scope, localparams); // Now scan the parameters again, this time elaborating them // for use as parameter values. This is after the previous // scan so that local parameter names can be used in the // r-value expressions. - for (mparm_it_t cur = parameters.begin() - ; cur != parameters.end() ; cur ++) { - - elaborate_parm_item_((*cur).first, (*cur).second, des, scope); - } + elaborate_scope_parameters_(des, scope, parameters); /* run parameter replacements that were collected from the containing scope and meant for me. */ - for (replace_t::const_iterator cur = replacements.begin() - ; cur != replacements.end() ; cur ++) { + replace_scope_parameters_(scope, *this, replacements); - NetExpr*val = (*cur).second; - if (val == 0) { - cerr << get_fileline() << ": internal error: " - << "Missing expression in parameter replacement for " - << (*cur).first; - } - assert(val); - if (debug_scopes) { - cerr << get_fileline() << ": debug: " - << "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) { - cerr << val->get_fileline() << ": warning: parameter " - << (*cur).first << " not found in " - << scope_path(scope) << "." << endl; - } - } - - for (mparm_it_t cur = localparams.begin() - ; cur != localparams.end() ; cur ++) { - - elaborate_parm_item_((*cur).first, (*cur).second, des, scope); - } + elaborate_scope_localparams_(des, scope, localparams); // Run through the defparams for this module, elaborate the // expressions in this context and save the result is a table @@ -401,11 +441,7 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, // elaboration, so do it now. This allows for normal // elaboration to reference these events. - for (map::const_iterator et = events.begin() - ; et != events.end() ; et ++ ) { - - (*et).second->elaborate_scope(des, scope); - } + elaborate_scope_events_(des, scope, events); return des->errors == 0; } @@ -693,6 +729,16 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) (*cur) -> generate_scope(des, scope); } + // Scan the localparams in this scope, and create stub parameter + // entries in the scope for the parameter names. + collect_scope_localparams_(scope, localparams); + + // Now scan the localparams again, this time elaborating them + // for use as parameter values. + elaborate_scope_localparams_(des, scope, localparams); + + // Scan through all the task and function declarations in this + // scope. elaborate_scope_tasks(des, scope, *this, tasks); elaborate_scope_funcs(des, scope, *this, funcs); @@ -710,6 +756,9 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope) (*cur) -> statement() -> elaborate_scope(des, scope); } + // Scan through all the named events in this scope. + elaborate_scope_events_(des, scope, events); + // Save the scope that we created, for future use. scope_list_.push_back(scope); } @@ -991,6 +1040,25 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const { assert(scope->type() == NetScope::FUNC); + // Scan the parameters in the function, and create stub parameter + // entries in the scope for the parameter names. + + collect_scope_parameters_(scope, parameters); + + collect_scope_localparams_(scope, localparams); + + // Now scan the parameters again, this time elaborating them + // for use as parameter values. This is after the previous + // scan so that local parameter names can be used in the + // r-value expressions. + + elaborate_scope_parameters_(des, scope, parameters); + + elaborate_scope_localparams_(des, scope, localparams); + + // Scan through all the named events in this scope. + elaborate_scope_events_(des, scope, events); + if (statement_) statement_->elaborate_scope(des, scope); } @@ -999,6 +1067,25 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const { assert(scope->type() == NetScope::TASK); + // Scan the parameters in the task, and create stub parameter + // entries in the scope for the parameter names. + + collect_scope_parameters_(scope, parameters); + + collect_scope_localparams_(scope, localparams); + + // Now scan the parameters again, this time elaborating them + // for use as parameter values. This is after the previous + // scan so that local parameter names can be used in the + // r-value expressions. + + elaborate_scope_parameters_(des, scope, parameters); + + elaborate_scope_localparams_(des, scope, localparams); + + // Scan through all the named events in this scope. + elaborate_scope_events_(des, scope, events); + if (statement_) statement_->elaborate_scope(des, scope); } @@ -1035,11 +1122,29 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const ? NetScope::FORK_JOIN : NetScope::BEGIN_END); my_scope->set_line(get_file(), get_lineno()); + + // Scan the parameters in the module, and create stub parameter + // entries in the scope for the parameter names. + + collect_scope_parameters_(my_scope, parameters); + + collect_scope_localparams_(my_scope, localparams); + + // Now scan the parameters again, this time elaborating them + // for use as parameter values. This is after the previous + // scan so that local parameter names can be used in the + // r-value expressions. + + elaborate_scope_parameters_(des, my_scope, parameters); + + elaborate_scope_localparams_(des, my_scope, localparams); + + // Scan through all the named events in this scope. + elaborate_scope_events_(des, my_scope, events); } for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) list_[idx] -> elaborate_scope(des, my_scope); - } /* diff --git a/elaborate.cc b/elaborate.cc index e693f45d5..59130d660 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -91,7 +91,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const return; } - assert(lval->pin_count() == 1); + ivl_assert(*this, lval->pin_count() == 1); if (debug_elaborate) { cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" @@ -99,208 +99,76 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << ", type=" << lval->data_type() << endl; } - /* Handle the special case that the rval is simply an - identifier. Get the rval as a NetNet, then use NetBUFZ - objects to connect it to the l-value. This is necessary to - direct drivers. This is how I attach strengths to the - assignment operation. */ - if (const PEIdent*id = dynamic_cast(pin(1))) { - NetNet*rid = id->elaborate_net(des, scope, lval->vector_width(), - 0, 0, 0, Link::STRONG, - Link::STRONG); - if (rid == 0) { - des->errors += 1; - return; - } + NetExpr*rval_expr = elaborate_rval_expr(des, scope, lval->data_type(), + lval->vector_width(), pin(1)); - /* Cast the right side when needed. */ - if ((lval->data_type() == IVL_VT_REAL && - rid->data_type() != IVL_VT_REAL)) { - rid = cast_to_real(des, scope, rid); - } else if ((lval->data_type() != IVL_VT_REAL && - rid->data_type() == IVL_VT_REAL)) { - rid = cast_to_int(des, scope, rid, lval->vector_width()); - } - - ivl_assert(*this, rid); - if (rid->pin_count() != 1) { - cerr << get_fileline() << ": internal error: " - << "Invalid elaborate_net results here:" << endl; - rid->dump_net(cerr, 4); - des->errors += 1; - return; - } - ivl_assert(*this, rid->pin_count() == 1); - - /* If the right hand net is the same type as the left - side net (i.e., WIRE/WIRE) then it is enough to just - connect them together. Otherwise, put a bufz between - them to carry strengths from the rval. - - While we are at it, handle the case where the r-value - is not as wide as the l-value by padding with a - constant-0. */ - - unsigned cnt = lval->vector_width(); - if (rid->vector_width() < cnt) - cnt = rid->vector_width(); - - bool need_driver_flag = false; - - /* If the device is linked to itself, a driver is - needed. Should I print a warning here? */ - if (lval->pin(0) .is_linked (rid->pin(0))) - need_driver_flag = true; - - /* If the nets are different type (i.e., reg vs. tri) then - a driver is needed. */ - if (rid->type() != lval->type()) - need_driver_flag = true; - - /* If there is a delay, then I need a driver to carry - it. */ - if (rise_time || fall_time || decay_time) - need_driver_flag = true; - - /* If there is a strength to be carried, then I need a - driver to carry that strength. */ - if (rid->pin(0).drive0() != drive0) - need_driver_flag = true; - - if (rid->pin(0).drive1() != drive1) - need_driver_flag = true; - - /* If the r-value is more narrow then the l-value, pad - it to the desired width. */ - if (cnt < lval->vector_width()) { - if (lval->get_signed() && rid->get_signed()) { - - unsigned use_width = lval->vector_width(); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: PGassign " - << "Generate sign-extend node." << endl; - - rid = pad_to_width_signed(des, rid, use_width); - - } else { - - if (debug_elaborate) - cerr << get_fileline() << ": debug: PGAssign " - << "Unsigned pad r-value from " - << cnt << " bits to " - << lval->vector_width() << " bits." << endl; - - NetNet*tmp = pad_to_width(des, rid, - lval->vector_width()); - rid = tmp; - } - - } else if (cnt < rid->vector_width()) { - - if (debug_elaborate) - cerr << get_fileline() << ": debug: PGAssign " - << "Truncate r-value from " - << cnt << " bits to " - << lval->vector_width() << " bits." << endl; - - NetNet*tmp = crop_to_width(des, rid, lval->vector_width()); - rid = tmp; - } - - if (! need_driver_flag) { - - /* Don't need a driver, presumably because the - r-value already has the needed drivers. Just - hook things up. If the r-value is too narrow - for the l-value, then sign extend it or zero - extend it, whichever makes sense. */ - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: PGAssign: " - << "Connect lval directly to " - << id->path() << endl; - } - - connect(lval->pin(0), rid->pin(0)); - - } else { - /* Do need a driver. Use BUFZ objects to carry the - strength and delays. */ - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: PGAssign: " - << "Connect lval to " << id->path() - << " through bufz. delay=("; - if (rise_time) - cerr << *rise_time << ":"; - else - cerr << ":"; - if (fall_time) - cerr << *fall_time << ":"; - else - cerr << ":"; - if (decay_time) - cerr << *decay_time; - else - cerr << ""; - cerr << ")" << endl; - } - - NetBUFZ*dev = new NetBUFZ(scope, scope->local_symbol(), - rid->vector_width()); - connect(lval->pin(0), dev->pin(0)); - connect(rid->pin(0), dev->pin(1)); - dev->rise_time(rise_time); - dev->fall_time(fall_time); - dev->decay_time(decay_time); - dev->pin(0).drive0(drive0); - dev->pin(0).drive1(drive1); - des->add_node(dev); - - } - - return; - } - - /* Elaborate the r-value. Account for the initial decays, - which are going to be attached to the last gate before the - generated NetNet. */ - NetNet*rval = pin(1)->elaborate_net(des, scope, - lval->vector_width(), - 0, 0, 0, - drive0, drive1); - if (rval == 0) { + if (rval_expr == 0) { cerr << get_fileline() << ": error: Unable to elaborate r-value: " << *pin(1) << endl; des->errors += 1; return; } + if (type_is_vectorable(rval_expr->expr_type()) + && type_is_vectorable(lval->data_type()) + && rval_expr->expr_width() < lval->vector_width()) { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "r-value expressions width "<expr_width() + << " of " << (rval_expr->has_sign()? "signed":"unsigned") + << " expression is to small for l-value width " + << lval->vector_width() << "." << endl; + } + rval_expr = pad_to_width(rval_expr, lval->vector_width()); + } + + NetNet*rval = rval_expr->synthesize(des, scope); + + if (rval == 0) { + cerr << get_fileline() << ": internal error: " + << "Failed to synthesize expression: " << *rval_expr << endl; + des->errors += 1; + return; + } + if (debug_elaborate) { cerr << get_fileline() << ": debug: PGAssign: elaborated r-value" - << " width="<vector_width() - << ", type="<< rval->data_type() << endl; + << " width="<< rval->vector_width() + << ", type="<< rval->data_type() + << ", expr=" << *rval_expr << endl; } assert(lval && rval); assert(rval->pin_count() == 1); + // Detect the case that the rvalue-expression is a simple + // expression. In this case, we will need to create a driver + // (later) to carry strengths. + bool need_driver_flag = false; + if (dynamic_cast(rval_expr)) + need_driver_flag = true; + /* Cast the right side when needed. */ if ((lval->data_type() == IVL_VT_REAL && rval->data_type() != IVL_VT_REAL)) { rval = cast_to_real(des, scope, rval); + need_driver_flag = false; } else if ((lval->data_type() != IVL_VT_REAL && rval->data_type() == IVL_VT_REAL)) { rval = cast_to_int(des, scope, rval, lval->vector_width()); + need_driver_flag = false; } /* If the r-value insists on being smaller then the l-value (perhaps it is explicitly sized) the pad it out to be the right width so that something is connected to all the bits of the l-value. */ - if (lval->vector_width() > rval->vector_width()) - rval = pad_to_width(des, rval, lval->vector_width()); + if (lval->vector_width() > rval->vector_width()) { + if (rval->get_signed()) + rval = pad_to_width_signed(des, rval, lval->vector_width()); + else + rval = pad_to_width(des, rval, lval->vector_width()); + } /* If, on the other hand, the r-value insists on being LARGER then the l-value, use a part select to chop it down @@ -313,17 +181,40 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::TRI, lval->vector_width()); osig->set_line(*this); + osig->local_flag(true); osig->data_type(rval->data_type()); connect(osig->pin(0), tmp->pin(0)); rval = osig; + need_driver_flag = false; } - /* If there is a rise/fall/decay time, then attach that delay - to the drivers for this net. */ - if (rise_time || fall_time || decay_time) { - rval->pin(0).drivers_delays(rise_time, fall_time, decay_time); + if (need_driver_flag) { + NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(), + rval->vector_width()); + driver->set_line(*this); + des->add_node(driver); + + connect(rval->pin(0), driver->pin(1)); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, rval->vector_width()); + tmp->set_line(*this); + tmp->data_type(rval->data_type()); + tmp->local_flag(true); + + connect(driver->pin(0), tmp->pin(0)); + + rval = tmp; } + /* Set the drive and delays for the r-val. */ + + if (drive0 != Link::STRONG || drive1 != Link::STRONG) + rval->pin(0).drivers_drive(drive0, drive1); + + if (rise_time || fall_time || decay_time) + rval->pin(0).drivers_delays(rise_time, fall_time, decay_time); + connect(lval->pin(0), rval->pin(0)); if (lval->local_flag()) @@ -331,19 +222,12 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const } -/* - * Elaborate a Builtin gate. These normally get translated into - * NetLogic nodes that reflect the particular logic function. - */ -void PGBuiltin::elaborate(Design*des, NetScope*scope) const +unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope, + long&high, long&low) const { unsigned count = 1; - unsigned instance_width = 1; - long low = 0, high = 0; - string name = string(get_name()); - - if (name == "") - name = scope->local_symbol(); + high = 0; + low = 0; /* If the Verilog source has a range specification for the gates, then I am expected to make more than one @@ -359,14 +243,14 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": error: Unable to evaluate " "expression " << *msb_ << endl; des->errors += 1; - return; + return 0; } if (lsb_con == 0) { cerr << get_fileline() << ": error: Unable to evaluate " "expression " << *lsb_ << endl; des->errors += 1; - return; + return 0; } verinum msb = msb_con->value(); @@ -386,29 +270,360 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: PGBuiltin: Make array " << "[" << high << ":" << low << "]" - << " of " << count << " gates for " << name << endl; + << " of " << count << " gates for " << get_name() << endl; } } - /* Now we have a gate count. Elaborate the output expression - only. We do it early so that we can see if we can make a - wide gate instead of an array of gates. */ + return count; +} - if (pin(0) == 0) { - cerr << get_fileline() << ": error: Logic gate port " - "expressions are not optional." << endl; - des->errors += 1; - return; +unsigned PGBuiltin::calculate_output_count_(void) const +{ + unsigned output_count; + + switch (type()) { + case BUF: + case NOT: + output_count = pin_count() - 1; + break; + case PULLDOWN: + case PULLUP: + output_count = pin_count(); + break; + default: + output_count = 1; + break; + } + + return output_count; +} + +NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, + perm_string gate_name, + unsigned instance_width) const +{ + NetNode*gate = 0; + + switch (type()) { + + case AND: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the AND " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::AND, instance_width); + } + break; + + case BUF: + gate = new NetLogic(scope, gate_name, 2, + NetLogic::BUF, instance_width); + break; + + case BUFIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the BUFIF0 " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::BUFIF0, instance_width); + } + break; + + case BUFIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the BUFIF1 " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::BUFIF1, instance_width); + } + break; + + case CMOS: + if (pin_count() != 4) { + cerr << get_fileline() << ": error: the CMOS " + "primitive must have four arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::CMOS, instance_width); + } + break; + + case NAND: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the NAND " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::NAND, instance_width); + } + break; + + case NMOS: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the NMOS " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::NMOS, instance_width); + } + break; + + case NOR: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the NOR " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::NOR, instance_width); + } + break; + + case NOT: + gate = new NetLogic(scope, gate_name, 2, + NetLogic::NOT, instance_width); + break; + + case NOTIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the NOTIF0 " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::NOTIF0, instance_width); + } + break; + + case NOTIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the NOTIF1 " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::NOTIF1, instance_width); + } + break; + + case OR: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the OR " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::OR, instance_width); + } + break; + + case RCMOS: + if (pin_count() != 4) { + cerr << get_fileline() << ": error: the RCMOS " + "primitive must have four arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::RCMOS, instance_width); + } + break; + + case RNMOS: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the RNMOS " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::RNMOS, instance_width); + } + break; + + case RPMOS: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the RPMOS " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::RPMOS, instance_width); + } + break; + + case PMOS: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: the PMOS " + "primitive must have three arguments." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::PMOS, instance_width); + } + break; + + case PULLDOWN: + gate = new NetLogic(scope, gate_name, 1, + NetLogic::PULLDOWN, instance_width); + break; + + case PULLUP: + gate = new NetLogic(scope, gate_name, 1, + NetLogic::PULLUP, instance_width); + break; + + case XNOR: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the XNOR " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, pin_count(), + NetLogic::XNOR, instance_width); + } + break; + + case XOR: + if (pin_count() < 2) { + cerr << get_fileline() << ": error: the XOR " + "primitive must have an input." << endl; + des->errors += 1; + } else { + gate = new NetLogic(scope, gate_name, 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; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_TRAN); + } + break; + + case RTRAN: + if (pin_count() != 2) { + cerr << get_fileline() << ": error: Pin count for " + << "rtran device." << endl; + des->errors += 1; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_RTRAN); + } + break; + + case TRANIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "tranif0 device." << endl; + des->errors += 1; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_TRANIF0); + } + break; + + case RTRANIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "rtranif0 device." << endl; + des->errors += 1; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_RTRANIF0); + } + break; + + case TRANIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "tranif1 device." << endl; + des->errors += 1; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_TRANIF1); + } + break; + + case RTRANIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "rtranif1 device." << endl; + des->errors += 1; + } else { + gate = new NetTran(scope, gate_name, IVL_SW_RTRANIF1); + } + break; + + default: + cerr << get_fileline() << ": internal error: unhandled " + "gate type." << endl; + des->errors += 1; + break; + } + + return gate; +} + +/* + * Elaborate a Builtin gate. These normally get translated into + * NetLogic nodes that reflect the particular logic function. + */ +void PGBuiltin::elaborate(Design*des, NetScope*scope) const +{ + unsigned instance_width = 1; + perm_string name = get_name(); + + if (name == "") + name = scope->local_symbol(); + + /* Calculate the array bounds and instance count for the gate, + as described in the Verilog source. If there is none, then + the count is 1, and high==low==0. */ + + long low=0, high=0; + unsigned array_count = calculate_array_count_(des, scope, high, low); + if (array_count == 0) + return; + + unsigned output_count = calculate_output_count_(); + + /* Now we have a gate count. Elaborate the output expressions + only. We do it early so that we can see if we can make + wide gates instead of an array of gates. */ + + vectorlval_sigs (output_count); + + for (unsigned idx = 0 ; idx < output_count ; idx += 1) { + if (pin(idx) == 0) { + cerr << get_fileline() << ": error: Logic gate port " + "expressions are not optional." << endl; + des->errors += 1; + return; + } + lval_sigs[idx] = pin(idx)->elaborate_lnet(des, scope); + ivl_assert(*this, lval_sigs[idx]); + + // For now, assume all the outputs are the same width. + ivl_assert(*this, idx == 0 || lval_sigs[idx]->vector_width() == lval_sigs[0]->vector_width()); } - NetNet*lval_sig = pin(0)->elaborate_lnet(des, scope); - assert(lval_sig); /* Detect the special case that the l-value width exactly matches the gate count. In this case, we will make a single - gate that has the desired vector width. */ - if (lval_sig->vector_width() == count) { - instance_width = count; - count = 1; + gate that has the desired vector width. + + NOTE: This assumes that all the outputs have the same + width. For gates with 1 output, this is trivially true. */ + if (lval_sigs[0]->vector_width() == array_count) { + instance_width = array_count; + array_count = 1; if (debug_elaborate && instance_width != 1) cerr << get_fileline() << ": debug: PGBuiltin: " @@ -416,10 +631,6 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const "(" << instance_width << ") instance." << endl; } - /* Allocate all the netlist nodes for the gates. */ - NetNode**cur = new NetNode*[count]; - assert(cur); - /* Calculate the gate delays from the delay expressions given in the source. For logic gates, the decay time is meaningless because it can never go to high @@ -441,289 +652,25 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); + /* Allocate all the netlist nodes for the gates. */ + vectorcur (array_count*output_count); + /* Now make as many gates as the bit count dictates. Give each a unique name, and set the delay times. */ - for (unsigned idx = 0 ; idx < count ; idx += 1) { - ostringstream tmp; - unsigned index; - if (low < high) - index = low + idx; - else - index = low - idx; + for (unsigned idx = 0 ; idx < array_count*output_count ; idx += 1) { + unsigned array_idx = idx/output_count; + unsigned output_idx = idx%output_count; - tmp << name << "<" << index << ">"; + ostringstream tmp; + unsigned index = (low < high)? (low+array_idx) : (low-array_idx); + + tmp << name << "<" << index << "." << output_idx << ">"; perm_string inm = lex_strings.make(tmp.str()); - switch (type()) { - case AND: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the AND " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::AND, instance_width); - break; - case BUF: - if (pin_count() > 2) { - cerr << get_fileline() << ": sorry: multiple output BUF " - "primitives are not supported." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::BUF, instance_width); - break; - case BUFIF0: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the BUFIF0 " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::BUFIF0, instance_width); - break; - case BUFIF1: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the BUFIF1 " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::BUFIF1, instance_width); - break; - case CMOS: - if (pin_count() != 4) { - cerr << get_fileline() << ": error: the CMOS " - "primitive must have four arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::CMOS, instance_width); - break; - case NAND: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the NAND " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NAND, instance_width); - break; - case NMOS: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the NMOS " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NMOS, instance_width); - break; - case NOR: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the NOR " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NOR, instance_width); - break; - case NOT: - if (pin_count() > 2) { - cerr << get_fileline() << ": sorry: multiple output NOT " - "primitives are not supported." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NOT, instance_width); - break; - case NOTIF0: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the NOTIF0 " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NOTIF0, instance_width); - break; - case NOTIF1: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the NOTIF1 " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::NOTIF1, instance_width); - break; - case OR: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the OR " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::OR, instance_width); - break; - case RCMOS: - if (pin_count() != 4) { - cerr << get_fileline() << ": error: the RCMOS " - "primitive must have four arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::RCMOS, instance_width); - break; - case RNMOS: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the RNMOS " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::RNMOS, instance_width); - break; - case RPMOS: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the RPMOS " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::RPMOS, instance_width); - break; - case PMOS: - if (pin_count() != 3) { - cerr << get_fileline() << ": error: the PMOS " - "primitive must have three arguments." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::PMOS, instance_width); - break; - case PULLDOWN: - if (pin_count() > 1) { - cerr << get_fileline() << ": sorry: multiple output PULLDOWN " - "primitives are not supported." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::PULLDOWN, - instance_width); - break; - case PULLUP: - if (pin_count() > 1) { - cerr << get_fileline() << ": sorry: multiple output PULLUP " - "primitives are not supported." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::PULLUP, instance_width); - break; - case XNOR: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the XNOR " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - cur[idx] = new NetLogic(scope, inm, pin_count(), - NetLogic::XNOR, instance_width); - break; - case XOR: - if (pin_count() < 2) { - cerr << get_fileline() << ": error: the XOR " - "primitive must have an input." << endl; - des->errors += 1; - return; - } else - 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; - des->errors += 1; + cur[idx] = create_gate_for_output_(des, scope, inm, instance_width); + if (cur[idx] == 0) return; - } for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) cur[idx]->attribute(attrib_list[adx].key, @@ -751,6 +698,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const the parameters and attaches the ports of the objects. */ for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { + const PExpr*ex = pin(idx); if (ex == 0) { cerr << get_fileline() << ": error: Logic gate port " @@ -758,15 +706,24 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } - NetNet*sig = (idx == 0) - ? lval_sig - : ex->elaborate_net(des, scope, 0, 0, 0, 0); + NetNet*sig = 0; + if (idx < output_count) { + sig = lval_sigs[idx]; + + } else { + unsigned use_width = array_count * instance_width; + NetExpr*tmp = elab_and_eval(des, scope, ex, + use_width, use_width); + sig = tmp->synthesize(des, scope); + delete tmp; + } + if (sig == 0) continue; - assert(sig); + ivl_assert(*this, sig); - if (count == 1) { + if (array_count == 1) { /* Handle the case where there is one gate that carries the whole vector width. */ @@ -801,33 +758,59 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; } - connect(cur[0]->pin(idx), sig->pin(0)); + // There is only 1 instance, but there may be + // multiple outputs to that gate. That would + // potentially mean multiple actual gates. + // Although in Verilog proper a multiple + // output gate has only 1 input, this conditional + // handles gates with N outputs and M inputs. + if (idx < output_count) { + connect(cur[idx]->pin(0), sig->pin(0)); + } else { + for (unsigned dev = 0 ; dev < output_count; dev += 1) + connect(cur[dev]->pin(idx-output_count+1), sig->pin(0)); + } } else if (sig->vector_width() == 1) { - /* Handle the case where a single bit is connected - repetitively to all the instances. */ - for (unsigned gdx = 0 ; gdx < count ; gdx += 1) - connect(cur[gdx]->pin(idx), sig->pin(0)); - } else if (sig->vector_width() == count) { + /* Handle the case where a single bit is connected + repetitively to all the instances. If idx is an + output port, connect it to all array_count + devices that have outputs at this + position. Otherwise, idx is an input to all + array_count*output_count devices. */ + + if (idx < output_count) { + for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) { + unsigned dev = gdx*output_count; + connect(cur[dev+idx]->pin(0), sig->pin(0)); + } + } else { + unsigned use_idx = idx - output_count + 1; + for (unsigned gdx = 0 ; gdx < cur.size() ; gdx += 1) + connect(cur[gdx]->pin(use_idx), sig->pin(0)); + } + + } else if (sig->vector_width() == array_count) { /* Handle the general case that each bit of the value is connected to a different instance. In this case, the output is handled slightly different from the inputs. */ - if (idx == 0) { + if (idx < output_count) { NetConcat*cc = new NetConcat(scope, scope->local_symbol(), sig->vector_width(), - count); + array_count); des->add_node(cc); /* Connect the concat to the signal. */ connect(cc->pin(0), sig->pin(0)); /* Connect the outputs of the gates to the concat. */ - for (unsigned gdx = 0 ; gdx < count ; gdx += 1) { - connect(cur[gdx]->pin(0), cc->pin(gdx+1)); + for (unsigned gdx = 0 ; gdx < array_count; gdx += 1) { + unsigned dev = gdx*output_count; + connect(cur[dev+idx]->pin(0), cc->pin(gdx+1)); NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), @@ -837,7 +820,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const connect(cc->pin(gdx+1), tmp2->pin(0)); } - } else for (unsigned gdx = 0 ; gdx < count ; gdx += 1) { + } else for (unsigned gdx = 0 ; gdx < array_count ; gdx += 1) { /* Use part selects to get the bits connected to the inputs of out gate. */ NetPartSelect*tmp1 = new NetPartSelect(sig, gdx, 1, @@ -850,12 +833,15 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const tmp2->local_flag(true); tmp2->data_type(sig->data_type()); connect(tmp1->pin(0), tmp2->pin(0)); - connect(cur[gdx]->pin(idx), tmp1->pin(0)); + unsigned use_idx = idx - output_count + 1; + unsigned dev = gdx*output_count; + for (unsigned gdx2 = 0 ; gdx2 < output_count ; gdx2 += 1) + connect(cur[dev+gdx2]->pin(use_idx), tmp1->pin(0)); } } else { cerr << get_fileline() << ": error: Gate count of " << - count << " does not match net width of " << + array_count << " does not match net width of " << sig->vector_width() << " at pin " << idx << "." << endl; des->errors += 1; @@ -863,13 +849,11 @@ 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, NetNet*sig, unsigned port_wid, - NetNet::PortType dir) const + NetNet::PortType dir, bool as_signed) const { ivl_assert(*this, dir != NetNet::NOT_A_PORT); ivl_assert(*this, dir != NetNet::PIMPLICIT); @@ -886,6 +870,9 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, unsigned wida = sig->vector_width(); unsigned widb = tmp->vector_width(); bool part_b = widb < wida; + // This needs to pad the value! + // Also delete the inout specific warning when this is fixed. + // It is located just before this routine is called. NetTran*node = new NetTran(scope, scope->local_symbol(), part_b? wida : widb, part_b? widb : wida, @@ -904,30 +891,39 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, return tmp; } - NetPartSelect*node = 0; - + unsigned pwidth = tmp->vector_width(); + unsigned swidth = sig->vector_width(); switch (dir) { case NetNet::POUTPUT: - if (tmp->vector_width() > sig->vector_width()) { - node = new NetPartSelect(tmp, 0, sig->vector_width(), + if (pwidth > swidth) { + NetPartSelect*node = new NetPartSelect(tmp, 0, swidth, NetPartSelect::VP); connect(node->pin(0), sig->pin(0)); + des->add_node(node); } else { - node = new NetPartSelect(sig, 0, tmp->vector_width(), - NetPartSelect::PV); - connect(node->pin(0), tmp->pin(0)); + NetNet*osig; + if (as_signed) { + osig = pad_to_width_signed(des, tmp, swidth); + } else { + osig = pad_to_width(des, tmp, swidth); + } + connect(osig->pin(0), sig->pin(0)); } break; case NetNet::PINPUT: - if (tmp->vector_width() > sig->vector_width()) { - node = new NetPartSelect(tmp, 0, sig->vector_width(), - NetPartSelect::PV); - connect(node->pin(0), sig->pin(0)); + if (pwidth > swidth) { + delete tmp; + if (as_signed) { + tmp = pad_to_width_signed(des, sig, pwidth); + } else { + tmp = pad_to_width(des, sig, pwidth); + } } else { - node = new NetPartSelect(sig, 0, tmp->vector_width(), + NetPartSelect*node = new NetPartSelect(sig, 0, pwidth, NetPartSelect::VP); connect(node->pin(0), tmp->pin(0)); + des->add_node(node); } break; @@ -939,8 +935,6 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, ivl_assert(*this, 0); } - des->add_node(node); - return tmp; } @@ -1177,9 +1171,16 @@ v NOTE that this also handles the case that the port is actually empty on the inside. We assume in that case that the port is input. */ - sig = pins[idx]->elaborate_net(des, scope, - desired_vector_width, - 0, 0, 0); + NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], + desired_vector_width, + desired_vector_width); + if (tmp_expr == 0) { + cerr << pins[idx]->get_fileline() + << ": internal error: Port expression " + << "too complicated for elaboration." << endl; + continue; + } + sig = tmp_expr->synthesize(des, scope); if (sig == 0) { cerr << pins[idx]->get_fileline() << ": internal error: Port expression " @@ -1187,6 +1188,9 @@ v NOTE that this also handles the case that the continue; } + delete tmp_expr; + sig->set_line(*this); + if (need_bufz_for_input_port(prts)) { NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(), sig->vector_width()); @@ -1297,22 +1301,36 @@ v NOTE that this also handles the case that the << type_ << " expects " << prts_vector_width << " bits, got " << sig->vector_width() << "." << endl; - if (prts_vector_width > sig->vector_width()) { + // Delete this when inout ports pad correctly. + if (prts[0]->port_type() == NetNet::PINOUT) { + if (prts_vector_width > sig->vector_width()) { cerr << get_fileline() << ": : Leaving " << (prts_vector_width-sig->vector_width()) << " high bits of the port unconnected." << endl; - - - } else { + } else { cerr << get_fileline() << ": : Leaving " << (sig->vector_width()-prts_vector_width) << " high bits of the expression dangling." << endl; + } + // Keep the if, but delete the "} else" when fixed. + } else if (prts_vector_width > sig->vector_width()) { + cerr << get_fileline() << ": : Padding " + << (prts_vector_width-sig->vector_width()) + << " high bits of the port." + << endl; + } else { + cerr << get_fileline() << ": : Padding " + << (sig->vector_width()-prts_vector_width) + << " high bits of the expression." + << endl; } sig = resize_net_to_port_(des, scope, sig, prts_vector_width, - prts[0]->port_type()); + prts[0]->port_type(), + prts[0]->get_signed() && + sig->get_signed()); } // Connect the sig expression that is the context of the @@ -1597,12 +1615,17 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const if (pins[idx] == 0) continue; - NetNet*sig = pins[idx]->elaborate_net(des, scope, 1, 0, 0, 0); - if (sig == 0) { + NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1, 1); + if (expr_tmp == 0) { cerr << "internal error: Expression too complicated " "for elaboration:" << pins[idx] << endl; continue; } + NetNet*sig = expr_tmp->synthesize(des, scope); + ivl_assert(*this, sig); + sig->set_line(*this); + + delete expr_tmp; connect(sig->pin(0), net->pin(idx)); } @@ -1705,6 +1728,17 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const return lval_->elaborate_lval(des, scope, false); } +NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, + unsigned lv_width, + ivl_variable_type_t lv_type) const +{ + ivl_assert(*this, rval_); + + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, lv_width, rval()); + + return rv; +} + /* * This function elaborates delay expressions. This is a little * different from normal elaboration because the result may need to be @@ -1786,20 +1820,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const delay = elaborate_delay_expr(delay_, des, scope); - assert(rval()); - /* Elaborate the r-value expression, then try to evaluate it. */ - - /* Find out what the r-value width is going to be. We guess it - will be the l-value width, but it may turn out to be - something else based on self-determined widths inside. */ - unsigned use_width = lv->lwidth(); - bool unsized_flag = false; - use_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag); - - /* Now elaborate to the expected width. Pass the lwidth to - prune any constant result to fit with the lvalue at hand. */ - NetExpr*rv = elab_and_eval(des, scope, rval(), use_width, lv->lwidth()); + NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); if (rv == 0) return 0; assert(rv); @@ -1932,9 +1954,11 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const } else { unsigned wid = count_lval_width(lv); - rv->set_width(wid); - rv = pad_to_width(rv, wid); - assert(rv->expr_width() >= wid); + if (wid > rv->expr_width()) { + rv->set_width(wid); + rv = pad_to_width(rv, wid); + } + ivl_assert(*this, rv->expr_width() >= wid); } NetAssign*cur = new NetAssign(lv, rv); @@ -1964,12 +1988,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const NetAssign_*lv = elaborate_lval(des, scope); if (lv == 0) return 0; - assert(rval()); - - /* Elaborate and precalculate the r-value. */ - NetExpr*rv = elab_and_eval(des, scope, rval(), count_lval_width(lv)); - if (rv == 0) - return 0; + NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); /* Handle the (common) case that the r-value is a vector. This includes just about everything but reals. In this case, we @@ -1986,11 +2005,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const } NetExpr*delay = 0; - if (delay_ != 0) + if (delay_ != 0) { + assert(count_ == 0 && event_ == 0); delay = elaborate_delay_expr(delay_, des, scope); + } + NetExpr*count = 0; + NetEvWait*event = 0; if (count_ != 0 || event_ != 0) { - NetExpr*count = 0; if (count_ != 0) { assert(event_ != 0); count = elab_and_eval(des, scope, count_, -1); @@ -1998,27 +2020,39 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": Unable to elaborate " "repeat expression." << endl; des->errors += 1; -// return 0; + return 0; } } - NetProc* event = event_->elaborate(des, scope); - if (event == 0) { + NetProc*st = event_->elaborate(des, scope); + if (st == 0) { cerr << get_fileline() << ": unable to elaborate " "event expression." << endl; des->errors += 1; -// return 0; + return 0; } + event = dynamic_cast(st) ; + assert(event); - cerr << get_fileline() << ": sorry: non blocking "; - if (count_) cerr << "repeat "; - cerr << "event controls are not supported." << endl; - des->errors += 1; - return 0; + // Some constant values are special. + if (NetEConst*ce = dynamic_cast(count)) { + long val = ce->value().as_long(); + // We only need the assignment statement. + if (val <= 0) { + delete count; + delete event; + count = 0; + event = 0; + // We only need the event. + } else if (val == 1) { + delete count; + count = 0; + } + } } /* All done with this node. Mark its line number and check it in. */ - NetAssignNB*cur = new NetAssignNB(lv, rv); + NetAssignNB*cur = new NetAssignNB(lv, rv, event, count); cur->set_delay(delay); cur->set_line(*this); return cur; @@ -2389,6 +2423,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const return block; } + /* If this is an automatic task, generate a statement to + allocate the local storage. */ + if (task->is_auto()) { + NetAlloc*ap = new NetAlloc(task); + block->append(ap); + } + /* Generate assignment statement statements for the input and INOUT ports of the task. These are managed by writing assignments with the task port the l-value and the passed @@ -2468,6 +2509,13 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const block->append(ass); } + /* If this is an automatic task, generate a statement to free + the local storage. */ + if (task->is_auto()) { + NetFree*fp = new NetFree(task); + block->append(fp); + } + return block; } @@ -2772,17 +2820,29 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, bool save_flag = error_implicit; error_implicit = true; - NetNet*expr = expr_[idx]->expr()->elaborate_net(des, scope, - 0, 0, 0, 0); - error_implicit = save_flag; + NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0); + if (tmp == 0) { + expr_[idx]->dump(cerr); + cerr << endl; + des->errors += 1; + error_implicit = save_flag; + continue; + } + + NetNet*expr = tmp->synthesize(des, scope); + expr->set_line(*this); if (expr == 0) { expr_[idx]->dump(cerr); cerr << endl; des->errors += 1; + error_implicit = save_flag; continue; } assert(expr); + delete tmp; + + error_implicit = save_flag; unsigned pins = (expr_[idx]->type() == PEEvent::ANYEDGE) ? expr->pin_count() : 1; @@ -3102,7 +3162,8 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const any other assignment statement. */ unsigned use_width = lv->lwidth(); bool unsized_flag = false; - use_width = expr1_->test_width(des, scope, use_width, use_width, unsized_flag); + ivl_variable_type_t expr1_type = IVL_VT_NO_TYPE; + use_width = expr1_->test_width(des, scope, use_width, use_width, expr1_type, unsized_flag); /* Make the r-value of the initial assignment, and size it properly. Then use it to build the assignment statement. */ @@ -3515,7 +3576,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const // FIXME: Look for constant expressions here? // Get a net form. - condit_sig = tmp->synthesize(des); + condit_sig = tmp->synthesize(des, scope); ivl_assert(*condition, condit_sig); } @@ -3658,6 +3719,7 @@ static void elaborate_tasks(Design*des, NetScope*scope, bool Module::elaborate(Design*des, NetScope*scope) const { bool result_flag = true; + error_implicit = true; if (gn_specify_blocks_flag) { // Elaborate specparams @@ -3722,6 +3784,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const // complex. const list&gl = get_gates(); + error_implicit = false; for (list::const_iterator gt = gl.begin() ; gt != gl.end() ; gt ++ ) { @@ -3729,6 +3792,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const (*gt)->elaborate(des, scope); } + error_implicit = true; + // Elaborate the behaviors, making processes out of them. This // involves scanning the PProcess* list, creating a NetProcTop // for each process. diff --git a/emit.cc b/emit.cc index 785520a12..6d1be63a8 100644 --- a/emit.cc +++ b/emit.cc @@ -196,6 +196,12 @@ bool NetProc::emit_proc(struct target_t*tgt) const return false; } +bool NetAlloc::emit_proc(struct target_t*tgt) const +{ + tgt->proc_alloc(this); + return true; +} + bool NetAssign::emit_proc(struct target_t*tgt) const { return tgt->proc_assign(this); @@ -249,6 +255,12 @@ bool NetForever::emit_proc(struct target_t*tgt) const return true; } +bool NetFree::emit_proc(struct target_t*tgt) const +{ + tgt->proc_free(this); + return true; +} + bool NetPDelay::emit_proc(struct target_t*tgt) const { return tgt->proc_delay(this); @@ -540,17 +552,3 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_unary(this); } - -int emit(const Design*des, const char*type) -{ - for (unsigned idx = 0 ; target_table[idx] ; idx += 1) { - const struct target*tgt = target_table[idx]; - if (strcmp(tgt->name, type) == 0) - return des->emit(tgt->meth); - - } - - cerr << "error: Code generator type " << type - << " not found." << endl; - return -1; -} diff --git a/eval_tree.cc b/eval_tree.cc index 5c8630621..06b660df6 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -133,6 +133,8 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width) verinum lval = lc->value(); verinum rval = rc->value(); + ivl_assert(*this, se->expr_width() == this->expr_width()); + verinum val; if (op_ == se->op_) { /* (a + lval) + rval --> a + (rval+lval) */ @@ -144,6 +146,13 @@ NetExpr* NetEBAdd::eval_tree(int prune_to_width) val = rval - lval; } + val = pad_to_width(val, expr_width()); + if (val.len() > expr_width()) { + verinum tmp (val, expr_width()); + tmp.has_sign(val.has_sign()); + val = tmp; + } + NetEConst*tmp = new NetEConst(val); left_ = se->left_->dup_expr(); delete se; @@ -528,6 +537,13 @@ NetEConst* NetEBComp::eval_gteq_() } } +/* + * Evaluate == or !=. The equality operator checks all the + * bits and returns true(false) if there are any bits in the vector + * that are defined (0 or 1) and different. If all the defined bits + * are equal, but there are are x/z bits, then the situation is + * ambiguous so the result is x. + */ NetEConst* NetEBComp::eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag) { NetEConst*vtmp; @@ -606,11 +622,14 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag) for (unsigned idx = 0 ; idx < top ; idx += 1) { + bool x_bit_present = false; + switch (lv.get(idx)) { case verinum::Vx: case verinum::Vz: res = verinum::Vx; + x_bit_present = true; break; default: @@ -622,17 +641,20 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag) case verinum::Vx: case verinum::Vz: res = verinum::Vx; + x_bit_present = true; break; default: break; } - if (res == verinum::Vx) - break; + if (x_bit_present) + continue; - if (rv.get(idx) != lv.get(idx)) + if (rv.get(idx) != lv.get(idx)) { res = ne_res; + break; + } } if (res != verinum::Vx) { @@ -1633,8 +1655,9 @@ NetEConst* NetEUReduce::eval_tree(int prune_to_width) return new NetEConst(verinum(res, 1)); } -NetExpr* evaluate_clog2(NetExpr*arg) +NetExpr* evaluate_clog2(NetExpr*&arg) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); if (tmpi || tmpr) { @@ -1645,9 +1668,9 @@ NetExpr* evaluate_clog2(NetExpr*arg) arg = verinum(tmpr->value().as_double(), true); } - /* If we have an x in the verinum we return 32'bx. */ + /* If we have an x in the verinum we return 'bx. */ if (!arg.is_defined()) { - verinum tmp (verinum::Vx, 32); + verinum tmp (verinum::Vx, integer_width); tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; @@ -1675,7 +1698,7 @@ NetExpr* evaluate_clog2(NetExpr*arg) if (is_neg && res < integer_width) res = integer_width; - verinum tmp (res, 32); + verinum tmp (res, integer_width); NetEConst*rtn = new NetEConst(tmp); return rtn; } @@ -1683,8 +1706,9 @@ NetExpr* evaluate_clog2(NetExpr*arg) return 0; } -NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name) +NetExpr* evaluate_math_one_arg(NetExpr*&arg, const char*name) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); if (tmpi || tmpr) { @@ -1739,8 +1763,10 @@ NetExpr* evaluate_math_one_arg(NetExpr*arg, const char*name) return 0; } -NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name) +NetExpr* evaluate_math_two_args(NetExpr*&arg0, NetExpr*&arg1, const char*name) { + eval_expr(arg0); + eval_expr(arg1); NetEConst*tmpi0 = dynamic_cast(arg0); NetECReal*tmpr0 = dynamic_cast(arg0); NetEConst*tmpi1 = dynamic_cast(arg1); @@ -1770,8 +1796,9 @@ NetExpr* evaluate_math_two_args(NetExpr*arg0, NetExpr*arg1, const char*name) return 0; } -NetExpr* evaluate_abs(NetExpr*arg) +NetExpr* evaluate_abs(NetExpr*&arg) { + eval_expr(arg); NetEConst*tmpi = dynamic_cast(arg); if (tmpi) { verinum arg = tmpi->value(); @@ -1790,8 +1817,10 @@ NetExpr* evaluate_abs(NetExpr*arg) return 0; } -NetExpr* evaluate_min_max(NetExpr*arg0, NetExpr*arg1, const char*name) +NetExpr* evaluate_min_max(NetExpr*&arg0, NetExpr*&arg1, const char*name) { + eval_expr(arg0); + eval_expr(arg1); NetEConst*tmpi0 = dynamic_cast(arg0); NetECReal*tmpr0 = dynamic_cast(arg0); NetEConst*tmpi1 = dynamic_cast(arg1); @@ -1866,11 +1895,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes a single argument." << endl; return 0; } + NetExpr*arg = parm(0)->dup_expr(); if (strcmp(nm, "$clog2") == 0) { - rtn = evaluate_clog2(parm(0)); + rtn = evaluate_clog2(arg); } else { - rtn = evaluate_math_one_arg(parm(0), nm); + rtn = evaluate_math_one_arg(arg, nm); } + delete arg; } if (strcmp(nm, "$pow") == 0 || @@ -1881,7 +1912,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes two arguments." << endl; return 0; } - rtn = evaluate_math_two_args(parm(0), parm(1), nm); + NetExpr*arg0 = parm(0)->dup_expr(); + NetExpr*arg1 = parm(1)->dup_expr(); + rtn = evaluate_math_two_args(arg0, arg1, nm); + delete arg0; + delete arg1; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && @@ -1891,11 +1926,13 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes a single argument." << endl; return 0; } + NetExpr*arg = parm(0)->dup_expr(); if (strcmp(nm, "$log") == 0) { - rtn = evaluate_math_one_arg(parm(0), nm); + rtn = evaluate_math_one_arg(arg, nm); } else { - rtn = evaluate_abs(parm(0)); + rtn = evaluate_abs(arg); } + delete arg; } if ((gn_icarus_misc_flag || gn_verilog_ams_flag) && @@ -1905,7 +1942,11 @@ NetExpr* NetESFunc::eval_tree(int prune_to_width) << " takes two arguments." << endl; return 0; } - rtn = evaluate_min_max(parm(0), parm(1), nm); + NetExpr*arg0 = parm(0)->dup_expr(); + NetExpr*arg1 = parm(1)->dup_expr(); + rtn = evaluate_min_max(arg0, arg1, nm); + delete arg0; + delete arg1; } if (rtn != 0) { diff --git a/expr_synth.cc b/expr_synth.cc index 4bec199dc..9fe178fe1 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -20,56 +20,56 @@ # include "config.h" # include "compiler.h" +# include # include # include "netlist.h" # include "netmisc.h" # include "ivl_assert.h" -NetNet* convert_to_real_const(Design*des, NetExpr*expr, NetExpr*obj) +static NetNet* convert_to_real_const(Design*des, NetScope*scope, NetEConst*expr) { - NetNet* sig; - - if (NetEConst*tmp = dynamic_cast(expr)) { - verireal vrl(tmp->value().as_double()); - NetECReal rlval(vrl); - sig = rlval.synthesize(des); - } else { - cerr << obj->get_fileline() << ": sorry: Cannot convert " - "bit based value (" << *expr << ") to real." << endl; - des->errors += 1; - sig = 0; - } + verireal vrl(expr->value().as_double()); + NetECReal rlval(vrl); + NetNet* sig = rlval.synthesize(des, scope); return sig; } /* Note that lsig, rsig and real_args are references. */ -bool process_binary_args(Design*des, NetExpr*left, NetExpr*right, - NetNet*&lsig, NetNet*&rsig, bool&real_args, - NetExpr*obj) +static bool process_binary_args(Design*des, NetScope*scope, + NetExpr*left, NetExpr*right, + NetNet*&lsig, NetNet*&rsig, bool&real_args, + NetExpr*obj) { if (left->expr_type() == IVL_VT_REAL || right->expr_type() == IVL_VT_REAL) { real_args = true; - /* Currently we will have a runtime assert if both expressions - are not real, though we can convert constants. */ + /* Convert the arguments to real. Handle the special + cases of constants, which can be converted more directly. */ if (left->expr_type() == IVL_VT_REAL) { - lsig = left->synthesize(des); + lsig = left->synthesize(des, scope); + } else if (NetEConst*tmp = dynamic_cast (left)) { + lsig = convert_to_real_const(des, scope, tmp); } else { - lsig = convert_to_real_const(des, left, obj); + NetNet*tmp = left->synthesize(des, scope); + lsig = cast_to_real(des, scope, tmp); } if (right->expr_type() == IVL_VT_REAL) { - rsig = right->synthesize(des); + rsig = right->synthesize(des, scope); + } else if (NetEConst*tmp = dynamic_cast (right)) { + rsig = convert_to_real_const(des, scope, tmp); } else { - rsig = convert_to_real_const(des, right, obj); + NetNet*tmp = right->synthesize(des, scope); + rsig = cast_to_real(des, scope, tmp); } + } else { real_args = false; - lsig = left->synthesize(des); - rsig = right->synthesize(des); + lsig = left->synthesize(des, scope); + rsig = right->synthesize(des, scope); } @@ -77,7 +77,7 @@ bool process_binary_args(Design*des, NetExpr*left, NetExpr*right, else return false; } -NetNet* NetExpr::synthesize(Design*des) +NetNet* NetExpr::synthesize(Design*des, NetScope*scope) { cerr << get_fileline() << ": internal error: cannot synthesize expression: " << *this << endl; @@ -88,25 +88,35 @@ NetNet* NetExpr::synthesize(Design*des) /* * Make an LPM_ADD_SUB device from addition operators. */ -NetNet* NetEBAdd::synthesize(Design*des) +NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope) { - assert((op()=='+') || (op()=='-')); + ivl_assert(*this, (op()=='+') || (op()=='-')); NetNet *lsig=0, *rsig=0; bool real_args=false; - if (process_binary_args(des, left_, right_, lsig, rsig, + if (process_binary_args(des, scope, left_, right_, lsig, rsig, real_args, this)) { return 0; } - assert(expr_width() >= lsig->vector_width()); - assert(expr_width() >= rsig->vector_width()); + ivl_assert(*this, expr_width() >= lsig->vector_width()); + ivl_assert(*this, expr_width() >= rsig->vector_width()); - lsig = pad_to_width(des, lsig, expr_width()); - rsig = pad_to_width(des, rsig, expr_width()); + unsigned width; + if (expr_type() == IVL_VT_REAL) { + width = 1; + if (lsig->data_type() != IVL_VT_REAL) + lsig = cast_to_real(des, scope, lsig); + if (rsig->data_type() != IVL_VT_REAL) + rsig = cast_to_real(des, scope, rsig); - assert(lsig->vector_width() == rsig->vector_width()); - unsigned width=lsig->vector_width(); + } else { + lsig = pad_to_width(des, lsig, expr_width()); + rsig = pad_to_width(des, rsig, expr_width()); + + assert(lsig->vector_width() == rsig->vector_width()); + width=lsig->vector_width(); + } perm_string path = lsig->scope()->local_symbol(); NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width); @@ -138,10 +148,10 @@ NetNet* NetEBAdd::synthesize(Design*des) * signals, then just connect a single gate to each bit of the vector * of the expression. */ -NetNet* NetEBBits::synthesize(Design*des) +NetNet* NetEBBits::synthesize(Design*des, NetScope*scope) { - NetNet*lsig = left_->synthesize(des); - NetNet*rsig = right_->synthesize(des); + NetNet*lsig = left_->synthesize(des, scope); + NetNet*rsig = right_->synthesize(des, scope); if (lsig == 0 || rsig == 0) return 0; @@ -154,10 +164,7 @@ NetNet* NetEBBits::synthesize(Design*des) return 0; } - NetScope*scope = lsig->scope(); - assert(scope); - - unsigned width = lsig->vector_width(); + unsigned width = expr_width(); if (rsig->vector_width() > width) width = rsig->vector_width(); lsig = pad_to_width(des, lsig, width); @@ -205,13 +212,13 @@ NetNet* NetEBBits::synthesize(Design*des) return osig; } -NetNet* NetEBComp::synthesize(Design*des) +NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; bool real_args=false; - if (process_binary_args(des, left_, right_, lsig, rsig, + if (process_binary_args(des, scope, left_, right_, lsig, rsig, real_args, this)) { return 0; } @@ -222,13 +229,16 @@ NetNet* NetEBComp::synthesize(Design*des) width = lsig->vector_width(); if (rsig->vector_width() > width) width = rsig->vector_width(); - lsig = pad_to_width(des, lsig, width); - rsig = pad_to_width(des, rsig, width); + if (lsig->get_signed()) + lsig = pad_to_width_signed(des, lsig, width); + else + lsig = pad_to_width(des, lsig, width); + if (rsig->get_signed()) + rsig = pad_to_width_signed(des, rsig, width); + else + rsig = pad_to_width(des, rsig, width); } - NetScope*scope = lsig->scope(); - assert(scope); - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, 1); osig->set_line(*this); @@ -236,10 +246,30 @@ NetNet* NetEBComp::synthesize(Design*des) osig->data_type(IVL_VT_LOGIC); bool signed_compare = lsig->get_signed() && rsig->get_signed(); + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Comparison (" << op_ << ")" + << " is " << (signed_compare? "signed" : "unsigned") + << endl; + cerr << get_fileline() << ": : lsig is " + << (lsig->get_signed()? "signed" : "unsigned") + << " rsig is " << (rsig->get_signed()? "signed" : "unsigned") + << endl; + } + + if (op_ == 'E' || op_ == 'N') { + NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(), + width, op_=='E'?true:false); + gate->set_line(*this); + connect(gate->pin(0), osig->pin(0)); + connect(gate->pin(1), lsig->pin(0)); + connect(gate->pin(2), rsig->pin(0)); + des->add_node(gate); + return osig; + } /* Handle the special case of a single bit equality operation. Make an XNOR gate instead of a comparator. */ - if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) { + if ((width == 1) && (op_ == 'e') && !real_args) { NetLogic*gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XNOR, 1); gate->set_line(*this); @@ -253,7 +283,7 @@ NetNet* NetEBComp::synthesize(Design*des) /* Handle the special case of a single bit inequality operation. This is similar to single bit equality, but uses an XOR instead of an XNOR gate. */ - if ((width == 1) && ((op_ == 'n') || (op_ == 'N')) && !real_args) { + if ((width == 1) && (op_ == 'n') && !real_args) { NetLogic*gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XOR, 1); gate->set_line(*this); @@ -321,12 +351,12 @@ NetNet* NetEBComp::synthesize(Design*des) return osig; } -NetNet* NetEBPow::synthesize(Design*des) +NetNet* NetEBPow::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; bool real_args=false; - if (process_binary_args(des, left_, right_, lsig, rsig, + if (process_binary_args(des, scope, left_, right_, lsig, rsig, real_args, this)) { return 0; } @@ -334,9 +364,6 @@ NetNet* NetEBPow::synthesize(Design*des) if (real_args) width = 1; else width = expr_width(); - NetScope*scope = lsig->scope(); - assert(scope); - NetPow*powr = new NetPow(scope, scope->local_symbol(), width, lsig->vector_width(), rsig->vector_width()); @@ -359,12 +386,12 @@ NetNet* NetEBPow::synthesize(Design*des) return osig; } -NetNet* NetEBMult::synthesize(Design*des) +NetNet* NetEBMult::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; bool real_args=false; - if (process_binary_args(des, left_, right_, lsig, rsig, + if (process_binary_args(des, scope, left_, right_, lsig, rsig, real_args, this)) { return 0; } @@ -372,9 +399,6 @@ NetNet* NetEBMult::synthesize(Design*des) if (real_args) width = 1; else width = expr_width(); - NetScope*scope = lsig->scope(); - assert(scope); - NetMult*mult = new NetMult(scope, scope->local_symbol(), width, lsig->vector_width(), @@ -398,12 +422,12 @@ NetNet* NetEBMult::synthesize(Design*des) return osig; } -NetNet* NetEBDiv::synthesize(Design*des) +NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; bool real_args=false; - if (process_binary_args(des, left_, right_, lsig, rsig, + if (process_binary_args(des, scope, left_, right_, lsig, rsig, real_args, this)) { return 0; } @@ -411,12 +435,11 @@ NetNet* NetEBDiv::synthesize(Design*des) if (real_args) width = 1; else width = expr_width(); - NetScope*scope = lsig->scope(); - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, width); osig->set_line(*this); osig->data_type(lsig->data_type()); + osig->set_signed(has_sign()); osig->local_flag(true); switch (op()) { @@ -427,6 +450,7 @@ NetNet* NetEBDiv::synthesize(Design*des) lsig->vector_width(), rsig->vector_width()); div->set_line(*this); + div->set_signed(has_sign()); des->add_node(div); connect(div->pin_DataA(), lsig->pin(0)); @@ -471,10 +495,10 @@ NetNet* NetEBDiv::synthesize(Design*des) return osig; } -NetNet* NetEBLogic::synthesize(Design*des) +NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope) { - NetNet*lsig = left_->synthesize(des); - NetNet*rsig = right_->synthesize(des); + NetNet*lsig = left_->synthesize(des, scope); + NetNet*rsig = right_->synthesize(des, scope); if (lsig == 0 || rsig == 0) return 0; @@ -487,9 +511,6 @@ NetNet* NetEBLogic::synthesize(Design*des) return 0; } - NetScope*scope = lsig->scope(); - assert(scope); - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, 1); osig->data_type(expr_type()); @@ -551,11 +572,11 @@ NetNet* NetEBLogic::synthesize(Design*des) return osig; } -NetNet* NetEBShift::synthesize(Design*des) +NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) { eval_expr(right_); - NetNet*lsig = left_->synthesize(des); + NetNet*lsig = left_->synthesize(des, scope); if (lsig == 0) return 0; @@ -568,10 +589,8 @@ NetNet* NetEBShift::synthesize(Design*des) return 0; } - bool right_flag = op_ == 'r' || op_ == 'R'; - bool signed_flag = op_ == 'R'; - - NetScope*scope = lsig->scope(); + const bool right_flag = op_ == 'r' || op_ == 'R'; + const bool signed_flag = op_ == 'R'; /* Detect the special case where the shift amount is constant. Evaluate the shift amount, and simply reconnect @@ -580,7 +599,7 @@ NetNet* NetEBShift::synthesize(Design*des) verinum shift_v = rcon->value(); long shift = shift_v.as_long(); - if (op() == 'r') + if (right_flag) shift = 0-shift; if (shift == 0) @@ -593,34 +612,13 @@ NetNet* NetEBShift::synthesize(Design*des) // ushift is the amount of pad created by the shift. unsigned long ushift = shift>=0? shift : -shift; - if (ushift > osig->vector_width()) - ushift = osig->vector_width(); + ivl_assert(*this, ushift < osig->vector_width()); // part_width is the bits of the vector that survive the shift. unsigned long part_width = osig->vector_width() - ushift; - verinum znum (verinum::V0, ushift, true); - NetConst*zcon = new NetConst(scope, scope->local_symbol(), - znum); - des->add_node(zcon); - - /* Detect the special case that the shift is the size of - the whole expression. Simply connect the pad to the - osig and escape. */ - if (ushift >= osig->vector_width()) { - connect(zcon->pin(0), osig->pin(0)); - return osig; - } - - NetNet*zsig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, znum.len()); - zsig->data_type(osig->data_type()); - zsig->local_flag(true); - zsig->set_line(*this); - connect(zcon->pin(0), zsig->pin(0)); - - /* Create a part select to reduce the width of the lsig - to the amount left by the shift. */ + // Create a part select to reduce the width of the lsig + // to the amount left by the shift. NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0, part_width, NetPartSelect::VP); @@ -633,6 +631,34 @@ NetNet* NetEBShift::synthesize(Design*des) psig->set_line(*this); connect(psig->pin(0), psel->pin(0)); + // Handle the special case of a signed right shift. In + // this case, use the NetSignExtend device to pad the + // result to the desired width. + if (signed_flag && right_flag) { + NetSignExtend*pad = new NetSignExtend(scope, scope->local_symbol(), + osig->vector_width()); + des->add_node(pad); + pad->set_line(*this); + + connect(pad->pin(1), psig->pin(0)); + connect(pad->pin(0), osig->pin(0)); + return osig; + } + + // Other cases are handled by zero-extending on the + // proper end. + verinum znum (verinum::V0, ushift, true); + NetConst*zcon = new NetConst(scope, scope->local_symbol(), + znum); + des->add_node(zcon); + + NetNet*zsig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, znum.len()); + zsig->data_type(osig->data_type()); + zsig->local_flag(true); + zsig->set_line(*this); + connect(zcon->pin(0), zsig->pin(0)); + NetConcat*ccat = new NetConcat(scope, scope->local_symbol(), osig->vector_width(), 2); ccat->set_line(*this); @@ -652,7 +678,7 @@ NetNet* NetEBShift::synthesize(Design*des) return osig; } - NetNet*rsig = right_->synthesize(des); + NetNet*rsig = right_->synthesize(des, scope); if (rsig == 0) return 0; @@ -678,13 +704,13 @@ NetNet* NetEBShift::synthesize(Design*des) return osig; } -NetNet* NetEConcat::synthesize(Design*des) +NetNet* NetEConcat::synthesize(Design*des, NetScope*scope) { /* First, synthesize the operands. */ NetNet**tmp = new NetNet*[parms_.count()]; bool flag = true; for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { - tmp[idx] = parms_[idx]->synthesize(des); + tmp[idx] = parms_[idx]->synthesize(des, scope); if (tmp[idx] == 0) flag = false; } @@ -692,9 +718,7 @@ NetNet* NetEConcat::synthesize(Design*des) if (flag == false) return 0; - assert(tmp[0]); - NetScope*scope = tmp[0]->scope(); - assert(scope); + ivl_assert(*this, tmp[0]); /* Make a NetNet object to carry the output vector. */ perm_string path = scope->local_symbol(); @@ -712,7 +736,9 @@ NetNet* NetEConcat::synthesize(Design*des) unsigned cur_pin = 1; for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { - connect(concat->pin(cur_pin), tmp[parms_.count()-idx-1]->pin(0)); + unsigned concat_item = parms_.count()-idx-1; + ivl_assert(*this, tmp[concat_item]); + connect(concat->pin(cur_pin), tmp[concat_item]->pin(0)); cur_pin += 1; } } @@ -721,17 +747,14 @@ NetNet* NetEConcat::synthesize(Design*des) return osig; } -NetNet* NetEConst::synthesize(Design*des) +NetNet* NetEConst::synthesize(Design*des, NetScope*scope) { - NetScope*scope = des->find_root_scope(); - assert(scope); - perm_string path = scope->local_symbol(); unsigned width=expr_width(); - NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width-1,0); + NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width); osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); + osig->data_type(expr_type()); osig->set_signed(has_sign()); NetConst*con = new NetConst(scope, scope->local_symbol(), value()); connect(osig->pin(0), con->pin(0)); @@ -743,11 +766,8 @@ NetNet* NetEConst::synthesize(Design*des) /* * Create a NetLiteral object to represent real valued constants. */ -NetNet* NetECReal::synthesize(Design*des) +NetNet* NetECReal::synthesize(Design*des, NetScope*scope) { - NetScope*scope = des->find_root_scope(); - assert(scope); - perm_string path = scope->local_symbol(); NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1); @@ -768,9 +788,9 @@ NetNet* NetECReal::synthesize(Design*des) * The bitwise unary logic operator (there is only one) is turned * into discrete gates just as easily as the binary ones above. */ -NetNet* NetEUBits::synthesize(Design*des) +NetNet* NetEUBits::synthesize(Design*des, NetScope*scope) { - NetNet*isig = expr_->synthesize(des); + NetNet*isig = expr_->synthesize(des, scope); if (isig == 0) return 0; @@ -782,9 +802,6 @@ NetNet* NetEUBits::synthesize(Design*des) return 0; } - NetScope*scope = isig->scope(); - assert(scope); - unsigned width = isig->vector_width(); NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, width); @@ -810,13 +827,56 @@ NetNet* NetEUBits::synthesize(Design*des) return osig; } -NetNet* NetEUReduce::synthesize(Design*des) +NetNet* NetEUnary::synthesize(Design*des, NetScope*scope) { - NetNet*isig = expr_->synthesize(des); + if (op_ == '+') + return expr_->synthesize(des, scope); + + if (op_ == '-') { + NetNet*sig = expr_->synthesize(des, scope); + sig = sub_net_from(des, scope, 0, sig); + return sig; + } + + if (op_ == 'm') { + NetNet*sub = expr_->synthesize(des, scope); + if (expr_->has_sign() == false) + return sub; + + NetNet*sig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sub->vector_width()); + sig->set_line(*this); + sig->local_flag(true); + sig->data_type(sub->data_type()); + + NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub->vector_width()); + des->add_node(tmp); + tmp->set_line(*this); + + connect(tmp->pin(1), sub->pin(0)); + connect(tmp->pin(0), sig->pin(0)); + return sig; + } + + cerr << get_fileline() << ": iternal error: " + << "NetEUnary::synthesize cannot handle op_=" << op_ << endl; + des->errors += 1; + return expr_->synthesize(des, scope); +} + +NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope) +{ + NetNet*isig = expr_->synthesize(des, scope); if (isig == 0) return 0; if (isig->data_type() == IVL_VT_REAL) { + if (op() == '!') { + cerr << get_fileline() << ": sorry: ! is currently " + "unsupported for real values." << endl; + des->errors += 1; + return 0; + } cerr << get_fileline() << ": error: reduction operator (" << human_readable_op(op_) << ") may not have a REAL operand." << endl; @@ -824,9 +884,6 @@ NetNet* NetEUReduce::synthesize(Design*des) return 0; } - NetScope*scope = isig->scope(); - assert(scope); - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, 1); osig->data_type(expr_type()); @@ -849,7 +906,7 @@ NetNet* NetEUReduce::synthesize(Design*des) rtype = NetUReduce::XOR; break; case 'A': - rtype = NetUReduce::XNOR; + rtype = NetUReduce::NAND; break; case 'X': rtype = NetUReduce::XNOR; @@ -871,22 +928,101 @@ NetNet* NetEUReduce::synthesize(Design*des) return osig; } -NetNet* NetESelect::synthesize(Design *des) +/* + * Turn a part/bit select expression into gates. + * We know some things about the expression that elaboration enforces + * for us: + * + * - Expression elaboration already converted the offset expression into + * cannonical form, so we don't have to worry about that here. + */ +NetNet* NetESelect::synthesize(Design *des, NetScope*scope) { - NetNet*sub = expr_->synthesize(des); + NetNet*sub = expr_->synthesize(des, scope); if (sub == 0) return 0; - NetScope*scope = sub->scope(); - NetNet*off = 0; + // Detect the special case that there is a base expression and + // it is constant. In this case we can generate fixed part selects. + if (NetEConst*base_const = dynamic_cast(base_)) { + verinum base_tmp = base_const->value(); + ivl_assert(*this, base_tmp.is_defined()); + + long base_val = base_tmp.as_long(); + unsigned select_width = expr_width(); + + // Any below X bits? + NetNet*below = 0; + if (base_val < 0) { + unsigned below_width = abs(base_val); + base_val = 0; + ivl_assert(*this, below_width < select_width); + select_width -= below_width; + + below = make_const_x(des, scope, below_width); + below->set_line(*this); + } + + // Any above bits? + NetNet*above = 0; + if ((unsigned)base_val+select_width > sub->vector_width()) { + select_width = sub->vector_width() - base_val; + unsigned above_width = expr_width() - select_width; + + above = make_const_x(des, scope, above_width); + above->set_line(*this); + } + + // Make the make part select. + NetPartSelect*sel = new NetPartSelect(sub, base_val, select_width, + NetPartSelect::VP); + des->add_node(sel); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, select_width); + tmp->data_type(sub->data_type()); + tmp->local_flag(true); + tmp->set_line(*this); + connect(sel->pin(0), tmp->pin(0)); + + unsigned concat_count = 1; + if (above) + concat_count += 1; + if (below) + concat_count += 1; + if (concat_count > 1) { + NetConcat*cat = new NetConcat(scope, scope->local_symbol(), + expr_width(), concat_count); + cat->set_line(*this); + des->add_node(cat); + if (below) { + connect(cat->pin(1), below->pin(0)); + connect(cat->pin(2), tmp->pin(0)); + } else { + connect(cat->pin(1), tmp->pin(0)); + } + if (above) { + connect(cat->pin(concat_count), above->pin(0)); + } + + tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, expr_width()); + tmp->data_type(sub->data_type()); + tmp->local_flag(true); + tmp->set_line(*this); + connect(cat->pin(0), tmp->pin(0)); + } + return tmp; + } + // This handles the case that the NetESelect exists to do an // actual part/bit select. Generate a NetPartSelect object to // do the work, and replace "sub" with the selected output. if (base_ != 0) { - off = base_->synthesize(des); + off = base_->synthesize(des, scope); NetPartSelect*sel = new NetPartSelect(sub, off, expr_width()); sel->set_line(*this); @@ -967,21 +1103,26 @@ NetNet* NetESelect::synthesize(Design *des) * expressions to the B and A inputs. This way, when the select input * is one, the B input, which is the true expression, is selected. */ -NetNet* NetETernary::synthesize(Design *des) +NetNet* NetETernary::synthesize(Design *des, NetScope*scope) { - NetNet*csig = cond_->synthesize(des), - *tsig = true_val_->synthesize(des), - *fsig = false_val_->synthesize(des); + NetNet*csig = cond_->synthesize(des, scope), + *tsig = true_val_->synthesize(des, scope), + *fsig = false_val_->synthesize(des, scope); if (csig == 0 || tsig == 0 || fsig == 0) return 0; - if (tsig->data_type() != fsig->data_type()) { - cerr << get_fileline() << ": error: True and False clauses of " - "ternary expression have different types." << endl; + if (! NetETernary::test_operand_compat(tsig->data_type(),fsig->data_type())) { + cerr << get_fileline() << ": internal error: " + << " True and False clauses of ternary expression " + << " have incompatible types." << endl; cerr << get_fileline() << ": : True clause is: " - << tsig->data_type() << endl; + << tsig->data_type() + << " (" << true_val_->expr_type() << "): " + << *true_val_ << endl; cerr << get_fileline() << ": : False clause is: " - << fsig->data_type() << endl; + << fsig->data_type() + << " (" << false_val_->expr_type() << "): " + << *false_val_ << endl; des->errors += 1; return 0; } else if (tsig->data_type() == IVL_VT_NO_TYPE) { @@ -993,7 +1134,7 @@ NetNet* NetETernary::synthesize(Design *des) perm_string path = csig->scope()->local_symbol(); - assert(csig->vector_width() == 1); + ivl_assert(*this, csig->vector_width() == 1); unsigned width=expr_width(); NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width); @@ -1025,26 +1166,25 @@ NetNet* NetETernary::synthesize(Design *des) * a bit more work needs to be done. Return a temporary that represents * the selected word. */ -NetNet* NetESignal::synthesize(Design*des) +NetNet* NetESignal::synthesize(Design*des, NetScope*scope) { if (word_ == 0) return net_; - NetScope*scope = net_->scope(); - NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet::IMPLICIT, net_->vector_width()); tmp->set_line(*this); tmp->local_flag(true); tmp->data_type(net_->data_type()); + // For NetExpr objects, the word index is already converted to + // a canonical (lsb==0) address. Just use the index directly. + if (NetEConst*index_co = dynamic_cast (word_)) { + long index = index_co->value().as_long(); - - assert(net_->array_index_is_valid(index)); - index = net_->array_index_to_address(index); - connect(tmp->pin(0), net_->pin(index)); + } else { unsigned selwid = word_->expr_width(); @@ -1053,7 +1193,7 @@ NetNet* NetESignal::synthesize(Design*des) mux->set_line(*this); des->add_node(mux); - NetNet*index_net = word_->synthesize(des); + NetNet*index_net = word_->synthesize(des, scope); connect(mux->pin_Address(), index_net->pin(0)); connect(tmp->pin(0), mux->pin_Result()); @@ -1061,22 +1201,68 @@ NetNet* NetESignal::synthesize(Design*des) return tmp; } -NetNet* NetESFunc::synthesize(Design*des) +NetNet* NetESFunc::synthesize(Design*des, NetScope*scope) { - cerr << get_fileline() << ": sorry: cannot synthesize system function: " - << *this << " in this context" << endl; - des->errors += 1; - return 0; + + const struct sfunc_return_type*def = lookup_sys_func(name_); + + /* We cannot use the default value for system functions in a + * continuous assignment since the function name is NULL. */ + if (def == 0 || def->name == 0) { + cerr << get_fileline() << ": error: System function " + << name_ << " not defined in system " + "table or SFT file(s)." << endl; + des->errors += 1; + return 0; + } + + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Net system function " + << name_ << " returns " << def->type << endl; + } + + NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(), + def, 1+nparms_); + net->set_line(*this); + des->add_node(net); + + NetNet*osig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, def->wid); + osig->local_flag(true); + osig->set_signed(def->type==IVL_VT_REAL? true : false); + osig->data_type(def->type); + osig->set_line(*this); + + connect(net->pin(0), osig->pin(0)); + + unsigned errors = 0; + for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) { + NetNet*tmp = parms_[idx]->synthesize(des, scope); + if (tmp == 0) { + cerr << get_fileline() << ": error: Unable to elaborate " + << "argument " << idx << " of call to " << name_ << + "." << endl; + errors += 1; + des->errors += 1; + continue; + } + + connect(net->pin(1+idx), tmp->pin(0)); + } + + if (errors > 0) return 0; + + return osig; } -NetNet* NetEUFunc::synthesize(Design*des) +NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope) { svector eparms (parms_.count()); /* Synthesize the arguments. */ bool errors = false; for (unsigned idx = 0; idx < eparms.count(); idx += 1) { - NetNet*tmp = parms_[idx]->synthesize(des); + NetNet*tmp = parms_[idx]->synthesize(des, scope); if (tmp == 0) { cerr << get_fileline() << ": error: Unable to synthesize " "port " << idx << " of call to " diff --git a/ivl_target.h b/ivl_target.h index f198fe55d..33b2adb5f 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -343,6 +343,7 @@ typedef enum ivl_signal_type_e { typedef enum ivl_statement_type_e { IVL_ST_NONE = 0, IVL_ST_NOOP = 1, + IVL_ST_ALLOC = 25, IVL_ST_ASSIGN = 2, IVL_ST_ASSIGN_NB = 3, IVL_ST_BLOCK = 4, @@ -359,6 +360,7 @@ typedef enum ivl_statement_type_e { IVL_ST_FORCE = 14, IVL_ST_FOREVER = 15, IVL_ST_FORK = 16, + IVL_ST_FREE = 26, IVL_ST_RELEASE = 17, IVL_ST_REPEAT = 18, IVL_ST_STASK = 19, @@ -502,7 +504,8 @@ extern ivl_net_const_t ivl_design_const(ivl_design_t, unsigned idx); * ivl_const_bits * This returns a pointer to an array of constant characters, * each byte a '0', '1', 'x' or 'z'. The array is *not* nul - * terminated. + * terminated. This value is only value if ivl_const_type is + * IVL_VT_LOGIC or IVL_VT_BOOL. It returns nil otherwise. * * ivl_const_nex * Return the ivl_nexus_t of the output for the constant. @@ -1254,7 +1257,7 @@ extern const char*ivl_lpm_string(ivl_lpm_t net); */ extern unsigned ivl_lval_width(ivl_lval_t net); -extern ivl_expr_t ivl_lval_mux(ivl_lval_t net); // XXXX Obsolete? +extern ivl_expr_t ivl_lval_mux(ivl_lval_t net); /* XXXX Obsolete? */ extern ivl_expr_t ivl_lval_idx(ivl_lval_t net); extern ivl_expr_t ivl_lval_part_off(ivl_lval_t net); extern ivl_signal_t ivl_lval_sig(ivl_lval_t net); @@ -1927,7 +1930,7 @@ extern unsigned ivl_switch_lineno(ivl_switch_t net); #endif extern DLLEXPORT int target_design(ivl_design_t des); - +extern DLLEXPORT const char* target_query(const char*key); /* target_design @@ -1945,6 +1948,7 @@ extern DLLEXPORT int target_design(ivl_design_t des); ivl core. This function is how the target module is invoked. */ typedef int (*target_design_f)(ivl_design_t des); +typedef const char* (*target_query_f) (const char*key); _END_DECL diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index b66ed207a..2a3e0d22f 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -40,7 +40,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) @CPPFLAGS@ @DEFS@ +CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 492b07a13..a25e4dc5a 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -698,7 +698,7 @@ static int is_defined(const char*name) * These variables are also used for storing the actual arguments when * a macro is instantiated. */ -#define MAX_DEF_ARG 256 // allows argument IDs to be stored in a single char +#define MAX_DEF_ARG 256 /* allows argument IDs to be stored in a single char */ #define DEF_BUF_CHUNK 256 @@ -707,14 +707,14 @@ static int def_buf_size = 0; static int def_buf_free = 0; static int def_argc = 0; -static int def_argo[MAX_DEF_ARG]; // offset of first character in arg -static int def_argl[MAX_DEF_ARG]; // length of arg string. +static int def_argo[MAX_DEF_ARG]; /* offset of first character in arg */ +static int def_argl[MAX_DEF_ARG]; /* length of arg string. */ /* * Return a pointer to the start of argument 'arg'. Returned pointers * may go stale after a call to def_buf_grow_to_fit. */ -static inline char* def_argv(int arg) +static /* inline */ char* def_argv(int arg) { return def_buf + def_argo[arg]; } diff --git a/ivlpp/main.c b/ivlpp/main.c index 7c91ed853..cdf4e4297 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -17,7 +17,8 @@ const char COPYRIGHT[] = * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -# include "config.h" +# include "config.h" +# include "version.h" const char NOTICE[] = " This program is free software; you can redistribute it and/or modify\n" @@ -35,8 +36,6 @@ const char NOTICE[] = " Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" ; -const char VERSION[] = "$Name: $ $State: Exp $"; - # include # include #ifdef HAVE_MALLOC_H @@ -103,6 +102,8 @@ static int flist_read_flags(const char*path) char*cp = line_buf + strspn(line_buf, " \t\r\b\f"); /* Remove trailing white space. */ char*tail = cp + strlen(cp); + char*arg; + while (tail > cp) { if (! isspace(tail[-1])) break; @@ -118,7 +119,7 @@ static int flist_read_flags(const char*path) continue; /* The arg points to the argument to the keyword. */ - char*arg = strchr(cp, ':'); + arg = strchr(cp, ':'); if (arg) *arg++ = 0; if (strcmp(cp,"D") == 0) { @@ -229,7 +230,7 @@ int main(int argc, char*argv[]) include_dir[0] = 0; /* 0 is reserved for the current files path. */ include_dir[1] = strdup("."); - while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:v")) != EOF) switch (opt) { + while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vV")) != EOF) switch (opt) { case 'F': flist_read_flags(optarg); @@ -284,12 +285,19 @@ int main(int argc, char*argv[]) } case 'v': - fprintf(stderr, "Icarus Verilog Preprocessor version %s\n", - VERSION); + fprintf(stderr, "Icarus Verilog Preprocessor version " + VERSION " (" VERSION_TAG ")\n\n"); fprintf(stderr, "%s\n", COPYRIGHT); fputs(NOTICE, stderr); break; + case 'V': + fprintf(stdout, "Icarus Verilog Preprocessor version " + VERSION " (" VERSION_TAG ")\n\n"); + fprintf(stdout, "%s\n", COPYRIGHT); + fputs(NOTICE, stdout); + return 0; + default: flag_errors += 1; break; @@ -304,7 +312,8 @@ int main(int argc, char*argv[]) " -o - Send the output to \n" " -p - Write precompiled defines to \n" " -P - Read precompiled defines from \n" - " -v - Print version information\n", + " -v - Verbose\n" + " -V - Print version information and quit\n", argv[0]); return flag_errors; } diff --git a/lexor.lex b/lexor.lex index 936f5ce0f..34eca1c0b 100644 --- a/lexor.lex +++ b/lexor.lex @@ -87,6 +87,7 @@ static void process_timescale(const char*txt); static list keyword_mask_stack; static int comment_enter; +static bool in_module = false; %} %x CCOMMENT @@ -123,8 +124,8 @@ S [afpnumkKMGT] /* The contents of C-style comments are ignored, like white space. */ "/*" { comment_enter = YY_START; BEGIN(CCOMMENT); } -. { yymore(); } -\n { yylloc.first_line += 1; yymore(); } +. { ; } +\n { yylloc.first_line += 1; } "*/" { BEGIN(comment_enter); } @@ -227,6 +228,15 @@ S [afpnumkKMGT] BEGIN(EDGES); break; + case K_module: + case K_macromodule: + in_module = true; + break; + + case K_endmodule: + in_module = false; + break; + default: yylval.text = 0; break; @@ -343,6 +353,12 @@ S [afpnumkKMGT] ^{W}?`timescale { BEGIN(PPTIMESCALE); } .* { process_timescale(yytext); } \n { + if (in_module) { + cerr << yylloc.text << ":" << yylloc.first_line << ": error: " + "`timescale directive can not be inside a module " + "definition." << endl; + error_count += 1; + } yylloc.first_line += 1; BEGIN(0); } @@ -439,7 +455,7 @@ S [afpnumkKMGT] } else { cerr << yylloc.text << ":" << yylloc.first_line - << " error: Net type " << yytext + << ": error: Net type " << yytext << " is not a valid (and supported)" << " default net type." << endl; net_type = NetNet::WIRE; @@ -457,37 +473,37 @@ S [afpnumkKMGT] ^{W}?`define{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `define not supported. Use an external preprocessor." + ": warning: `define not supported. Use an external preprocessor." << endl; } ^{W}?`else{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `else not supported. Use an external preprocessor." + ": warning: `else not supported. Use an external preprocessor." << endl; } ^{W}?`endif{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `endif not supported. Use an external preprocessor." + ": warning: `endif not supported. Use an external preprocessor." << endl; } ^{W}?`ifdef{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `ifdef not supported. Use an external preprocessor." + ": warning: `ifdef not supported. Use an external preprocessor." << endl; } ^`include{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `include not supported. Use an external preprocessor." + ": warning: `include not supported. Use an external preprocessor." << endl; } ^`undef{W}?.* { cerr << yylloc.text << ":" << yylloc.first_line << - ": `undef not supported. Use an external preprocessor." + ": warning: `undef not supported. Use an external preprocessor." << endl; } diff --git a/libveriuser/a_fetch_type.c b/libveriuser/a_fetch_type.c index 7563a626a..abbf973b1 100644 --- a/libveriuser/a_fetch_type.c +++ b/libveriuser/a_fetch_type.c @@ -99,7 +99,7 @@ PLI_INT32 acc_fetch_fulltype(handle obj) return accTopModule; else return accModuleInstance; - // FIXME accCellInstance + /* FIXME accCellInstance */ case vpiNamedEvent: return accNamedEvent; diff --git a/libveriuser/a_next.c b/libveriuser/a_next.c index f88cd9a2d..c773346c9 100644 --- a/libveriuser/a_next.c +++ b/libveriuser/a_next.c @@ -55,7 +55,7 @@ handle acc_next(PLI_INT32 *type, handle scope, handle prev) * rescan all the items up to the previous one, then return * the next one. */ - iter = vpi_iterate(vpiScope, scope); // ICARUS extension + iter = vpi_iterate(vpiScope, scope); /* ICARUS extension */ if (prev) { while ((hand = vpi_scan(iter))) { if (hand == prev) break; diff --git a/libveriuser/veriusertfs.c b/libveriuser/veriusertfs.c index f0fe42ba7..896ab3553 100644 --- a/libveriuser/veriusertfs.c +++ b/libveriuser/veriusertfs.c @@ -366,7 +366,7 @@ PLI_INT32 tf_isetrealdelay(double dly, void*obj) s_cb_data cb; s_vpi_time ti = {vpiSimTime}; - // Scale delay to SimTime + /* Scale delay to SimTime */ ivl_u64_t delay = ((dly * pow(10, tf_gettimeprecision() - tf_gettimeunit())) + 0.5); diff --git a/main.cc b/main.cc index deaae3359..99bfa4a2c 100644 --- a/main.cc +++ b/main.cc @@ -20,6 +20,7 @@ const char COPYRIGHT[] = */ # include "config.h" +# include "version.h" const char NOTICE[] = " This program is free software; you can redistribute it and/or modify\n" @@ -59,6 +60,7 @@ const char NOTICE[] = # include "target.h" # include "compiler.h" # include "discipline.h" +# include "t-dll.h" #if defined(__MINGW32__) && !defined(HAVE_GETOPT_H) extern "C" int getopt(int argc, char*argv[], const char*fmt); @@ -75,12 +77,8 @@ extern "C" const char*optarg; /* Count errors detected in flag processing. */ unsigned flag_errors = 0; -const char VERSION[] = "$Name: $"; - const char*basedir = "."; -const char*target = "null"; - /* * These are the language support control flags. These support which * language features (the generation) to support. The generation_flag @@ -293,7 +291,7 @@ static void find_module_mention(map&check_map, PGenerate*s); * -T: * Select which expression to use. * - * -t: + * -t: (obsolete) * Usually, "-t:dll" * * basedir: @@ -483,7 +481,7 @@ static void read_iconfig_file(const char*ipath) library_suff.push_back(strdup(cp)); } else if (strcmp(buf,"-t") == 0) { - target = strdup(cp); + // NO LONGER USED } else if (strcmp(buf,"-T") == 0) { if (strcmp(cp,"min") == 0) { @@ -533,6 +531,7 @@ int main(int argc, char*argv[]) { bool help_flag = false; bool times_flag = false; + bool version_flag = false; const char* net_path = 0; const char* pf_path = 0; @@ -576,10 +575,8 @@ int main(int argc, char*argv[]) # endif break; case 'V': - cout << "Icarus Verilog version " << VERSION << endl; - cout << COPYRIGHT << endl; - cout << endl << NOTICE << endl; - return 0; + version_flag = true; + break; default: flag_errors += 1; break; @@ -588,8 +585,20 @@ int main(int argc, char*argv[]) if (flag_errors) return flag_errors; + if (version_flag) { + cout << "\n\nIcarus Verilog Parser/Elaborator version " + << VERSION << " (" << VERSION_TAG << ")" << endl; + cout << COPYRIGHT << endl; + cout << endl << NOTICE << endl; + + dll_target_obj.test_version(flags["DLL"]); + + return 0; + } + if (help_flag) { - cout << "Icarus Verilog version " << VERSION << endl << + cout << "Icarus Verilog Parser/Elaborator version " + << VERSION << " (" << VERSION_TAG << ")" << endl << "usage: ivl \n" "options:\n" "\t-C Config file from driver.\n" @@ -844,20 +853,21 @@ int main(int argc, char*argv[]) } if (verbose_flag) { - cout << "CODE GENERATION -t "< 0) { - cerr << "error: Code generation had " - << emit_rc << " errors." - << endl; - return 1; - } - if (emit_rc < 0) { - cerr << "error: Code generator failure: " << emit_rc << endl; - return -1; + if (int emit_rc = des->emit(&dll_target_obj)) { + if (emit_rc > 0) { + cerr << "error: Code generation had " + << emit_rc << " errors." + << endl; + return 1; + } + if (emit_rc < 0) { + cerr << "error: Code generator failure: " << emit_rc << endl; + return -1; + } + assert(emit_rc); } if (verbose_flag) { diff --git a/net_assign.cc b/net_assign.cc index 485b2cc45..d44d89999 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -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,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: net_assign.cc,v 1.22 2007/01/16 05:44:15 steve Exp $" -#endif # include "config.h" @@ -84,6 +81,11 @@ unsigned NetAssign_::lwidth() const return lwid_; } +ivl_variable_type_t NetAssign_::expr_type() const +{ + return sig_->data_type(); +} + perm_string NetAssign_::name() const { if (sig_) { @@ -212,15 +214,34 @@ NetAssign::~NetAssign() { } -NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv) +NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, NetExpr*cnt) : NetAssignBase(lv, rv) { + event_ = ev; + count_ = cnt; } NetAssignNB::~NetAssignNB() { } +unsigned NetAssignNB::nevents() const +{ + if (event_) return event_->nevents(); + return 0; +} + +const NetEvent*NetAssignNB::event(unsigned idx) const +{ + if (event_) return event_->event(idx); + return 0; +} + +const NetExpr*NetAssignNB::get_count() const +{ + return count_; +} + NetCAssign::NetCAssign(NetAssign_*lv, NetExpr*rv) : NetAssignBase(lv, rv) { @@ -256,34 +277,3 @@ NetRelease::NetRelease(NetAssign_*l) NetRelease::~NetRelease() { } - -/* - * $Log: net_assign.cc,v $ - * Revision 1.22 2007/01/16 05:44:15 steve - * Major rework of array handling. Memories are replaced with the - * more general concept of arrays. The NetMemory and NetEMemory - * classes are removed from the ivl core program, and the IVL_LPM_RAM - * lpm type is removed from the ivl_target API. - * - * Revision 1.21 2006/02/02 02:43:58 steve - * Allow part selects of memory words in l-values. - * - * Revision 1.20 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.19 2004/12/11 02:31:26 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.18 2004/08/28 15:08:31 steve - * Do not change reg to wire in NetAssign_ unless synthesizing. - * - * Revision 1.17 2004/02/18 17:11:56 steve - * Use perm_strings for named langiage items. - * - * Revision 1.16 2003/01/26 21:15:58 steve - * Rework expression parsing and elaboration to - * accommodate real/realtime values and expressions. - */ - diff --git a/net_event.cc b/net_event.cc index 3535e7ea9..3804ff8fb 100644 --- a/net_event.cc +++ b/net_event.cc @@ -251,7 +251,6 @@ NetEvProbe::NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt, { for (unsigned idx = 0 ; idx < p ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("P"), idx); } enext_ = event_->probes_; diff --git a/net_expr.cc b/net_expr.cc index e749cdca1..6b1a9fccd 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -127,6 +127,9 @@ ivl_variable_type_t NetEBAdd::expr_type() const NetEBComp::NetEBComp(char op, NetExpr*l, NetExpr*r) : NetEBinary(op, l, r) { + // The output of compare is always unsigned. + cast_signed_base_(false); + if (NetEConst*tmp = dynamic_cast(r)) do { if (tmp->has_width()) @@ -242,7 +245,11 @@ ivl_variable_type_t NetEBMinMax::expr_type() const NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r) : NetEBinary(op, l, r) { - expr_width(l->expr_width() + r->expr_width()); + if (expr_type() == IVL_VT_REAL) + expr_width(1); + else + expr_width(l->expr_width() + r->expr_width()); + cast_signed(l->has_sign() && r->has_sign()); /* If it turns out that this is not a signed expression, then @@ -302,10 +309,6 @@ ivl_variable_type_t NetEBPow::expr_type() const return IVL_VT_REAL; if (left_->expr_type() == IVL_VT_REAL) return IVL_VT_REAL; - if (left_->has_sign()) - return IVL_VT_REAL; - if (right_->has_sign()) - return IVL_VT_REAL; return IVL_VT_LOGIC; } diff --git a/net_func.cc b/net_func.cc index 564d16258..8e4f05d7f 100644 --- a/net_func.cc +++ b/net_func.cc @@ -34,12 +34,10 @@ NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d) def_(d) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(def_->basename(), 0); for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D"), idx-1); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } @@ -135,13 +133,11 @@ NetSysFunc::NetSysFunc(NetScope*s, perm_string n, { def_ = def; - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q"), 0); + pin(0).set_dir(Link::OUTPUT); // Q for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D"), idx-1); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } diff --git a/net_link.cc b/net_link.cc index e105a98eb..7863f0377 100644 --- a/net_link.cc +++ b/net_link.cc @@ -64,7 +64,7 @@ void connect(Link&l, Link&r) Link::Link() : dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx), - inst_(0), next_(0), nexus_(0) + next_(0), nexus_(0) { (new Nexus()) -> relink(this); } @@ -103,6 +103,11 @@ void Link::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay) nexus_->drivers_delays(rise, fall, decay); } +void Link::drivers_drive(strength_t drive0, strength_t drive1) +{ + nexus_->drivers_drive(drive0, drive1); +} + void Link::drive0(Link::strength_t str) { drive0_ = str; @@ -136,14 +141,14 @@ verinum::V Link::get_init() const void Link::cur_link(NetPins*&net, unsigned &pin) { - net = node_; - pin = pin_; + net = get_obj(); + pin = get_pin(); } void Link::cur_link(const NetPins*&net, unsigned &pin) const { - net = node_; - pin = pin_; + net = get_obj(); + pin = get_pin(); } void Link::unlink() @@ -188,33 +193,28 @@ const Link* Link::next_nlink() const const NetPins*Link::get_obj() const { - return node_; + if (pin_zero_) + return node_; + const Link*tmp = this - pin_; + assert(tmp->pin_zero_); + return tmp->node_; } NetPins*Link::get_obj() { - return node_; + if (pin_zero_) + return node_; + Link*tmp = this - pin_; + assert(tmp->pin_zero_); + return tmp->node_; } unsigned Link::get_pin() const { - return pin_; -} - -void Link::set_name(perm_string n, unsigned i) -{ - name_ = n; - inst_ = i; -} - -perm_string Link::get_name() const -{ - return name_; -} - -unsigned Link::get_inst() const -{ - return inst_; + if (pin_zero_) + return 0; + else + return pin_; } Nexus::Nexus() @@ -298,6 +298,17 @@ void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay) } } +void Nexus::drivers_drive(Link::strength_t drive0, Link::strength_t drive1) +{ + for (Link*cur = list_ ; cur ; cur = cur->next_) { + if (cur->get_dir() != Link::OUTPUT) + continue; + + cur->drive0(drive0); + cur->drive1(drive1); + } +} + void Nexus::unlink(Link*that) { if (name_) { @@ -437,10 +448,9 @@ const char* Nexus::name() const const Link*lnk = first_nlink(); const NetObj*obj = dynamic_cast(lnk->get_obj()); pin = lnk->get_pin(); - cerr << "internal error: No signal for nexus of " << - obj->name() << " pin " << pin << "(" << - lnk->get_name() << "<" << lnk->get_inst() << ">)" - " type=" << typeid(*obj).name() << "?" << endl; + cerr << "internal error: No signal for nexus of " + << obj->name() << " pin " << pin + << " type=" << typeid(*obj).name() << "?" << endl; } assert(sig); diff --git a/net_modulo.cc b/net_modulo.cc index 5ff3be9e4..de99a4dba 100644 --- a/net_modulo.cc +++ b/net_modulo.cc @@ -40,12 +40,9 @@ NetModulo::NetModulo(NetScope*s, perm_string n, unsigned wr, : NetNode(s, n, 3), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetModulo::~NetModulo() diff --git a/net_tran.cc b/net_tran.cc index 42b726307..baa37b410 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -45,19 +45,18 @@ static bool has_enable(ivl_switch_type_t tt) 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); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_dir(Link::PASSIVE); if (pin_count() == 3) { - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("E"), 0); + pin(2).set_dir(Link::INPUT); // Enable } } 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); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_dir(Link::PASSIVE); } NetTran::~NetTran() diff --git a/net_udp.cc b/net_udp.cc index c5d3df01f..8924027f5 100644 --- a/net_udp.cc +++ b/net_udp.cc @@ -30,10 +30,8 @@ NetUDP::NetUDP(NetScope*s, perm_string n, unsigned pins, PUdp *u) : NetNode(s, n, pins), udp(u) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); } } diff --git a/netlist.cc b/netlist.cc index 4da3f5755..20a9284ff 100644 --- a/netlist.cc +++ b/netlist.cc @@ -23,6 +23,7 @@ # include # include +# include # include "compiler.h" # include "netlist.h" # include "netmisc.h" @@ -175,9 +176,12 @@ NetPins::NetPins(unsigned npins) : npins_(npins) { pins_ = new Link[npins_]; - for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { - pins_[idx].node_ = this; - pins_[idx].pin_ = idx; + pins_[0].pin_zero_ = true; + pins_[0].node_ = this; + + for (unsigned idx = 1 ; idx < npins_ ; idx += 1) { + pins_[idx].pin_zero_ = false; + pins_[idx].pin_ = idx; } } @@ -196,12 +200,15 @@ Link& NetPins::pin(unsigned idx) } assert(idx < npins_); + assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx); + return pins_[idx]; } const Link& NetPins::pin(unsigned idx) const { assert(idx < npins_); + assert(idx == 0? pins_[0].pin_zero_ : pins_[idx].pin_==idx); return pins_[idx]; } @@ -238,9 +245,7 @@ NetNode::~NetNode() NetBranch::NetBranch(discipline_t*dis) : NetPins(2), discipline_(dis) { - pin(0).set_name(perm_string::literal("A"), 0); pin(0).set_dir(Link::PASSIVE); - pin(1).set_name(perm_string::literal("B"), 0); pin(1).set_dir(Link::PASSIVE); } @@ -266,13 +271,11 @@ NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins, posedge_ = false; negedge_ = false; for (unsigned idx = 0 ; idx < npins ; idx += 1) { - pin(idx).set_name(perm_string::literal("I"), idx); pin(idx).set_dir(Link::INPUT); } if (condit_src) { condit_flag_ = true; - pin(npins).set_name(perm_string::literal("COND"), 0); pin(npins).set_dir(Link::INPUT); } } @@ -455,7 +458,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) break; } - pin(0).set_name(perm_string::literal("P"), 0); pin(0).set_dir(dir); pin(0).set_init(init_value); @@ -494,7 +496,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P"), idx); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -542,7 +543,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P"), idx); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -627,7 +627,10 @@ void NetNet::data_type(ivl_variable_type_t t) bool NetNet::get_signed() const { - return signed_; + if (data_type_ == IVL_VT_REAL) + return true; + else + return signed_; } void NetNet::set_signed(bool flag) @@ -796,8 +799,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, 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); } NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, @@ -819,10 +820,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, break; } pin(2).set_dir(Link::INPUT); - - pin(0).set_name(perm_string::literal("Part"), 0); - pin(1).set_name(perm_string::literal("Vect"), 0); - pin(2).set_name(perm_string::literal("Select"), 0); } NetPartSelect::~NetPartSelect() @@ -887,28 +884,22 @@ NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width) : NetNode(scope, n, 2), width_(width) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); } NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag) : NetNode(scope, n, 2), signed_flag_(signed_flag) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); } NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt) : NetNode(scope, n, cnt+1), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); for (unsigned idx = 1 ; idx < cnt+1 ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); } } @@ -926,9 +917,7 @@ NetReplicate::NetReplicate(NetScope*scope, perm_string n, : NetNode(scope, n, 2), width_(wid), repeat_(rpt) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); } NetReplicate::~NetReplicate() @@ -963,21 +952,13 @@ NetFF::NetFF(NetScope*s, perm_string n, unsigned width) : NetNode(s, n, 8), width_(width) { pin_Clock().set_dir(Link::INPUT); - pin_Clock().set_name(perm_string::literal("Clock"), 0); pin_Enable().set_dir(Link::INPUT); - pin_Enable().set_name(perm_string::literal("Enable"), 0); pin_Aset().set_dir(Link::INPUT); - pin_Aset().set_name(perm_string::literal("Aset"), 0); pin_Aclr().set_dir(Link::INPUT); - pin_Aclr().set_name(perm_string::literal("Aclr"), 0); pin_Sset().set_dir(Link::INPUT); - pin_Sset().set_name(perm_string::literal("Sset"), 0); pin_Sclr().set_dir(Link::INPUT); - pin_Sclr().set_name(perm_string::literal("Sclr"), 0); pin_Data().set_dir(Link::INPUT); - pin_Data().set_name(perm_string::literal("Data"), 0); pin_Q().set_dir(Link::OUTPUT); - pin_Q().set_name(perm_string::literal("Q"), 0); } NetFF::~NetFF() @@ -1094,9 +1075,7 @@ NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 2), width_(w) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); } NetAbs::~NetAbs() @@ -1111,37 +1090,18 @@ unsigned NetAbs::width() const /* * The NetAddSub class represents an LPM_ADD_SUB device. The pinout is * assigned like so: - * 0 -- Add_Sub - * 1 -- Aclr - * 2 -- Clock - * 3 -- Cin - * 4 -- Cout - * 5 -- Overflow - * 6 -- DataA (normally a vector) - * 7 -- DataB (normally a vector) - * 8 -- Result (normally a vector) + * 0 -- Cout + * 1 -- DataA (normally a vector) + * 2 -- DataB (normally a vector) + * 3 -- Result (normally a vector) */ NetAddSub::NetAddSub(NetScope*s, perm_string n, unsigned w) -: NetNode(s, n, 9), width_(w) +: NetNode(s, n, 4), width_(w) { - pin(0).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("Add_Sub"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Aclr"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Clock"), 0); - pin(3).set_dir(Link::INPUT); - pin(3).set_name(perm_string::literal("Cin"), 0); - pin(4).set_dir(Link::OUTPUT); - pin(4).set_name(perm_string::literal("Cout"), 0); - pin(5).set_dir(Link::OUTPUT); - pin(5).set_name(perm_string::literal("Overflow"), 0); - pin(6).set_dir(Link::INPUT); - pin(6).set_name(perm_string::literal("DataA"), 0); - pin(7).set_dir(Link::INPUT); - pin(7).set_name(perm_string::literal("DataB"), 0); - pin(8).set_dir(Link::OUTPUT); - pin(8).set_name(perm_string::literal("Result"), 0); + pin(0).set_dir(Link::OUTPUT); // Cout + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB + pin(3).set_dir(Link::OUTPUT); // Result } NetAddSub::~NetAddSub() @@ -1155,52 +1115,50 @@ unsigned NetAddSub::width()const Link& NetAddSub::pin_Cout() { - return pin(4); + return pin(0); } const Link& NetAddSub::pin_Cout() const { - return pin(4); + return pin(0); } Link& NetAddSub::pin_DataA() { - return pin(6); + return pin(1); } const Link& NetAddSub::pin_DataA() const { - return pin(6); + return pin(1); } Link& NetAddSub::pin_DataB() { - return pin(7); + return pin(2); } const Link& NetAddSub::pin_DataB() const { - return pin(7); + return pin(2); } Link& NetAddSub::pin_Result() { - return pin(8); + return pin(3); } const Link& NetAddSub::pin_Result() const { - return pin(8); + return pin(3); } NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid) : NetNode(s, n, 2), mem_(mem), awidth_(awid) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Address"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // Address // Increment the expression reference count for the target // memory so that it is not deleted underneath me. mem->incr_eref(); @@ -1258,12 +1216,9 @@ NetCLShift::NetCLShift(NetScope*s, perm_string n, width_(width), width_dist_(width_dist), right_flag_(right_flag), signed_flag_(signed_flag) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Data"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Distance"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // Data + pin(2).set_dir(Link::INPUT); // Distance } NetCLShift::~NetCLShift() @@ -1324,26 +1279,16 @@ NetCompare::NetCompare(NetScope*s, perm_string n, unsigned wi) : NetNode(s, n, 10), width_(wi) { signed_flag_ = false; - pin(0).set_dir(Link::INPUT); pin(0).set_name( - perm_string::literal("Aclr")); - pin(1).set_dir(Link::INPUT); pin(1).set_name( - perm_string::literal("Clock")); - pin(2).set_dir(Link::OUTPUT); pin(2).set_name( - perm_string::literal("AGB")); - pin(3).set_dir(Link::OUTPUT); pin(3).set_name( - perm_string::literal("AGEB")); - pin(4).set_dir(Link::OUTPUT); pin(4).set_name( - perm_string::literal("AEB")); - pin(5).set_dir(Link::OUTPUT); pin(5).set_name( - perm_string::literal("ANEB")); - pin(6).set_dir(Link::OUTPUT); pin(6).set_name( - perm_string::literal("ALB")); - pin(7).set_dir(Link::OUTPUT); pin(7).set_name( - perm_string::literal("ALEB")); - pin(8).set_dir(Link::INPUT); - pin(8).set_name(perm_string::literal("DataA")); - pin(9).set_dir(Link::INPUT); - pin(9).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::INPUT); // Aclr + pin(1).set_dir(Link::INPUT); // Clock + pin(2).set_dir(Link::OUTPUT); // AGB + pin(3).set_dir(Link::OUTPUT); // AGEB + pin(4).set_dir(Link::OUTPUT); // AEB + pin(5).set_dir(Link::OUTPUT); // ANEB + pin(6).set_dir(Link::OUTPUT); // ALB + pin(7).set_dir(Link::OUTPUT); // ALEB + pin(8).set_dir(Link::INPUT); // DataA + pin(9).set_dir(Link::INPUT); // DataB } NetCompare::~NetCompare() @@ -1365,6 +1310,7 @@ void NetCompare::set_signed(bool flag) signed_flag_ = flag; } + Link& NetCompare::pin_Aclr() { return pin(0); @@ -1470,12 +1416,9 @@ NetDivide::NetDivide(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), width_r_(wr), width_a_(wa), width_b_(wb), signed_flag_(false) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetDivide::~NetDivide() @@ -1541,7 +1484,6 @@ NetLiteral::NetLiteral(NetScope*sc, perm_string n, const verireal&val) : NetNode(sc, n, 1), real_(val) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); } NetLiteral::~NetLiteral() @@ -1563,12 +1505,9 @@ NetMult::NetMult(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetMult::~NetMult() @@ -1635,12 +1574,9 @@ NetPow::NetPow(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetPow::~NetPow() @@ -1715,14 +1651,11 @@ NetMux::NetMux(NetScope*s, perm_string n, : NetNode(s, n, 2+si), width_(wi), size_(si), swidth_(sw) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q"), 0); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Sel"), 0); + pin(0).set_dir(Link::OUTPUT); // Q + pin(1).set_dir(Link::INPUT); // Sel for (unsigned idx = 0 ; idx < size_ ; idx += 1) { - pin_Data(idx).set_dir(Link::INPUT); - pin_Data(idx).set_name(perm_string::literal("D"), idx); + pin_Data(idx).set_dir(Link::INPUT); // Data[idx] } } @@ -1782,8 +1715,6 @@ NetSignExtend::NetSignExtend(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O"), 0); - pin(1).set_name(perm_string::literal("I"), 0); } NetSignExtend::~NetSignExtend() @@ -1800,8 +1731,6 @@ NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O"), 0); - pin(1).set_name(perm_string::literal("I"), 0); } NetBUFZ::~NetBUFZ() @@ -1816,9 +1745,9 @@ unsigned NetBUFZ::width() const NetCaseCmp::NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq) : NetNode(s, n, 3), width_(wid), eeq_(eeq) { - pin(0).set_dir(Link::OUTPUT); pin(0).set_name(perm_string::literal("O"),0); - pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("I"),0); - pin(2).set_dir(Link::INPUT); pin(2).set_name(perm_string::literal("I"),1); + pin(0).set_dir(Link::OUTPUT); + pin(1).set_dir(Link::INPUT); + pin(2).set_dir(Link::INPUT); } NetCaseCmp::~NetCaseCmp() @@ -1877,7 +1806,6 @@ NetConst::NetConst(NetScope*s, perm_string n, verinum::V v) : NetNode(s, n, 1), width_(1) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); value_ = new verinum::V[1]; value_[0] = v; } @@ -1886,7 +1814,6 @@ NetConst::NetConst(NetScope*s, perm_string n, const verinum&val) : NetNode(s, n, 1), width_(val.len()) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); value_ = new verinum::V[width_]; for (unsigned idx = 0 ; idx < width_ ; idx += 1) { value_[idx] = val.get(idx); @@ -1917,12 +1844,7 @@ NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const svector&po) NetFuncDef::~NetFuncDef() { } -#if 0 -const string NetFuncDef::name() const -{ - return scope_->name(); -} -#endif + const NetScope* NetFuncDef::scope() const { return scope_; @@ -2046,17 +1968,50 @@ NetUTask::NetUTask(NetScope*def) NetUTask::~NetUTask() { } -#if 0 -const string NetUTask::name() const -{ - return task_->name(); -} -#endif + const NetScope* NetUTask::task() const { return task_; } +NetAlloc::NetAlloc(NetScope*scope) +: scope_(scope) +{ +} + +NetAlloc::~NetAlloc() +{ +} +#if 0 +const string NetAlloc::name() const +{ + return scope_->name(); +} +#endif +const NetScope* NetAlloc::scope() const +{ + return scope_; +} + +NetFree::NetFree(NetScope*scope) +: scope_(scope) +{ +} + +NetFree::~NetFree() +{ +} +#if 0 +const string NetFree::name() const +{ + return scope_->name(); +} +#endif +const NetScope* NetFree::scope() const +{ + return scope_; +} + NetExpr::NetExpr(unsigned w) : width_(w), signed_flag_(false) { @@ -2076,6 +2031,13 @@ void NetExpr::cast_signed(bool flag) signed_flag_ = flag; } +void NetExpr::expr_width(unsigned w) +{ + // Catch underflow wrap errors. + ivl_assert(*this, w < (UINT_MAX - 256)); + width_ = w; +} + bool NetExpr::has_width() const { return true; @@ -2111,6 +2073,9 @@ NetEBBits* NetEBBits::dup_expr() const NetEBinary::NetEBinary(char op, NetExpr*l, NetExpr*r) : op_(op), left_(l), right_(r) { + // Binary expressions of all sorts are signed if both the + // arguments are signed. + cast_signed_base_( left_->has_sign() && right_->has_sign()); } NetEBinary::~NetEBinary() @@ -2329,6 +2294,8 @@ const NetExpr* NetETernary::false_expr() const ivl_variable_type_t NetETernary::expr_type() const { + ivl_assert(*this, true_val_); + ivl_assert(*this, false_val_); ivl_variable_type_t tru = true_val_->expr_type(); ivl_variable_type_t fal = false_val_->expr_type(); if (tru == IVL_VT_LOGIC && fal == IVL_VT_BOOL) @@ -2413,10 +2380,8 @@ NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins, : NetNode(s, n, pins), type_(t), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); } } @@ -2435,9 +2400,7 @@ NetUReduce::NetUReduce(NetScope*scope, perm_string n, : NetNode(scope, n, 2), type_(t), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I")); } NetUReduce::TYPE NetUReduce::type() const diff --git a/netlist.h b/netlist.h index a8826ceaa..ed8e16333 100644 --- a/netlist.h +++ b/netlist.h @@ -89,7 +89,7 @@ class NetPins : public LineInfo { Link&pin(unsigned idx); const Link&pin(unsigned idx) const; - void dump_node_pins(ostream&, unsigned) const; + void dump_node_pins(ostream&, unsigned, const char**pin_names =0) const; private: Link*pins_; @@ -194,9 +194,11 @@ class Link { enum strength_t { HIGHZ, WEAK, PULL, STRONG, SUPPLY }; + private: // Only NetPins can create/delete Link objects Link(); ~Link(); + public: // Manipulate the link direction. void set_dir(DIR d); DIR get_dir() const; @@ -210,6 +212,10 @@ class Link { void drive0(strength_t); void drive1(strength_t); + // This sets the drives for all drivers of this link, and not + // just the current link. + void drivers_drive(strength_t d0, strength_t d1); + strength_t drive0() const; strength_t drive1() const; @@ -252,28 +258,19 @@ class Link { NetPins*get_obj(); unsigned get_pin() const; - // A link of an object (sometimes called a "pin") has a - // name. It is convenient for the name to have a string and an - // integer part. - void set_name(perm_string, unsigned inst =0); - perm_string get_name() const; - unsigned get_inst() const; - private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. - NetPins *node_; - unsigned pin_; + union { + NetPins *node_; + unsigned pin_; + }; - DIR dir_; - strength_t drive0_, drive1_; - verinum::V init_; - - // These members name the pin of the link. If the name - // has width, then the inst_ member is the index of the - // pin. - perm_string name_; - unsigned inst_; + bool pin_zero_ : 1; + DIR dir_ : 2; + strength_t drive0_ : 3; + strength_t drive1_ : 3; + verinum::V init_ : 2; private: Link *next_; @@ -312,6 +309,7 @@ class Nexus { verinum::V get_init() const; void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay); + void drivers_drive(Link::strength_t d0, Link::strength_t d1); Link*first_nlink(); const Link* first_nlink()const; @@ -914,13 +912,7 @@ class NetAddSub : public NetNode { // operands and results). unsigned width() const; - Link& pin_Aclr(); - Link& pin_Add_Sub(); - Link& pin_Clock(); - Link& pin_Cin(); Link& pin_Cout(); - Link& pin_Overflow(); - Link& pin_DataA(); Link& pin_DataB(); Link& pin_Result(); @@ -1576,12 +1568,20 @@ class NetExpr : public LineInfo { virtual NexusSet* nex_input(bool rem_out = true) =0; // Return a version of myself that is structural. This is used - // for converting expressions to gates. - virtual NetNet*synthesize(Design*); + // for converting expressions to gates. The arguments are: + // + // des, scope: The context where this work is done + // + // rise/fall/decay: Attach these delays to the driver for the + // expression output. + // + // drive0/drive1: Attach these strengths tp the driver for + // the expression output. + virtual NetNet*synthesize(Design*des, NetScope*scope); protected: - void expr_width(unsigned w) { width_ = w; } + void expr_width(unsigned w); void cast_signed_base_(bool flag) {signed_flag_ = flag; } private: @@ -1615,7 +1615,7 @@ class NetEConst : public NetExpr { virtual void dump(ostream&) const; virtual NetEConst* dup_expr() const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -1632,7 +1632,7 @@ class NetEConstParam : public NetEConst { perm_string name() const; const NetScope*scope() const; - virtual bool set_width(unsigned w, bool last_chance); + virtual bool set_width(unsigned w, bool last_chance =false); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -1668,7 +1668,7 @@ class NetECReal : public NetExpr { virtual void dump(ostream&) const; virtual NetECReal* dup_expr() const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -2086,6 +2086,23 @@ class NetProc : public virtual LineInfo { NetProc& operator= (const NetProc&); }; +class NetAlloc : public NetProc { + + public: + NetAlloc(NetScope*); + ~NetAlloc(); + + const string name() const; + + const NetScope* scope() const; + + virtual bool emit_proc(struct target_t*) const; + virtual void dump(ostream&, unsigned ind) const; + + private: + NetScope*scope_; +}; + /* * Procedural assignment is broken into a suite of classes. These * classes represent the various aspects of the assignment statement @@ -2139,6 +2156,7 @@ class NetAssign_ { // method accounts for the presence of the mux, so it is not // necessarily the same as the pin_count(). unsigned lwidth() const; + ivl_variable_type_t expr_type() const; // Get the name of the underlying object. perm_string name() const; @@ -2230,7 +2248,8 @@ class NetAssign : public NetAssignBase { class NetAssignNB : public NetAssignBase { public: - explicit NetAssignNB(NetAssign_*lv, NetExpr*rv); + explicit NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, + NetExpr*cnt); ~NetAssignNB(); @@ -2238,7 +2257,13 @@ class NetAssignNB : public NetAssignBase { virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + unsigned nevents() const; + const NetEvent*event(unsigned) const; + const NetExpr* get_count() const; + private: + NetEvWait*event_; + NetExpr*count_; }; /* @@ -2620,6 +2645,8 @@ class NetEvWait : public NetProc { const svector&events); virtual void dump(ostream&, unsigned ind) const; + // This will ignore any statement. + virtual void dump_inline(ostream&) const; virtual DelayType delay_type() const; private: @@ -2629,6 +2656,8 @@ class NetEvWait : public NetProc { NetEvent**events_; }; +ostream& operator << (ostream&out, const NetEvWait&obj); + class NetEvProbe : public NetNode { friend class NetEvent; @@ -2694,6 +2723,23 @@ class NetForever : public NetProc { NetProc*statement_; }; +class NetFree : public NetProc { + + public: + NetFree(NetScope*); + ~NetFree(); + + const string name() const; + + const NetScope* scope() const; + + virtual bool emit_proc(struct target_t*) const; + virtual void dump(ostream&, unsigned ind) const; + + private: + NetScope*scope_; +}; + /* * A function definition is elaborated just like a task, though by now * it is certain that the first parameter (a phantom parameter) is the @@ -2905,7 +2951,7 @@ class NetEUFunc : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEUFunc*dup_expr() const; virtual NexusSet* nex_input(bool rem_out = true); - virtual NetNet* synthesize(Design*des); + virtual NetNet* synthesize(Design*des, NetScope*scope); private: NetScope*scope_; @@ -3120,7 +3166,7 @@ class NetEBAdd : public NetEBinary { virtual bool set_width(unsigned w, bool last_chance); virtual NetEBAdd* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: NetECReal* eval_tree_real_(); @@ -3142,7 +3188,7 @@ class NetEBDiv : public NetEBinary { virtual bool set_width(unsigned w, bool last_chance); virtual NetEBDiv* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); }; /* @@ -3169,7 +3215,7 @@ class NetEBBits : public NetEBinary { virtual NetEBBits* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); }; /* @@ -3200,7 +3246,7 @@ class NetEBComp : public NetEBinary { virtual NetEBComp* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); @@ -3232,7 +3278,7 @@ class NetEBLogic : public NetEBinary { virtual bool set_width(unsigned w, bool last_chance); virtual NetEBLogic* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: }; @@ -3270,7 +3316,7 @@ class NetEBMult : public NetEBinary { virtual bool set_width(unsigned w, bool last_chance); virtual NetEBMult* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: @@ -3292,7 +3338,7 @@ class NetEBPow : public NetEBinary { virtual bool set_width(unsigned w, bool last_chance); virtual NetEBPow* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: @@ -3324,7 +3370,7 @@ class NetEBShift : public NetEBinary { virtual NetEBShift* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); private: }; @@ -3358,7 +3404,7 @@ class NetEConcat : public NetExpr { virtual bool set_width(unsigned w, bool last_chance =false); virtual NetEConcat* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -3434,7 +3480,7 @@ class NetESelect : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetESelect* dup_expr() const; - virtual NetNet*synthesize(Design*des); + virtual NetNet*synthesize(Design*des, NetScope*scope); virtual void dump(ostream&) const; private: @@ -3514,7 +3560,7 @@ class NetESFunc : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetESFunc*dup_expr() const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope); private: const char* name_; @@ -3551,7 +3597,10 @@ class NetETernary : public NetExpr { virtual NexusSet* nex_input(bool rem_out = true); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope); + + public: + static bool test_operand_compat(ivl_variable_type_t tru, ivl_variable_type_t fal); private: NetExpr*cond_; @@ -3588,6 +3637,7 @@ class NetEUnary : public NetExpr { virtual NetEUnary* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); + virtual NetNet* synthesize(Design*, NetScope*scope); virtual ivl_variable_type_t expr_type() const; virtual NexusSet* nex_input(bool rem_out = true); @@ -3608,7 +3658,7 @@ class NetEUBits : public NetEUnary { NetEUBits(char op, NetExpr*ex); ~NetEUBits(); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; @@ -3621,7 +3671,7 @@ class NetEUReduce : public NetEUnary { ~NetEUReduce(); virtual bool set_width(unsigned w, bool last_chance); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope); virtual NetEUReduce* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; @@ -3648,7 +3698,7 @@ class NetESignal : public NetExpr { virtual bool set_width(unsigned, bool last_chance); virtual NetESignal* dup_expr() const; - NetNet* synthesize(Design*des); + NetNet* synthesize(Design*des, NetScope*scope); NexusSet* nex_input(bool rem_out = true); // This is the expression for selecting an array word, if this diff --git a/netmisc.cc b/netmisc.cc index 7f82fd129..b223795d3 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -76,6 +76,46 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val) #endif } +NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) +{ + NetNet*zero_net = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sig->vector_width()); + zero_net->data_type(sig->data_type()); + zero_net->local_flag(true); + + if (sig->data_type() == IVL_VT_REAL) { + verireal zero (val); + NetLiteral*zero_obj = new NetLiteral(scope, scope->local_symbol(), zero); + des->add_node(zero_obj); + + connect(zero_net->pin(0), zero_obj->pin(0)); + + } else { + verinum zero ((int64_t)val); + zero = pad_to_width(zero, sig->vector_width()); + NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero); + des->add_node(zero_obj); + + connect(zero_net->pin(0), zero_obj->pin(0)); + } + + NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), sig->vector_width()); + des->add_node(adder); + adder->attribute(perm_string::literal("LPM_Direction"), verinum("SUB")); + + connect(zero_net->pin(0), adder->pin_DataA()); + connect(adder->pin_DataB(), sig->pin(0)); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sig->vector_width()); + tmp->data_type(sig->data_type()); + tmp->local_flag(true); + + connect(adder->pin_Result(), tmp->pin(0)); + + return tmp; +} + NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid) { if (src->data_type() != IVL_VT_REAL) @@ -170,6 +210,27 @@ NetEConst* make_const_x(unsigned long wid) return resx; } +NetEConst* make_const_0(unsigned long wid) +{ + verinum xxx (verinum::V0, wid); + NetEConst*resx = new NetEConst(xxx); + return resx; +} + +NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid) +{ + verinum xxx (verinum::Vx, wid); + NetConst*res = new NetConst(scope, scope->local_symbol(), xxx); + des->add_node(res); + + NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + sig->local_flag(true); + sig->data_type(IVL_VT_LOGIC); + + connect(sig->pin(0), res->pin(0)); + return sig; +} + NetExpr* condition_reduce(NetExpr*expr) { if (expr->expr_width() == 1) @@ -317,26 +378,28 @@ const char *human_readable_op(const char op) { const char *type; switch (op) { - case '~': type = "~"; break; // Negation + case '~': type = "~"; break; // Negation - case '^': type = "^"; break; // XOR - case 'X': type = "~^"; break; // XNOR - case '&': type = "&"; break; // Bitwise AND - case 'A': type = "~&"; break; // NAND (~&) - case '|': type = "|"; break; // Bitwise OR - case 'O': type = "~|"; break; // NOR + case '^': type = "^"; break; // XOR + case 'X': type = "~^"; break; // XNOR + case '&': type = "&"; break; // Bitwise AND + case 'A': type = "~&"; break; // NAND (~&) + case '|': type = "|"; break; // Bitwise OR + case 'O': type = "~|"; break; // NOR - case 'a': type = "&&"; break; // Logical AND - case 'o': type = "||"; break; // Logical OR + case '!': type = "!"; break; // Logical NOT + case 'a': type = "&&"; break; // Logical AND + case 'o': type = "||"; break; // Logical OR - case 'E': type = "==="; break; // Case equality - case 'N': type = "!=="; break; // Case inequality + case 'E': type = "==="; break; // Case equality + case 'N': type = "!=="; break; // Case inequality - case 'l': type = "<<(<)"; break; // Left shifts - case 'r': type = ">>"; break; // Logical right shift - case 'R': type = ">>>"; break; // Arithmetic right shift + case 'l': type = "<<(<)"; break; // Left shifts + case 'r': type = ">>"; break; // Logical right shift + case 'R': type = ">>>"; break; // Arithmetic right shift - default: assert(0); + default: + assert(0); } return type; } diff --git a/netmisc.h b/netmisc.h index 7d1b42a90..7e31b37fa 100644 --- a/netmisc.h +++ b/netmisc.h @@ -91,6 +91,7 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); * return a new NetNet value that is the output of an addition. */ extern NetNet*add_to_net(Design*des, NetNet*sig, long val); +extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig); /* * These functions make various sorts of expressions, given operands @@ -113,6 +114,12 @@ 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); +extern NetEConst*make_const_0(unsigned long wid); + +/* + * Make A const net + */ +extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid); /* * In some cases the lval is accessible as a pointer to the head of @@ -130,14 +137,27 @@ extern unsigned count_lval_width(const class NetAssign_*first); * The expr_width is the width of the context where the expression is * being elaborated, or -1 if the expression is self-determined width. * - * Also, the prune_width is the maximum width of the result, and it - * passed to the eval_tree method of the expression to limit constant - * results if possible. + * The prune_width is the maximum width of the result, and is passed + * to the eval_tree method of the expression to limit constant + * results. The evaluation will prune any constant result down to the + * prune_width (if >0) so should only be used at the point where it is + * bound to the destination. */ class PExpr; extern NetExpr* elab_and_eval(Design*des, NetScope*scope, const PExpr*pe, int expr_wid, int prune_width =-1); + +/* + * This function elaborates an expression as if it is for the r-value + * of an assignment, The data_type_lv and expr_wid_lv are the type and + * with of the l-value, and the expr is the expression to + * elaborate. The result is the NetExpr elaborated and evaluated. + * (See elab_expr.cc) + */ +extern NetExpr* elaborate_rval_expr(Design*des, NetScope*scope, + ivl_variable_type_t data_type_lv, + int expr_wid_lv, const PExpr*expr); /* * This procedure elaborates an expression and if the elaboration is * successful the original expression is replaced with the new one. @@ -165,6 +185,13 @@ extern hname_t eval_path_component(Design*des, NetScope*scope, extern std::list eval_scope_path(Design*des, NetScope*scope, const pform_name_t&path); +/* + * Return true if the data type is a type that is normally available + * in vector for. IVL_VT_BOOL and IVL_VT_LOGIC are vectorable, + * IVL_VT_REAL is not. + */ +extern bool type_is_vectorable(ivl_variable_type_t type); + /* * Return a human readable version of the operator. */ diff --git a/pad_to_width.cc b/pad_to_width.cc index 784e98918..373d9457e 100644 --- a/pad_to_width.cc +++ b/pad_to_width.cc @@ -88,6 +88,7 @@ NetNet*pad_to_width(Design*des, NetNet*net, unsigned wid) tmp = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); tmp->data_type( net->data_type() ); + tmp->set_line(*net); tmp->local_flag(true); connect(cc->pin(0), tmp->pin(0)); diff --git a/parse.y b/parse.y index a0dde49d0..bbd049151 100644 --- a/parse.y +++ b/parse.y @@ -157,7 +157,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) svector*gates; Module::port_t *mport; - Module::range_t* value_range; + LexicalScope::range_t* value_range; svector*mports; named_pexpr_t*named_pexpr; @@ -459,10 +459,14 @@ block_item_decl with real value. Note that real and realtime are interchangeable in this context. */ - | attribute_list_opt K_real real_variable_list ';' - { delete $3; } - | attribute_list_opt K_realtime real_variable_list ';' - { delete $3; } + | attribute_list_opt K_real real_variable_list ';' + { delete $3; } + | attribute_list_opt K_realtime real_variable_list ';' + { delete $3; } + + | K_event list_of_identifiers ';' + { pform_make_events($2, @1.text, @1.first_line); + } | K_parameter parameter_assign_decl ';' | K_localparam localparam_assign_decl ';' @@ -2036,9 +2040,6 @@ module_item /* */ | K_defparam defparam_assign_list ';' - | K_event list_of_identifiers ';' - { pform_make_events($2, @1.text, @1.first_line); - } /* Most gate types have an optional drive strength and optional three-value delay. These rules handle the different cases. */ diff --git a/pform.cc b/pform.cc index c0b1156e4..03c6b266f 100644 --- a/pform.cc +++ b/pform.cc @@ -170,52 +170,39 @@ void pform_bind_attributes(map&attributes, delete attr; } +static LexicalScope*pform_get_cur_scope() +{ + if (pform_cur_generate) + if (pform_cur_generate->lexical_scope) + return pform_cur_generate->lexical_scope; + else + return pform_cur_generate; + else + return lexical_scope; +} + 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 cannot be within sub-scopes. Only directly in modules. */ - if (pform_cur_generate) - if (pform_cur_generate->lexical_scope) - return pform_cur_generate->lexical_scope->wires_find(name); - else - return pform_cur_generate->wires_find(name); - else - return lexical_scope->wires_find(name); + return pform_get_cur_scope()->wires_find(name); } static void pform_put_wire_in_scope(perm_string name, PWire*net) { - if (pform_cur_generate) - if (pform_cur_generate->lexical_scope) - pform_cur_generate->lexical_scope->wires[name] = net; - else - pform_cur_generate->wires[name] = net; - else - lexical_scope->wires[name] = net; + pform_get_cur_scope()->wires[name] = net; } static void pform_put_behavior_in_scope(PProcess*pp) { - if (pform_cur_generate) - if (pform_cur_generate->lexical_scope) - pform_cur_generate->lexical_scope->behaviors.push_back(pp); - else - pform_cur_generate->behaviors.push_back(pp); - else - lexical_scope->behaviors.push_back(pp); + pform_get_cur_scope()->behaviors.push_back(pp); } void pform_put_behavior_in_scope(AProcess*pp) { - if (pform_cur_generate) - if (pform_cur_generate->lexical_scope) - pform_cur_generate->lexical_scope->analog_behaviors.push_back(pp); - else - pform_cur_generate->analog_behaviors.push_back(pp); - else - lexical_scope->analog_behaviors.push_back(pp); + pform_get_cur_scope()->analog_behaviors.push_back(pp); } void pform_set_default_nettype(NetNet::Type type, @@ -1045,7 +1032,7 @@ static void pform_make_event(perm_string name, const char*fn, unsigned ln) { PEvent*event = new PEvent(name); FILE_NAME(event, fn, ln); - pform_cur_module->events[name] = event; + pform_get_cur_scope()->events[name] = event; } void pform_make_events(list*names, const char*fn, unsigned ln) @@ -1705,7 +1692,7 @@ void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r) cur->set_memory_idx(l, r); } -Module::range_t* pform_parameter_value_range(bool exclude_flag, +LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, bool low_open, PExpr*low_expr, bool hig_open, PExpr*hig_expr) { @@ -1714,7 +1701,7 @@ Module::range_t* pform_parameter_value_range(bool exclude_flag, if (low_expr == 0) low_open = false; if (hig_expr == 0) hig_open = false; - Module::range_t*tmp = new Module::range_t; + LexicalScope::range_t*tmp = new LexicalScope::range_t; tmp->exclude_flag = exclude_flag; tmp->low_open_flag = low_open; tmp->low_expr = low_expr; @@ -1727,10 +1714,15 @@ Module::range_t* pform_parameter_value_range(bool exclude_flag, void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, svector*range, PExpr*expr, - Module::range_t*value_range) + LexicalScope::range_t*value_range) { + if (pform_get_cur_scope() == pform_cur_generate) { + VLerror("parameter declarations are not permitted in generate blocks"); + return; + } + assert(expr); - Module::param_expr_t&parm = pform_cur_module->parameters[name]; + Module::param_expr_t&parm = pform_get_cur_scope()->parameters[name]; FILE_NAME(&parm, loc); parm.expr = expr; @@ -1749,7 +1741,8 @@ void pform_set_parameter(const struct vlltype&loc, parm.signed_flag = signed_flag; parm.range = value_range; - pform_cur_module->param_names.push_back(name); + if (pform_get_cur_scope() == pform_cur_module) + pform_cur_module->param_names.push_back(name); } void pform_set_localparam(const struct vlltype&loc, @@ -1757,7 +1750,7 @@ void pform_set_localparam(const struct vlltype&loc, bool signed_flag, svector*range, PExpr*expr) { assert(expr); - Module::param_expr_t&parm = pform_cur_module->localparams[name]; + Module::param_expr_t&parm = pform_get_cur_scope()->localparams[name]; FILE_NAME(&parm, loc); parm.expr = expr; diff --git a/pform.h b/pform.h index 455178804..d372db52b 100644 --- a/pform.h +++ b/pform.h @@ -272,7 +272,7 @@ 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 Module::range_t* pform_parameter_value_range(bool exclude_flag, +extern LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, bool low_open, PExpr*low_expr, bool hig_open, PExpr*hig_expr); @@ -281,7 +281,7 @@ extern void pform_set_parameter(const struct vlltype&loc, ivl_variable_type_t type, bool signed_flag, svector*range, - PExpr*expr, Module::range_t*value_range); + PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 2ce7aeedd..5660a8fe5 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -78,7 +78,7 @@ void pform_end_nature(const struct vlltype&loc) error_count += 1; } - // Map the access functio back to the nature so that + // Map the access function back to the nature so that // expressions that use the access function can find it. access_function_nature[nature_access] = tmp; diff --git a/pform_dump.cc b/pform_dump.cc index fbda728a3..a41b835d3 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -295,6 +295,9 @@ void PEBinary::dump(ostream&out) const case 'l': out << "<<"; break; + case 'L': + out << "<="; + break; case 'n': out << "!="; break; @@ -592,8 +595,15 @@ void PBlock::dump(ostream&out, unsigned ind) const out << " : " << pscope_name(); out << endl; - if (pscope_name() != 0) + if (pscope_name() != 0) { + dump_parameters_(out, ind+2); + + dump_localparams_(out, ind+2); + + dump_events_(out, ind+2); + dump_wires_(out, ind+2); + } for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) { if (list_[idx]) @@ -812,6 +822,12 @@ void PFunction::dump(ostream&out, unsigned ind) const out << (*ports_)[idx]->basename() << ";" << endl; } + dump_parameters_(out, ind); + + dump_localparams_(out, ind); + + dump_events_(out, ind); + dump_wires_(out, ind); if (statement_) @@ -857,6 +873,12 @@ void PTask::dump(ostream&out, unsigned ind) const out << (*ports_)[idx]->basename() << ";" << endl; } + dump_parameters_(out, ind); + + dump_localparams_(out, ind); + + dump_events_(out, ind); + dump_wires_(out, ind); if (statement_) @@ -993,11 +1015,11 @@ void PGenerate::dump(ostream&out, unsigned indent) const out << endl; - for (map::const_iterator idx = wires.begin() - ; idx != wires.end() ; idx++) { + dump_localparams_(out, indent+2); - (*idx).second->dump(out, indent+2); - } + dump_events_(out, indent+2); + + dump_wires_(out, indent+2); for (list::const_iterator idx = gates.begin() ; idx != gates.end() ; idx++) { @@ -1022,7 +1044,83 @@ void PGenerate::dump(ostream&out, unsigned indent) const out << setw(indent) << "" << "endgenerate" << endl; } -void PScope::dump_wires_(ostream&out, unsigned indent) const +void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const +{ + typedef map::const_iterator parm_iter_t; + for (parm_iter_t cur = parameters.begin() + ; cur != parameters.end() ; cur ++) { + out << setw(indent) << "" << "parameter " + << (*cur).second.type << " "; + if ((*cur).second.signed_flag) + out << "signed "; + if ((*cur).second.msb) + out << "[" << *(*cur).second.msb << ":" + << *(*cur).second.lsb << "] "; + out << (*cur).first << " = "; + if ((*cur).second.expr) + out << *(*cur).second.expr; + else + out << "/* ERROR */"; + for (LexicalScope::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 << ""; + out << ":"; + if (tmp->high_expr) + out << *(tmp->high_expr); + else if (tmp->high_open_flag==false) + out << "inf"; + else + out << ""; + if (tmp->high_open_flag) + out << ")"; + else + out << "]"; + } + out << ";" << endl; + } +} + +void LexicalScope::dump_localparams_(ostream&out, unsigned indent) const +{ + typedef map::const_iterator parm_iter_t; + for (parm_iter_t cur = localparams.begin() + ; cur != localparams.end() ; cur ++) { + out << setw(indent) << "" << "localparam "; + if ((*cur).second.msb) + out << "[" << *(*cur).second.msb << ":" + << *(*cur).second.lsb << "] "; + out << (*cur).first << " = "; + if ((*cur).second.expr) + out << *(*cur).second.expr << ";" << endl; + else + out << "/* ERROR */;" << endl; + } +} + +void LexicalScope::dump_events_(ostream&out, unsigned indent) const +{ + for (map::const_iterator cur = events.begin() + ; cur != events.end() ; cur ++ ) { + PEvent*ev = (*cur).second; + out << setw(indent) << "" << "event " << ev->name() << "; // " + << ev->get_fileline() << endl; + } +} + +void LexicalScope::dump_wires_(ostream&out, unsigned indent) const { // Iterate through and display all the wires. for (map::const_iterator wire = wires.begin() @@ -1067,63 +1165,9 @@ void Module::dump(ostream&out) const out << ")" << endl; } - typedef map::const_iterator parm_iter_t; - for (parm_iter_t cur = parameters.begin() - ; cur != parameters.end() ; cur ++) { - out << " parameter " << (*cur).second.type << " "; - if ((*cur).second.signed_flag) - out << "signed "; - if ((*cur).second.msb) - out << "[" << *(*cur).second.msb << ":" - << *(*cur).second.lsb << "] "; - out << (*cur).first << " = "; - if ((*cur).second.expr) - out << *(*cur).second.expr; - else - 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 << ""; - out << ":"; - if (tmp->high_expr) - out << *(tmp->high_expr); - else if (tmp->high_open_flag==false) - out << "inf"; - else - out << ""; - if (tmp->high_open_flag) - out << ")"; - else - out << "]"; - } - out << ";" << endl; - } + dump_parameters_(out, 4); - for (parm_iter_t cur = localparams.begin() - ; cur != localparams.end() ; cur ++) { - out << " localparam "; - if ((*cur).second.msb) - out << "[" << *(*cur).second.msb << ":" - << *(*cur).second.lsb << "] "; - out << (*cur).first << " = "; - if ((*cur).second.expr) - out << *(*cur).second.expr << ";" << endl; - else - out << "/* ERROR */;" << endl; - } + dump_localparams_(out, 4); typedef map::const_iterator genvar_iter_t; for (genvar_iter_t cur = genvars.begin() @@ -1154,12 +1198,7 @@ void Module::dump(ostream&out) const out << "/* ERROR */;" << endl; } - for (map::const_iterator cur = events.begin() - ; cur != events.end() ; cur ++ ) { - PEvent*ev = (*cur).second; - out << " event " << ev->name() << "; // " - << ev->get_fileline() << endl; - } + dump_events_(out, 4); // Iterate through and display all the wires. dump_wires_(out, 4); diff --git a/set_width.cc b/set_width.cc index 4aecfc849..cb736cea0 100644 --- a/set_width.cc +++ b/set_width.cc @@ -180,7 +180,13 @@ bool NetEBLogic::set_width(unsigned w, bool) */ bool NetEBMult::set_width(unsigned w, bool) { - return w == expr_width(); + if (w < left_->expr_width()) + left_->set_width(w); + if (w < right_->expr_width()) + right_->expr_width(); + + expr_width(w); + return true; } bool NetEBPow::set_width(unsigned w, bool last_chance) diff --git a/syn-rules.y b/syn-rules.y index 49ea2586b..78c4b4588 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 2000-2007 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 @@ -141,7 +141,7 @@ static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk, NetEvProbe*pclk = eclk->probe(0); NetESignal*d = dynamic_cast (asn->rval()); - NetNet*ce = cexp? cexp->synthesize(des) : 0; + NetNet*ce = cexp? cexp->synthesize(des, top->scope()) : 0; if (d == 0) { cerr << asn->get_fileline() << ": internal error: " diff --git a/synth.cc b/synth.cc index e92276d3a..ac2aaeb87 100644 --- a/synth.cc +++ b/synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2000 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: synth.cc,v 1.14 2002/08/12 01:35:00 steve Exp $" -#endif # include "config.h" @@ -36,12 +33,13 @@ class do_expr : public proc_match_t { public: - do_expr(Design*d) - : des_(d) { } + do_expr(Design*d, NetScope*s) + : des_(d), scope_(s) { } private: Design*des_; + NetScope*scope_; virtual int assign(NetAssign*); virtual int assign_nb(NetAssignNB*); @@ -55,7 +53,7 @@ int do_expr::assign(NetAssign*stmt) if (dynamic_cast(stmt->rval())) return 0; - NetNet*tmp = stmt->rval()->synthesize(des_); + NetNet*tmp = stmt->rval()->synthesize(des_, scope_); if (tmp == 0) return 0; @@ -70,7 +68,7 @@ int do_expr::assign_nb(NetAssignNB*stmt) if (dynamic_cast(stmt->rval())) return 0; - NetNet*tmp = stmt->rval()->synthesize(des_); + NetNet*tmp = stmt->rval()->synthesize(des_, scope_); if (tmp == 0) return 0; @@ -84,7 +82,7 @@ int do_expr::condit(NetCondit*stmt) { /* synthesize the condition expression, if necessary. */ if (! dynamic_cast(stmt->expr())) { - NetNet*tmp = stmt->expr()->synthesize(des_); + NetNet*tmp = stmt->expr()->synthesize(des_, scope_); if (tmp) { NetESignal*tmpe = new NetESignal(tmp); @@ -144,13 +142,13 @@ void synth_f::process(class Design*des, class NetProcTop*top) void synth_f::proc_always_(class Design*des) { - do_expr expr_pat(des); + do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } void synth_f::proc_initial_(class Design*des) { - do_expr expr_pat(des); + do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } @@ -159,28 +157,3 @@ void synth(Design*des) synth_f synth_obj; des->functor(&synth_obj); } - -/* - * $Log: synth.cc,v $ - * Revision 1.14 2002/08/12 01:35:00 steve - * conditional ident string using autoconfig. - * - * Revision 1.13 2002/06/05 03:44:25 steve - * Add support for memory words in l-value of - * non-blocking assignments, and remove the special - * NetAssignMem_ and NetAssignMemNB classes. - * - * Revision 1.12 2001/07/25 03:10:49 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.11 2000/11/22 21:18:42 steve - * synthesize the rvalue of <= statements. - * - * Revision 1.10 2000/05/13 20:55:47 steve - * Use yacc based synthesizer. - * - * Revision 1.9 2000/04/16 22:57:34 steve - * Catch expressions that are part of conditionals. - */ - diff --git a/synth2.cc b/synth2.cc index 812dceb03..dbd843759 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2007 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 @@ -60,7 +60,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*ff, bool NetAssignBase::synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out) { - NetNet*rsig = rval_->synthesize(des); + NetNet*rsig = rval_->synthesize(des, scope); assert(rsig); NetNet*lsig = lval_->sig(); @@ -155,7 +155,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope, const NetBus&nex_map, NetBus&nex_out) { /* Synthesize the select expression. */ - NetNet*esig = expr_->synthesize(des); + NetNet*esig = expr_->synthesize(des, scope); unsigned sel_width = esig->vector_width(); assert(sel_width > 0); diff --git a/t-dll-api.cc b/t-dll-api.cc index 5d9c49c41..ebfee98e5 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -118,6 +118,7 @@ extern "C" const char*ivl_const_bits(ivl_net_const_t net) assert(net); switch (net->type) { + case IVL_VT_BOOL: case IVL_VT_LOGIC: if (net->width_ <= sizeof(net->b.bit_)) return net->b.bit_; @@ -1912,9 +1913,15 @@ extern "C" ivl_statement_t ivl_stmt_block_stmt(ivl_statement_t net, extern "C" ivl_scope_t ivl_stmt_call(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ALLOC: + return net->u_.alloc_.scope; + case IVL_ST_DISABLE: return net->u_.disable_.scope; + case IVL_ST_FREE: + return net->u_.free_.scope; + case IVL_ST_UTASK: return net->u_.utask_.def; default: @@ -1972,6 +1979,9 @@ extern "C" ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned idx) extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.count; + case IVL_ST_CONDIT: return net->u_.condit_.cond_; @@ -2034,6 +2044,9 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.nevent; + case IVL_ST_WAIT: return net->u_.wait_.nevent; @@ -2049,6 +2062,13 @@ extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + assert(idx < net->u_.assign_.nevent); + if (net->u_.assign_.nevent == 1) + return net->u_.assign_.event; + else + return net->u_.assign_.events[idx]; + case IVL_ST_WAIT: assert(idx < net->u_.wait_.nevent); if (net->u_.wait_.nevent == 1) @@ -2059,6 +2079,7 @@ extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) case IVL_ST_TRIGGER: assert(idx == 0); return net->u_.wait_.event; + default: assert(0); } diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 8e26f6d3d..b3b96973f 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -59,7 +59,7 @@ bool dll_target::process(const NetProcTop*net) /* This little bit causes the process to be completely generated so that it can be passed to the DLL. The - stmt_cur_ member us used to hold a pointer to the current + stmt_cur_ member is used to hold a pointer to the current statement in progress, and the emit_proc() method fills in that object. @@ -188,6 +188,16 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net) } } +void dll_target::proc_alloc(const NetAlloc*net) +{ + assert(stmt_cur_); + assert(stmt_cur_->type_ == IVL_ST_NONE); + FILE_NAME(stmt_cur_, net); + + stmt_cur_->type_ = IVL_ST_ALLOC; + stmt_cur_->u_.alloc_.scope = lookup_scope_(net->scope()); +} + /* */ bool dll_target::proc_assign(const NetAssign*net) @@ -222,6 +232,7 @@ bool dll_target::proc_assign(const NetAssign*net) void dll_target::proc_assign_nb(const NetAssignNB*net) { const NetExpr* delay_exp = net->get_delay(); + const NetExpr* cnt_exp = net->get_count(); assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); @@ -229,6 +240,8 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) FILE_NAME(stmt_cur_, net); stmt_cur_->u_.assign_.delay = 0; + stmt_cur_->u_.assign_.count = 0; + stmt_cur_->u_.assign_.nevent = 0; /* Make the lval fields. */ make_assign_lvals_(net); @@ -239,6 +252,7 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.rval_ = expr_; expr_ = 0; + /* Process a delay if it exists. */ if (const NetEConst*delay_num = dynamic_cast(delay_exp)) { verinum val = delay_num->value(); ivl_expr_t de = new struct ivl_expr_s; @@ -253,6 +267,96 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.delay = expr_; expr_ = 0; } + + /* Process a count if it exists. */ + if (const NetEConst*cnt_num = dynamic_cast(cnt_exp)) { + verinum val = cnt_num->value(); + ivl_expr_t cnt = new struct ivl_expr_s; + cnt->type_ = IVL_EX_ULONG; + cnt->width_ = 8 * sizeof(unsigned long); + cnt->signed_ = 0; + cnt->u_.ulong_.value = val.as_ulong(); + stmt_cur_->u_.assign_.count = cnt; + + } else if (cnt_exp != 0) { + cnt_exp->expr_scan(this); + stmt_cur_->u_.assign_.count = expr_; + expr_ = 0; + } + + /* Process the events if they exist. This is a copy of code + * from NetEvWait below. */ + if (net->nevents() > 0) { + stmt_cur_->u_.assign_.nevent = net->nevents(); + if (net->nevents() > 1) { + stmt_cur_->u_.assign_.events = (ivl_event_t*) + calloc(net->nevents(), sizeof(ivl_event_t*)); + } + + for (unsigned edx = 0 ; edx < net->nevents() ; edx += 1) { + + /* Locate the event by name. Save the ivl_event_t in the + statement so that the generator can find it easily. */ + const NetEvent*ev = net->event(edx); + ivl_scope_t ev_scope = lookup_scope_(ev->scope()); + ivl_event_t ev_tmp=0; + + assert(ev_scope); + assert(ev_scope->nevent_ > 0); + for (unsigned idx = 0; idx < ev_scope->nevent_; idx += 1) { + const char*ename = + ivl_event_basename(ev_scope->event_[idx]); + if (strcmp(ev->name(), ename) == 0) { + ev_tmp = ev_scope->event_[idx]; + break; + } + } + // XXX should we assert(ev_tmp)? + + if (net->nevents() == 1) + stmt_cur_->u_.assign_.event = ev_tmp; + else + stmt_cur_->u_.assign_.events[edx] = ev_tmp; + + /* If this is an event with a probe, then connect up the + pins. This wasn't done during the ::event method because + the signals weren't scanned yet. */ + + if (ev->nprobe() >= 1) { + unsigned iany = 0; + unsigned ineg = ev_tmp->nany; + unsigned ipos = ineg + ev_tmp->nneg; + + for (unsigned idx = 0; idx < ev->nprobe(); idx += 1) { + const NetEvProbe*pr = ev->probe(idx); + unsigned base = 0; + + switch (pr->edge()) { + case NetEvProbe::ANYEDGE: + base = iany; + iany += pr->pin_count(); + break; + case NetEvProbe::NEGEDGE: + base = ineg; + ineg += pr->pin_count(); + break; + case NetEvProbe::POSEDGE: + base = ipos; + ipos += pr->pin_count(); + break; + } + + for (unsigned bit = 0; bit < pr->pin_count(); + bit += 1) { + ivl_nexus_t nex = (ivl_nexus_t) + pr->pin(bit).nexus()->t_cookie(); + assert(nex); + ev_tmp->pins[base+bit] = nex; + } + } + } + } + } } bool dll_target::proc_block(const NetBlock*net) @@ -535,6 +639,16 @@ void dll_target::proc_forever(const NetForever*net) stmt_cur_ = save_cur_; } +void dll_target::proc_free(const NetFree*net) +{ + assert(stmt_cur_); + assert(stmt_cur_->type_ == IVL_ST_NONE); + FILE_NAME(stmt_cur_, net); + + stmt_cur_->type_ = IVL_ST_FREE; + stmt_cur_->u_.free_.scope = lookup_scope_(net->scope()); +} + bool dll_target::proc_release(const NetRelease*net) { assert(stmt_cur_); @@ -643,6 +757,7 @@ bool dll_target::proc_wait(const NetEvWait*net) stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*) calloc(1, sizeof(struct ivl_statement_s)); + // This event processing code is also in the NB assign above. stmt_cur_->u_.wait_.nevent = net->nevents(); if (net->nevents() > 1) { stmt_cur_->u_.wait_.events = (ivl_event_t*) diff --git a/t-dll.cc b/t-dll.cc index 7e4f1714f..d41359bbd 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -32,6 +32,8 @@ # include # include "ivl_assert.h" +struct dll_target dll_target_obj; + #if defined(__WIN32__) inline ivl_dll_t ivl_dlopen(const char *name) @@ -144,8 +146,6 @@ static perm_string make_scope_name(const hname_t&name) return lex_strings.make(buf); } -static struct dll_target dll_target_obj; - static void drive_from_link(const Link&lnk, ivl_drive_t&drv0, ivl_drive_t&drv1) { switch (lnk.drive0()) { @@ -2199,7 +2199,7 @@ bool dll_target::net_const(const NetConst*net) struct ivl_net_const_s *obj = new struct ivl_net_const_s; - obj->type = IVL_VT_LOGIC; + obj->type = IVL_VT_BOOL; /* constants have a single vector output. */ assert(net->pin_count() == 1); @@ -2223,9 +2223,13 @@ bool dll_target::net_const(const NetConst*net) bits[idx] = '1'; break; case verinum::Vx: + if (obj->type == IVL_VT_BOOL) + obj->type = IVL_VT_LOGIC; bits[idx] = 'x'; break; case verinum::Vz: + if (obj->type == IVL_VT_BOOL) + obj->type = IVL_VT_LOGIC; bits[idx] = 'z'; break; } @@ -2579,4 +2583,38 @@ bool dll_target::signal_paths(const NetNet*net) return true; } -extern const struct target tgt_dll = { "dll", &dll_target_obj }; + +void dll_target::test_version(const char*target_name) +{ + dll_ = ivl_dlopen(target_name); + + if ((dll_ == 0) && (target_name[0] != '/')) { + size_t len = strlen(basedir) + 1 + strlen(target_name) + 1; + char*tmp = new char[len]; + sprintf(tmp, "%s/%s", basedir, target_name); + dll_ = ivl_dlopen(tmp); + delete[]tmp; + } + + if (dll_ == 0) { + cout << "\n\nUnable to load " << target_name + << " for version details." << endl; + return; + } + + target_query_f target_query = (target_query_f)ivl_dlsym(dll_, LU "target_query" TU); + if (target_query == 0) { + cerr << "Target " << target_name + << " has no version hooks." << endl; + return; + } + + const char*version_string = (*target_query) ("version"); + if (version_string == 0) { + cerr << "Target " << target_name + << " has no version string" << endl; + return; + } + + cout << target_name << ": " << version_string << endl; +} diff --git a/t-dll.h b/t-dll.h index e3646417b..7989ab8f9 100644 --- a/t-dll.h +++ b/t-dll.h @@ -63,6 +63,10 @@ struct ivl_design_s { */ struct dll_target : public target_t, public expr_scan_t { + // This is a special function for loading and testing the + // version of a loadable target code generator. + void test_version(const char*target_name); + bool start_design(const Design*); int end_design(const Design*); @@ -111,6 +115,7 @@ struct dll_target : public target_t, public expr_scan_t { /* These methods and members are used for forming the statements of a thread. */ struct ivl_statement_s*stmt_cur_; + void proc_alloc(const NetAlloc*); bool proc_assign(const NetAssign*); void proc_assign_nb(const NetAssignNB*); bool proc_block(const NetBlock*); @@ -122,6 +127,7 @@ struct dll_target : public target_t, public expr_scan_t { bool proc_disable(const NetDisable*); bool proc_force(const NetForce*); void proc_forever(const NetForever*); + void proc_free(const NetFree*); bool proc_release(const NetRelease*); void proc_repeat(const NetRepeat*); void proc_stask(const NetSTask*); @@ -178,6 +184,8 @@ struct dll_target : public target_t, public expr_scan_t { static ivl_expr_t expr_from_value_(const verinum&that); }; +extern struct dll_target dll_target_obj; + /* * These are various private declarations used by the t-dll target. */ @@ -659,12 +667,23 @@ struct ivl_statement_s { unsigned lineno; union { + struct { /* IVL_ST_ALLOC */ + ivl_scope_t scope; + } alloc_; + struct { /* IVL_ST_ASSIGN IVL_ST_ASSIGN_NB IVL_ST_CASSIGN, IVL_ST_DEASSIGN */ unsigned lvals_; struct ivl_lval_s*lval_; ivl_expr_t rval_; ivl_expr_t delay; + // The following are only for NB event control. + ivl_expr_t count; + unsigned nevent; + union { + ivl_event_t event; + ivl_event_t*events; + }; } assign_; struct { /* IVL_ST_BLOCK, IVL_ST_FORK */ @@ -705,6 +724,10 @@ struct ivl_statement_s { ivl_statement_t stmt_; } forever_; + struct { /* IVL_ST_FREE */ + ivl_scope_t scope; + } free_; + struct { /* IVL_ST_STASK */ const char*name_; unsigned nparm_; diff --git a/target.cc b/target.cc index fef82cedb..00bd9d0cb 100644 --- a/target.cc +++ b/target.cc @@ -243,6 +243,12 @@ bool target_t::process(const NetProcTop*top) return top->statement()->emit_proc(this); } +void target_t::proc_alloc(const NetAlloc*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_alloc." << endl; +} + bool target_t::proc_assign(const NetAssign*) { cerr << "target (" << typeid(*this).name() << "): " @@ -322,6 +328,12 @@ void target_t::proc_forever(const NetForever*) "Unhandled proc_forever." << endl; } +void target_t::proc_free(const NetFree*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled proc_free." << endl; +} + bool target_t::proc_release(const NetRelease*dev) { cerr << dev->get_fileline() << ": internal error: " diff --git a/target.h b/target.h index bed4815e6..2be4acf20 100644 --- a/target.h +++ b/target.h @@ -105,6 +105,7 @@ struct target_t { virtual bool process(const NetProcTop*); /* Various kinds of process nodes are dispatched through these. */ + virtual void proc_alloc(const NetAlloc*); virtual bool proc_assign(const NetAssign*); virtual void proc_assign_nb(const NetAssignNB*); virtual bool proc_block(const NetBlock*); @@ -116,6 +117,7 @@ struct target_t { virtual bool proc_disable(const NetDisable*); virtual bool proc_force(const NetForce*); virtual void proc_forever(const NetForever*); + virtual void proc_free(const NetFree*); virtual bool proc_release(const NetRelease*); virtual void proc_repeat(const NetRepeat*); virtual bool proc_trigger(const NetEvTrig*); @@ -151,11 +153,6 @@ struct expr_scan_t { }; -/* The emit functions take a design and emit it to the output stream - using the specified target. If the target is given by name, it is - located in the target_table and used. */ -extern int emit(const Design*des, const char*type); - /* This function takes a fully qualified Verilog name (which may have, for example, dots in it) and produces a mangled version that can be used by most any language. */ @@ -165,8 +162,4 @@ extern string mangle(const string&str); used inside a string constant for a C++ compiler. */ extern string stresc(const string&str); -/* This is the table of supported output targets. It is a null - terminated array of pointers to targets. */ -extern const struct target *target_table[]; - #endif diff --git a/targets.cc b/targets.cc deleted file mode 100644 index 8df415cf3..000000000 --- a/targets.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 1998 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 "target.h" - -extern const struct target tgt_dll; - -const struct target *target_table[] = { - &tgt_dll, - 0 -}; diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index 426d35230..845b2f0e1 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -35,7 +35,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -I$(srcdir) @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-null/null-s.conf b/tgt-null/null-s.conf index bf62222dc..8f1cd19ea 100644 --- a/tgt-null/null-s.conf +++ b/tgt-null/null-s.conf @@ -1,5 +1,4 @@ functor:synth2 functor:synth functor:syn-rules --t:dll flag:DLL=null.tgt diff --git a/tgt-null/null.c b/tgt-null/null.c index 97e245b89..9bed4a68d 100644 --- a/tgt-null/null.c +++ b/tgt-null/null.c @@ -16,11 +16,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: null.c,v 1.7 2002/08/12 01:35:03 steve Exp $" -#endif # include "config.h" +# include /* * This is a null target module. It does nothing. @@ -28,35 +26,34 @@ # include "ivl_target.h" +static const char*version_string = +"Icarus Verilog NULL Code Generator " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + int target_design(ivl_design_t des) { return 0; } -/* - * $Log: null.c,v $ - * Revision 1.7 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.6 2001/09/30 16:45:10 steve - * Fix some Cygwin DLL handling. (Venkat Iyer) - * - * Revision 1.5 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.4 2001/05/22 02:14:47 steve - * Update the mingw build to not require cygwin files. - * - * Revision 1.3 2001/05/20 15:09:40 steve - * Mingw32 support (Venkat Iyer) - * - * Revision 1.2 2001/02/07 22:21:59 steve - * ivl_target header search path fixes. - * - * Revision 1.1 2000/12/02 04:50:32 steve - * Make the null target into a loadable target. - * - */ +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} diff --git a/tgt-null/null.conf b/tgt-null/null.conf index 4d6369401..9d870274e 100644 --- a/tgt-null/null.conf +++ b/tgt-null/null.conf @@ -1,2 +1 @@ --t:dll flag:DLL=null.tgt diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index 20d0136f9..fbf4702b3 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -35,7 +35,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 98092d127..5a21a6a7a 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -81,16 +81,28 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind) switch (ivl_expr_opcode(net)) { case '*': - /* The width of multiply expressions is the sum of the - widths of the operands. This is slightly different - from the way the Verilog standard does it, but allows - us to keep operands smaller. */ - width = ivl_expr_width(ivl_expr_oper1(net)); - width += ivl_expr_width(ivl_expr_oper2(net)); - if (ivl_expr_width(net) != width) { - fprintf(out, "%*sERROR: Result width incorrect. Expecting %u, got %u\n", - ind+3, "", width, ivl_expr_width(net)); - stub_errors += 1; + if (ivl_expr_value(net) == IVL_VT_REAL) { + if (ivl_expr_width(net) != 1) { + fprintf(out, "%*sERROR: Result width incorrect. Expecting 1, got %u\n", + ind+3, "", ivl_expr_width(net)); + stub_errors += 1; + } + } else { + /* The width of a multiply may be any width. The + implicit assumption is that the multiply + returns a width that is the sum of the widths + of the arguments, that is then truncated to the + desired width, never padded. The compiler will + automatically take care of sign extensions of + arguments, so that the code generator need only + generate an UNSIGNED multiply, and the result + will come out right. */ + unsigned max_width = ivl_expr_width(oper1) + ivl_expr_width(oper2); + if (ivl_expr_width(net) > max_width) { + fprintf(out, "%*sERROR: Result width to width. Expecting <= %u, got %u\n", + ind+3, "", max_width, ivl_expr_width(net)); + stub_errors += 1; + } } break; diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index bf560cf5f..b7807bbcb 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -183,6 +183,10 @@ void show_statement(ivl_statement_t net, unsigned ind) switch (code) { + case IVL_ST_ALLOC: + fprintf(out, "%*sallocate automatic storage ...\n", ind, ""); + break; + case IVL_ST_ASSIGN: fprintf(out, "%*sASSIGN \n", ind, "", ivl_stmt_lwidth(net)); @@ -316,6 +320,10 @@ void show_statement(ivl_statement_t net, unsigned ind) break; } + case IVL_ST_FREE: + fprintf(out, "%*sfree automatic storage ...\n", ind, ""); + break; + case IVL_ST_NOOP: fprintf(out, "%*s/* noop */;\n", ind, ""); break; @@ -356,4 +364,3 @@ void show_statement(ivl_statement_t net, unsigned ind) fprintf(out, "%*sunknown statement type (%u)\n", ind, "", code); } } - diff --git a/tgt-stub/stub-s.conf b/tgt-stub/stub-s.conf index 190574ce0..193daf301 100644 --- a/tgt-stub/stub-s.conf +++ b/tgt-stub/stub-s.conf @@ -3,5 +3,4 @@ functor:synth functor:syn-rules functor:cprop functor:nodangle --t:dll flag:DLL=stub.tgt diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index fb170fb00..22f647e12 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -28,8 +28,26 @@ # include "priv.h" # include # include +# include # include +static const char*version_string = +"Icarus Verilog Stub Target " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + FILE*out; int stub_errors = 0; @@ -131,6 +149,26 @@ const char*data_type_string(ivl_variable_type_t vtype) return vt; } +/* + * The compiler will check the types of drivers to signals and will + * only connect outputs to signals that are compatible. This function + * shows the type compatibility that the compiler enforces at the + * ivl_target.h level. + */ +static int check_signal_drive_type(ivl_variable_type_t sig_type, + ivl_variable_type_t driver_type) +{ + if (sig_type == IVL_VT_LOGIC && driver_type == IVL_VT_BOOL) + return !0; + if (sig_type == IVL_VT_LOGIC && driver_type == IVL_VT_LOGIC) + return !0; + if (sig_type == IVL_VT_BOOL && driver_type == IVL_VT_BOOL) + return !0; + if (sig_type == driver_type) + return !0; + return 0; +} + /* * The compare-like LPM nodes have input widths that match the * ivl_lpm_width() value, and an output width of 1. This function @@ -178,11 +216,11 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net) static void show_lpm_abs(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); + ivl_nexus_t nex; fprintf(out, " LPM_ABS %s: \n", ivl_lpm_basename(net), width); - ivl_nexus_t nex; nex = ivl_lpm_q(net, 0); fprintf(out, " Q: %s\n", ivl_nexus_name(ivl_lpm_q(net, 0))); @@ -243,12 +281,13 @@ static void show_lpm_array(ivl_lpm_t net) static void show_lpm_cast_int(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); + ivl_nexus_t q, a; fprintf(out, " LPM_CAST_INT %s: \n", ivl_lpm_basename(net), width); - ivl_nexus_t q = ivl_lpm_q(net,0); - ivl_nexus_t a = ivl_lpm_data(net,0); + q = ivl_lpm_q(net,0); + a = ivl_lpm_data(net,0); fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0))); fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0))); @@ -268,12 +307,13 @@ static void show_lpm_cast_int(ivl_lpm_t net) static void show_lpm_cast_real(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); + ivl_nexus_t q, a; fprintf(out, " LPM_CAST_REAL %s: \n", ivl_lpm_basename(net), width); - ivl_nexus_t q = ivl_lpm_q(net,0); - ivl_nexus_t a = ivl_lpm_data(net,0); + q = ivl_lpm_q(net,0); + a = ivl_lpm_data(net,0); fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0))); fprintf(out, " A: %s\n", ivl_nexus_name(ivl_lpm_data(net,0))); @@ -1040,15 +1080,17 @@ static void signal_nexus_const(ivl_signal_t sig, fprintf(out, " const-"); switch (ivl_const_type(con)) { + case IVL_VT_BOOL: case IVL_VT_LOGIC: bits = ivl_const_bits(con); + assert(bits); for (idx = 0 ; idx < width ; idx += 1) { fprintf(out, "%c", bits[width-idx-1]); } break; case IVL_VT_REAL: - fprintf(out, "%lf", ivl_const_real(con)); + fprintf(out, "%f", ivl_const_real(con)); break; default: @@ -1064,7 +1106,10 @@ static void signal_nexus_const(ivl_signal_t sig, stub_errors += 1; } - if (ivl_signal_data_type(sig) != ivl_const_type(con)) { + int drive_type_ok = check_signal_drive_type(ivl_signal_data_type(sig), + ivl_const_type(con)); + + if (! drive_type_ok) { fprintf(out, "ERROR: Signal data type does not match" " literal type.\n"); stub_errors += 1; @@ -1443,12 +1488,13 @@ static void show_logic(ivl_net_logic_t net) static int show_scope(ivl_scope_t net, void*x) { unsigned idx; + char *is_auto; fprintf(out, "scope: %s (%u parameters, %u signals, %u logic)", ivl_scope_name(net), ivl_scope_params(net), ivl_scope_sigs(net), ivl_scope_logs(net)); - char *is_auto = ivl_scope_is_auto(net) ? "automatic " : ""; + is_auto = ivl_scope_is_auto(net) ? "automatic " : ""; switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: fprintf(out, " module %s", ivl_scope_tname(net)); @@ -1608,3 +1654,11 @@ int target_design(ivl_design_t des) return stub_errors; } + +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} diff --git a/tgt-stub/stub.conf b/tgt-stub/stub.conf index 5c0c1c576..eb4cee787 100644 --- a/tgt-stub/stub.conf +++ b/tgt-stub/stub.conf @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=stub.tgt diff --git a/tgt-stub/switches.c b/tgt-stub/switches.c index 5fa383ab4..278b17908 100644 --- a/tgt-stub/switches.c +++ b/tgt-stub/switches.c @@ -28,6 +28,9 @@ void show_switch(ivl_switch_t net) { const char*name = ivl_switch_basename(net); int has_enable = 0; + ivl_nexus_t nexa, nexb; + ivl_variable_type_t nex_type_a, nex_type_b; + const char*nex_name; switch (ivl_switch_type(net)) { case IVL_SW_TRAN: @@ -61,14 +64,14 @@ void show_switch(ivl_switch_t net) 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; + nexa = ivl_switch_a(net); + nex_name = nexa? ivl_nexus_name(nexa) : ""; + nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE; fprintf(out, " A: %s \n", nex_name, data_type_string(nex_type_a)); - ivl_nexus_t nexb = ivl_switch_b(net); + 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; + nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE; fprintf(out, " B: %s \n", nex_name, data_type_string(nex_type_b)); /* The A/B pins of the switch must be present, and must match. */ diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 80e5fe28e..269497b0d 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -47,7 +47,7 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, } /* - * Convert a gate intput to an unary expression. + * Convert a gate input to an unary expression. */ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, ivl_net_logic_t log) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index e1d825e91..738646ec1 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -34,7 +34,7 @@ * successfully. * * An alternative is to use the VHPI interface supported by - * some VHDL simulators and implement the $finish funcitonality + * some VHDL simulators and implement the $finish functionality * in C. This function can be enabled with the flag * -puse-vhpi-finish=1. */ @@ -232,7 +232,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, // performed on assignments of constant values to prevent // ordering problems. - // This also has another application: If this is an `inital' + // This also has another application: If this is an `initial' // process and we haven't yet generated a `wait' statement then // moving the assignment to the initialization preserves the // expected Verilog behaviour: VHDL does not distinguish @@ -628,7 +628,7 @@ int draw_utask(vhdl_procedural *proc, stmt_container *container, // TODO: adding some comments to the output would be helpful - // TOOD: this completely ignores paremeters! + // TOOD: this completely ignores parameters! draw_stmt(proc, container, ivl_scope_def(tscope), false); return 0; diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 875e38ebf..ecf59b339 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -97,7 +97,7 @@ bool seen_signal_before(ivl_signal_t sig) } /* - * Remeber the association of signal to entity. + * Remember the association of signal to entity. */ void remember_signal(ivl_signal_t sig, vhdl_scope *scope) { diff --git a/tgt-vhdl/vhdl.conf b/tgt-vhdl/vhdl.conf index b96c4c05e..0d382d395 100644 --- a/tgt-vhdl/vhdl.conf +++ b/tgt-vhdl/vhdl.conf @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=vhdl.tgt diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 20968ff65..5ca30e1fc 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -856,7 +856,7 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) : vhdl_decl(name, ret_type) { // A function contains two scopes: - // scope_ = The paramters + // scope_ = The parameters // variables_ = Local variables // A call to get_scope returns variables_ whose parent is scope_ variables_.set_parent(&scope_); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index f3e8b9b0d..b71c1310a 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -38,7 +38,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-vvp/draw_mux.c b/tgt-vvp/draw_mux.c index c5c0861f2..a3a32e11b 100644 --- a/tgt-vvp/draw_mux.c +++ b/tgt-vvp/draw_mux.c @@ -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: draw_mux.c,v 1.14 2007/01/16 05:44:16 steve Exp $" -#endif # include "vvp_priv.h" # include @@ -36,28 +33,50 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz) { unsigned width = ivl_lpm_width(net); + ivl_expr_t d_rise, d_fall, d_decay; + const char*dly; + const char* input[3]; /* Only support A-B muxes in this function. */ assert(ivl_lpm_size(net) == 2); assert(ivl_lpm_selects(net) == 1); - ivl_expr_t d_rise = ivl_lpm_delay(net, 0); - ivl_expr_t d_fall = ivl_lpm_delay(net, 1); - ivl_expr_t d_decay = ivl_lpm_delay(net, 2); + d_rise = ivl_lpm_delay(net, 0); + d_fall = ivl_lpm_delay(net, 1); + d_decay = ivl_lpm_delay(net, 2); - const char*dly = ""; + dly = ""; if (d_rise != 0) { - assert(number_is_immediate(d_rise, 64, 0)); - assert(number_is_immediate(d_fall, 64, 0)); - assert(number_is_immediate(d_decay, 64, 0)); dly = "/d"; - fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", - net, get_number_immediate(d_rise), - get_number_immediate(d_rise), - get_number_immediate(d_rise), net); + if (number_is_immediate(d_rise, 64, 0) && + number_is_immediate(d_fall, 64, 0) && + number_is_immediate(d_decay, 64, 0)) { + fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n", + net, get_number_immediate(d_rise), + get_number_immediate(d_rise), + get_number_immediate(d_rise), net); + } else { + ivl_signal_t sig; + assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); + assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); + assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); + + fprintf(vvp_out, "L_%p .delay L_%p/d", net, net); + + sig = ivl_expr_signal(d_rise); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0", sig); + + sig = ivl_expr_signal(d_fall); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0", sig); + + sig = ivl_expr_signal(d_decay); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0;\n", sig); + } } - const char* input[3]; input[0] = draw_net_input(ivl_lpm_data(net,0)); input[1] = draw_net_input(ivl_lpm_data(net,1)); input[2] = draw_net_input(ivl_lpm_select(net)); @@ -144,48 +163,3 @@ void draw_lpm_mux(ivl_lpm_t net) devices to handle the arbitrary size. */ draw_lpm_mux_nest(net, muxz); } - -/* - * $Log: draw_mux.c,v $ - * Revision 1.14 2007/01/16 05:44:16 steve - * Major rework of array handling. Memories are replaced with the - * more general concept of arrays. The NetMemory and NetEMemory - * classes are removed from the ivl core program, and the IVL_LPM_RAM - * lpm type is removed from the ivl_target API. - * - * Revision 1.13 2005/10/12 17:26:17 steve - * MUX nodes get inputs from nets, not from net inputs, - * Detect and draw alias nodes to reduce net size and - * handle force confusion. - * - * Revision 1.12 2005/09/01 04:11:37 steve - * Generate code to handle real valued muxes. - * - * Revision 1.11 2005/08/27 04:32:08 steve - * Handle synthesis of fully packed case statements. - * - * Revision 1.10 2005/06/17 03:46:52 steve - * Make functors know their own width. - * - * Revision 1.9 2005/04/06 05:29:09 steve - * Rework NetRamDq and IVL_LPM_RAM nodes. - * - * Revision 1.8 2005/02/12 22:54:29 steve - * Implement a-b muxes as vector devices - * - * Revision 1.7 2003/12/19 01:27:10 steve - * Fix various unsigned compare warnings. - * - * Revision 1.6 2003/02/25 03:40:45 steve - * Eliminate use of ivl_lpm_name function. - * - * Revision 1.5 2002/08/29 03:04:01 steve - * Generate x out for x select on wide muxes. - * - * Revision 1.4 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - */ diff --git a/tgt-vvp/draw_net_input.c b/tgt-vvp/draw_net_input.c index 909770e2c..17b368f23 100644 --- a/tgt-vvp/draw_net_input.c +++ b/tgt-vvp/draw_net_input.c @@ -146,12 +146,14 @@ static struct vvp_nexus_data*new_nexus_data() static int nexus_drive_is_strength_aware(ivl_nexus_ptr_t nptr) { + ivl_net_logic_t log; + 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); + 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 @@ -325,9 +327,11 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) cptr = ivl_nexus_ptr_con(nptr); if (cptr) { + char *result = 0; + ivl_expr_t d_rise, d_fall, d_decay; + /* 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: @@ -353,26 +357,48 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) 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); + d_rise = ivl_const_delay(cptr, 0); + d_fall = ivl_const_delay(cptr, 1); + d_decay = ivl_const_delay(cptr, 2); /* We have a delayed constant, so we need to build some code. */ if (d_rise != 0) { - assert(number_is_immediate(d_rise, 64, 0)); - assert(number_is_immediate(d_fall, 64, 0)); - assert(number_is_immediate(d_decay, 64, 0)); - - 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]; + fprintf(vvp_out, "L_%p/d .functor BUFZ 1, %s, " + "C4<0>, C4<0>, C4<0>;\n", cptr, result); + free(result); + + /* Is this a fixed or variable delay? */ + if (number_is_immediate(d_rise, 64, 0) && + number_is_immediate(d_fall, 64, 0) && + number_is_immediate(d_decay, 64, 0)) { + + 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); + + } else { + ivl_signal_t sig; + assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL); + assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL); + assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL); + + fprintf(vvp_out, "L_%p .delay L_%p/d", cptr, cptr); + + sig = ivl_expr_signal(d_rise); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0", sig); + + sig = ivl_expr_signal(d_fall); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0", sig); + + sig = ivl_expr_signal(d_decay); + assert(ivl_signal_dimensions(sig) == 0); + fprintf(vvp_out, ", v%p_0;\n", sig); + } + snprintf(tmp, sizeof tmp, "L_%p", cptr); result = strdup(tmp); } @@ -686,4 +712,3 @@ const char*draw_net_input(ivl_nexus_t nex) return nex_data->net_input; } - diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index fa9c67895..235106cbc 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -33,20 +33,24 @@ static void draw_tran_island(ivl_island_t island) void draw_switch_in_scope(ivl_switch_t sw) { - ivl_island_t island = ivl_switch_island(sw); + ivl_island_t island; + ivl_nexus_t nex_a, nex_b, enable; + const char*str_a, *str_b, *str_e; + + 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); + nex_a = ivl_switch_a(sw); assert(nex_a); - const char*str_a = draw_net_input(nex_a); + str_a = draw_net_input(nex_a); - ivl_nexus_t nex_b = ivl_switch_b(sw); + nex_b = ivl_switch_b(sw); assert(nex_b); - const char*str_b = draw_net_input(nex_b); + str_b = draw_net_input(nex_b); - ivl_nexus_t enable = ivl_switch_enable(sw); - const char*str_e = 0; + enable = ivl_switch_enable(sw); + str_e = 0; if (enable) str_e = draw_net_input(enable); diff --git a/tgt-vvp/draw_ufunc.c b/tgt-vvp/draw_ufunc.c index 6ea3b3637..4781e7f9d 100644 --- a/tgt-vvp/draw_ufunc.c +++ b/tgt-vvp/draw_ufunc.c @@ -28,13 +28,14 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t exp) { struct vector_info res; + unsigned pwidth; /* ports cannot be arrays. */ assert(ivl_signal_dimensions(port) == 0); res = draw_eval_expr_wid(exp, ivl_signal_width(port), 0); /* We could have extra bits so only select the ones we need. */ - unsigned pwidth = ivl_signal_width(port); + pwidth = ivl_signal_width(port); fprintf(vvp_out, " %%set/v v%p_0, %u, %u;\n", port, res.base, (res.wid > pwidth) ? pwidth : res.wid); @@ -87,6 +88,12 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) ivl_scope_t def = ivl_expr_def(exp); ivl_signal_t retval = ivl_scope_port(def, 0); struct vector_info res; + unsigned load_wid; + + /* If this is an automatic function, allocate the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%alloc S_%p;\n", def); + } /* evaluate the expressions and send the results to the function ports. */ @@ -122,7 +129,7 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) assert(res.base != 0); - unsigned load_wid = swid; + load_wid = swid; if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); @@ -134,6 +141,11 @@ struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) if (load_wid < wid) pad_expr_in_place(exp, res, swid); + /* If this is an automatic function, free the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%free S_%p;\n", def); + } + return res; } @@ -144,6 +156,11 @@ int draw_ufunc_real(ivl_expr_t exp) int res = 0; int idx; + /* If this is an automatic function, allocate the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%alloc S_%p;\n", def); + } + assert(ivl_expr_parms(exp) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(exp) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); @@ -163,6 +180,10 @@ int draw_ufunc_real(ivl_expr_t exp) res = allocate_word(); fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval); + /* If this is an automatic function, free the local storage. */ + if (ivl_scope_is_auto(def)) { + fprintf(vvp_out, " %%free S_%p;\n", def); + } + return res; } - diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index fa27d34f3..0e8cc5252 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -167,6 +167,8 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, case IVL_EX_SELECT: { ivl_expr_t vexpr = ivl_expr_oper1(expr); + ivl_expr_t bexpr; + assert(vexpr); /* This code is only for signals or selects. */ @@ -177,7 +179,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, /* Add &APV<> code here when it is finished. */ if (ivl_expr_oper1(vexpr)) return 0; - ivl_expr_t bexpr = ivl_expr_oper2(expr); + bexpr = ivl_expr_oper2(expr); assert(bexpr); /* This is a constant bit/part select. */ @@ -339,9 +341,10 @@ static void draw_vpi_taskfunc_args(const char*call_string, fprintf(vvp_out, "%s", call_string); for (idx = 0 ; idx < parm_count ; idx += 1) { + struct args_info*ptr; + fprintf(vvp_out, ", %s", args[idx].text); free(args[idx].text); - struct args_info*ptr; /* Clear the nested children vectors. */ for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) { if (ptr->vec_flag) { diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 069ab9278..ea67f4051 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -124,11 +124,13 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) { long imm = get_number_immediate(expr); if (imm >= 0) { - fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm); + fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm); } else { - fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm); - fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm); + fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm); + fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm); } + /* This can not have have a X/Z value so clear bit 4. */ + fprintf(vvp_out, " %%mov 4, 0, 1;\n"); } break; @@ -137,6 +139,7 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) unsigned word = 0; if (ivl_signal_dimensions(sig) > 0) { + ivl_expr_t ixe; /* Detect the special case that this is a variable array. In this case, the ix/getv @@ -144,13 +147,13 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) if (ivl_signal_type(sig) == IVL_SIT_REG) { struct vector_info rv; rv = draw_eval_expr(expr, 0); - fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", + fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", ix, rv.base, rv.wid); clr_vector(rv); break; } - ivl_expr_t ixe = ivl_expr_oper1(expr); + ixe = ivl_expr_oper1(expr); if (number_is_immediate(ixe, 8*sizeof(unsigned long), 0)) word = get_number_immediate(ixe); else { @@ -162,7 +165,9 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) break; } } - fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); + char*type = ivl_signal_signed(sig) ? "/s" : ""; + fprintf(vvp_out, " %%ix/getv%s %u, v%p_%u;\n", type, ix, + sig, word); break; } @@ -934,6 +939,8 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp, { ivl_expr_t le = ivl_expr_oper1(exp); ivl_expr_t re = ivl_expr_oper2(exp); + struct vector_info lv; + struct vector_info rv; if (ivl_expr_opcode(exp) == '&') { if (number_is_immediate(re, IMM_WID, 0) && !number_is_unknown(re)) @@ -942,9 +949,6 @@ static struct vector_info draw_binary_expr_logic(ivl_expr_t exp, return draw_logic_immediate(exp, re, le, wid); } - struct vector_info lv; - struct vector_info rv; - lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ); rv = draw_eval_expr_wid(re, wid, STUFF_OK_XZ); @@ -1271,9 +1275,9 @@ 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); + fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid); break; case 2: @@ -1282,7 +1286,7 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le, 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; } @@ -1303,7 +1307,7 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le, 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; } @@ -1621,6 +1625,9 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) unsigned nwid; struct vector_info res; const char*bits = ivl_expr_bits(exp); + unsigned long val; + unsigned val_bits; + unsigned val_addr; res.wid = wid; @@ -1675,7 +1682,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) instruction. */ if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) { unsigned long val = get_number_immediate(exp); - fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid); + fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid); return res; } @@ -1683,9 +1690,9 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) destination. Use the %mov to handle the remaining general bits. */ idx = 0; - unsigned long val = 0; - unsigned val_bits = 0; - unsigned val_addr = res.base; + val = 0; + val_bits = 0; + val_addr = res.base; while (idx < nwid) { char src = 0; switch (bits[idx]) { @@ -1707,7 +1714,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) if (val_bits >= IMM_WID || (val_bits>0 && src != 0) || (val_bits>0 && idx+1==nwid)) { - fprintf(vvp_out, " %%movi %u, %lu, %u;\n", + fprintf(vvp_out, " %%movi %u, %lu, %u;\n", val_addr, val, val_bits); val_addr += val_bits; val_bits = 0; @@ -1715,13 +1722,14 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) } if (src != 0) { - assert(val_bits == 0); unsigned cnt; + + assert(val_bits == 0); for (cnt = 1 ; idx+cnt < nwid ; cnt += 1) if (bits[idx+cnt] != bits[idx]) break; - fprintf(vvp_out, " %%mov %u, %c, %u;\n", val_addr, src, cnt); + fprintf(vvp_out, " %%mov %u, %c, %u;\n", val_addr, src, cnt); val_addr += cnt; idx += cnt-1; } @@ -1832,13 +1840,13 @@ static struct vector_info draw_realnum_expr(ivl_expr_t exp, unsigned wid) continue; } - fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run); + fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run); addr += run; run = 1; bit = next_bit; } - fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run); + fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run); return res; @@ -1936,14 +1944,14 @@ static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid) } } } - fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans); + fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans); idx += trans; } /* Pad the number up to the expression width. */ if (idx < wid) - fprintf(vvp_out, " %%mov %u, 0, %u;\n", res.base+idx, wid-idx); + fprintf(vvp_out, " %%mov %u, 0, %u;\n", res.base+idx, wid-idx); if (res.base >= 8) save_expression_lookaside(res.base, exp, wid); @@ -1976,9 +1984,9 @@ void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned 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); + fprintf(vvp_out, " %%movi %u, 0, %u;\n", base, count); else - fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count); + fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count); } } @@ -2011,15 +2019,15 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, draw_eval_expr_into_integer(ix, 3); if (add_index < 0) { - fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", + fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", res.base, sig, swid); pad_expr_in_place(exp, res, swid); } else { const char*sign_flag = (add_index>0)? "/s" : ""; /* Add an immediate value to an array value. */ - fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); - fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n", + fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); + fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n", sign_flag, res.base, sig, res.wid); } return; @@ -2027,11 +2035,12 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, if (ivl_signal_data_type(sig) == IVL_VT_REAL) { + int tmp; assert(add_index < 0); - int tmp = allocate_word(); - fprintf(vvp_out, " %%load/wr %d, v%p_%u;\n", tmp, sig, word); - fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, tmp, res.wid); + tmp = allocate_word(); + fprintf(vvp_out, " %%load/wr %d, v%p_%u;\n", tmp, sig, word); + fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, tmp, res.wid); clr_word(tmp); } else if (add_index >= 0) { @@ -2042,8 +2051,8 @@ static void draw_signal_dest(ivl_expr_t exp, struct vector_info res, if (immediate >= 0) { fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate); } else { - fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate); - fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate); + fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate); + fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate); } fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag, res.base, sig,word, res.wid); @@ -2107,7 +2116,7 @@ static struct vector_info draw_select_array(ivl_expr_t sube, shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO); draw_eval_expr_into_integer(ix, 3); - fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); + fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); if (shiv.base >= 8) clr_vector(shiv); @@ -2122,7 +2131,7 @@ static struct vector_info draw_select_array(ivl_expr_t sube, } for (idx = 0 ; idx < wid ; idx += 1) { - fprintf(vvp_out, " %%load/avx.p %u, v%p, 0;\n", res.base+idx, sig); + fprintf(vvp_out, " %%load/avx.p %u, v%p, 0;\n", res.base+idx, sig); } return res; @@ -2138,6 +2147,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, /* Use this word of the signal. */ unsigned use_word = 0; + unsigned use_wid; /* If this is an access to an array, try to get the index as a constant. If it is (and the array is not a reg array then @@ -2167,7 +2177,7 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, res.base = allocate_vector(wid); res.wid = wid; assert(res.base); - fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u of %u bits\n", + fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u of %u bits\n", res.base, sig, use_word, bit_wid, bit_wid, ivl_expr_width(sube)); save_signal_lookaside(res.base, sig, use_word, bit_wid); @@ -2186,14 +2196,14 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, res.wid = wid; assert(res.base); - unsigned use_wid = res.wid; + use_wid = res.wid; if (use_wid > bit_wid) use_wid = bit_wid; - fprintf(vvp_out, " %%load/x1p %u, v%p_%u, %u;\n", + fprintf(vvp_out, " %%load/x1p %u, v%p_%u, %u;\n", res.base, sig, use_word, use_wid); if (use_wid < res.wid) - fprintf(vvp_out, " %%movi %u, 0, %u;\n", + fprintf(vvp_out, " %%movi %u, 0, %u;\n", res.base + use_wid, res.wid - use_wid); return res; @@ -2581,15 +2591,15 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid) result a 1. */ if (res.base == 1) { res.base = allocate_vector(wid); - fprintf(vvp_out, " %%movi %d, 1, %u;\n", + fprintf(vvp_out, " %%movi %d, 1, %u;\n", res.base, res.wid); break; } - fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid); - fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); - fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid); - fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid); + fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid); + fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); + fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid); + fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid); fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count); local_count += 1; break; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index e060fac7d..3bd34c8ab 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -72,9 +72,12 @@ static int draw_binary_real(ivl_expr_t exp) case 'X': { struct vector_info vi; + int res; + const char*sign_flag; + vi = draw_eval_expr(exp, STUFF_OK_XZ); - int res = allocate_word(); - const char*sign_flag = ivl_expr_signed(exp)? "/s" : ""; + res = allocate_word(); + sign_flag = ivl_expr_signed(exp)? "/s" : ""; fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, vi.base, vi.wid); @@ -113,7 +116,7 @@ static int draw_binary_real(ivl_expr_t exp) fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r); break; - case 'm': { // min(l,r) + case 'm': { /* min(l,r) */ int lab_out = local_count++; int lab_r = local_count++; /* If r is NaN, the go out and accept l as result. */ @@ -131,7 +134,7 @@ static int draw_binary_real(ivl_expr_t exp) break; } - case 'M': { // max(l,r) + case 'M': { /* max(l,r) */ int lab_out = local_count++; int lab_r = local_count++; /* If r is NaN, the go out and accept l as result. */ @@ -168,28 +171,49 @@ static int draw_number_real(ivl_expr_t exp) unsigned long mant = 0, mask = -1UL; int vexp = 0x1000; - for (idx = 0 ; idx < wid ; idx += 1) { - mask <<= 1; - if (bits[idx] == '1') - mant |= 1 << idx; - } + /* If this is a negative number, then arrange for the 2's + complement to be calculated as we scan through the + value. Real values are sign-magnitude, and this negation + gets us a magnitide. */ - /* If this is actually a negative number, then get the - positive equivalent, and set the sign bit in the exponent - field. - - To get the positive equivalent of mant we need to take the - negative of the mantissa (0-mant) but also be aware that - the bits may not have been as many bits as the width of the - mant variable. This would lead to spurious '1' bits in the - high bits of mant that are masked by ~((-1UL)<> 1) & 1; + cur_bit &= 1; + } + + if (cur_bit) mant |= 1 << idx; + } + + for ( ; idx < wid ; idx += 1) { + if (ivl_expr_signed(exp) && (bits[idx] == bits[8*sizeof(mant)-1])) + continue; + + if (bits[idx] == '0') + continue; + + fprintf(stderr, "internal error: mantissa doesn't fit!\n"); + assert(0); + } + + /* If required, add in a sign bit. */ + if (negate) + vexp |= 0x4000; + + fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu (wid=%u)\n", + res, mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid); return res; } @@ -430,14 +454,20 @@ static int draw_ternary_real(ivl_expr_t exp) static int draw_unary_real(ivl_expr_t exp) { + ivl_expr_t sube; + int sub; + /* If the opcode is a ~ then the sub expression must not be a * real expression, so use vector evaluation and then convert * that result to a real value. */ if (ivl_expr_opcode(exp) == '~') { struct vector_info vi; + int res; + const char*sign_flag; + vi = draw_eval_expr(exp, STUFF_OK_XZ); - int res = allocate_word(); - const char*sign_flag = ivl_expr_signed(exp)? "/s" : ""; + res = allocate_word(); + sign_flag = ivl_expr_signed(exp)? "/s" : ""; fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, vi.base, vi.wid); @@ -449,9 +479,12 @@ static int draw_unary_real(ivl_expr_t exp) if (ivl_expr_opcode(exp) == '!') { struct vector_info vi; + int res; + const char*sign_flag; + vi = draw_eval_expr(exp, STUFF_OK_XZ); - int res = allocate_word(); - const char*sign_flag = ivl_expr_signed(exp)? "/s" : ""; + res = allocate_word(); + sign_flag = ivl_expr_signed(exp)? "/s" : ""; fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res, vi.base, vi.wid); @@ -461,9 +494,8 @@ static int draw_unary_real(ivl_expr_t exp) return res; } - ivl_expr_t sube = ivl_expr_oper1(exp); - - int sub = draw_eval_real(sube); + sube = ivl_expr_oper1(exp); + sub = draw_eval_real(sube); if (ivl_expr_opcode(exp) == '+') return sub; diff --git a/tgt-vvp/modpath.c b/tgt-vvp/modpath.c index 031257f70..c8fb45e28 100644 --- a/tgt-vvp/modpath.c +++ b/tgt-vvp/modpath.c @@ -84,6 +84,8 @@ static void draw_modpath_record(const char*label, const char*driver, int ppos = ivl_path_source_posedge(path); int pneg = ivl_path_source_negedge(path); const char*edge = ppos? " +" : pneg ? " -" : ""; + ivl_signal_t src_sig; + fprintf(vvp_out, ",\n %s%s", src_drivers[idx], edge); fprintf(vvp_out, " (%"PRIu64",%"PRIu64",%"PRIu64 @@ -109,7 +111,7 @@ static void draw_modpath_record(const char*label, const char*driver, fprintf(vvp_out, ")"); - ivl_signal_t src_sig = find_path_source_port(path); + src_sig = find_path_source_port(path); fprintf(vvp_out, " v%p_0", src_sig); } @@ -140,9 +142,10 @@ void cleanup_modpath(void) { while (modpath_list) { struct modpath_item*cur = modpath_list; + char modpath_label[64]; + modpath_list = cur->next; - char modpath_label[64]; snprintf(modpath_label, sizeof modpath_label, "V_%p/m", cur->path_sig); draw_modpath_record(modpath_label, cur->drive_label, cur->path_sig); free(cur->drive_label); diff --git a/tgt-vvp/vector.c b/tgt-vvp/vector.c index 77f08ec96..f1f4bff50 100644 --- a/tgt-vvp/vector.c +++ b/tgt-vvp/vector.c @@ -41,23 +41,23 @@ static struct allocation_score_s { /* This is the largest bit to have lookaside values. */ static unsigned lookaside_top = 0; -static inline ivl_expr_t peek_exp(unsigned addr) +static __inline__ ivl_expr_t peek_exp(unsigned addr) { return allocation_map[addr].exp; } -static inline unsigned peek_exp_bit(unsigned addr) +static __inline__ unsigned peek_exp_bit(unsigned addr) { return allocation_map[addr].exp_bit; } -static inline void set_exp(unsigned addr, ivl_expr_t exp, unsigned ebit) +static __inline__ void set_exp(unsigned addr, ivl_expr_t exp, unsigned ebit) { allocation_map[addr].exp = exp; allocation_map[addr].exp_bit = ebit; } -static inline void set_sig(unsigned addr, ivl_signal_t exp, unsigned sig_word, unsigned ebit) +static __inline__ void set_sig(unsigned addr, ivl_signal_t exp, unsigned sig_word, unsigned ebit) { allocation_map[addr].sig = exp; allocation_map[addr].sig_word = sig_word; diff --git a/tgt-vvp/vvp-s.conf.in b/tgt-vvp/vvp-s.conf.in index 81c6f4a37..6d45439b8 100644 --- a/tgt-vvp/vvp-s.conf.in +++ b/tgt-vvp/vvp-s.conf.in @@ -3,5 +3,4 @@ functor:synth functor:syn-rules functor:cprop functor:nodangle --t:dll flag:DLL=vvp.tgt diff --git a/tgt-vvp/vvp.c b/tgt-vvp/vvp.c index e1cb632f3..7d844721f 100644 --- a/tgt-vvp/vvp.c +++ b/tgt-vvp/vvp.c @@ -26,10 +26,27 @@ # include # include +static const char*version_string = +"Icarus Verilog VVP Code Generator " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + FILE*vvp_out = 0; int vvp_errors = 0; -inline static void draw_execute_header(ivl_design_t des) +__inline__ static void draw_execute_header(ivl_design_t des) { #if !defined(__MINGW32__) const char*cp = ivl_design_flag(des, "VVP_EXECUTABLE"); @@ -40,7 +57,7 @@ inline static void draw_execute_header(ivl_design_t des) #endif } -inline static void draw_module_declarations(ivl_design_t des) +__inline__ static void draw_module_declarations(ivl_design_t des) { const char*cp = ivl_design_flag(des, "VPI_MODULE_LIST"); @@ -67,6 +84,8 @@ int target_design(ivl_design_t des) int rc; ivl_scope_t *roots; unsigned nroots, i; + unsigned size; + unsigned idx; const char*path = ivl_design_flag(des, "-o"); assert(path); @@ -106,10 +125,9 @@ int target_design(ivl_design_t des) rc = ivl_design_process(des, draw_process, 0); /* Dump the file name table. */ - unsigned size = ivl_file_table_size(); + size = ivl_file_table_size(); fprintf(vvp_out, "# The file index is used to find the file name in " "the following table.\n:file_names %u;\n", size); - unsigned idx; for (idx = 0; idx < size; idx++) { fprintf(vvp_out, " \"%s\";\n", ivl_file_table_item(idx)); } @@ -119,3 +137,11 @@ int target_design(ivl_design_t des) return rc + vvp_errors; } + +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} diff --git a/tgt-vvp/vvp.conf.in b/tgt-vvp/vvp.conf.in index 2dbe4a66b..c416038ac 100644 --- a/tgt-vvp/vvp.conf.in +++ b/tgt-vvp/vvp.conf.in @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=vvp.tgt diff --git a/tgt-vvp/vvp_config.h.in b/tgt-vvp/vvp_config.h.in index 66f24faaa..a5cd66e4c 100644 --- a/tgt-vvp/vvp_config.h.in +++ b/tgt-vvp/vvp_config.h.in @@ -46,4 +46,4 @@ * Isolate configure from containing config.h * */ -#endif // __vvp_config_H +#endif /* __vvp_config_H */ diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 6147b5225..5815cbbe5 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -25,6 +25,10 @@ #endif # include +#ifdef __MINGW32__ /* MinGW has inconsistent %p output. */ +#define snprintf _snprintf +#endif + static int show_statement(ivl_statement_t net, ivl_scope_t sscope); unsigned local_count = 0; @@ -220,7 +224,8 @@ static void set_to_lvariable(ivl_lval_t lval, static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, unsigned bit, unsigned delay, ivl_expr_t dexp, - ivl_expr_t part_off_ex, unsigned width) + ivl_expr_t part_off_ex, unsigned width, + unsigned nevents) { unsigned skip_assign = transient_id++; @@ -232,64 +237,52 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, part_off_ex = 0; } - if (dexp == 0) { - /* Constant delay... */ - if (number_is_immediate(word_ix, 64, 0)) { - fprintf(vvp_out, " %%ix/load 3, %lu; address\n", - get_number_immediate(word_ix)); - } else { - /* Calculate array word index into index register 3 */ - draw_eval_expr_into_integer(word_ix, 3); - /* Skip assignment if word expression is not defined. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - } - /* Store expression width into index word 0 */ - fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); - if (part_off_ex) { - draw_eval_expr_into_integer(part_off_ex, 1); - /* If the index expression has XZ bits, skip the assign. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - } else { - /* Store word part select base into index 1 */ - fprintf(vvp_out, " %%ix/load 1, %u; part base\n", part_off); - } - fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, - delay, bit); + /* This code is common to all the different types of array delays. */ + if (number_is_immediate(word_ix, 64, 0)) { + fprintf(vvp_out, " %%ix/load 3, %lu; address\n", + get_number_immediate(word_ix)); } else { + /* Calculate array word index into index register 3 */ + draw_eval_expr_into_integer(word_ix, 3); + /* Skip assignment if word expression is not defined. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } + /* Store expression width into index word 0 */ + fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); + if (part_off_ex) { + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } else { + /* Store word part select into index 1 */ + fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off); + } + + if (dexp != 0) { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); - if (number_is_immediate(word_ix, 64, 0)) { - fprintf(vvp_out, " %%ix/load 3, %lu; address\n", - get_number_immediate(word_ix)); - } else { - /* Calculate array word index into index register 3 */ - draw_eval_expr_into_integer(word_ix, 3); - /* Skip assignment if word expression is not defined. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - } - /* Store expression width into index word 0 */ - fprintf(vvp_out, " %%ix/load 0, %u; word width\n", width); - if (part_off_ex) { - draw_eval_expr_into_integer(part_off_ex, 1); - /* If the index expression has XZ bits, skip the assign. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - } else { - /* Store word part select into index 1 */ - fprintf(vvp_out, " %%ix/load 1, %u; part off\n", part_off); - } fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig, - delay_index, bit); + delay_index, bit); + clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%assign/av/e v%p, %u;\n", lsig, bit); + } else { + /* Constant delay... */ + fprintf(vvp_out, " %%assign/av v%p, %u, %u;\n", lsig, + delay, bit); } fprintf(vvp_out, "t_%u ;\n", skip_assign); + if (nevents != 0) fprintf(vvp_out, " %%evctl/c;\n"); clear_expression_lookaside(); } static void assign_to_lvector(ivl_lval_t lval, unsigned bit, unsigned delay, ivl_expr_t dexp, - unsigned width) + unsigned width, unsigned nevents) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); @@ -300,7 +293,8 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (ivl_signal_dimensions(sig) > 0) { assert(word_ix); - assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width); + assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, + width, nevents); return; } @@ -316,16 +310,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (part_off_ex) { unsigned skip_assign = transient_id++; - if (dexp == 0) { - /* Constant delay... */ - draw_eval_expr_into_integer(part_off_ex, 1); - /* If the index expression has XZ bits, skip the assign. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", - sig, use_word, delay, bit); - fprintf(vvp_out, "t_%u ;\n", skip_assign); - } else { + if (dexp != 0) { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); @@ -337,6 +322,25 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, sig, use_word, delay_index, bit); fprintf(vvp_out, "t_%u ;\n", skip_assign); clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", + sig, use_word, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); + fprintf(vvp_out, " %%evctl/c;\n"); + } else { + /* Constant delay... */ + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); } } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { @@ -345,14 +349,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, single-bit set instruction. */ assert(ivl_lval_width(lval) == width); - if (dexp == 0) { - /* Constant delay... */ - fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); - fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", - sig, use_word, delay, bit); - - } else { + if (dexp != 0) { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); @@ -361,14 +358,33 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n", sig, use_word, delay_index, bit); clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); + fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", + sig, use_word, bit); + } else { + /* Constant delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); } } else if (dexp != 0) { + /* Calculated delay... */ draw_eval_expr_into_integer(dexp, 1); fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n", sig, use_word, bit); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/e v%p_%lu, %u;\n", + sig, use_word, bit); } else { + /* Constant delay... */ fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n", sig, use_word, delay, bit); @@ -412,6 +428,14 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res) } } +static int show_stmt_alloc(ivl_statement_t net) +{ + ivl_scope_t scope = ivl_stmt_call(net); + + fprintf(vvp_out, " %%alloc S_%p;\n", scope); + return 0; +} + static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); @@ -531,7 +555,8 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) unsigned long use_word = 0; /* thread address for a word value. */ int word; - unsigned long delay; + unsigned long delay = 0; + unsigned nevents = ivl_stmt_nevent(net); /* Must be exactly 1 l-value. */ assert(ivl_stmt_lvals(net) == 1); @@ -547,20 +572,29 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) use_word = get_number_immediate(word_ix); } - delay = 0; if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); del = 0; } - /* XXXX For now, presume delays are constant. */ - assert(del == 0); - /* Evaluate the r-value */ word = draw_eval_real(rval); - fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", - sig, use_word, delay, word); + /* We need to calculate the delay expression. */ + if (del) { + assert(nevents == 0); + int delay_index = allocate_word(); + draw_eval_expr_into_integer(del, delay_index); + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", + sig, use_word, delay_index, word); + clr_word(delay_index); + } else if (nevents) { + fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n", + sig, use_word, word); + } else { + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", + sig, use_word, delay, word); + } clr_word(word); @@ -573,6 +607,51 @@ static int show_stmt_assign_nb(ivl_statement_t net) ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t del = ivl_stmt_delay_expr(net); ivl_signal_t sig; + unsigned nevents = ivl_stmt_nevent(net); + + /* If we have an event control build the control structure. */ + if (nevents) { + assert(del == 0); + + ivl_expr_t cnt = ivl_stmt_cond_expr(net); + unsigned long count = 1; + if (cnt && (ivl_expr_type(cnt) == IVL_EX_ULONG)) { + count = ivl_expr_uvalue(cnt); + cnt = 0; + } + + char name[256]; + if (nevents == 1) { + ivl_event_t ev = ivl_stmt_events(net, 0); + snprintf(name, sizeof(name), "E_%p", ev); + } else { + unsigned idx; + static unsigned int cascade_counter = 0; + ivl_event_t ev = ivl_stmt_events(net, 0); + fprintf(vvp_out, "Eassign_%u .event/or E_%p", + cascade_counter, ev); + + for (idx = 1; idx < nevents; idx += 1) { + ev = ivl_stmt_events(net, idx); + fprintf(vvp_out, ", E_%p", ev); + } + snprintf(name, sizeof(name), "Eassign_%u", cascade_counter); + cascade_counter += 1; + } + + if (cnt) { + int count_index = allocate_word(); + char*type = ivl_expr_signed(cnt) ? "/s" : ""; + draw_eval_expr_into_integer(cnt, count_index); + fprintf(vvp_out, " %%evctl%s %s, %d;\n", type, name, + count_index); + clr_word(count_index); + } else { + fprintf(vvp_out, " %%evctl/i %s, %lu;\n", name, count); + } + } else { + assert(ivl_stmt_cond_expr(net) == 0); + } unsigned long delay = 0; @@ -600,15 +679,15 @@ static int show_stmt_assign_nb(ivl_statement_t net) for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) { unsigned bit_limit = wid - cur_rbit; + unsigned bidx; + lval = ivl_stmt_lval(net, lidx); if (bit_limit > ivl_lval_width(lval)) bit_limit = ivl_lval_width(lval); - unsigned bidx; - bidx = res.base < 4? res.base : (res.base+cur_rbit); - assign_to_lvector(lval, bidx, delay, del, bit_limit); + assign_to_lvector(lval, bidx, delay, del, bit_limit, nevents); cur_rbit += bit_limit; @@ -861,6 +940,8 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) static void force_real_to_lval(ivl_statement_t net, int res) { const char*command_name; + ivl_lval_t lval; + ivl_signal_t lsig; switch (ivl_statement_type(net)) { case IVL_ST_CASSIGN: @@ -876,8 +957,8 @@ static void force_real_to_lval(ivl_statement_t net, int res) } assert(ivl_stmt_lvals(net) == 1); - ivl_lval_t lval = ivl_stmt_lval(net, 0); - ivl_signal_t lsig = ivl_lval_sig(lval); + lval = ivl_stmt_lval(net, 0); + lsig = ivl_lval_sig(lval); assert(ivl_lval_width(lval) == 1); assert(ivl_lval_part_off(lval) == 0); @@ -962,10 +1043,11 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) { - ivl_signal_t rsig;; + ivl_signal_t rsig; ivl_lval_t lval; ivl_signal_t lsig; const char*command_name; + ivl_expr_t part_off_ex; ivl_expr_t lword_idx, rword_idx; unsigned long use_lword = 0, use_rword = 0; @@ -993,7 +1075,7 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) /* We do not currently support driving a signal to a bit or * part select (this could give us multiple drivers). */ - ivl_expr_t part_off_ex = ivl_lval_part_off(lval); + part_off_ex = ivl_lval_part_off(lval); if (ivl_signal_width(lsig) > ivl_signal_width(rsig) || (part_off_ex && get_number_immediate(part_off_ex) != 0)) { fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot %s signal to " @@ -1060,9 +1142,13 @@ static int show_stmt_cassign(ivl_statement_t net) static int show_stmt_deassign(ivl_statement_t net) { ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0)); + unsigned lidx; + if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { + ivl_lval_t lval; + assert(ivl_stmt_lvals(net) == 1); - ivl_lval_t lval = ivl_stmt_lval(net, 0); + lval = ivl_stmt_lval(net, 0); assert(ivl_lval_width(lval) == 1); assert(ivl_lval_part_off(lval) == 0); assert(ivl_lval_idx(lval) == 0); @@ -1071,21 +1157,22 @@ static int show_stmt_deassign(ivl_statement_t net) return 0; } - unsigned lidx; - for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) { ivl_lval_t lval = ivl_stmt_lval(net, lidx); ivl_signal_t lsig = ivl_lval_sig(lval); ivl_expr_t word_idx = ivl_lval_idx(lval); unsigned long use_word = 0; + unsigned use_wid; + ivl_expr_t part_off_ex; + unsigned part_off; assert(lsig != 0); assert(ivl_lval_mux(lval) == 0); - unsigned use_wid = ivl_lval_width(lval); - ivl_expr_t part_off_ex = ivl_lval_part_off(lval); - unsigned part_off = 0; + use_wid = ivl_lval_width(lval); + part_off_ex = ivl_lval_part_off(lval); + part_off = 0; if (part_off_ex != 0) { assert(number_is_immediate(part_off_ex, 64, 0)); part_off = get_number_immediate(part_off_ex); @@ -1327,6 +1414,14 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope) return rc; } +static int show_stmt_free(ivl_statement_t net) +{ + ivl_scope_t scope = ivl_stmt_call(net); + + fprintf(vvp_out, " %%free S_%p;\n", scope); + return 0; +} + /* * noop statements are implemented by doing nothing. */ @@ -1338,11 +1433,14 @@ static int show_stmt_noop(ivl_statement_t net) static int show_stmt_release(ivl_statement_t net) { ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0)); + unsigned lidx; + if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { unsigned type = 0; + ivl_lval_t lval; assert(ivl_stmt_lvals(net) == 1); - ivl_lval_t lval = ivl_stmt_lval(net, 0); + lval = ivl_stmt_lval(net, 0); assert(ivl_lval_width(lval) == 1); assert(ivl_lval_part_off(lval) == 0); assert(ivl_lval_idx(lval) == 0); @@ -1353,8 +1451,6 @@ static int show_stmt_release(ivl_statement_t net) return 0; } - unsigned lidx; - for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) { ivl_lval_t lval = ivl_stmt_lval(net, lidx); ivl_signal_t lsig = ivl_lval_sig(lval); @@ -1362,12 +1458,16 @@ static int show_stmt_release(ivl_statement_t net) ivl_expr_t word_idx = ivl_lval_idx(lval); unsigned long use_word = 0; + unsigned use_wid; + ivl_expr_t part_off_ex; + unsigned part_off; + assert(lsig != 0); assert(ivl_lval_mux(lval) == 0); - unsigned use_wid = ivl_lval_width(lval); - ivl_expr_t part_off_ex = ivl_lval_part_off(lval); - unsigned part_off = 0; + use_wid = ivl_lval_width(lval); + part_off_ex = ivl_lval_part_off(lval); + part_off = 0; if (part_off_ex != 0) { assert(number_is_immediate(part_off_ex, 64, 0)); part_off = get_number_immediate(part_off_ex); @@ -1574,6 +1674,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) switch (code) { + case IVL_ST_ALLOC: + rc += show_stmt_alloc(net); + break; + case IVL_ST_ASSIGN: rc += show_stmt_assign(net); break; @@ -1635,6 +1739,10 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope) rc += show_stmt_fork(net, sscope); break; + case IVL_ST_FREE: + rc += show_stmt_free(net); + break; + case IVL_ST_NOOP: rc += show_stmt_noop(net); break; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 89cc691a9..3eb57d22e 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -36,7 +36,7 @@ * Escape non-symbol characters in ids, and quotes in strings. */ -inline static char hex_digit(unsigned i) +__inline__ static char hex_digit(unsigned i) { i &= 0xf; return i>=10 ? i-10+'A' : i+'0'; @@ -322,6 +322,8 @@ char* draw_Cr_to_string(double value) char tmp[256]; uint64_t mant = 0; + int sign, expo, vexp; + double fract; if (isinf(value)) { if (value > 0) @@ -335,19 +337,18 @@ char* draw_Cr_to_string(double value) return strdup(tmp); } - int sign = 0; + sign = 0; if (value < 0) { sign = 0x4000; value *= -1; } - int expo; - double fract = frexp(value, &expo); + fract = frexp(value, &expo); fract = ldexp(fract, 63); mant = fract; expo -= 63; - int vexp = expo + 0x1000; + vexp = expo + 0x1000; assert(vexp >= 0); assert(vexp < 0x2000); vexp += sign; @@ -1085,9 +1086,11 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net) static void draw_lpm_abs(ivl_lpm_t net) { const char*src_table[1]; + const char*dly; + draw_lpm_data_inputs(net, 0, 1, src_table); - const char*dly = draw_lpm_output_delay(net); + dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .abs %s;\n", net, dly, src_table[0]); @@ -1096,9 +1099,11 @@ static void draw_lpm_abs(ivl_lpm_t net) static void draw_lpm_cast_int(ivl_lpm_t net) { const char*src_table[1]; + const char*dly; + draw_lpm_data_inputs(net, 0, 1, src_table); - const char*dly = draw_lpm_output_delay(net); + dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n", net, dly, ivl_lpm_width(net), src_table[0]); @@ -1107,11 +1112,13 @@ static void draw_lpm_cast_int(ivl_lpm_t net) static void draw_lpm_cast_real(ivl_lpm_t net) { const char*src_table[1]; + const char*dly; + const char*is_signed = ""; + draw_lpm_data_inputs(net, 0, 1, src_table); - const char*dly = draw_lpm_output_delay(net); + dly = draw_lpm_output_delay(net); - const char*is_signed = ""; if (ivl_lpm_signed(net)) is_signed = ".s"; fprintf(vvp_out, "L_%p%s .cast/real%s %s;\n", @@ -1126,6 +1133,7 @@ static void draw_lpm_add(ivl_lpm_t net) ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0)); ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1)); ivl_variable_type_t dto = IVL_VT_LOGIC; + const char*dly; if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL) dto = IVL_VT_REAL; @@ -1179,7 +1187,7 @@ static void draw_lpm_add(ivl_lpm_t net) draw_lpm_data_inputs(net, 0, 2, src_table); - const char*dly = draw_lpm_output_delay(net); + dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .arith/%s %u, %s, %s;\n", net, dly, type, width, src_table[0], src_table[1]); @@ -1193,8 +1201,10 @@ static void draw_lpm_array(ivl_lpm_t net) { ivl_nexus_t nex; ivl_signal_t mem = ivl_lpm_array(net); + const char*tmp; + nex = ivl_lpm_select(net); - const char*tmp = draw_net_input(nex); + tmp = draw_net_input(nex); fprintf(vvp_out, "L_%p .array/port v%p, %s;\n", net, mem, tmp); } @@ -1208,6 +1218,7 @@ static void draw_lpm_cmp(ivl_lpm_t net) ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0)); ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1)); ivl_variable_type_t dtc = IVL_VT_LOGIC; + const char*dly; if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL) dtc = IVL_VT_REAL; @@ -1259,7 +1270,7 @@ static void draw_lpm_cmp(ivl_lpm_t net) draw_lpm_data_inputs(net, 0, 2, src_table); - const char*dly = draw_lpm_output_delay(net); + dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .cmp/%s%s %u, %s, %s;\n", net, dly, type, signed_string, width, @@ -1581,7 +1592,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net) fprintf(vvp_out, ")"); - /* Finally, print the reference to the signal from which the + /* Now print the reference to the signal from which the result is collected. */ { ivl_signal_t psig = ivl_scope_port(def, 0); assert(ivl_lpm_width(net) == ivl_signal_width(psig)); @@ -1590,7 +1601,8 @@ static void draw_lpm_ufunc(ivl_lpm_t net) fprintf(vvp_out, " v%p_0", psig); } - fprintf(vvp_out, ";\n"); + /* Finally, print the scope identifier. */ + fprintf(vvp_out, " S_%p;\n", def); } /* @@ -1650,15 +1662,19 @@ static void draw_lpm_re(ivl_lpm_t net, const char*type) static void draw_lpm_repeat(ivl_lpm_t net) { - fprintf(vvp_out, "L_%p .repeat %u, %u, %s;\n", net, + const char*dly = draw_lpm_output_delay(net); + + fprintf(vvp_out, "L_%p%s .repeat %u, %u, %s;\n", net, dly, ivl_lpm_width(net), ivl_lpm_size(net), draw_net_input(ivl_lpm_data(net,0))); } static void draw_lpm_sign_ext(ivl_lpm_t net) { - fprintf(vvp_out, "L_%p .extend/s %u, %s;\n", - net, ivl_lpm_width(net), + const char*dly = draw_lpm_output_delay(net); + + fprintf(vvp_out, "L_%p%s .extend/s %u, %s;\n", + net, dly, ivl_lpm_width(net), draw_net_input(ivl_lpm_data(net,0))); } @@ -1770,13 +1786,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) { unsigned idx; const char *type; - /* For now we do not support automatic tasks or functions. */ - if (ivl_scope_is_auto(net)) { - fprintf(stderr, "%s:%u: vvp-tgt sorry: automatic tasks/functions " - "are not supported!\n", - ivl_scope_def_file(net), ivl_scope_def_lineno(net)); - exit(1); - } + + const char*prefix = ivl_scope_is_auto(net) ? "auto" : ""; + switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: type = "module"; break; case IVL_SCT_FUNCTION: type = "function"; break; @@ -1787,8 +1799,8 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) default: type = "?"; assert(0); } - fprintf(vvp_out, "S_%p .scope %s, \"%s\" \"%s\" %d %d", - net, type, vvp_mangle_name(ivl_scope_basename(net)), + fprintf(vvp_out, "S_%p .scope %s%s, \"%s\" \"%s\" %d %d", + net, prefix, type, vvp_mangle_name(ivl_scope_basename(net)), ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)), ivl_scope_lineno(net)); diff --git a/verinum.cc b/verinum.cc index 76c3fb75d..e48ceb80e 100644 --- a/verinum.cc +++ b/verinum.cc @@ -23,6 +23,22 @@ # include # include # include // Needed to get pow for as_double(). +# include // Needed to get snprintf for as_string(). + +#if !defined(HAVE_LROUND) +/* + * If the system doesn't provide the lround function, then we provide + * it ourselves here. It is simply the nearest integer, rounded away + * from zero. + */ +extern "C" long int lround(double x) +{ + if (x >= 0.0) + return (long)floor(x+0.5); + else + return (long)ceil(x-0.5); +} +#endif static verinum::V add_with_carry(verinum::V l, verinum::V r, verinum::V&c); diff --git a/vpi/sdf_lexor.lex b/vpi/sdf_lexor.lex index 0a92c5eb6..accb02ed1 100644 --- a/vpi/sdf_lexor.lex +++ b/vpi/sdf_lexor.lex @@ -143,8 +143,10 @@ static int lookup_keyword(const char*text) */ static void process_quoted_string(void) { + char*endp; + yylval.string_val = strdup(yytext+1); - char*endp = yylval.string_val+strlen(yylval.string_val); + endp = yylval.string_val+strlen(yylval.string_val); assert(endp[-1] == '"'); endp[-1] = 0; } diff --git a/vpi/sys_clog2.c b/vpi/sys_clog2.c index 3941d443a..883c9105b 100644 --- a/vpi/sys_clog2.c +++ b/vpi/sys_clog2.c @@ -29,9 +29,10 @@ */ static unsigned is_numeric_obj(vpiHandle obj) { - assert(obj); unsigned rtn = 0; + assert(obj); + switch(vpi_get(vpiType, obj)) { case vpiConstant: case vpiParameter: @@ -60,10 +61,11 @@ static unsigned is_numeric_obj(vpiHandle obj) static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv, arg; + assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - (void) name; // Not used! + argv = vpi_iterate(vpiArgument, callh); + (void) name; /* Not used! */ /* We must have an argument. */ if (argv == 0) { @@ -86,11 +88,13 @@ static PLI_INT32 sys_clog2_compiletf(PLI_BYTE8 *name) /* We can have a maximum of one argument. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s $clog2 takes at most one argument.\n", msg); @@ -109,7 +113,7 @@ static PLI_INT32 sys_clog2_calltf(PLI_BYTE8 *name) vpiHandle arg; s_vpi_value val; s_vpi_vecval vec; - (void) name; // Not used!/ + (void) name; /* Not used! */ /* Get the argument. */ arg = vpi_scan(argv); diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 0cd571cc9..2a327f60e 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -60,29 +60,30 @@ struct strobe_cb_info { unsigned mcd; }; -// 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 -// this transcendental number as 146/485, to avoid the vagaries -// of floating-point. The smallest nr_bits for which this -// approximation fails is 2621, -// 2621*log_10(2)=789.9996, but (2621*146+484)/485=790 (exactly). -// In cases like this, all that happens is we allocate one -// unneeded char for the output. I add a "L" suffix to 146 -// to make sure the computation is done as long ints, otherwise -// on a 16-bit int machine (allowed by ISO C) we would mangle -// this computation for bit-length of 224. I'd like to put -// in a test for nr_bits < LONG_MAX/146, but don't know how -// to fail, other than crashing. -// -// In an April 2000 thread in comp.unix.programmer, with subject -// "integer -> string", I give the 28/93 -// approximation, but overstate its accuracy: that version first -// fails when the number of bits is 289, not 671. -// -// This result does not include space for a trailing '\0', if any. -// -inline static int calc_dec_size(int nr_bits, int is_signed) +/* + * 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 + * this transcendental number as 146/485, to avoid the vagaries + * of floating-point. The smallest nr_bits for which this + * approximation fails is 2621, + * 2621*log_10(2)=789.9996, but (2621*146+484)/485=790 (exactly). + * In cases like this, all that happens is we allocate one + * unneeded char for the output. I add a "L" suffix to 146 + * to make sure the computation is done as long ints, otherwise + * on a 16-bit int machine (allowed by ISO C) we would mangle + * this computation for bit-length of 224. I'd like to put + * in a test for nr_bits < LONG_MAX/146, but don't know how + * to fail, other than crashing. + * + * In an April 2000 thread in comp.unix.programmer, with subject + * "integer -> string", I give the 28/93 + * approximation, but overstate its accuracy: that version first + * fails when the number of bits is 289, not 671. + * + * This result does not include space for a trailing '\0', if any. +*/ +__inline__ static int calc_dec_size(int nr_bits, int is_signed) { int r; if (is_signed) --nr_bits; @@ -378,7 +379,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd, use_count = 0; break; - // new Verilog 2001 format specifiers... + /* new Verilog 2001 format specifiers... */ case 'l': case 'L': case 'u': @@ -445,7 +446,7 @@ static int format_str_char(vpiHandle scope, unsigned int mcd, { char* value_str = value.value.str; if (leading_zero==1){ - // Strip away all leading zeros from string + /* Strip away all leading zeros from string */ unsigned int i=0; while(i< (strlen(value_str)-1) && value_str[i]=='0') i++; @@ -511,11 +512,12 @@ static int format_str_char(vpiHandle scope, unsigned int mcd, } if (fsize==-1){ - // simple %d parameter, or %0d parameter. - // Size is now determined by the width - // of the vector or integer. If %0d, then - // set the size to 0 so that the minimum - // size is used. + /* simple %d parameter, or %0d parameter. + * Size is now determined by the width + * of the vector or integer. If %0d, then + * set the size to 0 so that the minimum + * size is used. + */ fsize = (leading_zero==1) ? 0 : vpi_get_dec_size(argv[idx]); @@ -871,7 +873,7 @@ static int get_default_format(char *name) int default_format; switch(name[ strlen(name)-1 ]){ - // writE/strobE or monitoR or displaY/fdisplaY or sformaT + /* writE/strobE or monitoR or displaY/fdisplaY or sformaT */ case 'e': case 'r': case 't': @@ -1938,7 +1940,7 @@ static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) } /* The first argument must be a register. */ - reg = vpi_scan(argv); //* This should never be zero. */ + reg = vpi_scan(argv); /* This should never be zero. */ if (vpi_get(vpiType, reg) != vpiReg) { vpi_printf("ERROR: %s's first argument must be a register.\n", name); vpi_control(vpiFinish, 1); @@ -1998,7 +2000,7 @@ static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name) } /* The first argument must be a register. */ - arg = vpi_scan(argv); //* This should never be zero. */ + arg = vpi_scan(argv); /* This should never be zero. */ if (vpi_get(vpiType, arg) != vpiReg) { vpi_printf("ERROR: %s's first argument must be a register.\n", name); vpi_control(vpiFinish, 1); @@ -2201,7 +2203,7 @@ void sys_display_register() s_cb_data cb_data; s_vpi_systf_data tf_data; - //============================== display + /*============================== display */ tf_data.type = vpiSysTask; tf_data.tfname = "$display"; tf_data.calltf = sys_display_calltf; @@ -2234,7 +2236,7 @@ void sys_display_register() tf_data.user_data = "$displayb"; vpi_register_systf(&tf_data); - //============================== write + /*============================== write */ tf_data.type = vpiSysTask; tf_data.tfname = "$write"; tf_data.calltf = sys_display_calltf; @@ -2267,7 +2269,7 @@ void sys_display_register() tf_data.user_data = "$writeb"; vpi_register_systf(&tf_data); - //============================== strobe + /*============================== strobe */ tf_data.type = vpiSysTask; tf_data.tfname = "$strobe"; tf_data.calltf = sys_strobe_calltf; @@ -2300,7 +2302,7 @@ void sys_display_register() tf_data.user_data = "$strobeb"; vpi_register_systf(&tf_data); - //============================== fstrobe + /*============================== fstrobe */ tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobe"; tf_data.calltf = sys_strobe_calltf; @@ -2333,7 +2335,7 @@ void sys_display_register() tf_data.user_data = "$fstrobeb"; vpi_register_systf(&tf_data); - //============================== monitor + /*============================== monitor */ tf_data.type = vpiSysTask; tf_data.tfname = "$monitor"; tf_data.calltf = sys_monitor_calltf; @@ -2382,7 +2384,7 @@ void sys_display_register() tf_data.user_data = "$monitoroff"; vpi_register_systf(&tf_data); - //============================== fdisplay + /*============================== fdisplay */ tf_data.type = vpiSysTask; tf_data.tfname = "$fdisplay"; tf_data.calltf = sys_fdisplay_calltf; @@ -2415,7 +2417,7 @@ void sys_display_register() tf_data.user_data = "$fdisplayb"; vpi_register_systf(&tf_data); - //============================== fwrite + /*============================== fwrite */ tf_data.type = vpiSysTask; tf_data.tfname = "$fwrite"; tf_data.calltf = sys_fdisplay_calltf; @@ -2448,7 +2450,7 @@ void sys_display_register() tf_data.user_data = "$fwriteb"; vpi_register_systf(&tf_data); - //============================== swrite + /*============================== swrite */ tf_data.type = vpiSysTask; tf_data.tfname = "$swrite"; tf_data.calltf = sys_swrite_calltf; @@ -2489,7 +2491,7 @@ void sys_display_register() tf_data.user_data = "$sformat"; vpi_register_systf(&tf_data); - //============================ timeformat + /*============================ timeformat */ tf_data.type = vpiSysTask; tf_data.tfname = "$timeformat"; tf_data.calltf = sys_timeformat_calltf; diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index b763bb776..ac36d9f05 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -34,9 +34,10 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle argv; vpiHandle arg; + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); /* Check that there is a file name argument and that it is a string. */ if (argv == 0) { @@ -68,11 +69,13 @@ static PLI_INT32 sys_fopen_compiletf(PLI_BYTE8 *name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes at most two string arguments.\n", @@ -95,6 +98,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) unsigned idx; vpiHandle item = vpi_scan(argv); vpiHandle mode = vpi_scan(argv); + unsigned len; /* Get the mode handle if it exists. */ if (mode) { @@ -177,7 +181,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) * Verify that the file name is composed of only printable * characters. */ - unsigned len = strlen(val.value.str); + len = strlen(val.value.str); for (idx = 0; idx < len; idx++) { if (! isprint(val.value.str[idx])) { char msg [64]; @@ -217,10 +221,11 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle file = vpi_scan(argv); - vpi_free_object(argv); - s_vpi_value val; char *mode; + unsigned idx, len; + + vpi_free_object(argv); /* Get the mode. */ mode = name + strlen(name) - 1; @@ -242,7 +247,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) * Verify that the file name is composed of only printable * characters. */ - unsigned idx, len = strlen(val.value.str); + len = strlen(val.value.str); for (idx = 0; idx < len; idx++) { if (! isprint(val.value.str[idx])) { char msg [64]; @@ -272,12 +277,12 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name) vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle fd = vpi_scan(argv); - vpi_free_object(argv); - (void) name; /* Not used! */ - s_vpi_value val; PLI_UINT32 fd_mcd; + vpi_free_object(argv); + (void) name; /* Not used! */ + val.format = vpiIntVal; vpi_get_value(fd, &val); fd_mcd = val.value.integer; @@ -406,11 +411,13 @@ static PLI_INT32 sys_fgets_compiletf(PLI_BYTE8*name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes two arguments.\n", msg, name); @@ -590,11 +597,13 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes three arguments.\n", msg, name); @@ -727,7 +736,7 @@ void sys_fileio_register() { s_vpi_systf_data tf_data; - //============================== fopen + /*============================== fopen */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$fopen"; @@ -737,7 +746,7 @@ void sys_fileio_register() tf_data.user_data = "$fopen"; vpi_register_systf(&tf_data); - //============================== fopenr + /*============================== fopenr */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$fopenr"; @@ -747,17 +756,17 @@ void sys_fileio_register() tf_data.user_data = "$fopenr"; vpi_register_systf(&tf_data); - //============================== fopenw + /*============================== fopenw */ tf_data.tfname = "$fopenw"; tf_data.user_data = "$fopenw"; vpi_register_systf(&tf_data); - //============================== fopena + /*============================== fopena */ tf_data.tfname = "$fopena"; tf_data.user_data = "$fopena"; vpi_register_systf(&tf_data); - //============================== fclose + /*============================== fclose */ tf_data.type = vpiSysTask; tf_data.tfname = "$fclose"; tf_data.calltf = sys_fclose_calltf; @@ -766,7 +775,7 @@ void sys_fileio_register() tf_data.user_data = "$fclose"; vpi_register_systf(&tf_data); - //============================== fflush + /*============================== fflush */ tf_data.type = vpiSysTask; tf_data.tfname = "$fflush"; tf_data.calltf = sys_fflush_calltf; @@ -775,7 +784,7 @@ void sys_fileio_register() tf_data.user_data = "$fflush"; vpi_register_systf(&tf_data); - //============================== fputc + /*============================== fputc */ tf_data.type = vpiSysTask; tf_data.tfname = "$fputc"; tf_data.calltf = sys_fputc_calltf; @@ -784,7 +793,7 @@ void sys_fileio_register() tf_data.user_data = "$fputc"; vpi_register_systf(&tf_data); - //============================== fgetc + /*============================== fgetc */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$fgetc"; @@ -794,7 +803,7 @@ void sys_fileio_register() tf_data.user_data = "$fgetc"; vpi_register_systf(&tf_data); - //============================== fgets + /*============================== fgets */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$fgets"; @@ -804,7 +813,7 @@ void sys_fileio_register() tf_data.user_data = "$fgets"; vpi_register_systf(&tf_data); - //============================== ungetc + /*============================== ungetc */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$ungetc"; @@ -814,7 +823,7 @@ void sys_fileio_register() tf_data.user_data = "$ungetc"; vpi_register_systf(&tf_data); - //============================== ftell + /*============================== ftell */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$ftell"; @@ -824,7 +833,7 @@ void sys_fileio_register() tf_data.user_data = "$ftell"; vpi_register_systf(&tf_data); - //============================== fseek + /*============================== fseek */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$fseek"; @@ -834,7 +843,7 @@ void sys_fileio_register() tf_data.user_data = "$fseek"; vpi_register_systf(&tf_data); - //============================== rewind + /*============================== rewind */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$rewind"; @@ -845,7 +854,7 @@ void sys_fileio_register() vpi_register_systf(&tf_data); /* $feof() is from 1364-2005. */ - //============================== feof + /*============================== feof */ tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.tfname = "$feof"; diff --git a/vpi/sys_lxt.c b/vpi/sys_lxt.c index df9da94e4..6521d749b 100644 --- a/vpi/sys_lxt.c +++ b/vpi/sys_lxt.c @@ -202,7 +202,7 @@ struct vcd_names_list_s lxt_tab; static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; -inline static int dump_header_pending(void) +__inline__ static int dump_header_pending(void) { return dumpvars_status != 2; } @@ -312,7 +312,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) return 0; } -inline static int install_dumpvars_callback(void) +__inline__ static int install_dumpvars_callback(void) { struct t_cb_data cb; static struct t_vpi_time time; @@ -712,7 +712,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name) /* This dumps all the modules in the design if none are given. */ if (!argv || !(item = vpi_scan(argv))) { argv = vpi_iterate(vpiModule, 0x0); - assert(argv); // There must be at least one top level module. + assert(argv); /* There must be at least one top level module. */ item = vpi_scan(argv); } diff --git a/vpi/sys_lxt2.c b/vpi/sys_lxt2.c index b85486244..797078502 100644 --- a/vpi/sys_lxt2.c +++ b/vpi/sys_lxt2.c @@ -204,7 +204,7 @@ struct vcd_names_list_s lxt_tab; static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; -inline static int dump_header_pending(void) +__inline__ static int dump_header_pending(void) { return dumpvars_status != 2; } @@ -311,7 +311,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) return 0; } -inline static int install_dumpvars_callback(void) +__inline__ static int install_dumpvars_callback(void) { struct t_cb_data cb; static struct t_vpi_time time; @@ -724,7 +724,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name) /* This dumps all the modules in the design if none are given. */ if (!argv || !(item = vpi_scan(argv))) { argv = vpi_iterate(vpiModule, 0x0); - assert(argv); // There must be at least one top level module. + assert(argv); /* There must be at least one top level module. */ item = vpi_scan(argv); } diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index 70f0a4316..6b008844a 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -41,9 +41,10 @@ PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time) */ unsigned is_constant_obj(vpiHandle obj) { - assert(obj); unsigned rtn = 0; + assert(obj); + switch(vpi_get(vpiType, obj)) { case vpiConstant: case vpiParameter: @@ -60,9 +61,10 @@ unsigned is_constant_obj(vpiHandle obj) */ unsigned is_numeric_obj(vpiHandle obj) { - assert(obj); unsigned rtn = 0; + assert(obj); + switch(vpi_get(vpiType, obj)) { case vpiConstant: case vpiParameter: @@ -92,9 +94,10 @@ unsigned is_numeric_obj(vpiHandle obj) */ unsigned is_string_obj(vpiHandle obj) { - assert(obj); unsigned rtn = 0; + assert(obj); + switch(vpi_get(vpiType, obj)) { case vpiConstant: case vpiParameter: { @@ -147,11 +150,13 @@ PLI_INT32 sys_no_arg_compiletf(PLI_BYTE8 *name) /* Make sure there are no arguments. */ if (argv != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 0; + argc = 0; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s does not take an argument.\n", msg, name); @@ -188,11 +193,13 @@ PLI_INT32 sys_one_numeric_arg_compiletf(PLI_BYTE8 *name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes a single numeric argument.\n", msg, name); @@ -223,11 +230,13 @@ PLI_INT32 sys_one_opt_numeric_arg_compiletf(PLI_BYTE8 *name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes at most one numeric argument.\n", @@ -282,11 +291,13 @@ PLI_INT32 sys_two_numeric_args_compiletf(PLI_BYTE8 *name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes two numeric arguments.\n", msg, name); @@ -322,11 +333,13 @@ PLI_INT32 sys_one_string_arg_compiletf(PLI_BYTE8 *name) /* Make sure there are no extra arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s %s takes a single string argument.\n", msg, name); diff --git a/vpi/sys_random_mti.c b/vpi/sys_random_mti.c index ba6c64d99..c19942d7e 100644 --- a/vpi/sys_random_mti.c +++ b/vpi/sys_random_mti.c @@ -43,7 +43,7 @@ static struct context_s global_context = { #if defined(__GCC__) .mti = #else - // For MSVC simply use the fact that mti is located first + /* For MSVC simply use the fact that mti is located first */ #endif NP1 }; diff --git a/vpi/sys_scanf.c b/vpi/sys_scanf.c index aff54193f..6a4615741 100644 --- a/vpi/sys_scanf.c +++ b/vpi/sys_scanf.c @@ -46,7 +46,7 @@ static int byte_getc(struct byte_source*byte) } ch = fgetc(byte->fd); -// fprintf(stderr, "byte_getc --> '%c' (%d)\n", ch, ch); +/* fprintf(stderr, "byte_getc --> '%c' (%d)\n", ch, ch); */ return ch; } @@ -594,7 +594,7 @@ void sys_scanf_register() { s_vpi_systf_data tf_data; - //============================== fscanf + /*============================== fscanf */ tf_data.type = vpiSysFunc; tf_data.tfname = "$fscanf"; tf_data.calltf = sys_fscanf_calltf; @@ -603,7 +603,7 @@ void sys_scanf_register() tf_data.user_data = "$fscanf"; vpi_register_systf(&tf_data); - //============================== sscanf + /*============================== sscanf */ tf_data.type = vpiSysFunc; tf_data.tfname = "$sscanf"; tf_data.calltf = sys_sscanf_calltf; diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index f4d332ae4..a939fc433 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -127,6 +127,7 @@ static const char*edge_str(int vpi_edge) void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, const struct sdf_delval_list_s*delval_list) { + s_vpi_delay delays; if (sdf_cur_cell == 0) return; @@ -140,7 +141,6 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, delay_vals[idx].real = delval_list->val[idx]; } - s_vpi_delay delays; delays.da = delay_vals; delays.no_of_delays = delval_list->count; delays.time_type = vpiScaledRealTime; diff --git a/vpi/sys_time.c b/vpi/sys_time.c index 5d040f966..35b64458a 100644 --- a/vpi/sys_time.c +++ b/vpi/sys_time.c @@ -86,22 +86,17 @@ static PLI_INT32 sys_realtime_calltf(PLI_BYTE8*name) s_vpi_time now; vpiHandle call_handle; vpiHandle mod; - int units, prec; call_handle = vpi_handle(vpiSysTfCall, 0); assert(call_handle); mod = sys_func_module(call_handle); - now.type = vpiSimTime; - vpi_get_time(0, &now); - - units = vpi_get(vpiTimeUnit, mod); - prec = vpi_get(vpiTimePrecision, 0); + now.type = vpiScaledRealTime; + vpi_get_time(mod, &now); val.format = vpiRealVal; - val.value.real = pow(10.0, prec-units) * now.low; - assert(now.high == 0); + val.value.real = now.real; vpi_put_value(call_handle, &val, 0, vpiNoDelay); diff --git a/vpi/sys_vcd.c b/vpi/sys_vcd.c index 76c444851..222745167 100644 --- a/vpi/sys_vcd.c +++ b/vpi/sys_vcd.c @@ -144,7 +144,7 @@ struct vcd_names_list_s vcd_var = { 0 }; static int dumpvars_status = 0; /* 0:fresh 1:cb installed, 2:callback done */ static PLI_UINT64 dumpvars_time; -inline static int dump_header_pending(void) +__inline__ static int dump_header_pending(void) { return dumpvars_status != 2; } @@ -258,7 +258,7 @@ static PLI_INT32 finish_cb(p_cb_data cause) return 0; } -inline static int install_dumpvars_callback(void) +__inline__ static int install_dumpvars_callback(void) { struct t_cb_data cb; static struct t_vpi_time time; @@ -714,13 +714,14 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name) /* This dumps all the modules in the design if none are given. */ if (!argv || !(item = vpi_scan(argv))) { argv = vpi_iterate(vpiModule, 0x0); - assert(argv); // There must be at least one top level module. + assert(argv); /* There must be at least one top level module. */ item = vpi_scan(argv); } for ( ; item; item = vpi_scan(argv)) { const char *scname; int add_var = 0; + int dep; vcd_names_sort(&vcd_tab); @@ -744,7 +745,7 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name) } } - int dep = draw_scope(item, callh); + dep = draw_scope(item, callh); scan_item(depth, item, 0); diff --git a/vpi/v2005_math.c b/vpi/v2005_math.c index 7d124d869..582598851 100644 --- a/vpi/v2005_math.c +++ b/vpi/v2005_math.c @@ -131,15 +131,19 @@ vpiHandle va_process_argument(vpiHandle callh, const char *name, */ static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8 *ud) { - assert(ud != 0); - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - t_single_data *data = (t_single_data *) ud; - const char *name = data->name; + vpiHandle callh, argv, arg; + t_single_data *data; + const char *name; + va_single_t* fun_data; - va_single_t* fun_data = malloc(sizeof(va_single_t)); + assert(ud != 0); + callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + data = (t_single_data *) ud; + name = data->name; + + fun_data = malloc(sizeof(va_single_t)); /* Check that malloc gave use some memory. */ if (fun_data == 0) { @@ -180,10 +184,12 @@ static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); s_vpi_value val; + va_single_t* fun_data; + (void) ud; /* Not used! */ /* Retrieve the function and argument data. */ - va_single_t* fun_data = vpi_get_userdata(callh); + fun_data = vpi_get_userdata(callh); /* Calculate the result */ val.format = vpiRealVal; @@ -202,15 +208,19 @@ static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud) */ static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8 *ud) { - assert(ud != 0); - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - t_double_data *data = (t_double_data *) ud; - const char *name = data->name; + vpiHandle callh, argv, arg; + t_double_data *data; + const char *name; + va_double_t* fun_data; - va_double_t* fun_data = malloc(sizeof(va_double_t)); + assert(ud != 0); + callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + data = (t_double_data *) ud; + name = data->name; + + fun_data = malloc(sizeof(va_double_t)); /* Check that malloc gave use some memory. */ if (fun_data == 0) { @@ -259,10 +269,12 @@ static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud) vpiHandle callh = vpi_handle(vpiSysTfCall, 0); s_vpi_value val; double first_arg; + va_double_t* fun_data; + (void) ud; /* Not used! */ /* Retrieve the function and argument data. */ - va_double_t* fun_data = vpi_get_userdata(callh); + fun_data = vpi_get_userdata(callh); /* Calculate the result */ val.format = vpiRealVal; diff --git a/vpi/va_math.c b/vpi/va_math.c index 62502a34e..ebd57a737 100644 --- a/vpi/va_math.c +++ b/vpi/va_math.c @@ -163,15 +163,19 @@ vpiHandle va_process_argument(vpiHandle callh, const char *name, */ static PLI_INT32 va_single_argument_compiletf(PLI_BYTE8 *ud) { - assert(ud != 0); - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - t_single_data *data = (t_single_data *) ud; - const char *name = data->name; + vpiHandle callh, argv, arg; + t_single_data *data; + const char *name; + va_single_t* fun_data; - va_single_t* fun_data = malloc(sizeof(va_single_t)); + assert(ud != 0); + callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + data = (t_single_data *) ud; + name = data->name; + + fun_data = malloc(sizeof(va_single_t)); /* Check that malloc gave use some memory. */ if (fun_data == 0) { @@ -212,10 +216,12 @@ static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); s_vpi_value val; + va_single_t* fun_data; + (void) ud; /* Not used! */ /* Retrieve the function and argument data. */ - va_single_t* fun_data = vpi_get_userdata(callh); + fun_data = vpi_get_userdata(callh); /* Calculate the result */ val.format = vpiRealVal; @@ -234,15 +240,19 @@ static PLI_INT32 va_single_argument_calltf(PLI_BYTE8 *ud) */ static PLI_INT32 va_double_argument_compiletf(PLI_BYTE8 *ud) { - assert(ud != 0); - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - t_double_data *data = (t_double_data *) ud; - const char *name = data->name; + vpiHandle callh, argv, arg; + t_double_data *data; + const char *name; + va_double_t* fun_data; - va_double_t* fun_data = malloc(sizeof(va_double_t)); + assert(ud != 0); + callh = vpi_handle(vpiSysTfCall, 0); + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + data = (t_double_data *) ud; + name = data->name; + + fun_data = malloc(sizeof(va_double_t)); /* Check that malloc gave use some memory. */ if (fun_data == 0) { @@ -291,10 +301,12 @@ static PLI_INT32 va_double_argument_calltf(PLI_BYTE8 *ud) vpiHandle callh = vpi_handle(vpiSysTfCall, 0); s_vpi_value val; double first_arg; + va_double_t* fun_data; + (void) ud; /* Not used! */ /* Retrieve the function and argument data. */ - va_double_t* fun_data = vpi_get_userdata(callh); + fun_data = vpi_get_userdata(callh); /* Calculate the result */ val.format = vpiRealVal; diff --git a/vpi/vams_simparam.c b/vpi/vams_simparam.c index 90a73ced5..d39206227 100644 --- a/vpi/vams_simparam.c +++ b/vpi/vams_simparam.c @@ -36,10 +36,11 @@ */ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) { - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle callh, argv, arg; + + callh = vpi_handle(vpiSysTfCall, 0); assert(callh != 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; + argv = vpi_iterate(vpiArgument, callh); /* We must have at least one argument. */ if (argv == 0) { @@ -87,11 +88,13 @@ static PLI_INT32 simparam_compiletf(PLI_BYTE8 *name_ext) /* We can have a maximum of two arguments. */ if (vpi_scan(argv) != 0) { char msg [64]; + unsigned argc; + snprintf(msg, 64, "ERROR: %s line %d:", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - unsigned argc = 1; + argc = 1; while (vpi_scan(argv)) argc += 1; vpi_printf("%s $simparam%s takes at most two arguments.\n", @@ -250,7 +253,7 @@ static PLI_INT32 simparam_str_sizetf(PLI_BYTE8 *name_ext) { (void) name_ext; /* Not used! */ - return MAX_STRING_RESULT; // 128 characters max! + return MAX_STRING_RESULT; /* 128 characters max! */ } /* diff --git a/vpi/vcd_priv.c b/vpi/vcd_priv.c index e1c370c5d..ad4276c8f 100644 --- a/vpi/vcd_priv.c +++ b/vpi/vcd_priv.c @@ -143,7 +143,7 @@ struct vcd_id_s int nex; }; -static inline unsigned ihash(int nex) +static __inline__ unsigned ihash(int nex) { unsigned a = nex; a ^= a>>16; diff --git a/vpi/vpi_config.h.in b/vpi/vpi_config.h.in index 59a8d13b8..88bd59bbc 100644 --- a/vpi/vpi_config.h.in +++ b/vpi/vpi_config.h.in @@ -32,4 +32,4 @@ # define _FILE_OFFSET_BITS 64 #endif -#endif // __config_H +#endif /* __config_H */ diff --git a/vvp/README.txt b/vvp/README.txt index 188f58e36..4781f6814 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -96,8 +96,8 @@ The syntax of a scope statement is: