From 37017334af4c6d165f97f9f03954f7e2a8cc389c Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 24 Dec 2011 09:29:55 -0800 Subject: [PATCH 01/88] Fix build issues in tgt-pcb On Ubunto 10.10 (32 bit) tgt-pcb would not build because there were include file issues. This patch fixes those and uses the C++ include version where appropriate. --- tgt-pcb/pcb.cc | 4 +++- tgt-pcb/pcb_priv.h | 2 +- tgt-pcb/scope.cc | 1 + tgt-pcb/show_netlist.cc | 1 + tgt-pcb/show_pcb.cc | 2 ++ 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tgt-pcb/pcb.cc b/tgt-pcb/pcb.cc index 547dc3a7b..60ad4d121 100644 --- a/tgt-pcb/pcb.cc +++ b/tgt-pcb/pcb.cc @@ -24,7 +24,9 @@ # include "version_base.h" # include "version_tag.h" # include "pcb_config.h" -# include +# include +# include +# include # include "pcb_priv.h" # include "ivl_target.h" diff --git a/tgt-pcb/pcb_priv.h b/tgt-pcb/pcb_priv.h index b98fceef0..466dbfd54 100644 --- a/tgt-pcb/pcb_priv.h +++ b/tgt-pcb/pcb_priv.h @@ -23,7 +23,7 @@ # include # include # include -# include +# include "ivl_target.h" extern int scan_scope(ivl_scope_t scope); diff --git a/tgt-pcb/scope.cc b/tgt-pcb/scope.cc index 22f8e25d4..0ea50a995 100644 --- a/tgt-pcb/scope.cc +++ b/tgt-pcb/scope.cc @@ -21,6 +21,7 @@ # include # include # include +# include using namespace std; diff --git a/tgt-pcb/show_netlist.cc b/tgt-pcb/show_netlist.cc index a2a5d6be2..992be0c5e 100644 --- a/tgt-pcb/show_netlist.cc +++ b/tgt-pcb/show_netlist.cc @@ -18,6 +18,7 @@ */ # include "pcb_priv.h" +# include # include using namespace std; diff --git a/tgt-pcb/show_pcb.cc b/tgt-pcb/show_pcb.cc index 02623bb90..42fd5299d 100644 --- a/tgt-pcb/show_pcb.cc +++ b/tgt-pcb/show_pcb.cc @@ -19,6 +19,8 @@ # include "pcb_config.h" # include "pcb_priv.h" +# include +# include using namespace std; From 4b96b6316693ee9286b93962f681fddd8798fe46 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 24 Dec 2011 09:59:56 -0800 Subject: [PATCH 02/88] Fix more tgt-pcb compile problems. On some systems having both %.o: %.c and %.o: %.cc rules confused the make system. This is directory only has C++ code so remove the %o: %.c rule. Also the C++ compiler should be used to link C++ object code. --- tgt-pcb/Makefile.in | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index 9e728681a..f8e8d16a0 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -66,10 +66,6 @@ Makefile: $(srcdir)/Makefile.in ../config.status dep: mkdir dep -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o - mv $*.d dep - %.o: %.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep @@ -83,7 +79,7 @@ else endif pcb.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CXX) @shared@ -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/pcb.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/pcb.conf $(libdir)/ivl$(suffix)/pcb-s.conf From 965c77525c9596ea2ea1424e83874616bd4fdbfc Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 24 Dec 2011 11:20:54 -0800 Subject: [PATCH 03/88] A C++ function passed to C should be declared extern "C" --- tgt-pcb/scope.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-pcb/scope.cc b/tgt-pcb/scope.cc index 0ea50a995..d9ae6a0cc 100644 --- a/tgt-pcb/scope.cc +++ b/tgt-pcb/scope.cc @@ -86,7 +86,7 @@ int scan_scope(ivl_scope_t scope) return 0; } -static int child_scan_fun(ivl_scope_t scope, void*) +extern "C" int child_scan_fun(ivl_scope_t scope, void*) { int rc = scan_scope(scope); return 0; From 142f6617378cd28c5202dada4b06003f255b6d31 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 2 Jan 2012 10:11:56 -0800 Subject: [PATCH 04/88] Fix the compiler to keep the original file/line information. For a parameter we want to keep the base definition file/line information not the file/line information for the override. --- PExpr.h | 8 ++++---- elab_expr.cc | 28 +++++++++++++++++++++++----- libmisc/LineInfo.h | 4 ++-- net_design.cc | 4 ++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/PExpr.h b/PExpr.h index 8aa74beee..e087cb592 100644 --- a/PExpr.h +++ b/PExpr.h @@ -354,7 +354,7 @@ class PEIdent : public PExpr { NetExpr*elaborate_expr_param_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, unsigned expr_wid, @@ -362,21 +362,21 @@ class PEIdent : public PExpr { NetExpr*elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, unsigned expr_wid) const; NetExpr*elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const; NetExpr*elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const; diff --git a/elab_expr.cc b/elab_expr.cc index ad24ecff3..42ef38108 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2540,7 +2540,7 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined, NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const @@ -2613,6 +2613,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, base = normalize_variable_base(base, par_msv, par_lsv, wid, true); NetExpr*tmp = par->dup_expr(); + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_UP); tmp->set_line(*this); return tmp; @@ -2620,7 +2626,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const @@ -2694,6 +2700,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, base = normalize_variable_base(base, par_msv, par_lsv, wid, false); NetExpr*tmp = par->dup_expr(); + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_DOWN); tmp->set_line(*this); return tmp; @@ -2748,8 +2760,14 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, // rewritten in the above format, as I get to it. NetExpr*tmp = par->dup_expr(); - if (!tmp) - return 0; + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + if (! dynamic_cast(tmp)) { + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); + } if (use_sel == index_component_t::SEL_BIT) { ivl_assert(*this, !name_tail.index.empty()); @@ -2846,6 +2864,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, NetEConst*re2 = new NetEConst(verinum(rb, 1)); + re2->set_line(*this); delete tmp; delete mtmp; tmp = re2; @@ -2911,7 +2930,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, } } - tmp->set_line(*this); return tmp; } diff --git a/libmisc/LineInfo.h b/libmisc/LineInfo.h index f2262b568..357360fad 100644 --- a/libmisc/LineInfo.h +++ b/libmisc/LineInfo.h @@ -1,7 +1,7 @@ #ifndef __LineInfo_H #define __LineInfo_H /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,7 +40,7 @@ class LineInfo { // Get a fully formatted file/lineno string get_fileline() const; - // Set the file/line fro another LineInfo object. + // Set the file/line from another LineInfo object. void set_line(const LineInfo&that); // Access parts of LineInfo data diff --git a/net_design.cc b/net_design.cc index 84f4a7a34..3ed2fef8c 100644 --- a/net_design.cc +++ b/net_design.cc @@ -641,8 +641,8 @@ void NetScope::evaluate_parameters(Design*des) cur->second->evaluate_parameters(des); if (debug_scopes) - cerr << ":0" << ": debug: " - << "Evaluate parameters in " << scope_path(this) << endl; + cerr << "debug: " + << "Evaluating parameters in " << scope_path(this) << endl; for (param_ref_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur) { From ba4137d1e874e505781ae830e0b1fec6ebbcccbe Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 2 Jan 2012 10:14:20 -0800 Subject: [PATCH 05/88] Keep the width information for all the tran gates. Update the compiler to keep the actual width information for all the tran gates. --- elaborate.cc | 18 ++++++++++++------ net_tran.cc | 6 +++--- netlist.h | 3 ++- t-dll.cc | 3 +-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index ed85ab6b2..e2bf04e64 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -524,7 +524,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tran device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRAN); + gate = new NetTran(scope, inst_name, IVL_SW_TRAN, + instance_width); } break; @@ -534,7 +535,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtran device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRAN); + gate = new NetTran(scope, inst_name, IVL_SW_RTRAN, + instance_width); } break; @@ -544,7 +546,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tranif0 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0); + gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0, + instance_width); } break; @@ -554,7 +557,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtranif0 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0); + gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0, + instance_width); } break; @@ -564,7 +568,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tranif1 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1); + gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1, + instance_width); } break; @@ -574,7 +579,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtranif1 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1); + gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1, + instance_width); } break; diff --git a/net_tran.cc b/net_tran.cc index 79d9c50f0..e170bb3fc 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -42,15 +42,15 @@ 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) +NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt, + unsigned width) +: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt), wid_(width) { pin(0).set_dir(Link::PASSIVE); pin(1).set_dir(Link::PASSIVE); if (pin_count() == 3) { pin(2).set_dir(Link::INPUT); // Enable } - wid_ = 0; part_ = 0; off_ = 0; } diff --git a/netlist.h b/netlist.h index 8304bb777..055466b5d 100644 --- a/netlist.h +++ b/netlist.h @@ -1613,7 +1613,8 @@ class NetTran : public NetNode, public IslandBranch { public: // Tran devices other than TRAN_VP - NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type); + NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type, + unsigned wid); // Create a TRAN_VP NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off); diff --git a/t-dll.cc b/t-dll.cc index 7ac03ae15..676ae5f27 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -963,7 +963,7 @@ bool dll_target::tran(const NetTran*net) { struct ivl_switch_s*obj = new struct ivl_switch_s; obj->type = net->type(); - obj->width = 0; + obj->width = net->vector_width(); obj->part = 0; obj->offset = 0; obj->name = net->name(); @@ -996,7 +996,6 @@ bool dll_target::tran(const NetTran*net) } if (obj->type == IVL_SW_TRAN_VP) { - obj->width = net->vector_width(); obj->part = net->part_width(); obj->offset= net->part_offset(); } From a433fa3fcd89f60db15aa0e0d5f431fbc54fb129 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 2 Jan 2012 10:19:20 -0800 Subject: [PATCH 06/88] Update the Makefiles to use more override able values. Update the various Makefiles to use override able constants. --- cadpli/Makefile.in | 4 +--- ivlpp/Makefile.in | 2 +- libveriuser/Makefile.in | 2 +- tgt-fpga/Makefile.in | 2 +- tgt-null/Makefile.in | 2 +- tgt-pal/Makefile.in | 2 +- tgt-stub/Makefile.in | 2 +- tgt-verilog/Makefile.in | 2 +- tgt-vhdl/Makefile.in | 2 +- tgt-vlog95/Makefile.in | 2 +- tgt-vvp/Makefile.in | 2 +- vpi/Makefile.in | 4 ++-- vvp/Makefile.in | 2 +- 13 files changed, 14 insertions(+), 16 deletions(-) diff --git a/cadpli/Makefile.in b/cadpli/Makefile.in index 2aa370ea7..24f52ebab 100644 --- a/cadpli/Makefile.in +++ b/cadpli/Makefile.in @@ -47,8 +47,6 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -SHARED = @shared@ - O = cadpli.o all: dep cadpli.vpl $(ALL32) @@ -80,7 +78,7 @@ ifeq (@MINGW32@,yes) endif cadpli.vpl: $O ../vvp/libvpi.a ../libveriuser/libveriuser.o - $(CC) @shared@ -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS) install: all installdirs $(vpidir)/cadpli.vpl diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 62a799e98..9245bf18e 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -69,7 +69,7 @@ Makefile: $(srcdir)/Makefile.in ../config.status ivlpp@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@ -lexor.c: lexor.lex +lexor.c: $(srcdir)/lexor.lex $(LEX) -olexor.c $(srcdir)/lexor.lex install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@ diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index 52154fbbf..dc8bf3f46 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -88,7 +88,7 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status config.h: stamp-config-h libveriuser.o: $O - $(LD) -r -o $@ $O + $(LD) $(LDFLAGS) -r -o $@ $O libveriuser.a: libveriuser.o rm -f $@ diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index db72580a6..a8491da7e 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -83,7 +83,7 @@ else endif fpga.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index c3b2d6f85..8a354ef97 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -78,7 +78,7 @@ else endif null.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/null.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/null.conf $(libdir)/ivl$(suffix)/null-s.conf diff --git a/tgt-pal/Makefile.in b/tgt-pal/Makefile.in index 31f3ce7f3..7ae034a09 100644 --- a/tgt-pal/Makefile.in +++ b/tgt-pal/Makefile.in @@ -77,7 +77,7 @@ else endif pal.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal + $(CC) @shared@ $(LDFLAGS)-o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal install: all installdirs $(libdir)/ivl/pal.tgt diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index a1fa69549..b9df1d927 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -79,7 +79,7 @@ else endif stub.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/stub.tgt \ $(libdir)/ivl$(suffix)/stub.conf $(libdir)/ivl$(suffix)/stub-s.conf diff --git a/tgt-verilog/Makefile.in b/tgt-verilog/Makefile.in index 60f692780..b1ba3d771 100644 --- a/tgt-verilog/Makefile.in +++ b/tgt-verilog/Makefile.in @@ -77,7 +77,7 @@ else endif verilog.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl/verilog.tgt \ $(includedir)/vpi_user.h diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 553edceab..8487fc1ab 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -82,7 +82,7 @@ else endif vhdl.tgt: $O $(TGTDEPLIBS) - $(CXX) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CXX) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status @rm -f $@ diff --git a/tgt-vlog95/Makefile.in b/tgt-vlog95/Makefile.in index cfe1b5973..2c95d9e55 100644 --- a/tgt-vlog95/Makefile.in +++ b/tgt-vlog95/Makefile.in @@ -78,7 +78,7 @@ else endif vlog95.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/vlog95.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/vlog95.conf $(libdir)/ivl$(suffix)/vlog95-s.conf diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 4438c8c62..9edeb32ec 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -85,7 +85,7 @@ else endif vvp.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) vvp.conf: $(srcdir)/vvp.conf.in Makefile echo 'flag:VVP_EXECUTABLE=$(bindir)/vvp$(suffix)' | cat $(srcdir)/vvp.conf.in - > vvp.conf diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 2cdef7762..45dd03fee 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -124,12 +124,12 @@ endif system.vpi: $O $(OPP) ../vvp/libvpi.a $(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) -sys_readmem_lex.c: sys_readmem_lex.lex +sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex $(LEX) -t $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c sdf_lexor.o: sdf_lexor.c sdf_parse.h -sdf_lexor.c: sdf_lexor.lex +sdf_lexor.c: $(srcdir)/sdf_lexor.lex $(LEX) -t $(srcdir)/sdf_lexor.lex > sdf_lexor.c sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 6a7d278e2..beaf67387 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -129,7 +129,7 @@ vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS) else libvpi.a: libvpi.c - $(CC) $(CFLAGS) -c $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< rm -f libvpi.a $(AR) cqv libvpi.a libvpi.o $(RANLIB) libvpi.a From dab982f39b2c33b82d9317fdbfd8d86a3753bbbc Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 2 Jan 2012 11:28:50 -0800 Subject: [PATCH 07/88] vlog95: Major rework of nexus emitting code, etc. Rework the nexus emitting code to correctly translate most I/O ports. Fix a few other expression issues uncovered when port translation was done correctly. Ignore and warn that the SV ++/-- operators and enum types are not translatable. More updates of the nexus debug code. --- tgt-vlog95/event.c | 6 +- tgt-vlog95/expr.c | 67 +++++- tgt-vlog95/logic_lpm.c | 486 +++++++++++++++++++++++++++------------ tgt-vlog95/misc.c | 98 +++++++- tgt-vlog95/numbers.c | 2 + tgt-vlog95/scope.c | 96 +++++++- tgt-vlog95/stmt.c | 8 +- tgt-vlog95/udp.c | 2 +- tgt-vlog95/vlog95.c | 8 +- tgt-vlog95/vlog95_priv.h | 6 +- 10 files changed, 602 insertions(+), 177 deletions(-) diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c index 8454a3727..5af509168 100644 --- a/tgt-vlog95/event.c +++ b/tgt-vlog95/event.c @@ -36,7 +36,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) for (idx = 0; idx < count; idx += 1) { if (first) first = 0; else fprintf(vlog_out, " or "); - emit_name_of_nexus(scope, ivl_event_any(event, idx)); + emit_nexus_as_ca(scope, ivl_event_any(event, idx), 0); } /* Check for positive edge events. */ @@ -46,7 +46,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) if (first) first = 0; else fprintf(vlog_out, " or "); fprintf(vlog_out, "posedge "); - emit_name_of_nexus(scope, ivl_event_pos(event, idx)); + emit_nexus_as_ca(scope, ivl_event_pos(event, idx), 0); } /* Check for negative edge events. */ @@ -56,7 +56,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) if (first) first = 0; else fprintf(vlog_out, " or "); fprintf(vlog_out, "negedge "); - emit_name_of_nexus(scope, ivl_event_neg(event, idx)); + emit_nexus_as_ca(scope, ivl_event_neg(event, idx), 0); } /* We have a named event if there were no edge events. */ diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index f1c22f531..3d32ca023 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -79,7 +79,7 @@ static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { char *oper = ""; - switch(ivl_expr_opcode(expr)) { + switch (ivl_expr_opcode(expr)) { case '+': oper = "+"; break; case '-': oper = "-"; break; case '*': oper = "*"; break; @@ -108,7 +108,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) } fprintf(vlog_out, "("); - switch(ivl_expr_opcode(expr)) { + switch (ivl_expr_opcode(expr)) { case '%': if (ivl_expr_value(expr) == IVL_VT_REAL) { fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator " @@ -427,6 +427,18 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) } else { // HERE: Should this sign extend if the expression is signed? emit_expr(scope, sig_expr, wid); + /* Select part of a signal when needed. */ + if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) && + (ivl_expr_width(expr) < ivl_expr_width(sig_expr))) { + ivl_signal_t sig = ivl_expr_signal(sig_expr); + int msb = ivl_signal_msb(sig); + int lsb = ivl_signal_lsb(sig); + int64_t value = lsb; + unsigned e_wid = ivl_expr_width(expr) - 1; + if (msb >= lsb) value += e_wid; + else value -= e_wid; + fprintf(vlog_out, "[%"PRId64":%u]", value, lsb); + } } } @@ -508,6 +520,46 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) /* A cast is a noop. */ emit_expr(scope, ivl_expr_oper1(expr), wid); break; + case 'I': + fprintf(vlog_out, "(++"); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'i': + fprintf(vlog_out, "("); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, "++)"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'D': + fprintf(vlog_out, "(--"); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'd': + fprintf(vlog_out, "("); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, "--)"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; default: fprintf(vlog_out, ""); emit_expr(scope, ivl_expr_oper1(expr), wid); @@ -516,13 +568,14 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); + vlog_errors += 1; break; } } void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { - switch(ivl_expr_type(expr)) { + switch (ivl_expr_type(expr)) { case IVL_EX_ARRAY: emit_expr_array(scope, expr, wid); break; @@ -535,6 +588,14 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) case IVL_EX_DELAY: emit_expr_delay(scope, expr, wid); break; + case IVL_EX_ENUMTYPE: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Enum expressions " + "are not supported.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; case IVL_EX_EVENT: emit_expr_event(scope, expr, wid); break; diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 2ce8ba45a..4a57e6616 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -157,23 +157,33 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t rise, ivl_expr_t fall, static unsigned is_local_nexus(ivl_scope_t scope, ivl_nexus_t nex) { unsigned idx, count = ivl_nexus_ptrs(nex); - unsigned is_local = 0; + unsigned is_local = 1; + unsigned has_output_driver = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); if (! sig) continue; + /* Check to see if there is an output port driving into + * the local scope. */ + if ((scope == ivl_scope_parent(ivl_signal_scope(sig))) && + (ivl_signal_port(sig) == IVL_SIP_OUTPUT)) { + has_output_driver = 1; + continue; + } if (scope != ivl_signal_scope(sig)) continue; if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; if (ivl_signal_local(sig)) { -// assert(! is_local); is_local = 1; } else { is_local = 0; break; } } - return is_local; + /* We return is_local=true only if there is not an output driving + * into this scope. This is needed since some module outputs are + * combined with a concatenation. */ + return is_local && !has_output_driver; } /* @@ -252,10 +262,30 @@ static void emit_nexus_port_signal(ivl_scope_t scope, ivl_nexus_t nex) } } /* There will not be a signal for an empty port. */ - if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0), 0); else fprintf(vlog_out, "/* Empty */"); } +static ivl_signal_t find_local_signal(ivl_scope_t scope, ivl_nexus_t nex, + unsigned *word) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + ivl_signal_t sig = 0; + *word = 0; + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (!t_sig) continue; + if (ivl_signal_local(t_sig) && + (ivl_signal_port(t_sig) != IVL_SIP_INPUT)) continue; + if (ivl_signal_scope(t_sig) != scope) continue; + assert(! sig); + sig = t_sig; + *word = ivl_nexus_ptr_pin(nex_ptr); + } + return sig; +} + /* * Emit the input port driving expression. */ @@ -264,13 +294,15 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) unsigned idx, count = ivl_nexus_ptrs(nex); ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + unsigned word = 0; + /* Look for the nexus driver. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; @@ -282,29 +314,46 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); - net_logic = t_net_logic; + if (t_nlogic) { + assert(! nlogic); + nlogic = t_nlogic; } if (t_sig) { assert(! sig); sig = t_sig; + word = ivl_nexus_ptr_pin(nex_ptr); } } + /* An LPM is driving the nexus. */ if (lpm) { assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); - emit_lpm_as_ca(scope, lpm); + /* If there is a signal in this scope that is also driven by + * the LPM then use the signal instead. */ + sig = find_local_signal(scope, ivl_lpm_q(lpm), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_lpm_as_ca(scope, lpm); + /* A constant is driving the nexus. */ } else if (net_const) { - assert( !net_logic); + assert( !nlogic); assert(! sig); - emit_const_nexus(scope, net_const); - } else if (net_logic) { + /* If there is a signal in this scope that is also driven by + * the constant then use the signal instead. */ + sig = find_local_signal(scope, ivl_const_nex(net_const), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_const_nexus(scope, net_const); + /* A logic gate is driving the nexus. */ + } else if (nlogic) { assert(! sig); - emit_logic_as_ca(scope, net_logic); + /* If there is a signal in this scope that is also driven by + * the logic then use the signal instead. */ + sig = find_local_signal(scope, ivl_logic_pin(nlogic, 0), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_logic_as_ca(scope, nlogic); + /* A signal is driving the nexus. */ } else if (sig) { - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); /* If there is no driver then look for a single signal that is * driven by this nexus that has the correct scope. This is needed * to translate top level ports. */ @@ -313,7 +362,7 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) } } -void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) +void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD) { /* If there is no nexus then there is nothing to print. */ if (! nex) return; @@ -324,13 +373,14 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) unsigned out_of_scope_drive = 0; ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + unsigned word = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) { @@ -352,23 +402,32 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); - net_logic = t_net_logic; + if (t_nlogic) { + assert(! nlogic); + nlogic = t_nlogic; } if (t_sig) { assert(! sig); sig = t_sig; + word = ivl_nexus_ptr_pin(nex_ptr); } } if (lpm) { assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); assert(! must_be_sig); +// HERE: I think we need special input code like the following. +#if 0 + /* If these is a signal in this scope that is also driven by + * the LPM then use the signal instead. */ + sig = find_local_signal(scope, ivl_lpm_q(lpm), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_lpm_as_ca(scope, lpm); +#endif emit_lpm_as_ca(scope, lpm); } else if (net_const) { - assert( !net_logic); + assert( !nlogic); assert(! sig); assert(! must_be_sig); if (out_of_scope_drive) { @@ -380,14 +439,15 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) // For now report this as missing. fprintf(vlog_out, ""); } else emit_const_nexus(scope, net_const); - } else if (net_logic) { + } else if (nlogic) { assert(! sig); assert(! must_be_sig); - emit_logic_as_ca(scope, net_logic); + emit_logic_as_ca(scope, nlogic); } else if (sig) { +// HERE: should these be allow_UD? if (must_be_sig) { - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); - } else emit_name_of_nexus(scope, nex); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + } else emit_name_of_nexus(scope, nex, 0); // HERE: The assert causes pr1703959 to fail. // } else assert(0); } else { @@ -397,7 +457,7 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) fprintf(vlog_out, ""); } } else { - emit_name_of_nexus(scope, nex); + emit_name_of_nexus(scope, nex, allow_UD); } } @@ -408,61 +468,61 @@ static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic) case IVL_LO_AND: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " & "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_BUF: -// case IVL_LO_BUFT: + case IVL_LO_BUFT: case IVL_LO_BUFZ: assert(inputs == 1); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); break; case IVL_LO_NAND: assert(inputs == 2); fprintf(vlog_out, "~("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " & "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_NOR: assert(inputs == 2); fprintf(vlog_out, "~("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_NOT: assert(inputs == 1); fprintf(vlog_out, "(~ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LO_OR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_XNOR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " ~^ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_XOR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " ^ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; default: @@ -482,7 +542,7 @@ static void emit_lpm_array(ivl_scope_t scope, ivl_lpm_t lpm) emit_id(ivl_signal_basename(sig)); fprintf(vlog_out, "["); // HERE: Need to remove the scale to match array base instead of adding it back. - emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0); fprintf(vlog_out, " + %d]", ivl_signal_array_base(sig)); } @@ -500,56 +560,92 @@ static void emit_lpm_concat(ivl_scope_t scope, ivl_lpm_t lpm) /* If all the nexus match then we have a repeat. */ if ((idx == count) && (count > 1)) { fprintf(vlog_out, "%u{", count); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, "}"); + /* Icarus uses a concat to combine the output from multiple devices + * into a single vector, because of this we need to also look for + * the nexus driver outside the scope. emit_nexus_as_ca( , , 1) */ } else { for (idx = count-1; idx > 0; idx -= 1) { - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx), 1); fprintf(vlog_out, ", "); } - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1); } fprintf(vlog_out, "}"); } +/* + * Look for an output signal in the nexus that is driving into this scope. + */ +static ivl_signal_t find_output_signal(ivl_scope_t scope, ivl_nexus_t nex, + unsigned*array_word) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + /* The signal must not be a driver. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || + (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; + /* The signal must be an output. */ + if (ivl_signal_port(t_sig) != IVL_SIP_OUTPUT) continue; + /* The signal must be driving into this scope. */ + if (ivl_scope_parent(ivl_signal_scope(t_sig)) == scope) { + return t_sig; + } + } + return 0; +} + static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, - int*base, int*array_word) + int*base, unsigned*array_word) { unsigned idx, count = ivl_nexus_ptrs(nex); ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + /* Look for a signal in the local scope first. */ + sig = find_local_signal(scope, nex, array_word); + if (sig) return sig; + /* Now look for an output signal driving into the local scope. */ + sig = find_output_signal(scope, nex, array_word); + if (sig) return sig; + /* Now scan the nexus looking for a driver. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); - if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && - (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; if (t_lpm) { assert(! lpm); /* The real signal could be hidden behind a select. */ if (ivl_lpm_type(t_lpm) == IVL_LPM_PART_VP) { t_sig = nexus_is_signal(scope, ivl_lpm_data(t_lpm, 0), base, array_word); - if (t_sig) *base += ivl_lpm_base(t_lpm); - } else lpm = t_lpm; + } + + if (t_sig) *base += ivl_lpm_base(t_lpm); + else lpm = t_lpm; } if (t_net_const) { assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); + if (t_nlogic) { + assert(! nlogic); /* The real signal could be hidden behind a BUFZ gate. */ - if (ivl_logic_type(t_net_logic) == IVL_LO_BUFZ) { - assert(ivl_logic_pins(t_net_logic) == 2); + if (ivl_logic_type(t_nlogic) == IVL_LO_BUFZ) { + assert(ivl_logic_pins(t_nlogic) == 2); t_sig = nexus_is_signal(scope, - ivl_logic_pin(t_net_logic, 1), + ivl_logic_pin(t_nlogic, 1), base, array_word); - } else net_logic = t_net_logic; + } else nlogic = t_nlogic; } if (t_sig) { assert(! sig); @@ -558,18 +654,13 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, *array_word = ivl_nexus_ptr_pin(nex_ptr); } } - if (sig) { - assert(! lpm); - assert(! net_const); - assert(! net_logic); - } return sig; } static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) { unsigned width = ivl_lpm_width(lpm); - int array_word = 0; + unsigned array_word = 0; int base = ivl_lpm_base(lpm); int msb, lsb; ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0), @@ -587,7 +678,7 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) /* Check if the compiler used a select for a shift. */ assert(base >= 0); if (base) fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); if (base) { fprintf(vlog_out, " "); if (sign_extend) fprintf(vlog_out, ">"); @@ -598,6 +689,7 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) } if (sign_extend) fprintf(vlog_out, "("); + emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); if (ivl_signal_dimensions(sig)) { array_word += ivl_signal_array_base(sig); @@ -615,13 +707,13 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) return; } - fprintf(vlog_out, "["); if (width == 1) { ivl_nexus_t sel = ivl_lpm_data(lpm, 1); if (sel) { + fprintf(vlog_out, "["); // HERE: Need to scale the select nexus. if ((msb >= lsb) && (lsb == 0)) { - emit_nexus_as_ca(scope, sel); + emit_nexus_as_ca(scope, sel, 0); } else { fprintf(stderr, "%s:%u: vlog95 sorry: Non-zero based " "variable part selects are not " @@ -631,11 +723,15 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) fprintf(vlog_out, ""); } } else { + /* Skip a select of the entire bit. */ + if ((msb == lsb) && (lsb == base)) return; + fprintf(vlog_out, "["); if (msb >= lsb) base += lsb; else base = lsb - base; fprintf(vlog_out, "%d", base); } } else { + fprintf(vlog_out, "["); // HERE: No support for an indexed part select. ivl_nexus_t sel = ivl_lpm_data(lpm, 1); if (sel) { @@ -666,10 +762,10 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm) count -= 1; fprintf(vlog_out, "("); for (idx = 0; idx < count; idx += 1) { - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx), 0); fprintf(vlog_out, ", "); } - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, count)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, count), 0); fprintf(vlog_out, ")"); } } @@ -679,9 +775,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " + "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_ARRAY: @@ -690,48 +786,48 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_CAST_INT: case IVL_LPM_CAST_INT2: case IVL_LPM_CAST_REAL: - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); break; case IVL_LPM_CMP_EEQ: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " === "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_EQ: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " == "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " >= "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GT: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " > "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " != "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NEE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " !== "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CONCAT: @@ -739,9 +835,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) break; case IVL_LPM_DIVIDE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " / "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MOD: @@ -753,66 +849,66 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) vlog_errors += 1; } fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " %% "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MULT: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " * "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MUX: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0); fprintf(vlog_out, " ? "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, " : "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_PART_PV: - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1); break; case IVL_LPM_PART_VP: emit_lpm_part_select(scope, lpm); break; case IVL_LPM_RE_AND: fprintf(vlog_out, "(&"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NAND: fprintf(vlog_out, "(~&"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NOR: fprintf(vlog_out, "(~|"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_OR: fprintf(vlog_out, "(|"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XOR: fprintf(vlog_out, "(^"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XNOR: fprintf(vlog_out, "(~^"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_REPEAT: fprintf(vlog_out, "{%u{", ivl_lpm_size(lpm)); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, "}}"); break; case IVL_LPM_SFUNC: @@ -821,30 +917,30 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) break; case IVL_LPM_SHIFTL: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " << "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_SHIFTR: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " "); assert(! sign_extend); fprintf(vlog_out, " >> "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_SIGN_EXT: // assert(! sign_extend); sign_extend = 1; - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); break; case IVL_LPM_SUB: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " - "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_UFUNC: @@ -980,29 +1076,29 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) } fprintf(vlog_out, " ("); /* Emit the q pin. */ - emit_name_of_nexus(scope, ivl_lpm_q(lpm)); + emit_name_of_nexus(scope, ivl_lpm_q(lpm), 0); fprintf(vlog_out, ", "); /* Emit the clock pin. */ - emit_nexus_as_ca(scope, ivl_lpm_clk(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_clk(lpm), 0); fprintf(vlog_out, ", "); /* Emit the enable pin expression(s) if needed. */ emitted = 0; nex = ivl_lpm_enable(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } nex = ivl_lpm_sync_clr(lpm); if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } have_sset = 0; nex = ivl_lpm_sync_set(lpm); if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; have_sset = 1; } @@ -1012,37 +1108,37 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) have_data = ivl_lpm_data(lpm, 0) != 0; nex = ivl_lpm_sync_clr(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data | have_sset) fprintf(vlog_out, " & "); if (have_data & have_sset) fprintf(vlog_out, "("); } nex = ivl_lpm_sync_set(lpm); if (nex) { if (! sset_bits || (sset_bits && (sset_bits[0] == '1'))) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data) fprintf(vlog_out, " | "); } else { fprintf(vlog_out, "~"); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data) fprintf(vlog_out, " & "); } } nex = ivl_lpm_data(lpm, 0); - if (nex) emit_nexus_as_ca(scope, nex); + if (nex) emit_nexus_as_ca(scope, nex, 0); if (have_data & have_sset) fprintf(vlog_out, ")"); fprintf(vlog_out, ", "); /* Emit the clear pin expression(s) if needed. */ emitted = 0; nex = ivl_lpm_async_clr(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } nex = ivl_lpm_async_set(lpm); if (aset_bits && (aset_bits[0] != '0')) nex = 0; if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } if (!emitted) fprintf(vlog_out, "1'b0"); @@ -1050,7 +1146,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) /* Emit the set pin expression(s) if needed. */ nex = ivl_lpm_async_set(lpm); if (aset_bits && (aset_bits[0] != '1')) nex = 0; - if (nex) emit_nexus_as_ca(scope, nex); + if (nex) emit_nexus_as_ca(scope, nex, 0); else fprintf(vlog_out, "1'b0"); fprintf(vlog_out, ");\n"); /* We need to emit a primitive for this instance. */ @@ -1145,6 +1241,31 @@ static void emit_lpm_part_pv(ivl_scope_t scope, ivl_lpm_t lpm) fprintf(vlog_out, "]"); } +unsigned output_is_module_instantiation_input(ivl_scope_t scope, + ivl_nexus_t nex) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + unsigned rtn = 0; + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + /* Skip drivers. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || + (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + /* If the nexus is driving other things or signals that are + * not a module instantiation input then return false. */ +// HERE: debug this to see if the output can drive other things local to the +// module that is being called. +// if (! t_sig) return 0; + if (! t_sig) continue; + if (ivl_signal_port(t_sig) != IVL_SIP_INPUT) return 0; + if (ivl_scope_parent(ivl_signal_scope(t_sig)) != scope) return 0; + if (rtn) return 0; + rtn = 1; + } + return rtn; +} + void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) { ivl_nexus_t output = get_lpm_output(scope, lpm); @@ -1156,6 +1277,9 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) emit_lpm_ff(scope, lpm); return; } +// HERE: Look for a select passed to a pull device (pr2019553). + /* Skip assignments to a module instantiation input. */ + if (output_is_module_instantiation_input(scope, output)) return; fprintf(vlog_out, "%*cassign", indent, ' '); emit_lpm_strength(lpm); emit_delay(scope, @@ -1165,7 +1289,7 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) 3); fprintf(vlog_out, " "); if (type == IVL_LPM_PART_PV) emit_lpm_part_pv(scope, lpm); - else emit_name_of_nexus(scope, output); + else emit_name_of_nexus(scope, output, 0); fprintf(vlog_out, " = "); emit_lpm_as_ca(scope, lpm); fprintf(vlog_out, ";"); @@ -1200,9 +1324,9 @@ static void emit_bufz(ivl_scope_t scope, ivl_net_logic_t nlogic) ivl_logic_delay(nlogic, 2), 3); fprintf(vlog_out, " "); - emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0)); + emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0), 0); fprintf(vlog_out, " = "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, ";"); emit_logic_file_line(nlogic); fprintf(vlog_out, "\n"); @@ -1219,7 +1343,7 @@ static void emit_name_of_logic_nexus(ivl_scope_t scope, ivl_net_logic_t nlogic, ivl_nexus_t nex) { if (nex) { - emit_name_of_nexus(scope, nex); + emit_name_of_nexus(scope, nex, 0); } else { if (ivl_logic_type(nlogic) != IVL_LO_UDP) { fprintf(stderr, "%s:%u: vlog95 warning: Missing logic pin " @@ -1242,7 +1366,6 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) // short circuit. Verify input count. unsigned idx, count, dly_count, strength_type = 2; unsigned outputs = 1; - unsigned width = ivl_logic_width(nlogic); const char *name; /* Skip gates that have a local nexus as the output since they are * part of a continuous assignment. */ @@ -1262,7 +1385,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) ivl_logic_delay(nlogic, 2), 3); fprintf(vlog_out, " "); - emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0)); + emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0), 0); fprintf(vlog_out, " = "); emit_logic_as_ca(scope, nlogic); fprintf(vlog_out, ";"); @@ -1390,6 +1513,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) if (name && *name) { char *fixed_name = strdup(name); unsigned lp = strlen(name) - 1; + unsigned width = ivl_logic_width(nlogic); if (fixed_name[lp] == '>') { while (fixed_name[lp] != '<') { assert(lp > 0); @@ -1413,11 +1537,11 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) fprintf(vlog_out, ", "); } for (/* None */; idx < count; idx += 1) { - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx), 0); fprintf(vlog_out, ", "); } if (strength_type == 2) { - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx), 0); } else { /* A pull gate only has a single output connection. */ assert(count == 0); @@ -1431,6 +1555,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) void emit_tran(ivl_scope_t scope, ivl_switch_t tran) { unsigned dly_count, pins; + const char *name; fprintf(vlog_out, "%*c", indent, ' '); switch (ivl_switch_type(tran)) { case IVL_SW_RTRAN: @@ -1482,14 +1607,32 @@ void emit_tran(ivl_scope_t scope, ivl_switch_t tran) dly_count); assert(pins == 2 || pins == 3); // The same problem here as for the gates above. -// fprintf(vlog_out, " %s(", ivl_switch_basename(tran)); + name = ivl_switch_basename(tran); + if (name && *name) { + char *fixed_name = strdup(name); + unsigned lp = strlen(name) - 1; + unsigned width = ivl_switch_width(tran); + if (fixed_name[lp] == '>') { + while (fixed_name[lp] != '<') { + assert(lp > 0); + lp -= 1; + } + fixed_name[lp] = 0; + } + fprintf(vlog_out, " "); + emit_id(fixed_name); + free(fixed_name); + if (width > 1) { + fprintf(vlog_out, " [%u:0]", width-1); + } + } fprintf(vlog_out, " ("); - emit_name_of_nexus(scope, ivl_switch_a(tran)); + emit_name_of_nexus(scope, ivl_switch_a(tran), 0); fprintf(vlog_out, ", "); - emit_name_of_nexus(scope, ivl_switch_b(tran)); + emit_name_of_nexus(scope, ivl_switch_b(tran), 0); if (pins == 3) { fprintf(vlog_out, ", "); - emit_nexus_as_ca(scope, ivl_switch_enable(tran)); + emit_nexus_as_ca(scope, ivl_switch_enable(tran), 0); } fprintf(vlog_out, ");"); if (emit_file_line) { @@ -1561,14 +1704,16 @@ static void dump_drive(ivl_drive_t drive) */ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) { - unsigned idx, count = ivl_nexus_ptrs(nex); - fprintf(stderr, "Dumping nexus from scope: %s\n", + unsigned idx, count; + if ((scope == 0) || (nex == 0)) return; + count = ivl_nexus_ptrs(nex); + fprintf(stderr, "Dumping nexus %p from scope: %s\n", nex, ivl_scope_name(scope)); for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); fprintf(stderr, " %u (", idx); dump_drive(ivl_nexus_ptr_drive1(nex_ptr)); @@ -1578,12 +1723,12 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) if (lpm) { ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); fprintf(stderr, "LPM: "); - fprintf(stderr, "%s:%d ", ivl_lpm_file(lpm), + fprintf(stderr, "{%s:%d} ", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); - if (scope != lpm_scope) fprintf(stderr, "%s ", + if (scope != lpm_scope) fprintf(stderr, "(%s) ", ivl_scope_name(lpm_scope)); switch (ivl_lpm_type(lpm)) { case IVL_LPM_ABS: fprintf(stderr, "abs"); break; @@ -1604,7 +1749,9 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_LPM_MOD: fprintf(stderr, "mod"); break; case IVL_LPM_MULT: fprintf(stderr, "mult"); break; case IVL_LPM_MUX: fprintf(stderr, "mux"); break; - case IVL_LPM_PART_VP: fprintf(stderr, "part-VP"); break; + case IVL_LPM_PART_VP: fprintf(stderr, "part-VP"); + fprintf(stderr, "(%u+%u)", ivl_lpm_base(lpm), + ivl_lpm_width(lpm)); break; case IVL_LPM_PART_PV: fprintf(stderr, "part-PV"); break; case IVL_LPM_POW: fprintf(stderr, "pow"); break; case IVL_LPM_RE_AND: fprintf(stderr, "R-AND"); break; @@ -1620,22 +1767,69 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_LPM_SIGN_EXT: fprintf(stderr, "sign"); break; case IVL_LPM_SUB: fprintf(stderr, "sub"); break; case IVL_LPM_UFUNC: fprintf(stderr, "U-func"); break; + default: fprintf(stderr, "<%d>", ivl_lpm_type(lpm)); } } else if (net_const) { - assert(! net_logic); + ivl_scope_t const_scope = ivl_const_scope(net_const); + assert(! nlogic); assert(! sig); fprintf(stderr, "Const: "); - } else if (net_logic) { + if (scope != const_scope) fprintf(stderr, "(%s) ", + ivl_scope_name(const_scope)); + } else if (nlogic) { + ivl_scope_t logic_scope = ivl_logic_scope(nlogic); assert(! sig); fprintf(stderr, "Logic: "); + fprintf(stderr, "{%s:%d} ", ivl_logic_file(nlogic), + ivl_logic_lineno(nlogic)); + if (scope != logic_scope) fprintf(stderr, "(%s) ", + ivl_scope_name(logic_scope)); + switch (ivl_logic_type(nlogic)) { + case IVL_LO_AND: fprintf(stderr, "and"); break; + case IVL_LO_BUF: fprintf(stderr, "buf"); break; + case IVL_LO_BUFIF0: fprintf(stderr, "bufif0"); break; + case IVL_LO_BUFIF1: fprintf(stderr, "bufif1"); break; + case IVL_LO_BUFT: fprintf(stderr, "buft"); break; + case IVL_LO_BUFZ: fprintf(stderr, "bufz"); break; + case IVL_LO_CMOS: fprintf(stderr, "cmos"); break; + case IVL_LO_NAND: fprintf(stderr, "nand"); break; + case IVL_LO_NMOS: fprintf(stderr, "nmos"); break; + case IVL_LO_NOR: fprintf(stderr, "nor"); break; + case IVL_LO_NOT: fprintf(stderr, "not"); break; + case IVL_LO_NOTIF0: fprintf(stderr, "notif0"); break; + case IVL_LO_NOTIF1: fprintf(stderr, "notif1"); break; + case IVL_LO_OR: fprintf(stderr, "or"); break; + case IVL_LO_PMOS: fprintf(stderr, "pmos"); break; + case IVL_LO_PULLDOWN: fprintf(stderr, "pulldown"); break; + case IVL_LO_PULLUP: fprintf(stderr, "pullup"); break; + case IVL_LO_RCMOS: fprintf(stderr, "rcmos"); break; + case IVL_LO_RNMOS: fprintf(stderr, "rnmos"); break; + case IVL_LO_RPMOS: fprintf(stderr, "rpmos"); break; + case IVL_LO_UDP: { + ivl_udp_t udp = ivl_logic_udp(nlogic); + assert(udp); + fprintf(stderr, "UDP %s", ivl_udp_name(udp)); + break; + } + case IVL_LO_XNOR: fprintf(stderr, "xnor"); break; + case IVL_LO_XOR: fprintf(stderr, "xor"); break; + default: fprintf(stderr, "<%d>", ivl_logic_type(nlogic)); + } + fprintf(stderr, "(%u inputs)", ivl_logic_pins(nlogic) - 1); } else if (sig) { ivl_scope_t sig_scope = ivl_signal_scope(sig); - fprintf(stderr, "Signal: "); + fprintf(stderr, "Signal: \""); if (scope != sig_scope) fprintf(stderr, "%s.", ivl_scope_name(sig_scope)); fprintf(stderr, "%s", ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig) > 0) { + fprintf(stderr, "[]"); + } + fprintf(stderr, "\""); // HERE: Do we need to add support for an array word or is that an LPM. - if (ivl_signal_local(sig)) fprintf(stderr, " (local)"); + if (ivl_signal_local(sig)) fprintf(stderr, " {local}"); + else fprintf(stderr, " {%s:%d}", ivl_signal_file(sig), + ivl_signal_lineno(sig)); switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: fprintf(stderr, " input"); break; case IVL_SIP_OUTPUT: fprintf(stderr, " output"); break; diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index e23294770..0f83ec7ae 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -70,7 +70,7 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt) ivl_signal_t sig = ivl_expr_signal(expr); if (ivl_signal_local(sig)) { assert(! is_stmt); - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0), 0); return; } } @@ -412,9 +412,8 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex) unsigned is_driver = 0; unsigned is_array = 0; int64_t array_idx = 0; - unsigned idx, count; + unsigned idx, count = ivl_nexus_ptrs(nex); - count = ivl_nexus_ptrs(nex); for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); @@ -501,7 +500,7 @@ static void emit_number_as_string(ivl_net_const_t net_const) /* Skip any NULL bytes. */ if (val == 0) continue; - /* Print some values that must be escapped. */ + /* Print some values that must be escaped. */ if (val == '"') fprintf(vlog_out, "\\\""); else if (val == '\\') fprintf(vlog_out, "\\\\"); /* Print the printable characters. */ @@ -616,8 +615,84 @@ static unsigned find_const_nexus(ivl_scope_t scope, ivl_nexus_t nex) return 0; } +static unsigned find_driving_signal(ivl_scope_t scope, ivl_nexus_t nex) +{ + ivl_signal_t sig = 0; + unsigned is_array = 0; + int64_t array_idx = 0; + unsigned idx, count = ivl_nexus_ptrs(nex); + + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + if (ivl_signal_local(t_sig)) continue; + /* An output can be used if it is driven by this nexus. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ) && + (ivl_signal_port(t_sig) != IVL_SIP_OUTPUT)) { + continue; + } + /* We have a signal that can be used to find the name. */ + if (sig) { +// HERE: Which one should we use? For now it's the first one found. +// I believe this needs to be solved (see above). + fprintf(stderr, "%s:%u: vlog95 warning: Duplicate name (%s", + ivl_signal_file(t_sig), ivl_signal_lineno(t_sig), + ivl_signal_basename(t_sig)); + if (ivl_signal_dimensions(t_sig) > 0) { + int64_t tmp_idx = ivl_nexus_ptr_pin(nex_ptr); + tmp_idx += ivl_signal_array_base(t_sig); + fprintf(stderr, "[%"PRId64"]", tmp_idx); + } + fprintf(stderr, ") found for nexus (%s", + ivl_signal_basename(sig)); + if (is_array) fprintf(stderr, "[%"PRId64"]", array_idx); + fprintf(stderr, ")\n"); + } else { + sig = t_sig; + if (ivl_signal_dimensions(sig) > 0) { + is_array = 1; + array_idx = ivl_nexus_ptr_pin(nex_ptr); + array_idx += ivl_signal_array_base(sig); + } + } + } + + if (sig) { + emit_scope_call_path(scope, ivl_signal_scope(sig)); + emit_id(ivl_signal_basename(sig)); + if (is_array) fprintf(vlog_out, "[%"PRId64"]", array_idx); + return 1; + } + + return 0; +} + +static unsigned is_local_input(ivl_scope_t scope, ivl_nexus_t nex) +{ + ivl_signal_t sig = 0; + unsigned idx, count = ivl_nexus_ptrs(nex); + + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + if (! ivl_signal_local(t_sig)) continue; + if (ivl_signal_port(t_sig) != IVL_SIP_INPUT) continue; + assert(! sig); + assert(ivl_signal_dimensions(t_sig) == 0); + sig = t_sig; + } + if (sig) { + fprintf(vlog_out, "ivlog%s", ivl_signal_basename(sig)); + return 1; + } + return 0; +} + // HERE: Does this work correctly with an array reference created from @*? -void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) +void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD) { ivl_scope_t mod_scope; /* First look in the local scope for the nexus name. */ @@ -630,9 +705,16 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) if (find_signal_in_nexus(mod_scope, nex)) return; } + /* Look to see if this is a up/down reference. */ + if (allow_UD && find_driving_signal(scope, nex)) return; + /* If there is no signals driving this then look for a constant. */ if (find_const_nexus(scope, nex)) return; + /* Module inputs that are split (arg[7:4], arg[3:0]) need to use + * the local signal names. */ + if (is_local_input(scope, nex)) return; + // HERE: Need to check arr[var]? Can this be rebuilt? // Then look for down scopes and then any scope. For all this warn if // multiples are found in a given scope. This all needs to be before @@ -641,7 +723,7 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) /* It is possible that the nexus does not have a name. For this * case do not print an actual name. */ fprintf(vlog_out, "/* Empty */"); - dump_nexus_information(scope, nex); +// dump_nexus_information(scope, nex); } /* @@ -758,6 +840,10 @@ static unsigned is_escaped(const char *id) return 1; } } + /* Any Verilog keyword should also be escaped. */ +// HERE: Create a keyword.gperf file to do this check. + if ((strcmp(id, "input") == 0) || + (strcmp(id, "output") == 0) ) return 1; /* We looked at all the digits, so this is a normal id. */ return 0; } diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index 2dd1bc1af..9a769c7a7 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -61,6 +61,8 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits, } } /* Sign extend as needed. */ +// HERE: Need to emit 1 instead of -1 for some of the constants. +// if (is_signed && (nbits > 1) && (msb == '1') && (trim_wid < 32U)) { if (is_signed && (msb == '1') && (trim_wid < 32U)) { value |= ~(((int32_t)1 << trim_wid) - (int32_t)1); } diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 767281111..a3bc6b34e 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -204,7 +204,7 @@ void emit_net_def(ivl_scope_t scope, ivl_signal_t sig) ivl_signal_lineno(sig), ivl_signal_basename(sig)); vlog_errors += 1; } else { - switch(ivl_signal_type(sig)) { + switch (ivl_signal_type(sig)) { case IVL_SIT_TRI: case IVL_SIT_UWIRE: // HERE: Need to add support for supply nets. Probably supply strength @@ -363,19 +363,21 @@ static void emit_module_ports(ivl_scope_t scope) if (count == 0) return; fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0)); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0), 0); for (idx = 1; idx < count; idx += 1) { fprintf(vlog_out, ", "); - emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx)); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx), 0); } fprintf(vlog_out, ")"); } -static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex) +static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, + unsigned *word) { assert(nex); unsigned idx, count = ivl_nexus_ptrs(nex); ivl_signal_t sig = 0; + *word = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); @@ -383,6 +385,7 @@ static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex) if (ivl_signal_scope(t_sig) != scope) continue; assert(! sig); sig = t_sig; + *word = ivl_nexus_ptr_pin(nex_ptr); } } return sig; @@ -475,7 +478,12 @@ static void emit_port(ivl_signal_t port) } emit_sig_type(port); fprintf(vlog_out, " "); - emit_id(ivl_signal_basename(port)); + /* Split port (arg[7:4],arg[3:0]) are generated using local signals. */ + if (ivl_signal_local(port)) { + fprintf(vlog_out, "ivlog%s", ivl_signal_basename(port)); + } else { + emit_id(ivl_signal_basename(port)); + } fprintf(vlog_out, ";"); emit_sig_file_line(port); fprintf(vlog_out, "\n"); @@ -483,10 +491,11 @@ static void emit_port(ivl_signal_t port) static void emit_module_port_defs(ivl_scope_t scope) { - unsigned idx, count = ivl_scope_ports(scope); + unsigned word, idx, count = ivl_scope_ports(scope); for (idx = 0; idx < count; idx += 1) { ivl_nexus_t nex = ivl_scope_mod_port(scope, idx); - ivl_signal_t port = get_port_from_nexus(scope, nex); + ivl_signal_t port = get_port_from_nexus(scope, nex, &word); +// HERE: Do we need to use word? if (port) emit_port(port); else { fprintf(vlog_out, ""); @@ -502,15 +511,17 @@ static void emit_module_port_defs(ivl_scope_t scope) static void emit_module_call_expr(ivl_scope_t scope, unsigned idx) { + unsigned word; ivl_nexus_t nex = ivl_scope_mod_port(scope, idx); - ivl_signal_t port = get_port_from_nexus(scope, nex); + ivl_signal_t port = get_port_from_nexus(scope, nex, &word); /* For an input port we need to emit the driving expression. */ if (ivl_signal_port(port) == IVL_SIP_INPUT) { emit_nexus_port_driver_as_ca(ivl_scope_parent(scope), - ivl_signal_nex(port, 0)); + ivl_signal_nex(port, word)); /* For an output we need to emit the signal the output is driving. */ } else { - emit_nexus_as_ca(ivl_scope_parent(scope), ivl_signal_nex(port, 0)); + emit_nexus_as_ca(ivl_scope_parent(scope), + ivl_signal_nex(port, word), 0); } } @@ -536,6 +547,70 @@ static void emit_task_func_port_defs(ivl_scope_t scope) if (count) fprintf(vlog_out, "\n"); } +/* + * Look at all the processes to see if we can find one with the expected + * scope. If we don't find one then we can assume the block only has + * variable definitions and needs to be emitted here in the scope code. + */ +static int no_stmts_in_process(ivl_process_t proc, ivl_scope_t scope) +{ + ivl_statement_t stmt = ivl_process_stmt(proc); + switch (ivl_statement_type(stmt)) { + case IVL_ST_BLOCK: + case IVL_ST_FORK: + if (ivl_stmt_block_scope(stmt) == scope) return 1; + default: /* Do nothing. */ ; + } + return 0; +} + +/* + * If a named block has no statements then we may need to emit it here if + * there are variable definitions in the scope. We translate all this to + * an initial and named begin since that is enough to hold the variables. + */ +static void emit_named_block_scope(ivl_scope_t scope) +{ + unsigned idx, count = ivl_scope_events(scope); + unsigned named_ev = 0; + + /* If there are no parameters, signals or named events then skip + * this block. */ + for (idx = 0; idx < count; idx += 1) { + ivl_event_t event = ivl_scope_event(scope, idx); + /* If this event has any type of edge sensitivity then it is + * not a named event. */ + if (ivl_event_nany(event)) continue; + if (ivl_event_npos(event)) continue; + if (ivl_event_nneg(event)) continue; + named_ev = 1; + break; + } + if ((ivl_scope_params(scope) == 0) && (ivl_scope_sigs(scope) == 0) && + (named_ev == 0)) return; + /* Currently we only need to emit a named block for the variables + * if the parent scope is a module. This gets much more complicated + * if this is not true. */ + if (ivl_scope_type(ivl_scope_parent(scope)) != IVL_SCT_MODULE) return; + /* Scan all the processes looking for one that matches this scope. + * If a match is found then this named block was already emitted by + * the process code. */ + if (ivl_design_process(design, (ivl_process_f)no_stmts_in_process, + scope)) return; + /* A match was not found so emit the named block here to get the + * variable definitions. */ + fprintf(vlog_out, "\n%*cinitial begin: ", indent, ' '); + emit_id(ivl_scope_tname(scope)); + emit_scope_file_line(scope); + fprintf(vlog_out, "\n"); + indent += indent_incr; + emit_scope_variables(scope); + indent -= indent_incr; + fprintf(vlog_out, "%*cend /* ", indent, ' '); + emit_id(ivl_scope_tname(scope)); + fprintf(vlog_out, " */\n"); +} + /* * This search method may be slow for a large structural design with a * large number of gate types. That's not what this converter was built @@ -652,6 +727,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) case IVL_SCT_BEGIN: case IVL_SCT_FORK: assert(indent != 0); + emit_named_block_scope(scope); return 0; /* A named begin/fork is handled in line. */ default: fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type " diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 96eac0654..31ee451a5 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -780,7 +780,7 @@ static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt) { char *case_type; unsigned idx, default_case, count = ivl_stmt_case_count(stmt); - switch(ivl_statement_type(stmt)) { + switch (ivl_statement_type(stmt)) { case IVL_ST_CASE: case IVL_ST_CASER: case_type = "case"; @@ -1047,7 +1047,7 @@ static void emit_stmt_while(ivl_scope_t scope, ivl_statement_t stmt) void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) { - switch(ivl_statement_type(stmt)) { + switch (ivl_statement_type(stmt)) { case IVL_ST_NOOP: /* If this is a statement termination then just finish the * statement, otherwise print an empty begin/end pair. */ @@ -1159,7 +1159,8 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) void emit_process(ivl_scope_t scope, ivl_process_t proc) { - ivl_statement_t stmt; + ivl_statement_t stmt = ivl_process_stmt(proc); + if (ivl_statement_type(stmt) == IVL_ST_NOOP) return; fprintf(vlog_out, "\n%*c", get_indent(), ' '); switch (ivl_process_type(proc)) { case IVL_PR_INITIAL: @@ -1181,7 +1182,6 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc) ivl_process_file(proc), ivl_process_lineno(proc)); } - stmt = ivl_process_stmt(proc); if (ivl_statement_type(stmt) == IVL_ST_NOOP) { fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' '); } else { diff --git a/tgt-vlog95/udp.c b/tgt-vlog95/udp.c index 34feb356d..b33fe0752 100644 --- a/tgt-vlog95/udp.c +++ b/tgt-vlog95/udp.c @@ -25,7 +25,7 @@ static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun) { const char *value = 0; - switch(entry) { + switch (entry) { case '0': value = " 0 "; break; diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index 0266529a2..be00636f5 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ static const char*version_string = "Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n" -"Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com)\n\n" +"Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)\n\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" @@ -195,6 +195,10 @@ int target_design(ivl_design_t des) fclose(vlog_out); + /* A do nothing call to prevent warnings about this routine not + * being used. */ + dump_nexus_information(0, 0); + return vlog_errors; } diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 492057491..12ce11cc0 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -85,8 +85,10 @@ extern void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_scope_variables(ivl_scope_t scope); extern void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope); -extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex); -extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex); +extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, + unsigned allow_UD); +extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, + unsigned allow_UD); extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); From 7f4246a9164e26edcccbd3f5f45b023f0d612e7a Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 3 Jan 2012 16:12:56 -0800 Subject: [PATCH 08/88] Fix tgt-fpga Makefile target --- tgt-fpga/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index a8491da7e..7aa2e1f14 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -65,7 +65,7 @@ cppcheck: $(O:.o=.c) cppcheck --enable=all -f $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status - cd ..; ./config.status --file=tgt-fpga$@ + cd ..; ./config.status --file=tgt-fpga/$@ dep: mkdir dep From f22b42c2cdade6e02b4d4d4c9434723841b6f333 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 3 Jan 2012 16:33:23 -0800 Subject: [PATCH 09/88] Update tgt-pcb Makefile to handle/clean up config header This change matches what is in other header files. --- tgt-pcb/Makefile.in | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index f8e8d16a0..9178dcca6 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -56,6 +56,7 @@ clean: distclean: clean rm -f Makefile config.log + rm -f stamp-pcb_config-h pcb_config.h cppcheck: $(O:.o=.c) cppcheck --enable=all -f $(INCLUDE_PATH) $^ @@ -66,6 +67,11 @@ Makefile: $(srcdir)/Makefile.in ../config.status dep: mkdir dep +stamp-pcb_config-h: $(srcdir)/pcb_config.h.in ../config.status + @rm -f $@ + cd ..; ./config.status --header=tgt-pcb/pcb_config.h +pcb_config.h: stamp-pcb_config-h + %.o: %.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o mv $*.d dep From 9c99bce054c67c59435f2ef0e5dfc6698bebe2dc Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 4 Jan 2012 17:59:41 -0800 Subject: [PATCH 10/88] Update lex/yacc builds to be consistent and to support parallel builds Not all the lex/yacc (flex/bison) targets were using a consistent syntax. This patch fixes that and explicitly serializes the *.c/*.cc and *.h build. Not doing this was causing problem when using make -j. The issue appears to be that if two targets are specified for a rule (e.g. file.cc file.h: file.y) make does not realize they are both built by the same call so the rule is executed twice. Once for the .cc target and once for the .h target. This is not a problem for a serial build. To work around this only use the .c/.cc file in the main target and then make the .h file depend on the .c/.cc file as a sub-target. --- Makefile.in | 16 +++++++++------- driver/Makefile.in | 10 ++++++---- ivlpp/Makefile.in | 2 +- vhdlpp/Makefile.in | 8 +++++--- vpi/Makefile.in | 18 +++++++++++------- vvp/Makefile.in | 6 +++--- 6 files changed, 35 insertions(+), 25 deletions(-) diff --git a/Makefile.in b/Makefile.in index cac099f67..3abafbe55 100644 --- a/Makefile.in +++ b/Makefile.in @@ -150,8 +150,8 @@ endif clean: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true rm -f *.o parse.cc parse.h lexor.cc - rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps parse.output - rm -f syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp + rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps + rm -f parse.output syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc rm -rf dep rm -f version.exe @@ -244,15 +244,17 @@ lexor.o: lexor.cc parse.h parse.o: parse.cc -parse.cc parse.h: $(srcdir)/parse.y - $(YACC) --verbose -t -p VL -d -o parse.cc $(srcdir)/parse.y - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h +# Build this in two steps to avoid parallel build issues (see pr3462585) +parse.cc: $(srcdir)/parse.y + $(YACC) --verbose -t -p VL -d -o $@ $< +parse.h: parse.cc + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ syn-rules.cc: $(srcdir)/syn-rules.y - $(YACC) --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y + $(YACC) --verbose -t -p syn_ -o $@ $< lexor.cc: $(srcdir)/lexor.lex - $(LEX) -s -olexor.cc $(srcdir)/lexor.lex + $(LEX) -s -t $< > $@ lexor_keyword.o: lexor_keyword.cc parse.h diff --git a/driver/Makefile.in b/driver/Makefile.in index 7a1930bb9..c6f3e4922 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -79,11 +79,13 @@ dep: iverilog@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@ @EXTRALIBS@ -cflexor.c: cflexor.lex - $(LEX) -s -ocflexor.c $(srcdir)/cflexor.lex +cflexor.c: $(srcdir)/cflexor.lex + $(LEX) -s -t $< > $@ -cfparse.h cfparse.c: cfparse.y - $(YACC) --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y +# Build this in two steps to avoid parallel build issues (see pr3462585) +cfparse.c: $(srcdir)/cfparse.y + $(YACC) --verbose -t -p cf -d -o $@ $< +cfparse.h: cfparse.c %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 9245bf18e..226d5fb51 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -70,7 +70,7 @@ ivlpp@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@ lexor.c: $(srcdir)/lexor.lex - $(LEX) -olexor.c $(srcdir)/lexor.lex + $(LEX) -s -t $< > $@ install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@ diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index 92b159fb6..b7c9115c8 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -110,9 +110,11 @@ parse.o: parse.cc lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -olexor.cc $(srcdir)/lexor.lex -parse.cc parse.h: $(srcdir)/parse.y - $(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h +# Build this in two steps to avoid parallel build issues (see pr3462585) +parse.cc: $(srcdir)/parse.y + $(YACC) --verbose -t -d -o $@ $< +parse.h: parse.cc + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ lexor_keyword.o: lexor_keyword.cc parse.h diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 45dd03fee..7ce19bd14 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -125,23 +125,27 @@ system.vpi: $O $(OPP) ../vvp/libvpi.a $(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex - $(LEX) -t $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c + $(LEX) -s -t $< > $@ sdf_lexor.o: sdf_lexor.c sdf_parse.h sdf_lexor.c: $(srcdir)/sdf_lexor.lex - $(LEX) -t $(srcdir)/sdf_lexor.lex > sdf_lexor.c + $(LEX) -s -t $< > $@ -sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y - $(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y +# Build this in two steps to avoid parallel build issues (see pr3462585) +sdf_parse.c: $(srcdir)/sdf_parse.y + $(YACC) --verbose -t -p sdf -d -o $@ $< +sdf_parse.h: sdf_parse.c table_mod_lexor.o: table_mod_lexor.c table_mod_parse.h table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex - $(LEX) -t $< > $@ + $(LEX) -s -t $< > $@ -table_mod_parse.c table_mod_parse.h: $(srcdir)/table_mod_parse.y - $(YACC) --verbose -d -p tblmod -o table_mod_parse.c $< +# Build this in two steps to avoid parallel build issues (see pr3462585) +table_mod_parse.c: $(srcdir)/table_mod_parse.y + $(YACC) --verbose -t -p tblmod -d -o $@ $< +table_mod_parse.h: table_mod_parse.c v2005_math.vpi: $M ../vvp/libvpi.a $(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) diff --git a/vvp/Makefile.in b/vvp/Makefile.in index beaf67387..4f3a59a80 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -157,11 +157,11 @@ parse.o: parse.cc tables.o: tables.cc +# Build this in two steps to avoid parallel build issues (see pr3462585) parse.cc: $(srcdir)/parse.y - $(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y - + $(YACC) --verbose -t -d -o $@ $< parse.h: parse.cc - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -olexor.cc $(srcdir)/lexor.lex From fc7e7640ed3853fb1c1bc98ead33ab6a12549a99 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 5 Jan 2012 17:24:37 -0800 Subject: [PATCH 11/88] Remove some MinGW32-w64 compile warnings. --- ivlpp/Makefile.in | 2 +- libveriuser/Makefile.in | 3 +-- netlist.cc | 4 ++-- tgt-vhdl/cast.cc | 3 ++- tgt-vhdl/vhdl_helper.hh | 3 ++- tgt-vvp/eval_expr.c | 10 +++++----- tgt-vvp/eval_real.c | 3 ++- vpi/Makefile.in | 6 +++--- vpi/sys_queue.c | 4 ++-- vvp/config.h.in | 8 +++++++- 10 files changed, 27 insertions(+), 19 deletions(-) diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 226d5fb51..44b800e4b 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -70,7 +70,7 @@ ivlpp@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@ lexor.c: $(srcdir)/lexor.lex - $(LEX) -s -t $< > $@ + $(LEX) -t $< > $@ install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@ diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index dc8bf3f46..557c12fa0 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -46,7 +46,6 @@ endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ -LDFLAGS = @LDFLAGS@ A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \ a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \ @@ -88,7 +87,7 @@ stamp-config-h: $(srcdir)/config.h.in ../config.status config.h: stamp-config-h libveriuser.o: $O - $(LD) $(LDFLAGS) -r -o $@ $O + $(LD) -r -o $@ $O libveriuser.a: libveriuser.o rm -f $@ diff --git a/netlist.cc b/netlist.cc index d0aad7adf..8d8e9af9a 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -2429,7 +2429,7 @@ NetECast::~NetECast() ivl_variable_type_t NetECast::expr_type() const { - ivl_variable_type_t ret; + ivl_variable_type_t ret = IVL_VT_NO_TYPE; switch (op_) { case 'v': ret = IVL_VT_LOGIC; diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index f54dacf94..11dd34eb5 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -1,7 +1,7 @@ /* * Generate code to convert between VHDL types. * - * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -219,6 +219,7 @@ vhdl_expr *vhdl_expr::to_std_ulogic() } else assert(false); + return NULL; } /* diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index 814c5369d..d801f190b 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -1,7 +1,7 @@ /* * Helper functions for VHDL syntax elements. * - * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,6 +64,7 @@ static inline char vl_to_vhdl_bit(char bit) return '-'; } assert(false); + return 0; } #endif diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 5af817e48..3e7b548d0 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -2924,8 +2924,8 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) static struct vector_info increment(ivl_expr_t e, unsigned wid, bool pre) { - ivl_signal_t s; - unsigned w; + ivl_signal_t s = 0; + unsigned w = 0; struct vector_info r; struct vector_info rc; @@ -3000,8 +3000,8 @@ static inline struct vector_info post_increment(ivl_expr_t e, unsigned wid) static struct vector_info decrement(ivl_expr_t e, unsigned wid, bool pre) { - ivl_signal_t s; - unsigned w; + ivl_signal_t s = 0; + unsigned w = 0; struct vector_info r; struct vector_info rc; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index ce8c10d22..56fb2fe7b 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -590,6 +590,7 @@ static int draw_unary_real(ivl_expr_t expr) fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n", ivl_expr_opcode(expr)); assert(0); + return 0; } int draw_eval_real(ivl_expr_t expr) diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 7ce19bd14..a0aa48993 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -125,12 +125,12 @@ system.vpi: $O $(OPP) ../vvp/libvpi.a $(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex - $(LEX) -s -t $< > $@ + $(LEX) -t $< > $@ sdf_lexor.o: sdf_lexor.c sdf_parse.h sdf_lexor.c: $(srcdir)/sdf_lexor.lex - $(LEX) -s -t $< > $@ + $(LEX) -t $< > $@ # Build this in two steps to avoid parallel build issues (see pr3462585) sdf_parse.c: $(srcdir)/sdf_parse.y @@ -140,7 +140,7 @@ sdf_parse.h: sdf_parse.c table_mod_lexor.o: table_mod_lexor.c table_mod_parse.h table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex - $(LEX) -s -t $< > $@ + $(LEX) -t $< > $@ # Build this in two steps to avoid parallel build issues (see pr3462585) table_mod_parse.c: $(srcdir)/table_mod_parse.y diff --git a/vpi/sys_queue.c b/vpi/sys_queue.c index c45fb63ec..4f1dc0e25 100644 --- a/vpi/sys_queue.c +++ b/vpi/sys_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -587,7 +587,7 @@ static unsigned check_numeric_args(vpiHandle argv, unsigned count, /* Check that the first count arguments are numeric. Currently * only three are needed/supported. */ for (idx = 0; idx < count; idx += 1) { - char *loc; + char *loc = NULL; vpiHandle arg = vpi_scan(argv); /* Get the name for this argument. */ diff --git a/vvp/config.h.in b/vvp/config.h.in index f945cfa03..4c19d788f 100644 --- a/vvp/config.h.in +++ b/vvp/config.h.in @@ -1,7 +1,7 @@ #ifndef __config_H #define __config_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -86,9 +86,15 @@ typedef uint64_t vvp_time64_t; +#ifdef __MINGW32__ +# define TIME_FMT_O "I64o" +# define TIME_FMT_U "I64u" +# define TIME_FMT_X "I64x" +#else # define TIME_FMT_O PRIo64 # define TIME_FMT_U PRIu64 # define TIME_FMT_X PRIx64 +#endif # if UINT64_T_AND_ULONG_SAME # define UL_AND_TIME64_SAME From 62b7c523296f400eb5bdf3733aea6d2b40ae4ce9 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 5 Jan 2012 18:52:36 -0800 Subject: [PATCH 12/88] Fix a few cppcheck issues and update some suppressions --- cppcheck.sup | 4 ++-- tgt-pcb/Makefile.in | 2 +- vvp/vthread.cc | 4 +--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cppcheck.sup b/cppcheck.sup index 31acd1554..0c003b15d 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -1,3 +1,3 @@ // These are correct and are used to find the base (zero) pin. -thisSubtraction:netlist.h:4168 -thisSubtraction:netlist.h:4177 +thisSubtraction:netlist.h:4169 +thisSubtraction:netlist.h:4178 diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index 9178dcca6..4f894f0dc 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -58,7 +58,7 @@ distclean: clean rm -f Makefile config.log rm -f stamp-pcb_config-h pcb_config.h -cppcheck: $(O:.o=.c) +cppcheck: $(O:.o=.cc) cppcheck --enable=all -f $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status diff --git a/vvp/vthread.cc b/vvp/vthread.cc index a949d00e9..3fd4c0719 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -3574,8 +3574,6 @@ bool of_PAD(vthread_t thr, vvp_code_t cp) vvp_vector4_t tmp (cp->number, pad_bit); thr->bits4.set_vec(cp->bit_idx[0], tmp); return true; - - return true; } /* From 8563218cd26609f3576f58fac11c5f2f7559126b Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 5 Jan 2012 19:21:03 -0800 Subject: [PATCH 13/88] Register Icarus vpi debug routine as a system function. --- vpi/vpi_debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vpi/vpi_debug.c b/vpi/vpi_debug.c index 2b8e0cdfc..96f334201 100644 --- a/vpi/vpi_debug.c +++ b/vpi/vpi_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 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 @@ -104,6 +104,7 @@ void sys_register() tf_data.sizetf = 0; tf_data.user_data = "$vpi_tree"; res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); } void (*vlog_startup_routines[])() = { From d5b5fbd2742f4b921a564b30fff55a59d06e5b46 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 6 Jan 2012 19:33:19 -0800 Subject: [PATCH 14/88] vlog95: Don't emit the \n, \t, \" or \\ values as octal constants. 1364-1995 Verilog allows the \n, \t, \" or \\ string escape sequences so use them when emitting a string. --- tgt-vlog95/misc.c | 6 ++++-- tgt-vlog95/numbers.c | 51 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index 0f83ec7ae..492f88f68 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -500,9 +500,11 @@ static void emit_number_as_string(ivl_net_const_t net_const) /* Skip any NULL bytes. */ if (val == 0) continue; - /* Print some values that must be escaped. */ + /* Print some values that can be escaped. */ if (val == '"') fprintf(vlog_out, "\\\""); else if (val == '\\') fprintf(vlog_out, "\\\\"); + else if (val == '\n') fprintf(vlog_out, "\\n"); + else if (val == '\t') fprintf(vlog_out, "\\t"); /* Print the printable characters. */ else if (isprint((int)val)) fprintf(vlog_out, "%c", val); /* Print the non-printable characters as an octal escape. */ diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index 9a769c7a7..e81b4e0a1 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -317,6 +317,17 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type) ivl_expr_signed(expr), result_type); } +/* + * Routine to remove two characters starting at the given address. + */ +static void remove_two_chars(char* str) +{ + for (; str[2]; str += 1) { + str[0] = str[2]; + } + str[0] = 0; +} + /* * Routine to print a string value as a string after removing any leading * escaped NULL bytes. @@ -324,12 +335,42 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type) void emit_string(const char* string) { char *buffer = strdup(string); - char *cptr = buffer; + char *bptr = buffer; + char *cptr; fprintf(vlog_out, "\""); /* Prune any leading escaped NULL bytes. */ - while ((cptr[0] == '\\') && (cptr[1] == '0') && - (cptr[2] == '0') && (cptr[3] == '0')) cptr += 4; - if (*cptr) fprintf(vlog_out, "%s", cptr); + while ((bptr[0] == '\\') && (bptr[1] == '0') && + (bptr[2] == '0') && (bptr[3] == '0')) bptr += 4; + for (cptr = bptr; *cptr; cptr += 1) { + if (*cptr == '\\') { + /* Replace any \011 with \t */ + if ((cptr[1] == '0') && (cptr[2] == '1') && + (cptr[3] == '1')) { + cptr[1] = 't'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \012 with \n */ + } else if ((cptr[1] == '0') && (cptr[2] == '1') && + (cptr[3] == '2')) { + cptr[1] = 'n'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \042 with \" */ + } else if ((cptr[1] == '0') && (cptr[2] == '4') && + (cptr[3] == '2')) { + cptr[1] = '"'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \134 with \\ */ + } else if ((cptr[1] == '1') && (cptr[2] == '3') && + (cptr[3] == '4')) { + cptr[1] = '\\'; + remove_two_chars(cptr+2); + cptr += 1; + } else cptr += 3; + } + } + if (*bptr) fprintf(vlog_out, "%s", bptr); free(buffer); fprintf(vlog_out, "\""); } From e485ac99810d3a06fc2cc1e4a4828affc5f98d70 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 7 Jan 2012 12:36:28 +0000 Subject: [PATCH 15/88] Fix for pr3465541. vvp_net_t::send_vec8_pv() needs to call the output filter if one is present, and vvp_wire_vec4::filter_vec8() needs to support part selects. --- vvp/vvp_net.h | 27 ++++++++++++++++++++++++--- vvp/vvp_net_sig.cc | 18 +++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 5fd8525cc..e9c55c78a 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1546,10 +1546,9 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val, } } -inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, - unsigned base, unsigned wid, unsigned vwid) +inline void vvp_send_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&val, + unsigned base, unsigned wid, unsigned vwid) { - vvp_net_ptr_t ptr = out_; while (class vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; @@ -1623,6 +1622,28 @@ inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) } } +inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, + unsigned base, unsigned wid, unsigned vwid) +{ + if (fil == 0) { + vvp_send_vec8_pv(out_, val, base, wid, vwid); + return; + } + + assert(val.size() == wid); + vvp_vector8_t rep; + switch (fil->filter_vec8(val, rep, base, vwid)) { + case vvp_net_fil_t::STOP: + break; + case vvp_net_fil_t::PROP: + vvp_send_vec8_pv(out_, val, base, wid, vwid); + break; + case vvp_net_fil_t::REPL: + vvp_send_vec8_pv(out_, rep, base, wid, vwid); + break; + } +} + inline void vvp_net_t::send_real(double val, vvp_context_t context) { if (fil && ! fil->filter_real(val)) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 1da9edb85..183c81b8e 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -651,12 +651,20 @@ vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec8(const vvp_vector8_t&bit, unsigned base, unsigned vwid) { - // For now there is no support for a non-zero base. - assert(0 == base); assert(bits4_.size() == vwid); - assert(bits4_.size() == bit.size()); - bits4_ = reduce4(bit); - return filter_mask_(bit, vvp_vector8_t(force4_,6,6), rep, 0); + + // Keep track of the value being driven from this net, even if + // it is not ultimately what survives the force filter. + vvp_vector4_t bit4 (reduce4(bit)); + if (base==0 && bit4.size()==vwid) { + if (bits4_ .eeq( bit4 ) && !needs_init_) return STOP; + bits4_ = bit4; + } else { + bits4_.set_vec(base, bit4); + } + + needs_init_ = false; + return filter_mask_(bit, vvp_vector8_t(force4_,6,6), rep, base); } unsigned vvp_wire_vec4::filter_size() const From 498bfcd24b9fa3752b476a64a6db556c37406add Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 7 Jan 2012 10:23:07 -0800 Subject: [PATCH 16/88] Trivial optimizer cleanup. --- net_link.cc | 2 +- scripts/devel-stub.conf | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/net_link.cc b/net_link.cc index 2ed0588b1..0d99acd90 100644 --- a/net_link.cc +++ b/net_link.cc @@ -278,7 +278,7 @@ bool Nexus::assign_lval() const if (net == 0) continue; - if (net->peek_lref()) + if (net->peek_lref() > 0) return true; } diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf index 01009dc3d..5982f4988 100644 --- a/scripts/devel-stub.conf +++ b/scripts/devel-stub.conf @@ -20,6 +20,7 @@ debug:elaborate debug:elab_pexpr debug:scopes debug:synth2 +debug:optimizer out:a.out ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp sys_func:scripts/devel-stub.sft From ea065a674d8e2f471622e1787090f55eaddd1264 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 9 Jan 2012 19:11:36 -0800 Subject: [PATCH 17/88] Use the identifier to get the correct line information Using the closing ')' was not giving the correct line number. --- parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parse.y b/parse.y index 3f4c78dbf..df5b5e962 100644 --- a/parse.y +++ b/parse.y @@ -3041,7 +3041,7 @@ module_item current_function = 0; delete[]$4; if ($7==0 && !gn_system_verilog()) { - yyerror(@7, "error: Empty parenthesis syntax requires SystemVerilog."); + yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); } } | K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction From 6662a3f78ae58e9da50518bfc7dfe2c81206da50 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 10 Jan 2012 18:22:52 -0800 Subject: [PATCH 18/88] Better VPI reference to part of array word. Create the &APV<> token in vvp that create a VPI handle for a part of an array word. This works better with things like $monitor. --- tgt-vvp/draw_vpi.c | 25 ++++++- vvp/array.cc | 159 +++++++++++++++++++++++++++++++++++++++++++-- vvp/lexor.lex | 1 + vvp/parse.y | 5 +- vvp/vpi_priv.h | 5 +- 5 files changed, 183 insertions(+), 12 deletions(-) diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 601b04378..ef4bf50c0 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -170,6 +170,7 @@ 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; + ivl_expr_t wexpr; assert(vexpr); @@ -179,20 +180,38 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, /* The signal is part of an array. */ /* Add &APV<> code here when it is finished. */ - if (ivl_expr_oper1(vexpr)) return 0; - bexpr = ivl_expr_oper2(expr); /* This is a pad operation. */ if (!bexpr) return 0; + wexpr = ivl_expr_oper1(vexpr); + + /* If vexpr has an operand, then that operand is a word + index and we are taking a select from an array + word. This would come up in expressions like + "array[][]" where wexpr is */ + if (wexpr && number_is_immediate(wexpr, 64, 1) + && number_is_immediate(bexpr, 64, 1)) { + assert(! number_is_unknown(bexpr)); + assert(! number_is_unknown(wexpr)); + snprintf(buffer, sizeof buffer, "&APV", + ivl_expr_signal(vexpr), + get_number_immediate(wexpr), + get_number_immediate(bexpr), + ivl_expr_width(expr)); + + } else if (wexpr) { + return 0; + /* This is a constant bit/part select. */ - if (number_is_immediate(bexpr, 64, 1)) { + } else if (number_is_immediate(bexpr, 64, 1)) { assert(! number_is_unknown(bexpr)); snprintf(buffer, sizeof buffer, "&PV", ivl_expr_signal(vexpr), get_number_immediate(bexpr), ivl_expr_width(expr)); + /* This is an indexed bit/part select. */ } else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL || ivl_expr_type(bexpr) == IVL_EX_SELECT) { diff --git a/vvp/array.cc b/vvp/array.cc index 2d0be3155..e70e00097 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -182,6 +182,15 @@ struct __vpiArrayVthrA { } }; + +struct __vpiArrayVthrAPV { + struct __vpiHandle base; + struct __vpiArray*array; + unsigned word_sel; + unsigned part_bit; + unsigned part_wid; +}; + /* Get the array word size. */ unsigned get_array_word_size(vvp_array_t array) { @@ -270,6 +279,10 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp); static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int); static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref); +static int vpi_array_vthr_APV_get(int code, vpiHandle); +static char*vpi_array_vthr_APV_get_str(int code, vpiHandle); +static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp); + static const struct __vpirt vpip_arraymem_rt = { vpiMemory, vpi_array_get, @@ -357,6 +370,20 @@ static const struct __vpirt vpip_array_vthr_A_rt = { 0 }; +static const struct __vpirt vpip_array_vthr_APV_rt = { + vpiMemoryWord, + &vpi_array_vthr_APV_get, + &vpi_array_vthr_APV_get_str, + &vpi_array_vthr_APV_get_value, + 0, //&vpi_array_vthr_A_put_value, + 0, //&vpi_array_vthr_A_get_handle, + 0, + 0, + 0, + 0, + 0 +}; + # define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \ (struct __vpiArray*)ref) @@ -390,6 +417,16 @@ static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref) return (struct __vpiArrayVthrA*) ref; } +static struct __vpiArrayVthrAPV* array_vthr_apv_from_handle(vpiHandle ref) +{ + if (ref == 0) + return 0; + if (ref->vpi_type != &vpip_array_vthr_APV_rt) + return 0; + + return (struct __vpiArrayVthrAPV*) ref; +} + static void array_make_vals_words(struct __vpiArray*parent) { assert(parent->vals_words == 0); @@ -862,6 +899,72 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) return 0; } +static int vpi_array_vthr_APV_get(int code, vpiHandle ref) +{ + struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + struct __vpiArray*parent = obj->array; + + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! + + case vpiSize: + return obj->part_wid; + + case vpiLeftRange: + return parent->msb.value; + + case vpiRightRange: + return parent->lsb.value; + + case vpiIndex: + return (int)obj->word_sel; + + case vpiAutomatic: + return (int) parent->scope->is_automatic; + + case vpiConstantSelect: + return 1; + + default: + return 0; + } +} + +static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) +{ + struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + assert(obj); + struct __vpiArray*parent = obj->array; + + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + char sidx [64]; + snprintf(sidx, 63, "%u", obj->word_sel + parent->first_addr.value); + return generic_get_str(code, &parent->scope->base, parent->name, sidx); +} + +static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) +{ + struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + assert(obj); + struct __vpiArray*parent = obj->array; + + assert(parent); + + unsigned index = obj->word_sel; + if (vpi_array_is_real(parent)) { + double tmp = array_get_word_r(parent, index); + vpip_real_get_value(tmp, vp); + } else { + vvp_vector4_t tmp = array_get_word(parent, index); + tmp = tmp.subvalue(obj->part_bit, obj->part_wid); + vpip_vec4_get_value(tmp, obj->part_wid, parent->signed_flag, vp); + } +} + void array_set_word(vvp_array_t arr, unsigned address, unsigned part_off, @@ -1517,6 +1620,10 @@ void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) } else if (struct __vpiArrayVthrA*tword = array_vthr_a_from_handle(obj)) { parent = tword->array; cb->extra_data = tword->address; + + } else if (struct __vpiArrayVthrAPV*apvword = array_vthr_apv_from_handle(obj)) { + parent = apvword->array; + cb->extra_data = apvword->word_sel; } assert(parent); @@ -1592,14 +1699,20 @@ void compile_array_alias(char*label, char*name, char*src) assert(!array_find(label)); array_table->sym_set_value(label, obj); - compile_vpi_symbol(label, &obj->base); - vpip_attach_to_current_scope(&obj->base); + compile_vpi_symbol(label, vpi_handle(obj)); + vpip_attach_to_current_scope(vpi_handle(obj)); free(label); free(name); free(src); } +/* + * &A + * This represents a VPI handle for an addressed array. This comes + * from expressions like "label[addr]" where "label" is the array and + * "addr" is the canonical address of the desired word. + */ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) { struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) @@ -1617,9 +1730,16 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) obj->address = addr; obj->wid = 0; - return &(obj->base); + return vpi_handle(obj); } +/* + * &A + * This represents a VPI handle for an addressed word, where the word + * address in thread vector space. The tbase/twod/is_signed variables + * are the location and interpretation of the bits. This comes from + * source expressions that look like label[]. + */ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, char*is_signed) { @@ -1641,9 +1761,15 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, delete [] is_signed; - return &(obj->base); + return vpi_handle(obj); } +/* + * &A + * This represents a VPI handle for an addressed word, where the + * word address is calculated from the VPI object that symbol + * represents. The expression that leads to this looks like label[symbol]. + */ vpiHandle vpip_make_vthr_A(char*label, char*symbol) { struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) @@ -1662,8 +1788,9 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol) obj->address = 0; obj->wid = 0; - return &(obj->base); + return vpi_handle(obj); } + vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) { struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) @@ -1681,7 +1808,27 @@ vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) obj->address = 0; obj->wid = 0; - return &(obj->base); + return vpi_handle(obj); +} + +vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid) +{ + struct __vpiArrayVthrAPV*obj = (struct __vpiArrayVthrAPV*) + malloc(sizeof (struct __vpiArrayVthrAPV)); + + obj->base.vpi_type = &vpip_array_vthr_APV_rt; + + array_resolv_list_t*resolv_mem + = new array_resolv_list_t(label); + + resolv_mem->array = &obj->array; + resolv_submit(resolv_mem); + + obj->word_sel = index; + obj->part_bit = bit; + obj->part_wid = wid; + + return vpi_handle(obj); } void compile_array_cleanup(void) diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 02d98b942..1109205cd 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -220,6 +220,7 @@ static char* strdupnew(char const *str) /* Handle the specialized variable access functions. */ "&A" { return K_A; } +"&APV" { return K_APV; } "&PV" { return K_PV; } "%"[.$_/a-zA-Z0-9]+ { diff --git a/vvp/parse.y b/vvp/parse.y index 6c03a3335..aff881aa2 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -70,7 +70,7 @@ static struct __vpiModPath*modpath_dst = 0; vvp_delay_t*cdelay; }; -%token K_A K_ALIAS K_ALIAS_R +%token K_A K_ALIAS K_ALIAS_R K_APV %token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD %token K_ARITH_MOD_R K_ARITH_MOD_S %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R @@ -971,6 +971,9 @@ symbol_access { $$ = vpip_make_PV($3, $5, $7); } | K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER T_STRING ',' T_NUMBER '>' { $$ = vpip_make_PV($3, $5, $6, $7, $9); } + | K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_vthr_APV($3, $5, $7, $9); } + ; /* functor operands can only be a list of symbols. */ symbols diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index b6b244fde..224997f0e 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -127,10 +127,10 @@ struct __vpirt { * "base" that is a __vpiHandle object. This template can convert any * of those structures into a vpiHandle object. */ -template vpiHandle vpi_handle(T obj) +template inline vpiHandle vpi_handle(T obj) { return &obj->base; } -template char*vpip_get_str(int code, T obj) +template inline char*vpip_get_str(int code, T obj) { return obj->base.vpi_type->vpi_get_str_(code, vpi_handle(obj)); } /* @@ -519,6 +519,7 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol); vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, char*is_signed); vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle); +vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid); /* * This function is called before any compilation to load VPI From b3ef8171e2ebc908e96a83ce3e1609e05878bb15 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 14 Jan 2012 11:01:54 -0800 Subject: [PATCH 19/88] Short circuit propagation of part selects when possible Full vector assigns are able to short circuit the propagation of the value if it finds that there are no value changes. This patch supports that behavior in writes to parts as well. Put this change to use in logic devices as well. --- vvp/logic.cc | 24 ++++---- vvp/vvp_net.cc | 145 ++++++++++++++++++++++++++++++--------------- vvp/vvp_net.h | 11 ++-- vvp/vvp_net_sig.cc | 23 ++++++- 4 files changed, 139 insertions(+), 64 deletions(-) diff --git a/vvp/logic.cc b/vvp/logic.cc index dd0faafbe..1372f9700 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -63,10 +63,11 @@ void vvp_fun_boolean_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_[port].subvalue(base, wid) .eeq( bit )) + // Set the part for the input. If nothing changes, then break. + bool flag = input_[port] .set_vec(base, bit); + if (flag == false) return; - input_[port] .set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); @@ -151,10 +152,11 @@ void vvp_fun_buf::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_.subvalue(base, wid) .eeq( bit )) + // Set the input part. If nothing changes, then break. + bool flag = input_.set_vec(base, bit); + if (flag == false) return; - input_.set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); @@ -370,16 +372,17 @@ void vvp_fun_muxz::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, { assert(bit.size() == wid); assert(base + wid <= vwid); + bool flag; switch (ptr.port()) { case 0: - if (a_.subvalue(base, wid) .eeq(bit) && has_run_) return; - a_.set_vec(base, bit); + flag = a_.set_vec(base, bit); + if (flag == false && has_run_) return; if (select_ == SEL_PORT1) return; // The other port is selected. break; case 1: - if (b_.subvalue(base, wid) .eeq(bit) && has_run_) return; - b_.set_vec(base, bit); + flag = b_.set_vec(base, bit); + if (flag == false && has_run_) return; if (select_ == SEL_PORT0) return; // The other port is selected. break; case 2: @@ -475,10 +478,11 @@ void vvp_fun_not::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_.subvalue(base, wid) .eeq( bit )) + // Set the part value. If nothing changes, then break. + bool flag = input_.set_vec(base, bit); + if (flag == false) return; - input_.set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index d0128940e..aadaa61c9 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1023,9 +1023,10 @@ void vvp_vector4_t::setarray(unsigned adr, unsigned wid, const unsigned long*val * into the addressed part of this vector. Use bit masking and word * copies to go as fast as reasonably possible. */ -void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) +bool vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) { assert(adr+that.size_ <= size_); + bool diff_flag = false; if (size_ <= BITS_PER_WORD) { @@ -1046,12 +1047,16 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) hmask = (1UL << (adr+that.size_)) - 1; unsigned long mask = hmask & ~lmask; - abits_val_ = - (abits_val_ & ~mask) - | ((that.abits_val_< BITS_PER_WORD) { unsigned tail = doff + that.size_ - BITS_PER_WORD; mask = (1UL << tail) - 1; dptr += 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~mask) - | ((that.abits_val_ >> (that.size_-tail)) & mask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~mask) - | ((that.bbits_val_ >> (that.size_-tail)) & mask); + tmp = (that.abits_val_ >> (that.size_-tail)) & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_val_ >> (that.size_-tail)) & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } else if (adr%BITS_PER_WORD == 0) { @@ -1102,8 +1116,14 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) unsigned sptr = 0; unsigned dptr = adr / BITS_PER_WORD; while (remain >= BITS_PER_WORD) { - abits_ptr_[dptr] = that.abits_ptr_[sptr]; - bbits_ptr_[dptr] = that.bbits_ptr_[sptr]; + if (abits_ptr_[dptr] != that.abits_ptr_[sptr]) { + diff_flag = true; + abits_ptr_[dptr] = that.abits_ptr_[sptr]; + } + if (bbits_ptr_[dptr] != that.bbits_ptr_[sptr]) { + diff_flag = true; + bbits_ptr_[dptr] = that.bbits_ptr_[sptr]; + } dptr += 1; sptr += 1; remain -= BITS_PER_WORD; @@ -1111,12 +1131,18 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) if (remain > 0) { unsigned long mask = (1UL << remain) - 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~mask) - | (that.abits_ptr_[sptr] & mask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~mask) - | (that.bbits_ptr_[sptr] & mask); + unsigned long tmp; + + tmp = that.abits_ptr_[sptr] & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = that.bbits_ptr_[sptr] & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } else { @@ -1131,20 +1157,30 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) unsigned long lmask = (1UL << doff) - 1; unsigned ndoff = BITS_PER_WORD - doff; while (remain >= BITS_PER_WORD) { - abits_ptr_[dptr] = - (abits_ptr_[dptr] & lmask) - | ((that.abits_ptr_[sptr] << doff) & ~lmask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & lmask) - | ((that.bbits_ptr_[sptr] << doff) & ~lmask); + unsigned long tmp; + + tmp = (that.abits_ptr_[sptr] << doff) & ~lmask; + if ((abits_ptr_[dptr] & ~lmask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & lmask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] << doff) & ~lmask; + if ((bbits_ptr_[dptr] & ~lmask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & lmask) | tmp; + } dptr += 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~lmask) - | ((that.abits_ptr_[sptr] >> ndoff) & lmask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~lmask) - | ((that.bbits_ptr_[sptr] >> ndoff) & lmask); + tmp = (that.abits_ptr_[sptr] >> ndoff) & lmask; + if ((abits_ptr_[dptr] & lmask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~lmask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] >> ndoff) & lmask; + if ((bbits_ptr_[dptr] & lmask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~lmask) | tmp; + } remain -= BITS_PER_WORD; sptr += 1; @@ -1159,11 +1195,18 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) hmask = (1UL << (doff+remain)) - 1; unsigned long mask = hmask & ~lmask; + unsigned long tmp; - abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) - | ((that.abits_ptr_[sptr] << doff) & mask); - bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) - | ((that.bbits_ptr_[sptr] << doff) & mask); + tmp = (that.abits_ptr_[sptr] << doff) & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] << doff) & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } if ((doff + remain) > BITS_PER_WORD) { unsigned tail = doff + remain - BITS_PER_WORD; @@ -1173,14 +1216,22 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) mask = (1UL << tail) - 1; dptr += 1; - abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | - ((that.abits_ptr_[sptr] >> (remain-tail))&mask); - bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | - ((that.bbits_ptr_[sptr] >> (remain-tail))&mask); + + tmp = (that.abits_ptr_[sptr] >> (remain-tail))&mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] >> (remain-tail))&mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } } + return diff_flag; } void vvp_vector4_t::mov(unsigned dst, unsigned src, unsigned cnt) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index e9c55c78a..e3456bbc7 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -234,8 +234,10 @@ class vvp_vector4_t { unsigned long*subarray(unsigned idx, unsigned size) const; void setarray(unsigned idx, unsigned size, const unsigned long*val); + // Set a 4-value bit or subvector into the vector. Return true + // if any bits of the vector change as a result of this operation. void set_bit(unsigned idx, vvp_bit4_t val); - void set_vec(unsigned idx, const vvp_vector4_t&that); + bool set_vec(unsigned idx, const vvp_vector4_t&that); // Get the bits from another vector, but keep my size. void copy_bits(const vvp_vector4_t&that); @@ -1188,11 +1190,10 @@ class vvp_net_fun_t { /* * A vvp_net_fil_t is a filter object that filters an output from a - * vvp_net_t. The send_*() methods of the vvp_net_t object call the + * vvp_net_t. The send_*() methods of the vvp_net_t object invoke the * filter of the output being transmitted. The filter function will - * decide if this value is to be propagated, and return true or - * false. If false, then send_*() continues as usual. If false, output - * propagation is stopped. + * decide if this value is to be propagated, and how, and return a + * prop_t enumeration to reflect the choice. * * The filter object also provides an implementation hooks for * force/release. diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 183c81b8e..f0f7423ff 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -30,9 +30,26 @@ # include +/* + * The filter_mask_ method takes as an input the value to propagate, + * the mask of what is being forced, and returns a propagation + * mode. In the process, it may update the filtered output value. + * + * The input value is the subvector "val" that is placed as "base" in + * the output. The val may be shorter then the target vector. + * + * The "force" vector in the value being force, with the force_mask_ + * member a bit mask of which parts of the force vector really apply. + */ template vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(const T&val, const T&force, T&filter, unsigned base) { if (!test_force_mask_is_zero()) { + // Some bits are being forced. Go through the + // force_mask_ and force value to see which bits are + // propogated and which are kept from the forced + // value. Update the filter with the filtered result and + // return REPL to indicate that some bits have changed, + // or STOP if no bits change. bool propagate_flag = force_propagate_; force_propagate_ = false; assert(force_mask_.size() == force.size()); @@ -639,7 +656,8 @@ vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec4(const vvp_vector4_t&bit, vvp_ve if (bits4_ .eeq( bit ) && !needs_init_) return STOP; bits4_ = bit; } else { - bits4_.set_vec(base, bit); + bool rc = bits4_.set_vec(base, bit); + if (rc == false && !needs_init_) return STOP; } needs_init_ = false; @@ -660,7 +678,8 @@ vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec8(const vvp_vector8_t&bit, if (bits4_ .eeq( bit4 ) && !needs_init_) return STOP; bits4_ = bit4; } else { - bits4_.set_vec(base, bit4); + bool rc = bits4_.set_vec(base, bit4); + if (rc == false && !needs_init_) return STOP; } needs_init_ = false; From a20bac6a660d9b5cca400b0f8715389f0155cefe Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 16 Jan 2012 11:04:02 -0800 Subject: [PATCH 20/88] support parameters declared with atom2 types. --- parse.y | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/parse.y b/parse.y index df5b5e962..3bc87a667 100644 --- a/parse.y +++ b/parse.y @@ -3362,6 +3362,16 @@ parameter_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } + | atom2_type + { param_active_range = make_range_from_width($1); + param_active_signed = true; + param_active_type = IVL_VT_BOOL; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } ; parameter_assign_list @@ -3487,6 +3497,16 @@ localparam_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } + | atom2_type + { param_active_range = make_range_from_width($1); + param_active_signed = true; + param_active_type = IVL_VT_BOOL; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } ; localparam_assign_list From a48c9c3b4a64f3bfd4b2e149f661b590cadf888a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 19 Jan 2012 10:16:39 -0800 Subject: [PATCH 21/88] Reword __vpiHandle objects to create a class structure. Instead of C-like data structures where the __vpiHandle base is a leading member, make the __vpiHandle a derived class. Give the base class a virtual destructor so that dynamic_cast works reliably, and now pretty much all of the junk for testing if an object really is of the derived class goes away. Also, problems with casting up to a vpiHandle become trivial non-issues. --- vvp/array.cc | 314 ++++++++++++++++++++--------------------- vvp/compile.cc | 6 +- vvp/delay.cc | 83 ++++------- vvp/enum_type.cc | 60 ++++---- vvp/file_line.cc | 23 +-- vvp/schedule.cc | 4 +- vvp/stop.cc | 39 +++-- vvp/vpi_callback.cc | 27 ++-- vvp/vpi_const.cc | 200 +++++++++++--------------- vvp/vpi_event.cc | 35 +++-- vvp/vpi_iter.cc | 43 +++--- vvp/vpi_priv.cc | 172 ++++++++-------------- vvp/vpi_priv.h | 190 +++++++++++++++---------- vvp/vpi_real.cc | 64 ++++----- vvp/vpi_scope.cc | 88 +++++------- vvp/vpi_signal.cc | 159 ++++++++++----------- vvp/vpi_tasks.cc | 134 ++++++++---------- vvp/vpi_time.cc | 39 +++-- vvp/vpi_vthr_vector.cc | 74 +++++----- vvp/vthread.cc | 2 +- vvp/words.cc | 2 +- 21 files changed, 803 insertions(+), 955 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index e70e00097..5bbcba787 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2012 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 @@ -80,8 +80,8 @@ vvp_array_t array_find(const char*label) * array of double variables. This is very much line the way the * vector4 array works. */ -struct __vpiArray { - struct __vpiHandle base; +struct __vpiArray : public __vpiHandle { + __vpiArray(); struct __vpiScope*scope; const char*name; /* Permanently allocated string */ unsigned array_count; @@ -103,20 +103,23 @@ struct __vpiArray { bool swap_addr; }; -struct __vpiArrayIterator { - struct __vpiHandle base; +struct __vpiArrayIterator : public __vpiHandle { + __vpiArrayIterator(); + struct __vpiArray*array; unsigned next; }; -struct __vpiArrayIndex { - struct __vpiHandle base; +struct __vpiArrayIndex : public __vpiHandle { + __vpiArrayIndex(); struct __vpiDecConst *index; unsigned done; }; -struct __vpiArrayVthrA { - struct __vpiHandle base; +struct __vpiArrayVthrA : public __vpiHandle { + + __vpiArrayVthrA(); + struct __vpiArray*array; // If this is set, then use it to get the index value. vpiHandle address_handle; @@ -133,15 +136,15 @@ struct __vpiArrayVthrA { s_vpi_value vp; /* Check to see if the value is defined. */ vp.format = vpiVectorVal; - vpi_get_value(address_handle, &vp); - int words = (vpi_get(vpiSize, address_handle)-1)/32 + 1; + address_handle->vpi_get_value(&vp); + int words = (address_handle->vpi_get(vpiSize)-1)/32 + 1; for(int idx = 0; idx < words; idx += 1) { /* Return UINT_MAX to indicate an X base. */ if (vp.value.vector[idx].bval != 0) return UINT_MAX; } /* The value is defined so get and return it. */ vp.format = vpiIntVal; - vpi_get_value(address_handle, &vp); + address_handle->vpi_get_value(&vp); return vp.value.integer; } @@ -183,8 +186,8 @@ struct __vpiArrayVthrA { }; -struct __vpiArrayVthrAPV { - struct __vpiHandle base; +struct __vpiArrayVthrAPV : public __vpiHandle { + __vpiArrayVthrAPV(); struct __vpiArray*array; unsigned word_sel; unsigned part_bit; @@ -200,7 +203,7 @@ unsigned get_array_word_size(vvp_array_t array) /* For a net array we need to get the width from the first element. */ if (array->nets) { assert(array->vals4 == 0 && array->valsr == 0); - struct __vpiSignal*vsig = vpip_signal_from_handle(array->nets[0]); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(array->nets[0]); assert(vsig); width = vpip_size(vsig); /* For a variable array we can get the width from vals_width. */ @@ -214,9 +217,9 @@ unsigned get_array_word_size(vvp_array_t array) bool is_net_array(vpiHandle obj) { - assert(obj->vpi_type->type_code == vpiMemory); + struct __vpiArray*rfp = dynamic_cast<__vpiArray*> (obj); + assert(rfp); - struct __vpiArray*rfp = (struct __vpiArray*) obj; if (rfp->nets != 0) return true; return false; } @@ -242,16 +245,23 @@ bool is_net_array(vpiHandle obj) * of vpi functions is bound to the same structure. All the details * for the word also apply when treating this as an index. */ + + struct __vpiArrayWord { - struct __vpiHandle as_word; - struct __vpiHandle as_index; + struct as_word_t : public __vpiHandle { + as_word_t(); + } as_word; + + struct as_index_t : public __vpiHandle { + as_index_t(); + } as_index; + union { struct __vpiArray*parent; struct __vpiArrayWord*word0; }; }; - static int vpi_array_get(int code, vpiHandle ref); static char*vpi_array_get_str(int code, vpiHandle ref); static vpiHandle vpi_array_get_handle(int code, vpiHandle ref); @@ -296,6 +306,11 @@ static const struct __vpirt vpip_arraymem_rt = { 0, 0 }; +inline __vpiArray::__vpiArray() +: __vpiHandle(&vpip_arraymem_rt) +{ +} + static const struct __vpirt vpip_array_iterator_rt = { vpiIterator, @@ -311,6 +326,12 @@ static const struct __vpirt vpip_array_iterator_rt = { 0 }; +inline __vpiArrayIterator::__vpiArrayIterator() +: __vpiHandle(&vpip_array_iterator_rt) +{ +} + + /* This should look a bit odd since it provides a fake iteration on * this object. This trickery is used to implement the two forms of * index access, simple handle access and iteration access. */ @@ -328,6 +349,11 @@ static const struct __vpirt vpip_array_index_rt = { 0 }; +inline __vpiArrayIndex::__vpiArrayIndex() +: __vpiHandle(&vpip_array_index_rt) +{ +} + static const struct __vpirt vpip_array_var_word_rt = { vpiMemoryWord, &vpi_array_var_word_get, @@ -341,6 +367,10 @@ static const struct __vpirt vpip_array_var_word_rt = { 0, 0 }; +inline __vpiArrayWord::as_word_t::as_word_t() +: __vpiHandle(&vpip_array_var_word_rt) +{ +} static const struct __vpirt vpip_array_var_index_rt = { vpiIndex, @@ -355,6 +385,10 @@ static const struct __vpirt vpip_array_var_index_rt = { 0, 0 }; +inline __vpiArrayWord::as_index_t::as_index_t() +: __vpiHandle(&vpip_array_var_index_rt) +{ +} static const struct __vpirt vpip_array_vthr_A_rt = { vpiMemoryWord, @@ -370,6 +404,11 @@ static const struct __vpirt vpip_array_vthr_A_rt = { 0 }; +inline __vpiArrayVthrA::__vpiArrayVthrA() +: __vpiHandle(&vpip_array_vthr_A_rt) +{ +} + static const struct __vpirt vpip_array_vthr_APV_rt = { vpiMemoryWord, &vpi_array_vthr_APV_get, @@ -384,14 +423,17 @@ static const struct __vpirt vpip_array_vthr_APV_rt = { 0 }; -# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \ - (struct __vpiArray*)ref) +inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() +: __vpiHandle(&vpip_array_vthr_APV_rt) +{ +} static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) { if (ref == 0) return 0; - if (ref->vpi_type != &vpip_array_var_word_rt) + __vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref); + if (ptr == 0) return 0; return (struct __vpiArrayWord*) ref; @@ -401,32 +443,15 @@ static struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref) { if (ref == 0) return 0; - if (ref->vpi_type != &vpip_array_var_index_rt) + __vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref); + if (ptr == 0) return 0; + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t)); + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t)); return (struct __vpiArrayWord*) (ref-1); } -static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref) -{ - if (ref == 0) - return 0; - if (ref->vpi_type != &vpip_array_vthr_A_rt) - return 0; - - return (struct __vpiArrayVthrA*) ref; -} - -static struct __vpiArrayVthrAPV* array_vthr_apv_from_handle(vpiHandle ref) -{ - if (ref == 0) - return 0; - if (ref->vpi_type != &vpip_array_vthr_APV_rt) - return 0; - - return (struct __vpiArrayVthrAPV*) ref; -} - static void array_make_vals_words(struct __vpiArray*parent) { assert(parent->vals_words == 0); @@ -439,8 +464,6 @@ static void array_make_vals_words(struct __vpiArray*parent) struct __vpiArrayWord*words = parent->vals_words; for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) { - words[idx].as_word.vpi_type = &vpip_array_var_word_rt; - words[idx].as_index.vpi_type = &vpip_array_var_index_rt; words[idx].word0 = words; } } @@ -455,7 +478,7 @@ static unsigned decode_array_word_pointer(struct __vpiArrayWord*word, static int vpi_array_get(int code, vpiHandle ref) { - struct __vpiArray*obj = ARRAY_HANDLE(ref); + struct __vpiArray*obj = dynamic_cast<__vpiArray*> (ref); switch (code) { case vpiLineNo: @@ -474,31 +497,31 @@ static int vpi_array_get(int code, vpiHandle ref) static char*vpi_array_get_str(int code, vpiHandle ref) { - struct __vpiArray*obj = ARRAY_HANDLE(ref); + struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } - return generic_get_str(code, &obj->scope->base, obj->name, NULL); + return generic_get_str(code, obj->scope, obj->name, NULL); } static vpiHandle vpi_array_get_handle(int code, vpiHandle ref) { - struct __vpiArray*obj = ARRAY_HANDLE(ref); + struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); switch (code) { case vpiLeftRange: - if (obj->swap_addr) return &(obj->last_addr.base); - else return &(obj->first_addr.base); + if (obj->swap_addr) return &(obj->last_addr); + else return &(obj->first_addr); case vpiRightRange: - if (obj->swap_addr) return &(obj->first_addr.base); - else return &(obj->last_addr.base); + if (obj->swap_addr) return &(obj->first_addr); + else return &(obj->last_addr); case vpiScope: - return &obj->scope->base; + return obj->scope; case vpiModule: return vpip_module(obj->scope); @@ -509,17 +532,16 @@ static vpiHandle vpi_array_get_handle(int code, vpiHandle ref) static vpiHandle vpi_array_iterate(int code, vpiHandle ref) { - struct __vpiArray*obj = ARRAY_HANDLE(ref); + struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); switch (code) { case vpiMemoryWord: { struct __vpiArrayIterator*res; - res = (struct __vpiArrayIterator*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_array_iterator_rt; + res = new __vpiArrayIterator; res->array = obj; res->next = 0; - return &res->base; + return res; } } @@ -533,7 +555,7 @@ static vpiHandle vpi_array_iterate(int code, vpiHandle ref) */ static vpiHandle vpi_array_index(vpiHandle ref, int index) { - struct __vpiArray*obj = ARRAY_HANDLE(ref); + struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); index -= obj->first_addr.value; if (index >= (long)obj->array_count) @@ -606,7 +628,7 @@ static char*vpi_array_var_word_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value); - return generic_get_str(code, &parent->scope->base, parent->name, sidx); + return generic_get_str(code, parent->scope, parent->name, sidx); } static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp) @@ -649,16 +671,16 @@ static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref) return &(obj->as_index); case vpiLeftRange: - return &parent->msb.base; + return &parent->msb; case vpiRightRange: - return &parent->lsb.base; + return &parent->lsb; case vpiParent: - return &parent->base; + return parent; case vpiScope: - return &parent->scope->base; + return parent->scope; case vpiModule: return vpip_module(parent->scope); @@ -679,12 +701,9 @@ static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) vp->value.integer = index; } -# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ - (struct __vpiArrayIterator*)ref) - static vpiHandle array_iterator_scan(vpiHandle ref, int) { - struct __vpiArrayIterator*obj = ARRAY_ITERATOR(ref); + struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); if (obj->next >= obj->array->array_count) { vpi_free_object(ref); @@ -705,37 +724,33 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) static int array_iterator_free_object(vpiHandle ref) { - struct __vpiArrayIterator*obj = ARRAY_ITERATOR(ref); + struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); free(obj); return 1; } -# define ARRAY_INDEX(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ - (struct __vpiArrayIndex*)ref) - vpiHandle array_index_iterate(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiConstant); - struct __vpiDecConst*obj = (struct __vpiDecConst*)ref; + struct __vpiDecConst*obj = dynamic_cast<__vpiDecConst*>(ref); + assert(obj); if (code == vpiIndex) { struct __vpiArrayIndex*res; - res = (struct __vpiArrayIndex*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_array_index_rt; + res = new __vpiArrayIndex; res->index = obj; res->done = 0; - return &res->base; + return res; } return 0; } static vpiHandle array_index_scan(vpiHandle ref, int) { - struct __vpiArrayIndex*obj = ARRAY_INDEX(ref); + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); if (obj->done == 0) { obj->done = 1; - return &obj->index->base; + return obj->index; } vpi_free_object(ref); @@ -744,14 +759,14 @@ static vpiHandle array_index_scan(vpiHandle ref, int) static int array_index_free_object(vpiHandle ref) { - struct __vpiArrayIndex*obj = ARRAY_INDEX(ref); + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); free(obj); return 1; } static int vpi_array_vthr_A_get(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -794,7 +809,7 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -804,7 +819,7 @@ static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value); - return generic_get_str(code, &parent->scope->base, parent->name, sidx); + return generic_get_str(code, parent->scope, parent->name, sidx); } // This function return true if the underlying array words are real. @@ -817,10 +832,8 @@ static unsigned vpi_array_is_real(vvp_array_t arr) // This must be a net array so look at element 0 to find the type. assert(arr->nets != 0); assert(arr->array_count > 0); - struct __vpiRealVar*rsig = vpip_realvar_from_handle(arr->nets[0]); + struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]); if (rsig) { - struct __vpiSignal*vsig = vpip_signal_from_handle(arr->nets[0]); - assert(vsig == 0); return 1U; } @@ -829,7 +842,7 @@ static unsigned vpi_array_is_real(vvp_array_t arr) static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -848,7 +861,7 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -871,7 +884,7 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -881,16 +894,16 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) break; // Not implemented! case vpiLeftRange: - return &parent->msb.base; + return &parent->msb; case vpiRightRange: - return &parent->lsb.base; + return &parent->lsb; case vpiParent: - return &parent->base; + return parent; case vpiScope: - return &parent->scope->base; + return parent->scope; case vpiModule: return vpip_module(parent->scope); @@ -901,7 +914,7 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) static int vpi_array_vthr_APV_get(int code, vpiHandle ref) { - struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); struct __vpiArray*parent = obj->array; switch (code) { @@ -933,7 +946,7 @@ static int vpi_array_vthr_APV_get(int code, vpiHandle ref) static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) { - struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -943,12 +956,12 @@ static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%u", obj->word_sel + parent->first_addr.value); - return generic_get_str(code, &parent->scope->base, parent->name, sidx); + return generic_get_str(code, parent->scope, parent->name, sidx); } static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) { - struct __vpiArrayVthrAPV*obj = array_vthr_apv_from_handle(ref); + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -997,7 +1010,7 @@ void array_set_word(vvp_array_t arr, // Select the word of the array that we affect. vpiHandle word = arr->nets[address]; - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0); @@ -1031,7 +1044,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) assert(arr->array_count > 0); vpiHandle word = arr->nets[0]; assert(word); - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->node->fil); assert(sig); @@ -1039,7 +1052,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) } vpiHandle word = arr->nets[address]; - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->node->fil); assert(sig); @@ -1059,7 +1072,7 @@ double array_get_word_r(vvp_array_t arr, unsigned address) assert(arr->nets); vpiHandle word = arr->nets[address]; - struct __vpiRealVar*vsig = vpip_realvar_from_handle(word); + struct __vpiRealVar*vsig = dynamic_cast<__vpiRealVar*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->net->fil); assert(sig); @@ -1073,8 +1086,7 @@ static vpiHandle vpip_make_array(char*label, const char*name, int first_addr, int last_addr, bool signed_flag) { - struct __vpiArray*obj = (struct __vpiArray*) - malloc(sizeof(struct __vpiArray)); + struct __vpiArray*obj = new __vpiArray; obj->signed_flag = signed_flag; @@ -1092,21 +1104,18 @@ static vpiHandle vpip_make_array(char*label, const char*name, // For now, treat all arrays as memories. This is not quite // correct, as arrays are arrays with memories a special case. - obj->base.vpi_type = &vpip_arraymem_rt; obj->scope = vpip_peek_current_scope(); obj->name = vpip_name_string(name); obj->array_count = array_count; - vpip_make_dec_const(&obj->first_addr, first_addr); - vpip_make_dec_const(&obj->last_addr, last_addr); + obj->first_addr.value = first_addr; + obj->last_addr.value = last_addr; // Start off now knowing if we are nets or variables. obj->nets = 0; obj->vals4 = 0; obj->valsr = 0; obj->vals_width = 0; - vpip_make_dec_const(&obj->msb, 0); - vpip_make_dec_const(&obj->lsb, 0); obj->vals_words = 0; // Initialize (clear) the read-ports list. @@ -1123,12 +1132,12 @@ static vpiHandle vpip_make_array(char*label, const char*name, /* Add this into the table of VPI objects. This is used for contexts that try to look up VPI objects in general. (i.e. arguments to vpi_task calls.) */ - compile_vpi_symbol(label, &(obj->base)); + compile_vpi_symbol(label, obj); /* Blindly attach to the scope as an object. */ - vpip_attach_to_current_scope(&(obj->base)); + vpip_attach_to_current_scope(obj); - return &(obj->base); + return obj; } void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word, @@ -1147,27 +1156,27 @@ void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word) assert(array->nets); array->nets[addr] = word; - if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) { + if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(word)) { vvp_net_t*net = sig->node; assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); assert(fun); fun->attach_as_word(array, addr); sig->is_netarray = 1; - sig->within.parent = &array->base; - sig->id.index = vpip_make_dec_const(addr + array->first_addr.value); + sig->within.parent = array; + sig->id.index = new __vpiDecConst(addr + array->first_addr.value); return; } - if (struct __vpiRealVar*sig = (struct __vpiRealVar*)word) { + if (struct __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(word)) { vvp_net_t*net = sig->net; assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); assert(fun); fun->attach_as_word(array, addr); sig->is_netarray = 1; - sig->within.parent = &array->base; - sig->id.index = vpip_make_dec_const(addr + array->first_addr.value); + sig->within.parent = array; + sig->id.index = new __vpiDecConst(addr + array->first_addr.value); return; } } @@ -1178,7 +1187,7 @@ void compile_var_array(char*label, char*name, int last, int first, vpiHandle obj = vpip_make_array(label, name, first, last, signed_flag != 0); - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ arr->vals_width = labs(msb-lsb) + 1; @@ -1189,8 +1198,8 @@ void compile_var_array(char*label, char*name, int last, int first, arr->vals4 = new vvp_vector4array_sa(arr->vals_width, arr->array_count); } - vpip_make_dec_const(&arr->msb, msb); - vpip_make_dec_const(&arr->lsb, lsb); + arr->msb.value = msb; + arr->lsb.value = lsb; count_var_arrays += 1; count_var_array_words += arr->array_count; @@ -1204,7 +1213,7 @@ void compile_real_array(char*label, char*name, int last, int first, { vpiHandle obj = vpip_make_array(label, name, first, last, true); - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ arr->valsr = new vvp_realarray_t(arr->array_count); @@ -1224,7 +1233,7 @@ void compile_net_array(char*label, char*name, int last, int first) { vpiHandle obj = vpip_make_array(label, name, first, last, false); - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); count_net_arrays += 1; @@ -1617,11 +1626,11 @@ void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) unsigned addr = decode_array_word_pointer(word, parent); cb->extra_data = addr; - } else if (struct __vpiArrayVthrA*tword = array_vthr_a_from_handle(obj)) { + } else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(obj)) { parent = tword->array; cb->extra_data = tword->address; - } else if (struct __vpiArrayVthrAPV*apvword = array_vthr_apv_from_handle(obj)) { + } else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(obj)) { parent = apvword->array; cb->extra_data = apvword->word_sel; } @@ -1633,7 +1642,7 @@ void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) void vpip_array_change(struct __vpiCallback*cb, vpiHandle obj) { - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); cb->extra_data = -1; // This is a callback for every element. cb->next = arr->vpi_callbacks; arr->vpi_callbacks = cb; @@ -1668,22 +1677,20 @@ void compile_array_alias(char*label, char*name, char*src) vvp_array_t mem = array_find(src); assert(mem); - struct __vpiArray*obj = (struct __vpiArray*) - malloc(sizeof (struct __vpiArray)); + struct __vpiArray*obj = new __vpiArray; - obj->base.vpi_type = &vpip_arraymem_rt; obj->scope = vpip_peek_current_scope(); obj->name = vpip_name_string(name); obj->array_count = mem->array_count; obj->signed_flag = mem->signed_flag; // Need to set an accurate range of addresses. - vpip_make_dec_const(&obj->first_addr, mem->first_addr.value); - vpip_make_dec_const(&obj->last_addr, mem->last_addr.value); + obj->first_addr.value = mem->first_addr.value; + obj->last_addr.value = mem->last_addr.value; obj->swap_addr = mem->swap_addr; - vpip_make_dec_const(&obj->msb, mem->msb.value); - vpip_make_dec_const(&obj->lsb, mem->lsb.value); + obj->msb.value = mem->msb.value; + obj->lsb.value = mem->lsb.value; // Share the words with the source array. obj->nets = mem->nets; @@ -1699,8 +1706,8 @@ void compile_array_alias(char*label, char*name, char*src) assert(!array_find(label)); array_table->sym_set_value(label, obj); - compile_vpi_symbol(label, vpi_handle(obj)); - vpip_attach_to_current_scope(vpi_handle(obj)); + compile_vpi_symbol(label, obj); + vpip_attach_to_current_scope(obj); free(label); free(name); @@ -1715,10 +1722,7 @@ void compile_array_alias(char*label, char*name, char*src) */ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1730,7 +1734,7 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) obj->address = addr; obj->wid = 0; - return vpi_handle(obj); + return obj; } /* @@ -1743,10 +1747,7 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, char*is_signed) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1761,7 +1762,7 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, delete [] is_signed; - return vpi_handle(obj); + return obj; } /* @@ -1772,10 +1773,7 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, */ vpiHandle vpip_make_vthr_A(char*label, char*symbol) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1788,15 +1786,12 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol) obj->address = 0; obj->wid = 0; - return vpi_handle(obj); + return obj; } vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1808,15 +1803,12 @@ vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) obj->address = 0; obj->wid = 0; - return vpi_handle(obj); + return obj; } vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid) { - struct __vpiArrayVthrAPV*obj = (struct __vpiArrayVthrAPV*) - malloc(sizeof (struct __vpiArrayVthrAPV)); - - obj->base.vpi_type = &vpip_array_vthr_APV_rt; + struct __vpiArrayVthrAPV*obj = new __vpiArrayVthrAPV; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1828,7 +1820,7 @@ vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned obj->part_bit = bit; obj->part_wid = wid; - return vpi_handle(obj); + return obj; } void compile_array_cleanup(void) @@ -1856,7 +1848,7 @@ void memory_delete(vpiHandle item) if (arr->nets) { for (unsigned idx = 0; idx < arr->array_count; idx += 1) { if (struct __vpiSignal*sig = - vpip_signal_from_handle(arr->nets[idx])) { + dynamic_cast<__vpiSignal*>(arr->nets[idx])) { // Delete the individual words? constant_delete(sig->id.index); /* These should only be the real words. */ diff --git a/vvp/compile.cc b/vvp/compile.cc index 23d266b98..a424b20e8 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -287,7 +287,7 @@ vvp_net_t* vvp_net_lookup(const char*label) symbol_value_t val = sym_get_value(sym_vpi, label); if (val.ptr) { vpiHandle vpi = (vpiHandle) val.ptr; - switch (vpi->vpi_type->type_code) { + switch (vpi->get_type_code()) { case vpiNet: case vpiReg: case vpiBitVar: @@ -312,7 +312,7 @@ vvp_net_t* vvp_net_lookup(const char*label) default: fprintf(stderr, "Unsupported type %d.\n", - vpi->vpi_type->type_code); + vpi->get_type_code()); assert(0); } } @@ -1397,7 +1397,7 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, vvp_net_t*net = new vvp_net_t; struct __vpiModPathSrc* srcobj = vpip_make_modpath_src(path, net) ; - vpip_attach_to_current_scope(vpi_handle(srcobj)); + vpip_attach_to_current_scope(srcobj); net->fun = obj; /* Save the vpiEdge directory into the input path term. */ diff --git a/vvp/delay.cc b/vvp/delay.cc index 2a37c40c1..ef5aa4807 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -737,43 +737,41 @@ bool vvp_fun_modpath_edge::test_vec4(const vvp_vector4_t&bit) */ static int modpath_src_get(int, vpiHandle ref) { - struct __vpiModPathSrc*obj = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*obj =dynamic_cast<__vpiModPathSrc*>(ref); assert(obj); return 0; } static void modpath_src_get_value(vpiHandle ref, p_vpi_value) { - assert((ref->vpi_type->type_code == vpiModPathIn)); - struct __vpiModPathSrc* modpathsrc = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc* modpathsrc = dynamic_cast<__vpiModPathSrc*>(ref); assert(modpathsrc); return; } static vpiHandle modpath_src_put_value(vpiHandle ref, s_vpi_value *, int ) { - assert((ref->vpi_type->type_code == vpiModPathIn)); - struct __vpiModPathSrc* modpathsrc = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc* modpathsrc = dynamic_cast<__vpiModPathSrc*>(ref); assert(modpathsrc); return 0; } static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) { - struct __vpiModPathSrc*rfp = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*rfp = dynamic_cast<__vpiModPathSrc*>(ref); assert(rfp); switch (code) { case vpiScope: - return vpi_handle(rfp->dest->scope); + return rfp->dest->scope; case vpiModule: { struct __vpiScope*scope = rfp->dest->scope; - while (scope && scope->base.vpi_type->type_code != vpiModule) + while (scope && scope->get_type_code() != vpiModule) scope = scope->scope; assert(scope); - return vpi_handle(scope); + return scope; } // Handles to path term objects should really be obtained via @@ -782,17 +780,17 @@ static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) // older versions of Icarus Verilog. case vpiModPathIn: - return vpi_handle(&rfp->path_term_in); + return &rfp->path_term_in; case vpiModPathOut: - return vpi_handle(&rfp->dest->path_term_out); + return &rfp->dest->path_term_out; } return 0; } static vpiHandle modpath_src_iterate(int code, vpiHandle ref) { - struct __vpiModPathSrc*rfp = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*rfp = dynamic_cast<__vpiModPathSrc*>(ref); assert(rfp); // Module paths with multiple sources or destinations are @@ -802,12 +800,12 @@ static vpiHandle modpath_src_iterate(int code, vpiHandle ref) switch (code) { case vpiModPathIn: { vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); - args[0] = vpi_handle(&rfp->path_term_in); + args[0] = &rfp->path_term_in; return vpip_make_iterator(1, args, true); } case vpiModPathOut: { vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); - args[0] = vpi_handle(&rfp->dest->path_term_out); + args[0] = &rfp->dest->path_term_out; return vpip_make_iterator(1, args, true); } } @@ -816,14 +814,14 @@ static vpiHandle modpath_src_iterate(int code, vpiHandle ref) static vpiHandle modpath_src_index ( vpiHandle ref, int) { - assert(ref->vpi_type->type_code == vpiModPathIn); + assert(ref->get_type_code() == vpiModPathIn); return 0; } static int modpath_src_free_object( vpiHandle ref ) { - assert( (ref->vpi_type->type_code == vpiModPathIn ) ); + assert( ref->get_type_code() == vpiModPathIn ); free ( ref ) ; return 1 ; } @@ -838,7 +836,7 @@ static void modpath_src_put_delays (vpiHandle ref, p_vpi_delay delays) { vvp_time64_t tmp[12]; int idx; - struct __vpiModPathSrc * src = vpip_modpath_src_from_handle( ref) ; + struct __vpiModPathSrc * src = dynamic_cast<__vpiModPathSrc*>(ref) ; assert(src) ; vvp_fun_modpath_src *fun = dynamic_cast(src->net->fun); @@ -908,7 +906,7 @@ static void modpath_src_put_delays (vpiHandle ref, p_vpi_delay delays) static void modpath_src_get_delays ( vpiHandle ref, p_vpi_delay delays ) { - struct __vpiModPathSrc*src = vpip_modpath_src_from_handle( ref) ; + struct __vpiModPathSrc*src = dynamic_cast<__vpiModPathSrc*>(ref) ; assert(src); vvp_fun_modpath_src *fun = dynamic_cast(src->net->fun); @@ -944,7 +942,7 @@ static void modpath_src_get_delays ( vpiHandle ref, p_vpi_delay delays ) static int pathterm_get(int code, vpiHandle ref) { - struct __vpiModPathTerm*obj = vpip_modpath_term_from_handle(ref); + struct __vpiModPathTerm*obj = dynamic_cast<__vpiModPathTerm*>(ref); assert(obj); switch (code) { @@ -957,7 +955,7 @@ static int pathterm_get(int code, vpiHandle ref) static vpiHandle pathterm_get_handle(int code, vpiHandle ref) { - struct __vpiModPathTerm*obj = vpip_modpath_term_from_handle(ref); + struct __vpiModPathTerm*obj = dynamic_cast<__vpiModPathTerm*>(ref); assert(obj); switch (code) { @@ -987,6 +985,11 @@ static const struct __vpirt vpip_modpath_src_rt = { modpath_src_put_delays }; +inline __vpiModPathSrc::__vpiModPathSrc() +: __vpiHandle(&vpip_modpath_src_rt) +{ +} + static const struct __vpirt vpip_modpath_term_rt = { vpiPathTerm, pathterm_get, @@ -1001,9 +1004,13 @@ static const struct __vpirt vpip_modpath_term_rt = { 0 // vpi_put_delays }; +inline __vpiModPathTerm::__vpiModPathTerm() +: __vpiHandle(&vpip_modpath_term_rt) +{ +} + static void initialize_path_term(struct __vpiModPathTerm&obj) { - obj.base.vpi_type = &vpip_modpath_term_rt; obj.expr = 0; obj.edge = vpiNoEdge; } @@ -1021,7 +1028,7 @@ static unsigned mp_count = 0; struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) { - struct __vpiModPath*obj = (struct __vpiModPath *)calloc(1, sizeof ( struct __vpiModPath ) ); + struct __vpiModPath*obj = new __vpiModPath; obj->scope = vpip_peek_current_scope ( ); initialize_path_term(obj->path_term_out); @@ -1058,40 +1065,12 @@ void modpath_delete() struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path, vvp_net_t *net) { - struct __vpiModPathSrc *obj = (struct __vpiModPathSrc *) calloc (1, sizeof ( struct __vpiModPathSrc ) ) ; + struct __vpiModPathSrc *obj = new __vpiModPathSrc; - obj->base.vpi_type = &vpip_modpath_src_rt; obj->dest = path; + obj->type = 0; obj->net = net; initialize_path_term(obj->path_term_in); return obj; } - - -/* - this routine will safely convert a modpath vpiHandle - to a struct __vpiModPath { } -*/ - -struct __vpiModPathTerm* vpip_modpath_term_from_handle(vpiHandle ref) -{ - if (ref->vpi_type->type_code != vpiPathTerm) - return 0; - - return (struct __vpiModPathTerm*) ref; -} - -/* - this routine will safely convert a modpathsrc vpiHandle - to a struct __vpiModPathSrc { }, This is equivalent to a - vpiModPathIn handle -*/ - -struct __vpiModPathSrc* vpip_modpath_src_from_handle(vpiHandle ref) -{ - if (ref->vpi_type->type_code != vpiModPath) - return 0; - - return (struct __vpiModPathSrc *) ref; -} diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 13ad72b4b..eacb17fc9 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -25,39 +25,25 @@ # include # include -struct enumconst_s { - struct __vpiHandle base; +struct enumconst_s : public __vpiHandle { + enumconst_s(); + const char*name; vvp_vector2_t val2; vvp_vector4_t val4; }; -static struct enumconst_s* enumconst_from_handle(vpiHandle obj) -{ - if (obj->vpi_type->type_code == vpiEnumConst) - return (struct enumconst_s*) obj; - else - return 0; -} +struct __vpiEnumTypespec : public __vpiHandle { + __vpiEnumTypespec(); -struct __vpiEnumTypespec { - struct __vpiHandle base; std::vector names; int base_type_code; bool is_signed; }; -static struct __vpiEnumTypespec* vpip_enum_typespec_from_handle(vpiHandle obj) -{ - if (obj->vpi_type->type_code == vpiEnumTypespec) - return (struct __vpiEnumTypespec*) obj; - - return 0; -} - static int enum_type_get(int code, vpiHandle obj) { - struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); + struct __vpiEnumTypespec*ref = dynamic_cast<__vpiEnumTypespec*>(obj); assert(ref); switch (code) { @@ -84,14 +70,14 @@ static int enum_type_get(int code, vpiHandle obj) static vpiHandle enum_type_iterate(int code, vpiHandle obj) { - struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); + struct __vpiEnumTypespec*ref = dynamic_cast<__vpiEnumTypespec*>(obj); assert(ref); if (code == vpiEnumConst) { vpiHandle*args = (vpiHandle*) calloc(ref->names.size(), sizeof(vpiHandle*)); for (size_t idx = 0 ; idx < ref->names.size() ; idx += 1) - args[idx] = vpi_handle(&ref->names[idx]); + args[idx] = &ref->names[idx]; return vpip_make_iterator(ref->names.size(), args, true); } @@ -113,9 +99,14 @@ static const struct __vpirt enum_type_rt = { 0, //enum_type_put_delays }; +inline __vpiEnumTypespec::__vpiEnumTypespec() +: __vpiHandle(&enum_type_rt) +{ +} + static int enum_name_get(int code, vpiHandle obj) { - struct enumconst_s*ref = enumconst_from_handle(obj); + struct enumconst_s*ref = dynamic_cast(obj); assert(ref); switch (code) { @@ -128,7 +119,7 @@ static int enum_name_get(int code, vpiHandle obj) static char* enum_name_get_str(int code, vpiHandle obj) { - struct enumconst_s*ref = enumconst_from_handle(obj); + struct enumconst_s*ref = dynamic_cast(obj); assert(ref); switch (code) { @@ -141,7 +132,7 @@ static char* enum_name_get_str(int code, vpiHandle obj) static void enum_name_get_value(vpiHandle obj, p_vpi_value value) { - struct enumconst_s*ref = enumconst_from_handle(obj); + struct enumconst_s*ref = dynamic_cast(obj); assert(ref); if (ref->val4.size() > 0) @@ -164,11 +155,15 @@ static const struct __vpirt enum_name_rt = { 0, //enum_name_put_delays }; +inline enumconst_s::enumconst_s() +: __vpiHandle(&enum_name_rt) +{ +} + void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names) { struct __vpiEnumTypespec*spec = new struct __vpiEnumTypespec; - spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; spec->base_type_code = vpiBitVar; @@ -177,14 +172,13 @@ void compile_enum2_type(char*label, long width, bool signed_flag, for (list::iterator cur = names->begin() ; cur != names->end() ; ++cur, ++idx) { assert(cur->val4 == 0); - spec->names[idx].base.vpi_type = &enum_name_rt; spec->names[idx].name = cur->text; spec->names[idx].val2 = vvp_vector2_t(cur->val2, width); } assert(idx == spec->names.size()); - compile_vpi_symbol(label, vpi_handle(spec)); - vpip_attach_to_current_scope(vpi_handle(spec)); + compile_vpi_symbol(label, spec); + vpip_attach_to_current_scope(spec); free(label); delete names; @@ -194,7 +188,6 @@ void compile_enum4_type(char*label, long width, bool signed_flag, std::list*names) { struct __vpiEnumTypespec*spec = new struct __vpiEnumTypespec; - spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; spec->base_type_code = vpiReg; @@ -202,7 +195,6 @@ void compile_enum4_type(char*label, long width, bool signed_flag, size_t idx = 0; for (list::iterator cur = names->begin() ; cur != names->end() ; ++cur, ++idx) { - spec->names[idx].base.vpi_type = &enum_name_rt; spec->names[idx].name = cur->text; assert(cur->val4); spec->names[idx].val4 = vector4_from_text(cur->val4, width); @@ -211,8 +203,8 @@ void compile_enum4_type(char*label, long width, bool signed_flag, } assert(idx == spec->names.size()); - compile_vpi_symbol(label, vpi_handle(spec)); - vpip_attach_to_current_scope(vpi_handle(spec)); + compile_vpi_symbol(label, spec); + vpip_attach_to_current_scope(spec); free(label); delete names; @@ -221,7 +213,7 @@ void compile_enum4_type(char*label, long width, bool signed_flag, #ifdef CHECK_WITH_VALGRIND void enum_delete(vpiHandle item) { - struct __vpiEnumTypespec*obj = (struct __vpiEnumTypespec*) item; + struct __vpiEnumTypespec*obj = dynamic_cast<__vpiEnumTypespec*>(item); for (vector::iterator iter = obj->names.begin(); iter != obj->names.end(); ++ iter ) { diff --git a/vvp/file_line.cc b/vvp/file_line.cc index 924f7d710..22f95fd4b 100644 --- a/vvp/file_line.cc +++ b/vvp/file_line.cc @@ -19,8 +19,9 @@ # include "compile.h" # include "vpi_priv.h" -struct __vpiFileLine { - struct __vpiHandle base; +struct __vpiFileLine : public __vpiHandle { + __vpiFileLine(); + const char *description; unsigned file_idx; unsigned lineno; @@ -31,9 +32,8 @@ bool code_is_instrumented = false; static int file_line_get(int type, vpiHandle ref) { - struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref; - - assert(ref->vpi_type->type_code == _vpiFileLine); + struct __vpiFileLine*rfp = dynamic_cast<__vpiFileLine*>(ref); + assert(rfp); switch (type) { case vpiLineNo: @@ -45,9 +45,8 @@ static int file_line_get(int type, vpiHandle ref) static char *file_line_get_str(int type, vpiHandle ref) { - struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref; - - assert(ref->vpi_type->type_code == _vpiFileLine); + struct __vpiFileLine*rfp = dynamic_cast<__vpiFileLine*>(ref); + assert(rfp); switch (type) { case vpiFile: @@ -75,6 +74,11 @@ static const struct __vpirt vpip_file_line_rt = { 0 }; +inline __vpiFileLine::__vpiFileLine() +: __vpiHandle(&vpip_file_line_rt) +{ +} + vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) { struct __vpiFileLine*obj = new struct __vpiFileLine; @@ -83,11 +87,10 @@ vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) show_file_line = true; code_is_instrumented = true; - obj->base.vpi_type = &vpip_file_line_rt; if (description) obj->description = vpip_name_string(description); else obj->description = 0; obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } diff --git a/vvp/schedule.cc b/vvp/schedule.cc index f2ab78f54..83d627ae2 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -123,7 +123,7 @@ void vthread_event_s::single_step_display(void) { struct __vpiScope*scope = vthread_scope(thr); cerr << "vthread_event: Resume thread" - << " scope=" << vpip_get_str(vpiFullName, scope) + << " scope=" << scope->vpi_get_str(vpiFullName) << endl; } @@ -156,7 +156,7 @@ void del_thr_event_s::single_step_display(void) { struct __vpiScope*scope = vthread_scope(thr); cerr << "del_thr_event: Reap completed thread" - << " scope=" << vpip_get_str(vpiFullName, scope) << endl; + << " scope=" << scope->vpi_get_str(vpiFullName) << endl; } struct assign_vector4_event_s : public event_s { diff --git a/vvp/stop.cc b/vvp/stop.cc index 438a8785a..b25a432fc 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -101,7 +101,7 @@ static void cmd_call(unsigned argc, char*argv[]) .(dot) string. This represents the handle for the current scope. */ if (stop_current_scope && (strcmp(argv[idx+1], ".") == 0)) - handle = &stop_current_scope->base; + handle = stop_current_scope; /* Is the argument a quoted string? */ if (handle == 0 && argv[idx+1][0] == '"') { @@ -119,7 +119,7 @@ static void cmd_call(unsigned argc, char*argv[]) /* Is the argument a decimal constant? */ if (handle == 0 && strspn(argv[idx+1],"0123456789") == strlen(argv[idx+1])) { - handle = vpip_make_dec_const(strtol(argv[idx+1],0,10)); + handle = new __vpiDecConst(strtol(argv[idx+1],0,10)); add_to_free_list = true; } @@ -130,14 +130,14 @@ static void cmd_call(unsigned argc, char*argv[]) struct __vpiScope*scope; const char*name; - switch (table[tmp]->vpi_type->type_code) { + switch (table[tmp]->get_type_code()) { case vpiModule: case vpiFunction: case vpiTask: case vpiNamedBegin: case vpiNamedFork: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); if (strcmp(scope->name, argv[idx+1]) == 0) handle = table[tmp]; break; @@ -229,29 +229,29 @@ static void cmd_list(unsigned, char*[]) struct __vpiScope*scope; struct __vpiSignal*sig; - switch (table[idx]->vpi_type->type_code) { + switch (table[idx]->get_type_code()) { case vpiModule: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("module : %s\n", scope->name); break; case vpiTask: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("task : %s\n", scope->name); break; case vpiFunction: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("function: %s\n", scope->name); break; case vpiNamedBegin: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("block : %s\n", scope->name); break; case vpiNamedFork: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("fork : %s\n", scope->name); break; @@ -260,7 +260,7 @@ static void cmd_list(unsigned, char*[]) break; case vpiReg: - sig = (struct __vpiSignal*) table[idx]; + sig = dynamic_cast<__vpiSignal*>(table[idx]); if ((sig->msb == 0) && (sig->lsb == 0)) printf("reg : %s%s\n", vpi_get_str(vpiName, table[idx]), @@ -273,7 +273,7 @@ static void cmd_list(unsigned, char*[]) break; case vpiNet: - sig = (struct __vpiSignal*) table[idx]; + sig = dynamic_cast<__vpiSignal*>(table[idx]); if ((sig->msb == 0) && (sig->lsb == 0)) printf("net : %s%s\n", vpi_get_str(vpiName, table[idx]), @@ -287,7 +287,7 @@ static void cmd_list(unsigned, char*[]) default: printf("%8d: \n", - table[idx]->vpi_type->type_code); + table[idx]->get_type_code()); break; } @@ -329,10 +329,10 @@ static void cmd_push(unsigned argc, char* argv[]) child = 0; unsigned tmp; for (tmp = 0 ; tmp < ntable ; tmp += 1) { - if (table[tmp]->vpi_type->type_code != vpiModule) + if (table[tmp]->get_type_code() != vpiModule) continue; - struct __vpiScope*cp = (struct __vpiScope*) table[tmp]; + struct __vpiScope*cp = dynamic_cast<__vpiScope*>(table[tmp]); /* This is a scope, and the name matches, then report that I found the child. */ @@ -392,15 +392,12 @@ static void cmd_where(unsigned, char*[]) struct __vpiScope*cur = stop_current_scope; while (cur) { - switch (cur->base.vpi_type->type_code) { + switch (cur->get_type_code()) { case vpiModule: - printf("module %s\n", - cur->name); + printf("module %s\n", cur->name); break; default: - printf("scope (%d) %s;\n", - cur->base.vpi_type->type_code, - cur->name); + printf("scope (%d) %s;\n", cur->get_type_code(), cur->name); break; } diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 1ff3b9352..5a3af8215 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -60,6 +60,11 @@ const struct __vpirt callback_rt = { 0, 0 }; +inline __vpiCallback::__vpiCallback() +: __vpiHandle(&callback_rt) +{ +} + /* * Callback handles are created when the VPI function registers a @@ -85,14 +90,12 @@ struct sync_cb : public vvp_gen_event_s { virtual void run_run(); }; - struct __vpiCallback* new_vpi_callback() { struct __vpiCallback* obj; obj = new __vpiCallback; - obj->base.vpi_type = &callback_rt; obj->cb_sync = 0; obj->next = 0; return obj; @@ -101,8 +104,6 @@ struct __vpiCallback* new_vpi_callback() void delete_vpi_callback(struct __vpiCallback* ref) { assert(ref); - assert(ref->base.vpi_type); - assert(ref->base.vpi_type->type_code == vpiCallback); delete ref->cb_sync; delete ref; } @@ -141,9 +142,8 @@ static struct __vpiCallback* make_value_change(p_cb_data data) obj->cb_data.value = &obj->cb_value; assert(data->obj); - assert(data->obj->vpi_type); - switch (data->obj->vpi_type->type_code) { + switch (data->obj->get_type_code()) { case vpiReg: case vpiNet: @@ -156,7 +156,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) /* Attach the callback to the vvp_fun_signal node by putting it in the vpi_callbacks list. */ struct __vpiSignal*sig; - sig = reinterpret_cast<__vpiSignal*>(data->obj); + sig = dynamic_cast<__vpiSignal*>(data->obj); vvp_net_fil_t*sig_fil; sig_fil = dynamic_cast(sig->node->fil); @@ -172,7 +172,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) case vpiNamedEvent: struct __vpiNamedEvent*nev; - nev = reinterpret_cast<__vpiNamedEvent*>(data->obj); + nev = dynamic_cast<__vpiNamedEvent*>(data->obj); obj->next = nev->callbacks; nev->callbacks = obj; break; @@ -199,7 +199,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) default: fprintf(stderr, "make_value_change: sorry: I cannot callback " "values on type code=%d\n", - data->obj->vpi_type->type_code); + data->obj->get_type_code()); delete obj; return 0; } @@ -473,7 +473,7 @@ vpiHandle vpi_register_cb(p_cb_data data) break; } - return obj? &obj->base : 0; + return obj; } /* @@ -483,11 +483,8 @@ vpiHandle vpi_register_cb(p_cb_data data) */ PLI_INT32 vpi_remove_cb(vpiHandle ref) { - assert(ref); - assert(ref->vpi_type); - assert(ref->vpi_type->type_code == vpiCallback); - - struct __vpiCallback*obj = (struct __vpiCallback*)ref; + struct __vpiCallback*obj = dynamic_cast<__vpiCallback*>(ref); + assert(obj); obj->cb_data.cb_rtn = 0; return 1; diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 82464b112..d1c639afe 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -35,13 +35,8 @@ static int string_get(int code, vpiHandle ref) switch (code) { case vpiSize: - rfp = (struct __vpiStringConst*)ref; - - assert((ref->vpi_type->type_code == vpiConstant) - || ((ref->vpi_type->type_code == vpiParameter))); - - //fprintf(stderr, "String:|%s|, Length: %d\n", rfp->value, strlen(rfp->value)); - return strlen(rfp->value)*8; + rfp = dynamic_cast<__vpiStringConst*>(ref); + return strlen(rfp->value)*8; case vpiSigned: return 0; @@ -69,14 +64,11 @@ static void string_value(vpiHandle ref, p_vpi_value vp) { unsigned uint_value; p_vpi_vecval vecp; - struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref; + struct __vpiStringConst*rfp = dynamic_cast<__vpiStringConst*>(ref); int size = strlen(rfp->value); char*rbuf = 0; char*cp; - assert((ref->vpi_type->type_code == vpiConstant) - || ((ref->vpi_type->type_code == vpiParameter))); - switch (vp->format) { case vpiObjTypeVal: /* String parameters by default have vpiStringVal values. */ @@ -187,11 +179,18 @@ static const struct __vpirt vpip_string_rt = { 0, 0 }; +inline __vpiStringConst::__vpiStringConst() +: __vpiHandle(&vpip_string_rt) +{ +} + +struct __vpiStringConstTEMP : public __vpiStringConst { + __vpiStringConstTEMP(); +}; static int free_temp_string(vpiHandle obj) { - struct __vpiStringConst*rfp = (struct __vpiStringConst*)obj; - assert(obj->vpi_type->type_code == vpiConstant); + struct __vpiStringConstTEMP*rfp = dynamic_cast<__vpiStringConstTEMP*>(obj); delete [] rfp->value; free(rfp); @@ -212,6 +211,11 @@ static const struct __vpirt vpip_string_temp_rt = { 0 }; +inline __vpiStringConstTEMP::__vpiStringConstTEMP() +: __vpiStringConst(&vpip_string_temp_rt) +{ +} + /* * Strings are described at the level of the vvp source as a string * with literal characters or octal escapes. No other escapes are @@ -247,20 +251,17 @@ vpiHandle vpip_make_string_const(char*text, bool persistent_flag) { struct __vpiStringConst*obj; - obj = (struct __vpiStringConst*) - malloc(sizeof (struct __vpiStringConst)); - obj->base.vpi_type = persistent_flag - ? &vpip_string_rt - : &vpip_string_temp_rt; + obj = persistent_flag? new __vpiStringConst : new __vpiStringConstTEMP; obj->value = text; obj->value_len = 0; vpip_process_string(obj); - return &obj->base; + return obj; } struct __vpiStringParam : public __vpiStringConst { + __vpiStringParam(); const char*basename; struct __vpiScope* scope; unsigned file_idx; @@ -269,9 +270,8 @@ struct __vpiStringParam : public __vpiStringConst { static int string_param_get(int code, vpiHandle ref) { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); + struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(ref); + assert(ref); if (code == vpiLineNo) { return rfp->lineno; @@ -282,26 +282,24 @@ static int string_param_get(int code, vpiHandle ref) static char* string_param_get_str(int code, vpiHandle obj) { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(obj); + assert(rfp); if (code == vpiFile) { return simple_set_rbuf_str(file_names[rfp->file_idx]); } - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + return generic_get_str(code, rfp->scope, rfp->basename, NULL); } static vpiHandle string_param_handle(int code, vpiHandle obj) { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(obj); + assert(rfp); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiModule: return vpip_module(rfp->scope); @@ -325,15 +323,16 @@ static const struct __vpirt vpip_string_param_rt = { 0 }; +inline __vpiStringParam::__vpiStringParam() +: __vpiStringConst(&vpip_string_param_rt) +{ +} + vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { - struct __vpiStringParam*obj; - - obj = (struct __vpiStringParam*) - malloc(sizeof (struct __vpiStringParam)); - obj->base.vpi_type = &vpip_string_param_rt; + struct __vpiStringParam*obj = new __vpiStringParam; obj->value = text; obj->value_len = 0; obj->basename = name; @@ -343,14 +342,12 @@ vpiHandle vpip_make_string_param(char*name, char*text, vpip_process_string(obj); - return &obj->base; + return obj; } static int binary_get(int code, vpiHandle ref) { - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref; - assert(ref->vpi_type->type_code == vpiConstant - || ref->vpi_type->type_code == vpiParameter); + struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(ref); switch (code) { case vpiConstType: @@ -384,11 +381,7 @@ static int binary_get(int code, vpiHandle ref) static void binary_value(vpiHandle ref, p_vpi_value vp) { - assert(ref->vpi_type->type_code == vpiConstant - || ref->vpi_type->type_code == vpiParameter); - - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref; - + struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(ref); switch (vp->format) { @@ -428,6 +421,11 @@ static const struct __vpirt vpip_binary_rt = { 0 }; +inline __vpiBinaryConst::__vpiBinaryConst() +: __vpiHandle(&vpip_binary_rt) +{ +} + /* * Make a VPI constant from a vector string. The string is normally a * ASCII string, with each letter a 4-value bit. The first character @@ -435,10 +433,7 @@ static const struct __vpirt vpip_binary_rt = { */ vpiHandle vpip_make_binary_const(unsigned wid, const char*bits) { - struct __vpiBinaryConst*obj; - - obj = new __vpiBinaryConst; - obj->base.vpi_type = &vpip_binary_rt; + struct __vpiBinaryConst*obj = new __vpiBinaryConst; obj->signed_flag = 0; obj->sized_flag = 0; @@ -451,7 +446,7 @@ vpiHandle vpip_make_binary_const(unsigned wid, const char*bits) obj->bits = vector4_from_text(bp, wid); - return &(obj->base); + return obj; } vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) @@ -482,6 +477,7 @@ vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) } struct __vpiBinaryParam : public __vpiBinaryConst { + __vpiBinaryParam(); const char*basename; struct __vpiScope*scope; unsigned file_idx; @@ -490,9 +486,7 @@ struct __vpiBinaryParam : public __vpiBinaryConst { static int binary_param_get(int code, vpiHandle ref) { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); + struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(ref); if (code == vpiLineNo) { return rfp->lineno; @@ -503,26 +497,22 @@ static int binary_param_get(int code, vpiHandle ref) static char* binary_param_get_str(int code, vpiHandle obj) { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(obj); if (code == vpiFile) { return simple_set_rbuf_str(file_names[rfp->file_idx]); } - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + return generic_get_str(code, rfp->scope, rfp->basename, NULL); } static vpiHandle binary_param_handle(int code, vpiHandle obj) { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(obj); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiModule: return vpip_module(rfp->scope); @@ -545,6 +535,10 @@ static const struct __vpirt vpip_binary_param_rt = { 0, 0 }; +inline __vpiBinaryParam::__vpiBinaryParam() +: __vpiBinaryConst(&vpip_binary_param_rt) +{ +} vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, @@ -552,7 +546,6 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, { struct __vpiBinaryParam*obj = new __vpiBinaryParam; - obj->base.vpi_type = &vpip_binary_param_rt; obj->bits = bits; obj->signed_flag = signed_flag? 1 : 0; obj->sized_flag = 0; @@ -561,7 +554,7 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } @@ -597,8 +590,7 @@ static int dec_get(int code, vpiHandle) static void dec_value(vpiHandle ref, p_vpi_value vp) { - struct __vpiDecConst*rfp = (struct __vpiDecConst*)ref; - assert(ref->vpi_type->type_code == vpiConstant); + struct __vpiDecConst*rfp = dynamic_cast<__vpiDecConst*>(ref); char*rbuf = need_result_buf(64 + 1, RBUF_VAL); char*cp = rbuf; @@ -658,25 +650,12 @@ static const struct __vpirt vpip_dec_rt = { 0, 0 }; - -vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value) +__vpiDecConst::__vpiDecConst(int val) +: __vpiHandle(&vpip_dec_rt) { - obj->base.vpi_type = &vpip_dec_rt; - obj->value = value; - - return &(obj->base); + value = val; } -vpiHandle vpip_make_dec_const(int value) -{ - struct __vpiDecConst*obj; - - obj = (struct __vpiDecConst*) - malloc(sizeof (struct __vpiDecConst)); - return vpip_make_dec_const(obj, value); -} - - static int real_get(int code, vpiHandle) { @@ -711,10 +690,7 @@ static int real_get(int code, vpiHandle) static void real_value(vpiHandle ref, p_vpi_value vp) { - struct __vpiRealConst*rfp = (struct __vpiRealConst*)ref; - assert((ref->vpi_type->type_code == vpiConstant) || - (ref->vpi_type->type_code == vpiParameter)); - + struct __vpiRealConst*rfp = dynamic_cast<__vpiRealConst*>(ref); vpip_real_get_value(rfp->value, vp); } @@ -731,22 +707,20 @@ static const struct __vpirt vpip_real_rt = { 0, 0 }; - -vpiHandle vpip_make_real_const(struct __vpiRealConst*obj, double value) +inline __vpiRealConst::__vpiRealConst() +: __vpiHandle(&vpip_real_rt) { - obj->base.vpi_type = &vpip_real_rt; - obj->value = value; - return &(obj->base); } vpiHandle vpip_make_real_const(double value) { - struct __vpiRealConst*obj; - obj =(struct __vpiRealConst*) malloc(sizeof (struct __vpiRealConst)); - return vpip_make_real_const(obj, value); + struct __vpiRealConst*obj = new __vpiRealConst; + obj->value = value; + return obj; } struct __vpiRealParam : public __vpiRealConst { + __vpiRealParam(); const char*basename; struct __vpiScope* scope; unsigned file_idx; @@ -755,9 +729,7 @@ struct __vpiRealParam : public __vpiRealConst { static int real_param_get(int code, vpiHandle ref) { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); + struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(ref); if (code == vpiLineNo) { return rfp->lineno; @@ -768,26 +740,22 @@ static int real_param_get(int code, vpiHandle ref) static char* real_param_get_str(int code, vpiHandle obj) { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(obj); if (code == vpiFile) { return simple_set_rbuf_str(file_names[rfp->file_idx]); } - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + return generic_get_str(code, rfp->scope, rfp->basename, NULL); } static vpiHandle real_param_handle(int code, vpiHandle obj) { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); + struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(obj); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiModule: return vpip_module(rfp->scope); @@ -810,22 +778,24 @@ static const struct __vpirt vpip_real_param_rt = { 0, 0 }; +inline __vpiRealParam::__vpiRealParam() +: __vpiRealConst(&vpip_real_param_rt) +{ +} + vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) { - struct __vpiRealParam*obj; + struct __vpiRealParam*obj = new __vpiRealParam; - obj = (struct __vpiRealParam*) - malloc(sizeof (struct __vpiRealParam)); - obj->base.vpi_type = &vpip_real_param_rt; obj->value = value; obj->basename = name; obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -834,20 +804,20 @@ void constant_delete(vpiHandle item) assert(item->vpi_type->type_code == vpiConstant); switch(vpi_get(vpiConstType, item)) { case vpiStringConst: { - struct __vpiStringConst*rfp = (struct __vpiStringConst*)item; + struct __vpiStringConst*rfp = dynamic_cast<__vpiStringConst*>(item); delete [] rfp->value; free(rfp); break; } case vpiDecConst: { - struct __vpiDecConst*rfp = (struct __vpiDecConst*)item; + struct __vpiDecConst*rfp = dynamic_cast<__vpiDecConst*>(item); free(rfp); break; } case vpiBinaryConst: { - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)item; + struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(item); delete rfp; break; } case vpiRealConst: { - struct __vpiRealConst*rfp = (struct __vpiRealConst*)item; + struct __vpiRealConst*rfp = dynamic_cast<__vpiRealConst*>(item); free(rfp); break; } default: @@ -859,18 +829,18 @@ void parameter_delete(vpiHandle item) { switch(vpi_get(vpiConstType, item)) { case vpiStringConst: { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)item; + struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(item); delete [] rfp->basename; delete [] rfp->value; free(rfp); break; } case vpiBinaryConst: { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)item; + struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(item); delete [] rfp->basename; delete rfp; break; } case vpiRealConst: { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)item; + struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(item); delete [] rfp->basename; free(rfp); break; } diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 49c01cab0..c28f0aa58 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2012 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 @@ -27,9 +27,8 @@ static int named_event_get(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; + struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); + assert(obj); switch (code) { @@ -42,25 +41,23 @@ static int named_event_get(int code, vpiHandle ref) static char* named_event_get_str(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; + struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); + assert(obj); if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } - return generic_get_str(code, &obj->scope->base, obj->name, NULL); + return generic_get_str(code, obj->scope, obj->name, NULL); } static vpiHandle named_event_get_handle(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; + struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); + assert(obj); switch (code) { case vpiScope: - return &obj->scope->base; + return obj->scope; case vpiModule: return vpip_module(obj->scope); @@ -83,19 +80,21 @@ static const struct __vpirt vpip_named_event_rt = { 0, 0 }; +inline __vpiNamedEvent::__vpiNamedEvent() +: __vpiHandle(&vpip_named_event_rt) +{ +} vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*) - malloc(sizeof(struct __vpiNamedEvent)); + struct __vpiNamedEvent*obj = new __vpiNamedEvent; - obj->base.vpi_type = &vpip_named_event_rt; obj->name = vpip_name_string(name); obj->scope = vpip_peek_current_scope(); obj->funct = funct; obj->callbacks = 0; - return &obj->base; + return obj; } /* @@ -113,9 +112,7 @@ vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) */ void vpip_run_named_event_callbacks(vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; + struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); struct __vpiCallback*next = obj->callbacks; struct __vpiCallback*prev = 0; diff --git a/vvp/vpi_iter.cc b/vvp/vpi_iter.cc index f548e796a..229e96ca7 100644 --- a/vvp/vpi_iter.cc +++ b/vvp/vpi_iter.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,8 +28,8 @@ static int iterator_free_object(vpiHandle ref) { - struct __vpiIterator*hp = (struct __vpiIterator*)ref; - assert(ref->vpi_type->type_code == vpiIterator); + struct __vpiIterator*hp = dynamic_cast<__vpiIterator*>(ref); + assert(hp); if (hp->free_args_flag) free(hp->args); @@ -51,20 +51,22 @@ static const struct __vpirt vpip_iterator_rt = { 0, // vpi_get_delay 0 // vpi_put_delay }; +inline __vpiIterator::__vpiIterator() +: __vpiHandle(&vpip_iterator_rt) +{ +} vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, bool free_args_flag) { - struct __vpiIterator*res = (struct __vpiIterator*) - calloc(1, sizeof(struct __vpiIterator)); - res->base.vpi_type = &vpip_iterator_rt; + struct __vpiIterator*res = new __vpiIterator; res->args = args; res->nargs = nargs; res->next = 0; res->free_args_flag = free_args_flag; - return &(res->base); + return res; } /* @@ -79,25 +81,14 @@ vpiHandle vpi_scan(vpiHandle ref) return 0; } - if (ref->vpi_type->type_code != vpiIterator) { - fprintf(stderr, "ERROR: vpi_scan argument is " - "inappropriate vpiType code %d\n", - ref->vpi_type->type_code); - assert(0); - return 0; + if (struct __vpiIterator*hp = dynamic_cast<__vpiIterator*>(ref)) { + if (hp->next == hp->nargs) { + vpi_free_object(ref); + return 0; + } + + return hp->args[hp->next++]; } - struct __vpiIterator*hp = (struct __vpiIterator*)ref; - assert(ref); - assert(ref->vpi_type->type_code == vpiIterator); - - if (ref->vpi_type->index_) - return (ref->vpi_type->index_(ref, 0)); - - if (hp->next == hp->nargs) { - vpi_free_object(ref); - return 0; - } - - return hp->args[hp->next++]; + return ref->vpi_index(0); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index f1c2ab814..b8e5f6d4d 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2012 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 @@ -67,11 +67,11 @@ struct __vpiScope* vpip_scope(__vpiRealVar*sig) vpiHandle vpip_module(struct __vpiScope*scope) { - while(scope && scope->base.vpi_type->type_code != vpiModule) { + while(scope && scope->get_type_code() != vpiModule) { scope = scope->scope; } assert(scope); - return &scope->base; + return scope; } const char *vpip_string(const char*str) @@ -165,17 +165,13 @@ PLI_INT32 vpi_compare_objects(vpiHandle obj1, vpiHandle obj2) */ void vpi_get_systf_info(vpiHandle ref, p_vpi_systf_data data) { - assert((ref->vpi_type->type_code == vpiUserSystf) || - (ref->vpi_type->type_code == vpiSysTaskCall) || - (ref->vpi_type->type_code == vpiSysFuncCall)); - - struct __vpiUserSystf* rfp; - if (ref->vpi_type->type_code == vpiUserSystf) { - rfp = (struct __vpiUserSystf*)ref; - } else { - struct __vpiSysTaskCall*call = (struct __vpiSysTaskCall*)ref; + struct __vpiUserSystf* rfp = dynamic_cast<__vpiUserSystf*>(ref); + if (rfp == 0) { + struct __vpiSysTaskCall*call = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(call); rfp = call->defn; } + /* Assert that vpiUserDefn is true! */ assert(rfp->is_user_defn); @@ -204,10 +200,7 @@ PLI_INT32 vpi_free_object(vpiHandle ref) } assert(ref); - if (ref->vpi_type->vpi_free_object_ == 0) - rtn = 1; - else - rtn = ref->vpi_type->vpi_free_object_(ref); + rtn = __vpiHandle::vpi_free_object(ref); if (vpi_trace) fprintf(vpi_trace, " --> %d\n", rtn); @@ -327,25 +320,16 @@ PLI_INT32 vpi_get(int property, vpiHandle ref) if (property == vpiType) { if (vpi_trace) { fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n", - ref, vpi_type_values(ref->vpi_type->type_code)); + ref, vpi_type_values(ref->get_type_code())); } - if (ref->vpi_type->type_code == vpiMemory && is_net_array(ref)) + if (ref->get_type_code() == vpiMemory && is_net_array(ref)) return vpiNetArray; else - return ref->vpi_type->type_code; + return ref->get_type_code(); } - if (ref->vpi_type->vpi_get_ == 0) { - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get(%s, %p) --X\n", - vpi_property_str(property), ref); - } - - return vpiUndefined; - } - - int res = (ref->vpi_type->vpi_get_)(property, ref); + int res = ref->vpi_get(property); if (vpi_trace) { fprintf(vpi_trace, "vpi_get(%s, %p) --> %d\n", @@ -380,30 +364,22 @@ char* vpi_get_str(PLI_INT32 property, vpiHandle ref) if (property == vpiType) { if (vpi_trace) { fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n", - ref, vpi_type_values(ref->vpi_type->type_code)); + ref, vpi_type_values(ref->get_type_code())); } PLI_INT32 type; - if (ref->vpi_type->type_code == vpiMemory && is_net_array(ref)) + if (ref->get_type_code() == vpiMemory && is_net_array(ref)) type = vpiNetArray; else - type = ref->vpi_type->type_code; + type = ref->get_type_code(); return (char *)vpi_type_values(type); } - if (ref->vpi_type->vpi_get_str_ == 0) { - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get_str(%s, %p) --X\n", - vpi_property_str(property), ref); - } - return 0; - } - - char*res = (char*)(ref->vpi_type->vpi_get_str_)(property, ref); + char*res = ref->vpi_get_str(property); if (vpi_trace) { fprintf(vpi_trace, "vpi_get_str(%s, %p) --> %s\n", - vpi_property_str(property), ref, res); + vpi_property_str(property), ref, res? res : ""); } return res; @@ -418,24 +394,24 @@ int vpip_time_units_from_handle(vpiHandle obj) if (obj == 0) return vpip_get_time_precision(); - switch (obj->vpi_type->type_code) { + switch (obj->get_type_code()) { case vpiSysTaskCall: - task = (struct __vpiSysTaskCall*)obj; + task = dynamic_cast<__vpiSysTaskCall*>(obj); return task->scope->time_units; case vpiModule: - scope = (struct __vpiScope*)obj; + scope = dynamic_cast<__vpiScope*>(obj); return scope->time_units; case vpiNet: case vpiReg: - signal = vpip_signal_from_handle(obj); + signal = dynamic_cast<__vpiSignal*>(obj); scope = vpip_scope(signal); return scope->time_units; default: fprintf(stderr, "ERROR: vpip_time_units_from_handle called with " - "object handle type=%u\n", obj->vpi_type->type_code); + "object handle type=%u\n", obj->get_type_code()); assert(0); return 0; } @@ -450,24 +426,24 @@ int vpip_time_precision_from_handle(vpiHandle obj) if (obj == 0) return vpip_get_time_precision(); - switch (obj->vpi_type->type_code) { + switch (obj->get_type_code()) { case vpiSysTaskCall: - task = (struct __vpiSysTaskCall*)obj; + task = dynamic_cast<__vpiSysTaskCall*>(obj); return task->scope->time_precision; case vpiModule: - scope = (struct __vpiScope*)obj; + scope = dynamic_cast<__vpiScope*>(obj); return scope->time_precision; case vpiNet: case vpiReg: - signal = vpip_signal_from_handle(obj); + signal = dynamic_cast<__vpiSignal*>(obj); scope = vpip_scope(signal); return scope->time_precision; default: fprintf(stderr, "ERROR: vpip_time_precision_from_handle called " - "with object handle type=%u\n", obj->vpi_type->type_code); + "with object handle type=%u\n", obj->get_type_code()); assert(0); return 0; } @@ -879,38 +855,34 @@ void vpi_get_value(vpiHandle expr, s_vpi_value*vp) { assert(expr); assert(vp); - if (expr->vpi_type->vpi_get_value_) { - (expr->vpi_type->vpi_get_value_)(expr, vp); - if (vpi_trace) switch (vp->format) { + expr->vpi_get_value(vp); + + if (vpi_trace) switch (vp->format) { case vpiStringVal: fprintf(vpi_trace,"vpi_get_value(%p=<%d>) -> string=\"%s\"\n", - expr, expr->vpi_type->type_code, vp->value.str); + expr, expr->get_type_code(), vp->value.str); break; case vpiBinStrVal: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> binstr=%s\n", - expr->vpi_type->type_code, vp->value.str); + expr->get_type_code(), vp->value.str); break; case vpiIntVal: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> int=%d\n", - expr->vpi_type->type_code, (int)vp->value.integer); + expr->get_type_code(), (int)vp->value.integer); + break; + + case vpiSuppressVal: + fprintf(vpi_trace, "vpi_get_value(<%d>...) -> \n", + expr->get_type_code()); break; default: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> <%d>=?\n", - expr->vpi_type->type_code, (int)vp->format); + expr->get_type_code(), (int)vp->format); } - return; - } - - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get_value(<%d>...) -> \n", - expr->vpi_type->type_code); - } - - vp->format = vpiSuppressVal; } struct vpip_put_value_event : vvp_gen_event_s { @@ -923,7 +895,7 @@ struct vpip_put_value_event : vvp_gen_event_s { void vpip_put_value_event::run_run() { - handle->vpi_type->vpi_put_value_ (handle, &value, flags); + handle->vpi_put_value(&value, flags); switch (value.format) { /* Free the copied string. */ case vpiBinStrVal: @@ -947,7 +919,7 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, { assert(obj); - if (obj->vpi_type->vpi_put_value_ == 0) + if (! obj->can_put_value()) return 0; flags &= ~vpiReturnEvent; @@ -1008,7 +980,7 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, return 0; } - (obj->vpi_type->vpi_put_value_)(obj, vp, flags); + obj->vpi_put_value(vp, flags); return 0; } @@ -1024,11 +996,11 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) if (vpi_trace) { fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) " - "-> %p (%s)\n", &vpip_cur_task->base, + "-> %p (%s)\n", vpip_cur_task, vpip_cur_task->defn->info.tfname); } - return &vpip_cur_task->base; + return vpip_cur_task; } if (ref == 0) { @@ -1037,18 +1009,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) return 0; } - if (ref->vpi_type->handle_ == 0) { - - if (vpi_trace) { - fprintf(vpi_trace, "vpi_handle(%d, %p) -X\n", - (int)type, ref); - } - - return 0; - } - - assert(ref->vpi_type->handle_); - vpiHandle res = (ref->vpi_type->handle_)(type, ref); + vpiHandle res = ref->vpi_handle(type); if (vpi_trace) { fprintf(vpi_trace, "vpi_handle(%d, %p) -> %p\n", @@ -1099,8 +1060,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref) if (ref == 0) rtn = vpi_iterate_global(type); - else if (ref->vpi_type->iterate_) - rtn = (ref->vpi_type->iterate_)(type, ref); + else + rtn = ref->vpi_iterate(type); if (vpi_trace) { fprintf(vpi_trace, "vpi_iterate(%d, %p) ->%s\n", @@ -1113,18 +1074,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref) vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx) { assert(ref); - - if (ref->vpi_type->index_ == 0) - return 0; - - assert(ref->vpi_type->index_); - return (ref->vpi_type->index_)(ref, idx); + return ref->vpi_index(idx); } static vpiHandle find_name(const char *name, vpiHandle handle) { vpiHandle rtn = 0; - struct __vpiScope*ref = (struct __vpiScope*)handle; + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(handle); /* check module names */ if (!strcmp(name, vpi_get_str(vpiName, handle))) @@ -1260,16 +1216,12 @@ void vpi_get_delays(vpiHandle expr, p_vpi_delay delays) assert(expr); assert(delays); - if (expr->vpi_type->vpi_get_delays_) - { - (expr->vpi_type->vpi_get_delays_)(expr, delays); + expr->vpi_get_delays(delays); - if (vpi_trace) - { - fprintf(vpi_trace, - "vpi_get_delays(%p, %p) -->\n", expr, delays); - } - } + if (vpi_trace) { + fprintf(vpi_trace, + "vpi_get_delays(%p, %p) -->\n", expr, delays); + } } @@ -1278,16 +1230,12 @@ void vpi_put_delays(vpiHandle expr, p_vpi_delay delays) assert(expr ); assert(delays ); - if (expr->vpi_type->vpi_put_delays_) - { - (expr->vpi_type->vpi_put_delays_)(expr, delays); + expr->vpi_put_delays(delays); - if (vpi_trace) - { - fprintf(vpi_trace, - "vpi_put_delays(%p, %p) -->\n", expr, delays); - } - } + if (vpi_trace) { + fprintf(vpi_trace, + "vpi_put_delays(%p, %p) -->\n", expr, delays); + } } diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 224997f0e..91fa50628 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -1,7 +1,7 @@ #ifndef __vpi_priv_H #define __vpi_priv_H /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -83,15 +83,6 @@ enum vpi_mode_t { }; extern vpi_mode_t vpi_mode_flag; -/* - * This structure is the very base of a vpiHandle. Every handle - * structure starts with this structure, so that the library can - * internally pass the derived types as pointers to one of these. - */ -struct __vpiHandle { - const struct __vpirt *vpi_type; -}; - /* * Objects with this structure are used to represent a type of * vpiHandle. A specific object becomes of this type by holding a @@ -123,15 +114,56 @@ struct __vpirt { }; /* - * In general a vpi object is a structure that contains the member - * "base" that is a __vpiHandle object. This template can convert any - * of those structures into a vpiHandle object. + * This structure is the very base of a vpiHandle. Every handle + * structure is derived from this class so that the library can + * internally pass the derived types as pointers to one of these. */ -template inline vpiHandle vpi_handle(T obj) -{ return &obj->base; } +class __vpiHandle { + public: + inline __vpiHandle(const struct __vpirt *tp) : vpi_type_(tp) { } + // The descructor is virtual so that dynamic types will work. + virtual ~__vpiHandle() { } + + inline int get_type_code(void) const { return vpi_type_->type_code; } + + inline int vpi_get(int code) + { return vpi_type_->vpi_get_? vpi_type_->vpi_get_(code,this) : vpiUndefined; } + + inline char* vpi_get_str(int code) + { return vpi_type_->vpi_get_str_? vpi_type_->vpi_get_str_(code, this) : 0; } + + inline void vpi_get_value(p_vpi_value val) + { if (vpi_type_->vpi_get_value_) vpi_type_->vpi_get_value_(this, val); + else val->format = vpiSuppressVal; + } + + inline bool can_put_value() const { return vpi_type_->vpi_put_value_ != 0; } + + inline vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return vpi_type_->vpi_put_value_? vpi_type_->vpi_put_value_(this, val, flags) : 0; } + + inline vpiHandle vpi_handle(int code) + { return vpi_type_->handle_? vpi_type_->handle_(code, this) : 0; } + + inline vpiHandle vpi_iterate(int code) + { return vpi_type_->iterate_? vpi_type_->iterate_(code, this) : 0; } + + inline vpiHandle vpi_index(int idx) + { return vpi_type_->index_? vpi_type_->index_(this, idx) : 0; } + + static inline int vpi_free_object(vpiHandle ref) + { return ref->vpi_type_->vpi_free_object_? ref->vpi_type_->vpi_free_object_(ref) : 1; } + + inline void vpi_get_delays(p_vpi_delay del) + { if (vpi_type_->vpi_get_delays_) vpi_type_->vpi_get_delays_(this, del); } + + inline void vpi_put_delays(p_vpi_delay del) + { if (vpi_type_->vpi_put_delays_) vpi_type_->vpi_put_delays_(this, del); } + + private: + const struct __vpirt *vpi_type_; +}; -template inline char*vpip_get_str(int code, T obj) -{ return obj->base.vpi_type->vpi_get_str_(code, vpi_handle(obj)); } /* * The vpiHandle for an iterator has this structure. The definition of @@ -144,8 +176,8 @@ template inline char*vpip_get_str(int code, T obj) * The free_args_flag member is true if when this iterator object is * released it must also free the args array. */ -struct __vpiIterator { - struct __vpiHandle base; +struct __vpiIterator : public __vpiHandle { + __vpiIterator(); vpiHandle *args; unsigned nargs; unsigned next; @@ -157,10 +189,11 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, /* * This represents callback handles. There are some private types that - * are defined and used in vpi_callback.cc. + * are defined and used in vpi_callback.cc. The __vpiCallback are + * always used in association with vvp_vpi_callback objects. */ -struct __vpiCallback { - struct __vpiHandle base; +struct __vpiCallback : public __vpiHandle { + __vpiCallback(); // user supplied callback data struct t_cb_data cb_data; @@ -181,18 +214,32 @@ extern struct __vpiCallback* new_vpi_callback(); extern void delete_vpi_callback(struct __vpiCallback* ref); extern void callback_execute(struct __vpiCallback*cur); -struct __vpiSystemTime { - struct __vpiHandle base; - struct __vpiScope *scope; +struct __vpiSystemTime : public __vpiHandle { + __vpiSystemTime(); + struct __vpiScope*scope; + protected: + inline __vpiSystemTime(const struct __vpirt*rt) : __vpiHandle(rt) { } }; +struct __vpiScopedTime : public __vpiSystemTime { + __vpiScopedTime(); +}; +struct __vpiScopedSTime : public __vpiSystemTime { + __vpiScopedSTime(); +}; +struct __vpiScopedRealtime : public __vpiSystemTime { + __vpiScopedRealtime(); +}; + + /* * Scopes are created by .scope statements in the source. These * objects hold the items and properties that are knowingly bound to a * scope. */ -struct __vpiScope { - struct __vpiHandle base; +struct __vpiScope : public __vpiHandle { + __vpiScope(const struct __vpirt*rt) : __vpiHandle(rt) { } + struct __vpiScope *scope; /* The scope has a name. */ const char*name; @@ -204,9 +251,9 @@ struct __vpiScope { bool is_automatic; bool is_cell; /* The scope has a system time of its own. */ - struct __vpiSystemTime scoped_time; - struct __vpiSystemTime scoped_stime; - struct __vpiSystemTime scoped_realtime; + struct __vpiScopedTime scoped_time; + struct __vpiScopedSTime scoped_stime; + struct __vpiScopedRealtime scoped_realtime; /* Keep an array of internal scope items. */ struct __vpiHandle**intern; unsigned nintern; @@ -238,8 +285,8 @@ extern void vpip_make_root_iterator(struct __vpiHandle**&table, * distinguished by the vpiType code. They also have a parent scope, * a declared name and declaration indices. */ -struct __vpiSignal { - struct __vpiHandle base; +struct __vpiSignal : public __vpiHandle { + inline __vpiSignal(const struct __vpirt*rt) : __vpiHandle(rt) { } #ifdef CHECK_WITH_VALGRIND struct __vpiSignal *pool; #endif @@ -258,6 +305,13 @@ struct __vpiSignal { unsigned is_netarray : 1; // This is word of a net array /* The represented value is here. */ vvp_net_t*node; + + public: + static void*operator new(std::size_t size); + static void operator delete(void*); // not implemented + private: // Not implemented + static void*operator new[] (std::size_t size); + static void operator delete[](void*); }; extern unsigned vpip_size(__vpiSignal *sig); extern struct __vpiScope* vpip_scope(__vpiSignal*sig); @@ -268,15 +322,15 @@ extern vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec); extern vpiHandle vpip_make_var4(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*net); -extern vpiHandle vpip_make_net4(const char*name, int msb, int lsb, - bool signed_flag, vvp_net_t*node); +extern vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, + int msb, int lsb, bool signed_flag, vvp_net_t*node); /* * This is used by system calls to represent a bit/part select of * a simple variable or constant array word. */ -struct __vpiPV { - struct __vpiHandle base; +struct __vpiPV : public __vpiHandle { + __vpiPV(); vpiHandle parent; vvp_net_t*net; vpiHandle sbase; @@ -290,26 +344,18 @@ extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width); extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, char*is_signed, int width); -extern struct __vpiPV* vpip_PV_from_handle(vpiHandle obj); extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle obj); -/* - * This function safely converts a vpiHandle back to a - * __vpiSignal. Return a nil if the type is not appropriate. - */ -extern __vpiSignal* vpip_signal_from_handle(vpiHandle obj); - - -struct __vpiModPathTerm { - struct __vpiHandle base; +struct __vpiModPathTerm : public __vpiHandle { + __vpiModPathTerm(); vpiHandle expr; /* The value returned by vpi_get(vpiEdge, ...); */ int edge; }; -struct __vpiModPathSrc { - struct __vpiHandle base; +struct __vpiModPathSrc : public __vpiHandle { + __vpiModPathSrc(); struct __vpiModPath *dest; int type; @@ -340,9 +386,6 @@ struct __vpiModPath { vvp_net_t *input_net ; }; -extern struct __vpiModPathTerm* vpip_modpath_term_from_handle(vpiHandle ref); -extern struct __vpiModPathSrc* vpip_modpath_src_from_handle(vpiHandle ref); - /* * The Function is used to create the vpiHandle @@ -360,8 +403,9 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; * passed in will be saved, so the caller must allocate it (or not * free it) after it is handed to this function. */ -struct __vpiNamedEvent { - struct __vpiHandle base; +struct __vpiNamedEvent : public __vpiHandle { + __vpiNamedEvent(); + /* base name of the event object */ const char*name; /* Parent scope of this object. */ @@ -389,8 +433,8 @@ extern bool is_net_array(vpiHandle obj); /* * These are the various variable types. */ -struct __vpiRealVar { - struct __vpiHandle base; +struct __vpiRealVar : public __vpiHandle { + __vpiRealVar(); union { // The scope or parent array that contains me. vpiHandle parent; struct __vpiScope* scope; @@ -406,7 +450,7 @@ struct __vpiRealVar { extern struct __vpiScope* vpip_scope(__vpiRealVar*sig); extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net); -extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj); + /* * When a loaded VPI module announces a system task/function, one @@ -426,8 +470,8 @@ extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj); * additional part is the vbit/vwid that is used by the put of the * system function call to place the values in the vthread bit space. */ -struct __vpiUserSystf { - struct __vpiHandle base; +struct __vpiUserSystf : public __vpiHandle { + __vpiUserSystf(); s_vpi_systf_data info; bool is_user_defn; }; @@ -437,8 +481,8 @@ extern vpiHandle vpip_make_systf_iterator(void); extern struct __vpiUserSystf* vpip_find_systf(const char*name); -struct __vpiSysTaskCall { - struct __vpiHandle base; +struct __vpiSysTaskCall : public __vpiHandle { + __vpiSysTaskCall(const struct __vpirt*rt) : __vpiHandle(rt) { } struct __vpiScope* scope; struct __vpiUserSystf*defn; unsigned nargs; @@ -464,23 +508,28 @@ extern struct __vpiSysTaskCall*vpip_cur_task; * handle to be persistent. This is necessary for cases where the * string handle may be reused, which is the normal case. */ -struct __vpiStringConst { - struct __vpiHandle base; +struct __vpiStringConst : public __vpiHandle { + __vpiStringConst(); + char*value; size_t value_len; + protected: + inline __vpiStringConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_string_const(char*text, bool persistent =true); vpiHandle vpip_make_string_param(char*name, char*value, long file_idx, long lineno); -struct __vpiBinaryConst { - struct __vpiHandle base; +struct __vpiBinaryConst : public __vpiHandle { + __vpiBinaryConst(); vvp_vector4_t bits; /* TRUE if this constant is signed. */ int signed_flag :1; /* TRUE if this constant has an explicit size (i.e. 19'h0 vs. 'h0) */ int sized_flag :1; + protected: + inline __vpiBinaryConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_binary_const(unsigned wid, const char*bits); @@ -488,17 +537,16 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno); -struct __vpiDecConst { - struct __vpiHandle base; +struct __vpiDecConst : public __vpiHandle { + __vpiDecConst(int val =0); int value; }; -vpiHandle vpip_make_dec_const(int value); -vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value); - -struct __vpiRealConst { - struct __vpiHandle base; +struct __vpiRealConst : public __vpiHandle { + __vpiRealConst(); double value; + protected: + inline __vpiRealConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_real_const(double value); diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index 72812ecca..f0b5b8bc8 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -30,20 +30,10 @@ # include # include "ivl_alloc.h" -struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj) -{ - assert(obj); - if (obj->vpi_type->type_code == vpiRealVar) - return (struct __vpiRealVar*)obj; - else - return 0; -} - static int real_var_get(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = vpip_realvar_from_handle(ref); + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); switch (code) { case vpiArray: @@ -64,9 +54,8 @@ static int real_var_get(int code, vpiHandle ref) static char* real_var_get_str(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); @@ -84,16 +73,15 @@ static char* real_var_get_str(int code, vpiHandle ref) ixs = NULL; } - char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs); + char *rbuf = generic_get_str(code, vpip_scope(rfp), nm, ixs); free(nm); return rbuf; } static vpiHandle real_var_get_handle(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); switch (code) { @@ -104,7 +92,7 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref) return rfp->is_netarray ? rfp->id.index : 0; case vpiScope: - return &(vpip_scope(rfp)->base); + return vpip_scope(rfp); case vpiModule: return vpip_module(vpip_scope(rfp)); @@ -115,13 +103,11 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref) static vpiHandle real_var_iterate(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); if (code == vpiIndex) { - return rfp->is_netarray ? (rfp->id.index->vpi_type->iterate_) - (code, rfp->id.index) : 0; + return rfp->is_netarray ? rfp->id.index->vpi_iterate(code) : 0; } return 0; @@ -129,10 +115,9 @@ static vpiHandle real_var_iterate(int code, vpiHandle ref) static void real_var_get_value(vpiHandle ref, s_vpi_value*vp) { - assert(ref->vpi_type->type_code == vpiRealVar); + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); - struct __vpiRealVar*rfp - = (struct __vpiRealVar*)ref; vvp_signal_value*fil = dynamic_cast(rfp->net->fil); @@ -141,11 +126,9 @@ static void real_var_get_value(vpiHandle ref, s_vpi_value*vp) static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiRealVar); - double result = real_from_vpi_value(vp); - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); assert(rfp); vvp_net_ptr_t destination (rfp->net, 0); vvp_send_real(destination, result, vthread_get_wt_context()); @@ -167,12 +150,17 @@ static const struct __vpirt vpip_real_var_rt = { 0, 0 }; +inline __vpiRealVar::__vpiRealVar() +: __vpiHandle(&vpip_real_var_rt) +{ +} + void vpip_real_value_change(struct __vpiCallback*cbh, vpiHandle ref) { - struct __vpiRealVar*rfp - = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); vvp_vpi_callback*obj = dynamic_cast(rfp->net->fil); assert(obj); @@ -181,27 +169,25 @@ void vpip_real_value_change(struct __vpiCallback*cbh, vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net) { - struct __vpiRealVar*obj = (struct __vpiRealVar*) - malloc(sizeof(struct __vpiRealVar)); + struct __vpiRealVar*obj = new __vpiRealVar; - obj->base.vpi_type = &vpip_real_var_rt; obj->id.name = name ? vpip_name_string(name) : 0; obj->is_netarray = 0; obj->net = net; obj->within.scope = vpip_peek_current_scope(); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND void real_delete(vpiHandle item) { - struct __vpiRealVar*obj = (struct __vpiRealVar*) item; + struct __vpiRealVar*obj = dynamic_cast<__vpiRealVar*>(item); assert(obj->net->fil); obj->net->fil->clear_all_callbacks(); vvp_net_delete(obj->net); - free(obj); + delete obj; } #endif diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 33bb34ace..f3e0e0086 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -117,20 +117,10 @@ void root_table_delete(void) } #endif -static bool handle_is_scope(vpiHandle obj) -{ - return (obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork); -} - static int scope_get(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - - assert(handle_is_scope(obj)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(obj); switch (code) { case vpiCellInstance: @@ -189,9 +179,8 @@ static const char* scope_get_type(int code) static char* scope_get_str(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - - assert(handle_is_scope(obj)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(ref); char buf[4096]; // XXX is a fixed buffer size really reliable? const char *p=0; @@ -231,21 +220,16 @@ static char* scope_get_str(int code, vpiHandle obj) static vpiHandle scope_get_handle(int code, vpiHandle obj) { - assert((obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork)); - - struct __vpiScope*rfp = (struct __vpiScope*)obj; + struct __vpiScope*rfp = dynamic_cast<__vpiScope*>(obj); + assert(rfp); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiModule: - return &rfp->scope->base; + return rfp->scope; } return 0; @@ -291,7 +275,7 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) vpiHandle*args; for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1) - if (compare_types(code, ref->intern[idx]->vpi_type->type_code)) + if (compare_types(code, ref->intern[idx]->get_type_code())) mcnt += 1; if (mcnt == 0) @@ -299,7 +283,7 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) args = (vpiHandle*)calloc(mcnt, sizeof(vpiHandle)); for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1) - if (compare_types(code, ref->intern[idx]->vpi_type->type_code)) + if (compare_types(code, ref->intern[idx]->get_type_code())) args[ncnt++] = ref->intern[idx]; assert(ncnt == mcnt); @@ -315,12 +299,8 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) */ static vpiHandle module_iter(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - assert((obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(ref); return module_iter_subset(code, ref); } @@ -429,40 +409,36 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, char*parent, long file_idx, long lineno, long def_file_idx, long def_lineno, long is_cell) { - struct __vpiScope*scope = new struct __vpiScope; count_vpi_scopes += 1; - char*base_type = 0; + char*base_type; + bool is_automatic; if (strncmp(type,"auto",4) == 0) { - scope->is_automatic = true; + is_automatic = true; base_type = &type[4]; } else { - scope->is_automatic = false; + is_automatic = false; base_type = &type[0]; } - if (is_cell) scope->is_cell = true; - else scope->is_cell = false; - + struct __vpiScope*scope; if (strcmp(base_type,"module") == 0) { - scope->base.vpi_type = &vpip_scope_module_rt; + scope = new __vpiScope(&vpip_scope_module_rt); } else if (strcmp(base_type,"function") == 0) { - scope->base.vpi_type = &vpip_scope_function_rt; + scope = new __vpiScope(&vpip_scope_function_rt); } else if (strcmp(base_type,"task") == 0) { - scope->base.vpi_type = &vpip_scope_task_rt; + scope = new __vpiScope(&vpip_scope_task_rt); } else if (strcmp(base_type,"fork") == 0) { - scope->base.vpi_type = &vpip_scope_fork_rt; + scope = new __vpiScope(&vpip_scope_fork_rt); } else if (strcmp(base_type,"begin") == 0) { - scope->base.vpi_type = &vpip_scope_begin_rt; + scope = new __vpiScope(&vpip_scope_begin_rt); } else if (strcmp(base_type,"generate") == 0) { - scope->base.vpi_type = &vpip_scope_begin_rt; + scope = new __vpiScope(&vpip_scope_begin_rt); } else { - scope->base.vpi_type = &vpip_scope_module_rt; + scope = new __vpiScope(&vpip_scope_module_rt); assert(0); } - assert(scope->base.vpi_type); - scope->name = vpip_name_string(name); if (tname) scope->tname = vpip_name_string(tname); else scope->tname = vpip_name_string(""); @@ -470,6 +446,7 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, scope->lineno = (unsigned) lineno; scope->def_file_idx = (unsigned) def_file_idx; scope->def_lineno = (unsigned) def_lineno; + scope->is_automatic = is_automatic; scope->intern = 0; scope->nintern = 0; scope->item = 0; @@ -477,9 +454,12 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, scope->live_contexts = 0; scope->free_contexts = 0; + if (is_cell) scope->is_cell = true; + else scope->is_cell = false; + current_scope = scope; - compile_vpi_symbol(label, &scope->base); + compile_vpi_symbol(label, scope); free(label); free(type); @@ -490,9 +470,9 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, static vpiHandle obj; compile_vpi_lookup(&obj, parent); assert(obj); - struct __vpiScope*sp = (struct __vpiScope*) obj; - vpip_attach_to_scope(sp, &scope->base); - scope->scope = (struct __vpiScope*)obj; + struct __vpiScope*sp = dynamic_cast<__vpiScope*>(obj); + vpip_attach_to_scope(sp, scope); + scope->scope = dynamic_cast<__vpiScope*>(obj); /* Inherit time units and precision from the parent scope. */ scope->time_units = sp->time_units; @@ -504,7 +484,7 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, unsigned cnt = vpip_root_table_cnt + 1; vpip_root_table_ptr = (vpiHandle*) realloc(vpip_root_table_ptr, cnt * sizeof(vpiHandle)); - vpip_root_table_ptr[vpip_root_table_cnt] = &scope->base; + vpip_root_table_ptr[vpip_root_table_cnt] = scope; vpip_root_table_cnt = cnt; /* Root scopes inherit time_units and precision from the diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 65011380b..4e0fbdd35 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -505,31 +505,12 @@ static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid, } } -struct __vpiSignal* vpip_signal_from_handle(vpiHandle ref) -{ - switch (ref->vpi_type->type_code) { - case vpiNet: - case vpiReg: - /* This handles both reg and logic */ - case vpiIntegerVar: - case vpiByteVar: - case vpiShortIntVar: - case vpiIntVar: - case vpiLongIntVar: - case vpiBitVar: - return (struct __vpiSignal*)ref; - - default: - return 0; - } -} - /* * implement vpi_get for vpiReg objects. */ static int signal_get(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); switch (code) { @@ -559,7 +540,7 @@ static int signal_get(int code, vpiHandle ref) return rfp->lsb - rfp->msb + 1; case vpiNetType: - if (ref->vpi_type->type_code==vpiNet) + if (ref->get_type_code()==vpiNet) return vpiWire; else return vpiUndefined; @@ -589,7 +570,7 @@ static int signal_get(int code, vpiHandle ref) static char* signal_get_str(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); if (code == vpiFile) { // Not implemented for now! @@ -611,14 +592,14 @@ static char* signal_get_str(int code, vpiHandle ref) } /* The scope information is added here for vpiFullName. */ - char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs); + char *rbuf = generic_get_str(code, vpip_scope(rfp), nm, ixs); free(nm); return rbuf; } static vpiHandle signal_get_handle(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); switch (code) { @@ -630,7 +611,7 @@ static vpiHandle signal_get_handle(int code, vpiHandle ref) return rfp->is_netarray? rfp->id.index : 0; case vpiScope: - return &(vpip_scope(rfp)->base); + return vpip_scope(rfp); case vpiModule: return vpip_module(vpip_scope(rfp)); @@ -641,7 +622,7 @@ static vpiHandle signal_get_handle(int code, vpiHandle ref) static vpiHandle signal_iterate(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); if (code == vpiIndex) { @@ -667,7 +648,7 @@ static unsigned signal_width(const struct __vpiSignal*rfp) */ static void signal_get_value(vpiHandle ref, s_vpi_value*vp) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); unsigned wid = signal_width(rfp); @@ -773,7 +754,7 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid) static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags) { unsigned wid; - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); /* If this is a release, then we are not really putting a @@ -995,8 +976,8 @@ static const struct __vpirt vpip_longint_rt = { */ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb,lsb, true, vec); - obj->vpi_type = &vpip_integer_rt; + vpiHandle obj = vpip_make_net4(name, &vpip_integer_rt, + msb,lsb, true, vec); return obj; } @@ -1006,37 +987,37 @@ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb, lsb, signed_flag, vec); + const struct __vpirt*vpi_type; // All unsigned 2-state variables are a vpiBitVar. All 2-state // variables with a non-zero lsb are also a vpiBitVar. if ((! signed_flag) || (lsb != 0) ) { - obj->vpi_type = &vpip_bitvar_rt; + vpi_type = &vpip_bitvar_rt; } else { // These could also be bit declarations with matching // information, but for now they get the apparent type. switch (msb) { case 7: - obj->vpi_type = &vpip_byte_rt; + vpi_type = &vpip_byte_rt; break; case 15: - obj->vpi_type = &vpip_shortint_rt; + vpi_type = &vpip_shortint_rt; break; case 31: - obj->vpi_type = &vpip_int_rt; + vpi_type = &vpip_int_rt; break; case 63: - obj->vpi_type = &vpip_longint_rt; + vpi_type = &vpip_longint_rt; break; default: // Every other type of bit vector is a vpiBitVar with // array dimensions. - obj->vpi_type = &vpip_bitvar_rt; + vpi_type = &vpip_bitvar_rt; break; } } - return obj; + return vpip_make_net4(name, vpi_type, msb, lsb, signed_flag, vec); } /* @@ -1045,9 +1026,7 @@ vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vpiHandle vpip_make_var4(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb,lsb, signed_flag, vec); - obj->vpi_type = &vpip_reg_rt; - return obj; + return vpip_make_net4(name, &vpip_reg_rt, msb,lsb, signed_flag, vec); } #ifdef CHECK_WITH_VALGRIND @@ -1057,30 +1036,35 @@ static unsigned long signal_count = 0; static unsigned long signal_dels = 0; #endif -static struct __vpiSignal* allocate_vpiSignal(void) +struct vpiSignal_plug { + unsigned char space[sizeof (struct __vpiSignal)]; +}; + +void* __vpiSignal::operator new(size_t siz) { - static struct __vpiSignal*alloc_array = 0; + assert(siz == sizeof(struct vpiSignal_plug)); + static struct vpiSignal_plug*alloc_array = 0; static unsigned alloc_index = 0; const unsigned alloc_count = 512; if ((alloc_array == 0) || (alloc_index == alloc_count)) { - alloc_array = (struct __vpiSignal*) - calloc(alloc_count, sizeof(struct __vpiSignal)); + alloc_array = (struct vpiSignal_plug*) + calloc(alloc_count, sizeof(struct vpiSignal_plug)); alloc_index = 0; #ifdef CHECK_WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS(alloc_array, alloc_count * - sizeof(struct __vpiSignal)); + sizeof(struct vpiSignal_plug)); VALGRIND_CREATE_MEMPOOL(alloc_array, 0, 1); signal_pool_count += 1; - signal_pool = (__vpiSignal **) realloc(signal_pool, - signal_pool_count*sizeof(__vpiSignal **)); + signal_pool = (vpiSignal_plug **) realloc(signal_pool, + signal_pool_count*sizeof(vpiSignal_plug **)); signal_pool[signal_pool_count-1] = alloc_array; #endif } - struct __vpiSignal*cur = alloc_array + alloc_index; + struct vpiSignal_plug*cur = alloc_array + alloc_index; #ifdef CHECK_WITH_VALGRIND - VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct __vpiSignal)); + VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct vpiSignal_plug)); cur->pool = alloc_array; signal_count += 1; #endif @@ -1088,6 +1072,11 @@ static struct __vpiSignal* allocate_vpiSignal(void) return cur; } +void __vpiSignal::operator delete(void*ptr) +{ + assert(0); +} + #ifdef CHECK_WITH_VALGRIND void signal_delete(vpiHandle item) { @@ -1125,11 +1114,11 @@ void signal_pool_delete() * The name is the PLI name for the object. If it is an array it is * []. */ -vpiHandle vpip_make_net4(const char*name, int msb, int lsb, - bool signed_flag, vvp_net_t*node) +vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, + int msb, int lsb, bool signed_flag, vvp_net_t*node) { - struct __vpiSignal*obj = allocate_vpiSignal(); - obj->base.vpi_type = &vpip_net_rt; + if (rt == 0) rt = &vpip_net_rt; + struct __vpiSignal*obj = new __vpiSignal(rt); obj->id.name = name? vpip_name_string(name) : 0; obj->msb = msb; obj->lsb = lsb; @@ -1144,7 +1133,7 @@ vpiHandle vpip_make_net4(const char*name, int msb, int lsb, count_vpi_nets += 1; - return &obj->base; + return obj; } static int PV_get_base(struct __vpiPV*rfp) @@ -1205,8 +1194,8 @@ static int PV_get_base(struct __vpiPV*rfp) static int PV_get(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); int rval = 0; switch (code) { @@ -1246,8 +1235,8 @@ static int PV_get(int code, vpiHandle ref) static char* PV_get_str(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); switch (code) { case vpiFile: // Not implemented for now! @@ -1276,8 +1265,8 @@ static char* PV_get_str(int code, vpiHandle ref) static void PV_get_value(vpiHandle ref, p_vpi_value vp) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); vvp_signal_value*sig = dynamic_cast(rfp->net->fil); assert(sig); @@ -1334,8 +1323,8 @@ static void PV_get_value(vpiHandle ref, p_vpi_value vp) static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); vvp_signal_value*sig = dynamic_cast(rfp->net->fil); assert(sig); @@ -1382,8 +1371,8 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle PV_get_handle(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code==vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); switch (code) { case vpiParent: @@ -1409,19 +1398,14 @@ static const struct __vpirt vpip_PV_rt = { 0, 0 }; - -struct __vpiPV* vpip_PV_from_handle(vpiHandle obj) +inline __vpiPV::__vpiPV() +: __vpiHandle(&vpip_PV_rt) { - if (obj->vpi_type->type_code == vpiPartSelect) - return (__vpiPV*) obj; - else - return 0; } vpiHandle vpip_make_PV(char*var, int base, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = 0; obj->tbase = base; @@ -1430,13 +1414,12 @@ vpiHandle vpip_make_PV(char*var, int base, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, char*symbol, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); compile_vpi_lookup(&obj->sbase, symbol); obj->tbase = 0; @@ -1445,13 +1428,12 @@ vpiHandle vpip_make_PV(char*var, char*symbol, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = handle; obj->tbase = 0; @@ -1460,13 +1442,12 @@ vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = 0; obj->tbase = tbase; @@ -1478,12 +1459,18 @@ vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width) delete [] is_signed; - return &obj->base; + return obj; } +/* + * Attach the __vpiCallback to the object that this part select + * selects from. The part select itself is not a vvp_vpi_callback + * object, but it refers to a net that is a vvp_vpi_callback, so + * add the callback to that object. + */ void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref) { - struct __vpiPV*obj = vpip_PV_from_handle(ref); + struct __vpiPV*obj = dynamic_cast<__vpiPV*>(ref); assert(obj); vvp_vpi_callback*sig_fil; @@ -1497,7 +1484,7 @@ void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref) #ifdef CHECK_WITH_VALGRIND void PV_delete(vpiHandle item) { - struct __vpiPV *obj = (__vpiPV *) item; + struct __vpiPV *obj = dynamic_cast<__vpiPV*>(item); if (obj->sbase) { switch (obj->sbase->vpi_type->type_code) { case vpiMemoryWord: @@ -1513,6 +1500,6 @@ void PV_delete(vpiHandle item) } assert(obj->net->fil); obj->net->fil->clear_all_callbacks(); - free(obj); + delete obj; } #endif diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 7eee8f9c7..22e91b880 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -49,20 +49,23 @@ static const struct __vpirt vpip_systf_def_rt = { 0 }; +inline __vpiUserSystf::__vpiUserSystf() +: __vpiHandle(&vpip_systf_def_rt) +{ +} + static vpiHandle systask_handle(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiUserSystf: /* Assert that vpiUserDefn is true! */ assert(rfp->defn->is_user_defn); - return &rfp->defn->base; + return rfp->defn; default: return 0; @@ -71,10 +74,7 @@ static vpiHandle systask_handle(int type, vpiHandle ref) static int systask_get(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { /* This is not the correct way to get this information, but @@ -99,9 +99,7 @@ static int systask_get(int type, vpiHandle ref) // support getting vpiSize for a system function call static int sysfunc_get(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert(ref->vpi_type->type_code == vpiSysFuncCall); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiSize: @@ -124,10 +122,7 @@ static int sysfunc_get(int type, vpiHandle ref) static char *systask_get_str(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiFile: @@ -147,9 +142,7 @@ static char *systask_get_str(int type, vpiHandle ref) */ static vpiHandle systask_iter(int, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); if (rfp->nargs == 0) return 0; @@ -171,7 +164,6 @@ static const struct __vpirt vpip_systask_rt = { 0 }; - /* * A value *can* be put to a vpiSysFuncCall object. This is how the * return value is set. The value that is given should be converted to @@ -180,9 +172,7 @@ static const struct __vpirt vpip_systask_rt = { */ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -310,9 +300,7 @@ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -338,9 +326,7 @@ static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -443,9 +429,7 @@ static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -467,10 +451,8 @@ static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) return 0; } -static vpiHandle sysfunc_put_no_value(vpiHandle ref, p_vpi_value, int) +static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - return 0; } @@ -547,6 +529,13 @@ static const struct __vpirt vpip_sysfunc_no_rt = { /* **** Manipulate the internal data structures. **** */ +/* + * We keep a table of all the __vpiUserSystf objects that are created + * so that the user can iterate over them. The def_table is an array + * of pointers to __vpiUserSystf objects. This table can be searched + * by name using the vpi_find_systf function, and they can be + * collected into an iterator using the vpip_make_systf_iterator function. + */ static struct __vpiUserSystf**def_table = 0; static unsigned def_count = 0; @@ -556,8 +545,7 @@ static struct __vpiUserSystf* allocate_def(void) def_table = (struct __vpiUserSystf**) malloc(sizeof (struct __vpiUserSystf*)); - def_table[0] = (struct __vpiUserSystf*) - calloc(1, sizeof(struct __vpiUserSystf)); + def_table[0] = new __vpiUserSystf; def_count = 1; return def_table[0]; @@ -566,8 +554,7 @@ static struct __vpiUserSystf* allocate_def(void) def_table = (struct __vpiUserSystf**) realloc(def_table, (def_count+1)*sizeof (struct __vpiUserSystf*)); - def_table[def_count] = (struct __vpiUserSystf*) - calloc(1, sizeof(struct __vpiUserSystf)); + def_table[def_count] = new __vpiUserSystf; return def_table[def_count++]; } @@ -577,7 +564,7 @@ void def_table_delete(void) { for (unsigned idx = 0; idx < def_count; idx += 1) { free(const_cast(def_table[idx]->info.tfname)); - free(def_table[idx]); + delete def_table[idx]; } free(def_table); def_table = 0; @@ -585,15 +572,14 @@ void def_table_delete(void) } #endif -struct __vpiSystfIterator { - struct __vpiHandle base; +struct __vpiSystfIterator : public __vpiHandle { + __vpiSystfIterator(); unsigned next; }; static vpiHandle systf_iterator_scan(vpiHandle ref, int) { - assert(ref->vpi_type->type_code == vpiIterator); - struct __vpiSystfIterator*obj = (struct __vpiSystfIterator*) ref; + struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref); if (obj->next >= def_count) { vpi_free_object(ref); @@ -610,14 +596,13 @@ static vpiHandle systf_iterator_scan(vpiHandle ref, int) } } obj->next += 1; - return &(def_table[use_index])->base; + return def_table[use_index]; } static int systf_iterator_free_object(vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiIterator); - struct __vpiSystfIterator*obj = (struct __vpiSystfIterator*) ref; - free(obj); + struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref); + delete obj; return 1; } @@ -634,6 +619,10 @@ static const struct __vpirt vpip_systf_iterator_rt = { 0, 0 }; +inline __vpiSystfIterator::__vpiSystfIterator() +: __vpiHandle(&vpip_systf_iterator_rt) +{ +} vpiHandle vpip_make_systf_iterator(void) { @@ -648,11 +637,9 @@ vpiHandle vpip_make_systf_iterator(void) } if (!have_user_defn) return 0; - struct __vpiSystfIterator*res; - res = (struct __vpiSystfIterator*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_systf_iterator_rt; + struct __vpiSystfIterator*res = new __vpiSystfIterator; res->next = idx; - return &res->base; + return res; } struct __vpiUserSystf* vpip_find_systf(const char*name) @@ -667,8 +654,8 @@ struct __vpiUserSystf* vpip_find_systf(const char*name) void vpip_make_systf_system_defined(vpiHandle ref) { assert(ref); - assert(ref->vpi_type->type_code == vpiUserSystf); - struct __vpiUserSystf*obj = (__vpiUserSystf*) ref; + struct __vpiUserSystf*obj = dynamic_cast<__vpiUserSystf*>(ref); + assert(obj); obj->is_user_defn = false; } @@ -821,28 +808,28 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, assert(0); } - struct __vpiSysTaskCall*obj = new struct __vpiSysTaskCall; + struct __vpiSysTaskCall*obj = 0; switch (defn->info.type) { case vpiSysTask: - obj->base.vpi_type = &vpip_systask_rt; + obj = new __vpiSysTaskCall(&vpip_systask_rt); break; case vpiSysFunc: if (fnet && vwid == -vpiRealConst) { - obj->base.vpi_type = &vpip_sysfunc_rnet_rt; + obj = new __vpiSysTaskCall(&vpip_sysfunc_rnet_rt); } else if (fnet && vwid > 0) { - obj->base.vpi_type = &vpip_sysfunc_4net_rt; + obj = new __vpiSysTaskCall(&vpip_sysfunc_4net_rt); } else if (vwid == -vpiRealConst) { - obj->base.vpi_type = &vpip_sysfunc_real_rt; + obj = new __vpiSysTaskCall(&vpip_sysfunc_real_rt); } else if (vwid > 0) { - obj->base.vpi_type = &vpip_sysfunc_rt; + obj = new __vpiSysTaskCall(&vpip_sysfunc_rt); } else if (vwid == 0 && fnet == 0) { - obj->base.vpi_type = &vpip_sysfunc_no_rt; + obj = new __vpiSysTaskCall(&vpip_sysfunc_no_rt); } else { assert(0); @@ -864,7 +851,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, compile_compiletf(obj); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -918,10 +905,7 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) { vpip_current_vthread = thr; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); - - vpip_cur_task = (struct __vpiSysTaskCall*)ref; + vpip_cur_task = dynamic_cast<__vpiSysTaskCall*>(ref); if (vpip_cur_task->defn->info.calltf) { assert(vpi_mode_flag == VPI_MODE_NONE); @@ -931,7 +915,7 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) vpi_mode_flag = VPI_MODE_NONE; /* If the function call did not set a value then put a * default value (0). */ - if (ref->vpi_type->type_code == vpiSysFuncCall && + if (ref->get_type_code() == vpiSysFuncCall && !vpip_cur_task->put_value) { s_vpi_value val; if (vpip_cur_task->vwid == -vpiRealConst) { @@ -959,7 +943,6 @@ vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) switch (ss->type) { case vpiSysTask: case vpiSysFunc: - cur->base.vpi_type = &vpip_systf_def_rt; break; default: fprintf(stderr, "Unsupported type %d.\n", (int)ss->type); @@ -970,26 +953,23 @@ vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) cur->info.tfname = strdup(ss->tfname); cur->is_user_defn = true; - return &cur->base; + return cur; } PLI_INT32 vpi_put_userdata(vpiHandle ref, void*data) { - if (ref->vpi_type->type_code != vpiSysTaskCall - && ref->vpi_type->type_code != vpiSysFuncCall) + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + if (rfp == 0) return 0; - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - rfp->userdata = data; return 1; } void* vpi_get_userdata(vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(rfp); return rfp->userdata; } diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 167fbe6d8..e298d9b8b 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -199,12 +199,11 @@ static int timevar_realtime_get(int code, vpiHandle) static vpiHandle timevar_handle(int code, vpiHandle ref) { - struct __vpiSystemTime*rfp - = reinterpret_cast(ref); + struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; default: return 0; } @@ -217,8 +216,7 @@ static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func, the caller. */ static struct t_vpi_time time_value; - struct __vpiSystemTime*rfp - = reinterpret_cast(ref); + struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref); unsigned long num_bits; vvp_time64_t x, simtime = schedule_simtime(); int units = rfp->scope? rfp->scope->time_units : vpi_time_precision; @@ -326,6 +324,10 @@ static const struct __vpirt vpip_system_time_rt = { 0, 0 }; +__vpiScopedTime::__vpiScopedTime() +: __vpiSystemTime(&vpip_system_time_rt) +{ +} static const struct __vpirt vpip_system_stime_rt = { vpiSysFuncCall, @@ -340,6 +342,10 @@ static const struct __vpirt vpip_system_stime_rt = { 0, 0 }; +__vpiScopedSTime::__vpiScopedSTime() +: __vpiSystemTime(&vpip_system_stime_rt) +{ +} static const struct __vpirt vpip_system_simtime_rt = { vpiSysFuncCall, @@ -354,6 +360,11 @@ static const struct __vpirt vpip_system_simtime_rt = { 0, 0 }; +__vpiSystemTime::__vpiSystemTime() +: __vpiHandle(&vpip_system_simtime_rt) +{ + scope = 0; +} static const struct __vpirt vpip_system_realtime_rt = { vpiSysFuncCall, @@ -368,6 +379,11 @@ static const struct __vpirt vpip_system_realtime_rt = { 0, 0 }; +__vpiScopedRealtime::__vpiScopedRealtime() +: __vpiSystemTime(&vpip_system_realtime_rt) +{ +} + /* * Create a handle to represent a call to $time/$stime/$simtime. The @@ -378,26 +394,21 @@ vpiHandle vpip_sim_time(struct __vpiScope*scope, bool is_stime) { if (scope) { if (is_stime) { - scope->scoped_stime.base.vpi_type = &vpip_system_stime_rt; scope->scoped_stime.scope = scope; - return &scope->scoped_stime.base; + return &scope->scoped_stime; } else { - scope->scoped_time.base.vpi_type = &vpip_system_time_rt; scope->scoped_time.scope = scope; - return &scope->scoped_time.base; + return &scope->scoped_time; } } else { - global_simtime.base.vpi_type = &vpip_system_simtime_rt; - global_simtime.scope = 0; - return &global_simtime.base; + return &global_simtime; } } vpiHandle vpip_sim_realtime(struct __vpiScope*scope) { - scope->scoped_realtime.base.vpi_type = &vpip_system_realtime_rt; scope->scoped_realtime.scope = scope; - return &scope->scoped_realtime.base; + return &scope->scoped_realtime; } int vpip_get_time_precision(void) diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 785ccbbe1..b4abc871c 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2001 Stephan Boettcher * * This source code is free software; you can redistribute it @@ -35,8 +35,8 @@ # include # include "ivl_alloc.h" -struct __vpiVThrVec { - struct __vpiHandle base; +struct __vpiVThrVec : public __vpiHandle { + __vpiVThrVec(); unsigned bas; unsigned wid; unsigned signed_flag : 1; @@ -77,11 +77,8 @@ extern const char oct_digits[64]; */ static int vthr_vec_get(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); switch (code) { @@ -106,11 +103,8 @@ static int vthr_vec_get(int code, vpiHandle ref) static char* vthr_vec_get_str(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); switch (code) { @@ -177,11 +171,8 @@ static void vthr_vec_StringVal(struct __vpiVThrVec*rfp, s_vpi_value*vp) */ static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); char *rbuf; unsigned wid = rfp->wid; @@ -363,10 +354,8 @@ static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp) */ static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); unsigned wid = rfp->wid; @@ -456,6 +445,11 @@ static const struct __vpirt vpip_vthr_const_rt = { 0, 0 }; +__vpiVThrVec::__vpiVThrVec() +: __vpiHandle(&vpip_vthr_const_rt) +{ +} + /* * Construct a vpiReg object. Give the object specified dimensions, @@ -463,9 +457,7 @@ static const struct __vpirt vpip_vthr_const_rt = { */ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag) { - struct __vpiVThrVec*obj = (struct __vpiVThrVec*) - malloc(sizeof(struct __vpiVThrVec)); - obj->base.vpi_type = &vpip_vthr_const_rt; + struct __vpiVThrVec*obj = new __vpiVThrVec; assert(base < 65536); obj->bas = base; assert(wid < 65536); @@ -473,7 +465,7 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag) obj->signed_flag = signed_flag? 1 : 0; obj->name = vpip_name_string("T<>"); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -486,13 +478,13 @@ void thread_vthr_delete(vpiHandle item) static void thread_vthr_delete_real(vpiHandle item) { - struct __vpiVThrVec*obj = (struct __vpiVThrVec*)item; - free (obj); + struct __vpiVThrVec*obj = dynamic_cast<__vpiVThrVec*>(item); + delete obj; } #endif -struct __vpiVThrWord { - struct __vpiHandle base; +struct __vpiVThrWord : public __vpiHandle { + __vpiVThrWord(); const char* name; int subtype; unsigned index; @@ -500,9 +492,7 @@ struct __vpiVThrWord { static int vthr_word_get(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code==vpiConstant); - - struct __vpiVThrWord*rfp = (struct __vpiVThrWord*)ref; + struct __vpiVThrWord*rfp = dynamic_cast<__vpiVThrWord*>(ref); switch (code) { @@ -521,9 +511,7 @@ static int vthr_word_get(int code, vpiHandle ref) static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) { - assert(ref->vpi_type->type_code==vpiConstant); - - struct __vpiVThrWord*obj = (struct __vpiVThrWord*)ref; + struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(ref); char *rbuf = need_result_buf(66, RBUF_VAL); double val = 0.0; @@ -604,21 +592,23 @@ static const struct __vpirt vpip_vthr_const_real_rt = { 0, 0 }; +inline __vpiVThrWord::__vpiVThrWord() +: __vpiHandle(&vpip_vthr_const_real_rt) +{ +} vpiHandle vpip_make_vthr_word(unsigned base, const char*type) { - struct __vpiVThrWord*obj = (struct __vpiVThrWord*) - malloc(sizeof(struct __vpiVThrWord)); + struct __vpiVThrWord*obj = new __vpiVThrWord; assert(type[0] == 'r'); - obj->base.vpi_type = &vpip_vthr_const_real_rt; obj->name = vpip_name_string("W<>"); obj->subtype = vpiRealConst; assert(base < 65536); obj->index = base; - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -629,8 +619,8 @@ void thread_word_delete(vpiHandle item) static void thread_word_delete_real(vpiHandle item) { - struct __vpiVThrWord*obj = (struct __vpiVThrWord*)item; - free(obj); + struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(item); + delete obj; } void vpi_handle_delete() diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 3fd4c0719..31695764d 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2549,7 +2549,7 @@ bool of_FORK(vthread_t thr, vvp_code_t cp) /* If the new child was created to evaluate a function, run it immediately, then return to this thread. */ - if (cp->scope->base.vpi_type->type_code == vpiFunction) { + if (cp->scope->get_type_code() == vpiFunction) { child->is_scheduled = 1; vthread_run(child); running_thread = thr; diff --git a/vvp/words.cc b/vvp/words.cc index 2cfdcd3dc..22fa2bede 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -258,7 +258,7 @@ static void do_compile_net(vvp_net_t*node, vvp_array_t array, vpiHandle obj = 0; if (! local_flag) { /* Make the vpiHandle for the reg. */ - obj = vpip_make_net4(name, msb, lsb, signed_flag, node); + obj = vpip_make_net4(name, 0, msb, lsb, signed_flag, node); /* This attaches the label to the vpiHandle */ compile_vpi_symbol(my_label, obj); } From ac2b68fc1b4f4bcf6ed65ee0db5a474102d8200d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 19 Jan 2012 15:04:51 -0800 Subject: [PATCH 22/88] Implement __vpiHandle::get_type_code pure virtual method. --- vvp/array.cc | 30 ++++++++++++++++ vvp/delay.cc | 8 ++++- vvp/enum_type.cc | 10 +++++- vvp/file_line.cc | 6 +++- vvp/vpi_callback.cc | 5 ++- vvp/vpi_const.cc | 29 ++++++++++++++- vvp/vpi_event.cc | 4 +++ vvp/vpi_iter.cc | 3 ++ vvp/vpi_priv.h | 42 ++++++++++++++++++---- vvp/vpi_real.cc | 5 ++- vvp/vpi_scope.cc | 39 ++++++++++++++++---- vvp/vpi_signal.cc | 81 ++++++++++++++++++++++++++++++++---------- vvp/vpi_tasks.cc | 49 ++++++++++++++++++++----- vvp/vpi_time.cc | 7 +++- vvp/vpi_vthr_vector.cc | 12 ++++++- vvp/words.cc | 2 +- 16 files changed, 283 insertions(+), 49 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 5bbcba787..e4b829263 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -82,6 +82,8 @@ vvp_array_t array_find(const char*label) */ struct __vpiArray : public __vpiHandle { __vpiArray(); + int get_type_code(void) const; + struct __vpiScope*scope; const char*name; /* Permanently allocated string */ unsigned array_count; @@ -105,6 +107,7 @@ struct __vpiArray : public __vpiHandle { struct __vpiArrayIterator : public __vpiHandle { __vpiArrayIterator(); + int get_type_code(void) const; struct __vpiArray*array; unsigned next; @@ -112,6 +115,8 @@ struct __vpiArrayIterator : public __vpiHandle { struct __vpiArrayIndex : public __vpiHandle { __vpiArrayIndex(); + int get_type_code(void) const; + struct __vpiDecConst *index; unsigned done; }; @@ -119,6 +124,7 @@ struct __vpiArrayIndex : public __vpiHandle { struct __vpiArrayVthrA : public __vpiHandle { __vpiArrayVthrA(); + int get_type_code(void) const; struct __vpiArray*array; // If this is set, then use it to get the index value. @@ -188,6 +194,8 @@ struct __vpiArrayVthrA : public __vpiHandle { struct __vpiArrayVthrAPV : public __vpiHandle { __vpiArrayVthrAPV(); + int get_type_code(void) const; + struct __vpiArray*array; unsigned word_sel; unsigned part_bit; @@ -250,10 +258,12 @@ bool is_net_array(vpiHandle obj) struct __vpiArrayWord { struct as_word_t : public __vpiHandle { as_word_t(); + int get_type_code(void) const; } as_word; struct as_index_t : public __vpiHandle { as_index_t(); + int get_type_code(void) const; } as_index; union { @@ -311,6 +321,8 @@ inline __vpiArray::__vpiArray() { } +int __vpiArray::get_type_code(void) const +{ return vpiMemory; } static const struct __vpirt vpip_array_iterator_rt = { vpiIterator, @@ -331,6 +343,9 @@ inline __vpiArrayIterator::__vpiArrayIterator() { } +int __vpiArrayIterator::get_type_code(void) const +{ return vpiIterator; } + /* This should look a bit odd since it provides a fake iteration on * this object. This trickery is used to implement the two forms of @@ -354,6 +369,9 @@ inline __vpiArrayIndex::__vpiArrayIndex() { } +int __vpiArrayIndex::get_type_code(void) const +{ return vpiIterator; } + static const struct __vpirt vpip_array_var_word_rt = { vpiMemoryWord, &vpi_array_var_word_get, @@ -372,6 +390,9 @@ inline __vpiArrayWord::as_word_t::as_word_t() { } +int __vpiArrayWord::as_word_t::get_type_code(void) const +{ return vpiMemoryWord; } + static const struct __vpirt vpip_array_var_index_rt = { vpiIndex, 0, @@ -390,6 +411,9 @@ inline __vpiArrayWord::as_index_t::as_index_t() { } +int __vpiArrayWord::as_index_t::get_type_code(void) const +{ return vpiIndex; } + static const struct __vpirt vpip_array_vthr_A_rt = { vpiMemoryWord, &vpi_array_vthr_A_get, @@ -409,6 +433,9 @@ inline __vpiArrayVthrA::__vpiArrayVthrA() { } +int __vpiArrayVthrA::get_type_code(void) const +{ return vpiMemoryWord; } + static const struct __vpirt vpip_array_vthr_APV_rt = { vpiMemoryWord, &vpi_array_vthr_APV_get, @@ -428,6 +455,9 @@ inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() { } +int __vpiArrayVthrAPV::get_type_code(void) const +{ return vpiMemoryWord; } + static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) { if (ref == 0) diff --git a/vvp/delay.cc b/vvp/delay.cc index ef5aa4807..898bb77dc 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2011 Stephen Williams + * Copyright (c) 2005-2012 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -990,6 +990,9 @@ inline __vpiModPathSrc::__vpiModPathSrc() { } +int __vpiModPathSrc::get_type_code(void) const +{ return vpiModPath; } + static const struct __vpirt vpip_modpath_term_rt = { vpiPathTerm, pathterm_get, @@ -1009,6 +1012,9 @@ inline __vpiModPathTerm::__vpiModPathTerm() { } +int __vpiModPathTerm::get_type_code(void) const +{ return vpiPathTerm; } + static void initialize_path_term(struct __vpiModPathTerm&obj) { obj.expr = 0; diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index eacb17fc9..0b9937829 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2012 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 @@ -27,6 +27,7 @@ struct enumconst_s : public __vpiHandle { enumconst_s(); + int get_type_code(void) const; const char*name; vvp_vector2_t val2; @@ -35,6 +36,7 @@ struct enumconst_s : public __vpiHandle { struct __vpiEnumTypespec : public __vpiHandle { __vpiEnumTypespec(); + int get_type_code(void) const; std::vector names; int base_type_code; @@ -104,6 +106,9 @@ inline __vpiEnumTypespec::__vpiEnumTypespec() { } +int __vpiEnumTypespec::get_type_code(void) const +{ return vpiEnumTypespec; } + static int enum_name_get(int code, vpiHandle obj) { struct enumconst_s*ref = dynamic_cast(obj); @@ -160,6 +165,9 @@ inline enumconst_s::enumconst_s() { } +int enumconst_s::get_type_code(void) const +{ return vpiEnumConst; } + void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names) { diff --git a/vvp/file_line.cc b/vvp/file_line.cc index 22f95fd4b..10044be33 100644 --- a/vvp/file_line.cc +++ b/vvp/file_line.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ struct __vpiFileLine : public __vpiHandle { __vpiFileLine(); + int get_type_code(void) const; const char *description; unsigned file_idx; @@ -79,6 +80,9 @@ inline __vpiFileLine::__vpiFileLine() { } +int __vpiFileLine::get_type_code(void) const +{ return _vpiFileLine; } + vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) { struct __vpiFileLine*obj = new struct __vpiFileLine; diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 5a3af8215..f79acb429 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -65,6 +65,9 @@ inline __vpiCallback::__vpiCallback() { } +int __vpiCallback::get_type_code(void) const +{ return vpiCallback; } + /* * Callback handles are created when the VPI function registers a diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index d1c639afe..92b77236f 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -184,6 +184,9 @@ inline __vpiStringConst::__vpiStringConst() { } +int __vpiStringConst::get_type_code(void) const +{ return vpiConstant; } + struct __vpiStringConstTEMP : public __vpiStringConst { __vpiStringConstTEMP(); }; @@ -262,6 +265,8 @@ vpiHandle vpip_make_string_const(char*text, bool persistent_flag) struct __vpiStringParam : public __vpiStringConst { __vpiStringParam(); + int get_type_code(void) const; + const char*basename; struct __vpiScope* scope; unsigned file_idx; @@ -328,6 +333,8 @@ inline __vpiStringParam::__vpiStringParam() { } +int __vpiStringParam::get_type_code(void) const +{ return vpiParameter; } vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) @@ -426,6 +433,9 @@ inline __vpiBinaryConst::__vpiBinaryConst() { } +int __vpiBinaryConst::get_type_code(void) const +{ return vpiConstant; } + /* * Make a VPI constant from a vector string. The string is normally a * ASCII string, with each letter a 4-value bit. The first character @@ -478,6 +488,8 @@ vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) struct __vpiBinaryParam : public __vpiBinaryConst { __vpiBinaryParam(); + int get_type_code(void) const; + const char*basename; struct __vpiScope*scope; unsigned file_idx; @@ -540,6 +552,9 @@ inline __vpiBinaryParam::__vpiBinaryParam() { } +int __vpiBinaryParam::get_type_code(void) const +{ return vpiParameter; } + vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno) @@ -656,6 +671,9 @@ __vpiDecConst::__vpiDecConst(int val) value = val; } +int __vpiDecConst::get_type_code(void) const +{ return vpiConstant; } + static int real_get(int code, vpiHandle) { @@ -712,6 +730,10 @@ inline __vpiRealConst::__vpiRealConst() { } +int __vpiRealConst::get_type_code(void) const +{ return vpiConstant; } + + vpiHandle vpip_make_real_const(double value) { struct __vpiRealConst*obj = new __vpiRealConst; @@ -721,6 +743,8 @@ vpiHandle vpip_make_real_const(double value) struct __vpiRealParam : public __vpiRealConst { __vpiRealParam(); + int get_type_code(void) const; + const char*basename; struct __vpiScope* scope; unsigned file_idx; @@ -783,6 +807,9 @@ inline __vpiRealParam::__vpiRealParam() { } +int __vpiRealParam::get_type_code(void) const +{ return vpiParameter; } + vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index c28f0aa58..33131f9f6 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -85,6 +85,10 @@ inline __vpiNamedEvent::__vpiNamedEvent() { } +int __vpiNamedEvent::get_type_code(void) const +{ return vpiNamedEvent; } + + vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { struct __vpiNamedEvent*obj = new __vpiNamedEvent; diff --git a/vvp/vpi_iter.cc b/vvp/vpi_iter.cc index 229e96ca7..233b037e3 100644 --- a/vvp/vpi_iter.cc +++ b/vvp/vpi_iter.cc @@ -56,6 +56,9 @@ inline __vpiIterator::__vpiIterator() { } +int __vpiIterator::get_type_code(void) const +{ return vpiIterator; } + vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, bool free_args_flag) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 91fa50628..accfc21fe 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -89,7 +89,7 @@ extern vpi_mode_t vpi_mode_flag; * pointer to an instance of this structure. */ struct __vpirt { - int type_code; + int type_code_X; /* These methods extract information from the handle. */ int (*vpi_get_)(int, vpiHandle); @@ -124,7 +124,7 @@ class __vpiHandle { // The descructor is virtual so that dynamic types will work. virtual ~__vpiHandle() { } - inline int get_type_code(void) const { return vpi_type_->type_code; } + virtual int get_type_code(void) const =0; inline int vpi_get(int code) { return vpi_type_->vpi_get_? vpi_type_->vpi_get_(code,this) : vpiUndefined; } @@ -178,6 +178,8 @@ class __vpiHandle { */ struct __vpiIterator : public __vpiHandle { __vpiIterator(); + int get_type_code(void) const; + vpiHandle *args; unsigned nargs; unsigned next; @@ -194,6 +196,7 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, */ struct __vpiCallback : public __vpiHandle { __vpiCallback(); + int get_type_code(void) const; // user supplied callback data struct t_cb_data cb_data; @@ -216,6 +219,8 @@ extern void callback_execute(struct __vpiCallback*cur); struct __vpiSystemTime : public __vpiHandle { __vpiSystemTime(); + int get_type_code(void) const; + struct __vpiScope*scope; protected: inline __vpiSystemTime(const struct __vpirt*rt) : __vpiHandle(rt) { } @@ -238,8 +243,6 @@ struct __vpiScopedRealtime : public __vpiSystemTime { * scope. */ struct __vpiScope : public __vpiHandle { - __vpiScope(const struct __vpirt*rt) : __vpiHandle(rt) { } - struct __vpiScope *scope; /* The scope has a name. */ const char*name; @@ -268,6 +271,10 @@ struct __vpiScope : public __vpiHandle { std::set threads; signed int time_units :8; signed int time_precision :8; + + protected: + __vpiScope(const struct __vpirt*rt) : __vpiHandle(rt) { } + }; extern struct __vpiScope* vpip_peek_current_scope(void); @@ -286,7 +293,7 @@ extern void vpip_make_root_iterator(struct __vpiHandle**&table, * a declared name and declaration indices. */ struct __vpiSignal : public __vpiHandle { - inline __vpiSignal(const struct __vpirt*rt) : __vpiHandle(rt) { } + #ifdef CHECK_WITH_VALGRIND struct __vpiSignal *pool; #endif @@ -309,6 +316,8 @@ struct __vpiSignal : public __vpiHandle { public: static void*operator new(std::size_t size); static void operator delete(void*); // not implemented + protected: + inline __vpiSignal(const struct __vpirt*rt) : __vpiHandle(rt) { } private: // Not implemented static void*operator new[] (std::size_t size); static void operator delete[](void*); @@ -322,8 +331,8 @@ extern vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec); extern vpiHandle vpip_make_var4(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*net); -extern vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, - int msb, int lsb, bool signed_flag, vvp_net_t*node); +extern vpiHandle vpip_make_net4(const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node); /* * This is used by system calls to represent a bit/part select of @@ -331,6 +340,8 @@ extern vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, */ struct __vpiPV : public __vpiHandle { __vpiPV(); + int get_type_code(void) const; + vpiHandle parent; vvp_net_t*net; vpiHandle sbase; @@ -349,6 +360,8 @@ extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ob struct __vpiModPathTerm : public __vpiHandle { __vpiModPathTerm(); + int get_type_code(void) const; + vpiHandle expr; /* The value returned by vpi_get(vpiEdge, ...); */ int edge; @@ -356,6 +369,8 @@ struct __vpiModPathTerm : public __vpiHandle { struct __vpiModPathSrc : public __vpiHandle { __vpiModPathSrc(); + int get_type_code(void) const; + struct __vpiModPath *dest; int type; @@ -405,6 +420,7 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; */ struct __vpiNamedEvent : public __vpiHandle { __vpiNamedEvent(); + int get_type_code(void) const; /* base name of the event object */ const char*name; @@ -435,6 +451,8 @@ extern bool is_net_array(vpiHandle obj); */ struct __vpiRealVar : public __vpiHandle { __vpiRealVar(); + int get_type_code(void) const; + union { // The scope or parent array that contains me. vpiHandle parent; struct __vpiScope* scope; @@ -472,6 +490,8 @@ extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net); */ struct __vpiUserSystf : public __vpiHandle { __vpiUserSystf(); + int get_type_code(void) const; + s_vpi_systf_data info; bool is_user_defn; }; @@ -483,6 +503,7 @@ extern struct __vpiUserSystf* vpip_find_systf(const char*name); struct __vpiSysTaskCall : public __vpiHandle { __vpiSysTaskCall(const struct __vpirt*rt) : __vpiHandle(rt) { } + struct __vpiScope* scope; struct __vpiUserSystf*defn; unsigned nargs; @@ -510,6 +531,7 @@ extern struct __vpiSysTaskCall*vpip_cur_task; */ struct __vpiStringConst : public __vpiHandle { __vpiStringConst(); + int get_type_code(void) const; char*value; size_t value_len; @@ -523,6 +545,8 @@ vpiHandle vpip_make_string_param(char*name, char*value, struct __vpiBinaryConst : public __vpiHandle { __vpiBinaryConst(); + int get_type_code(void) const; + vvp_vector4_t bits; /* TRUE if this constant is signed. */ int signed_flag :1; @@ -539,11 +563,15 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, struct __vpiDecConst : public __vpiHandle { __vpiDecConst(int val =0); + int get_type_code(void) const; + int value; }; struct __vpiRealConst : public __vpiHandle { __vpiRealConst(); + int get_type_code(void) const; + double value; protected: inline __vpiRealConst(const struct __vpirt*rt) : __vpiHandle(rt) { } diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index f0b5b8bc8..c13449e8d 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -155,6 +155,9 @@ inline __vpiRealVar::__vpiRealVar() { } +int __vpiRealVar::get_type_code(void) const +{ return vpiRealVar; } + void vpip_real_value_change(struct __vpiCallback*cbh, vpiHandle ref) diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index f3e0e0086..bf0395474 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -320,6 +320,11 @@ static const struct __vpirt vpip_scope_module_rt = { 0 }; +struct vpiScopeModule : public __vpiScope { + inline vpiScopeModule() : __vpiScope(&vpip_scope_module_rt) { } + int get_type_code(void) const { return vpiModule; } +}; + static const struct __vpirt vpip_scope_task_rt = { vpiTask, scope_get, @@ -334,6 +339,11 @@ static const struct __vpirt vpip_scope_task_rt = { 0 }; +struct vpiScopeTask : public __vpiScope { + inline vpiScopeTask() : __vpiScope(&vpip_scope_task_rt) { } + int get_type_code(void) const { return vpiTask; } +}; + static const struct __vpirt vpip_scope_function_rt = { vpiFunction, scope_get, @@ -348,6 +358,11 @@ static const struct __vpirt vpip_scope_function_rt = { 0 }; +struct vpiScopeFunction : public __vpiScope { + inline vpiScopeFunction() : __vpiScope(&vpip_scope_function_rt) { } + int get_type_code(void) const { return vpiFunction; } +}; + static const struct __vpirt vpip_scope_begin_rt = { vpiNamedBegin, scope_get, @@ -362,6 +377,11 @@ static const struct __vpirt vpip_scope_begin_rt = { 0 }; +struct vpiScopeBegin : public __vpiScope { + inline vpiScopeBegin() : __vpiScope(&vpip_scope_begin_rt) { } + int get_type_code(void) const { return vpiNamedBegin; } +}; + static const struct __vpirt vpip_scope_fork_rt = { vpiNamedFork, scope_get, @@ -376,6 +396,11 @@ static const struct __vpirt vpip_scope_fork_rt = { 0 }; +struct vpiScopeFork : public __vpiScope { + inline vpiScopeFork() : __vpiScope(&vpip_scope_fork_rt) { } + int get_type_code(void) const { return vpiNamedFork; } +}; + /* * The current_scope is a compile time concept. As the vvp source is * compiled, items that have scope are placed in the current @@ -423,19 +448,19 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, struct __vpiScope*scope; if (strcmp(base_type,"module") == 0) { - scope = new __vpiScope(&vpip_scope_module_rt); + scope = new vpiScopeModule; } else if (strcmp(base_type,"function") == 0) { - scope = new __vpiScope(&vpip_scope_function_rt); + scope = new vpiScopeFunction; } else if (strcmp(base_type,"task") == 0) { - scope = new __vpiScope(&vpip_scope_task_rt); + scope = new vpiScopeTask; } else if (strcmp(base_type,"fork") == 0) { - scope = new __vpiScope(&vpip_scope_fork_rt); + scope = new vpiScopeFork; } else if (strcmp(base_type,"begin") == 0) { - scope = new __vpiScope(&vpip_scope_begin_rt); + scope = new vpiScopeBegin; } else if (strcmp(base_type,"generate") == 0) { - scope = new __vpiScope(&vpip_scope_begin_rt); + scope = new vpiScopeBegin; } else { - scope = new __vpiScope(&vpip_scope_module_rt); + scope = new vpiScopeModule; assert(0); } diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 4e0fbdd35..fb22826b6 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -131,6 +131,10 @@ char *generic_get_str(int code, vpiHandle ref, const char *name, const char *ind return res; } +static vpiHandle fill_in_net4(struct __vpiSignal*obj, + const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node); + /* * The standard formating/conversion routines. * They work with full or partial signals. @@ -869,6 +873,10 @@ static const struct __vpirt vpip_reg_rt = { 0, 0 }; +struct signal_reg : public __vpiSignal { + inline signal_reg() : __vpiSignal(&vpip_reg_rt) { } + int get_type_code(void) const { return vpiReg; } +}; static const struct __vpirt vpip_integer_rt = { vpiIntegerVar, @@ -883,6 +891,10 @@ static const struct __vpirt vpip_integer_rt = { 0, 0 }; +struct signal_integer : public __vpiSignal { + inline signal_integer() : __vpiSignal(&vpip_integer_rt) { } + int get_type_code(void) const { return vpiIntegerVar; } +}; static const struct __vpirt vpip_net_rt = { vpiNet, @@ -897,6 +909,10 @@ static const struct __vpirt vpip_net_rt = { 0, 0 }; +struct signal_net : public __vpiSignal { + inline signal_net() : __vpiSignal(&vpip_net_rt) { } + int get_type_code(void) const { return vpiNet; } +}; static const struct __vpirt vpip_byte_rt = { vpiByteVar, @@ -911,6 +927,10 @@ static const struct __vpirt vpip_byte_rt = { 0, 0 }; +struct signal_byte : public __vpiSignal { + inline signal_byte() : __vpiSignal(&vpip_byte_rt) { } + int get_type_code(void) const { return vpiByteVar; } +}; static const struct __vpirt vpip_bitvar_rt = { vpiBitVar, @@ -925,6 +945,10 @@ static const struct __vpirt vpip_bitvar_rt = { 0, 0 }; +struct signal_bitvar : public __vpiSignal { + inline signal_bitvar() : __vpiSignal(&vpip_bitvar_rt) { } + int get_type_code(void) const { return vpiBitVar; } +}; static const struct __vpirt vpip_shortint_rt = { vpiShortIntVar, @@ -939,6 +963,10 @@ static const struct __vpirt vpip_shortint_rt = { 0, 0 }; +struct signal_shortint : public __vpiSignal { + inline signal_shortint() : __vpiSignal(&vpip_shortint_rt) { } + int get_type_code(void) const { return vpiShortIntVar; } +}; static const struct __vpirt vpip_int_rt = { vpiIntVar, @@ -953,6 +981,10 @@ static const struct __vpirt vpip_int_rt = { 0, 0 }; +struct signal_int : public __vpiSignal { + inline signal_int() : __vpiSignal(&vpip_int_rt) { } + int get_type_code(void) const { return vpiIntVar; } +}; static const struct __vpirt vpip_longint_rt = { vpiLongIntVar, @@ -967,6 +999,10 @@ static const struct __vpirt vpip_longint_rt = { 0, 0 }; +struct signal_longint : public __vpiSignal { + inline signal_longint() : __vpiSignal(&vpip_longint_rt) { } + int get_type_code(void) const { return vpiLongIntVar; } +}; /* @@ -976,9 +1012,8 @@ static const struct __vpirt vpip_longint_rt = { */ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, &vpip_integer_rt, - msb,lsb, true, vec); - return obj; + __vpiSignal*obj = new signal_integer; + return fill_in_net4(obj, name, msb, lsb, true, vec); } /* @@ -987,37 +1022,37 @@ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - const struct __vpirt*vpi_type; + __vpiSignal*obj; // All unsigned 2-state variables are a vpiBitVar. All 2-state // variables with a non-zero lsb are also a vpiBitVar. if ((! signed_flag) || (lsb != 0) ) { - vpi_type = &vpip_bitvar_rt; + obj = new signal_bitvar; } else { // These could also be bit declarations with matching // information, but for now they get the apparent type. switch (msb) { case 7: - vpi_type = &vpip_byte_rt; + obj = new signal_byte; break; case 15: - vpi_type = &vpip_shortint_rt; + obj = new signal_shortint; break; case 31: - vpi_type = &vpip_int_rt; + obj = new signal_int; break; case 63: - vpi_type = &vpip_longint_rt; + obj = new signal_longint; break; default: // Every other type of bit vector is a vpiBitVar with // array dimensions. - vpi_type = &vpip_bitvar_rt; + obj = new signal_bitvar; break; } } - return vpip_make_net4(name, vpi_type, msb, lsb, signed_flag, vec); + return fill_in_net4(obj, name, msb, lsb, signed_flag, vec); } /* @@ -1026,7 +1061,8 @@ vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vpiHandle vpip_make_var4(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - return vpip_make_net4(name, &vpip_reg_rt, msb,lsb, signed_flag, vec); + __vpiSignal*obj = new signal_reg; + return fill_in_net4(obj, name, msb, lsb, signed_flag, vec); } #ifdef CHECK_WITH_VALGRIND @@ -1072,7 +1108,7 @@ void* __vpiSignal::operator new(size_t siz) return cur; } -void __vpiSignal::operator delete(void*ptr) +void __vpiSignal::operator delete(void*) { assert(0); } @@ -1114,11 +1150,10 @@ void signal_pool_delete() * The name is the PLI name for the object. If it is an array it is * []. */ -vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, - int msb, int lsb, bool signed_flag, vvp_net_t*node) +static vpiHandle fill_in_net4(struct __vpiSignal*obj, + const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node) { - if (rt == 0) rt = &vpip_net_rt; - struct __vpiSignal*obj = new __vpiSignal(rt); obj->id.name = name? vpip_name_string(name) : 0; obj->msb = msb; obj->lsb = lsb; @@ -1136,6 +1171,13 @@ vpiHandle vpip_make_net4(const char*name, const struct __vpirt*rt, return obj; } +vpiHandle vpip_make_net4(const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node) +{ + struct __vpiSignal*obj = new signal_net; + return fill_in_net4(obj, name, msb, lsb, signed_flag, node); +} + static int PV_get_base(struct __vpiPV*rfp) { /* We return from the symbol base if it is defined. */ @@ -1403,6 +1445,9 @@ inline __vpiPV::__vpiPV() { } +int __vpiPV::get_type_code(void) const +{ return vpiPartSelect; } + vpiHandle vpip_make_PV(char*var, int base, int width) { struct __vpiPV*obj = new __vpiPV; diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 22e91b880..933fa0366 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -54,6 +54,10 @@ inline __vpiUserSystf::__vpiUserSystf() { } +int __vpiUserSystf::get_type_code(void) const +{ return vpiUserSystf; } + + static vpiHandle systask_handle(int type, vpiHandle ref) { struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); @@ -163,6 +167,10 @@ static const struct __vpirt vpip_systask_rt = { 0, 0 }; +struct systask_def : public __vpiSysTaskCall { + inline systask_def() : __vpiSysTaskCall(&vpip_systask_rt) { } + int get_type_code(void) const { return vpiSysTaskCall; } +}; /* * A value *can* be put to a vpiSysFuncCall object. This is how the @@ -173,6 +181,7 @@ static const struct __vpirt vpip_systask_rt = { static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) { struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(rfp); rfp->put_value = true; @@ -456,7 +465,6 @@ static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) return 0; } - static const struct __vpirt vpip_sysfunc_rt = { vpiSysFuncCall, sysfunc_get, @@ -470,6 +478,10 @@ static const struct __vpirt vpip_sysfunc_rt = { 0, 0 }; +struct sysfunc_def : public __vpiSysTaskCall { + inline sysfunc_def() : __vpiSysTaskCall(&vpip_sysfunc_rt) { } + int get_type_code(void) const { return vpiSysFuncCall; } +}; static const struct __vpirt vpip_sysfunc_real_rt = { vpiSysFuncCall, @@ -484,6 +496,10 @@ static const struct __vpirt vpip_sysfunc_real_rt = { 0, 0 }; +struct sysfunc_real : public __vpiSysTaskCall { + inline sysfunc_real() : __vpiSysTaskCall(&vpip_sysfunc_real_rt) { } + int get_type_code(void) const { return vpiSysFuncCall; } +}; static const struct __vpirt vpip_sysfunc_4net_rt = { vpiSysFuncCall, @@ -498,6 +514,10 @@ static const struct __vpirt vpip_sysfunc_4net_rt = { 0, 0 }; +struct sysfunc_4net : public __vpiSysTaskCall { + inline sysfunc_4net() : __vpiSysTaskCall(&vpip_sysfunc_4net_rt) { } + int get_type_code(void) const { return vpiSysFuncCall; } +}; static const struct __vpirt vpip_sysfunc_rnet_rt = { vpiSysFuncCall, @@ -512,6 +532,10 @@ static const struct __vpirt vpip_sysfunc_rnet_rt = { 0, 0 }; +struct sysfunc_rnet : public __vpiSysTaskCall { + inline sysfunc_rnet() : __vpiSysTaskCall(&vpip_sysfunc_rnet_rt) { } + int get_type_code(void) const { return vpiSysFuncCall; } +}; static const struct __vpirt vpip_sysfunc_no_rt = { vpiSysFuncCall, @@ -526,6 +550,10 @@ static const struct __vpirt vpip_sysfunc_no_rt = { 0, 0 }; +struct sysfunc_no : public __vpiSysTaskCall { + inline sysfunc_no() : __vpiSysTaskCall(&vpip_sysfunc_no_rt) { } + int get_type_code(void) const { return vpiSysFuncCall; } +}; /* **** Manipulate the internal data structures. **** */ @@ -574,6 +602,8 @@ void def_table_delete(void) struct __vpiSystfIterator : public __vpiHandle { __vpiSystfIterator(); + int get_type_code(void) const; + unsigned next; }; @@ -624,6 +654,9 @@ inline __vpiSystfIterator::__vpiSystfIterator() { } +int __vpiSystfIterator::get_type_code(void) const +{ return vpiIterator; } + vpiHandle vpip_make_systf_iterator(void) { /* Check to see if there are any user defined functions. */ @@ -812,24 +845,24 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, switch (defn->info.type) { case vpiSysTask: - obj = new __vpiSysTaskCall(&vpip_systask_rt); + obj = new systask_def; break; case vpiSysFunc: if (fnet && vwid == -vpiRealConst) { - obj = new __vpiSysTaskCall(&vpip_sysfunc_rnet_rt); + obj = new sysfunc_rnet; } else if (fnet && vwid > 0) { - obj = new __vpiSysTaskCall(&vpip_sysfunc_4net_rt); + obj = new sysfunc_4net; } else if (vwid == -vpiRealConst) { - obj = new __vpiSysTaskCall(&vpip_sysfunc_real_rt); + obj = new sysfunc_real; } else if (vwid > 0) { - obj = new __vpiSysTaskCall(&vpip_sysfunc_rt); + obj = new sysfunc_def; } else if (vwid == 0 && fnet == 0) { - obj = new __vpiSysTaskCall(&vpip_sysfunc_no_rt); + obj = new sysfunc_no; } else { assert(0); @@ -857,7 +890,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, #ifdef CHECK_WITH_VALGRIND void vpi_call_delete(vpiHandle item) { - struct __vpiSysTaskCall*obj = (struct __vpiSysTaskCall *) item; + struct __vpiSysTaskCall*obj = dynamic_cast<__vpiSysTaskCall*>(item); /* The object can be NULL if there was an error. */ if (!obj) return; for (unsigned arg = 0; arg < obj->nargs; arg += 1) { diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index e298d9b8b..d45f23eac 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -366,6 +366,11 @@ __vpiSystemTime::__vpiSystemTime() scope = 0; } +int __vpiSystemTime::get_type_code(void) const +{ + return vpiSysFuncCall; +} + static const struct __vpirt vpip_system_realtime_rt = { vpiSysFuncCall, timevar_realtime_get, diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index b4abc871c..6f875997a 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -37,6 +37,8 @@ struct __vpiVThrVec : public __vpiHandle { __vpiVThrVec(); + int get_type_code(void) const; + unsigned bas; unsigned wid; unsigned signed_flag : 1; @@ -445,11 +447,14 @@ static const struct __vpirt vpip_vthr_const_rt = { 0, 0 }; -__vpiVThrVec::__vpiVThrVec() +inline __vpiVThrVec::__vpiVThrVec() : __vpiHandle(&vpip_vthr_const_rt) { } +int __vpiVThrVec::get_type_code(void) const +{ return vpiConstant; } + /* * Construct a vpiReg object. Give the object specified dimensions, @@ -485,6 +490,8 @@ static void thread_vthr_delete_real(vpiHandle item) struct __vpiVThrWord : public __vpiHandle { __vpiVThrWord(); + int get_type_code(void) const; + const char* name; int subtype; unsigned index; @@ -597,6 +604,9 @@ inline __vpiVThrWord::__vpiVThrWord() { } +int __vpiVThrWord::get_type_code(void) const +{ return vpiConstant; } + vpiHandle vpip_make_vthr_word(unsigned base, const char*type) { struct __vpiVThrWord*obj = new __vpiVThrWord; diff --git a/vvp/words.cc b/vvp/words.cc index 22fa2bede..2cfdcd3dc 100644 --- a/vvp/words.cc +++ b/vvp/words.cc @@ -258,7 +258,7 @@ static void do_compile_net(vvp_net_t*node, vvp_array_t array, vpiHandle obj = 0; if (! local_flag) { /* Make the vpiHandle for the reg. */ - obj = vpip_make_net4(name, 0, msb, lsb, signed_flag, node); + obj = vpip_make_net4(name, msb, lsb, signed_flag, node); /* This attaches the label to the vpiHandle */ compile_vpi_symbol(my_label, obj); } From c07c4509e47768ad4329a2da59efe620e337af1d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 20 Jan 2012 11:39:48 -0800 Subject: [PATCH 23/88] Move all vpirt functions to __vpiHandle virtual methods. This takes care of all the functions accept the delete methood, which will need special treatment. --- vvp/array.cc | 153 +++++++++++++++++++++++++++----- vvp/delay.cc | 51 ++++++++--- vvp/enum_type.cc | 34 ++++++-- vvp/file_line.cc | 13 ++- vvp/vpi_const.cc | 193 +++++++++++++++++++++++++++++++++++------ vvp/vpi_event.cc | 14 ++- vvp/vpi_priv.cc | 34 +++++++- vvp/vpi_priv.h | 130 ++++++++++++++++++++------- vvp/vpi_real.cc | 29 +++++-- vvp/vpi_scope.cc | 52 ++++++----- vvp/vpi_signal.cc | 140 +++++++++++++++++++----------- vvp/vpi_tasks.cc | 102 ++++++++++++++++------ vvp/vpi_time.cc | 89 +++++++++++++++---- vvp/vpi_vthr_vector.cc | 35 ++++++-- 14 files changed, 838 insertions(+), 231 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index e4b829263..45c3d0283 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -83,6 +83,11 @@ vvp_array_t array_find(const char*label) struct __vpiArray : public __vpiHandle { __vpiArray(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); struct __vpiScope*scope; const char*name; /* Permanently allocated string */ @@ -108,6 +113,9 @@ struct __vpiArray : public __vpiHandle { struct __vpiArrayIterator : public __vpiHandle { __vpiArrayIterator(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_index(int idx); struct __vpiArray*array; unsigned next; @@ -116,6 +124,10 @@ struct __vpiArrayIterator : public __vpiHandle { struct __vpiArrayIndex : public __vpiHandle { __vpiArrayIndex(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); struct __vpiDecConst *index; unsigned done; @@ -125,6 +137,11 @@ struct __vpiArrayVthrA : public __vpiHandle { __vpiArrayVthrA(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); struct __vpiArray*array; // If this is set, then use it to get the index value. @@ -195,6 +212,9 @@ struct __vpiArrayVthrA : public __vpiHandle { struct __vpiArrayVthrAPV : public __vpiHandle { __vpiArrayVthrAPV(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); struct __vpiArray*array; unsigned word_sel; @@ -259,11 +279,19 @@ struct __vpiArrayWord { struct as_word_t : public __vpiHandle { as_word_t(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); } as_word; struct as_index_t : public __vpiHandle { as_index_t(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); } as_index; union { @@ -305,13 +333,13 @@ static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp); static const struct __vpirt vpip_arraymem_rt = { vpiMemory, - vpi_array_get, - vpi_array_get_str, + 0, //vpi_array_get, + 0, //vpi_array_get_str, 0, 0, - vpi_array_get_handle, - vpi_array_iterate, - vpi_array_index, + 0, //vpi_array_get_handle, + 0, //vpi_array_iterate, + 0, //vpi_array_index, 0, 0, 0 @@ -324,6 +352,21 @@ inline __vpiArray::__vpiArray() int __vpiArray::get_type_code(void) const { return vpiMemory; } +int __vpiArray::vpi_get(int code) +{ return vpi_array_get(code, this); } + +char* __vpiArray::vpi_get_str(int code) +{ return vpi_array_get_str(code, this); } + +vpiHandle __vpiArray::vpi_handle(int code) +{ return vpi_array_get_handle(code, this); } + +vpiHandle __vpiArray::vpi_iterate(int code) +{ return vpi_array_iterate(code, this); } + +vpiHandle __vpiArray::vpi_index(int idx) +{ return vpi_array_index(this, idx); } + static const struct __vpirt vpip_array_iterator_rt = { vpiIterator, 0, @@ -332,7 +375,7 @@ static const struct __vpirt vpip_array_iterator_rt = { 0, 0, 0, - array_iterator_scan, + 0, //array_iterator_scan, &array_iterator_free_object, 0, 0 @@ -346,6 +389,14 @@ inline __vpiArrayIterator::__vpiArrayIterator() int __vpiArrayIterator::get_type_code(void) const { return vpiIterator; } +int __vpiArrayIterator::vpi_get(int) +{ return vpiUndefined; } + +char* __vpiArrayIterator::vpi_get_str(int) +{ return 0; } + +vpiHandle __vpiArrayIterator::vpi_index(int code) +{ return array_iterator_scan(this, code); } /* This should look a bit odd since it provides a fake iteration on * this object. This trickery is used to implement the two forms of @@ -357,8 +408,8 @@ static const struct __vpirt vpip_array_index_rt = { 0, 0, 0, - array_index_iterate, - array_index_scan, + 0, //array_index_iterate, + 0, //array_index_scan, array_index_free_object, 0, 0 @@ -372,13 +423,25 @@ inline __vpiArrayIndex::__vpiArrayIndex() int __vpiArrayIndex::get_type_code(void) const { return vpiIterator; } +int __vpiArrayIndex::vpi_get(int) +{ return vpiUndefined; } + +char* __vpiArrayIndex::vpi_get_str(int) +{ return 0; } + +vpiHandle __vpiArrayIndex::vpi_iterate(int code) +{ return array_index_iterate(code, this); } + +vpiHandle __vpiArrayIndex::vpi_index(int idx) +{ return array_index_scan(this, idx); } + static const struct __vpirt vpip_array_var_word_rt = { vpiMemoryWord, - &vpi_array_var_word_get, - &vpi_array_var_word_get_str, - &vpi_array_var_word_get_value, - &vpi_array_var_word_put_value, - &vpi_array_var_word_get_handle, + 0, //&vpi_array_var_word_get, + 0, //&vpi_array_var_word_get_str, + 0, //&vpi_array_var_word_get_value, + 0, //&vpi_array_var_word_put_value, + 0, //&vpi_array_var_word_get_handle, 0, 0, 0, @@ -393,6 +456,21 @@ inline __vpiArrayWord::as_word_t::as_word_t() int __vpiArrayWord::as_word_t::get_type_code(void) const { return vpiMemoryWord; } +int __vpiArrayWord::as_word_t::vpi_get(int code) +{ return vpi_array_var_word_get(code, this); } + +char* __vpiArrayWord::as_word_t::vpi_get_str(int code) +{ return vpi_array_var_word_get_str(code, this); } + +void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value val) +{ vpi_array_var_word_get_value(this, val); } + +vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value val, int flags) +{ return vpi_array_var_word_put_value(this, val, flags); } + +vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) +{ return vpi_array_var_word_get_handle(code, this); } + static const struct __vpirt vpip_array_var_index_rt = { vpiIndex, 0, @@ -414,13 +492,22 @@ inline __vpiArrayWord::as_index_t::as_index_t() int __vpiArrayWord::as_index_t::get_type_code(void) const { return vpiIndex; } +int __vpiArrayWord::as_index_t::vpi_get(int) +{ return vpiUndefined; } + +char* __vpiArrayWord::as_index_t::vpi_get_str(int) +{ return 0; } + +void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value val) +{ vpi_array_var_index_get_value(this, val); } + static const struct __vpirt vpip_array_vthr_A_rt = { vpiMemoryWord, - &vpi_array_vthr_A_get, - &vpi_array_vthr_A_get_str, - &vpi_array_vthr_A_get_value, - &vpi_array_vthr_A_put_value, - &vpi_array_vthr_A_get_handle, + 0, //&vpi_array_vthr_A_get, + 0, //&vpi_array_vthr_A_get_str, + 0, //&vpi_array_vthr_A_get_value, + 0, //&vpi_array_vthr_A_put_value, + 0, //&vpi_array_vthr_A_get_handle, 0, 0, 0, @@ -436,11 +523,26 @@ inline __vpiArrayVthrA::__vpiArrayVthrA() int __vpiArrayVthrA::get_type_code(void) const { return vpiMemoryWord; } +int __vpiArrayVthrA::vpi_get(int code) +{ return vpi_array_vthr_A_get(code, this); } + +char* __vpiArrayVthrA::vpi_get_str(int code) +{ return vpi_array_vthr_A_get_str(code, this); } + +void __vpiArrayVthrA::vpi_get_value(p_vpi_value val) +{ vpi_array_vthr_A_get_value(this, val); } + +vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value val, int flags) +{ return vpi_array_vthr_A_put_value(this, val, flags); } + +vpiHandle __vpiArrayVthrA::vpi_handle(int code) +{ return vpi_array_vthr_A_get_handle(code, this); } + static const struct __vpirt vpip_array_vthr_APV_rt = { vpiMemoryWord, - &vpi_array_vthr_APV_get, - &vpi_array_vthr_APV_get_str, - &vpi_array_vthr_APV_get_value, + 0, //&vpi_array_vthr_APV_get, + 0, //&vpi_array_vthr_APV_get_str, + 0, //&vpi_array_vthr_APV_get_value, 0, //&vpi_array_vthr_A_put_value, 0, //&vpi_array_vthr_A_get_handle, 0, @@ -458,6 +560,15 @@ inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() int __vpiArrayVthrAPV::get_type_code(void) const { return vpiMemoryWord; } +int __vpiArrayVthrAPV::vpi_get(int code) +{ return vpi_array_vthr_APV_get(code, this); } + +char* __vpiArrayVthrAPV::vpi_get_str(int code) +{ return vpi_array_vthr_APV_get_str(code, this); } + +void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value val) +{ vpi_array_vthr_APV_get_value(this, val); } + static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) { if (ref == 0) diff --git a/vvp/delay.cc b/vvp/delay.cc index 898bb77dc..f4f9024f5 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -973,16 +973,16 @@ static vpiHandle pathterm_get_handle(int code, vpiHandle ref) */ static const struct __vpirt vpip_modpath_src_rt = { vpiModPath, - modpath_src_get, + 0, //modpath_src_get, 0, /* vpi_get_str */ - modpath_src_get_value, - modpath_src_put_value, - modpath_src_get_handle, - modpath_src_iterate, - modpath_src_index, + 0, //modpath_src_get_value, + 0, //modpath_src_put_value, + 0, //modpath_src_get_handle, + 0, //modpath_src_iterate, + 0, //modpath_src_index, modpath_src_free_object, - modpath_src_get_delays, - modpath_src_put_delays + 0, //modpath_src_get_delays, + 0, //modpath_src_put_delays }; inline __vpiModPathSrc::__vpiModPathSrc() @@ -993,13 +993,38 @@ inline __vpiModPathSrc::__vpiModPathSrc() int __vpiModPathSrc::get_type_code(void) const { return vpiModPath; } +int __vpiModPathSrc::vpi_get(int code) +{ return modpath_src_get(code, this); } + +void __vpiModPathSrc::vpi_get_value(p_vpi_value val) +{ modpath_src_get_value(this, val); } + +vpiHandle __vpiModPathSrc::vpi_put_value(p_vpi_value val, int flags) +{ return modpath_src_put_value(this, val, flags); } + +vpiHandle __vpiModPathSrc::vpi_handle(int code) +{ return modpath_src_get_handle(code, this); } + +vpiHandle __vpiModPathSrc::vpi_iterate(int code) +{ return modpath_src_iterate(code, this); } + +vpiHandle __vpiModPathSrc:: vpi_index(int idx) +{ return modpath_src_index(this, idx); } + +void __vpiModPathSrc::vpi_get_delays(p_vpi_delay del) +{ modpath_src_get_delays(this, del); } + +void __vpiModPathSrc::vpi_put_delays(p_vpi_delay del) +{ modpath_src_put_delays(this, del); } + + static const struct __vpirt vpip_modpath_term_rt = { vpiPathTerm, - pathterm_get, + 0, 0, // vpi_get_str 0, // vpi_get_value, 0, // vpi_put_value, - pathterm_get_handle, + 0, //pathterm_get_handle, 0, // vpi_iterate, 0, // vpi_index, 0, // vpi_free_object, @@ -1015,6 +1040,12 @@ inline __vpiModPathTerm::__vpiModPathTerm() int __vpiModPathTerm::get_type_code(void) const { return vpiPathTerm; } +int __vpiModPathTerm::vpi_get(int code) +{ return pathterm_get(code, this); } + +vpiHandle __vpiModPathTerm::vpi_handle(int code) +{ return pathterm_get_handle(code, this); } + static void initialize_path_term(struct __vpiModPathTerm&obj) { obj.expr = 0; diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 0b9937829..4568146a0 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -28,6 +28,9 @@ struct enumconst_s : public __vpiHandle { enumconst_s(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); const char*name; vvp_vector2_t val2; @@ -37,6 +40,9 @@ struct enumconst_s : public __vpiHandle { struct __vpiEnumTypespec : public __vpiHandle { __vpiEnumTypespec(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_iterate(int code); std::vector names; int base_type_code; @@ -89,12 +95,12 @@ static vpiHandle enum_type_iterate(int code, vpiHandle obj) static const struct __vpirt enum_type_rt = { vpiEnumTypespec, - enum_type_get, + 0, //enum_type_get, 0, //enum_type_get_str, 0, //enum_type_get_value, 0, //enum_type_put_value, 0, //enum_type_handle, - enum_type_iterate, + 0, //enum_type_iterate, 0, //enum_type_index, 0, //enum_type_free_object, 0, //enum_type_get_delays, @@ -109,6 +115,15 @@ inline __vpiEnumTypespec::__vpiEnumTypespec() int __vpiEnumTypespec::get_type_code(void) const { return vpiEnumTypespec; } +int __vpiEnumTypespec::vpi_get(int code) +{ return enum_type_get(code, this); } + +char* __vpiEnumTypespec::vpi_get_str(int) +{ return 0; } + +vpiHandle __vpiEnumTypespec::vpi_iterate(int code) +{ return enum_type_iterate(code, this); } + static int enum_name_get(int code, vpiHandle obj) { struct enumconst_s*ref = dynamic_cast(obj); @@ -148,9 +163,9 @@ static void enum_name_get_value(vpiHandle obj, p_vpi_value value) static const struct __vpirt enum_name_rt = { vpiEnumConst, - enum_name_get, - enum_name_get_str, - enum_name_get_value, + 0, //enum_name_get, + 0, //enum_name_get_str, + 0, //enum_name_get_value, 0, //enum_name_put_value, 0, //enum_name_handle, 0, //enum_name_iterate, @@ -168,6 +183,15 @@ inline enumconst_s::enumconst_s() int enumconst_s::get_type_code(void) const { return vpiEnumConst; } +int enumconst_s::vpi_get(int code) +{ return enum_name_get(code, this); } + +char* enumconst_s::vpi_get_str(int code) +{ return enum_name_get_str(code, this); } + +void enumconst_s::vpi_get_value(p_vpi_value val) +{ enum_name_get_value(this, val); } + void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names) { diff --git a/vvp/file_line.cc b/vvp/file_line.cc index 10044be33..309a3f678 100644 --- a/vvp/file_line.cc +++ b/vvp/file_line.cc @@ -22,6 +22,8 @@ struct __vpiFileLine : public __vpiHandle { __vpiFileLine(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); const char *description; unsigned file_idx; @@ -63,8 +65,8 @@ static char *file_line_get_str(int type, vpiHandle ref) static const struct __vpirt vpip_file_line_rt = { _vpiFileLine, - file_line_get, - file_line_get_str, + 0, //file_line_get, + 0, //file_line_get_str, 0, 0, 0, @@ -83,6 +85,13 @@ inline __vpiFileLine::__vpiFileLine() int __vpiFileLine::get_type_code(void) const { return _vpiFileLine; } +int __vpiFileLine::vpi_get(int code) +{ return file_line_get(code, this); } + +char* __vpiFileLine::vpi_get_str(int code) +{ return file_line_get_str(code, this); } + + vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) { struct __vpiFileLine*obj = new struct __vpiFileLine; diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 92b77236f..d239a9802 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -168,9 +168,9 @@ static void string_value(vpiHandle ref, p_vpi_value vp) static const struct __vpirt vpip_string_rt = { vpiConstant, - string_get, 0, - string_value, + 0, + 0, //string_value, 0, 0, 0, @@ -187,6 +187,33 @@ inline __vpiStringConst::__vpiStringConst() int __vpiStringConst::get_type_code(void) const { return vpiConstant; } +int __vpiStringConst::vpi_get(int code) +{ return string_get(code, this); } + +char*__vpiStringConst::vpi_get_str(int) +{ return 0; } + +void __vpiStringConst::vpi_get_value(p_vpi_value val) +{ string_value(this, val); } + +vpiHandle __vpiStringConst::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiStringConst::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiStringConst::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiStringConst::vpi_index(int) +{ return 0; } + +void __vpiStringConst::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiStringConst::vpi_put_delays(p_vpi_delay) +{ } + struct __vpiStringConstTEMP : public __vpiStringConst { __vpiStringConstTEMP(); }; @@ -201,10 +228,10 @@ static int free_temp_string(vpiHandle obj) } static const struct __vpirt vpip_string_temp_rt = { - vpiConstant, - string_get, - 0, - string_value, + vpiConstant, // Inherit from __vpiStringConst + 0, // Inherit from __vpiStringConst + 0, // Inherit from __vpiStringConst + 0, // Inherit from __vpiStringConst: string_value, 0, 0, 0, @@ -266,6 +293,9 @@ vpiHandle vpip_make_string_const(char*text, bool persistent_flag) struct __vpiStringParam : public __vpiStringConst { __vpiStringParam(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); const char*basename; struct __vpiScope* scope; @@ -316,11 +346,11 @@ static vpiHandle string_param_handle(int code, vpiHandle obj) static const struct __vpirt vpip_string_param_rt = { vpiParameter, - string_param_get, - string_param_get_str, - string_value, 0, - string_param_handle, + 0, + 0, // Inherit from __vpiStringConst string_value, + 0, + 0, //string_param_handle, 0, 0, 0, @@ -336,6 +366,15 @@ inline __vpiStringParam::__vpiStringParam() int __vpiStringParam::get_type_code(void) const { return vpiParameter; } +int __vpiStringParam::vpi_get(int code) +{ return string_param_get(code, this); } + +char*__vpiStringParam::vpi_get_str(int code) +{ return string_param_get_str(code, this); } + +vpiHandle __vpiStringParam::vpi_handle(int code) +{ return string_param_handle(code, this); } + vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { @@ -416,9 +455,9 @@ static void binary_value(vpiHandle ref, p_vpi_value vp) static const struct __vpirt vpip_binary_rt = { vpiConstant, - binary_get, 0, - binary_value, + 0, + 0, //binary_value, 0, 0, 0, @@ -436,6 +475,33 @@ inline __vpiBinaryConst::__vpiBinaryConst() int __vpiBinaryConst::get_type_code(void) const { return vpiConstant; } +int __vpiBinaryConst::vpi_get(int code) +{ return binary_get(code, this); } + +char* __vpiBinaryConst::vpi_get_str(int) +{ return 0; } + +void __vpiBinaryConst::vpi_get_value(p_vpi_value val) +{ binary_value(this, val); } + +vpiHandle __vpiBinaryConst::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiBinaryConst::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiBinaryConst::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiBinaryConst::vpi_index(int) +{ return 0; } + +void __vpiBinaryConst::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiBinaryConst::vpi_put_delays(p_vpi_delay) +{ } + /* * Make a VPI constant from a vector string. The string is normally a * ASCII string, with each letter a 4-value bit. The first character @@ -489,6 +555,9 @@ vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) struct __vpiBinaryParam : public __vpiBinaryConst { __vpiBinaryParam(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); const char*basename; struct __vpiScope*scope; @@ -536,11 +605,11 @@ static vpiHandle binary_param_handle(int code, vpiHandle obj) static const struct __vpirt vpip_binary_param_rt = { vpiParameter, - binary_param_get, - binary_param_get_str, - binary_value, 0, - binary_param_handle, + 0, + 0, //Inherit from __vpiBinaryConst: binary_value, + 0, + 0, //binary_param_handle, 0, 0, 0, @@ -555,6 +624,15 @@ inline __vpiBinaryParam::__vpiBinaryParam() int __vpiBinaryParam::get_type_code(void) const { return vpiParameter; } +int __vpiBinaryParam::vpi_get(int code) +{ return binary_param_get(code, this); } + +char*__vpiBinaryParam::vpi_get_str(int code) +{ return binary_param_get_str(code, this); } + +vpiHandle __vpiBinaryParam::vpi_handle(int code) +{ return binary_param_handle(code, this); } + vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno) @@ -654,9 +732,9 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) static const struct __vpirt vpip_dec_rt = { vpiConstant, - dec_get, 0, - dec_value, + 0, + 0, //dec_value, 0, 0, 0, @@ -674,6 +752,33 @@ __vpiDecConst::__vpiDecConst(int val) int __vpiDecConst::get_type_code(void) const { return vpiConstant; } +int __vpiDecConst::vpi_get(int code) +{ return dec_get(code, this); } + +char* __vpiDecConst::vpi_get_str(int) +{ return 0; } + +void __vpiDecConst::vpi_get_value(p_vpi_value val) +{ dec_value(this, val); } + +vpiHandle __vpiDecConst::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiDecConst::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiDecConst::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiDecConst::vpi_index(int) +{ return 0; } + +void __vpiDecConst::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiDecConst::vpi_put_delays(p_vpi_delay) +{ } + static int real_get(int code, vpiHandle) { @@ -714,9 +819,9 @@ static void real_value(vpiHandle ref, p_vpi_value vp) static const struct __vpirt vpip_real_rt = { vpiConstant, - real_get, 0, - real_value, + 0, + 0, //real_value, 0, 0, 0, @@ -733,6 +838,32 @@ inline __vpiRealConst::__vpiRealConst() int __vpiRealConst::get_type_code(void) const { return vpiConstant; } +int __vpiRealConst::vpi_get(int code) +{ return real_get(code, this); } + +char* __vpiRealConst::vpi_get_str(int) +{ return 0; } + +void __vpiRealConst::vpi_get_value(p_vpi_value val) +{ real_value(this, val); } + +vpiHandle __vpiRealConst::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiRealConst::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiRealConst::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiRealConst::vpi_index(int) +{ return 0; } + +void __vpiRealConst::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiRealConst::vpi_put_delays(p_vpi_delay) +{ } vpiHandle vpip_make_real_const(double value) { @@ -744,7 +875,10 @@ vpiHandle vpip_make_real_const(double value) struct __vpiRealParam : public __vpiRealConst { __vpiRealParam(); int get_type_code(void) const; - + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); + const char*basename; struct __vpiScope* scope; unsigned file_idx; @@ -791,11 +925,11 @@ static vpiHandle real_param_handle(int code, vpiHandle obj) static const struct __vpirt vpip_real_param_rt = { vpiParameter, - real_param_get, - real_param_get_str, - real_value, 0, - real_param_handle, + 0, + 0, //Inherited from __vpiRealConst: real_value, + 0, + 0, //real_param_handle, 0, 0, 0, @@ -810,6 +944,15 @@ inline __vpiRealParam::__vpiRealParam() int __vpiRealParam::get_type_code(void) const { return vpiParameter; } +int __vpiRealParam::vpi_get(int code) +{ return real_param_get(code, this); } + +char* __vpiRealParam::vpi_get_str(int code) +{ return real_param_get_str(code, this); } + +vpiHandle __vpiRealParam::vpi_handle(int code) +{ return real_param_handle(code, this); } + vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 33131f9f6..2ccd565f4 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -69,11 +69,11 @@ static vpiHandle named_event_get_handle(int code, vpiHandle ref) static const struct __vpirt vpip_named_event_rt = { vpiNamedEvent, - named_event_get, - named_event_get_str, + 0, //named_event_get, + 0, //named_event_get_str, 0, 0, - named_event_get_handle, + 0, //named_event_get_handle, 0, 0, 0, @@ -88,6 +88,14 @@ inline __vpiNamedEvent::__vpiNamedEvent() int __vpiNamedEvent::get_type_code(void) const { return vpiNamedEvent; } +int __vpiNamedEvent::vpi_get(int code) +{ return named_event_get(code, this); } + +char* __vpiNamedEvent::vpi_get_str(int code) +{ return named_event_get_str(code, this); } + +vpiHandle __vpiNamedEvent::vpi_handle(int code) +{ return named_event_get_handle(code, this); } vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index b8e5f6d4d..cf2a994e7 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -34,6 +34,37 @@ FILE*vpi_trace = 0; static s_vpi_vlog_info vpi_vlog_info; static s_vpi_error_info vpip_last_error = { 0, 0, 0, 0, 0, 0, 0 }; +__vpiHandle::~__vpiHandle() +{ } + +int __vpiHandle::vpi_get(int) +{ return vpiUndefined; } + +char* __vpiHandle::vpi_get_str(int) +{ return 0; } + +void __vpiHandle::vpi_get_value(p_vpi_value) +{ } + +vpiHandle __vpiHandle::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_index(int) +{ return 0; } + +void __vpiHandle::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiHandle::vpi_put_delays(p_vpi_delay) +{ } + + /* * The vpip_string function creates a constant string from the pass * input. This constant string is permanently allocated from an @@ -919,9 +950,6 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, { assert(obj); - if (! obj->can_put_value()) - return 0; - flags &= ~vpiReturnEvent; if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index accfc21fe..24d7ad580 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -122,44 +122,23 @@ class __vpiHandle { public: inline __vpiHandle(const struct __vpirt *tp) : vpi_type_(tp) { } // The descructor is virtual so that dynamic types will work. - virtual ~__vpiHandle() { } + virtual ~__vpiHandle(); virtual int get_type_code(void) const =0; + virtual int vpi_get(int code); + virtual char* vpi_get_str(int code); - inline int vpi_get(int code) - { return vpi_type_->vpi_get_? vpi_type_->vpi_get_(code,this) : vpiUndefined; } - - inline char* vpi_get_str(int code) - { return vpi_type_->vpi_get_str_? vpi_type_->vpi_get_str_(code, this) : 0; } - - inline void vpi_get_value(p_vpi_value val) - { if (vpi_type_->vpi_get_value_) vpi_type_->vpi_get_value_(this, val); - else val->format = vpiSuppressVal; - } - - inline bool can_put_value() const { return vpi_type_->vpi_put_value_ != 0; } - - inline vpiHandle vpi_put_value(p_vpi_value val, int flags) - { return vpi_type_->vpi_put_value_? vpi_type_->vpi_put_value_(this, val, flags) : 0; } - - inline vpiHandle vpi_handle(int code) - { return vpi_type_->handle_? vpi_type_->handle_(code, this) : 0; } - - inline vpiHandle vpi_iterate(int code) - { return vpi_type_->iterate_? vpi_type_->iterate_(code, this) : 0; } - - inline vpiHandle vpi_index(int idx) - { return vpi_type_->index_? vpi_type_->index_(this, idx) : 0; } + virtual void vpi_get_value(p_vpi_value val); + virtual vpiHandle vpi_put_value(p_vpi_value val, int flags); + virtual vpiHandle vpi_handle(int code); + virtual vpiHandle vpi_iterate(int code); + virtual vpiHandle vpi_index(int idx); + virtual void vpi_get_delays(p_vpi_delay del); + virtual void vpi_put_delays(p_vpi_delay del); static inline int vpi_free_object(vpiHandle ref) { return ref->vpi_type_->vpi_free_object_? ref->vpi_type_->vpi_free_object_(ref) : 1; } - inline void vpi_get_delays(p_vpi_delay del) - { if (vpi_type_->vpi_get_delays_) vpi_type_->vpi_get_delays_(this, del); } - - inline void vpi_put_delays(p_vpi_delay del) - { if (vpi_type_->vpi_put_delays_) vpi_type_->vpi_put_delays_(this, del); } - private: const struct __vpirt *vpi_type_; }; @@ -220,6 +199,15 @@ extern void callback_execute(struct __vpiCallback*cur); struct __vpiSystemTime : public __vpiHandle { __vpiSystemTime(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); struct __vpiScope*scope; protected: @@ -228,12 +216,21 @@ struct __vpiSystemTime : public __vpiHandle { struct __vpiScopedTime : public __vpiSystemTime { __vpiScopedTime(); + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); }; struct __vpiScopedSTime : public __vpiSystemTime { __vpiScopedSTime(); + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); }; struct __vpiScopedRealtime : public __vpiSystemTime { __vpiScopedRealtime(); + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); }; @@ -243,6 +240,11 @@ struct __vpiScopedRealtime : public __vpiSystemTime { * scope. */ struct __vpiScope : public __vpiHandle { + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + struct __vpiScope *scope; /* The scope has a name. */ const char*name; @@ -293,6 +295,12 @@ extern void vpip_make_root_iterator(struct __vpiHandle**&table, * a declared name and declaration indices. */ struct __vpiSignal : public __vpiHandle { + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); #ifdef CHECK_WITH_VALGRIND struct __vpiSignal *pool; @@ -341,6 +349,11 @@ extern vpiHandle vpip_make_net4(const char*name, int msb, int lsb, struct __vpiPV : public __vpiHandle { __vpiPV(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); vpiHandle parent; vvp_net_t*net; @@ -361,6 +374,8 @@ extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ob struct __vpiModPathTerm : public __vpiHandle { __vpiModPathTerm(); int get_type_code(void) const; + int vpi_get(int code); + vpiHandle vpi_handle(int code); vpiHandle expr; /* The value returned by vpi_get(vpiEdge, ...); */ @@ -370,6 +385,14 @@ struct __vpiModPathTerm : public __vpiHandle { struct __vpiModPathSrc : public __vpiHandle { __vpiModPathSrc(); int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); struct __vpiModPath *dest; int type; @@ -421,6 +444,9 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; struct __vpiNamedEvent : public __vpiHandle { __vpiNamedEvent(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); /* base name of the event object */ const char*name; @@ -452,6 +478,12 @@ extern bool is_net_array(vpiHandle obj); struct __vpiRealVar : public __vpiHandle { __vpiRealVar(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); union { // The scope or parent array that contains me. vpiHandle parent; @@ -532,6 +564,15 @@ extern struct __vpiSysTaskCall*vpip_cur_task; struct __vpiStringConst : public __vpiHandle { __vpiStringConst(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); char*value; size_t value_len; @@ -546,6 +587,15 @@ vpiHandle vpip_make_string_param(char*name, char*value, struct __vpiBinaryConst : public __vpiHandle { __vpiBinaryConst(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); vvp_vector4_t bits; /* TRUE if this constant is signed. */ @@ -564,6 +614,15 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, struct __vpiDecConst : public __vpiHandle { __vpiDecConst(int val =0); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); int value; }; @@ -571,6 +630,15 @@ struct __vpiDecConst : public __vpiHandle { struct __vpiRealConst : public __vpiHandle { __vpiRealConst(); int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); double value; protected: diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index c13449e8d..c0d2db69c 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -138,13 +138,13 @@ static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) static const struct __vpirt vpip_real_var_rt = { vpiRealVar, - real_var_get, - real_var_get_str, - real_var_get_value, - real_var_put_value, + 0, //real_var_get, + 0, //real_var_get_str, + 0, //real_var_get_value, + 0, //real_var_put_value, - real_var_get_handle, - real_var_iterate, + 0, //real_var_get_handle, + 0, //real_var_iterate, 0, 0, 0, @@ -158,6 +158,23 @@ inline __vpiRealVar::__vpiRealVar() int __vpiRealVar::get_type_code(void) const { return vpiRealVar; } +int __vpiRealVar::vpi_get(int code) +{ return real_var_get(code, this); } + +char* __vpiRealVar::vpi_get_str(int code) +{ return real_var_get_str(code, this); } + +void __vpiRealVar::vpi_get_value(p_vpi_value val) +{ real_var_get_value(this, val); } + +vpiHandle __vpiRealVar::vpi_put_value(p_vpi_value val, int flags) +{ return real_var_put_value(this, val, flags); } + +vpiHandle __vpiRealVar::vpi_handle(int code) +{ return real_var_get_handle(code, this); } + +vpiHandle __vpiRealVar::vpi_iterate(int code) +{ return real_var_iterate(code, this); } void vpip_real_value_change(struct __vpiCallback*cbh, vpiHandle ref) diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index bf0395474..92b90eeac 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -306,14 +306,26 @@ static vpiHandle module_iter(int code, vpiHandle obj) } +int __vpiScope::vpi_get(int code) +{ return scope_get(code, this); } + +char*__vpiScope::vpi_get_str(int code) +{ return scope_get_str(code, this); } + +vpiHandle __vpiScope::vpi_handle(int code) +{ return scope_get_handle(code, this); } + +vpiHandle __vpiScope::vpi_iterate(int code) +{ return module_iter(code, this); } + static const struct __vpirt vpip_scope_module_rt = { vpiModule, - scope_get, - scope_get_str, + 0, // Inherit from__vpiScope: scope_get, + 0, // Inherit from __vpiScope: scope_get_str, 0, 0, - scope_get_handle, - module_iter, + 0, // Inherit from__vpiScope: scope_get_handle, + 0, // Inherit from__vpiScope: module_iter, 0, 0, 0, @@ -327,12 +339,12 @@ struct vpiScopeModule : public __vpiScope { static const struct __vpirt vpip_scope_task_rt = { vpiTask, - scope_get, - scope_get_str, + 0, // Inherit from__vpiScope: scope_get, + 0, // Inherit from __vpiScope: scope_get_str, 0, 0, - scope_get_handle, - module_iter, + 0, // Inherit from__vpiScope: scope_get_handle, + 0, // Inherit from__vpiScope: module_iter, 0, 0, 0, @@ -346,12 +358,12 @@ struct vpiScopeTask : public __vpiScope { static const struct __vpirt vpip_scope_function_rt = { vpiFunction, - scope_get, - scope_get_str, + 0, // Inherit from__vpiScope: scope_get, + 0, // Inherit from __vpiScope: scope_get_str, 0, 0, - scope_get_handle, - module_iter, + 0, // Inherit from__vpiScope: scope_get_handle, + 0, // Inherit from__vpiScope: module_iter, 0, 0, 0, @@ -365,12 +377,12 @@ struct vpiScopeFunction : public __vpiScope { static const struct __vpirt vpip_scope_begin_rt = { vpiNamedBegin, - scope_get, - scope_get_str, + 0, // Inherit from__vpiScope: scope_get, + 0, // Inherit from __vpiScope: scope_get_str, 0, 0, - scope_get_handle, - module_iter, + 0, // Inherit from__vpiScope: scope_get_handle, + 0, // Inherit from__vpiScope: module_iter, 0, 0, 0, @@ -384,12 +396,12 @@ struct vpiScopeBegin : public __vpiScope { static const struct __vpirt vpip_scope_fork_rt = { vpiNamedFork, - scope_get, - scope_get_str, + 0, // Inherit from__vpiScope: scope_get, + 0, // Inherit from __vpiScope: scope_get_str, 0, 0, - scope_get_handle, - module_iter, + 0, // Inherit from__vpiScope: scope_get_handle, + 0, // Inherit from__vpiScope: module_iter, 0, 0, 0, diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index fb22826b6..80142f597 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -860,14 +860,32 @@ vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid) return val; } +int __vpiSignal::vpi_get(int code) +{ return signal_get(code, this); } + +char* __vpiSignal::vpi_get_str(int code) +{ return signal_get_str(code, this); } + +void __vpiSignal::vpi_get_value(p_vpi_value val) +{ signal_get_value(this, val); } + +vpiHandle __vpiSignal::vpi_put_value(p_vpi_value val, int flags) +{ return signal_put_value(this, val, flags); } + +vpiHandle __vpiSignal::vpi_handle(int code) +{ return signal_get_handle(code, this); } + +vpiHandle __vpiSignal::vpi_iterate(int code) +{ return signal_iterate(code, this); } + static const struct __vpirt vpip_reg_rt = { vpiReg, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -880,12 +898,12 @@ struct signal_reg : public __vpiSignal { static const struct __vpirt vpip_integer_rt = { vpiIntegerVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -898,12 +916,12 @@ struct signal_integer : public __vpiSignal { static const struct __vpirt vpip_net_rt = { vpiNet, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -916,12 +934,12 @@ struct signal_net : public __vpiSignal { static const struct __vpirt vpip_byte_rt = { vpiByteVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -934,12 +952,12 @@ struct signal_byte : public __vpiSignal { static const struct __vpirt vpip_bitvar_rt = { vpiBitVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -952,12 +970,12 @@ struct signal_bitvar : public __vpiSignal { static const struct __vpirt vpip_shortint_rt = { vpiShortIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -970,12 +988,12 @@ struct signal_shortint : public __vpiSignal { static const struct __vpirt vpip_int_rt = { vpiIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -988,12 +1006,12 @@ struct signal_int : public __vpiSignal { static const struct __vpirt vpip_longint_rt = { vpiLongIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, + 0, //Inherit from __vpiSignal: signal_get, + 0, //Inherit from __vpiSignal: signal_get_str, + 0, //Inherit from __vpiSignal: signal_get_value, + 0, //Inherit from __vpiSignal: signal_put_value, + 0, //Inherit from __vpiSignal: signal_get_handle, + 0, //Inherit from __vpiSignal: signal_iterate, 0, 0, 0, @@ -1378,6 +1396,7 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) vvp_vector4_t val = vec4_from_vpi_value(vp, width); + fprintf(stderr, "XXXX PV_put_value(..)\n"); /* * If the base is less than zero then trim off any unneeded * lower bits. @@ -1429,11 +1448,11 @@ static vpiHandle PV_get_handle(int code, vpiHandle ref) static const struct __vpirt vpip_PV_rt = { vpiPartSelect, - PV_get, - PV_get_str, - PV_get_value, - PV_put_value, - PV_get_handle, + 0, //PV_get, + 0, //PV_get_str, + 0, //PV_get_value, + 0, //PV_put_value, + 0, //PV_get_handle, 0, 0, 0, @@ -1448,6 +1467,21 @@ inline __vpiPV::__vpiPV() int __vpiPV::get_type_code(void) const { return vpiPartSelect; } +int __vpiPV::vpi_get(int code) +{ return PV_get(code, this); } + +char* __vpiPV::vpi_get_str(int code) +{ return PV_get_str(code, this); } + +void __vpiPV::vpi_get_value(p_vpi_value val) +{ PV_get_value(this, val); } + +vpiHandle __vpiPV::vpi_put_value(p_vpi_value val, int flags) +{ return PV_put_value(this, val, flags); } + +vpiHandle __vpiPV::vpi_handle(int code) +{ return PV_get_handle(code, this); } + vpiHandle vpip_make_PV(char*var, int base, int width) { struct __vpiPV*obj = new __vpiPV; diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 933fa0366..9239de611 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -156,12 +156,12 @@ static vpiHandle systask_iter(int, vpiHandle ref) static const struct __vpirt vpip_systask_rt = { vpiSysTaskCall, - systask_get, - systask_get_str, + 0, //systask_get, + 0, //systask_get_str, 0, 0, - systask_handle, - systask_iter, + 0, //systask_handle, + 0, //systask_iter, 0, 0, 0, @@ -170,6 +170,10 @@ static const struct __vpirt vpip_systask_rt = { struct systask_def : public __vpiSysTaskCall { inline systask_def() : __vpiSysTaskCall(&vpip_systask_rt) { } int get_type_code(void) const { return vpiSysTaskCall; } + int vpi_get(int code) { return systask_get(code, this); } + char*vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_handle(int code) { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } }; /* @@ -467,12 +471,12 @@ static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) static const struct __vpirt vpip_sysfunc_rt = { vpiSysFuncCall, - sysfunc_get, - systask_get_str, + 0, //sysfunc_get, + 0, //systask_get_str, 0, - sysfunc_put_value, - systask_handle, - systask_iter, + 0, //sysfunc_put_value, + 0, //systask_handle, + 0, //systask_iter, 0, 0, 0, @@ -481,16 +485,24 @@ static const struct __vpirt vpip_sysfunc_rt = { struct sysfunc_def : public __vpiSysTaskCall { inline sysfunc_def() : __vpiSysTaskCall(&vpip_sysfunc_rt) { } int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; static const struct __vpirt vpip_sysfunc_real_rt = { vpiSysFuncCall, - sysfunc_get, - systask_get_str, + 0, //sysfunc_get, + 0, //systask_get_str, 0, - sysfunc_put_real_value, - systask_handle, - systask_iter, + 0, //sysfunc_put_real_value, + 0, //systask_handle, + 0, //systask_iter, 0, 0, 0, @@ -499,16 +511,24 @@ static const struct __vpirt vpip_sysfunc_real_rt = { struct sysfunc_real : public __vpiSysTaskCall { inline sysfunc_real() : __vpiSysTaskCall(&vpip_sysfunc_real_rt) { } int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_real_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; static const struct __vpirt vpip_sysfunc_4net_rt = { vpiSysFuncCall, - sysfunc_get, - systask_get_str, + 0, //sysfunc_get, + 0, //systask_get_str, 0, - sysfunc_put_4net_value, - systask_handle, - systask_iter, + 0, //sysfunc_put_4net_value, + 0, //systask_handle, + 0, //systask_iter, 0, 0, 0, @@ -517,16 +537,24 @@ static const struct __vpirt vpip_sysfunc_4net_rt = { struct sysfunc_4net : public __vpiSysTaskCall { inline sysfunc_4net() : __vpiSysTaskCall(&vpip_sysfunc_4net_rt) { } int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_4net_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; static const struct __vpirt vpip_sysfunc_rnet_rt = { vpiSysFuncCall, - sysfunc_get, - systask_get_str, + 0, //sysfunc_get, + 0, //systask_get_str, 0, - sysfunc_put_rnet_value, - systask_handle, - systask_iter, + 0, //sysfunc_put_rnet_value, + 0, //systask_handle, + 0, //systask_iter, 0, 0, 0, @@ -535,12 +563,20 @@ static const struct __vpirt vpip_sysfunc_rnet_rt = { struct sysfunc_rnet : public __vpiSysTaskCall { inline sysfunc_rnet() : __vpiSysTaskCall(&vpip_sysfunc_rnet_rt) { } int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_rnet_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; static const struct __vpirt vpip_sysfunc_no_rt = { vpiSysFuncCall, - sysfunc_get, - systask_get_str, + 0, //sysfunc_get, + 0, //systask_get_str, 0, sysfunc_put_no_value, systask_handle, @@ -553,6 +589,14 @@ static const struct __vpirt vpip_sysfunc_no_rt = { struct sysfunc_no : public __vpiSysTaskCall { inline sysfunc_no() : __vpiSysTaskCall(&vpip_sysfunc_no_rt) { } int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_no_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; /* **** Manipulate the internal data structures. **** */ @@ -603,6 +647,7 @@ void def_table_delete(void) struct __vpiSystfIterator : public __vpiHandle { __vpiSystfIterator(); int get_type_code(void) const; + vpiHandle vpi_index(int idx); unsigned next; }; @@ -644,7 +689,7 @@ static const struct __vpirt vpip_systf_iterator_rt = { 0, 0, 0, - systf_iterator_scan, + 0, //systf_iterator_scan, systf_iterator_free_object, 0, 0 @@ -657,6 +702,9 @@ inline __vpiSystfIterator::__vpiSystfIterator() int __vpiSystfIterator::get_type_code(void) const { return vpiIterator; } +vpiHandle __vpiSystfIterator::vpi_index(int idx) +{ return systf_iterator_scan(this, idx); } + vpiHandle vpip_make_systf_iterator(void) { /* Check to see if there are any user defined functions. */ diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index d45f23eac..741e76bd7 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -313,11 +313,11 @@ static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp) static const struct __vpirt vpip_system_time_rt = { vpiSysFuncCall, - timevar_time_get, - timevar_time_get_str, - timevar_get_ivalue, 0, - timevar_handle, + 0, //timevar_time_get_str, + 0, //timevar_get_ivalue, + 0, + 0, //Inherit from __vpiSystemTime: timevar_handle, 0, 0, 0, @@ -329,13 +329,22 @@ __vpiScopedTime::__vpiScopedTime() { } +int __vpiScopedTime::vpi_get(int code) +{ return timevar_time_get(code, this); } + +char* __vpiScopedTime::vpi_get_str(int code) +{ return timevar_time_get_str(code, this); } + +void __vpiScopedTime::vpi_get_value(p_vpi_value val) +{ timevar_get_ivalue(this, val); } + static const struct __vpirt vpip_system_stime_rt = { vpiSysFuncCall, - timevar_stime_get, - timevar_stime_get_str, - timevar_get_svalue, 0, - timevar_handle, + 0, + 0, //timevar_get_svalue, + 0, + 0, //Inherit from __vpiSystemTime: timevar_handle, 0, 0, 0, @@ -347,13 +356,22 @@ __vpiScopedSTime::__vpiScopedSTime() { } +int __vpiScopedSTime::vpi_get(int code) +{ return timevar_stime_get(code, this); } + +char* __vpiScopedSTime::vpi_get_str(int code) +{ return timevar_stime_get_str(code, this); } + +void __vpiScopedSTime::vpi_get_value(p_vpi_value val) +{ timevar_get_svalue(this, val); } + static const struct __vpirt vpip_system_simtime_rt = { vpiSysFuncCall, - timevar_time_get, - timevar_simtime_get_str, - timevar_get_ivalue, 0, - timevar_handle, + 0, + 0, //timevar_get_ivalue, + 0, + 0, //timevar_handle, 0, 0, 0, @@ -367,17 +385,42 @@ __vpiSystemTime::__vpiSystemTime() } int __vpiSystemTime::get_type_code(void) const -{ - return vpiSysFuncCall; -} +{ return vpiSysFuncCall; } + +int __vpiSystemTime::vpi_get(int code) +{ return timevar_time_get(code, this); } + +char* __vpiSystemTime::vpi_get_str(int code) +{ return timevar_simtime_get_str(code, this); } + +void __vpiSystemTime::vpi_get_value(p_vpi_value val) +{ timevar_get_ivalue(this, val); } + +vpiHandle __vpiSystemTime::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiSystemTime::vpi_handle(int code) +{ return timevar_handle(code, this); } + +vpiHandle __vpiSystemTime::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiSystemTime::vpi_index(int) +{ return 0; } + +void __vpiSystemTime::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiSystemTime::vpi_put_delays(p_vpi_delay) +{ } static const struct __vpirt vpip_system_realtime_rt = { vpiSysFuncCall, - timevar_realtime_get, - timevar_realtime_get_str, - timevar_get_rvalue, 0, - timevar_handle, + 0, + 0, //timevar_get_rvalue, + 0, + 0, //Inherit from __vpiSystemTime: timevar_handle, 0, 0, 0, @@ -389,6 +432,14 @@ __vpiScopedRealtime::__vpiScopedRealtime() { } +int __vpiScopedRealtime::vpi_get(int code) +{ return timevar_realtime_get(code, this); } + +char* __vpiScopedRealtime::vpi_get_str(int code) +{ return timevar_realtime_get_str(code, this); } + +void __vpiScopedRealtime::vpi_get_value(p_vpi_value val) +{ timevar_get_rvalue(this, val); } /* * Create a handle to represent a call to $time/$stime/$simtime. The diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 6f875997a..68795bf46 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -38,6 +38,10 @@ struct __vpiVThrVec : public __vpiHandle { __vpiVThrVec(); int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); unsigned bas; unsigned wid; @@ -436,10 +440,10 @@ static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int) static const struct __vpirt vpip_vthr_const_rt = { vpiConstant, - vthr_vec_get, - vthr_vec_get_str, - vthr_vec_get_value, - vthr_vec_put_value, + 0, //vthr_vec_get, + 0, //vthr_vec_get_str, + 0, //vthr_vec_get_value, + 0, //vthr_vec_put_value, 0, 0, 0, @@ -455,6 +459,17 @@ inline __vpiVThrVec::__vpiVThrVec() int __vpiVThrVec::get_type_code(void) const { return vpiConstant; } +int __vpiVThrVec::vpi_get(int code) +{ return vthr_vec_get(code, this); } + +char* __vpiVThrVec::vpi_get_str(int code) +{ return vthr_vec_get_str(code, this); } + +void __vpiVThrVec::vpi_get_value(p_vpi_value val) +{ vthr_vec_get_value(this, val); } + +vpiHandle __vpiVThrVec::vpi_put_value(p_vpi_value val, int flags) +{ return vthr_vec_put_value(this, val, flags); } /* * Construct a vpiReg object. Give the object specified dimensions, @@ -491,6 +506,8 @@ static void thread_vthr_delete_real(vpiHandle item) struct __vpiVThrWord : public __vpiHandle { __vpiVThrWord(); int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); const char* name; int subtype; @@ -588,9 +605,9 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) static const struct __vpirt vpip_vthr_const_real_rt = { vpiConstant, - vthr_word_get, + 0, //vthr_word_get, 0, - vthr_real_get_value, + 0, //vthr_real_get_value, 0, 0, 0, @@ -607,6 +624,12 @@ inline __vpiVThrWord::__vpiVThrWord() int __vpiVThrWord::get_type_code(void) const { return vpiConstant; } +int __vpiVThrWord::vpi_get(int code) +{ return vthr_word_get(code, this); } + +void __vpiVThrWord::vpi_get_value(p_vpi_value val) +{ vthr_real_get_value(this, val); } + vpiHandle vpip_make_vthr_word(unsigned base, const char*type) { struct __vpiVThrWord*obj = new __vpiVThrWord; From d6dba0456cfe7a4002e51b9b618e56f714d977f6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 20 Jan 2012 14:15:26 -0800 Subject: [PATCH 24/88] Fully remove the __vpirt structure All the methods that this structure supported are now pulled into the __vpiHandle class as virtual methods. This includes the vpi_free_object_ method, which required some extra trickery. --- vvp/array.cc | 139 ++++---------------------------- vvp/delay.cc | 37 +-------- vvp/enum_type.cc | 39 +-------- vvp/file_line.cc | 18 +---- vvp/vpi_callback.cc | 20 +---- vvp/vpi_const.cc | 179 +++-------------------------------------- vvp/vpi_event.cc | 18 +---- vvp/vpi_iter.cc | 20 +---- vvp/vpi_priv.cc | 8 +- vvp/vpi_priv.h | 78 ++++-------------- vvp/vpi_real.cc | 19 +---- vvp/vpi_scope.cc | 79 ++---------------- vvp/vpi_signal.cc | 137 +++---------------------------- vvp/vpi_tasks.cc | 129 +++-------------------------- vvp/vpi_time.cc | 66 +-------------- vvp/vpi_vthr_vector.cc | 34 +------- 16 files changed, 96 insertions(+), 924 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 45c3d0283..cfe4327d0 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -116,6 +116,7 @@ struct __vpiArrayIterator : public __vpiHandle { int vpi_get(int code); char* vpi_get_str(int code); vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); struct __vpiArray*array; unsigned next; @@ -128,6 +129,7 @@ struct __vpiArrayIndex : public __vpiHandle { char* vpi_get_str(int code); vpiHandle vpi_iterate(int code); vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); struct __vpiDecConst *index; unsigned done; @@ -289,8 +291,6 @@ struct __vpiArrayWord { struct as_index_t : public __vpiHandle { as_index_t(); int get_type_code(void) const; - int vpi_get(int code); - char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); } as_index; @@ -331,23 +331,8 @@ static int vpi_array_vthr_APV_get(int code, vpiHandle); static char*vpi_array_vthr_APV_get_str(int code, vpiHandle); static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp); -static const struct __vpirt vpip_arraymem_rt = { - vpiMemory, - 0, //vpi_array_get, - 0, //vpi_array_get_str, - 0, - 0, - 0, //vpi_array_get_handle, - 0, //vpi_array_iterate, - 0, //vpi_array_index, - 0, - 0, - 0 -}; inline __vpiArray::__vpiArray() -: __vpiHandle(&vpip_arraymem_rt) -{ -} +{ } int __vpiArray::get_type_code(void) const { return vpiMemory; } @@ -367,24 +352,8 @@ vpiHandle __vpiArray::vpi_iterate(int code) vpiHandle __vpiArray::vpi_index(int idx) { return vpi_array_index(this, idx); } -static const struct __vpirt vpip_array_iterator_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - 0, - 0, //array_iterator_scan, - &array_iterator_free_object, - 0, - 0 -}; - inline __vpiArrayIterator::__vpiArrayIterator() -: __vpiHandle(&vpip_array_iterator_rt) -{ -} +{ } int __vpiArrayIterator::get_type_code(void) const { return vpiIterator; } @@ -398,27 +367,11 @@ char* __vpiArrayIterator::vpi_get_str(int) vpiHandle __vpiArrayIterator::vpi_index(int code) { return array_iterator_scan(this, code); } -/* This should look a bit odd since it provides a fake iteration on - * this object. This trickery is used to implement the two forms of - * index access, simple handle access and iteration access. */ -static const struct __vpirt vpip_array_index_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - 0, //array_index_iterate, - 0, //array_index_scan, - array_index_free_object, - 0, - 0 -}; +__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) +{ return &array_iterator_free_object; } inline __vpiArrayIndex::__vpiArrayIndex() -: __vpiHandle(&vpip_array_index_rt) -{ -} +{ } int __vpiArrayIndex::get_type_code(void) const { return vpiIterator; } @@ -435,23 +388,11 @@ vpiHandle __vpiArrayIndex::vpi_iterate(int code) vpiHandle __vpiArrayIndex::vpi_index(int idx) { return array_index_scan(this, idx); } -static const struct __vpirt vpip_array_var_word_rt = { - vpiMemoryWord, - 0, //&vpi_array_var_word_get, - 0, //&vpi_array_var_word_get_str, - 0, //&vpi_array_var_word_get_value, - 0, //&vpi_array_var_word_put_value, - 0, //&vpi_array_var_word_get_handle, - 0, - 0, - 0, - 0, - 0 -}; +__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void) +{ return &array_index_free_object; } + inline __vpiArrayWord::as_word_t::as_word_t() -: __vpiHandle(&vpip_array_var_word_rt) -{ -} +{ } int __vpiArrayWord::as_word_t::get_type_code(void) const { return vpiMemoryWord; } @@ -471,54 +412,17 @@ vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value val, int flags) vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) { return vpi_array_var_word_get_handle(code, this); } -static const struct __vpirt vpip_array_var_index_rt = { - vpiIndex, - 0, - 0, - &vpi_array_var_index_get_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiArrayWord::as_index_t::as_index_t() -: __vpiHandle(&vpip_array_var_index_rt) -{ -} +{ } int __vpiArrayWord::as_index_t::get_type_code(void) const { return vpiIndex; } -int __vpiArrayWord::as_index_t::vpi_get(int) -{ return vpiUndefined; } - -char* __vpiArrayWord::as_index_t::vpi_get_str(int) -{ return 0; } - void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value val) { vpi_array_var_index_get_value(this, val); } -static const struct __vpirt vpip_array_vthr_A_rt = { - vpiMemoryWord, - 0, //&vpi_array_vthr_A_get, - 0, //&vpi_array_vthr_A_get_str, - 0, //&vpi_array_vthr_A_get_value, - 0, //&vpi_array_vthr_A_put_value, - 0, //&vpi_array_vthr_A_get_handle, - 0, - 0, - 0, - 0, - 0 -}; - inline __vpiArrayVthrA::__vpiArrayVthrA() -: __vpiHandle(&vpip_array_vthr_A_rt) -{ -} +{ } int __vpiArrayVthrA::get_type_code(void) const { return vpiMemoryWord; } @@ -538,24 +442,9 @@ vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value val, int flags) vpiHandle __vpiArrayVthrA::vpi_handle(int code) { return vpi_array_vthr_A_get_handle(code, this); } -static const struct __vpirt vpip_array_vthr_APV_rt = { - vpiMemoryWord, - 0, //&vpi_array_vthr_APV_get, - 0, //&vpi_array_vthr_APV_get_str, - 0, //&vpi_array_vthr_APV_get_value, - 0, //&vpi_array_vthr_A_put_value, - 0, //&vpi_array_vthr_A_get_handle, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() -: __vpiHandle(&vpip_array_vthr_APV_rt) -{ -} +{ } int __vpiArrayVthrAPV::get_type_code(void) const { return vpiMemoryWord; } diff --git a/vvp/delay.cc b/vvp/delay.cc index f4f9024f5..856481fcf 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -971,24 +971,8 @@ static vpiHandle pathterm_get_handle(int code, vpiHandle ref) * vpiModPath object. The __vpiModPath structure contains items that * are common to a bunch of modpaths, including the destination term. */ -static const struct __vpirt vpip_modpath_src_rt = { - vpiModPath, - 0, //modpath_src_get, - 0, /* vpi_get_str */ - 0, //modpath_src_get_value, - 0, //modpath_src_put_value, - 0, //modpath_src_get_handle, - 0, //modpath_src_iterate, - 0, //modpath_src_index, - modpath_src_free_object, - 0, //modpath_src_get_delays, - 0, //modpath_src_put_delays -}; - inline __vpiModPathSrc::__vpiModPathSrc() -: __vpiHandle(&vpip_modpath_src_rt) -{ -} +{ } int __vpiModPathSrc::get_type_code(void) const { return vpiModPath; } @@ -1017,25 +1001,12 @@ void __vpiModPathSrc::vpi_get_delays(p_vpi_delay del) void __vpiModPathSrc::vpi_put_delays(p_vpi_delay del) { modpath_src_put_delays(this, del); } +__vpiHandle::free_object_fun_t __vpiModPathSrc::free_object_fun(void) +{ return &modpath_src_free_object; } -static const struct __vpirt vpip_modpath_term_rt = { - vpiPathTerm, - 0, - 0, // vpi_get_str - 0, // vpi_get_value, - 0, // vpi_put_value, - 0, //pathterm_get_handle, - 0, // vpi_iterate, - 0, // vpi_index, - 0, // vpi_free_object, - 0, // vpi_get_delays, - 0 // vpi_put_delays -}; inline __vpiModPathTerm::__vpiModPathTerm() -: __vpiHandle(&vpip_modpath_term_rt) -{ -} +{ } int __vpiModPathTerm::get_type_code(void) const { return vpiPathTerm; } diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 4568146a0..794b11ba9 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -41,7 +41,6 @@ struct __vpiEnumTypespec : public __vpiHandle { __vpiEnumTypespec(); int get_type_code(void) const; int vpi_get(int code); - char*vpi_get_str(int code); vpiHandle vpi_iterate(int code); std::vector names; @@ -93,24 +92,9 @@ static vpiHandle enum_type_iterate(int code, vpiHandle obj) return 0; } -static const struct __vpirt enum_type_rt = { - vpiEnumTypespec, - 0, //enum_type_get, - 0, //enum_type_get_str, - 0, //enum_type_get_value, - 0, //enum_type_put_value, - 0, //enum_type_handle, - 0, //enum_type_iterate, - 0, //enum_type_index, - 0, //enum_type_free_object, - 0, //enum_type_get_delays, - 0, //enum_type_put_delays -}; inline __vpiEnumTypespec::__vpiEnumTypespec() -: __vpiHandle(&enum_type_rt) -{ -} +{ } int __vpiEnumTypespec::get_type_code(void) const { return vpiEnumTypespec; } @@ -118,9 +102,6 @@ int __vpiEnumTypespec::get_type_code(void) const int __vpiEnumTypespec::vpi_get(int code) { return enum_type_get(code, this); } -char* __vpiEnumTypespec::vpi_get_str(int) -{ return 0; } - vpiHandle __vpiEnumTypespec::vpi_iterate(int code) { return enum_type_iterate(code, this); } @@ -161,24 +142,8 @@ static void enum_name_get_value(vpiHandle obj, p_vpi_value value) vpip_vec2_get_value(ref->val2, ref->val2.size(), false, value); } -static const struct __vpirt enum_name_rt = { - vpiEnumConst, - 0, //enum_name_get, - 0, //enum_name_get_str, - 0, //enum_name_get_value, - 0, //enum_name_put_value, - 0, //enum_name_handle, - 0, //enum_name_iterate, - 0, //enum_name_index, - 0, //enum_name_free_object, - 0, //enum_name_get_delays, - 0, //enum_name_put_delays -}; - inline enumconst_s::enumconst_s() -: __vpiHandle(&enum_name_rt) -{ -} +{ } int enumconst_s::get_type_code(void) const { return vpiEnumConst; } diff --git a/vvp/file_line.cc b/vvp/file_line.cc index 309a3f678..99a1b2490 100644 --- a/vvp/file_line.cc +++ b/vvp/file_line.cc @@ -63,24 +63,8 @@ static char *file_line_get_str(int type, vpiHandle ref) } } -static const struct __vpirt vpip_file_line_rt = { - _vpiFileLine, - 0, //file_line_get, - 0, //file_line_get_str, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; - inline __vpiFileLine::__vpiFileLine() -: __vpiHandle(&vpip_file_line_rt) -{ -} +{ } int __vpiFileLine::get_type_code(void) const { return _vpiFileLine; } diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index f79acb429..e8e79c5c6 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -47,27 +47,15 @@ static int free_simple_callback(vpiHandle) return 1; } -const struct __vpirt callback_rt = { - vpiCallback, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - &free_simple_callback, - 0, - 0 -}; inline __vpiCallback::__vpiCallback() -: __vpiHandle(&callback_rt) -{ -} +{ } int __vpiCallback::get_type_code(void) const { return vpiCallback; } +__vpiHandle::free_object_fun_t __vpiCallback::free_object_fun(void) +{ return &free_simple_callback; } + /* * Callback handles are created when the VPI function registers a diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index d239a9802..46b4ad6f8 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -166,23 +166,8 @@ static void string_value(vpiHandle ref, p_vpi_value vp) } } -static const struct __vpirt vpip_string_rt = { - vpiConstant, - 0, - 0, - 0, //string_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiStringConst::__vpiStringConst() -: __vpiHandle(&vpip_string_rt) -{ -} +{ } int __vpiStringConst::get_type_code(void) const { return vpiConstant; } @@ -216,6 +201,7 @@ void __vpiStringConst::vpi_put_delays(p_vpi_delay) struct __vpiStringConstTEMP : public __vpiStringConst { __vpiStringConstTEMP(); + free_object_fun_t free_object_fun(void); }; static int free_temp_string(vpiHandle obj) @@ -227,24 +213,11 @@ static int free_temp_string(vpiHandle obj) return 1; } -static const struct __vpirt vpip_string_temp_rt = { - vpiConstant, // Inherit from __vpiStringConst - 0, // Inherit from __vpiStringConst - 0, // Inherit from __vpiStringConst - 0, // Inherit from __vpiStringConst: string_value, - 0, - 0, - 0, - 0, - free_temp_string, - 0, - 0 -}; inline __vpiStringConstTEMP::__vpiStringConstTEMP() -: __vpiStringConst(&vpip_string_temp_rt) -{ -} +{ } +__vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) +{ return &free_temp_string; } /* * Strings are described at the level of the vvp source as a string @@ -344,24 +317,9 @@ static vpiHandle string_param_handle(int code, vpiHandle obj) } } -static const struct __vpirt vpip_string_param_rt = { - vpiParameter, - 0, - 0, - 0, // Inherit from __vpiStringConst string_value, - 0, - 0, //string_param_handle, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiStringParam::__vpiStringParam() -: __vpiStringConst(&vpip_string_param_rt) -{ -} +{ } int __vpiStringParam::get_type_code(void) const { return vpiParameter; } @@ -453,24 +411,9 @@ static void binary_value(vpiHandle ref, p_vpi_value vp) } } -static const struct __vpirt vpip_binary_rt = { - vpiConstant, - 0, - 0, - 0, //binary_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiBinaryConst::__vpiBinaryConst() -: __vpiHandle(&vpip_binary_rt) -{ -} +{ } int __vpiBinaryConst::get_type_code(void) const { return vpiConstant; } @@ -603,23 +546,8 @@ static vpiHandle binary_param_handle(int code, vpiHandle obj) } } -static const struct __vpirt vpip_binary_param_rt = { - vpiParameter, - 0, - 0, - 0, //Inherit from __vpiBinaryConst: binary_value, - 0, - 0, //binary_param_handle, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiBinaryParam::__vpiBinaryParam() -: __vpiBinaryConst(&vpip_binary_param_rt) -{ -} +{ } int __vpiBinaryParam::get_type_code(void) const { return vpiParameter; } @@ -730,21 +658,7 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) } } -static const struct __vpirt vpip_dec_rt = { - vpiConstant, - 0, - 0, - 0, //dec_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; __vpiDecConst::__vpiDecConst(int val) -: __vpiHandle(&vpip_dec_rt) { value = val; } @@ -755,30 +669,9 @@ int __vpiDecConst::get_type_code(void) const int __vpiDecConst::vpi_get(int code) { return dec_get(code, this); } -char* __vpiDecConst::vpi_get_str(int) -{ return 0; } - void __vpiDecConst::vpi_get_value(p_vpi_value val) { dec_value(this, val); } -vpiHandle __vpiDecConst::vpi_put_value(p_vpi_value, int) -{ return 0; } - -vpiHandle __vpiDecConst::vpi_handle(int) -{ return 0; } - -vpiHandle __vpiDecConst::vpi_iterate(int) -{ return 0; } - -vpiHandle __vpiDecConst::vpi_index(int) -{ return 0; } - -void __vpiDecConst::vpi_get_delays(p_vpi_delay) -{ } - -void __vpiDecConst::vpi_put_delays(p_vpi_delay) -{ } - static int real_get(int code, vpiHandle) { @@ -817,23 +710,8 @@ static void real_value(vpiHandle ref, p_vpi_value vp) vpip_real_get_value(rfp->value, vp); } -static const struct __vpirt vpip_real_rt = { - vpiConstant, - 0, - 0, - 0, //real_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiRealConst::__vpiRealConst() -: __vpiHandle(&vpip_real_rt) -{ -} +{ } int __vpiRealConst::get_type_code(void) const { return vpiConstant; } @@ -841,30 +719,9 @@ int __vpiRealConst::get_type_code(void) const int __vpiRealConst::vpi_get(int code) { return real_get(code, this); } -char* __vpiRealConst::vpi_get_str(int) -{ return 0; } - void __vpiRealConst::vpi_get_value(p_vpi_value val) { real_value(this, val); } -vpiHandle __vpiRealConst::vpi_put_value(p_vpi_value, int) -{ return 0; } - -vpiHandle __vpiRealConst::vpi_handle(int) -{ return 0; } - -vpiHandle __vpiRealConst::vpi_iterate(int) -{ return 0; } - -vpiHandle __vpiRealConst::vpi_index(int) -{ return 0; } - -void __vpiRealConst::vpi_get_delays(p_vpi_delay) -{ } - -void __vpiRealConst::vpi_put_delays(p_vpi_delay) -{ } - vpiHandle vpip_make_real_const(double value) { struct __vpiRealConst*obj = new __vpiRealConst; @@ -923,23 +780,9 @@ static vpiHandle real_param_handle(int code, vpiHandle obj) } } -static const struct __vpirt vpip_real_param_rt = { - vpiParameter, - 0, - 0, - 0, //Inherited from __vpiRealConst: real_value, - 0, - 0, //real_param_handle, - 0, - 0, - 0, - 0, - 0 -}; + inline __vpiRealParam::__vpiRealParam() -: __vpiRealConst(&vpip_real_param_rt) -{ -} +{ } int __vpiRealParam::get_type_code(void) const { return vpiParameter; } diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 2ccd565f4..df402c17c 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -66,24 +66,8 @@ static vpiHandle named_event_get_handle(int code, vpiHandle ref) return 0; } -static const struct __vpirt vpip_named_event_rt = { - vpiNamedEvent, - - 0, //named_event_get, - 0, //named_event_get_str, - 0, - 0, - 0, //named_event_get_handle, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiNamedEvent::__vpiNamedEvent() -: __vpiHandle(&vpip_named_event_rt) -{ -} +{ } int __vpiNamedEvent::get_type_code(void) const { return vpiNamedEvent; } diff --git a/vvp/vpi_iter.cc b/vvp/vpi_iter.cc index 233b037e3..723803b8b 100644 --- a/vvp/vpi_iter.cc +++ b/vvp/vpi_iter.cc @@ -38,27 +38,15 @@ static int iterator_free_object(vpiHandle ref) return 1; } -static const struct __vpirt vpip_iterator_rt = { - vpiIterator, - 0, // vpi_get_ - 0, // vpi_get_str_ - 0, // vpi_get_value_ - 0, // vpi_put_value_ - 0, // handle_ - 0, // iterate_ - 0, // index_ - &iterator_free_object, - 0, // vpi_get_delay - 0 // vpi_put_delay -}; inline __vpiIterator::__vpiIterator() -: __vpiHandle(&vpip_iterator_rt) -{ -} +{ } int __vpiIterator::get_type_code(void) const { return vpiIterator; } +__vpiHandle::free_object_fun_t __vpiIterator::free_object_fun(void) +{ return &iterator_free_object; } + vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, bool free_args_flag) { diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index cf2a994e7..67dc6ba09 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -64,6 +64,8 @@ void __vpiHandle::vpi_get_delays(p_vpi_delay) void __vpiHandle::vpi_put_delays(p_vpi_delay) { } +__vpiHandle::free_object_fun_t __vpiHandle::free_object_fun(void) +{ return 0; } /* * The vpip_string function creates a constant string from the pass @@ -231,7 +233,11 @@ PLI_INT32 vpi_free_object(vpiHandle ref) } assert(ref); - rtn = __vpiHandle::vpi_free_object(ref); + __vpiHandle::free_object_fun_t fun = ref->free_object_fun(); + if (fun) + rtn = fun (ref); + else + rtn = 1; if (vpi_trace) fprintf(vpi_trace, " --> %d\n", rtn); diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 24d7ad580..039922849 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -83,36 +83,6 @@ enum vpi_mode_t { }; extern vpi_mode_t vpi_mode_flag; -/* - * Objects with this structure are used to represent a type of - * vpiHandle. A specific object becomes of this type by holding a - * pointer to an instance of this structure. - */ -struct __vpirt { - int type_code_X; - - /* These methods extract information from the handle. */ - int (*vpi_get_)(int, vpiHandle); - char* (*vpi_get_str_)(int, vpiHandle); - void (*vpi_get_value_)(vpiHandle, p_vpi_value); - vpiHandle (*vpi_put_value_)(vpiHandle, p_vpi_value, int flags); - - /* These methods follow references. */ - vpiHandle (*handle_)(int, vpiHandle); - vpiHandle (*iterate_)(int, vpiHandle); - vpiHandle (*index_)(vpiHandle, int); - - /* This implements the vpi_free_object method. */ - int (*vpi_free_object_)(vpiHandle); - - /* - These two methods are used to read/write delay - values from/into modpath records - */ - void (*vpi_get_delays_)(vpiHandle, p_vpi_delay); - void (*vpi_put_delays_)(vpiHandle, p_vpi_delay); -}; - /* * This structure is the very base of a vpiHandle. Every handle * structure is derived from this class so that the library can @@ -120,8 +90,8 @@ struct __vpirt { */ class __vpiHandle { public: - inline __vpiHandle(const struct __vpirt *tp) : vpi_type_(tp) { } - // The descructor is virtual so that dynamic types will work. + inline __vpiHandle() { } + // The destructor is virtual so that dynamic types will work. virtual ~__vpiHandle(); virtual int get_type_code(void) const =0; @@ -136,11 +106,12 @@ class __vpiHandle { virtual void vpi_get_delays(p_vpi_delay del); virtual void vpi_put_delays(p_vpi_delay del); - static inline int vpi_free_object(vpiHandle ref) - { return ref->vpi_type_->vpi_free_object_? ref->vpi_type_->vpi_free_object_(ref) : 1; } - - private: - const struct __vpirt *vpi_type_; + // Objects may have destroyer functions of their own. If so, + // then this virtual method will return a POINTER to that + // function. The pointer is used to "delete" the object, which + // is why the function itself cannot be a method. + typedef int (*free_object_fun_t)(vpiHandle); + virtual free_object_fun_t free_object_fun(void); }; @@ -158,6 +129,7 @@ class __vpiHandle { struct __vpiIterator : public __vpiHandle { __vpiIterator(); int get_type_code(void) const; + free_object_fun_t free_object_fun(void); vpiHandle *args; unsigned nargs; @@ -176,6 +148,7 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, struct __vpiCallback : public __vpiHandle { __vpiCallback(); int get_type_code(void) const; + free_object_fun_t free_object_fun(void); // user supplied callback data struct t_cb_data cb_data; @@ -210,8 +183,6 @@ struct __vpiSystemTime : public __vpiHandle { void vpi_put_delays(p_vpi_delay del); struct __vpiScope*scope; - protected: - inline __vpiSystemTime(const struct __vpirt*rt) : __vpiHandle(rt) { } }; struct __vpiScopedTime : public __vpiSystemTime { @@ -275,8 +246,7 @@ struct __vpiScope : public __vpiHandle { signed int time_precision :8; protected: - __vpiScope(const struct __vpirt*rt) : __vpiHandle(rt) { } - + inline __vpiScope() { } }; extern struct __vpiScope* vpip_peek_current_scope(void); @@ -325,7 +295,7 @@ struct __vpiSignal : public __vpiHandle { static void*operator new(std::size_t size); static void operator delete(void*); // not implemented protected: - inline __vpiSignal(const struct __vpirt*rt) : __vpiHandle(rt) { } + inline __vpiSignal() { } private: // Not implemented static void*operator new[] (std::size_t size); static void operator delete[](void*); @@ -393,6 +363,7 @@ struct __vpiModPathSrc : public __vpiHandle { vpiHandle vpi_index(int idx); void vpi_get_delays(p_vpi_delay del); void vpi_put_delays(p_vpi_delay del); + free_object_fun_t free_object_fun(void); struct __vpiModPath *dest; int type; @@ -534,7 +505,6 @@ extern struct __vpiUserSystf* vpip_find_systf(const char*name); struct __vpiSysTaskCall : public __vpiHandle { - __vpiSysTaskCall(const struct __vpirt*rt) : __vpiHandle(rt) { } struct __vpiScope* scope; struct __vpiUserSystf*defn; @@ -549,6 +519,8 @@ struct __vpiSysTaskCall : public __vpiHandle { unsigned file_idx; unsigned lineno; bool put_value; + protected: + inline __vpiSysTaskCall() { } }; extern struct __vpiSysTaskCall*vpip_cur_task; @@ -576,8 +548,6 @@ struct __vpiStringConst : public __vpiHandle { char*value; size_t value_len; - protected: - inline __vpiStringConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_string_const(char*text, bool persistent =true); @@ -602,8 +572,6 @@ struct __vpiBinaryConst : public __vpiHandle { int signed_flag :1; /* TRUE if this constant has an explicit size (i.e. 19'h0 vs. 'h0) */ int sized_flag :1; - protected: - inline __vpiBinaryConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_binary_const(unsigned wid, const char*bits); @@ -615,14 +583,7 @@ struct __vpiDecConst : public __vpiHandle { __vpiDecConst(int val =0); int get_type_code(void) const; int vpi_get(int code); - char* vpi_get_str(int code); void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - void vpi_get_delays(p_vpi_delay del); - void vpi_put_delays(p_vpi_delay del); int value; }; @@ -631,18 +592,9 @@ struct __vpiRealConst : public __vpiHandle { __vpiRealConst(); int get_type_code(void) const; int vpi_get(int code); - char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - void vpi_get_delays(p_vpi_delay del); - void vpi_put_delays(p_vpi_delay del); double value; - protected: - inline __vpiRealConst(const struct __vpirt*rt) : __vpiHandle(rt) { } }; vpiHandle vpip_make_real_const(double value); diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index c0d2db69c..0b7f833fb 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -135,25 +135,8 @@ static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) return 0; } -static const struct __vpirt vpip_real_var_rt = { - vpiRealVar, - - 0, //real_var_get, - 0, //real_var_get_str, - 0, //real_var_get_value, - 0, //real_var_put_value, - - 0, //real_var_get_handle, - 0, //real_var_iterate, - 0, - 0, - 0, - 0 -}; inline __vpiRealVar::__vpiRealVar() -: __vpiHandle(&vpip_real_var_rt) -{ -} +{ } int __vpiRealVar::get_type_code(void) const { return vpiRealVar; } diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 92b90eeac..07341fe8b 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -318,98 +318,29 @@ vpiHandle __vpiScope::vpi_handle(int code) vpiHandle __vpiScope::vpi_iterate(int code) { return module_iter(code, this); } -static const struct __vpirt vpip_scope_module_rt = { - vpiModule, - 0, // Inherit from__vpiScope: scope_get, - 0, // Inherit from __vpiScope: scope_get_str, - 0, - 0, - 0, // Inherit from__vpiScope: scope_get_handle, - 0, // Inherit from__vpiScope: module_iter, - 0, - 0, - 0, - 0 -}; struct vpiScopeModule : public __vpiScope { - inline vpiScopeModule() : __vpiScope(&vpip_scope_module_rt) { } + inline vpiScopeModule() { } int get_type_code(void) const { return vpiModule; } }; -static const struct __vpirt vpip_scope_task_rt = { - vpiTask, - 0, // Inherit from__vpiScope: scope_get, - 0, // Inherit from __vpiScope: scope_get_str, - 0, - 0, - 0, // Inherit from__vpiScope: scope_get_handle, - 0, // Inherit from__vpiScope: module_iter, - 0, - 0, - 0, - 0 -}; - struct vpiScopeTask : public __vpiScope { - inline vpiScopeTask() : __vpiScope(&vpip_scope_task_rt) { } + inline vpiScopeTask() { } int get_type_code(void) const { return vpiTask; } }; -static const struct __vpirt vpip_scope_function_rt = { - vpiFunction, - 0, // Inherit from__vpiScope: scope_get, - 0, // Inherit from __vpiScope: scope_get_str, - 0, - 0, - 0, // Inherit from__vpiScope: scope_get_handle, - 0, // Inherit from__vpiScope: module_iter, - 0, - 0, - 0, - 0 -}; - struct vpiScopeFunction : public __vpiScope { - inline vpiScopeFunction() : __vpiScope(&vpip_scope_function_rt) { } + inline vpiScopeFunction() { } int get_type_code(void) const { return vpiFunction; } }; -static const struct __vpirt vpip_scope_begin_rt = { - vpiNamedBegin, - 0, // Inherit from__vpiScope: scope_get, - 0, // Inherit from __vpiScope: scope_get_str, - 0, - 0, - 0, // Inherit from__vpiScope: scope_get_handle, - 0, // Inherit from__vpiScope: module_iter, - 0, - 0, - 0, - 0 -}; - struct vpiScopeBegin : public __vpiScope { - inline vpiScopeBegin() : __vpiScope(&vpip_scope_begin_rt) { } + inline vpiScopeBegin() { } int get_type_code(void) const { return vpiNamedBegin; } }; -static const struct __vpirt vpip_scope_fork_rt = { - vpiNamedFork, - 0, // Inherit from__vpiScope: scope_get, - 0, // Inherit from __vpiScope: scope_get_str, - 0, - 0, - 0, // Inherit from__vpiScope: scope_get_handle, - 0, // Inherit from__vpiScope: module_iter, - 0, - 0, - 0, - 0 -}; - struct vpiScopeFork : public __vpiScope { - inline vpiScopeFork() : __vpiScope(&vpip_scope_fork_rt) { } + inline vpiScopeFork() { } int get_type_code(void) const { return vpiNamedFork; } }; diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 80142f597..1b3c656cc 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -878,147 +878,43 @@ vpiHandle __vpiSignal::vpi_handle(int code) vpiHandle __vpiSignal::vpi_iterate(int code) { return signal_iterate(code, this); } -static const struct __vpirt vpip_reg_rt = { - vpiReg, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_reg : public __vpiSignal { - inline signal_reg() : __vpiSignal(&vpip_reg_rt) { } + inline signal_reg() { } int get_type_code(void) const { return vpiReg; } }; -static const struct __vpirt vpip_integer_rt = { - vpiIntegerVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_integer : public __vpiSignal { - inline signal_integer() : __vpiSignal(&vpip_integer_rt) { } + inline signal_integer() { } int get_type_code(void) const { return vpiIntegerVar; } }; -static const struct __vpirt vpip_net_rt = { - vpiNet, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_net : public __vpiSignal { - inline signal_net() : __vpiSignal(&vpip_net_rt) { } + inline signal_net() { } int get_type_code(void) const { return vpiNet; } }; -static const struct __vpirt vpip_byte_rt = { - vpiByteVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_byte : public __vpiSignal { - inline signal_byte() : __vpiSignal(&vpip_byte_rt) { } + inline signal_byte() { } int get_type_code(void) const { return vpiByteVar; } }; -static const struct __vpirt vpip_bitvar_rt = { - vpiBitVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_bitvar : public __vpiSignal { - inline signal_bitvar() : __vpiSignal(&vpip_bitvar_rt) { } + inline signal_bitvar() { } int get_type_code(void) const { return vpiBitVar; } }; -static const struct __vpirt vpip_shortint_rt = { - vpiShortIntVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_shortint : public __vpiSignal { - inline signal_shortint() : __vpiSignal(&vpip_shortint_rt) { } + inline signal_shortint() { } int get_type_code(void) const { return vpiShortIntVar; } }; -static const struct __vpirt vpip_int_rt = { - vpiIntVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_int : public __vpiSignal { - inline signal_int() : __vpiSignal(&vpip_int_rt) { } + inline signal_int() { } int get_type_code(void) const { return vpiIntVar; } }; -static const struct __vpirt vpip_longint_rt = { - vpiLongIntVar, - 0, //Inherit from __vpiSignal: signal_get, - 0, //Inherit from __vpiSignal: signal_get_str, - 0, //Inherit from __vpiSignal: signal_get_value, - 0, //Inherit from __vpiSignal: signal_put_value, - 0, //Inherit from __vpiSignal: signal_get_handle, - 0, //Inherit from __vpiSignal: signal_iterate, - 0, - 0, - 0, - 0 -}; struct signal_longint : public __vpiSignal { - inline signal_longint() : __vpiSignal(&vpip_longint_rt) { } + inline signal_longint() { } int get_type_code(void) const { return vpiLongIntVar; } }; @@ -1446,23 +1342,8 @@ static vpiHandle PV_get_handle(int code, vpiHandle ref) return 0; } -static const struct __vpirt vpip_PV_rt = { - vpiPartSelect, - 0, //PV_get, - 0, //PV_get_str, - 0, //PV_get_value, - 0, //PV_put_value, - 0, //PV_get_handle, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiPV::__vpiPV() -: __vpiHandle(&vpip_PV_rt) -{ -} +{ } int __vpiPV::get_type_code(void) const { return vpiPartSelect; } diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 9239de611..59750325e 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -35,24 +35,8 @@ # include # include "ivl_alloc.h" -static const struct __vpirt vpip_systf_def_rt = { - vpiUserSystf, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; - inline __vpiUserSystf::__vpiUserSystf() -: __vpiHandle(&vpip_systf_def_rt) -{ -} +{ } int __vpiUserSystf::get_type_code(void) const { return vpiUserSystf; } @@ -154,21 +138,8 @@ static vpiHandle systask_iter(int, vpiHandle ref) return vpip_make_iterator(rfp->nargs, rfp->args, false); } -static const struct __vpirt vpip_systask_rt = { - vpiSysTaskCall, - 0, //systask_get, - 0, //systask_get_str, - 0, - 0, - 0, //systask_handle, - 0, //systask_iter, - 0, - 0, - 0, - 0 -}; struct systask_def : public __vpiSysTaskCall { - inline systask_def() : __vpiSysTaskCall(&vpip_systask_rt) { } + inline systask_def() { } int get_type_code(void) const { return vpiSysTaskCall; } int vpi_get(int code) { return systask_get(code, this); } char*vpi_get_str(int code) { return systask_get_str(code, this); } @@ -469,21 +440,8 @@ static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) return 0; } -static const struct __vpirt vpip_sysfunc_rt = { - vpiSysFuncCall, - 0, //sysfunc_get, - 0, //systask_get_str, - 0, - 0, //sysfunc_put_value, - 0, //systask_handle, - 0, //systask_iter, - 0, - 0, - 0, - 0 -}; struct sysfunc_def : public __vpiSysTaskCall { - inline sysfunc_def() : __vpiSysTaskCall(&vpip_sysfunc_rt) { } + inline sysfunc_def() { } int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code) { return sysfunc_get(code, this); } char* vpi_get_str(int code) { return systask_get_str(code, this); } @@ -495,21 +453,8 @@ struct sysfunc_def : public __vpiSysTaskCall { { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_real_rt = { - vpiSysFuncCall, - 0, //sysfunc_get, - 0, //systask_get_str, - 0, - 0, //sysfunc_put_real_value, - 0, //systask_handle, - 0, //systask_iter, - 0, - 0, - 0, - 0 -}; struct sysfunc_real : public __vpiSysTaskCall { - inline sysfunc_real() : __vpiSysTaskCall(&vpip_sysfunc_real_rt) { } + inline sysfunc_real() { } int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code) { return sysfunc_get(code, this); } char* vpi_get_str(int code) { return systask_get_str(code, this); } @@ -521,21 +466,8 @@ struct sysfunc_real : public __vpiSysTaskCall { { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_4net_rt = { - vpiSysFuncCall, - 0, //sysfunc_get, - 0, //systask_get_str, - 0, - 0, //sysfunc_put_4net_value, - 0, //systask_handle, - 0, //systask_iter, - 0, - 0, - 0, - 0 -}; struct sysfunc_4net : public __vpiSysTaskCall { - inline sysfunc_4net() : __vpiSysTaskCall(&vpip_sysfunc_4net_rt) { } + inline sysfunc_4net() { } int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code) { return sysfunc_get(code, this); } char* vpi_get_str(int code) { return systask_get_str(code, this); } @@ -547,21 +479,8 @@ struct sysfunc_4net : public __vpiSysTaskCall { { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_rnet_rt = { - vpiSysFuncCall, - 0, //sysfunc_get, - 0, //systask_get_str, - 0, - 0, //sysfunc_put_rnet_value, - 0, //systask_handle, - 0, //systask_iter, - 0, - 0, - 0, - 0 -}; struct sysfunc_rnet : public __vpiSysTaskCall { - inline sysfunc_rnet() : __vpiSysTaskCall(&vpip_sysfunc_rnet_rt) { } + inline sysfunc_rnet() { } int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code) { return sysfunc_get(code, this); } char* vpi_get_str(int code) { return systask_get_str(code, this); } @@ -573,21 +492,8 @@ struct sysfunc_rnet : public __vpiSysTaskCall { { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_no_rt = { - vpiSysFuncCall, - 0, //sysfunc_get, - 0, //systask_get_str, - 0, - sysfunc_put_no_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 -}; struct sysfunc_no : public __vpiSysTaskCall { - inline sysfunc_no() : __vpiSysTaskCall(&vpip_sysfunc_no_rt) { } + inline sysfunc_no() { } int get_type_code(void) const { return vpiSysFuncCall; } int vpi_get(int code) { return sysfunc_get(code, this); } char* vpi_get_str(int code) { return systask_get_str(code, this); } @@ -648,6 +554,7 @@ struct __vpiSystfIterator : public __vpiHandle { __vpiSystfIterator(); int get_type_code(void) const; vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); unsigned next; }; @@ -681,23 +588,8 @@ static int systf_iterator_free_object(vpiHandle ref) return 1; } -static const struct __vpirt vpip_systf_iterator_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - 0, - 0, //systf_iterator_scan, - systf_iterator_free_object, - 0, - 0 -}; inline __vpiSystfIterator::__vpiSystfIterator() -: __vpiHandle(&vpip_systf_iterator_rt) -{ -} +{ } int __vpiSystfIterator::get_type_code(void) const { return vpiIterator; } @@ -705,6 +597,9 @@ int __vpiSystfIterator::get_type_code(void) const vpiHandle __vpiSystfIterator::vpi_index(int idx) { return systf_iterator_scan(this, idx); } +__vpiHandle::free_object_fun_t __vpiSystfIterator::free_object_fun(void) +{ return &systf_iterator_free_object; } + vpiHandle vpip_make_systf_iterator(void) { /* Check to see if there are any user defined functions. */ diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 741e76bd7..359d1612f 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -311,23 +311,8 @@ static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp) timevar_get_value(ref, vp, false, false); } -static const struct __vpirt vpip_system_time_rt = { - vpiSysFuncCall, - 0, - 0, //timevar_time_get_str, - 0, //timevar_get_ivalue, - 0, - 0, //Inherit from __vpiSystemTime: timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; __vpiScopedTime::__vpiScopedTime() -: __vpiSystemTime(&vpip_system_time_rt) -{ -} +{ } int __vpiScopedTime::vpi_get(int code) { return timevar_time_get(code, this); } @@ -338,23 +323,9 @@ char* __vpiScopedTime::vpi_get_str(int code) void __vpiScopedTime::vpi_get_value(p_vpi_value val) { timevar_get_ivalue(this, val); } -static const struct __vpirt vpip_system_stime_rt = { - vpiSysFuncCall, - 0, - 0, - 0, //timevar_get_svalue, - 0, - 0, //Inherit from __vpiSystemTime: timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; + __vpiScopedSTime::__vpiScopedSTime() -: __vpiSystemTime(&vpip_system_stime_rt) -{ -} +{ } int __vpiScopedSTime::vpi_get(int code) { return timevar_stime_get(code, this); } @@ -365,21 +336,7 @@ char* __vpiScopedSTime::vpi_get_str(int code) void __vpiScopedSTime::vpi_get_value(p_vpi_value val) { timevar_get_svalue(this, val); } -static const struct __vpirt vpip_system_simtime_rt = { - vpiSysFuncCall, - 0, - 0, - 0, //timevar_get_ivalue, - 0, - 0, //timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; __vpiSystemTime::__vpiSystemTime() -: __vpiHandle(&vpip_system_simtime_rt) { scope = 0; } @@ -414,23 +371,8 @@ void __vpiSystemTime::vpi_get_delays(p_vpi_delay) void __vpiSystemTime::vpi_put_delays(p_vpi_delay) { } -static const struct __vpirt vpip_system_realtime_rt = { - vpiSysFuncCall, - 0, - 0, - 0, //timevar_get_rvalue, - 0, - 0, //Inherit from __vpiSystemTime: timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; __vpiScopedRealtime::__vpiScopedRealtime() -: __vpiSystemTime(&vpip_system_realtime_rt) -{ -} +{ } int __vpiScopedRealtime::vpi_get(int code) { return timevar_realtime_get(code, this); } diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 68795bf46..e69ad7d47 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -438,23 +438,8 @@ static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int) // The code fully supports vpiReg, vpi_Net, but we do not // create such things, yet. Lacking a name, for example. -static const struct __vpirt vpip_vthr_const_rt = { - vpiConstant, - 0, //vthr_vec_get, - 0, //vthr_vec_get_str, - 0, //vthr_vec_get_value, - 0, //vthr_vec_put_value, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiVThrVec::__vpiVThrVec() -: __vpiHandle(&vpip_vthr_const_rt) -{ -} +{ } int __vpiVThrVec::get_type_code(void) const { return vpiConstant; } @@ -603,23 +588,8 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) } } -static const struct __vpirt vpip_vthr_const_real_rt = { - vpiConstant, - 0, //vthr_word_get, - 0, - 0, //vthr_real_get_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; inline __vpiVThrWord::__vpiVThrWord() -: __vpiHandle(&vpip_vthr_const_real_rt) -{ -} +{ } int __vpiVThrWord::get_type_code(void) const { return vpiConstant; } From 43e11574e136108ac86a70aa6514c7d1c0c07589 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 20 Jan 2012 17:16:42 -0800 Subject: [PATCH 25/88] General cleanup of the __vpiHandle class work. --- vvp/array.cc | 243 ++++++++++++----------------- vvp/enum_type.cc | 109 +++++-------- vvp/sfunc.cc | 12 +- vvp/vpi_const.cc | 396 ++++++++++++++++------------------------------- vvp/vpi_event.cc | 72 ++++----- vvp/vpi_priv.h | 20 --- vvp/vpi_time.cc | 244 +++++++++++++---------------- 7 files changed, 411 insertions(+), 685 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index cfe4327d0..a478dcae4 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -113,8 +113,6 @@ struct __vpiArray : public __vpiHandle { struct __vpiArrayIterator : public __vpiHandle { __vpiArrayIterator(); int get_type_code(void) const; - int vpi_get(int code); - char* vpi_get_str(int code); vpiHandle vpi_index(int idx); free_object_fun_t free_object_fun(void); @@ -125,8 +123,6 @@ struct __vpiArrayIterator : public __vpiHandle { struct __vpiArrayIndex : public __vpiHandle { __vpiArrayIndex(); int get_type_code(void) const; - int vpi_get(int code); - char* vpi_get_str(int code); vpiHandle vpi_iterate(int code); vpiHandle vpi_index(int idx); free_object_fun_t free_object_fun(void); @@ -300,12 +296,7 @@ struct __vpiArrayWord { }; }; -static int vpi_array_get(int code, vpiHandle ref); -static char*vpi_array_get_str(int code, vpiHandle ref); -static vpiHandle vpi_array_get_handle(int code, vpiHandle ref); -static vpiHandle vpi_array_iterate(int code, vpiHandle ref); -static vpiHandle vpi_array_index(vpiHandle ref, int index); - +static void array_make_vals_words(struct __vpiArray*parent); static vpiHandle array_iterator_scan(vpiHandle ref, int); static int array_iterator_free_object(vpiHandle ref); @@ -338,19 +329,92 @@ int __vpiArray::get_type_code(void) const { return vpiMemory; } int __vpiArray::vpi_get(int code) -{ return vpi_array_get(code, this); } +{ + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! + + case vpiSize: + return (int) array_count; + + case vpiAutomatic: + return (int) scope->is_automatic; + + default: + return 0; + } +} char* __vpiArray::vpi_get_str(int code) -{ return vpi_array_get_str(code, this); } +{ + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + return generic_get_str(code, scope, name, NULL); +} vpiHandle __vpiArray::vpi_handle(int code) -{ return vpi_array_get_handle(code, this); } +{ + switch (code) { + + case vpiLeftRange: + if (swap_addr) return &last_addr; + else return &first_addr; + + case vpiRightRange: + if (swap_addr) return &first_addr; + else return &last_addr; + + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + } + + return 0; +} vpiHandle __vpiArray::vpi_iterate(int code) -{ return vpi_array_iterate(code, this); } +{ + switch (code) { + + case vpiMemoryWord: { + struct __vpiArrayIterator*res; + res = new __vpiArrayIterator; + res->array = this; + res->next = 0; + return res; + } + + } + + return 0; +} + +/* +* VPI code passes indices that are not yet converted to canonical +* form, so this index function does it here. +*/ +vpiHandle __vpiArray::vpi_index(int index) +{ + index -= first_addr.value; + if (index >= (long)array_count) + return 0; + if (index < 0) + return 0; + + if (nets != 0) { + return nets[index]; + } + + if (vals_words == 0) + array_make_vals_words(this); + + return &(vals_words[index].as_word); +} -vpiHandle __vpiArray::vpi_index(int idx) -{ return vpi_array_index(this, idx); } inline __vpiArrayIterator::__vpiArrayIterator() { } @@ -358,14 +422,25 @@ inline __vpiArrayIterator::__vpiArrayIterator() int __vpiArrayIterator::get_type_code(void) const { return vpiIterator; } -int __vpiArrayIterator::vpi_get(int) -{ return vpiUndefined; } +vpiHandle __vpiArrayIterator::vpi_index(int) +{ + if (next >= array->array_count) { + vpi_free_object(this); + return 0; + } -char* __vpiArrayIterator::vpi_get_str(int) -{ return 0; } + unsigned use_index = next; + next += 1; + + if (array->nets) return array->nets[use_index]; + + assert(array->vals4 || array->valsr); + + if (array->vals_words == 0) array_make_vals_words(array); + + return &(array->vals_words[use_index].as_word); +} -vpiHandle __vpiArrayIterator::vpi_index(int code) -{ return array_iterator_scan(this, code); } __vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) { return &array_iterator_free_object; } @@ -376,12 +451,6 @@ inline __vpiArrayIndex::__vpiArrayIndex() int __vpiArrayIndex::get_type_code(void) const { return vpiIterator; } -int __vpiArrayIndex::vpi_get(int) -{ return vpiUndefined; } - -char* __vpiArrayIndex::vpi_get_str(int) -{ return 0; } - vpiHandle __vpiArrayIndex::vpi_iterate(int code) { return array_index_iterate(code, this); } @@ -506,103 +575,6 @@ static unsigned decode_array_word_pointer(struct __vpiArrayWord*word, return word - word0; } -static int vpi_array_get(int code, vpiHandle ref) -{ - struct __vpiArray*obj = dynamic_cast<__vpiArray*> (ref); - - switch (code) { - case vpiLineNo: - return 0; // Not implemented for now! - - case vpiSize: - return (int) obj->array_count; - - case vpiAutomatic: - return (int) obj->scope->is_automatic; - - default: - return 0; - } -} - -static char*vpi_array_get_str(int code, vpiHandle ref) -{ - struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); - - if (code == vpiFile) { // Not implemented for now! - return simple_set_rbuf_str(file_names[0]); - } - - return generic_get_str(code, obj->scope, obj->name, NULL); -} - -static vpiHandle vpi_array_get_handle(int code, vpiHandle ref) -{ - struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); - - switch (code) { - - case vpiLeftRange: - if (obj->swap_addr) return &(obj->last_addr); - else return &(obj->first_addr); - - case vpiRightRange: - if (obj->swap_addr) return &(obj->first_addr); - else return &(obj->last_addr); - - case vpiScope: - return obj->scope; - - case vpiModule: - return vpip_module(obj->scope); - } - - return 0; -} - -static vpiHandle vpi_array_iterate(int code, vpiHandle ref) -{ - struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); - - switch (code) { - - case vpiMemoryWord: { - struct __vpiArrayIterator*res; - res = new __vpiArrayIterator; - res->array = obj; - res->next = 0; - return res; - } - - } - - return 0; -} - -/* -* VPI code passes indices that are not yet converted to canonical -* form, so this index function does it here. -*/ -static vpiHandle vpi_array_index(vpiHandle ref, int index) -{ - struct __vpiArray*obj = dynamic_cast<__vpiArray*>(ref); - - index -= obj->first_addr.value; - if (index >= (long)obj->array_count) - return 0; - if (index < 0) - return 0; - - if (obj->nets != 0) { - return obj->nets[index]; - } - - if (obj->vals_words == 0) - array_make_vals_words(obj); - - return &(obj->vals_words[index].as_word); -} - static int vpi_array_var_word_get(int code, vpiHandle ref) { struct __vpiArrayWord*obj = array_var_word_from_handle(ref); @@ -731,27 +703,6 @@ static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) vp->value.integer = index; } -static vpiHandle array_iterator_scan(vpiHandle ref, int) -{ - struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); - - if (obj->next >= obj->array->array_count) { - vpi_free_object(ref); - return 0; - } - - unsigned use_index = obj->next; - obj->next += 1; - - if (obj->array->nets) return obj->array->nets[use_index]; - - assert(obj->array->vals4 || obj->array->valsr); - - if (obj->array->vals_words == 0) array_make_vals_words(obj->array); - - return &(obj->array->vals_words[use_index].as_word); -} - static int array_iterator_free_object(vpiHandle ref) { struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 794b11ba9..caeea4d22 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -48,24 +48,28 @@ struct __vpiEnumTypespec : public __vpiHandle { bool is_signed; }; -static int enum_type_get(int code, vpiHandle obj) -{ - struct __vpiEnumTypespec*ref = dynamic_cast<__vpiEnumTypespec*>(obj); - assert(ref); +inline __vpiEnumTypespec::__vpiEnumTypespec() +{ } + +int __vpiEnumTypespec::get_type_code(void) const +{ return vpiEnumTypespec; } + +int __vpiEnumTypespec::vpi_get(int code) +{ switch (code) { case vpiSize: - return ref->names.size(); + return names.size(); /* This is not currently set correctly. We always use vpiReg for * four state variables and vpiBitVar for two state variables. * This minimal functionality is needed to get the next() and * prev() methods to work correctly with invalid values. */ case vpiBaseTypespec: - return ref->base_type_code; + return base_type_code; case vpiSigned: - return ref->is_signed; + return is_signed; default: fprintf(stderr, "vvp error: get %d not supported " @@ -75,73 +79,22 @@ static int enum_type_get(int code, vpiHandle obj) } } -static vpiHandle enum_type_iterate(int code, vpiHandle obj) -{ - struct __vpiEnumTypespec*ref = dynamic_cast<__vpiEnumTypespec*>(obj); - assert(ref); +vpiHandle __vpiEnumTypespec::vpi_iterate(int code) +{ if (code == vpiEnumConst) { vpiHandle*args = (vpiHandle*) - calloc(ref->names.size(), sizeof(vpiHandle*)); - for (size_t idx = 0 ; idx < ref->names.size() ; idx += 1) - args[idx] = &ref->names[idx]; + calloc(names.size(), sizeof(vpiHandle*)); + for (size_t idx = 0 ; idx < names.size() ; idx += 1) + args[idx] = &names[idx]; - return vpip_make_iterator(ref->names.size(), args, true); + return vpip_make_iterator(names.size(), args, true); } return 0; } -inline __vpiEnumTypespec::__vpiEnumTypespec() -{ } - -int __vpiEnumTypespec::get_type_code(void) const -{ return vpiEnumTypespec; } - -int __vpiEnumTypespec::vpi_get(int code) -{ return enum_type_get(code, this); } - -vpiHandle __vpiEnumTypespec::vpi_iterate(int code) -{ return enum_type_iterate(code, this); } - -static int enum_name_get(int code, vpiHandle obj) -{ - struct enumconst_s*ref = dynamic_cast(obj); - assert(ref); - - switch (code) { - case vpiSize: - return ref->val4.size()? ref->val4.size() : ref->val2.size(); - default: - return 0; - } -} - -static char* enum_name_get_str(int code, vpiHandle obj) -{ - struct enumconst_s*ref = dynamic_cast(obj); - assert(ref); - - switch (code) { - case vpiName: - return const_cast (ref->name); - default: - return 0; - } -} - -static void enum_name_get_value(vpiHandle obj, p_vpi_value value) -{ - struct enumconst_s*ref = dynamic_cast(obj); - assert(ref); - - if (ref->val4.size() > 0) - vpip_vec4_get_value(ref->val4, ref->val4.size(), false, value); - else - vpip_vec2_get_value(ref->val2, ref->val2.size(), false, value); -} - inline enumconst_s::enumconst_s() { } @@ -149,13 +102,35 @@ int enumconst_s::get_type_code(void) const { return vpiEnumConst; } int enumconst_s::vpi_get(int code) -{ return enum_name_get(code, this); } +{ + switch (code) { + case vpiSize: + return val4.size()? val4.size() : val2.size(); + default: + return 0; + } +} + char* enumconst_s::vpi_get_str(int code) -{ return enum_name_get_str(code, this); } +{ + switch (code) { + case vpiName: + return const_cast (name); + default: + return 0; + } +} + void enumconst_s::vpi_get_value(p_vpi_value val) -{ enum_name_get_value(this, val); } +{ + if (val4.size() > 0) + vpip_vec4_get_value(val4, val4.size(), false, val); + else + vpip_vec2_get_value(val2, val2.size(), false, val); +} + void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names) diff --git a/vvp/sfunc.cc b/vvp/sfunc.cc index d6b9bbf27..1c7e85d8e 100644 --- a/vvp/sfunc.cc +++ b/vvp/sfunc.cc @@ -62,10 +62,8 @@ void sfunc_core::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&/*bit*/, void sfunc_core::recv_vec4_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - assert(vpi_get(vpiConstType,vpi) == vpiBinaryConst); - - struct __vpiBinaryConst*obj - = (struct __vpiBinaryConst*)vpi; + struct __vpiBinaryConst*obj = dynamic_cast<__vpiBinaryConst*>(vpi); + assert(obj); obj->bits = value(port); @@ -76,10 +74,8 @@ void sfunc_core::recv_vec4_from_inputs(unsigned port) void sfunc_core::recv_real_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - assert(vpi_get(vpiConstType,vpi) == vpiRealConst); - - struct __vpiRealConst*obj - = (struct __vpiRealConst*)vpi; + struct __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); + assert(obj); obj->value = value_r(port); diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 46b4ad6f8..7b9b94ebd 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -29,14 +29,18 @@ # include # include "ivl_alloc.h" -static int string_get(int code, vpiHandle ref) -{ - struct __vpiStringConst*rfp; +inline __vpiStringConst::__vpiStringConst() +{ } + +int __vpiStringConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiStringConst::vpi_get(int code) +{ switch (code) { case vpiSize: - rfp = dynamic_cast<__vpiStringConst*>(ref); - return strlen(rfp->value)*8; + return strlen(value)*8; case vpiSigned: return 0; @@ -60,12 +64,11 @@ static int string_get(int code, vpiHandle ref) } } -static void string_value(vpiHandle ref, p_vpi_value vp) +void __vpiStringConst::vpi_get_value(p_vpi_value vp) { unsigned uint_value; p_vpi_vecval vecp; - struct __vpiStringConst*rfp = dynamic_cast<__vpiStringConst*>(ref); - int size = strlen(rfp->value); + int size = strlen(value); char*rbuf = 0; char*cp; @@ -76,7 +79,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) case vpiStringVal: rbuf = need_result_buf(size + 1, RBUF_VAL); - strcpy(rbuf, (char*)rfp->value); + strcpy(rbuf, (char*)value); vp->value.str = rbuf; break; @@ -91,7 +94,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) uint_value = 0; for(int i=0; ivalue[i]); + uint_value += (unsigned char)(value[i]); } sprintf(rbuf, "%u", uint_value); vp->value.str = rbuf; @@ -102,7 +105,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) cp = rbuf; for(int i=0; i=0; bit--){ - *cp++ = "01"[ (rfp->value[i]>>bit)&1 ]; + *cp++ = "01"[ (value[i]>>bit)&1 ]; } } *cp = 0; @@ -114,7 +117,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) cp = rbuf; for(int i=0; i=0; nibble--){ - *cp++ = "0123456789abcdef"[ (rfp->value[i]>>(nibble*4))&15 ]; + *cp++ = "0123456789abcdef"[ (value[i]>>(nibble*4))&15 ]; } } *cp = 0; @@ -131,7 +134,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) for(int i=0; i=0; bit--){ vp->value.integer <<= 1; - vp->value.integer += (rfp->value[i]>>bit)&1; + vp->value.integer += (value[i]>>bit)&1; } } break; @@ -145,7 +148,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) vecp = vp->value.vector; vecp->aval = vecp->bval = 0; for(int i=0; iaval |= rfp->value[i] << uint_value*8; + vecp->aval |= value[i] << uint_value*8; uint_value += 1; if (uint_value > 3) { uint_value = 0; @@ -166,41 +169,9 @@ static void string_value(vpiHandle ref, p_vpi_value vp) } } -inline __vpiStringConst::__vpiStringConst() -{ } - -int __vpiStringConst::get_type_code(void) const -{ return vpiConstant; } - -int __vpiStringConst::vpi_get(int code) -{ return string_get(code, this); } - -char*__vpiStringConst::vpi_get_str(int) -{ return 0; } - -void __vpiStringConst::vpi_get_value(p_vpi_value val) -{ string_value(this, val); } - -vpiHandle __vpiStringConst::vpi_put_value(p_vpi_value, int) -{ return 0; } - -vpiHandle __vpiStringConst::vpi_handle(int) -{ return 0; } - -vpiHandle __vpiStringConst::vpi_iterate(int) -{ return 0; } - -vpiHandle __vpiStringConst::vpi_index(int) -{ return 0; } - -void __vpiStringConst::vpi_get_delays(p_vpi_delay) -{ } - -void __vpiStringConst::vpi_put_delays(p_vpi_delay) -{ } struct __vpiStringConstTEMP : public __vpiStringConst { - __vpiStringConstTEMP(); + inline __vpiStringConstTEMP() { } free_object_fun_t free_object_fun(void); }; @@ -213,9 +184,6 @@ static int free_temp_string(vpiHandle obj) return 1; } - -inline __vpiStringConstTEMP::__vpiStringConstTEMP() -{ } __vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) { return &free_temp_string; } @@ -276,48 +244,6 @@ struct __vpiStringParam : public __vpiStringConst { unsigned lineno; }; -static int string_param_get(int code, vpiHandle ref) -{ - struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(ref); - assert(ref); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return string_get(code, ref); -} - -static char* string_param_get_str(int code, vpiHandle obj) -{ - struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(obj); - assert(rfp); - - if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); - } - - return generic_get_str(code, rfp->scope, rfp->basename, NULL); -} - -static vpiHandle string_param_handle(int code, vpiHandle obj) -{ - struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(obj); - assert(rfp); - - switch (code) { - case vpiScope: - return rfp->scope; - - case vpiModule: - return vpip_module(rfp->scope); - - default: - return 0; - } -} - - inline __vpiStringParam::__vpiStringParam() { } @@ -325,13 +251,37 @@ int __vpiStringParam::get_type_code(void) const { return vpiParameter; } int __vpiStringParam::vpi_get(int code) -{ return string_param_get(code, this); } +{ + if (code == vpiLineNo) + return lineno; + + return __vpiStringConst::vpi_get(code); +} + char*__vpiStringParam::vpi_get_str(int code) -{ return string_param_get_str(code, this); } +{ + if (code == vpiFile) { + return simple_set_rbuf_str(file_names[file_idx]); + } + + return generic_get_str(code, scope, basename, NULL); +} + vpiHandle __vpiStringParam::vpi_handle(int code) -{ return string_param_handle(code, this); } +{ + switch (code) { + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + + default: + return 0; + } +} vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) @@ -349,10 +299,16 @@ vpiHandle vpip_make_string_param(char*name, char*text, return obj; } -static int binary_get(int code, vpiHandle ref) -{ - struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(ref); + +inline __vpiBinaryConst::__vpiBinaryConst() +{ } + +int __vpiBinaryConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiBinaryConst::vpi_get(int code) +{ switch (code) { case vpiConstType: return vpiBinaryConst; @@ -361,10 +317,10 @@ static int binary_get(int code, vpiHandle ref) return 0; // Not implemented for now! case vpiSigned: - return rfp->signed_flag? 1 : 0; + return signed_flag? 1 : 0; case vpiSize: - return rfp->bits.size(); + return bits.size(); case vpiAutomatic: return 0; @@ -383,11 +339,9 @@ static int binary_get(int code, vpiHandle ref) } -static void binary_value(vpiHandle ref, p_vpi_value vp) +void __vpiBinaryConst::vpi_get_value(p_vpi_value val) { - struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(ref); - - switch (vp->format) { + switch (val->format) { case vpiObjTypeVal: case vpiBinStrVal: @@ -399,52 +353,18 @@ static void binary_value(vpiHandle ref, p_vpi_value vp) case vpiVectorVal: case vpiStringVal: case vpiRealVal: - vpip_vec4_get_value(rfp->bits, rfp->bits.size(), - rfp->signed_flag, vp); + vpip_vec4_get_value(bits, bits.size(), signed_flag, val); break; default: fprintf(stderr, "vvp error: format %d not supported " - "by vpiBinaryConst\n", (int)vp->format); - vp->format = vpiSuppressVal; + "by vpiBinaryConst\n", (int)val->format); + val->format = vpiSuppressVal; break; } } -inline __vpiBinaryConst::__vpiBinaryConst() -{ } - -int __vpiBinaryConst::get_type_code(void) const -{ return vpiConstant; } - -int __vpiBinaryConst::vpi_get(int code) -{ return binary_get(code, this); } - -char* __vpiBinaryConst::vpi_get_str(int) -{ return 0; } - -void __vpiBinaryConst::vpi_get_value(p_vpi_value val) -{ binary_value(this, val); } - -vpiHandle __vpiBinaryConst::vpi_put_value(p_vpi_value, int) -{ return 0; } - -vpiHandle __vpiBinaryConst::vpi_handle(int) -{ return 0; } - -vpiHandle __vpiBinaryConst::vpi_iterate(int) -{ return 0; } - -vpiHandle __vpiBinaryConst::vpi_index(int) -{ return 0; } - -void __vpiBinaryConst::vpi_get_delays(p_vpi_delay) -{ } - -void __vpiBinaryConst::vpi_put_delays(p_vpi_delay) -{ } - /* * Make a VPI constant from a vector string. The string is normally a * ASCII string, with each letter a 4-value bit. The first character @@ -508,44 +428,6 @@ struct __vpiBinaryParam : public __vpiBinaryConst { unsigned lineno; }; -static int binary_param_get(int code, vpiHandle ref) -{ - struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(ref); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return binary_get(code, ref); -} - -static char* binary_param_get_str(int code, vpiHandle obj) -{ - struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(obj); - - if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); - } - - return generic_get_str(code, rfp->scope, rfp->basename, NULL); -} - -static vpiHandle binary_param_handle(int code, vpiHandle obj) -{ - struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(obj); - - switch (code) { - case vpiScope: - return rfp->scope; - - case vpiModule: - return vpip_module(rfp->scope); - - default: - return 0; - } -} - inline __vpiBinaryParam::__vpiBinaryParam() { } @@ -553,13 +435,36 @@ int __vpiBinaryParam::get_type_code(void) const { return vpiParameter; } int __vpiBinaryParam::vpi_get(int code) -{ return binary_param_get(code, this); } +{ + if (code == vpiLineNo) + return lineno; + + return __vpiBinaryConst::vpi_get(code); +} char*__vpiBinaryParam::vpi_get_str(int code) -{ return binary_param_get_str(code, this); } +{ + if (code == vpiFile) + return simple_set_rbuf_str(file_names[file_idx]); + + return generic_get_str(code, scope, basename, NULL); +} + vpiHandle __vpiBinaryParam::vpi_handle(int code) -{ return binary_param_handle(code, this); } +{ + switch (code) { + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + + default: + return 0; + } +} + vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, @@ -579,9 +484,17 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, } -static int dec_get(int code, vpiHandle) -{ +__vpiDecConst::__vpiDecConst(int val) +{ + value = val; +} + +int __vpiDecConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiDecConst::vpi_get(int code) +{ switch (code) { case vpiConstType: return vpiDecConst; @@ -609,9 +522,8 @@ static int dec_get(int code, vpiHandle) } -static void dec_value(vpiHandle ref, p_vpi_value vp) +void __vpiDecConst::vpi_get_value(p_vpi_value vp) { - struct __vpiDecConst*rfp = dynamic_cast<__vpiDecConst*>(ref); char*rbuf = need_result_buf(64 + 1, RBUF_VAL); char*cp = rbuf; @@ -619,19 +531,19 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) case vpiObjTypeVal: case vpiIntVal: { - vp->value.integer = rfp->value; + vp->value.integer = value; break; } case vpiDecStrVal: - sprintf(rbuf, "%d", rfp->value); + sprintf(rbuf, "%d", value); vp->value.str = rbuf; break; case vpiBinStrVal: for(int bit=31; bit<=0;bit--){ - *cp++ = "01"[ (rfp->value>>bit)&1 ]; + *cp++ = "01"[ (value>>bit)&1 ]; } *cp = 0; @@ -639,13 +551,13 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) break; case vpiHexStrVal: - sprintf(rbuf, "%08x", rfp->value); + sprintf(rbuf, "%08x", value); vp->value.str = rbuf; break; case vpiOctStrVal: - sprintf(rbuf, "%011x", rfp->value); + sprintf(rbuf, "%011x", value); vp->value.str = rbuf; break; @@ -658,23 +570,15 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) } } -__vpiDecConst::__vpiDecConst(int val) -{ - value = val; -} -int __vpiDecConst::get_type_code(void) const +inline __vpiRealConst::__vpiRealConst() +{ } + +int __vpiRealConst::get_type_code(void) const { return vpiConstant; } -int __vpiDecConst::vpi_get(int code) -{ return dec_get(code, this); } - -void __vpiDecConst::vpi_get_value(p_vpi_value val) -{ dec_value(this, val); } - -static int real_get(int code, vpiHandle) +int __vpiRealConst::vpi_get(int code) { - switch (code) { case vpiLineNo: return 0; // Not implemented for now! @@ -704,23 +608,12 @@ static int real_get(int code, vpiHandle) } } -static void real_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiRealConst*rfp = dynamic_cast<__vpiRealConst*>(ref); - vpip_real_get_value(rfp->value, vp); -} - -inline __vpiRealConst::__vpiRealConst() -{ } - -int __vpiRealConst::get_type_code(void) const -{ return vpiConstant; } - -int __vpiRealConst::vpi_get(int code) -{ return real_get(code, this); } void __vpiRealConst::vpi_get_value(p_vpi_value val) -{ real_value(this, val); } +{ + vpip_real_get_value(value, val); +} + vpiHandle vpip_make_real_const(double value) { @@ -742,44 +635,6 @@ struct __vpiRealParam : public __vpiRealConst { unsigned lineno; }; -static int real_param_get(int code, vpiHandle ref) -{ - struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(ref); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return real_get(code, ref); -} - -static char* real_param_get_str(int code, vpiHandle obj) -{ - struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(obj); - - if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); - } - - return generic_get_str(code, rfp->scope, rfp->basename, NULL); -} - -static vpiHandle real_param_handle(int code, vpiHandle obj) -{ - struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(obj); - - switch (code) { - case vpiScope: - return rfp->scope; - - case vpiModule: - return vpip_module(rfp->scope); - - default: - return 0; - } -} - inline __vpiRealParam::__vpiRealParam() { } @@ -788,13 +643,34 @@ int __vpiRealParam::get_type_code(void) const { return vpiParameter; } int __vpiRealParam::vpi_get(int code) -{ return real_param_get(code, this); } +{ + if (code == vpiLineNo) + return lineno; + + return __vpiRealConst::vpi_get(code); +} char* __vpiRealParam::vpi_get_str(int code) -{ return real_param_get_str(code, this); } +{ + if (code == vpiFile) + return simple_set_rbuf_str(file_names[file_idx]); + + return generic_get_str(code, scope, basename, NULL); +} vpiHandle __vpiRealParam::vpi_handle(int code) -{ return real_param_handle(code, this); } +{ + switch (code) { + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + + default: + return 0; + } +} vpiHandle vpip_make_real_param(char*name, double value, diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index df402c17c..9c13b7246 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -25,47 +25,6 @@ # include # include "ivl_alloc.h" -static int named_event_get(int code, vpiHandle ref) -{ - struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); - assert(obj); - - switch (code) { - - case vpiAutomatic: - return (int) obj->scope->is_automatic; - } - - return 0; -} - -static char* named_event_get_str(int code, vpiHandle ref) -{ - struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); - assert(obj); - - if (code == vpiFile) { // Not implemented for now! - return simple_set_rbuf_str(file_names[0]); - } - return generic_get_str(code, obj->scope, obj->name, NULL); -} - -static vpiHandle named_event_get_handle(int code, vpiHandle ref) -{ - struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); - assert(obj); - - switch (code) { - case vpiScope: - return obj->scope; - - case vpiModule: - return vpip_module(obj->scope); - } - - return 0; -} - inline __vpiNamedEvent::__vpiNamedEvent() { } @@ -73,13 +32,38 @@ int __vpiNamedEvent::get_type_code(void) const { return vpiNamedEvent; } int __vpiNamedEvent::vpi_get(int code) -{ return named_event_get(code, this); } +{ + switch (code) { + + case vpiAutomatic: + return (int) scope->is_automatic; + } + + return 0; +} char* __vpiNamedEvent::vpi_get_str(int code) -{ return named_event_get_str(code, this); } +{ + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + return generic_get_str(code, scope, name, NULL); +} + vpiHandle __vpiNamedEvent::vpi_handle(int code) -{ return named_event_get_handle(code, this); } +{ + switch (code) { + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + } + + return 0; +} + vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 039922849..1c1b53b30 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -175,19 +175,13 @@ struct __vpiSystemTime : public __vpiHandle { int vpi_get(int code); char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - void vpi_get_delays(p_vpi_delay del); - void vpi_put_delays(p_vpi_delay del); struct __vpiScope*scope; }; struct __vpiScopedTime : public __vpiSystemTime { __vpiScopedTime(); - int vpi_get(int code); char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); }; @@ -537,14 +531,7 @@ struct __vpiStringConst : public __vpiHandle { __vpiStringConst(); int get_type_code(void) const; int vpi_get(int code); - char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - void vpi_get_delays(p_vpi_delay del); - void vpi_put_delays(p_vpi_delay del); char*value; size_t value_len; @@ -558,14 +545,7 @@ struct __vpiBinaryConst : public __vpiHandle { __vpiBinaryConst(); int get_type_code(void) const; int vpi_get(int code); - char*vpi_get_str(int code); void vpi_get_value(p_vpi_value val); - vpiHandle vpi_put_value(p_vpi_value val, int flags); - vpiHandle vpi_handle(int code); - vpiHandle vpi_iterate(int code); - vpiHandle vpi_index(int idx); - void vpi_get_delays(p_vpi_delay del); - void vpi_put_delays(p_vpi_delay del); vvp_vector4_t bits; /* TRUE if this constant is signed. */ diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 359d1612f..0b5c55424 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -94,121 +94,6 @@ vvp_time64_t vpip_scaled_real_to_time64(double val, struct __vpiScope*scope) return delay; } -static int timevar_time_get(int code, vpiHandle) -{ - switch (code) { - case vpiSize: - return 64; - - case vpiSigned: - return 0; - - case vpiFuncType: - return vpiTimeFunc; - - case vpiAutomatic: - return 0; - - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static int timevar_stime_get(int code, vpiHandle ref) -{ - switch (code) { - case vpiSize: - return 32; - - default: - return timevar_time_get(code, ref); - } -} - -static char* timevar_time_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$time"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_stime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$stime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_simtime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$simtime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_realtime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$realtime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static int timevar_realtime_get(int code, vpiHandle) -{ - switch (code) { - case vpiSize: - return 1; - - case vpiSigned: - return 0; - - case vpiFuncType: - return vpiRealFunc; - - case vpiAutomatic: - return 0; - - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static vpiHandle timevar_handle(int code, vpiHandle ref) -{ - struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref); - - switch (code) { - case vpiScope: - return rfp->scope; - default: - return 0; - } -} - static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func, bool is_stime) { @@ -314,11 +199,18 @@ static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp) __vpiScopedTime::__vpiScopedTime() { } -int __vpiScopedTime::vpi_get(int code) -{ return timevar_time_get(code, this); } - char* __vpiScopedTime::vpi_get_str(int code) -{ return timevar_time_get_str(code, this); } +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$time"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + void __vpiScopedTime::vpi_get_value(p_vpi_value val) { timevar_get_ivalue(this, val); } @@ -328,10 +220,29 @@ __vpiScopedSTime::__vpiScopedSTime() { } int __vpiScopedSTime::vpi_get(int code) -{ return timevar_stime_get(code, this); } +{ + switch (code) { + case vpiSize: + return 32; + + default: + return __vpiSystemTime::vpi_get(code); + } +} + char* __vpiScopedSTime::vpi_get_str(int code) -{ return timevar_stime_get_str(code, this); } +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$stime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + void __vpiScopedSTime::vpi_get_value(p_vpi_value val) { timevar_get_svalue(this, val); } @@ -345,40 +256,93 @@ int __vpiSystemTime::get_type_code(void) const { return vpiSysFuncCall; } int __vpiSystemTime::vpi_get(int code) -{ return timevar_time_get(code, this); } +{ + switch (code) { + case vpiSize: + return 64; + + case vpiSigned: + return 0; + + case vpiFuncType: + return vpiTimeFunc; + + case vpiAutomatic: + return 0; + + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + char* __vpiSystemTime::vpi_get_str(int code) -{ return timevar_simtime_get_str(code, this); } +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$simtime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + void __vpiSystemTime::vpi_get_value(p_vpi_value val) { timevar_get_ivalue(this, val); } -vpiHandle __vpiSystemTime::vpi_put_value(p_vpi_value, int) -{ return 0; } - vpiHandle __vpiSystemTime::vpi_handle(int code) -{ return timevar_handle(code, this); } +{ + switch (code) { + case vpiScope: + return scope; + default: + return 0; + } +} -vpiHandle __vpiSystemTime::vpi_iterate(int) -{ return 0; } - -vpiHandle __vpiSystemTime::vpi_index(int) -{ return 0; } - -void __vpiSystemTime::vpi_get_delays(p_vpi_delay) -{ } - -void __vpiSystemTime::vpi_put_delays(p_vpi_delay) -{ } __vpiScopedRealtime::__vpiScopedRealtime() { } int __vpiScopedRealtime::vpi_get(int code) -{ return timevar_realtime_get(code, this); } +{ + switch (code) { + case vpiSize: + return 1; + + case vpiSigned: + return 0; + + case vpiFuncType: + return vpiRealFunc; + + case vpiAutomatic: + return 0; + + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + char* __vpiScopedRealtime::vpi_get_str(int code) -{ return timevar_realtime_get_str(code, this); } +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$realtime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + void __vpiScopedRealtime::vpi_get_value(p_vpi_value val) { timevar_get_rvalue(this, val); } From d6fca81058c6c5f6a27ecd66d0f756edbe50e576 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 21 Jan 2012 11:59:49 -0800 Subject: [PATCH 26/88] More cleanup of __vpiHandle classes. --- vvp/array.cc | 30 +++---- vvp/compile.cc | 1 + vvp/delay.cc | 13 ++- vvp/vpi_callback.cc | 14 --- vvp/vpi_const.cc | 208 ++++++++++++++++++++++++++------------------ vvp/vpi_priv.cc | 16 ++-- vvp/vpi_priv.h | 23 ++--- 7 files changed, 161 insertions(+), 144 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index a478dcae4..b952347e2 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -298,10 +298,8 @@ struct __vpiArrayWord { static void array_make_vals_words(struct __vpiArray*parent); static vpiHandle array_iterator_scan(vpiHandle ref, int); -static int array_iterator_free_object(vpiHandle ref); static vpiHandle array_index_scan(vpiHandle ref, int); -static int array_index_free_object(vpiHandle ref); static int vpi_array_var_word_get(int code, vpiHandle); static char*vpi_array_var_word_get_str(int code, vpiHandle); @@ -442,6 +440,13 @@ vpiHandle __vpiArrayIterator::vpi_index(int) } +static int array_iterator_free_object(vpiHandle ref) +{ + struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); + delete obj; + return 1; +} + __vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) { return &array_iterator_free_object; } @@ -457,6 +462,13 @@ vpiHandle __vpiArrayIndex::vpi_iterate(int code) vpiHandle __vpiArrayIndex::vpi_index(int idx) { return array_index_scan(this, idx); } +static int array_index_free_object(vpiHandle ref) +{ + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); + delete obj; + return 1; +} + __vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void) { return &array_index_free_object; } @@ -703,13 +715,6 @@ static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) vp->value.integer = index; } -static int array_iterator_free_object(vpiHandle ref) -{ - struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); - free(obj); - return 1; -} - vpiHandle array_index_iterate(int code, vpiHandle ref) { struct __vpiDecConst*obj = dynamic_cast<__vpiDecConst*>(ref); @@ -738,13 +743,6 @@ static vpiHandle array_index_scan(vpiHandle ref, int) return 0; } -static int array_index_free_object(vpiHandle ref) -{ - struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); - free(obj); - return 1; -} - static int vpi_array_vthr_A_get(int code, vpiHandle ref) { struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); diff --git a/vvp/compile.cc b/vvp/compile.cc index a424b20e8..5fc1ba667 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1822,6 +1822,7 @@ void compile_param_logic(char*label, char*name, char*value, bool signed_flag, void compile_param_string(char*label, char*name, char*value, long file_idx, long lineno) { + // name and value become owned bi vpip_make_string_param vpiHandle obj = vpip_make_string_param(name, value, file_idx, lineno); compile_vpi_symbol(label, obj); vpip_attach_to_current_scope(obj); diff --git a/vvp/delay.cc b/vvp/delay.cc index 856481fcf..0b46cf1ab 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -819,13 +819,6 @@ static vpiHandle modpath_src_index ( vpiHandle ref, int) } -static int modpath_src_free_object( vpiHandle ref ) -{ - assert( ref->get_type_code() == vpiModPathIn ); - free ( ref ) ; - return 1 ; -} - /* * This routine will put specific dimension of delay[] values * into a vpiHandle. In this case, we will put @@ -1001,6 +994,12 @@ void __vpiModPathSrc::vpi_get_delays(p_vpi_delay del) void __vpiModPathSrc::vpi_put_delays(p_vpi_delay del) { modpath_src_put_delays(this, del); } +static int modpath_src_free_object( vpiHandle ref ) +{ + delete ref; + return 1 ; +} + __vpiHandle::free_object_fun_t __vpiModPathSrc::free_object_fun(void) { return &modpath_src_free_object; } diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index e8e79c5c6..089f0a5f8 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -35,17 +35,6 @@ # include # include -/* -* The vpi_free_object() call to a callback doesn't actually delete -* anything, we instead allow the object to run its course and delete -* itself. The semantics of vpi_free_object for a callback is that it -* deletes the *handle*, and not the object itself, so given the vvp -* implementation, there is nothing to do here. -*/ -static int free_simple_callback(vpiHandle) -{ - return 1; -} inline __vpiCallback::__vpiCallback() { } @@ -53,9 +42,6 @@ inline __vpiCallback::__vpiCallback() int __vpiCallback::get_type_code(void) const { return vpiCallback; } -__vpiHandle::free_object_fun_t __vpiCallback::free_object_fun(void) -{ return &free_simple_callback; } - /* * Callback handles are created when the VPI function registers a diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 7b9b94ebd..f7071de3b 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -29,9 +29,62 @@ # include # include "ivl_alloc.h" +class __vpiStringConst : public __vpiHandle { + public: + __vpiStringConst(char*val); + ~__vpiStringConst(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); -inline __vpiStringConst::__vpiStringConst() -{ } + private: + void process_string_(); + private: + char*value_; + size_t value_len_; +}; + +inline __vpiStringConst::__vpiStringConst(char*v) +: value_(v) +{ + process_string_(); +} + +/* + * Strings are described at the level of the vvp source as a string + * with literal characters or octal escapes. No other escapes are + * included, they are processed already by the compiler that generated + * the vvp source. + */ +void __vpiStringConst::process_string_(void) +{ + char*chr = value_; + char*dp = value_; + + while (*chr) { + char next_char = *chr; + + /* Process octal escapes that I might find. */ + if (*chr == '\\') { + for (int idx = 1 ; idx <= 3 ; idx += 1) { + assert(chr[idx] != 0); + assert(chr[idx] < '8'); + assert(chr[idx] >= '0'); + next_char = next_char*8 + chr[idx] - '0'; + } + chr += 3; + } + *dp++ = next_char; + chr += 1; + } + *dp = 0; + value_len_ = dp - value_; +} + +__vpiStringConst::~__vpiStringConst() +{ + delete[]value_; +} int __vpiStringConst::get_type_code(void) const { return vpiConstant; } @@ -40,7 +93,7 @@ int __vpiStringConst::vpi_get(int code) { switch (code) { case vpiSize: - return strlen(value)*8; + return strlen(value_)*8; case vpiSigned: return 0; @@ -68,7 +121,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) { unsigned uint_value; p_vpi_vecval vecp; - int size = strlen(value); + int size = strlen(value_); char*rbuf = 0; char*cp; @@ -79,7 +132,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) case vpiStringVal: rbuf = need_result_buf(size + 1, RBUF_VAL); - strcpy(rbuf, (char*)value); + strcpy(rbuf, value_); vp->value.str = rbuf; break; @@ -94,7 +147,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) uint_value = 0; for(int i=0; ivalue.str = rbuf; @@ -105,7 +158,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) cp = rbuf; for(int i=0; i=0; bit--){ - *cp++ = "01"[ (value[i]>>bit)&1 ]; + *cp++ = "01"[ (value_[i]>>bit)&1 ]; } } *cp = 0; @@ -117,7 +170,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) cp = rbuf; for(int i=0; i=0; nibble--){ - *cp++ = "0123456789abcdef"[ (value[i]>>(nibble*4))&15 ]; + *cp++ = "0123456789abcdef"[ (value_[i]>>(nibble*4))&15 ]; } } *cp = 0; @@ -134,7 +187,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) for(int i=0; i=0; bit--){ vp->value.integer <<= 1; - vp->value.integer += (value[i]>>bit)&1; + vp->value.integer += (value_[i]>>bit)&1; } } break; @@ -148,7 +201,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) vecp = vp->value.vector; vecp->aval = vecp->bval = 0; for(int i=0; iaval |= value[i] << uint_value*8; + vecp->aval |= value_[i] << uint_value*8; uint_value += 1; if (uint_value > 3) { uint_value = 0; @@ -171,81 +224,56 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) struct __vpiStringConstTEMP : public __vpiStringConst { - inline __vpiStringConstTEMP() { } + inline __vpiStringConstTEMP(char*v) : __vpiStringConst(v) { } free_object_fun_t free_object_fun(void); }; static int free_temp_string(vpiHandle obj) { struct __vpiStringConstTEMP*rfp = dynamic_cast<__vpiStringConstTEMP*>(obj); - - delete [] rfp->value; - free(rfp); + delete rfp; return 1; } __vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) { return &free_temp_string; } -/* - * Strings are described at the level of the vvp source as a string - * with literal characters or octal escapes. No other escapes are - * included, they are processed already by the compiler that generated - * the vvp source. - */ -static void vpip_process_string(struct __vpiStringConst*obj) -{ - char*chr = obj->value; - char*dp = obj->value; - - while (*chr) { - char next_char = *chr; - - /* Process octal escapes that I might find. */ - if (*chr == '\\') { - for (int idx = 1 ; idx <= 3 ; idx += 1) { - assert(chr[idx] != 0); - assert(chr[idx] < '8'); - assert(chr[idx] >= '0'); - next_char = next_char*8 + chr[idx] - '0'; - } - chr += 3; - } - *dp++ = next_char; - chr += 1; - } - *dp = 0; - obj->value_len = dp - obj->value; -} - vpiHandle vpip_make_string_const(char*text, bool persistent_flag) { struct __vpiStringConst*obj; - obj = persistent_flag? new __vpiStringConst : new __vpiStringConstTEMP; - obj->value = text; - obj->value_len = 0; - vpip_process_string(obj); + obj = persistent_flag? new __vpiStringConst(text) : new __vpiStringConstTEMP(text); return obj; } -struct __vpiStringParam : public __vpiStringConst { - __vpiStringParam(); +class __vpiStringParam : public __vpiStringConst { + public: + __vpiStringParam(char*txt, char*name); + ~__vpiStringParam(); int get_type_code(void) const; int vpi_get(int code); char*vpi_get_str(int code); vpiHandle vpi_handle(int code); - const char*basename; struct __vpiScope* scope; unsigned file_idx; unsigned lineno; + private: + const char*basename_; }; -inline __vpiStringParam::__vpiStringParam() -{ } +inline __vpiStringParam::__vpiStringParam(char*txt, char*nam) +: __vpiStringConst(txt) +{ + basename_ = nam; +} + +__vpiStringParam::~__vpiStringParam() +{ + delete[]basename_; +} int __vpiStringParam::get_type_code(void) const { return vpiParameter; } @@ -265,7 +293,7 @@ char*__vpiStringParam::vpi_get_str(int code) return simple_set_rbuf_str(file_names[file_idx]); } - return generic_get_str(code, scope, basename, NULL); + return generic_get_str(code, scope, basename_, NULL); } @@ -286,16 +314,11 @@ vpiHandle __vpiStringParam::vpi_handle(int code) vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { - struct __vpiStringParam*obj = new __vpiStringParam; - obj->value = text; - obj->value_len = 0; - obj->basename = name; + struct __vpiStringParam*obj = new __vpiStringParam(text, name); obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - vpip_process_string(obj); - return obj; } @@ -416,20 +439,30 @@ vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) } struct __vpiBinaryParam : public __vpiBinaryConst { - __vpiBinaryParam(); + __vpiBinaryParam(const vvp_vector4_t&b, char*name); + ~__vpiBinaryParam(); int get_type_code(void) const; int vpi_get(int code); char*vpi_get_str(int code); vpiHandle vpi_handle(int code); - const char*basename; struct __vpiScope*scope; unsigned file_idx; unsigned lineno; + private: + char*basename_; }; -inline __vpiBinaryParam::__vpiBinaryParam() -{ } +inline __vpiBinaryParam::__vpiBinaryParam(const vvp_vector4_t&b, char*nam) +{ + bits = b; + basename_ = nam; +} + +__vpiBinaryParam::~__vpiBinaryParam() +{ + delete[]basename_; +} int __vpiBinaryParam::get_type_code(void) const { return vpiParameter; } @@ -447,7 +480,7 @@ char*__vpiBinaryParam::vpi_get_str(int code) if (code == vpiFile) return simple_set_rbuf_str(file_names[file_idx]); - return generic_get_str(code, scope, basename, NULL); + return generic_get_str(code, scope, basename_, NULL); } @@ -470,12 +503,10 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno) { - struct __vpiBinaryParam*obj = new __vpiBinaryParam; + struct __vpiBinaryParam*obj = new __vpiBinaryParam(bits, name); - obj->bits = bits; obj->signed_flag = signed_flag? 1 : 0; obj->sized_flag = 0; - obj->basename = name; obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; @@ -571,7 +602,8 @@ void __vpiDecConst::vpi_get_value(p_vpi_value vp) } -inline __vpiRealConst::__vpiRealConst() +inline __vpiRealConst::__vpiRealConst(double val) +: value(val) { } int __vpiRealConst::get_type_code(void) const @@ -617,27 +649,37 @@ void __vpiRealConst::vpi_get_value(p_vpi_value val) vpiHandle vpip_make_real_const(double value) { - struct __vpiRealConst*obj = new __vpiRealConst; - obj->value = value; + struct __vpiRealConst*obj = new __vpiRealConst(value); return obj; } struct __vpiRealParam : public __vpiRealConst { - __vpiRealParam(); + __vpiRealParam(double val, char*name); + ~__vpiRealParam(); int get_type_code(void) const; int vpi_get(int code); char*vpi_get_str(int code); vpiHandle vpi_handle(int code); - const char*basename; struct __vpiScope* scope; unsigned file_idx; unsigned lineno; + private: + const char*basename_; }; -inline __vpiRealParam::__vpiRealParam() -{ } +inline __vpiRealParam::__vpiRealParam(double val, char*name) +: __vpiRealConst(val) +{ + basename_ = name; +} + +__vpiRealParam::~__vpiRealParam() +{ + delete[]basename_; +} + int __vpiRealParam::get_type_code(void) const { return vpiParameter; } @@ -655,7 +697,7 @@ char* __vpiRealParam::vpi_get_str(int code) if (code == vpiFile) return simple_set_rbuf_str(file_names[file_idx]); - return generic_get_str(code, scope, basename, NULL); + return generic_get_str(code, scope, basename_, NULL); } vpiHandle __vpiRealParam::vpi_handle(int code) @@ -676,10 +718,8 @@ vpiHandle __vpiRealParam::vpi_handle(int code) vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) { - struct __vpiRealParam*obj = new __vpiRealParam; + struct __vpiRealParam*obj = new __vpiRealParam(value, name); - obj->value = value; - obj->basename = name; obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; @@ -719,19 +759,15 @@ void parameter_delete(vpiHandle item) switch(vpi_get(vpiConstType, item)) { case vpiStringConst: { struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(item); - delete [] rfp->basename; - delete [] rfp->value; - free(rfp); + delete rfp; break; } case vpiBinaryConst: { struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(item); - delete [] rfp->basename; delete rfp; break; } case vpiRealConst: { struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(item); - delete [] rfp->basename; - free(rfp); + delete rfp; break; } default: assert(0); diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 67dc6ba09..0d82b5575 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -64,8 +64,17 @@ void __vpiHandle::vpi_get_delays(p_vpi_delay) void __vpiHandle::vpi_put_delays(p_vpi_delay) { } +/* + * The default behavior for the vpi_free_object to an object is to + * suppress the actual operation. This is because handles are + * generally allocated semi-permanently within vvp context. Dynamic + * objects will override the free_object_fun method to return an + * appropriately effective function. + */ +static int suppress_free(vpiHandle) +{ return 1; } __vpiHandle::free_object_fun_t __vpiHandle::free_object_fun(void) -{ return 0; } +{ return &suppress_free; } /* * The vpip_string function creates a constant string from the pass @@ -234,10 +243,7 @@ PLI_INT32 vpi_free_object(vpiHandle ref) assert(ref); __vpiHandle::free_object_fun_t fun = ref->free_object_fun(); - if (fun) - rtn = fun (ref); - else - rtn = 1; + rtn = fun (ref); if (vpi_trace) fprintf(vpi_trace, " --> %d\n", rtn); diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 1c1b53b30..615a5f6e0 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -148,7 +148,6 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, struct __vpiCallback : public __vpiHandle { __vpiCallback(); int get_type_code(void) const; - free_object_fun_t free_object_fun(void); // user supplied callback data struct t_cb_data cb_data; @@ -520,22 +519,13 @@ struct __vpiSysTaskCall : public __vpiHandle { extern struct __vpiSysTaskCall*vpip_cur_task; /* - * These are implemented in vpi_const.cc. These are vpiHandles for - * constants. - * * The persistent flag to vpip_make_string_const causes the created * handle to be persistent. This is necessary for cases where the * string handle may be reused, which is the normal case. + * + * When constructing with a string, the class takes possession of the + * text value string, and will delete it in the constructor. */ -struct __vpiStringConst : public __vpiHandle { - __vpiStringConst(); - int get_type_code(void) const; - int vpi_get(int code); - void vpi_get_value(p_vpi_value val); - - char*value; - size_t value_len; -}; vpiHandle vpip_make_string_const(char*text, bool persistent =true); vpiHandle vpip_make_string_param(char*name, char*value, @@ -568,12 +558,13 @@ struct __vpiDecConst : public __vpiHandle { int value; }; -struct __vpiRealConst : public __vpiHandle { - __vpiRealConst(); +class __vpiRealConst : public __vpiHandle { + public: + __vpiRealConst(double); int get_type_code(void) const; int vpi_get(int code); void vpi_get_value(p_vpi_value val); - + public: double value; }; From 2bba7ebbdaac805d9d01a9b57991b339e96a379a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 21 Jan 2012 12:01:57 -0800 Subject: [PATCH 27/88] Trivial fix of compiler warning. --- vvp/array.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/vvp/array.cc b/vvp/array.cc index b952347e2..a28332ef3 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -297,7 +297,6 @@ struct __vpiArrayWord { }; static void array_make_vals_words(struct __vpiArray*parent); -static vpiHandle array_iterator_scan(vpiHandle ref, int); static vpiHandle array_index_scan(vpiHandle ref, int); From bb58ace6d618180f0e6f8554b776ed53538f66c8 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sat, 21 Jan 2012 14:47:42 -0800 Subject: [PATCH 28/88] Update __vpiHandle to use class vs struct The clang compiler does not like mixing class and struct references. This patch updates all the struct __vpiHandle, etc. to use class since that is how they are now defined. --- vpi_user.h | 6 +++++- vvp/codes.h | 4 ++-- vvp/event.cc | 14 +++++++------- vvp/event.h | 16 ++++++++-------- vvp/sfunc.cc | 4 ++-- vvp/stop.cc | 8 ++++---- vvp/vpi_const.cc | 6 +++--- vvp/vpi_priv.h | 4 ++-- vvp/vpi_scope.cc | 2 +- vvp/vthread.cc | 8 ++++---- vvp/vvp_cleanup.h | 26 +++++++++++++------------- 11 files changed, 51 insertions(+), 47 deletions(-) diff --git a/vpi_user.h b/vpi_user.h index 7dbe6da81..3d5811835 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ #ifndef __vpi_user_H #define __vpi_user_H /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,7 +46,11 @@ EXTERN_C_START # include "_pli_types.h" #define ICARUS_VPI_CONST +#ifdef __cplusplus +typedef class __vpiHandle *vpiHandle; +#else typedef struct __vpiHandle *vpiHandle; +#endif /* * This structure is created by the VPI application to provide hooks diff --git a/vvp/codes.h b/vvp/codes.h index 1ca329810..e7632d5b2 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -1,7 +1,7 @@ #ifndef __codes_H #define __codes_H /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -186,7 +186,7 @@ struct vvp_code_s { vvp_net_t *net; vvp_code_t cptr; vvp_array_t array; - struct __vpiHandle*handle; + class __vpiHandle*handle; struct __vpiScope*scope; }; diff --git a/vvp/event.cc b/vvp/event.cc index c3f28c000..30ffa6f7c 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -71,7 +71,7 @@ bool evctl::dec_and_run() return ecount_ == 0; } -evctl_real::evctl_real(struct __vpiHandle*handle, double value, +evctl_real::evctl_real(class __vpiHandle*handle, double value, unsigned long ecount) :evctl(ecount) { @@ -88,7 +88,7 @@ void evctl_real::run_run() vpi_put_value(handle_, &val, 0, vpiNoDelay); } -void schedule_evctl(struct __vpiHandle*handle, double value, +void schedule_evctl(class __vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount) { // Get the functor we are going to wait on. @@ -655,7 +655,7 @@ void vvp_fun_event_or_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } } -vvp_named_event::vvp_named_event(struct __vpiHandle*h) +vvp_named_event::vvp_named_event(class __vpiHandle*h) { handle_ = h; } @@ -664,7 +664,7 @@ vvp_named_event::~vvp_named_event() { } -vvp_named_event_sa::vvp_named_event_sa(struct __vpiHandle*h) +vvp_named_event_sa::vvp_named_event_sa(class __vpiHandle*h) : vvp_named_event(h), threads_(0) { } @@ -691,7 +691,7 @@ void vvp_named_event_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vpip_run_named_event_callbacks(handle_); } -vvp_named_event_aa::vvp_named_event_aa(struct __vpiHandle*h) +vvp_named_event_aa::vvp_named_event_aa(class __vpiHandle*h) : vvp_named_event(h) { context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); @@ -851,7 +851,7 @@ void compile_named_event(char*label, char*name) } #ifdef CHECK_WITH_VALGRIND -void named_event_delete(struct __vpiHandle*handle) +void named_event_delete(class __vpiHandle*handle) { struct __vpiNamedEvent *obj = (struct __vpiNamedEvent *) handle; diff --git a/vvp/event.h b/vvp/event.h index ad812234b..96841d53a 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -1,7 +1,7 @@ #ifndef __event_H #define __event_H /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,13 +40,13 @@ class evctl { class evctl_real : public evctl { public: - explicit evctl_real(struct __vpiHandle*handle, double value, + explicit evctl_real(class __vpiHandle*handle, double value, unsigned long ecount); virtual ~evctl_real() {} void run_run(); private: - __vpiHandle*handle_; + class __vpiHandle*handle_; double value_; }; @@ -95,7 +95,7 @@ class evctl_array_r : public evctl { double value_; }; -extern void schedule_evctl(struct __vpiHandle*handle, double value, +extern void schedule_evctl(class __vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount); extern void schedule_evctl(vvp_net_ptr_t ptr, const vvp_vector4_t&value, @@ -357,11 +357,11 @@ class vvp_fun_event_or_aa : public vvp_fun_event_or, public automatic_hooks_s { class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { public: - explicit vvp_named_event(struct __vpiHandle*eh); + explicit vvp_named_event(class __vpiHandle*eh); ~vvp_named_event(); protected: - struct __vpiHandle*handle_; + class __vpiHandle*handle_; }; /* @@ -370,7 +370,7 @@ class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { class vvp_named_event_sa : public vvp_named_event { public: - explicit vvp_named_event_sa(struct __vpiHandle*eh); + explicit vvp_named_event_sa(class __vpiHandle*eh); ~vvp_named_event_sa(); vthread_t add_waiting_thread(vthread_t thread); @@ -388,7 +388,7 @@ class vvp_named_event_sa : public vvp_named_event { class vvp_named_event_aa : public vvp_named_event, public automatic_hooks_s { public: - explicit vvp_named_event_aa(struct __vpiHandle*eh); + explicit vvp_named_event_aa(class __vpiHandle*eh); ~vvp_named_event_aa(); void alloc_instance(vvp_context_t context); diff --git a/vvp/sfunc.cc b/vvp/sfunc.cc index 1c7e85d8e..1a00ab1d3 100644 --- a/vvp/sfunc.cc +++ b/vvp/sfunc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2012 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 @@ -74,7 +74,7 @@ void sfunc_core::recv_vec4_from_inputs(unsigned port) void sfunc_core::recv_real_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - struct __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); + class __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); assert(obj); obj->value = value_r(port); diff --git a/vvp/stop.cc b/vvp/stop.cc index b25a432fc..1313d9700 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -74,7 +74,7 @@ static bool interact_flag = true; static void cmd_call(unsigned argc, char*argv[]) { - struct __vpiHandle**table; + class __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -212,7 +212,7 @@ static void cmd_help(unsigned, char*[]); static void cmd_list(unsigned, char*[]) { - struct __vpiHandle**table; + class __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -314,7 +314,7 @@ static void cmd_push(unsigned argc, char* argv[]) { for (unsigned idx = 1 ; idx < argc ; idx += 1) { - struct __vpiHandle**table; + class __vpiHandle**table; unsigned ntable; struct __vpiScope*child = 0; diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index f7071de3b..532fb4424 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -240,7 +240,7 @@ __vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) vpiHandle vpip_make_string_const(char*text, bool persistent_flag) { - struct __vpiStringConst*obj; + class __vpiStringConst*obj; obj = persistent_flag? new __vpiStringConst(text) : new __vpiStringConstTEMP(text); @@ -314,7 +314,7 @@ vpiHandle __vpiStringParam::vpi_handle(int code) vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { - struct __vpiStringParam*obj = new __vpiStringParam(text, name); + class __vpiStringParam*obj = new __vpiStringParam(text, name); obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; @@ -649,7 +649,7 @@ void __vpiRealConst::vpi_get_value(p_vpi_value val) vpiHandle vpip_make_real_const(double value) { - struct __vpiRealConst*obj = new __vpiRealConst(value); + class __vpiRealConst*obj = new __vpiRealConst(value); return obj; } diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 615a5f6e0..51854651e 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -224,7 +224,7 @@ struct __vpiScope : public __vpiHandle { struct __vpiScopedSTime scoped_stime; struct __vpiScopedRealtime scoped_realtime; /* Keep an array of internal scope items. */ - struct __vpiHandle**intern; + class __vpiHandle**intern; unsigned nintern; /* Keep an array of items to be automatically allocated */ struct automatic_hooks_s**item; @@ -249,7 +249,7 @@ extern struct __vpiScope* vpip_peek_context_scope(void); extern unsigned vpip_add_item_to_context(automatic_hooks_s*item, struct __vpiScope*scope); extern vpiHandle vpip_make_root_iterator(void); -extern void vpip_make_root_iterator(struct __vpiHandle**&table, +extern void vpip_make_root_iterator(class __vpiHandle**&table, unsigned&ntable); /* diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 07341fe8b..6b45e8307 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -41,7 +41,7 @@ vpiHandle vpip_make_root_iterator(void) vpip_root_table_ptr, false); } -void vpip_make_root_iterator(struct __vpiHandle**&table, unsigned&ntable) +void vpip_make_root_iterator(class __vpiHandle**&table, unsigned&ntable) { table = vpip_root_table_ptr; ntable = vpip_root_table_cnt; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 31695764d..0e10fe99f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1173,7 +1173,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - struct __vpiHandle*tmp = cp->handle; + class __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1192,7 +1192,7 @@ bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - struct __vpiHandle*tmp = cp->handle; + class __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1206,7 +1206,7 @@ bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t cp) { assert(thr->event != 0); unsigned index = cp->bit_idx[0]; - struct __vpiHandle*tmp = cp->handle; + class __vpiHandle*tmp = cp->handle; // If the count is zero then just put the value. if (thr->ecount == 0) { @@ -3184,7 +3184,7 @@ bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t cp) bool of_LOAD_WR(vthread_t thr, vvp_code_t cp) { - struct __vpiHandle*tmp = cp->handle; + class __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; diff --git a/vvp/vvp_cleanup.h b/vvp/vvp_cleanup.h index c223f46dc..9fcc2f7a5 100644 --- a/vvp/vvp_cleanup.h +++ b/vvp/vvp_cleanup.h @@ -1,7 +1,7 @@ #ifndef __vvp_cleanup_H #define __vvp_cleanup_H /* - * Copyright (c) 2009-2011 Cary R. (cygcary@yahoo.com) + * Copyright (c) 2009-2012 Cary R. (cygcary@yahoo.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -39,19 +39,19 @@ extern void vpi_handle_delete(void); extern void vvp_net_pool_delete(void); extern void ufunc_pool_delete(void); -extern void A_delete(struct __vpiHandle *item); -extern void PV_delete(struct __vpiHandle *item); -extern void constant_delete(struct __vpiHandle *item); +extern void A_delete(class __vpiHandle *item); +extern void PV_delete(class __vpiHandle *item); +extern void constant_delete(class __vpiHandle *item); extern void contexts_delete(struct __vpiScope *scope); -extern void enum_delete(struct __vpiHandle *item); -extern void memory_delete(struct __vpiHandle *item); -extern void named_event_delete(struct __vpiHandle *item); -extern void parameter_delete(struct __vpiHandle *item); -extern void signal_delete(struct __vpiHandle *item); -extern void real_delete(struct __vpiHandle *item); -extern void thread_vthr_delete(struct __vpiHandle *item); -extern void thread_word_delete(struct __vpiHandle *item); -extern void vpi_call_delete(struct __vpiHandle *item); +extern void enum_delete(class __vpiHandle *item); +extern void memory_delete(class __vpiHandle *item); +extern void named_event_delete(class __vpiHandle *item); +extern void parameter_delete(class __vpiHandle *item); +extern void signal_delete(class __vpiHandle *item); +extern void real_delete(class __vpiHandle *item); +extern void thread_vthr_delete(class __vpiHandle *item); +extern void thread_word_delete(class __vpiHandle *item); +extern void vpi_call_delete(class __vpiHandle *item); extern void exec_ufunc_delete(vvp_code_t euf_code); extern void vthreads_delete(struct __vpiScope*scope); extern void vvp_net_delete(vvp_net_t *item); From d3df962b2a2760a4dbc8ac90135a283ea7f07fac Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 22 Jan 2012 20:37:01 -0800 Subject: [PATCH 29/88] Cleaner __vpiCallback construction. --- vvp/array.cc | 4 +-- vvp/compile.cc | 6 ++--- vvp/event.cc | 4 ++- vvp/vpi_callback.cc | 59 +++++++++++++++------------------------------ vvp/vpi_event.cc | 29 +++++++++++----------- vvp/vpi_priv.h | 28 +++++++++++++-------- 6 files changed, 60 insertions(+), 70 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index a28332ef3..a13d85dfe 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1516,13 +1516,13 @@ void array_word_change(vvp_array_t array, unsigned long addr) array->vpi_callbacks = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } else { assert(prev->next == cur); prev->next = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } } } diff --git a/vvp/compile.cc b/vvp/compile.cc index 5fc1ba667..89fe73717 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -296,17 +296,17 @@ vvp_net_t* vvp_net_lookup(const char*label) case vpiIntVar: case vpiLongIntVar: case vpiIntegerVar: { - __vpiSignal*sig = (__vpiSignal*)vpi; + __vpiSignal*sig = dynamic_cast<__vpiSignal*>(vpi); return sig->node; } case vpiRealVar: { - __vpiRealVar*sig = (__vpiRealVar*)vpi; + __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(vpi); return sig->net; } case vpiNamedEvent: { - __vpiNamedEvent*tmp = (__vpiNamedEvent*)vpi; + __vpiNamedEvent*tmp = dynamic_cast<__vpiNamedEvent*>(vpi); return tmp->funct; } diff --git a/vvp/event.cc b/vvp/event.cc index 30ffa6f7c..81fc84bf7 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -688,7 +688,9 @@ void vvp_named_event_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_net_t*net = port.ptr(); net->send_vec4(bit, 0); - vpip_run_named_event_callbacks(handle_); + __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(handle_); + assert(obj); + obj->run_vpi_callbacks(); } vvp_named_event_aa::vvp_named_event_aa(class __vpiHandle*h) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 089f0a5f8..5c6a617bb 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -34,15 +34,6 @@ # include # include # include - - -inline __vpiCallback::__vpiCallback() -{ } - -int __vpiCallback::get_type_code(void) const -{ return vpiCallback; } - - /* * Callback handles are created when the VPI function registers a * callback. The handle is stored by the run time, and it triggered @@ -67,24 +58,20 @@ struct sync_cb : public vvp_gen_event_s { virtual void run_run(); }; -struct __vpiCallback* new_vpi_callback() +inline __vpiCallback::__vpiCallback() { - struct __vpiCallback* obj; - - obj = new __vpiCallback; - - obj->cb_sync = 0; - obj->next = 0; - return obj; + cb_sync = 0; + next = 0; } -void delete_vpi_callback(struct __vpiCallback* ref) +__vpiCallback::~__vpiCallback() { - assert(ref); - delete ref->cb_sync; - delete ref; + delete cb_sync; } +int __vpiCallback::get_type_code(void) const +{ return vpiCallback; } + /* * A value change callback is tripped when a bit of a signal @@ -103,7 +90,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return 0; } - struct __vpiCallback*obj = new_vpi_callback(); + struct __vpiCallback*obj = new __vpiCallback; obj->cb_data = *data; if (data->time) { obj->cb_time = *(data->time); @@ -150,8 +137,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) case vpiNamedEvent: struct __vpiNamedEvent*nev; nev = dynamic_cast<__vpiNamedEvent*>(data->obj); - obj->next = nev->callbacks; - nev->callbacks = obj; + nev->add_vpi_callback(obj); break; case vpiMemoryWord: @@ -203,19 +189,17 @@ void sync_cb::run_run() vpi_mode_flag = VPI_MODE_NONE; } - delete_vpi_callback(cur); + delete cur; } static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) { - struct __vpiCallback*obj = new_vpi_callback(); + struct __vpiCallback*obj = new __vpiCallback; obj->cb_data = *data; assert(data->time); obj->cb_time = *(data->time); obj->cb_data.time = &obj->cb_time; - obj->next = 0; - struct sync_cb*cb = new sync_cb; cb->sync_flag = readonly_flag? true : false; cb->handle = obj; @@ -248,14 +232,11 @@ static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) { - struct __vpiCallback*obj = new_vpi_callback(); + struct __vpiCallback*obj = new __vpiCallback; obj->cb_data = *data; assert(data->time); obj->cb_time = *(data->time); obj->cb_data.time = &obj->cb_time; - - obj->next = 0; - struct sync_cb*cb = new sync_cb; cb->sync_flag = false; cb->handle = obj; @@ -317,7 +298,7 @@ void vpiEndOfCompile(void) { cur = EndOfCompile; EndOfCompile = cur->next; (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; @@ -337,7 +318,7 @@ void vpiStartOfSim(void) { cur = StartOfSimulation; StartOfSimulation = cur->next; (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; @@ -359,7 +340,7 @@ void vpiPostsim(void) { if (cur->cb_data.time) vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; @@ -377,14 +358,14 @@ void vpiNextSimTime(void) cur = NextSimTime; NextSimTime = cur->next; (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } } static struct __vpiCallback* make_prepost(p_cb_data data) { - struct __vpiCallback*obj = new_vpi_callback(); + struct __vpiCallback*obj = new __vpiCallback; obj->cb_data = *data; /* Insert at head of list */ @@ -562,13 +543,13 @@ void vvp_vpi_callback::run_vpi_callbacks() vpi_callbacks_ = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } else { assert(prev->next == cur); prev->next = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } } } diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 9c13b7246..1bd3032fc 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -25,8 +25,12 @@ # include # include "ivl_alloc.h" -inline __vpiNamedEvent::__vpiNamedEvent() -{ } +inline __vpiNamedEvent::__vpiNamedEvent(__vpiScope*sc, const char*nam) +{ + scope_ = sc; + name_ = vpip_name_string(nam); + callbacks_ = 0; +} int __vpiNamedEvent::get_type_code(void) const { return vpiNamedEvent; } @@ -36,7 +40,7 @@ int __vpiNamedEvent::vpi_get(int code) switch (code) { case vpiAutomatic: - return (int) scope->is_automatic; + return (int) scope_->is_automatic; } return 0; @@ -47,7 +51,7 @@ char* __vpiNamedEvent::vpi_get_str(int code) if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } - return generic_get_str(code, scope, name, NULL); + return generic_get_str(code, scope_, name_, NULL); } @@ -55,10 +59,10 @@ vpiHandle __vpiNamedEvent::vpi_handle(int code) { switch (code) { case vpiScope: - return scope; + return scope_; case vpiModule: - return vpip_module(scope); + return vpip_module(scope_); } return 0; @@ -67,12 +71,9 @@ vpiHandle __vpiNamedEvent::vpi_handle(int code) vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { - struct __vpiNamedEvent*obj = new __vpiNamedEvent; + struct __vpiNamedEvent*obj = new __vpiNamedEvent(vpip_peek_current_scope(), name); - obj->name = vpip_name_string(name); - obj->scope = vpip_peek_current_scope(); obj->funct = funct; - obj->callbacks = 0; return obj; } @@ -90,11 +91,9 @@ vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) * We can not use vpi_free_object() here since it does not really * delete the callback. */ -void vpip_run_named_event_callbacks(vpiHandle ref) +void __vpiNamedEvent::run_vpi_callbacks() { - struct __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(ref); - - struct __vpiCallback*next = obj->callbacks; + struct __vpiCallback*next = callbacks_; struct __vpiCallback*prev = 0; while (next) { struct __vpiCallback*cur = next; @@ -105,7 +104,7 @@ void vpip_run_named_event_callbacks(vpiHandle ref) prev = cur; } else if (prev == 0) { - obj->callbacks = next; + callbacks_ = next; cur->next = 0; delete cur; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 51854651e..8981bcbaa 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -147,6 +147,7 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, */ struct __vpiCallback : public __vpiHandle { __vpiCallback(); + ~__vpiCallback(); int get_type_code(void) const; // user supplied callback data @@ -164,8 +165,6 @@ struct __vpiCallback : public __vpiHandle { struct __vpiCallback*next; }; -extern struct __vpiCallback* new_vpi_callback(); -extern void delete_vpi_callback(struct __vpiCallback* ref); extern void callback_execute(struct __vpiCallback*cur); struct __vpiSystemTime : public __vpiHandle { @@ -405,25 +404,34 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; * passed in will be saved, so the caller must allocate it (or not * free it) after it is handed to this function. */ -struct __vpiNamedEvent : public __vpiHandle { - __vpiNamedEvent(); +class __vpiNamedEvent : public __vpiHandle { + public: + __vpiNamedEvent(__vpiScope*scope, const char*name); int get_type_code(void) const; int vpi_get(int code); char* vpi_get_str(int code); vpiHandle vpi_handle(int code); - /* base name of the event object */ - const char*name; - /* Parent scope of this object. */ - struct __vpiScope*scope; + inline void add_vpi_callback(__vpiCallback*cb) + { cb->next = callbacks_; + callbacks_ = cb; + } + + void run_vpi_callbacks(void); + /* The functor, used for %set operations. */ vvp_net_t*funct; + + private: + /* base name of the event object */ + const char*name_; + /* Parent scope of this object. */ + struct __vpiScope*scope_; /* List of callbacks interested in this event. */ - struct __vpiCallback*callbacks; + struct __vpiCallback*callbacks_; }; extern vpiHandle vpip_make_named_event(const char*name, vvp_net_t*f); -extern void vpip_run_named_event_callbacks(vpiHandle ref); extern void vpip_real_value_change(struct __vpiCallback*cbh, vpiHandle ref); From e9d68098d5bdd0d5546fcbad200a76b374cdb5b6 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 23 Jan 2012 18:42:02 -0800 Subject: [PATCH 30/88] Fix the formatting of time values that are less than 1 This patch is a modification of a user contributed patch that fixes the time formatting when the time is less than 1 and $timeformat() is used. --- vpi/sys_display.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 8e380572c..d5fdb4234 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -182,7 +182,6 @@ static char * format_as_string(int ljust, int plus, int ld_zero, int width, static void get_time(char *rtn, const char *value, int prec, PLI_INT32 time_units) { - int head, tail; int shift = time_units - timeformat_info.units; /* Strip any leading zeros, but leave a single zero. */ @@ -203,7 +202,9 @@ static void get_time(char *rtn, const char *value, int prec, /* We need to scale the number down. */ } else { - head = strlen(value) + shift; + int len = strlen(value); + int head = len + shift; + int tail; /* We have digits to the left of the decimal point. */ if (head > 0) { strncpy(rtn, value, head); @@ -222,18 +223,18 @@ static void get_time(char *rtn, const char *value, int prec, strcpy(rtn, "0"); if (prec > 0) strcat(rtn, "."); /* Add leading zeros as needed. */ - head = -shift - 1; + head = -head; if (head > prec) head = prec; while (head > 0) { strcat(rtn, "0"); head -= 1; } /* Add digits from the value if they fit. */ - tail = prec + shift + 1; + tail = prec + len + shift; if (tail > 0) { strncat(rtn, value, tail); /* Add trailing zeros to fill out the precision. */ - tail = prec + shift + 1 - strlen(value); + tail = prec + shift + 1 - len; while (tail > 0) { strcat(rtn, "0"); tail -= 1; From 53585c9209a435d1b299b27b6d34fd9401ca919d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 29 Jan 2012 17:31:19 -0800 Subject: [PATCH 31/88] Derived classes for different callback types. --- vvp/vpi_callback.cc | 131 ++++++++++++++++++++++++++++---------------- vvp/vpi_priv.h | 14 ++--- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 5c6a617bb..01cced8c1 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -50,7 +50,7 @@ */ struct sync_cb : public vvp_gen_event_s { - struct __vpiCallback*handle; + class sync_callback*handle; bool sync_flag; ~sync_cb () { } @@ -60,19 +60,44 @@ struct sync_cb : public vvp_gen_event_s { inline __vpiCallback::__vpiCallback() { - cb_sync = 0; next = 0; } __vpiCallback::~__vpiCallback() { - delete cb_sync; } int __vpiCallback::get_type_code(void) const { return vpiCallback; } +class value_callback : public __vpiCallback { + public: + explicit value_callback(p_cb_data data); + + public: + // user supplied callback data + struct t_vpi_time cb_time; + struct t_vpi_value cb_value; +}; + +inline value_callback::value_callback(p_cb_data data) +{ + cb_data = *data; + if (data->time) { + cb_time = *(data->time); + } else { + cb_time.type = vpiSuppressTime; + } + cb_data.time = &cb_time; + if (data->value) { + cb_value = *(data->value); + } else { + cb_value.format = vpiSuppressVal; + } + cb_data.value = &cb_value; +} + /* * A value change callback is tripped when a bit of a signal * changes. This function creates that value change callback and @@ -80,7 +105,7 @@ int __vpiCallback::get_type_code(void) const * does not already have them, create some callback functors to do the * actual value change detection. */ -static struct __vpiCallback* make_value_change(p_cb_data data) +static value_callback* make_value_change(p_cb_data data) { if (vpi_get(vpiAutomatic, data->obj)) { fprintf(stderr, "vpi error: cannot place value change " @@ -90,23 +115,9 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return 0; } - struct __vpiCallback*obj = new __vpiCallback; - obj->cb_data = *data; - if (data->time) { - obj->cb_time = *(data->time); - } else { - obj->cb_time.type = vpiSuppressTime; - } - obj->cb_data.time = &obj->cb_time; - if (data->value) { - obj->cb_value = *(data->value); - } else { - obj->cb_value.format = vpiSuppressVal; - } - obj->cb_data.value = &obj->cb_value; + value_callback*obj = new value_callback(data); assert(data->obj); - switch (data->obj->get_type_code()) { case vpiReg: @@ -170,12 +181,41 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return obj; } +class sync_callback : public __vpiCallback { + public: + explicit sync_callback(p_cb_data data); + ~sync_callback(); + + public: + // scheduled event + struct sync_cb* cb_sync; + // user supplied callback data + struct t_vpi_time cb_time; + + private: +}; + +inline sync_callback::sync_callback(p_cb_data data) +{ + cb_sync = 0; + + cb_data = *data; + assert(data->time); + cb_time = *(data->time); + cb_data.time = &cb_time; +} + +sync_callback::~sync_callback() +{ + delete cb_sync; +} + void sync_cb::run_run() { if (handle == 0) return; - struct __vpiCallback*cur = handle; + sync_callback*cur = handle; cur->cb_data.time->type = vpiSimTime; vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); @@ -192,13 +232,9 @@ void sync_cb::run_run() delete cur; } -static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) +static sync_callback* make_sync(p_cb_data data, bool readonly_flag) { - struct __vpiCallback*obj = new __vpiCallback; - obj->cb_data = *data; - assert(data->time); - obj->cb_time = *(data->time); - obj->cb_data.time = &obj->cb_time; + sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; cb->sync_flag = readonly_flag? true : false; @@ -232,11 +268,7 @@ static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) { - struct __vpiCallback*obj = new __vpiCallback; - obj->cb_data = *data; - assert(data->time); - obj->cb_time = *(data->time); - obj->cb_data.time = &obj->cb_time; + sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; cb->sync_flag = false; cb->handle = obj; @@ -279,13 +311,21 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) * callbacks. */ -static struct __vpiCallback*NextSimTime = 0; -static struct __vpiCallback*EndOfCompile = NULL; -static struct __vpiCallback*StartOfSimulation = NULL; -static struct __vpiCallback*EndOfSimulation = NULL; +class simulator_callback : public __vpiCallback { + public: + inline explicit simulator_callback(struct t_cb_data*data) + { cb_data = *data; } + + public: +}; + +static simulator_callback*NextSimTime = 0; +static simulator_callback*EndOfCompile = 0; +static simulator_callback*StartOfSimulation = 0; +static simulator_callback*EndOfSimulation = 0; void vpiEndOfCompile(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks, executing them and @@ -296,7 +336,7 @@ void vpiEndOfCompile(void) { while (EndOfCompile) { cur = EndOfCompile; - EndOfCompile = cur->next; + EndOfCompile = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); delete cur; } @@ -305,7 +345,7 @@ void vpiEndOfCompile(void) { } void vpiStartOfSim(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks, executing them and @@ -316,7 +356,7 @@ void vpiStartOfSim(void) { while (StartOfSimulation) { cur = StartOfSimulation; - StartOfSimulation = cur->next; + StartOfSimulation = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); delete cur; } @@ -325,7 +365,7 @@ void vpiStartOfSim(void) { } void vpiPostsim(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks @@ -335,7 +375,7 @@ void vpiPostsim(void) { while (EndOfSimulation) { cur = EndOfSimulation; - EndOfSimulation = cur->next; + EndOfSimulation = dynamic_cast(cur->next); /* Only set the time if it is not NULL. */ if (cur->cb_data.time) vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); @@ -352,21 +392,20 @@ void vpiPostsim(void) { */ void vpiNextSimTime(void) { - struct __vpiCallback* cur; + simulator_callback* cur; while (NextSimTime) { cur = NextSimTime; - NextSimTime = cur->next; + NextSimTime = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); delete cur; } } -static struct __vpiCallback* make_prepost(p_cb_data data) +static simulator_callback* make_prepost(p_cb_data data) { - struct __vpiCallback*obj = new __vpiCallback; - obj->cb_data = *data; + simulator_callback*obj = new simulator_callback(data); /* Insert at head of list */ switch (data->reason) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 8981bcbaa..949e092f6 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -150,19 +150,14 @@ struct __vpiCallback : public __vpiHandle { ~__vpiCallback(); int get_type_code(void) const; + // Used for listing callbacks. + struct __vpiCallback*next; + // user supplied callback data struct t_cb_data cb_data; - struct t_vpi_time cb_time; - struct t_vpi_value cb_value; - - // scheduled event - struct sync_cb* cb_sync; // The callback holder may use this for various purposes. long extra_data; - - // Used for listing callbacks. - struct __vpiCallback*next; }; extern void callback_execute(struct __vpiCallback*cur); @@ -405,6 +400,7 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; * free it) after it is handed to this function. */ class __vpiNamedEvent : public __vpiHandle { + public: __vpiNamedEvent(__vpiScope*scope, const char*name); int get_type_code(void) const; @@ -428,7 +424,7 @@ class __vpiNamedEvent : public __vpiHandle { /* Parent scope of this object. */ struct __vpiScope*scope_; /* List of callbacks interested in this event. */ - struct __vpiCallback*callbacks_; + __vpiCallback*callbacks_; }; extern vpiHandle vpip_make_named_event(const char*name, vvp_net_t*f); From c7a54891c441f30f8aa071421bdd8dfe1d6a7415 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Jan 2012 19:12:20 -0800 Subject: [PATCH 32/88] Properly handle value change callbacks on part selects. cbValueChange callbacks on part selects have to go through some extra effort to make sure the value they are watching really is changing. --- vvp/vpi_callback.cc | 128 ++++++++++++++++++++++++++++++++++++----- vvp/vpi_priv.h | 5 -- vvp/vpi_real.cc | 11 ---- vvp/vpi_signal.cc | 19 ------ vvp/vvp_vpi_callback.h | 6 +- 5 files changed, 119 insertions(+), 50 deletions(-) diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 01cced8c1..1f8804fb2 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -74,6 +74,8 @@ int __vpiCallback::get_type_code(void) const class value_callback : public __vpiCallback { public: explicit value_callback(p_cb_data data); + // Return true if the callback really is ready to be called + virtual bool test_value_callback_ready(void); public: // user supplied callback data @@ -81,7 +83,7 @@ class value_callback : public __vpiCallback { struct t_vpi_value cb_value; }; -inline value_callback::value_callback(p_cb_data data) +value_callback::value_callback(p_cb_data data) { cb_data = *data; if (data->time) { @@ -98,6 +100,104 @@ inline value_callback::value_callback(p_cb_data data) cb_data.value = &cb_value; } +/* + * Normally, any assign to a value triggers a value change callback, + * so return a constant true here. This is a stub. + */ +bool value_callback::test_value_callback_ready(void) +{ + return true; +} + +static void vpip_real_value_change(value_callback*cbh, vpiHandle ref) +{ + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); + vvp_vpi_callback*obj = dynamic_cast(rfp->net->fil); + assert(obj); + + obj->add_vpi_callback(cbh); +} + +class value_part_callback : public value_callback { + public: + explicit value_part_callback(p_cb_data data); + ~value_part_callback(); + + bool test_value_callback_ready(void); + + private: + char*value_bits_; + size_t value_off_; +}; + +inline value_part_callback::value_part_callback(p_cb_data data) +: value_callback(data) +{ + struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(data->obj); + assert(pobj); + + vvp_vpi_callback*sig_fil; + sig_fil = dynamic_cast(pobj->net->fil); + assert(sig_fil); + + sig_fil->add_vpi_callback(this); + // Get a reference value that can be used to compare with an + // updated value. Use the filter get_value to get the value, + // and get it in BinStr form so that compares are easy. Note + // that the vpiBinStr format has the MSB first, but the tbase + // is lsb first. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + sig_fil->get_value(&tmp_value); + + value_bits_ = new char[pobj->width+1]; + value_off_ = pobj->parent->vpi_get(vpiSize) - pobj->width - pobj->tbase; + + memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width); + value_bits_[pobj->width] = 0; +} + +value_part_callback::~value_part_callback() +{ + delete[]value_bits_; +} + +bool value_part_callback::test_value_callback_ready(void) +{ + struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(cb_data.obj); + assert(pobj); + + vvp_vpi_callback*sig_fil; + sig_fil = dynamic_cast(pobj->net->fil); + assert(sig_fil); + + // Get a reference value that can be used to compare with an + // updated value. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + sig_fil->get_value(&tmp_value); + + if (memcmp(value_bits_, tmp_value.value.str + value_off_, pobj->width) == 0) + return false; + + memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width); + return true; +} + +/* + * Attach the __vpiCallback to the object that this part select + * selects from. The part select itself is not a vvp_vpi_callback + * object, but it refers to a net that is a vvp_vpi_callback, so + * add the callback to that object. + */ +static value_callback*make_value_change_part(p_cb_data data) +{ + /* Attach the __vpiCallback object to the signal. */ + value_callback*cbh = new value_part_callback(data); + return cbh; +} + /* * A value change callback is tripped when a bit of a signal * changes. This function creates that value change callback and @@ -115,6 +215,10 @@ static value_callback* make_value_change(p_cb_data data) return 0; } + // Special case: the target object is a vpiPartSelect + if (data->obj->get_type_code() == vpiPartSelect) + return make_value_change_part(data); + value_callback*obj = new value_callback(data); assert(data->obj); @@ -159,10 +263,6 @@ static value_callback* make_value_change(p_cb_data data) vpip_array_change(obj, data->obj); break; - case vpiPartSelect: - vpip_part_select_value_change(obj, data->obj); - break; - case vpiModule: case vpiConstant: case vpiParameter: @@ -537,7 +637,7 @@ void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr) array_word_ = addr; } -void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb) +void vvp_vpi_callback::add_vpi_callback(value_callback*cb) { cb->next = vpi_callbacks_; vpi_callbacks_ = cb; @@ -564,18 +664,20 @@ void vvp_vpi_callback::run_vpi_callbacks() { if (array_) array_word_change(array_, array_word_); - struct __vpiCallback *next = vpi_callbacks_; - struct __vpiCallback *prev = 0; + value_callback *next = vpi_callbacks_; + value_callback *prev = 0; while (next) { - struct __vpiCallback*cur = next; - next = cur->next; + value_callback*cur = next; + next = dynamic_cast(cur->next); if (cur->cb_data.cb_rtn != 0) { - if (cur->cb_data.value) - get_value(cur->cb_data.value); + if (cur->test_value_callback_ready()) { + if (cur->cb_data.value) + get_value(cur->cb_data.value); - callback_execute(cur); + callback_execute(cur); + } prev = cur; } else if (prev == 0) { diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 949e092f6..4fa287cc9 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -325,9 +325,6 @@ extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width); extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, char*is_signed, int width); -extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle obj); - - struct __vpiModPathTerm : public __vpiHandle { __vpiModPathTerm(); int get_type_code(void) const; @@ -428,8 +425,6 @@ class __vpiNamedEvent : public __vpiHandle { }; extern vpiHandle vpip_make_named_event(const char*name, vvp_net_t*f); -extern void vpip_real_value_change(struct __vpiCallback*cbh, - vpiHandle ref); /* * Memory is an array of bits that is accessible in N-bit chunks, with diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index 0b7f833fb..09f9a96b5 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -159,17 +159,6 @@ vpiHandle __vpiRealVar::vpi_handle(int code) vpiHandle __vpiRealVar::vpi_iterate(int code) { return real_var_iterate(code, this); } -void vpip_real_value_change(struct __vpiCallback*cbh, - vpiHandle ref) -{ - struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); - assert(rfp); - vvp_vpi_callback*obj = dynamic_cast(rfp->net->fil); - assert(obj); - - obj->add_vpi_callback(cbh); -} - vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net) { struct __vpiRealVar*obj = new __vpiRealVar; diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 1b3c656cc..dd821c6c4 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1422,25 +1422,6 @@ vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width) return obj; } -/* - * Attach the __vpiCallback to the object that this part select - * selects from. The part select itself is not a vvp_vpi_callback - * object, but it refers to a net that is a vvp_vpi_callback, so - * add the callback to that object. - */ -void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref) -{ - struct __vpiPV*obj = dynamic_cast<__vpiPV*>(ref); - assert(obj); - - vvp_vpi_callback*sig_fil; - sig_fil = dynamic_cast(obj->net->fil); - assert(sig_fil); - - /* Attach the __vpiCallback object to the signal. */ - sig_fil->add_vpi_callback(cbh); -} - #ifdef CHECK_WITH_VALGRIND void PV_delete(vpiHandle item) { diff --git a/vvp/vvp_vpi_callback.h b/vvp/vvp_vpi_callback.h index 6a9cc2f35..3b2a3802a 100644 --- a/vvp/vvp_vpi_callback.h +++ b/vvp/vvp_vpi_callback.h @@ -22,6 +22,8 @@ # include "config.h" # include "vpi_user.h" +class value_callback; + /* * Things derived from vvp_vpi_callback may have callbacks * attached. This is how vpi callbacks are attached to the vvp @@ -38,7 +40,7 @@ class vvp_vpi_callback { void attach_as_word(struct __vpiArray* arr, unsigned long addr); - void add_vpi_callback(struct __vpiCallback*); + void add_vpi_callback(value_callback*); #ifdef CHECK_WITH_VALGRIND /* This has only been tested at EOS. */ void clear_all_callbacks(void); @@ -54,7 +56,7 @@ class vvp_vpi_callback { void run_vpi_callbacks(); private: - struct __vpiCallback*vpi_callbacks_; + value_callback*vpi_callbacks_; struct __vpiArray* array_; unsigned long array_word_; }; From 5677efdfe647e432907abab51e0eb33f465170e3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 2 Feb 2012 10:49:59 -0800 Subject: [PATCH 33/88] Filter callbacks of value changes to array words. When looking for a value change on a part select of an array word, the callback handle has to save the current value and test it with the new value to see if there is an actual change. If not, then suppress the callback. --- vvp/array.cc | 142 +++++++++++++++++++++++++++++++++----------- vvp/array.h | 5 +- vvp/vpi_callback.cc | 26 ++------ vvp/vpi_priv.h | 13 +++- 4 files changed, 128 insertions(+), 58 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index a13d85dfe..78d2e54d2 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1471,6 +1471,16 @@ static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun) } } +class array_word_value_callback : public value_callback { + public: + inline explicit array_word_value_callback(p_cb_data data) + : value_callback(data) + { } + + public: + long word_addr; +}; + void array_word_change(vvp_array_t array, unsigned long addr) { for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_) @@ -1481,35 +1491,38 @@ void array_word_change(vvp_array_t array, unsigned long addr) struct __vpiCallback *prev = 0; while (next) { - struct __vpiCallback*cur = next; + array_word_value_callback*cur = dynamic_cast(next); next = cur->next; // Skip callbacks that are not for me. -1 is for every element. - if (cur->extra_data != (long)addr && cur->extra_data != -1) { + if (cur->word_addr != (long)addr && cur->word_addr != -1) { prev = cur; continue; } // For whole array callbacks we need to set the index. - if (cur->extra_data == -1) { + if (cur->word_addr == -1) { cur->cb_data.index = (PLI_INT32) ((int)addr + array->first_addr.value); } if (cur->cb_data.cb_rtn != 0) { - if (cur->cb_data.value) { - if (vpi_array_is_real(array)) { - vpip_real_get_value(array->valsr->get_word(addr), - cur->cb_data.value); - } else { - vpip_vec4_get_value(array->vals4->get_word(addr), - array->vals_width, - array->signed_flag, - cur->cb_data.value); + if (cur->test_value_callback_ready()) { + if (cur->cb_data.value) { + if (vpi_array_is_real(array)) { + vpip_real_get_value(array->valsr->get_word(addr), + cur->cb_data.value); + } else { + vpip_vec4_get_value(array->vals4->get_word(addr), + array->vals_width, + array->signed_flag, + cur->cb_data.value); + } } + + callback_execute(cur); } - callback_execute(cur); prev = cur; } else if (prev == 0) { @@ -1597,33 +1610,94 @@ bool array_port_resolv_list_t::resolve(bool mes) return true; } -void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) +class array_word_part_callback : public array_word_value_callback { + public: + explicit array_word_part_callback(p_cb_data data); + ~array_word_part_callback(); + + bool test_value_callback_ready(void); + + private: + char*value_bits_; +}; + +array_word_part_callback::array_word_part_callback(p_cb_data data) +: array_word_value_callback(data) { - struct __vpiArray*parent = 0; - if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) { - unsigned addr = decode_array_word_pointer(word, parent); - cb->extra_data = addr; + // Get the initial value of the part, to use as a reference. + struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj); + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + apvword->vpi_get_value(&tmp_value); - } else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(obj)) { - parent = tword->array; - cb->extra_data = tword->address; + value_bits_ = new char[apvword->part_wid+1]; - } else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(obj)) { - parent = apvword->array; - cb->extra_data = apvword->word_sel; - } - - assert(parent); - cb->next = parent->vpi_callbacks; - parent->vpi_callbacks = cb; + memcpy(value_bits_, tmp_value.value.str, apvword->part_wid); + value_bits_[apvword->part_wid] = 0; } -void vpip_array_change(struct __vpiCallback*cb, vpiHandle obj) +array_word_part_callback::~array_word_part_callback() { - struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); - cb->extra_data = -1; // This is a callback for every element. - cb->next = arr->vpi_callbacks; - arr->vpi_callbacks = cb; + delete[]value_bits_; +} + +bool array_word_part_callback::test_value_callback_ready(void) +{ + struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(cb_data.obj); + assert(apvword); + + // Get a reference value that can be used to compare with an + // updated value. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + apvword->vpi_get_value(&tmp_value); + + if (memcmp(value_bits_, tmp_value.value.str, apvword->part_wid) == 0) + return false; + + memcpy(value_bits_, tmp_value.value.str, apvword->part_wid); + return true; + +} + +value_callback*vpip_array_word_change(p_cb_data data) +{ + struct __vpiArray*parent = 0; + array_word_value_callback*cbh = 0; + if (struct __vpiArrayWord*word = array_var_word_from_handle(data->obj)) { + unsigned addr = decode_array_word_pointer(word, parent); + cbh = new array_word_value_callback(data); + cbh->word_addr = addr; + + } else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(data->obj)) { + parent = tword->array; + cbh = new array_word_value_callback(data); + cbh->word_addr = tword->address; + + } else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj)) { + parent = apvword->array; + cbh = new array_word_part_callback(data); + cbh->word_addr = apvword->word_sel; + } + + assert(cbh); + assert(parent); + cbh->next = parent->vpi_callbacks; + parent->vpi_callbacks = cbh; + + return cbh; +} + +value_callback* vpip_array_change(p_cb_data data) +{ + array_word_value_callback*cbh = new array_word_value_callback(data); + assert(data->obj); + + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(data->obj); + cbh->word_addr = -1; // This is a callback for every element. + cbh->next = arr->vpi_callbacks; + arr->vpi_callbacks = cbh; + return cbh; } void compile_array_port(char*label, char*array, char*addr) diff --git a/vvp/array.h b/vvp/array.h index d5c1e15a3..567dfe40c 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -23,6 +23,7 @@ #include "vpi_user.h" typedef struct __vpiArray* vvp_array_t; +class value_callback; /* * This function tries to find the array (by label) in the global @@ -48,8 +49,8 @@ extern double array_get_word_r(vvp_array_t array, unsigned address); /* VPI hooks */ -extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word); -extern void vpip_array_change(struct __vpiCallback*cb, vpiHandle word); +extern value_callback* vpip_array_word_change(p_cb_data data); +extern value_callback* vpip_array_change(p_cb_data data); /* Compile hooks */ extern void compile_varw_real(char*label, vvp_array_t array, diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 1f8804fb2..5b05d48b4 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -71,18 +71,6 @@ int __vpiCallback::get_type_code(void) const { return vpiCallback; } -class value_callback : public __vpiCallback { - public: - explicit value_callback(p_cb_data data); - // Return true if the callback really is ready to be called - virtual bool test_value_callback_ready(void); - - public: - // user supplied callback data - struct t_vpi_time cb_time; - struct t_vpi_value cb_value; -}; - value_callback::value_callback(p_cb_data data) { cb_data = *data; @@ -219,6 +207,12 @@ static value_callback* make_value_change(p_cb_data data) if (data->obj->get_type_code() == vpiPartSelect) return make_value_change_part(data); + if (data->obj->get_type_code() == vpiMemoryWord) + return vpip_array_word_change(data); + + if (data->obj->get_type_code() == vpiMemory) + return vpip_array_change(data); + value_callback*obj = new value_callback(data); assert(data->obj); @@ -255,14 +249,6 @@ static value_callback* make_value_change(p_cb_data data) nev->add_vpi_callback(obj); break; - case vpiMemoryWord: - vpip_array_word_change(obj, data->obj); - break; - - case vpiMemory: - vpip_array_change(obj, data->obj); - break; - case vpiModule: case vpiConstant: case vpiParameter: diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 4fa287cc9..2f4237957 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -155,9 +155,18 @@ struct __vpiCallback : public __vpiHandle { // user supplied callback data struct t_cb_data cb_data; +}; - // The callback holder may use this for various purposes. - long extra_data; +class value_callback : public __vpiCallback { + public: + explicit value_callback(p_cb_data data); + // Return true if the callback really is ready to be called + virtual bool test_value_callback_ready(void); + + public: + // user supplied callback data + struct t_vpi_time cb_time; + struct t_vpi_value cb_value; }; extern void callback_execute(struct __vpiCallback*cur); From d362c8dba08eb7421b1a470f29f0320bd79e25fc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 3 Dec 2011 17:16:01 -0800 Subject: [PATCH 34/88] Parse support for struct variables. --- Makefile.in | 4 +- PWire.cc | 11 +++- PWire.h | 2 + elab_expr.cc | 28 +++++++-- elab_sig.cc | 6 ++ netlist.cc | 21 ++++++- netlist.h | 5 ++ netstruct.cc | 29 ++++++++++ netstruct.h | 34 +++++++++++ parse.y | 135 +++++++++++++++++++++++++++++++++++++++---- pform.cc | 2 +- pform.h | 4 ++ pform_struct_type.cc | 68 ++++++++++++++++++++++ pform_types.h | 16 +++++ 14 files changed, 342 insertions(+), 23 deletions(-) create mode 100644 netstruct.cc create mode 100644 netstruct.h create mode 100644 pform_struct_type.cc diff --git a/Makefile.in b/Makefile.in index 3abafbe55..ba3663735 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,10 +107,10 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \ - netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ + netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_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 \ + pform_disciplines.o pform_dump.o pform_struct_type.o pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ Attrib.o HName.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 \ diff --git a/PWire.cc b/PWire.cc index 6187528ca..a5d5407a3 100644 --- a/PWire.cc +++ b/PWire.cc @@ -30,7 +30,8 @@ PWire::PWire(perm_string n, signed_(false), isint_(false), port_msb_(0), port_lsb_(0), port_set_(false), net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), - error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), discipline_(0) + error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), + discipline_(0) { if (t == NetNet::INTEGER) { type_ = NetNet::REG; @@ -217,9 +218,17 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) void PWire::set_enumeration(enum_type_t*enum_type) { assert(enum_type_ == 0); + assert(struct_type_ == 0); enum_type_ = enum_type; } +void PWire::set_struct_type(struct_type_t*type) +{ + assert(enum_type_ == 0); + assert(struct_type_ == 0); + struct_type_ = type; +} + void PWire::set_discipline(ivl_discipline_t d) { assert(discipline_ == 0); diff --git a/PWire.h b/PWire.h index 680593edb..96f1b4964 100644 --- a/PWire.h +++ b/PWire.h @@ -80,6 +80,7 @@ class PWire : public LineInfo { void set_memory_idx(PExpr*ldx, PExpr*rdx); void set_enumeration(enum_type_t*enum_type); + void set_struct_type(struct_type_t*type); void set_discipline(ivl_discipline_t); ivl_discipline_t get_discipline(void) const; @@ -116,6 +117,7 @@ class PWire : public LineInfo { PExpr*ridx_; enum_type_t*enum_type_; + struct_type_t*struct_type_; ivl_discipline_t discipline_; diff --git a/elab_expr.cc b/elab_expr.cc index 42ef38108..b3d3458d5 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1418,6 +1418,15 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, return sys_expr; } +static NetExpr* check_for_struct_members(const LineInfo*li, + Design*des, NetScope*scope, + NetNet*net, perm_string method_name) +{ + cerr << li->get_fileline() << ": sorry: structures not supported here." << endl; + des->errors += 1; + return 0; +} + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -1456,8 +1465,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -1472,6 +1480,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, expr_wid, tmp, parms_.size()); } + } } @@ -2289,8 +2298,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + // If this net is actually an enum, the method may + // be an enumeration method. + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -2303,6 +2313,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, use_path, method_name, expr, expr_wid, NULL, 0); } + + // If this net is a struct, the method name may be + // a struct member. + if (net->struct_type() != 0) { + ivl_assert(*this, use_path.back().index.empty()); + + return check_for_struct_members(this, des, scope, + net, method_name); + } + } } diff --git a/elab_sig.cc b/elab_sig.cc index 77cab98fe..cf435013e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -32,6 +32,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -1094,6 +1095,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig->set_enumeration(use_enum); } + if (struct_type_) { + netstruct_t*use_type = new netstruct_t; + sig->set_struct_type(use_type); + } + if (wtype == NetNet::WIRE) sig->devirtualize_pins(); ivl_variable_type_t use_data_type = data_type_; diff --git a/netlist.cc b/netlist.cc index 8d8e9af9a..67899ba0a 100644 --- a/netlist.cc +++ b/netlist.cc @@ -450,7 +450,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0), + enumeration_(0), struct_type_(0), discipline_(0), + msb_(npins-1), lsb_(0), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { assert(s); @@ -496,7 +497,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), + enumeration_(0), struct_type_(0), discipline_(0), msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) @@ -544,7 +545,8 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), + discipline_(0), msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e), eref_count_(0), lref_count_(0) @@ -692,10 +694,23 @@ netenum_t*NetNet::enumeration(void) const void NetNet::set_enumeration(netenum_t*es) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, enumeration_ == 0); enumeration_ = es; } +netstruct_t*NetNet::struct_type(void) const +{ + return struct_type_; +} + +void NetNet::set_struct_type(netstruct_t*type) +{ + ivl_assert(*this, struct_type_ == 0); + ivl_assert(*this, enumeration_ == 0); + struct_type_ = type; +} + ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index 055466b5d..5e6d2bd2c 100644 --- a/netlist.h +++ b/netlist.h @@ -75,6 +75,7 @@ class NetEvWait; class PExpr; class PFunction; class netenum_t; +class netstruct_t; struct target; struct functor_t; @@ -603,6 +604,9 @@ class NetNet : public NetObj { void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; + void set_struct_type(netstruct_t*type); + netstruct_t*struct_type(void) const; + /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); @@ -676,6 +680,7 @@ class NetNet : public NetObj { bool is_scalar_ : 1; bool local_flag_: 1; netenum_t*enumeration_; + netstruct_t*struct_type_; ivl_discipline_t discipline_; long msb_, lsb_; diff --git a/netstruct.cc b/netstruct.cc new file mode 100644 index 000000000..36ba3353a --- /dev/null +++ b/netstruct.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 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 "netstruct.h" + +netstruct_t::netstruct_t() +: packed_(false) +{ +} + +netstruct_t::~netstruct_t() +{ +} diff --git a/netstruct.h b/netstruct.h new file mode 100644 index 000000000..48bdd0cc0 --- /dev/null +++ b/netstruct.h @@ -0,0 +1,34 @@ +#ifndef __netstruct_H +#define __netstruct_H +/* + * Copyright (c) 2011 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 "LineInfo.h" + +class netstruct_t : public LineInfo { + + public: + netstruct_t(); + ~netstruct_t(); + + private: + bool packed_; +}; + +#endif diff --git a/parse.y b/parse.y index 3bc87a667..9e0a65ef9 100644 --- a/parse.y +++ b/parse.y @@ -330,6 +330,13 @@ static void current_task_set_statement(vector*s) net_decl_assign_t*net_decl_assign; enum_type_t*enum_type; + decl_assignment_t*decl_assignment; + list*decl_assignments; + + struct_member_t*struct_member; + list*struct_members; + struct_type_t*struct_type; + verinum* number; verireal* realtime; @@ -436,7 +443,8 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number -%type unsigned_signed_opt signed_unsigned_opt reg_opt +%type unsigned_signed_opt signed_unsigned_opt +%type K_packed_opt K_reg_opt %type udp_reg_opt edge_operator automatic_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -491,6 +499,13 @@ static void current_task_set_statement(vector*s) %type expression_list_with_nuls expression_list_proper %type cont_assign cont_assign_list +%type variable_decl_assignment +%type list_of_variable_decl_assignments + +%type struct_union_member +%type struct_union_member_list +%type struct_data_type + %type range range_opt %type dimensions_opt dimensions %type net_type var_type net_type_opt @@ -695,6 +710,13 @@ block_item_decl if ($1) delete $1; } + /* struct data type declarations */ + + | attribute_list_opt struct_data_type register_variable_list ';' + { pform_set_struct_type($2, $3); + if ($1) delete $1; + } + /* real declarations are fairly simple as there is no range of signed flag in the declaration. Create the real as a NetNet::REG with real value. Note that real and realtime are interchangeable @@ -879,6 +901,63 @@ enum_name } ; +struct_data_type + : K_struct K_packed_opt '{' struct_union_member_list '}' + { struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + tmp->members .reset($4); + $$ = tmp; + } + | K_struct K_packed_opt '{' error '}' + { yyerror(@4, "error: Errors in struct/union member list."); + yyerrok; + struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + $$ = tmp; + } + ; + +struct_union_member_list + : struct_union_member_list struct_union_member + { list*tmp = $1; + tmp->push_back($2); + $$ = tmp; + } + | struct_union_member + { list*tmp = new list; + $$ = tmp; + } + ; + +struct_union_member + : attribute_list_opt K_bit range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt K_logic range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_LOGIC; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt atom2_type list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset( make_range_from_width($2) ); + tmp->names .reset($3); + $$ = tmp; + } + ; + case_item : expression_list_proper ':' statement_or_null { PCase::Item*tmp = new PCase::Item; @@ -3954,6 +4033,40 @@ register_variable_list } ; +/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ +list_of_variable_decl_assignments + : variable_decl_assignment + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | list_of_variable_decl_assignments ',' variable_decl_assignment + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +variable_decl_assignment + : IDENTIFIER dimensions_opt + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + if ($2) { + tmp->index = *$2; + delete $2; + } + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' expression + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->expr .reset($3); + delete[]$1; + $$ = tmp; + } + ; + real_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); @@ -4820,13 +4933,8 @@ task_item | task_port_item { $$ = $1; } ; -reg_opt - : K_reg { $$ = true; } - | { $$ = false; } - ; - task_port_item - : K_input reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + : K_input K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINPUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4834,7 +4942,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_output reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + | K_output K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4842,7 +4950,7 @@ task_port_item @1.text, @1.first_line); $$ = tmp; } - | K_inout reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + | K_inout K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' { svector*tmp = pform_make_task_ports(NetNet::PINOUT, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, @@ -4954,7 +5062,7 @@ task_item_list_opt task_port_decl - : K_input reg_opt unsigned_signed_opt range_opt IDENTIFIER + : K_input K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4968,7 +5076,7 @@ task_port_decl $$ = tmp; } - | K_output reg_opt unsigned_signed_opt range_opt IDENTIFIER + | K_output K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::POUTPUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -4981,7 +5089,7 @@ task_port_decl @1.text, @1.first_line); $$ = tmp; } - | K_inout reg_opt unsigned_signed_opt range_opt IDENTIFIER + | K_inout K_reg_opt unsigned_signed_opt range_opt IDENTIFIER { port_declaration_context.port_type = NetNet::PINOUT; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = $3; @@ -5504,3 +5612,6 @@ udp_primitive delete[]$6; } ; + +K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; +K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index 64405fc19..86a7f62a9 100644 --- a/pform.cc +++ b/pform.cc @@ -385,7 +385,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.push_back(enum_set); } -static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) +PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { diff --git a/pform.h b/pform.h index 030e37105..e781109eb 100644 --- a/pform.h +++ b/pform.h @@ -135,6 +135,8 @@ extern void pform_set_default_nettype(NetNet::Type net, */ extern PWire* pform_get_wire_in_scope(perm_string name); +extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type); + /* * The parser uses startmodule and endmodule together to build up a * module as it parses it. The startmodule tells the pform code that a @@ -280,6 +282,8 @@ extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); +extern void pform_set_struct_type(struct_type_t*struct_type, list*names); + /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are diff --git a/pform_struct_type.cc b/pform_struct_type.cc new file mode 100644 index 000000000..6f5fad8a8 --- /dev/null +++ b/pform_struct_type.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 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 "pform.h" +# include "ivl_assert.h" + +/* + * When we parse a packed struct, we can early on (right here) figure + * out the base type of the packed variable. Elaboration, later on, + * well figure out the rest. + */ +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) +{ + ivl_variable_type_t base_type = IVL_VT_BOOL; + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*tmp = *cur; + + if (tmp->type == IVL_VT_BOOL) { + continue; + } + + if (tmp->type == IVL_VT_LOGIC) { + base_type = IVL_VT_LOGIC; + continue; + } + } + + PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); + net->set_struct_type(struct_type); +} + +static void pform_set_struct_type(struct_type_t*struct_type, perm_string name) +{ + if (struct_type->packed_flag) { + pform_set_packed_struct(struct_type, name); + return; + } + + // For now, can only handle packed structs. + ivl_assert(*struct_type, 0); +} + +void pform_set_struct_type(struct_type_t*struct_type, list*names) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_struct_type(struct_type, *cur); + } +} diff --git a/pform_types.h b/pform_types.h index 609641e1f..3f6395fe8 100644 --- a/pform_types.h +++ b/pform_types.h @@ -57,6 +57,12 @@ struct name_component_t { std::listindex; }; +struct decl_assignment_t { + perm_string name; + std::listindex; + std::auto_ptr expr; +}; + /* * The enum_type_t holds the parsed declaration to represent an * enumeration. Since this is in the pform, it represents the type @@ -71,6 +77,16 @@ struct enum_type_t { LineInfo li; }; +struct struct_member_t : public LineInfo { + ivl_variable_type_t type; + std::auto_ptr< list > range; + std::auto_ptr< list > names; +}; + +struct struct_type_t : public LineInfo { + bool packed_flag; + std::auto_ptr< list > members; +}; /* * The pform_name_t is the general form for a hierarchical From 3a2866b57c267dba8971041e25ad54b3ac511f03 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 11 Dec 2011 10:28:04 -0800 Subject: [PATCH 35/88] Handle members of packed struct as implicit part selects. Packed struct members are synonymous with part selects, but in a much more convenient form, so get them to work that way. --- elab_expr.cc | 28 +++++++++++++-- elab_sig.cc | 97 ++++++++++++++++++++++++++++++++++++++++++---------- netlist.cc | 53 ++++++++++++++++++++++++---- netlist.h | 4 ++- netstruct.cc | 39 +++++++++++++++++++++ netstruct.h | 36 +++++++++++++++++++ parse.y | 1 + t-dll.cc | 2 +- 8 files changed, 230 insertions(+), 30 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index b3d3458d5..cd3555c3e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -29,6 +29,7 @@ # include "netenum.h" # include "discipline.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -1422,9 +1423,30 @@ static NetExpr* check_for_struct_members(const LineInfo*li, Design*des, NetScope*scope, NetNet*net, perm_string method_name) { - cerr << li->get_fileline() << ": sorry: structures not supported here." << endl; - des->errors += 1; - return 0; + netstruct_t*type = net->struct_type(); + ivl_assert(*li, type); + + if (! type->packed()) { + cerr << li->get_fileline() << ": sorry: unpacked structures not supported here. " + << "Method=" << method_name << endl; + des->errors += 1; + return 0; + } + + unsigned long off; + const netstruct_t::member_t*mem = type->packed_member(method_name, off); + if (mem == 0) + return 0; + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: Found struct member " <name + << " At offset " << off << endl; + } + + NetESignal*sig = new NetESignal(net); + NetEConst*base = make_const_val(off); + NetESelect*sel = new NetESelect(sig, base, mem->width()); + return sel; } NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, diff --git a/elab_sig.cc b/elab_sig.cc index cf435013e..f391a5d9a 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -781,6 +781,51 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } +static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, + struct_type_t*struct_type) +{ + netstruct_t*res = new netstruct_t; + + res->packed(struct_type->packed_flag); + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*curp = *cur; + long use_msb = 0; + long use_lsb = 0; + if (! curp->range->empty()) { + ivl_assert(*curp, curp->range->size() == 2); + PExpr*msb_pex = curp->range->front(); + PExpr*lsb_pex = curp->range->back(); + + NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); + ivl_assert(*curp, tmp); + bool rc = eval_as_long(use_msb, tmp); + ivl_assert(*curp, rc); + + tmp = elab_and_eval(des, scope, lsb_pex, -2, true); + ivl_assert(*curp, tmp); + rc = eval_as_long(use_lsb, tmp); + ivl_assert(*curp, rc); + } + + for (list::iterator name = curp->names->begin() + ; name != curp->names->end() ; ++ name) { + decl_assignment_t*namep = *name; + + netstruct_t::member_t memb; + memb.name = namep->name; + memb.type = curp->type; + memb.msb = use_msb; + memb.lsb = use_lsb; + res->append_member(memb); + } + } + + return res; +} + /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -1069,37 +1114,53 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } } - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create signal " << wtype; - if (!get_scalar()) { - cerr << " ["<packed()) + cerr << " " << use_type->packed_width() << " bit packed struct "; + else + cerr << " struct <> "; + cerr << name_; + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " " << name_; - if (array_dimensions > 0) { - cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + + sig = new NetNet(scope, name_, wtype, use_type); + + } else { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype; + if (!get_scalar()) { + cerr << " ["< 0) { + cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + } + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " in scope " << scope_path(scope) << endl; + + sig = array_dimensions > 0 + ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) + : new NetNet(scope, name_, wtype, msb, lsb); } - - NetNet*sig = array_dimensions > 0 - ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) - : new NetNet(scope, name_, wtype, msb, lsb); - // If this is an enumeration, then set the enumeration set for // the new signal. This turns it into an enumeration. if (enum_type_) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, ! enum_type_->names->empty()); list::const_iterator sample_name = enum_type_->names->begin(); netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); sig->set_enumeration(use_enum); } - if (struct_type_) { - netstruct_t*use_type = new netstruct_t; - sig->set_struct_type(use_type); - } - if (wtype == NetNet::WIRE) sig->devirtualize_pins(); ivl_variable_type_t use_data_type = data_type_; diff --git a/netlist.cc b/netlist.cc index 67899ba0a..eeaa48d41 100644 --- a/netlist.cc +++ b/netlist.cc @@ -27,6 +27,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "ivl_assert.h" @@ -579,6 +580,51 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, s->add_signal(this); } +static unsigned calculate_count(netstruct_t*type) +{ + long wid = type->packed_width(); + if (wid >= 0) + return wid; + else + return 1; +} + +/* + * When we create a netnet for a packed struct, create a single + * vector with the msb_/lsb_ chosen to name enough bits for the entire + * packed structure. + */ +NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), + discipline_(0), msb_(calculate_count(ty)-1), lsb_(0), + dimensions_(0), s0_(0), e0_(0), + eref_count_(0), lref_count_(0) +{ + Link::DIR dir = Link::PASSIVE; + + switch (t) { + case REG: + case IMPLICIT_REG: + dir = Link::OUTPUT; + break; + case SUPPLY0: + dir = Link::OUTPUT; + break; + case SUPPLY1: + dir = Link::OUTPUT; + break; + default: + break; + } + + initialize_dir_(dir); + + s->add_signal(this); +} + NetNet::~NetNet() { if (eref_count_ > 0) { @@ -704,13 +750,6 @@ netstruct_t*NetNet::struct_type(void) const return struct_type_; } -void NetNet::set_struct_type(netstruct_t*type) -{ - ivl_assert(*this, struct_type_ == 0); - ivl_assert(*this, enumeration_ == 0); - struct_type_ = type; -} - ivl_discipline_t NetNet::get_discipline() const { return discipline_; diff --git a/netlist.h b/netlist.h index 5e6d2bd2c..c2a429dd3 100644 --- a/netlist.h +++ b/netlist.h @@ -577,6 +577,9 @@ class NetNet : public NetObj { explicit NetNet(NetScope*s, perm_string n, Type t, long ms, long ls, long s0, long e0); + // This form builds a NetNet from its record definition. + explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); + virtual ~NetNet(); Type type() const; @@ -604,7 +607,6 @@ class NetNet : public NetObj { void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; - void set_struct_type(netstruct_t*type); netstruct_t*struct_type(void) const; /* Attach a discipline to the net. */ diff --git a/netstruct.cc b/netstruct.cc index 36ba3353a..63b673bae 100644 --- a/netstruct.cc +++ b/netstruct.cc @@ -18,6 +18,9 @@ */ # include "netstruct.h" +# include + +using namespace std; netstruct_t::netstruct_t() : packed_(false) @@ -27,3 +30,39 @@ netstruct_t::netstruct_t() netstruct_t::~netstruct_t() { } + +void netstruct_t::packed(bool flag) +{ + packed_ = flag; +} + +void netstruct_t::append_member(const netstruct_t::member_t&val) +{ + members_.push_back(val); +} + +const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const +{ + unsigned long count_off = 0; + for (size_t idx = members_.size() ; idx > 0 ; idx -= 1) { + if (members_[idx-1].name == name) { + off = count_off; + return &members_[idx-1]; + } + count_off += members_[idx-1].width(); + } + + return 0; +} + +long netstruct_t::packed_width(void) const +{ + if (! packed_) + return -1; + + long res = 0; + for (size_t idx = 0 ; idx < members_.size() ; idx += 1) + res += members_[idx].width(); + + return res; +} diff --git a/netstruct.h b/netstruct.h index 48bdd0cc0..6dc3a439f 100644 --- a/netstruct.h +++ b/netstruct.h @@ -20,15 +20,51 @@ */ # include "LineInfo.h" +# include +# include "ivl_target.h" class netstruct_t : public LineInfo { + public: + struct member_t { + perm_string name; + ivl_variable_type_t type; + long msb; + long lsb; + long width() const; + }; + public: netstruct_t(); ~netstruct_t(); + void packed(bool flag); + bool packed(void) const; + + void append_member(const member_t&); + + // Given the name of a member, return a pointer to the member + // description, and set the off value to be the offset into + // the packed value where the member begins. + const struct member_t* packed_member(perm_string name, unsigned long&off) const; + + // Return the width (in bits) of the packed record, or -1 if + // the record is not packed. + long packed_width() const; + private: bool packed_; + std::vectormembers_; }; +inline bool netstruct_t::packed(void) const { return packed_; } + +inline long netstruct_t::member_t::width() const +{ + if (msb >= lsb) + return msb - lsb + 1; + else + return lsb - msb + 1; +} + #endif diff --git a/parse.y b/parse.y index 9e0a65ef9..16d95dd7b 100644 --- a/parse.y +++ b/parse.y @@ -927,6 +927,7 @@ struct_union_member_list } | struct_union_member { list*tmp = new list; + tmp->push_back($1); $$ = tmp; } ; diff --git a/t-dll.cc b/t-dll.cc index 676ae5f27..c9b3f7024 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2503,7 +2503,7 @@ void dll_target::signal(const NetNet*net) obj->array_words = net->array_count(); obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; - assert(obj->array_words == net->pin_count()); + ivl_assert(*net, obj->array_words == net->pin_count()); if (debug_optimizer && obj->array_words > 1000) cerr << "debug: " "t-dll creating nexus array " << obj->array_words << " long" << endl; if (obj->array_words > 1 && net->pins_are_virtual()) { From e9e2fb33e9688e6f4bd6e620f26640459c8b7c4f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 18 Dec 2011 12:00:18 -0800 Subject: [PATCH 36/88] Handle nets that are packed structures. --- parse.y | 13 +++++++++++ pform.cc | 53 ++++++++++++++++++++++++++------------------ pform.h | 13 +++++++++++ pform_struct_type.cc | 48 ++++++++++++++++++++++++++++++++++----- 4 files changed, 99 insertions(+), 28 deletions(-) diff --git a/parse.y b/parse.y index 16d95dd7b..5521d3521 100644 --- a/parse.y +++ b/parse.y @@ -2775,6 +2775,19 @@ module_item } } + /* Allow struct nets. */ + + | attribute_list_opt net_type struct_data_type net_variable_list ';' + + { pform_makewire(@2, $3, NetNet::NOT_A_PORT, $4, $1); + delete $1; + } + + | attribute_list_opt net_type struct_data_type error ';' + + { yyerror(@5, "error: Errors in net variable list."); + } + /* This form doesn't have the range, but does have strengths. This gives strength to the assignment drivers. */ diff --git a/pform.cc b/pform.cc index 86a7f62a9..654129c3a 100644 --- a/pform.cc +++ b/pform.cc @@ -1898,6 +1898,36 @@ void pform_module_define_port(const struct vlltype&li, * function is called for every declaration. */ +static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name, + NetNet::Type type, NetNet::PortType ptype, + ivl_variable_type_t dtype) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur) { + // If this is not implicit ("implicit" meaning we don't + // know what the type is yet) then set the type now. + if (type != NetNet::IMPLICIT) { + bool rc = cur->set_wire_type(type); + if (rc == false) { + ostringstream msg; + msg << name << " " << type + << " definition conflicts with " << cur->get_wire_type() + << " definition at " << cur->get_fileline() + << "."; + VLerror(msg.str().c_str()); + } + FILE_NAME(cur, li.text, li.first_line); + } + return cur; + } + + cur = new PWire(name, type, ptype, dtype); + FILE_NAME(cur, li.text, li.first_line); + + pform_put_wire_in_scope(name, cur); + return cur; +} + /* * this is the basic form of pform_makewire. This takes a single simple * name, port type, net type, data type, and attributes, and creates @@ -1909,22 +1939,7 @@ void pform_makewire(const vlltype&li, perm_string name, ivl_variable_type_t dt, list*attr) { - PWire*cur = pform_get_wire_in_scope(name); - - // If this is not implicit ("implicit" meaning we don't know - // what the type is yet) then set the type now. - if (cur && type != NetNet::IMPLICIT) { - bool rc = cur->set_wire_type(type); - if (rc == false) { - ostringstream msg; - msg << name << " " << type - << " definition conflicts with " << cur->get_wire_type() - << " definition at " << cur->get_fileline() - << "."; - VLerror(msg.str().c_str()); - } - - } + PWire*cur = pform_get_or_make_wire(li, name, type, pt, dt); bool new_wire_flag = false; if (! cur) { @@ -1933,9 +1948,6 @@ void pform_makewire(const vlltype&li, perm_string name, FILE_NAME(cur, li.text, li.first_line); } - if (type != NetNet::IMPLICIT) - FILE_NAME(cur, li.text, li.first_line); - bool flag; switch (dt) { case IVL_VT_REAL: @@ -1960,9 +1972,6 @@ void pform_makewire(const vlltype&li, perm_string name, cur->attributes[attr_cur->name] = attr_cur->parm; } } - - if (new_wire_flag) - pform_put_wire_in_scope(name, cur); } /* diff --git a/pform.h b/pform.h index e781109eb..eccf55ae1 100644 --- a/pform.h +++ b/pform.h @@ -245,6 +245,12 @@ extern void pform_makewire(const struct vlltype&li, list*attr, PWSRType rt = SR_NET); +extern void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + list*names, + NetNet::PortType, + list*attr); + /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, list*range, @@ -255,6 +261,13 @@ extern void pform_makewire(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t); +/* This form handles nets declared as structures. (See pform_struct_type.cc) */ +extern void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType, + list*names, + list*attr); + extern void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr); diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 6f5fad8a8..1e07db36d 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -18,14 +18,10 @@ */ # include "pform.h" +# include "parse_misc.h" # include "ivl_assert.h" -/* - * When we parse a packed struct, we can early on (right here) figure - * out the base type of the packed variable. Elaboration, later on, - * well figure out the rest. - */ -static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) +static ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type) { ivl_variable_type_t base_type = IVL_VT_BOOL; @@ -44,6 +40,18 @@ static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) } } + return base_type; +} + +/* + * When we parse a packed struct, we can early on (right here) figure + * out the base type of the packed variable. Elaboration, later on, + * well figure out the rest. + */ +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) +{ + ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); net->set_struct_type(struct_type); } @@ -66,3 +74,31 @@ void pform_set_struct_type(struct_type_t*struct_type, list*names) pform_set_struct_type(struct_type, *cur); } } + +static void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType ptype, + perm_string name, + list*attr) +{ + ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + + PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type); + FILE_NAME(cur, li); + cur->set_struct_type(struct_type); +} + +void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType ptype, + list*names, + list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur ) { + perm_string txt = *cur; + pform_makewire(li, struct_type, ptype, txt, attr); + } + + delete names; +} From d2c3ff79992133890fc498c4643dccdb52934516 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 31 Dec 2011 17:27:30 -0800 Subject: [PATCH 37/88] Handle struct members in continuous assign l-values. --- elab_net.cc | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/elab_net.cc b/elab_net.cc index 2a7d75400..43e3c11f2 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -22,6 +22,7 @@ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "compiler.h" # include @@ -405,6 +406,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, NetNet* sig = 0; const NetExpr*par = 0; NetEvent* eve = 0; + perm_string method_name; symbol_search(this, des, scope, path_, sig, par, eve); @@ -416,6 +418,17 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; } + /* If the signal is not found, check to see if this is a + member of a struct. Take the name of the form "a.b.member", + remove the member and store it into method_name, and retry + the search with "a.b". */ + if (sig == 0 && path_.size() >= 2) { + pform_name_t use_path = path_; + method_name = peek_tail_name(use_path); + use_path.pop_back(); + symbol_search(this, des, scope, use_path, sig, par, eve); + } + if (sig == 0) { cerr << get_fileline() << ": error: Net " << path_ << " is not defined in this context." << endl; @@ -460,7 +473,26 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, const name_component_t&name_tail = path_.back(); - if (sig->array_dimensions() > 0) { + netstruct_t*struct_type = 0; + if ((struct_type = sig->struct_type()) && !method_name.nil()) { + + // Detect the variable is a structure and there was a + // methos name detected. + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Signal " << sig->name() << " is a structure, " + << "try to match member " << method_name << endl; + + unsigned long member_off = 0; + const struct netstruct_t::member_t*member = struct_type->packed_member(method_name, member_off); + ivl_assert(*this, member); + + // Rewrite a member select of a packed structure as a + // part select of the base variable. + lidx = member_off; + midx = lidx + member->width() - 1; + + } else if (sig->array_dimensions() > 0) { if (name_tail.index.empty()) { cerr << get_fileline() << ": error: array " << sig->name() From 124314576dfac46784f514771329ee718bf90af6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 3 Jan 2012 17:38:08 -0800 Subject: [PATCH 38/88] Packed struct members in behavioral assign l-values. --- PExpr.h | 3 +++ elab_lval.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ elab_net.cc | 6 ++++++ 3 files changed, 66 insertions(+) diff --git a/PExpr.h b/PExpr.h index e087cb592..17ca6f989 100644 --- a/PExpr.h +++ b/PExpr.h @@ -349,6 +349,9 @@ class PEIdent : public PExpr { bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const; bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, index_component_t::ctype_t) const; + bool elaborate_lval_net_packed_member_(Design*, NetScope*, + NetAssign_*, + const perm_string&) const; private: NetExpr*elaborate_expr_param_(Design*des, diff --git a/elab_lval.cc b/elab_lval.cc index 1997f89f3..ee2502c68 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -22,6 +22,7 @@ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "compiler.h" # include # include @@ -152,8 +153,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, NetNet* reg = 0; const NetExpr*par = 0; NetEvent* eve = 0; + perm_string method_name; symbol_search(this, des, scope, path_, reg, par, eve); + + /* If the signal is not found, check to see if this is a + member of a struct. Take the name of the form "a.b.member", + remove the member and store it into method_name, and retry + the search with "a.b". */ + if (reg == 0 && path_.size() >= 2) { + pform_name_t use_path = path_; + method_name = peek_tail_name(use_path); + use_path.pop_back(); + symbol_search(this, des, scope, use_path, reg, par, eve); + + if (reg && reg->struct_type() == 0) { + method_name = perm_string(); + reg = 0; + } + } + if (reg == 0) { cerr << get_fileline() << ": error: Could not find variable ``" << path_ << "'' in ``" << scope_path(scope) << @@ -193,6 +212,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return 0; } + if (reg->struct_type() && !method_name.nil()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_packed_member_(des, scope, lv, method_name); + return lv; + } + if (reg->array_dimensions() > 0) return elaborate_lval_net_word_(des, scope, reg); @@ -533,6 +558,38 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } +bool PEIdent::elaborate_lval_net_packed_member_(Design*des, + NetScope*scope, + NetAssign_*lv, + const perm_string&member_name) const +{ + NetNet*reg = lv->sig(); + ivl_assert(*this, reg); + + netstruct_t*struct_type = reg->struct_type(); + ivl_assert(*this, struct_type); + + if (! struct_type->packed()) { + cerr << get_fileline() << ": sorry: Only packed structures " + << "are supported in l-value." << endl; + des->errors += 1; + return false; + } + + unsigned long off; + const netstruct_t::member_t* member = struct_type->packed_member(member_name, off); + + if (member == 0) { + cerr << get_fileline() << ": error: Member " << member_name + << " is not a member of variable " << reg->name() << endl; + des->errors += 1; + return false; + } + + lv->set_part(new NetEConst(verinum(off)), member->width()); + return true; +} + NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const { cerr << get_fileline() << ": error: Constant values not allowed " diff --git a/elab_net.cc b/elab_net.cc index 43e3c11f2..cc992524a 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -427,6 +427,12 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, method_name = peek_tail_name(use_path); use_path.pop_back(); symbol_search(this, des, scope, use_path, sig, par, eve); + + // Whoops, not a struct signal, so give up on this avenue. + if (sig && sig->struct_type() == 0) { + method_name = perm_string(); + sig = 0; + } } if (sig == 0) { From e14628193aaf460f746f9216dafe6b8a9654423c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 7 Jan 2012 15:37:30 -0800 Subject: [PATCH 39/88] Parse simple typedefs Parse typedefs with structs and enums, but give a sorry message, because they are not yet supported. Rearrange some of the parse rules for variables in order to increase comonality with the typedef rules. --- parse.y | 38 ++++++++++++++++++++++++++++---------- pform.cc | 19 +++++++++++++++++++ pform.h | 2 ++ pform_types.cc | 4 ++++ pform_types.h | 13 +++++++++++-- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/parse.y b/parse.y index 5521d3521..f337e0670 100644 --- a/parse.y +++ b/parse.y @@ -337,6 +337,8 @@ static void current_task_set_statement(vector*s) list*struct_members; struct_type_t*struct_type; + data_type_t*data_type; + verinum* number; verireal* realtime; @@ -502,6 +504,7 @@ static void current_task_set_statement(vector*s) %type variable_decl_assignment %type list_of_variable_decl_assignments +%type data_type %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -703,17 +706,10 @@ block_item_decl if ($1) delete $1; } - /* Enum data types are possible here. */ + /* variable declarations */ - | attribute_list_opt enum_data_type register_variable_list ';' - { pform_set_enum(@2, $2, $3); - if ($1) delete $1; - } - - /* struct data type declarations */ - - | attribute_list_opt struct_data_type register_variable_list ';' - { pform_set_struct_type($2, $3); + | attribute_list_opt data_type register_variable_list ';' + { pform_set_data_type(@2, $2, $3); if ($1) delete $1; } @@ -734,6 +730,10 @@ block_item_decl | K_parameter parameter_assign_decl ';' | K_localparam localparam_assign_decl ';' + /* Blocks can have type declarations. */ + + | type_declaration + /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ @@ -779,6 +779,18 @@ block_item_decls_opt | ; +data_type + : struct_data_type + { $$ = $1; } + | enum_data_type + { $$ = $1; } + ; + +type_declaration + : K_typedef data_type IDENTIFIER ';' + { yyerror(@1, "sorry: typedef not yet supported."); } + ; + /* The structure for an enumeration data type is the keyword "enum", followed by the enumeration values in curly braces. Also allow for an optional base type. The default base type is "int", but it @@ -787,6 +799,7 @@ block_item_decls_opt enum_data_type : K_enum '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($3); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = true; @@ -795,6 +808,7 @@ enum_data_type } | K_enum atom2_type signed_unsigned_opt '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($5); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; @@ -803,6 +817,7 @@ enum_data_type } | K_enum K_integer signed_unsigned_opt '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($5); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; @@ -811,6 +826,7 @@ enum_data_type } | K_enum K_logic unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; @@ -819,6 +835,7 @@ enum_data_type } | K_enum K_reg unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; @@ -827,6 +844,7 @@ enum_data_type } | K_enum K_bit unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; diff --git a/pform.cc b/pform.cc index 654129c3a..a056b5f82 100644 --- a/pform.cc +++ b/pform.cc @@ -2493,6 +2493,25 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list delete names; } +/* + * This function detects the derived class for the given type and + * dispatches the type to the proper subtype function. + */ +void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names) +{ + if (struct_type_t*struct_type = dynamic_cast (data_type)) { + pform_set_struct_type(struct_type, names); + return; + } + + if (enum_type_t*enum_type = dynamic_cast (data_type)) { + pform_set_enum(li, enum_type, names); + return; + } + + assert(0); +} + static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, perm_string name) { diff --git a/pform.h b/pform.h index eccf55ae1..56f0a4aac 100644 --- a/pform.h +++ b/pform.h @@ -293,6 +293,8 @@ extern void pform_set_reg_time(list*names); extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); +extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names); + extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names); extern void pform_set_struct_type(struct_type_t*struct_type, list*names); diff --git a/pform_types.cc b/pform_types.cc index 1f5787f27..9a85b5b7e 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -19,3 +19,7 @@ # include "pform_types.h" + +data_type_t::~data_type_t() +{ +} diff --git a/pform_types.h b/pform_types.h index 3f6395fe8..db0739552 100644 --- a/pform_types.h +++ b/pform_types.h @@ -63,13 +63,22 @@ struct decl_assignment_t { std::auto_ptr expr; }; +/* + * This is the base class for data types that are matched by the + * "data_type" rule in the parse rule. We make the type virtual so + * that dynamic types will work. + */ +struct data_type_t : public LineInfo { + virtual ~data_type_t() = 0; +}; + /* * The enum_type_t holds the parsed declaration to represent an * enumeration. Since this is in the pform, it represents the type * before elaboration to the range, for example, man not be complete * until it is elaborated in a scope. */ -struct enum_type_t { +struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; std::auto_ptr< list > range; @@ -83,7 +92,7 @@ struct struct_member_t : public LineInfo { std::auto_ptr< list > names; }; -struct struct_type_t : public LineInfo { +struct struct_type_t : public data_type_t { bool packed_flag; std::auto_ptr< list > members; }; From 42b3e6f26844a0d3c9167374a2d5d48f16e90d23 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 8 Jan 2012 17:51:18 -0800 Subject: [PATCH 40/88] Implement simple typedefs, and parse type identifiers. This gets me to the point where the parser stashes a defined type, and the lexical analyzer uses the type names to differentiate IDENTIFIER and TYPE_IDENTIFIER. --- PScope.h | 5 +++++ lexor.lex | 7 +++++++ parse.y | 16 ++++++++++++---- parse_misc.h | 8 ++++++++ pform.cc | 22 ++++++++++++++++++++++ pform.h | 2 ++ pform_dump.cc | 16 ++++++++++++++++ pform_types.h | 3 +++ 8 files changed, 75 insertions(+), 4 deletions(-) diff --git a/PScope.h b/PScope.h index a6c11466c..d2b0feb53 100644 --- a/PScope.h +++ b/PScope.h @@ -83,6 +83,9 @@ class LexicalScope { mapparameters; maplocalparams; + // Defined types in the scope. + maptypedefs; + // Named events in the scope. mapevents; @@ -105,6 +108,8 @@ class LexicalScope { LexicalScope* parent_scope() const { return parent_; } protected: + void dump_typedefs_(ostream&out, unsigned indent) const; + void dump_parameters_(ostream&out, unsigned indent) const; void dump_localparams_(ostream&out, unsigned indent) const; diff --git a/lexor.lex b/lexor.lex index a197990fb..a6a683607 100644 --- a/lexor.lex +++ b/lexor.lex @@ -308,6 +308,13 @@ TU [munpf] } } + /* If this identifer names a previously declared type, then + return this as a TYPE_IDENTIFIER instead. */ + if (rc == IDENTIFIER && gn_system_verilog()) { + if (pform_test_type_identifier(yylval.text)) + rc = TYPE_IDENTIFIER; + } + return rc; } diff --git a/parse.y b/parse.y index f337e0670..08d9ba3cd 100644 --- a/parse.y +++ b/parse.y @@ -347,7 +347,7 @@ static void current_task_set_statement(vector*s) list *dimensions; }; -%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token IDENTIFIER SYSTEM_IDENTIFIER TYPE_IDENTIFIER STRING TIME_LITERAL %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER %token BASED_NUMBER DEC_NUMBER @@ -706,10 +706,11 @@ block_item_decl if ($1) delete $1; } - /* variable declarations */ + /* variable declarations. Note that data_type can be 0 if we are + recovering from an error. */ | attribute_list_opt data_type register_variable_list ';' - { pform_set_data_type(@2, $2, $3); + { if ($2) pform_set_data_type(@2, $2, $3); if ($1) delete $1; } @@ -784,11 +785,18 @@ data_type { $$ = $1; } | enum_data_type { $$ = $1; } + | TYPE_IDENTIFIER + { yyerror(@1, "sorry: Named types not supported here"); + $$ = 0; + } ; type_declaration : K_typedef data_type IDENTIFIER ';' - { yyerror(@1, "sorry: typedef not yet supported."); } + { perm_string name = lex_strings.make($3); + pform_set_typedef(name, $2); + delete[]$3; + } ; /* The structure for an enumeration data type is the keyword "enum", diff --git a/parse_misc.h b/parse_misc.h index f3b5dfc9b..0217a0cda 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -77,6 +77,14 @@ extern UCDriveType uc_drive; extern bool have_timeunit_decl; extern bool have_timeprec_decl; +/* + * Test if this identifier is a type identifier in the current + * context. The pform code needs to help the lexor here because the + * parser detects typedefs and marks the typedef'ed identifiers as + * type names. + */ +extern bool pform_test_type_identifier(const char*txt); + /* * Export these functions because we have to generate PENumber class * in pform.cc for user defparam definition from command file. diff --git a/pform.cc b/pform.cc index a056b5f82..97e7c8303 100644 --- a/pform.cc +++ b/pform.cc @@ -401,6 +401,28 @@ PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetN return cur; } +void pform_set_typedef(perm_string name, data_type_t*data_type) +{ + data_type_t*&ref = lexical_scope->typedefs[name]; + ivl_assert(*data_type, ref == 0); + ref = data_type; +} + +bool pform_test_type_identifier(const char*txt) +{ + // If there is no lexical_scope yet, then there is NO WAY the + // identifier can be a type_identifier. + if (lexical_scope == 0) + return false; + + perm_string name = lex_strings.make(txt); + map::iterator cur = lexical_scope->typedefs.find(name); + if (cur != lexical_scope->typedefs.end()) + return true; + else + return false; +} + static void pform_put_behavior_in_scope(PProcess*pp) { lexical_scope->behaviors.push_back(pp); diff --git a/pform.h b/pform.h index 56f0a4aac..dbdf85942 100644 --- a/pform.h +++ b/pform.h @@ -224,6 +224,8 @@ extern void pform_endgenerate(); */ extern PGenerate* pform_parent_generate(void); +extern void pform_set_typedef(perm_string name, data_type_t*data_type); + /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. diff --git a/pform_dump.cc b/pform_dump.cc index cd8829ccf..88fa71520 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -141,6 +141,11 @@ std::ostream& operator << (std::ostream&out, ivl_dis_domain_t dom) return out; } +void data_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << typeid(*this).name() << endl; +} + static void dump_attributes_map(ostream&out, const map&attributes, int ind) @@ -1050,6 +1055,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const } } +void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const +{ + typedef map::const_iterator iter_t; + for (iter_t cur = typedefs.begin() ; cur != typedefs.end() ; ++ cur) { + out << setw(indent) << "" << "typedef of " << cur->first << ":" << endl; + cur->second->pform_dump(out, indent+4); + } +} + void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const { typedef map::const_iterator parm_iter_t; @@ -1189,6 +1203,8 @@ void Module::dump(ostream&out) const out << ")" << endl; } + dump_typedefs_(out, 4); + dump_parameters_(out, 4); dump_localparams_(out, 4); diff --git a/pform_types.h b/pform_types.h index db0739552..354353dd4 100644 --- a/pform_types.h +++ b/pform_types.h @@ -70,6 +70,9 @@ struct decl_assignment_t { */ struct data_type_t : public LineInfo { virtual ~data_type_t() = 0; + + // This method is used by the pform dumper to diagnostic dump. + virtual void pform_dump(std::ostream&out, unsigned indent) const; }; /* From 764b38bb3b953588a020a516a1b52b3a25ed9b35 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 15 Jan 2012 17:29:18 -0800 Subject: [PATCH 41/88] Use user defined types in the syntax. Given that the syntax is already parsed and elaborated, it is a simple matter to bind that typedef'ed type to the instances that use it. --- lexor.lex | 6 +++++- parse.y | 7 +++---- parse_misc.h | 2 +- pform.cc | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lexor.lex b/lexor.lex index a6a683607..259a8fcd1 100644 --- a/lexor.lex +++ b/lexor.lex @@ -303,6 +303,7 @@ TU [munpf] perm_string tmp = lex_strings.make(yylval.text); map::iterator cur = disciplines.find(tmp); if (cur != disciplines.end()) { + delete[]yylval.text; yylval.discipline = (*cur).second; rc = DISCIPLINE_IDENTIFIER; } @@ -311,8 +312,11 @@ TU [munpf] /* If this identifer names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { - if (pform_test_type_identifier(yylval.text)) + if (data_type_t*type = pform_test_type_identifier(yylval.text)) { + delete[]yylval.text; + yylval.data_type = type; rc = TYPE_IDENTIFIER; + } } return rc; diff --git a/parse.y b/parse.y index 08d9ba3cd..dbb46dd31 100644 --- a/parse.y +++ b/parse.y @@ -347,7 +347,8 @@ static void current_task_set_statement(vector*s) list *dimensions; }; -%token IDENTIFIER SYSTEM_IDENTIFIER TYPE_IDENTIFIER STRING TIME_LITERAL +%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token TYPE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER %token BASED_NUMBER DEC_NUMBER @@ -786,9 +787,7 @@ data_type | enum_data_type { $$ = $1; } | TYPE_IDENTIFIER - { yyerror(@1, "sorry: Named types not supported here"); - $$ = 0; - } + { $$ = $1; } ; type_declaration diff --git a/parse_misc.h b/parse_misc.h index 0217a0cda..e9d642dfc 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -83,7 +83,7 @@ extern bool have_timeprec_decl; * parser detects typedefs and marks the typedef'ed identifiers as * type names. */ -extern bool pform_test_type_identifier(const char*txt); +extern data_type_t* pform_test_type_identifier(const char*txt); /* * Export these functions because we have to generate PENumber class diff --git a/pform.cc b/pform.cc index 97e7c8303..8ff97b60a 100644 --- a/pform.cc +++ b/pform.cc @@ -408,7 +408,7 @@ void pform_set_typedef(perm_string name, data_type_t*data_type) ref = data_type; } -bool pform_test_type_identifier(const char*txt) +data_type_t* pform_test_type_identifier(const char*txt) { // If there is no lexical_scope yet, then there is NO WAY the // identifier can be a type_identifier. @@ -418,9 +418,9 @@ bool pform_test_type_identifier(const char*txt) perm_string name = lex_strings.make(txt); map::iterator cur = lexical_scope->typedefs.find(name); if (cur != lexical_scope->typedefs.end()) - return true; + return cur->second; else - return false; + return 0; } static void pform_put_behavior_in_scope(PProcess*pp) From 5d35ad8a0d2908c79133a2de3c2ab43dd47653c5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 28 Jan 2012 10:20:09 -0800 Subject: [PATCH 42/88] Support uwire resolved writes to non-overlapping parts The individual bits of an unresolved wire may be assigned in different continuous assignments without generating an error. --- elab_net.cc | 15 ++++++++------- elab_sig.cc | 2 +- netlist.cc | 20 ++++++++++++++++++++ netlist.h | 5 +++++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index cc992524a..6f1aca6a7 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -453,13 +453,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, sig->type(NetNet::UNRESOLVED_WIRE); } - if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked()) { - cerr << get_fileline() << ": error: Unresolved net/uwire " - << sig->name() << " cannot have multiple drivers." << endl; - des->errors += 1; - return 0; - } - /* Don't allow registers as assign l-values. */ if (sig->type() == NetNet::REG) { cerr << get_fileline() << ": error: reg " << sig->name() @@ -591,6 +584,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned subnet_wid = midx-lidx+1; + /* Check if the l-value bits are double-driven. */ + if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) { + cerr << get_fileline() << ": error: Unresolved net/uwire " + << sig->name() << " cannot have multiple drivers." << endl; + des->errors += 1; + return 0; + } + if (sig->pin_count() > 1) { if (widx < 0 || widx >= (long) sig->pin_count()) { cerr << get_fileline() << ": warning: ignoring out of " diff --git a/elab_sig.cc b/elab_sig.cc index f391a5d9a..1c749413a 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -794,7 +794,7 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, struct_member_t*curp = *cur; long use_msb = 0; long use_lsb = 0; - if (! curp->range->empty()) { + if (curp->range.get() && ! curp->range->empty()) { ivl_assert(*curp, curp->range->size() == 2); PExpr*msb_pex = curp->range->front(); PExpr*lsb_pex = curp->range->back(); diff --git a/netlist.cc b/netlist.cc index eeaa48d41..ed07fda91 100644 --- a/netlist.cc +++ b/netlist.cc @@ -856,6 +856,26 @@ unsigned NetNet::peek_eref() const return eref_count_; } +/* + * Test each of the bits in the range, and set them. If any bits are + * already set then return true. + */ +bool NetNet::test_part_lref(unsigned msb, unsigned lsb) +{ + if (lref_mask_.size() == 0) + lref_mask_.resize(vector_width()); + + bool rc = false; + for (unsigned idx = lsb ; idx <= msb ; idx += 1) { + if (lref_mask_[idx]) + rc = true; + else + lref_mask_[idx] = true; + } + + return rc; +} + void NetNet::incr_lref() { lref_count_ += 1; diff --git a/netlist.h b/netlist.h index c2a429dd3..cae9e3a1e 100644 --- a/netlist.h +++ b/netlist.h @@ -660,6 +660,7 @@ class NetNet : public NetObj { void incr_lref(); void decr_lref(); unsigned peek_lref() const { return lref_count_; } + bool test_part_lref(unsigned msb, unsigned lsb); unsigned get_refs() const; @@ -691,6 +692,10 @@ class NetNet : public NetObj { unsigned eref_count_; unsigned lref_count_; + // When the signal is an unresolved wire, we need more detail + // which bits are assigned. This mask is true for each bit + // that is known to be driven. + std::vector lref_mask_; vector delay_paths_; }; From 950e7a632c09c3451682d6c184b58991f3d72a31 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 4 Feb 2012 16:19:27 -0800 Subject: [PATCH 43/88] Parse multi-dimension packed arrays to pform. --- PExpr.cc | 4 +-- PWire.cc | 69 +++++++++++++++++++++++++++++++++---------- PWire.h | 24 ++++++++++----- elab_sig.cc | 68 +++++++++++++++++++++++------------------- parse.y | 15 +++++++--- pform.cc | 82 ++++++++++++++++++++++++++++++++------------------- pform.h | 5 ++-- pform_dump.cc | 16 ++++++---- 8 files changed, 185 insertions(+), 98 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index b301cb3cb..7cbc649a4 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams + * Copyright (c) 1998-2012 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -346,7 +346,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC); net->set_file(get_file()); net->set_lineno(get_lineno()); - net->set_range(0, 0, SR_NET, true); + net->set_range_scalar(SR_NET); scope->wires[name] = net; if (warn_implicit) { cerr << get_fileline() << ": warning: implicit " diff --git a/PWire.cc b/PWire.cc index a5d5407a3..e5402a6cc 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,8 +28,7 @@ PWire::PWire(perm_string n, ivl_variable_type_t dt) : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), - port_msb_(0), port_lsb_(0), port_set_(false), - net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), + port_set_(false), net_set_(false), is_scalar_(false), error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), discipline_(0) { @@ -149,8 +148,9 @@ bool PWire::get_scalar() const return is_scalar_; } -void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) +void PWire::set_range_scalar(PWSRType type) { + is_scalar_ = true; switch (type) { case SR_PORT: if (port_set_) { @@ -158,10 +158,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared a port." << endl; error_cnt_ += 1; } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - is_scalar_ = is_scalar; } return; @@ -171,10 +168,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared." << endl; error_cnt_ += 1; } else { - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; } return; @@ -191,13 +185,58 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) error_cnt_ += 1; } } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; + } + return; + } +} + +void PWire::set_range(const list&rlist, PWSRType type) +{ + switch (type) { + case SR_PORT: + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } else { + port_ = rlist; + port_set_ = true; + is_scalar_ = false; + } + return; + + case SR_NET: + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } else { + net_ = rlist; + net_set_ = true; + is_scalar_ = false; + } + return; + + case SR_BOTH: + if (port_set_ || net_set_) { + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } + } else { + port_ = rlist; + port_set_ = true; + net_ = rlist; + net_set_ = true; + is_scalar_ = false; } return; } diff --git a/PWire.h b/PWire.h index 96f1b4964..5b6606fae 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef __PWire_H #define __PWire_H /* - * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009,2012 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 @@ -21,8 +21,8 @@ # include "netlist.h" # include "LineInfo.h" +# include # include -# include "svector.h" # include "StringHeap.h" #ifdef HAVE_IOSFWD @@ -51,6 +51,11 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH}; * the wire name. */ class PWire : public LineInfo { + public: + struct range_t { + PExpr*msb; + PExpr*lsb; + }; public: PWire(perm_string name, @@ -75,7 +80,8 @@ class PWire : public LineInfo { bool set_data_type(ivl_variable_type_t dt); ivl_variable_type_t get_data_type() const; - void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar); + void set_range_scalar(PWSRType type); + void set_range(const std::list&ranges, PWSRType type); void set_memory_idx(PExpr*ldx, PExpr*rdx); @@ -101,12 +107,14 @@ class PWire : public LineInfo { bool isint_; // original type of integer // These members hold expressions for the bit width of the - // wire. If they do not exist, the wire is 1 bit wide. - PExpr*port_msb_; - PExpr*port_lsb_; + // wire. If they do not exist, the wire is 1 bit wide. If they + // do exist, they represent the packed dimensions of the + // bit. The first item in the list is the first range, and so + // on. For example "reg [3:0][7:0] ..." will contains the + // range_t object for [3:0] first and [7:0] last. + std::listport_; bool port_set_; - PExpr*net_msb_; - PExpr*net_lsb_; + std::listnet_; bool net_set_; bool is_scalar_; unsigned error_cnt_; diff --git a/elab_sig.cc b/elab_sig.cc index 1c749413a..06854a52b 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -890,29 +890,31 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; bool bad_lsb = false, bad_msb = false; /* If they exist get the port definition MSB and LSB */ - if (port_set_ && port_msb_ != 0) { - NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true); + if (port_set_ && !port_.empty()) { + assert(port_.size() == 1); + PWire::range_t rng = port_.front(); + NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); if (! eval_as_long(pmsb, texpr)) { - cerr << port_msb_->get_fileline() << ": error: " + cerr << rng.msb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << port_msb_->get_fileline() << " : " + cerr << rng.msb->get_fileline() << " : " "This MSB expression violates the rule: " - << *port_msb_ << endl; + << *rng.msb << endl; des->errors += 1; bad_msb = true; } delete texpr; - texpr = elab_and_eval(des, scope, port_lsb_, -1, true); + texpr = elab_and_eval(des, scope, rng.lsb, -1, true); if (! eval_as_long(plsb, texpr)) { - cerr << port_lsb_->get_fileline() << ": error: " + cerr << rng.lsb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << port_lsb_->get_fileline() << " : " + cerr << rng.lsb->get_fileline() << " : " "This LSB expression violates the rule: " - << *port_lsb_ << endl; + << *rng.lsb << endl; des->errors += 1; bad_lsb = true; } @@ -923,49 +925,53 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; } - if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); - if (port_msb_ == 0) assert(port_lsb_ == 0); - if (port_lsb_ == 0) assert(port_msb_ == 0); + if (!port_set_) assert(port_.empty()); + + if (net_.size() > 1) { + cerr << net_.back().msb->get_fileline() << ": sorry: " + << "Multi-dimension packed arrays not supported." + << endl; + des->errors += 1; + } /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { - NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true); + if (net_set_ && !net_.empty() && !bad_msb && !bad_lsb) { + PWire::range_t rng = net_.front(); + NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); if (! eval_as_long(nmsb, texpr)) { - cerr << net_msb_->get_fileline() << ": error: " + cerr << rng.msb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << net_msb_->get_fileline() << " : " + cerr << rng.msb->get_fileline() << " : " "This MSB expression violates the rule: " - << *net_msb_ << endl; + << *rng.msb << endl; des->errors += 1; bad_msb = true; } delete texpr; - texpr = elab_and_eval(des, scope, net_lsb_, -1, true); + texpr = elab_and_eval(des, scope, rng.lsb, -1, true); if (! eval_as_long(nlsb, texpr)) { - cerr << net_lsb_->get_fileline() << ": error: " + cerr << rng.lsb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << net_lsb_->get_fileline() << " : " + cerr << rng.lsb->get_fileline() << " : " "This LSB expression violates the rule: " - << *net_lsb_ << endl; + << *rng.lsb << endl; des->errors += 1; bad_lsb = true; } delete texpr; } - if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0); - if (net_msb_ == 0) assert(net_lsb_ == 0); - if (net_lsb_ == 0) assert(net_msb_ == 0); + if (!net_set_) assert(net_.empty()); /* We have a port size error */ if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { /* Scalar port with a vector net/etc. definition */ - if (port_msb_ == 0) { + if (port_.empty()) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ @@ -982,8 +988,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } /* Vectored port with a scalar net/etc. definition */ - if (net_msb_ == 0) { - cerr << port_msb_->get_fileline() + if (net_.empty()) { + cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a scalar net declaration at " @@ -993,12 +999,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } /* Both vectored, but they have different ranges. */ - if (port_msb_ != 0 && net_msb_ != 0) { - cerr << port_msb_->get_fileline() + if (!port_.empty() && !net_.empty()) { + cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a net declaration [" << nmsb << ":" - << nlsb << "] at " << net_msb_->get_fileline() + << nlsb << "] at " << net_.front().msb->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; diff --git a/parse.y b/parse.y index dbb46dd31..149f19af7 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -3931,12 +3931,19 @@ range tmp->push_back($4); $$ = tmp; } + | range '[' expression ':' expression ']' + { list*tmp = $1; + tmp->push_back($3); + tmp->push_back($5); + $$ = tmp; + } ; range_opt - : range - | { $$ = 0; } - ; + : range + | { $$ = 0; } + ; + dimensions_opt : { $$ = 0; } | dimensions { $$ = $1; } diff --git a/pform.cc b/pform.cc index 8ff97b60a..9716ffdd9 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -1480,6 +1480,20 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } +static void ranges_from_list(list&rlist, const list*range) +{ + // There must be an even number of expressions in the + // range. The parser will assure that for us. + assert(range->size()%2 == 0); + list::const_iterator rcur = range->begin(); + while (rcur != range->end()) { + PWire::range_t rng; + rng.msb = *rcur; ++rcur; + rng.lsb = *rcur; ++rcur; + rlist.push_back(rng); + } +} + /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, @@ -1500,11 +1514,12 @@ static void pform_set_net_range(perm_string name, if (range == 0) { /* This is the special case that we really mean a scalar. Set a fake range. */ - cur->set_range(0, 0, rt, true); + cur->set_range_scalar(rt); } else { - assert(range->size() == 2); - cur->set_range(range->front(), range->back(), rt, false); + list rlist; + ranges_from_list(rlist, range); + cur->set_range(rlist, rt); } cur->set_signed(signed_flag); @@ -1515,15 +1530,14 @@ static void pform_set_net_range(perm_string name, void pform_set_net_range(list*names, list*range, bool signed_flag, - ivl_variable_type_t dt, - PWSRType rt) + ivl_variable_type_t dt) { - assert((range == 0) || (range->size() == 2)); + assert((range == 0) || (range->size()%2 == 0)); for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_net_range(txt, range, signed_flag, dt, rt); + pform_set_net_range(txt, range, signed_flag, dt, SR_NET); } delete names; @@ -1884,17 +1898,12 @@ void pform_module_define_port(const struct vlltype&li, cur->set_signed(signed_flag); if (range == 0) { - cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : - SR_BOTH, - true); + cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - cur->set_range(range->front(), range->back(), - (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, - false); + list rlist; + ranges_from_list(rlist, range); + cur->set_range(rlist, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } pform_bind_attributes(cur->attributes, attr); @@ -1981,7 +1990,7 @@ void pform_makewire(const vlltype&li, perm_string name, << " to " << dt << "." << endl; } ivl_assert(*cur, flag); - cur->set_range(0, 0, SR_NET, true); + cur->set_range_scalar(SR_NET); cur->set_signed(true); break; default: @@ -2168,8 +2177,9 @@ svector*pform_make_task_ports(NetNet::PortType pt, /* If there is a range involved, it needs to be set. */ if (range) { - assert(range->size() == 2); - curw->set_range(range->front(), range->back(), SR_PORT, false); + list rlist; + ranges_from_list(rlist, range); + curw->set_range(rlist, SR_PORT); } svector*tmp = new svector(*res, curw); @@ -2458,9 +2468,12 @@ static void pform_set_reg_integer(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + PWire::range_t rng; + rng.msb = new PENumber(new verinum(integer_width-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); cur->set_signed(true); } @@ -2479,9 +2492,12 @@ static void pform_set_reg_time(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + PWire::range_t rng; + rng.msb = new PENumber(new verinum(TIME_WIDTH-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_reg_time(list*names) @@ -2500,9 +2516,13 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin assert(cur); cur->set_signed(signed_flag); - cur->set_range(new PENumber(new verinum(width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + + PWire::range_t rng; + rng.msb = new PENumber(new verinum(width-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names) @@ -2545,7 +2565,9 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, assert(enum_type->range.get() != 0); assert(enum_type->range->size() == 2); - cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false); + listrlist; + ranges_from_list(rlist, enum_type->range.get()); + cur->set_range(rlist, SR_NET); cur->set_enumeration(enum_type); } diff --git a/pform.h b/pform.h index dbdf85942..b32ccce70 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef __pform_H #define __pform_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -287,8 +287,7 @@ extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, extern void pform_set_net_range(list*names, list*, bool signed_flag, - ivl_variable_type_t, - PWSRType rt = SR_NET); + ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); diff --git a/pform_dump.cc b/pform_dump.cc index 88fa71520..9d13320f1 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -351,17 +351,23 @@ void PWire::dump(ostream&out, unsigned ind) const } if (port_set_) { - if (port_msb_ == 0) { + if (port_.empty()) { out << " port"; } else { - out << " port[" << *port_msb_ << ":" << *port_lsb_ << "]"; + out << " port"; + for (list::const_iterator cur = port_.begin() + ; cur != port_.end() ; ++cur) + out << "[" << *cur->msb << ":" << *cur->lsb << "]"; } } if (net_set_) { - if (net_msb_ == 0) { + if (net_.empty()) { out << " net"; } else { - out << " net[" << *net_msb_ << ":" << *net_lsb_ << "]"; + out << " net"; + for (list::const_iterator cur = net_.begin() + ; cur != net_.end() ; ++cur) + out << "[" << *cur->msb << ":" << *cur->lsb << "]"; } } From ae11010707f27b2f6617a36c5e771102e9ccc52c Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 5 Feb 2012 17:41:11 -0800 Subject: [PATCH 44/88] Evaluate packed ranges for signals. --- elab_sig.cc | 224 +++++++++++++++++++++++++++++----------------------- netlist.cc | 4 +- netlist.h | 8 +- 3 files changed, 136 insertions(+), 100 deletions(-) diff --git a/elab_sig.cc b/elab_sig.cc index 06854a52b..c030fa6f6 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -826,6 +826,93 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, return res; } +static bool evaluate_ranges(Design*des, NetScope*scope, + list&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + NetNet::range_t lrng; + + NetExpr*texpr = elab_and_eval(des, scope, cur->msb, -1, true); + if (! eval_as_long(lrng.msb, texpr)) { + cerr << cur->msb->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->msb->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->msb << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->lsb, -1, true); + if (! eval_as_long(lrng.lsb, texpr)) { + cerr << cur->lsb->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->lsb->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->lsb << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(lrng); + } + + return bad_msb | bad_lsb; +} + +bool test_ranges_eeq(const list&lef, const list&rig) +{ + if (lef.size() != rig.size()) + return false; + + list::const_iterator lcur = lef.begin(); + list::const_iterator rcur = rig.begin(); + while (lcur != lef.end()) { + if (lcur->msb != rcur->msb) + return false; + if (lcur->lsb != rcur->lsb) + return false; + + ++ lcur; + ++ rcur; + } + + return true; +} + +static unsigned packed_ranges_to_wid(const list&packed) +{ + unsigned wid = 1; + for (list::const_iterator cur = packed.begin() + ; cur != packed.begin() ; ++cur) { + unsigned use_wid; + if (cur->msb >= cur->lsb) + use_wid = cur->msb - cur->lsb + 1; + else + use_wid = cur->lsb - cur->msb + 1; + wid *= use_wid; + } + + return wid; +} + +static ostream&operator<<(ostream&out, const list&rlist) +{ + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + out << "[" << cur->msb << ":" << cur->lsb << "]"; + } + return out; +} + /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -847,7 +934,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } unsigned wid = 1; - long lsb = 0, msb = 0; + listpacked_dimensions; des->errors += error_cnt_; @@ -887,101 +974,43 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } if (port_set_ || net_set_) { - long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; - bool bad_lsb = false, bad_msb = false; + bool bad_range = false; + list plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { - assert(port_.size() == 1); - PWire::range_t rng = port_.front(); - NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); - - if (! eval_as_long(pmsb, texpr)) { - cerr << rng.msb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.msb->get_fileline() << " : " - "This MSB expression violates the rule: " - << *rng.msb << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, rng.lsb, -1, true); - - if (! eval_as_long(plsb, texpr)) { - cerr << rng.lsb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.lsb->get_fileline() << " : " - "This LSB expression violates the rule: " - << *rng.lsb << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - nmsb = pmsb; - nlsb = plsb; + bad_range |= evaluate_ranges(des, scope, plist, port_); + nlist = plist; /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; } - if (!port_set_) assert(port_.empty()); - - if (net_.size() > 1) { - cerr << net_.back().msb->get_fileline() << ": sorry: " - << "Multi-dimension packed arrays not supported." - << endl; - des->errors += 1; - } + assert(port_set_ || port_.empty()); /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && !net_.empty() && !bad_msb && !bad_lsb) { - PWire::range_t rng = net_.front(); - NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); - - if (! eval_as_long(nmsb, texpr)) { - cerr << rng.msb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.msb->get_fileline() << " : " - "This MSB expression violates the rule: " - << *rng.msb << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, rng.lsb, -1, true); - - if (! eval_as_long(nlsb, texpr)) { - cerr << rng.lsb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.lsb->get_fileline() << " : " - "This LSB expression violates the rule: " - << *rng.lsb << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; + if (net_set_ && !net_.empty() && !bad_range) { + nlist.clear(); + bad_range |= evaluate_ranges(des, scope, nlist, net_); } - if (!net_set_) assert(net_.empty()); + assert(net_set_ || net_.empty()); + + /* If we find errors here, then give up on this signal. */ + if (bad_range) + return 0; /* We have a port size error */ - if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { + if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) { /* Scalar port with a vector net/etc. definition */ if (port_.empty()) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; } else { cerr << get_fileline() << ": error: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; des->errors += 1; return 0; } @@ -991,8 +1020,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (net_.empty()) { cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a scalar net declaration at " + << name_ << "'' " << plist + << " has a scalar net declaration at " << get_fileline() << "." << endl; des->errors += 1; return 0; @@ -1002,26 +1031,17 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (!port_.empty() && !net_.empty()) { cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a net declaration [" << nmsb << ":" - << nlsb << "] at " << net_.front().msb->get_fileline() + << name_ << "'' " << plist + << " has a net declaration " << nlist + << " at " << net_.front().msb->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; } } - /* Attempt to recover from errors. */ - if (bad_lsb) nlsb = 0; - if (bad_msb) nmsb = nlsb; - - lsb = nlsb; - msb = nmsb; - if (nmsb > nlsb) - wid = nmsb - nlsb + 1; - else - wid = nlsb - nmsb + 1; - + packed_dimensions = nlist; + wid = packed_ranges_to_wid(packed_dimensions); } @@ -1073,13 +1093,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const array_dimensions = 1; } - if (data_type_ == IVL_VT_REAL && (msb != 0 || lsb != 0)) { + if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) { cerr << get_fileline() << ": error: real "; if (wtype == NetNet::REG) cerr << "variable"; else cerr << "net"; cerr << " '" << name_ - << "' cannot be declared as a vector, found a range [" - << msb << ":" << lsb << "]." << endl; + << "' cannot be declared as a vector, found a range " + << packed_dimensions << "." << endl; des->errors += 1; return 0; } @@ -1143,7 +1163,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype; if (!get_scalar()) { - cerr << " ["< 0) { @@ -1152,6 +1172,16 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const cerr << " in scope " << scope_path(scope) << endl; } + if (packed_dimensions.size() > 1) { + cerr << get_fileline() << ": sorry: Multi-dimension " + << "packed arrays not supported." << endl; + des->errors += 1; + } + long msb = 0, lsb = 0; + if (packed_dimensions.size() >= 1) { + msb = packed_dimensions.front().msb; + lsb = packed_dimensions.front().lsb; + } sig = array_dimensions > 0 ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) : new NetNet(scope, name_, wtype, msb, lsb); diff --git a/netlist.cc b/netlist.cc index ed07fda91..704960ed2 100644 --- a/netlist.cc +++ b/netlist.cc @@ -860,13 +860,13 @@ unsigned NetNet::peek_eref() const * Test each of the bits in the range, and set them. If any bits are * already set then return true. */ -bool NetNet::test_part_lref(unsigned msb, unsigned lsb) +bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb) { if (lref_mask_.size() == 0) lref_mask_.resize(vector_width()); bool rc = false; - for (unsigned idx = lsb ; idx <= msb ; idx += 1) { + for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { if (lref_mask_[idx]) rc = true; else diff --git a/netlist.h b/netlist.h index cae9e3a1e..94b2ca5e5 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef __netlist_H #define __netlist_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -563,6 +563,12 @@ class NetNet : public NetObj { enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; + struct range_t { + long msb; + long lsb; + }; + + public: // The width in this case is a shorthand for ms=width-1 and // ls=0. Only one pin is created, the width is of the vector // that passed through. From e5c49022b46b3500ad9c5a409fdd2f385fcccdd9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 6 Feb 2012 17:47:53 -0800 Subject: [PATCH 45/88] The NetNet class carries multiple packed dimensions. --- design_dump.cc | 19 +++++++++---- elab_expr.cc | 8 +++--- elab_lval.cc | 33 ++++++++++++++++------- elab_sig.cc | 41 +++++----------------------- netlist.cc | 72 ++++++++++++++++++++++++++++++-------------------- netlist.h | 34 +++++++++++++++++------- netmisc.cc | 64 +++++++++++--------------------------------- netmisc.h | 3 +++ t-dll.cc | 12 ++++++--- 9 files changed, 143 insertions(+), 143 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 3ebeaae5f..bf046c2e8 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -187,6 +187,15 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } +ostream&operator<<(ostream&out, const list&rlist) +{ + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + out << "[" << cur->msb << ":" << cur->lsb << "]"; + } + return out; +} + /* Dump a net. This can be a wire or register. */ void NetNet::dump_net(ostream&o, unsigned ind) const { @@ -217,6 +226,8 @@ void NetNet::dump_net(ostream&o, unsigned ind) const if (ivl_discipline_t dis = get_discipline()) o << " discipline=" << dis->name(); + o << " packed dims: " << packed_dims_; + o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); @@ -1045,8 +1056,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const if (result_sig_) { o << setw(ind+2) << "" << "Return signal: "; if (result_sig_->get_signed()) o << "+"; - o << result_sig_->name() << "[" << result_sig_->msb() << ":" - << result_sig_->lsb() << "]" << endl; + o << result_sig_->name() << result_sig_->packed_dims() << endl; } o << setw(ind+2) << "" << "Arguments: "; if (port_count() == 0) o << ""; @@ -1068,8 +1078,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const break; } if (port(idx)->get_signed()) o << "+"; - o << port(idx)->name() << "[" << port(idx)->msb() << ":" - << port(idx)->lsb() << "]" << endl; + o << port(idx)->name() << port(idx)->packed_dims() << endl; } if (statement_) statement_->dump(o, ind+2); diff --git a/elab_expr.cc b/elab_expr.cc index cd3555c3e..a75636c74 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3435,8 +3435,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, else cerr << "vector "; cerr << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "[" << net->sig()->msb() << ":" - << net->sig()->lsb() << "]." << endl; + cerr << net->sig()->packed_dims() << "." << endl; cerr << get_fileline() << ": : " << "Replacing select with a constant 1'bx." << endl; @@ -3470,8 +3469,9 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(), - 1, true); + const list& sig_packed = net->sig()->packed_dims(); + assert(sig_packed.size() == 1); + ex = normalize_variable_base(ex, sig_packed, 1, true); NetESelect*ss = new NetESelect(net, ex, 1); ss->set_line(*this); diff --git a/elab_lval.cc b/elab_lval.cc index ee2502c68..70c0f8b2c 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -365,14 +365,20 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, mux = 0; } + // For now, we only understand 1-dim packed arrays. + const list&packed = reg->packed_dims(); + ivl_assert(*this, packed.size() == 1); + const NetNet::range_t rng = packed.back(); + if (mux) { // Non-constant bit mux. Correct the mux for the range - // of the vector, then set the l-value part select expression. - mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true); + // of the vector, then set the l-value part select + // expression. + mux = normalize_variable_base(mux, reg->packed_dims(), 1, true); lv->set_part(mux, 1); - } else if (lsb == reg->msb() && lsb == reg->lsb()) { + } else if (lsb == rng.msb && lsb == rng.lsb) { // Constant bit mux that happens to select the only bit // of the l-value. Don't bother with any select at all. @@ -410,9 +416,13 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, ivl_assert(*this, parts_defined_flag); NetNet*reg = lv->sig(); - assert(reg); + ivl_assert(*this, reg); - if (msb == reg->msb() && lsb == reg->lsb()) { + const list&packed = reg->packed_dims(); + ivl_assert(*this, packed.size() == 1); + const NetNet::range_t&rng = packed.back(); + + if (msb == rng.msb && lsb == rng.lsb) { /* Part select covers the entire vector. Simplest case. */ @@ -487,9 +497,14 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, if (base_c->value().is_defined()) { long lsv = base_c->value().as_long(); long offset = 0; - if (((reg->msb() < reg->lsb()) && + // This is a work-around for limited dimenions support. + const list&packed = reg->packed_dims(); + ivl_assert(*this, packed.size() == 1); + const NetNet::range_t&rng = packed.back(); + + if (((rng.msb < rng.lsb) && use_sel == index_component_t::SEL_IDX_UP) || - ((reg->msb() > reg->lsb()) && + ((rng.msb > rng.lsb) && use_sel == index_component_t::SEL_IDX_DO)) { offset = -wid + 1; } @@ -538,12 +553,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } else { /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { - base = normalize_variable_base(base, reg->msb(), reg->lsb(), + base = normalize_variable_base(base, reg->packed_dims(), wid, true); sel_type = IVL_SEL_IDX_UP; } else { // This is assumed to be a SEL_IDX_DO. - base = normalize_variable_base(base, reg->msb(), reg->lsb(), + base = normalize_variable_base(base, reg->packed_dims(), wid, false); sel_type = IVL_SEL_IDX_DOWN; } diff --git a/elab_sig.cc b/elab_sig.cc index c030fa6f6..7848c5540 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -494,7 +494,9 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const des->errors += 1; } - ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum); + list packed; + packed.push_back(NetNet::range_t(mnum, lnum)); + ret_sig = new NetNet(scope, fname, NetNet::REG, packed); ret_sig->set_scalar(false); } else { @@ -888,31 +890,6 @@ bool test_ranges_eeq(const list&lef, const list&packed) -{ - unsigned wid = 1; - for (list::const_iterator cur = packed.begin() - ; cur != packed.begin() ; ++cur) { - unsigned use_wid; - if (cur->msb >= cur->lsb) - use_wid = cur->msb - cur->lsb + 1; - else - use_wid = cur->lsb - cur->msb + 1; - wid *= use_wid; - } - - return wid; -} - -static ostream&operator<<(ostream&out, const list&rlist) -{ - for (list::const_iterator cur = rlist.begin() - ; cur != rlist.end() ; ++cur) { - out << "[" << cur->msb << ":" << cur->lsb << "]"; - } - return out; -} - /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -1041,7 +1018,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } packed_dimensions = nlist; - wid = packed_ranges_to_wid(packed_dimensions); + wid = NetNet::vector_width(packed_dimensions); } @@ -1177,14 +1154,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const << "packed arrays not supported." << endl; des->errors += 1; } - long msb = 0, lsb = 0; - if (packed_dimensions.size() >= 1) { - msb = packed_dimensions.front().msb; - lsb = packed_dimensions.front().lsb; - } + sig = array_dimensions > 0 - ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) - : new NetNet(scope, name_, wtype, msb, lsb); + ? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0) + : new NetNet(scope, name_, wtype, packed_dimensions); } // If this is an enumeration, then set the enumeration set for diff --git a/netlist.cc b/netlist.cc index 704960ed2..10c4668f7 100644 --- a/netlist.cc +++ b/netlist.cc @@ -452,12 +452,14 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), discipline_(0), - msb_(npins-1), lsb_(0), dimensions_(0), - s0_(0), e0_(0), eref_count_(0), lref_count_(0) + dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { assert(s); assert(npins>0); + // Synthesize a single range to describe this canonical vector. + packed_dims_.push_back(NetNet::range_t(npins-1, 0)); + Link::DIR dir = Link::PASSIVE; switch (t) { @@ -494,15 +496,15 @@ void NetNet::initialize_dir_(Link::DIR dir) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls) + const list&packed) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), discipline_(0), - msb_(ms), lsb_(ls), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { + packed_dims_ = packed; assert(s); Link::DIR dir = Link::PASSIVE; @@ -542,16 +544,16 @@ static unsigned calculate_count(long s, long e) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls, long array_s, long array_e) + const list&packed, long array_s, long array_e) : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), discipline_(0), - msb_(ms), lsb_(ls), dimensions_(1), s0_(array_s), e0_(array_e), eref_count_(0), lref_count_(0) { + packed_dims_ = packed; ivl_assert(*this, s); if (pin_count() == 0) { cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl; @@ -599,10 +601,11 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), - discipline_(0), msb_(calculate_count(ty)-1), lsb_(0), + discipline_(0), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { + packed_dims_.push_back(range_t(calculate_count(ty)-1, 0)); Link::DIR dir = Link::PASSIVE; switch (t) { @@ -761,38 +764,40 @@ void NetNet::set_discipline(ivl_discipline_t dis) discipline_ = dis; } -long NetNet::lsb() const +unsigned long NetNet::vector_width(const list&packed) { - return lsb_; -} + unsigned wid = 1; + for (list::const_iterator cur = packed.begin() + ; cur != packed.end() ; ++cur) { + unsigned use_wid; + if (cur->msb >= cur->lsb) + use_wid = cur->msb - cur->lsb + 1; + else + use_wid = cur->lsb - cur->msb + 1; + wid *= use_wid; + } -long NetNet::msb() const -{ - return msb_; -} - -unsigned long NetNet::vector_width() const -{ - if (msb_ > lsb_) - return msb_ - lsb_ + 1; - else - return lsb_ - msb_ + 1; + return wid; } bool NetNet::sb_is_valid(long sb) const { - if (msb_ >= lsb_) - return (sb <= msb_) && (sb >= lsb_); + assert(packed_dims_.size() == 1); + const range_t&rng = packed_dims_.back(); + if (rng.msb >= rng.lsb) + return (sb <= rng.msb) && (sb >= rng.lsb); else - return (sb <= lsb_) && (sb >= msb_); + return (sb <= rng.lsb) && (sb >= rng.msb); } long NetNet::sb_to_idx(long sb) const { - if (msb_ >= lsb_) - return sb - lsb_; + assert(packed_dims_.size() == 1); + const range_t&rng = packed_dims_.back(); + if (rng.msb >= rng.lsb) + return sb - rng.lsb; else - return lsb_ - sb; + return rng.lsb - sb; } unsigned NetNet::array_dimensions() const @@ -2370,14 +2375,23 @@ NetNet* NetESignal::sig() return net_; } +/* + * The lsi() and msi() methods should be removed from the NetESignal + * class, to be replaced with packed dimensions aware methods of + * getting at dimensions. + */ long NetESignal::lsi() const { - return net_->lsb(); + const list&packed = net_->packed_dims(); + ivl_assert(*this, packed.size() == 1); + return packed.back().lsb; } long NetESignal::msi() const { - return net_->msb(); + const list&packed = net_->packed_dims(); + ivl_assert(*this, packed.size() == 1); + return packed.back().msb; } ivl_variable_type_t NetESignal::expr_type() const diff --git a/netlist.h b/netlist.h index 94b2ca5e5..658523c44 100644 --- a/netlist.h +++ b/netlist.h @@ -564,6 +564,13 @@ class NetNet : public NetObj { enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; struct range_t { + inline range_t() : msb(0), lsb(0) { } + inline range_t(long m, long l) : msb(m), lsb(l) { } + inline range_t(const range_t&that) + : msb(that.msb), lsb(that.lsb) { } + inline range_t& operator = (const range_t&that) + { msb = that.msb; lsb = that.lsb; return *this; } + long msb; long lsb; }; @@ -579,9 +586,9 @@ class NetNet : public NetObj { // dimensions. If s0==e0, then this is not an array after // all. explicit NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls); + const std::list&packed); explicit NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls, long s0, long e0); + const std::list&packed, long s0, long e0); // This form builds a NetNet from its record definition. explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); @@ -619,13 +626,18 @@ class NetNet : public NetObj { ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); - /* These methods return the msb and lsb indices for the most - significant and least significant bits. These are signed - longs, and may be different from pin numbers. For example, - reg [1:8] has 8 bits, msb==1 and lsb==8. */ - long msb() const; - long lsb() const; - unsigned long vector_width() const; + /* This method returns a reference to the packed dimensions + for the vector. These are arranged as a list where the + first range in the list (front) is the left-most range in + the verilog declaration. */ + const std::list& packed_dims() const { return packed_dims_; } + + /* The vector_width returns the bit width of the packed array, + vector or scaler that is this NetNet object. The static + method is also a convenient way to convert a range list to + a vector width. */ + static unsigned long vector_width(const std::list&); + unsigned long vector_width() const { return vector_width(packed_dims_); } /* This method converts a signed index (the type that might be found in the Verilog source) to a pin number. It accounts @@ -692,7 +704,7 @@ class NetNet : public NetObj { netstruct_t*struct_type_; ivl_discipline_t discipline_; - long msb_, lsb_; + std::list packed_dims_; const unsigned dimensions_; long s0_, e0_; @@ -706,6 +718,8 @@ class NetNet : public NetObj { vector delay_paths_; }; +extern std::ostream&operator << (std::ostream&out, const std::list&rlist); + /* * This object type is used to contain a logical scope within a * design. The scope doesn't represent any executable hardware, but is diff --git a/netmisc.cc b/netmisc.cc index b9abaad93..09853f8f0 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -27,55 +27,6 @@ # include "compiler.h" # include "ivl_assert.h" -// This routines is not currently used! -#if 0 -NetNet* add_to_net(Design*des, NetNet*sig, long val) -{ - if (val == 0) - return sig; - cerr << sig->get_fileline() << ": XXXX: Forgot how to implement add_to_net" << endl; - return 0; - NetScope*scope = sig->scope(); - unsigned long abs_val = (val >= 0)? val : (-val); - unsigned width = sig->pin_count(); - - verinum val_v (abs_val, width); - - NetConst*val_c = new NetConst(scope, scope->local_symbol(), val_v); - - NetNet*val_s = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - val_s->local_flag(true); - - NetNet*res = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - res->local_flag(true); - - NetAddSub*add = new NetAddSub(scope, scope->local_symbol(), width); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(sig->pin(idx), add->pin_DataA(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(val_c->pin(idx), add->pin_DataB(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(val_s->pin(idx), add->pin_DataB(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(res->pin(idx), add->pin_Result(idx)); - - if (val < 0) - add->attribute(perm_string::literal("LPM_Direction"), verinum("SUB")); - else - add->attribute(perm_string::literal("LPM_Direction"), verinum("ADD")); - - des->add_node(add); - des->add_node(val_c); - - return res; -} -#endif NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) { @@ -344,6 +295,21 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, return base; } +/* + * This method is how indices should work except that the base should + * be a vector of expressions that matches the size of the dims list, + * so that we can generate an expression based on the entire packed + * vector. For now, we assert that there is only one set of dimensions. + */ +NetExpr *normalize_variable_base(NetExpr *base, + const list&dims, + unsigned long wid, bool is_up) +{ + ivl_assert(*base, dims.size() == 1); + const NetNet::range_t&rng = dims.back(); + return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); +} + /* * This routine generates the normalization expression needed for a variable * array word select. diff --git a/netmisc.h b/netmisc.h index 20d72461f..b0db81d32 100644 --- a/netmisc.h +++ b/netmisc.h @@ -100,6 +100,9 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); */ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, unsigned long wid, bool is_up); +extern NetExpr*normalize_variable_base(NetExpr *base, + const list&dims, + unsigned long wid, bool is_up); extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, unsigned count); diff --git a/t-dll.cc b/t-dll.cc index c9b3f7024..50ab72724 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -2399,10 +2399,16 @@ void dll_target::signal(const NetNet*net) /* Save the primitive properties of the signal in the ivl_signal_t object. */ + // FIX ME: This is a temporary workaround until the ivl_target + // API gets a way to represent multiple packed dimensions. + const list&packed = net->packed_dims(); + ivl_assert(*net, packed.size() <= 1); + const NetNet::range_t rng = packed.empty()? NetNet::range_t(0,0) : packed.back(); + obj->width_ = net->vector_width(); obj->signed_= net->get_signed()? 1 : 0; - obj->lsb_index = net->lsb(); - obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1; + obj->lsb_index = rng.lsb; + obj->lsb_dist = rng.msb >= rng.lsb ? 1 : -1; obj->isint_ = false; obj->local_ = net->local_flag()? 1 : 0; obj->forced_net_ = (net->type() != NetNet::REG) && From 3e4f8b625f4c323d4e72abedb39a45be7625345a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 10 Feb 2012 17:17:59 -0800 Subject: [PATCH 46/88] Get packed signals working through to simulation in some situations. When dynamic indexing of early dimensions is not needed, we can get pretty far with getting packed arrays to work. --- PExpr.h | 12 +++++++ design_dump.cc | 2 +- elab_expr.cc | 86 +++++++++++++++++++++++++++++++++++++++----------- elab_lval.cc | 73 ++++++++++++++++++++++++++++++++---------- elab_net.cc | 16 ++++++---- elab_sig.cc | 6 ---- ivl_target.h | 29 ++++++++++++----- netlist.cc | 56 ++++++++++++++++++++++++++++++-- netlist.h | 30 +++++++++++++++--- netmisc.cc | 76 ++++++++++++++++++++++++++++++++++++++++++++ netmisc.h | 5 +++ t-dll-api.cc | 30 ++++++++++++++++-- t-dll.cc | 15 +++++---- t-dll.h | 7 ++-- 14 files changed, 366 insertions(+), 77 deletions(-) diff --git a/PExpr.h b/PExpr.h index 17ca6f989..7691b44d1 100644 --- a/PExpr.h +++ b/PExpr.h @@ -343,6 +343,18 @@ class PEIdent : public PExpr { bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const; + // Evaluate the prefix indices. All but the final index in a + // chain of indices must be a single value and must evaluate + // to constants at compile time. For example: + // [x] - OK + // [1][2][x] - OK + // [1][x:y] - OK + // [2:0][x] - BAD + // [y][x] - BAD + // Leave the last index for special handling. + bool calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, + std::list&prefix_indices) const; + private: NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const; bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const; diff --git a/design_dump.cc b/design_dump.cc index bf046c2e8..5da7f9047 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1518,7 +1518,7 @@ void NetESignal::dump(ostream&o) const o << "+"; o << name(); if (word_) o << "[word=" << *word_ << "]"; - o << "[" << msi()<<":"<packed_dims(); } void NetETernary::dump(ostream&o) const diff --git a/elab_expr.cc b/elab_expr.cc index a75636c74..f886e7197 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1854,6 +1854,17 @@ NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const return tmp; } +bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, + list&prefix_indices) const +{ + list index; + index = path_.back().index; + for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1) + index.pop_front(); + + return evaluate_index_prefix(des, scope, prefix_indices, index); +} + /* * Given that the msb_ and lsb_ are part select expressions, this * function calculates their values. Note that this method does *not* @@ -3101,6 +3112,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, NetESignal*net, NetScope*, unsigned expr_wid) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + long msv, lsv; bool parts_defined_flag; bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag); @@ -3133,9 +3148,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, tmp->set_line(*this); return tmp; } - - long sb_lsb = net->sig()->sb_to_idx(lsv); - long sb_msb = net->sig()->sb_to_idx(msv); + long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv); + long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv); if (sb_msb < sb_lsb) { cerr << get_fileline() << ": error: part select " << net->name(); @@ -3207,6 +3221,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; @@ -3224,7 +3242,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sig()->sb_to_idx(lsv) == 0 && + if (net->sig()->sb_to_idx(prefix_indices, lsv) == 0 && wid == net->vector_width()) { delete base; net->cast_signed(false); @@ -3237,10 +3255,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + - offset)); + ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset)); if (warn_ob_select) { - long rel_base = net->sig()->sb_to_idx(lsv) + offset; + long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset; if (rel_base < 0) { cerr << get_fileline() << ": warning: " << net->name(); @@ -3296,6 +3313,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; @@ -3312,7 +3333,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && + if (net->sig()->sb_to_idx(prefix_indices,lsv) == (signed) (wid-1) && wid == net->vector_width()) { delete base; net->cast_signed(false); @@ -3325,10 +3346,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + - offset)); + ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset)); if (warn_ob_select) { - long rel_base = net->sig()->sb_to_idx(lsv) + offset; + long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset; if (rel_base < 0) { cerr << get_fileline() << ": warning: " << net->name(); @@ -3381,6 +3401,10 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -3388,12 +3412,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, ivl_assert(*this, index_tail.msb != 0); ivl_assert(*this, index_tail.lsb == 0); - NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1, need_const); + NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const); // If the bit select is constant, then treat it similar // to the part select, so that I save the effort of // making a mux part in the netlist. - if (NetEConst*msc = dynamic_cast (ex)) { + if (NetEConst*msc = dynamic_cast (mux)) { // Special case: The bit select expression is constant // x/z. The result of the expression is 1'bx. @@ -3414,12 +3438,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetEConst*tmp = make_const_x(1); tmp->set_line(*this); - delete ex; + delete mux; return tmp; } long msv = msc->value().as_long(); - long idx = net->sig()->sb_to_idx(msv); + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { /* The bit select is out of range of the @@ -3444,7 +3468,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetEConst*tmp = make_const_x(1); tmp->set_line(*this); - delete ex; + delete mux; return tmp; } @@ -3464,16 +3488,36 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + const list& sig_packed = net->sig()->packed_dims(); + if (prefix_indices.size()+2 <= sig_packed.size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // x[2] = ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + unsigned long lwid; + mux = normalize_variable_slice_base(prefix_indices, mux, + net->sig(), lwid); + mux->set_line(*net); + + // Make a PART select with the canonical index + NetESelect*res = new NetESelect(net, mux, lwid); + res->set_line(*net); + + return res; + } + // Non-constant bit select? punt and make a subsignal // device to mux the bit in the net. This is a fairly // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - const list& sig_packed = net->sig()->packed_dims(); assert(sig_packed.size() == 1); - ex = normalize_variable_base(ex, sig_packed, 1, true); + mux = normalize_variable_base(mux, sig_packed, 1, true); - NetESelect*ss = new NetESelect(net, ex, 1); + NetESelect*ss = new NetESelect(net, mux, 1); ss->set_line(*this); return ss; } @@ -3506,6 +3550,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return 0; } + list prefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, path_.back().index); + ivl_assert(*this, rc); + // If this is a part select of a signal, then make a new // temporary signal that is connected to just the // selected bits. The lsb_ and msb_ expressions are from diff --git a/elab_lval.cc b/elab_lval.cc index 70c0f8b2c..ce887fff6 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -183,16 +183,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } ivl_assert(*this, reg); - + // We are processing the tail of a string of names. For + // example, the verilog may be "a.b.c", so we are processing + // "c" at this point. const name_component_t&name_tail = path_.back(); + // Use the last index to determine what kind of select + // (bit/part/etc) we are processing. For example, the verilog + // may be "a.b.c[1][2][]". All but the last index must + // be simple expressions, only the may be a part + // select etc., so look at it to determine how we will be + // proceeding. index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; if (!name_tail.index.empty()) use_sel = name_tail.index.back().sel; - // This is the special case that the l-value is an entire - // memory. This is, in fact, an error. - if (reg->array_dimensions() > 0 && name_tail.index.empty()) { + // Special case: The l-value is an entire memory, or array + // slice. This is, in fact, an error in l-values. Detect the + // situation by noting if the index count is less then the + // array dimensions (unpacked). + if (reg->array_dimensions() > name_tail.index.size()) { cerr << get_fileline() << ": error: Cannot assign to array " << path_ << ". Did you forget a word index?" << endl; des->errors += 1; @@ -200,7 +210,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } /* Get the signal referenced by the identifier, and make sure - it is a register. Wires are not allows in this context, + it is a register. Wires are not allowed in this context, unless this is the l-value of a force. */ if ((reg->type() != NetNet::REG) && !is_force) { cerr << get_fileline() << ": error: " << path_ << @@ -347,7 +357,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, NetScope*scope, NetAssign_*lv) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + ivl_assert(*this, rc); + 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.msb != 0); ivl_assert(*this, index_tail.lsb == 0); @@ -365,26 +381,43 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, mux = 0; } - // For now, we only understand 1-dim packed arrays. - const list&packed = reg->packed_dims(); - ivl_assert(*this, packed.size() == 1); - const NetNet::range_t rng = packed.back(); - if (mux) { + if (prefix_indices.size()+2 <= reg->packed_dims().size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // x[2] = ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + if (mux == 0) { + long loff; + unsigned long lwid; + bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid); + ivl_assert(*this, rcl); + + lv->set_part(new NetEConst(verinum(loff)), lwid); + } else { + unsigned long lwid; + mux = normalize_variable_slice_base(prefix_indices, mux, + reg, lwid); + lv->set_part(mux, lwid); + } + + } else if (mux) { // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select // expression. mux = normalize_variable_base(mux, reg->packed_dims(), 1, true); - lv->set_part(mux, 1); - } else if (lsb == rng.msb && lsb == rng.lsb) { + } else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) { // Constant bit mux that happens to select the only bit // of the l-value. Don't bother with any select at all. } else { // Constant bit select that does something useful. - long loff = reg->sb_to_idx(lsb); + long loff = reg->sb_to_idx(prefix_indices,lsb); if (loff < 0 || loff >= (long)reg->vector_width()) { cerr << get_fileline() << ": error: bit select " @@ -404,6 +437,10 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, NetScope*scope, NetAssign_*lv) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + ivl_assert(*this, rc); + // The range expressions of a part select must be // constant. The calculate_parts_ function calculates the // values into msb and lsb. @@ -429,8 +466,8 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, } else { /* Get the canonical offsets into the vector. */ - long loff = reg->sb_to_idx(lsb); - long moff = reg->sb_to_idx(msb); + long loff = reg->sb_to_idx(prefix_indices,lsb); + long moff = reg->sb_to_idx(prefix_indices,msb); long wid = moff - loff + 1; if (moff < loff) { @@ -463,6 +500,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, NetAssign_*lv, index_component_t::ctype_t use_sel) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back();; ivl_assert(*this, !name_tail.index.empty()); @@ -509,7 +550,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, offset = -wid + 1; } delete base; - long rel_base = reg->sb_to_idx(lsv) + offset; + long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset; /* If we cover the entire lvalue just skip the select. */ if (rel_base == 0 && wid == reg->vector_width()) return true; base = new NetEConst(verinum(rel_base)); diff --git a/elab_net.cc b/elab_net.cc index 6f1aca6a7..98180dab5 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -200,6 +200,10 @@ bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, long&midx, long&lidx) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, sig, prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back(); // Only treat as part/bit selects any index that is beyond the // word selects for an array. This is not an array, then @@ -258,13 +262,13 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } long midx_val = tmp->value().as_long(); - midx = sig->sb_to_idx(midx_val); + midx = sig->sb_to_idx(prefix_indices, midx_val); delete tmp_ex; if (index_tail.sel == index_component_t::SEL_IDX_UP) - lidx = sig->sb_to_idx(midx_val+wid-1); + lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1); else - lidx = sig->sb_to_idx(midx_val-wid+1); + lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1); if (midx < lidx) { long tmpx = midx; @@ -313,8 +317,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, /* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag); ivl_assert(*this, part_defined_flag); - long lidx_tmp = sig->sb_to_idx(lsb); - long midx_tmp = sig->sb_to_idx(msb); + long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); + long midx_tmp = sig->sb_to_idx(prefix_indices, msb); /* Detect reversed indices of a part select. */ if (lidx_tmp > midx_tmp) { cerr << get_fileline() << ": error: Part select " @@ -370,7 +374,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } assert(mval); - midx = sig->sb_to_idx(mval->as_long()); + midx = sig->sb_to_idx(prefix_indices, mval->as_long()); if (midx >= (long)sig->vector_width()) { cerr << get_fileline() << ": error: Index " << sig->name() << "[" << mval->as_long() << "] is out of range." diff --git a/elab_sig.cc b/elab_sig.cc index 7848c5540..336a8e97e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1149,12 +1149,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const cerr << " in scope " << scope_path(scope) << endl; } - if (packed_dimensions.size() > 1) { - cerr << get_fileline() << ": sorry: Multi-dimension " - << "packed arrays not supported." << endl; - des->errors += 1; - } - sig = array_dimensions > 0 ? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0) : new NetNet(scope, name_, wtype, packed_dimensions); diff --git a/ivl_target.h b/ivl_target.h index 3a1c39b70..eda6861f9 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1785,13 +1785,23 @@ extern int ivl_scope_time_units(ivl_scope_t net); * If the signal has been declared with a domain (Verilog-AMS) then * this function will return a non-nil ivl_discipline_t. * - * ivl_signal_msb - * ivl_signal_lsb + * ivl_signal_msb (deprecated) + * ivl_signal_lsb (deprecated) + * ivl_signal_packed_dimensions + * ivl_signal_packed_msb + * ivl_signal_packed_lsb * ivl_signal_width - * These functions return the left and right indices, respectively, - * of the signal. If the signal is a scalar, both return 0. However, - * it doesn't mean that the signal is a scalar if both return 0, one - * can have a vector with 0 as both indices. + * These functions return the msb and lsb packed indices. The + * packed dimensions are declared differently from array + * dimensions, like so: + * reg [4:1][7:0] sig... + * which has two packed dimensions. The [4:1] dimension is the + * first, and so forth. If the signal is a scalar, it has 0 + * dimension. + * + * The ivl_signal_msb/ivl_signal_lsb functions are deprecated + * versions that only work with variables that have less then two + * dimensions. They will return msb==lsb==0 for scalars. * * ivl_signal_port * If the signal is a port to a module, this function returns the @@ -1859,8 +1869,11 @@ extern unsigned ivl_signal_array_count(ivl_signal_t net); extern unsigned ivl_signal_array_addr_swapped(ivl_signal_t net); extern unsigned ivl_signal_dimensions(ivl_signal_t net); extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net); -extern int ivl_signal_msb(ivl_signal_t net); -extern int ivl_signal_lsb(ivl_signal_t net); +extern unsigned ivl_signal_packed_dimensions(ivl_signal_t net); +extern int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim); +extern int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim); +extern int ivl_signal_msb(ivl_signal_t net) __attribute__((deprecated)); +extern int ivl_signal_lsb(ivl_signal_t net) __attribute__((deprecated)); extern unsigned ivl_signal_width(ivl_signal_t net); extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net); extern int ivl_signal_signed(ivl_signal_t net); diff --git a/netlist.cc b/netlist.cc index 10c4668f7..922f6f2bb 100644 --- a/netlist.cc +++ b/netlist.cc @@ -780,8 +780,9 @@ unsigned long NetNet::vector_width(const list&packed) return wid; } -bool NetNet::sb_is_valid(long sb) const +bool NetNet::sb_is_valid(const list&indices, long sb) const { + ivl_assert(*this, indices.size()+1 == packed_dims_.size()); assert(packed_dims_.size() == 1); const range_t&rng = packed_dims_.back(); if (rng.msb >= rng.lsb) @@ -790,8 +791,9 @@ bool NetNet::sb_is_valid(long sb) const return (sb <= rng.lsb) && (sb >= rng.msb); } -long NetNet::sb_to_idx(long sb) const +long NetNet::sb_to_idx(const list&indices, long sb) const { + ivl_assert(*this, indices.size()+1 == packed_dims_.size()); assert(packed_dims_.size() == 1); const range_t&rng = packed_dims_.back(); if (rng.msb >= rng.lsb) @@ -800,6 +802,56 @@ long NetNet::sb_to_idx(long sb) const return rng.lsb - sb; } +bool NetNet::sb_to_slice(const list&indices, long sb, long&loff, unsigned long&lwid) const +{ + ivl_assert(*this, indices.size() < packed_dims_.size()); + + size_t acc_wid = 1; + list::const_iterator pcur = packed_dims_.end(); + for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) { + -- pcur; + acc_wid *= pcur->width(); + } + + lwid = acc_wid; + + -- pcur; + if (sb < pcur->msb && sb < pcur->lsb) + return false; + if (sb > pcur->msb && sb > pcur->lsb) + return false; + + long acc_off = 0; + if (pcur->msb >= pcur->lsb) + acc_off += (sb - pcur->lsb) * acc_wid; + else + acc_off += (sb - pcur->msb) * acc_wid; + + if (indices.size() == 0) { + loff = acc_off; + return true; + } + + lwid *= pcur->width(); + + list::const_iterator icur = indices.end(); + do { + -- pcur; + -- icur; + acc_wid *= pcur->width(); + if (pcur->msb >= pcur->lsb) + acc_off += (*icur - pcur->lsb) * acc_wid; + else + acc_off += (*icur - pcur->msb) * acc_wid; + + } while (icur != indices.begin()); + + loff = acc_off; + + return true; +} + + unsigned NetNet::array_dimensions() const { return dimensions_; diff --git a/netlist.h b/netlist.h index 658523c44..42f31050e 100644 --- a/netlist.h +++ b/netlist.h @@ -550,7 +550,7 @@ class NetDelaySrc : public NetObj { * * NetNet objects are located by searching NetScope objects. * - * The pin of a NetNet object are PASSIVE: they do not drive + * The pins of a NetNet object are PASSIVE: they do not drive * anything and they are not a data sink, per se. The pins follow the * values on the nexus. */ @@ -573,6 +573,9 @@ class NetNet : public NetObj { long msb; long lsb; + + inline unsigned long width()const + { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; } }; public: @@ -639,15 +642,30 @@ class NetNet : public NetObj { static unsigned long vector_width(const std::list&); unsigned long vector_width() const { return vector_width(packed_dims_); } + /* Given a prefix of indices, figure out how wide the + resulting slice would be. This is a generalization of the + vector_width(), where the depth would be 0. */ + unsigned long slice_width(size_t depth) const; + /* This method converts a signed index (the type that might be - found in the Verilog source) to a pin number. It accounts - for variation in the definition of the reg/wire/whatever. */ - long sb_to_idx(long sb) const; + found in the Verilog source) to canonical. It accounts + for variation in the definition of the + reg/wire/whatever. Note that a canonical index of a + multi-dimensioned packed array is a single dimension. For + example, "reg [4:1][3:0]..." has the canonical dimension + [15:0] and the sb_to_idx) method will convert [2][2] to + the canonical index [6]. */ + long sb_to_idx(const std::list&prefix, long sb) const; + + /* This method converts a partial packed indices list and a + tail index, and generates a canonical slice offset and + width. */ + bool sb_to_slice(const std::list&prefix, long sb, long&off, unsigned long&wid) const; /* This method checks that the signed index is valid for this signal. If it is, the above sb_to_idx can be used to get the pin# from the index. */ - bool sb_is_valid(long sb) const; + bool sb_is_valid(const std::list&prefix, long sb) const; /* This method returns 0 for scalars and vectors, and greater for arrays. The value is the number of array @@ -2348,6 +2366,8 @@ class NetAssign_ { ivl_select_type_t select_type() const; void set_word(NetExpr*); + // Set a part select expression for the l-value vector. Note + // that the expression calculates a CANONICAL bit address. void set_part(NetExpr* loff, unsigned wid, ivl_select_type_t = IVL_SEL_OTHER); diff --git a/netmisc.cc b/netmisc.cc index 09853f8f0..c6e94e881 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -198,6 +198,21 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val) +{ + verinum val_v (val, expr->expr_width()); + val_v.has_sign(true); + + NetEConst*val_c = new NetEConst(val_v); + val_c->set_line(*expr); + + NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(), + expr->has_sign()); + res->set_line(*expr); + + return res; +} + /* * This routine is used to calculate the number of bits needed to * contain the given number. @@ -310,6 +325,31 @@ NetExpr *normalize_variable_base(NetExpr *base, return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); } +NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, + const NetNet*reg, unsigned long&lwid) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size() < packed_dims.size()); + + list::const_iterator pcur = packed_dims.end(); + for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) { + -- pcur; + } + + long sb; + if (pcur->msb >= pcur->lsb) + sb = pcur->lsb; + else + sb = pcur->msb; + + long loff; + reg->sb_to_slice(indices, sb, loff, lwid); + + base = make_mult_expr(base, lwid); + base = make_add_expr(base, loff); + return base; +} + /* * This routine generates the normalization expression needed for a variable * array word select. @@ -858,3 +898,39 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig) delete ps_obj; } } + +/* + * Evaluate the prefix indices. All but the final index in a + * chain of indices must be a single value and must evaluate + * to constants at compile time. For example: + * [x] - OK + * [1][2][x] - OK + * [1][x:y] - OK + * [2:0][x] - BAD + * [y][x] - BAD + * Leave the last index for special handling. + */ +bool evaluate_index_prefix(Design*des, NetScope*scope, + list&prefix_indices, + const list&indices) +{ + list::const_iterator icur = indices.begin(); + for (size_t idx = 0 ; (idx+1) < indices.size() ; idx += 1, ++icur) { + assert(icur != indices.end()); + assert(icur->sel == index_component_t::SEL_BIT); + NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true); + ivl_assert(*icur->msb, texpr); + long tmp; + if (!eval_as_long(tmp, texpr)) { + cerr << icur->msb->get_fileline() << ": error: " + "Array index expressions must be constant." << endl; + des->errors += 1; + return 0; + } + + prefix_indices .push_back(tmp); + delete texpr; + } + + return true; +} diff --git a/netmisc.h b/netmisc.h index b0db81d32..91d1fcfd9 100644 --- a/netmisc.h +++ b/netmisc.h @@ -103,6 +103,8 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, extern NetExpr*normalize_variable_base(NetExpr *base, const list&dims, unsigned long wid, bool is_up); +extern NetExpr*normalize_variable_slice_base(const list&indices, NetExpr *base, + const NetNet*reg, unsigned long&lwid); extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, unsigned count); @@ -238,4 +240,7 @@ extern uint64_t get_scaled_time_from_real(Design*des, extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig); +extern bool evaluate_index_prefix(Design*des, NetScope*scope, + list&prefix_indices, + const list&indices); #endif diff --git a/t-dll-api.cc b/t-dll-api.cc index b45da977e..008847127 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2147,15 +2147,39 @@ extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) } } +extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net) +{ + return net->packed_dims.size(); +} + +extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim) +{ + assert(dim < net->packed_dims.size()); + return net->packed_dims[dim].msb; +} + +extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim) +{ + assert(dim < net->packed_dims.size()); + return net->packed_dims[dim].lsb; +} + extern "C" int ivl_signal_msb(ivl_signal_t net) { - assert(net->lsb_dist == 1 || net->lsb_dist == -1); - return net->lsb_index + net->lsb_dist * (net->width_ - 1); + if (net->packed_dims.size() == 0) + return 0; + + assert(net->packed_dims.size() == 1); + return net->packed_dims[0].msb; } extern "C" int ivl_signal_lsb(ivl_signal_t net) { - return net->lsb_index; + if (net->packed_dims.size() == 0) + return 0; + + assert(net->packed_dims.size() == 1); + return net->packed_dims[0].lsb; } extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net) diff --git a/t-dll.cc b/t-dll.cc index 50ab72724..e6b44c75f 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2399,16 +2399,17 @@ void dll_target::signal(const NetNet*net) /* Save the primitive properties of the signal in the ivl_signal_t object. */ - // FIX ME: This is a temporary workaround until the ivl_target - // API gets a way to represent multiple packed dimensions. - const list&packed = net->packed_dims(); - ivl_assert(*net, packed.size() <= 1); - const NetNet::range_t rng = packed.empty()? NetNet::range_t(0,0) : packed.back(); + { size_t idx = 0; + list::const_iterator cur; + obj->packed_dims.resize(net->packed_dims().size()); + for (cur = net->packed_dims().begin(), idx = 0 + ; cur != net->packed_dims().end() ; ++cur, idx += 1) { + obj->packed_dims[idx] = *cur; + } + } obj->width_ = net->vector_width(); obj->signed_= net->get_signed()? 1 : 0; - obj->lsb_index = rng.lsb; - obj->lsb_dist = rng.msb >= rng.lsb ? 1 : -1; obj->isint_ = false; obj->local_ = net->local_flag()? 1 : 0; obj->forced_net_ = (net->type() != NetNet::REG) && diff --git a/t-dll.h b/t-dll.h index 62f2df303..2bdae36bb 100644 --- a/t-dll.h +++ b/t-dll.h @@ -688,10 +688,9 @@ struct ivl_signal_s { unsigned array_dimensions_ : 1; unsigned array_addr_swapped : 1; - /* These encode the run-time index for the least significant - bit, and the distance to the second bit. */ - signed lsb_index; - signed lsb_dist; + /* These encode the declared packed dimensions for the + signal, in case they are needed by the run-time */ + std::vector packed_dims; perm_string name_; ivl_scope_t scope_; From 4287fc4b509d8ac3057942805516eec1a6d8ecae Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 10 Feb 2012 18:48:12 -0800 Subject: [PATCH 47/88] Handle l-value part select of packed arrays. --- elab_lval.cc | 71 ++++++++++++++++++++++++--------------------- netlist.cc | 37 +++++++++++++++++++---- netlist.h | 2 +- tgt-stub/stub.c | 11 ++++--- tgt-vvp/vvp_scope.c | 13 +++++++-- 5 files changed, 89 insertions(+), 45 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index ce887fff6..cf1aecb8b 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -456,42 +456,47 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, ivl_assert(*this, reg); const list&packed = reg->packed_dims(); - ivl_assert(*this, packed.size() == 1); - const NetNet::range_t&rng = packed.back(); - if (msb == rng.msb && lsb == rng.lsb) { - - /* Part select covers the entire vector. Simplest case. */ - - } else { - - /* Get the canonical offsets into the vector. */ - long loff = reg->sb_to_idx(prefix_indices,lsb); - long moff = reg->sb_to_idx(prefix_indices,msb); - long wid = moff - loff + 1; - - if (moff < loff) { - cerr << get_fileline() << ": error: part select " - << reg->name() << "[" << msb<<":"<errors += 1; - return false; - } - - /* If the part select extends beyond the extremes of the - variable, then report an error. Note that loff is - converted to normalized form so is relative the - variable pins. */ - - if (loff < 0 || moff >= (signed)reg->vector_width()) { - cerr << get_fileline() << ": warning: Part select " - << reg->name() << "[" << msb<<":"<set_part(new NetEConst(verinum(loff)), wid); + // Part selects cannot select slices. So there must be enough + // prefix_indices to get all the way to the final dimension. + if (prefix_indices.size()+1 < packed.size()) { + cerr << get_fileline() << ": error: Cannot select a range " + << "of slices from a packed array." << endl; + des->errors += 1; + return false; } + long loff = reg->sb_to_idx(prefix_indices,lsb); + long moff = reg->sb_to_idx(prefix_indices,msb); + long wid = moff - loff + 1; + + if (moff < loff) { + cerr << get_fileline() << ": error: part select " + << reg->name() << "[" << msb<<":"<errors += 1; + return false; + } + + // Special case: The range winds up selecting the entire + // vector. Treat this as no part select at all. + if (loff == 0 && moff == (reg->vector_width()-1)) { + return true; + } + + /* If the part select extends beyond the extremes of the + variable, then report an error. Note that loff is + converted to normalized form so is relative the + variable pins. */ + + if (loff < 0 || moff >= (signed)reg->vector_width()) { + cerr << get_fileline() << ": warning: Part select " + << reg->name() << "[" << msb<<":"<set_part(new NetEConst(verinum(loff)), wid); + return true; } diff --git a/netlist.cc b/netlist.cc index 922f6f2bb..ef0b6c1a6 100644 --- a/netlist.cc +++ b/netlist.cc @@ -794,12 +794,39 @@ bool NetNet::sb_is_valid(const list&indices, long sb) const long NetNet::sb_to_idx(const list&indices, long sb) const { ivl_assert(*this, indices.size()+1 == packed_dims_.size()); - assert(packed_dims_.size() == 1); - const range_t&rng = packed_dims_.back(); - if (rng.msb >= rng.lsb) - return sb - rng.lsb; + + list::const_iterator pcur = packed_dims_.end(); + -- pcur; + + long acc_off; + long acc_wid = pcur->width(); + if (pcur->msb >= pcur->lsb) + acc_off = sb - pcur->lsb; else - return rng.lsb - sb; + acc_off = pcur->lsb - sb; + + // The acc_off is the possition within the innermost + // dimension. If this is a multi-dimension packed array then + // we need to add in the canonical address of the current slice. + if (indices.size() >= 1) { + list::const_iterator icur = indices.end(); + do { + -- icur; + -- pcur; + + long tmp_off; + if (pcur->msb >= pcur->lsb) + tmp_off = *icur - pcur->lsb; + else + tmp_off = pcur->lsb - *icur; + + acc_off += tmp_off * acc_wid; + acc_wid *= pcur->width(); + + } while (icur != indices.begin()); + } + + return acc_off; } bool NetNet::sb_to_slice(const list&indices, long sb, long&loff, unsigned long&lwid) const diff --git a/netlist.h b/netlist.h index 42f31050e..36f531dac 100644 --- a/netlist.h +++ b/netlist.h @@ -653,7 +653,7 @@ class NetNet : public NetObj { reg/wire/whatever. Note that a canonical index of a multi-dimensioned packed array is a single dimension. For example, "reg [4:1][3:0]..." has the canonical dimension - [15:0] and the sb_to_idx) method will convert [2][2] to + [15:0] and the sb_to_idx() method will convert [2][2] to the canonical index [6]. */ long sb_to_idx(const std::list&prefix, long sb) const; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 24fd5bdb4..3cddd2ab6 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1288,11 +1288,14 @@ static void show_signal(ivl_signal_t net) for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) { ivl_nexus_t nex = ivl_signal_nex(net, idx); + unsigned dim; - fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] " - " ", - type, sign, port, data_type, - ivl_signal_msb(net), ivl_signal_lsb(net), + fprintf(out, " %s %s %s%s", type, sign, port, data_type); + for (dim = 0 ; dim < ivl_signal_packed_dimensions(net) ; dim += 1) { + fprintf(out, "[%d:%d]", ivl_signal_packed_msb(net,dim), + ivl_signal_packed_lsb(net,dim)); + } + fprintf(out, " %s[word=%u, adr=%d] ", ivl_signal_basename(net), idx, ivl_signal_array_base(net)+idx, ivl_signal_width(net), diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 24b0e98dc..edb29b5e7 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -425,8 +425,17 @@ const char*draw_input_from_net(ivl_nexus_t nex) */ static void draw_reg_in_scope(ivl_signal_t sig) { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb; + int lsb; + if (ivl_signal_packed_dimensions(sig) > 1) { + // FIX ME: Improve this when vvp becomes aware of packed + // arrays. + msb = ivl_signal_width(sig) - 1; + lsb = 0; + } else { + msb = ivl_signal_msb(sig); + lsb = ivl_signal_lsb(sig); + } const char*datatype_flag = ivl_signal_integer(sig) ? "/i" : ivl_signal_signed(sig)? "/s" : ""; From 6eeef8311f23f0ae2f0dab6397a836ef31254cfe Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 Feb 2012 10:13:20 -0800 Subject: [PATCH 48/88] Handle indexed bit select of packed arrays. This handles a few cases where the non-constant bit selects are in the final index. This doesn't handle all the cases of packed arrays, but it handles some common cases. --- elab_expr.cc | 3 +-- elab_lval.cc | 2 +- netmisc.cc | 28 +++++++++++++++++++++++----- netmisc.h | 7 ++++++- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index f886e7197..d7d6c35de 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3514,8 +3514,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - assert(sig_packed.size() == 1); - mux = normalize_variable_base(mux, sig_packed, 1, true); + mux = normalize_variable_bit_base(prefix_indices, mux, net->sig()); NetESelect*ss = new NetESelect(net, mux, 1); ss->set_line(*this); diff --git a/elab_lval.cc b/elab_lval.cc index cf1aecb8b..b34143a80 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -408,7 +408,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select // expression. - mux = normalize_variable_base(mux, reg->packed_dims(), 1, true); + mux = normalize_variable_bit_base(prefix_indices, mux, reg); lv->set_part(mux, 1); } else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) { diff --git a/netmisc.cc b/netmisc.cc index c6e94e881..d4285c82e 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -239,10 +239,13 @@ static unsigned num_bits(long arg) /* * This routine generates the normalization expression needed for a variable - * bit select or a variable base expression for an indexed part select. + * bit select or a variable base expression for an indexed part + * select. This function doesn't actually look at the variable + * dimensions, it just does the final calculation using msb/lsb of the + * last slice, and the off of the slice in the variable. */ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, - unsigned long wid, bool is_up) + unsigned long wid, bool is_up, long soff) { long offset = lsb; @@ -275,13 +278,13 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, base = tmp; } /* Normalize the expression. */ - base = make_sub_expr(offset, base); + base = make_sub_expr(offset+soff, base); } else { /* Correct the offset if needed. */ if (!is_up) offset += wid - 1; /* If the offset is zero then just return the base (index) * expression. */ - if (offset == 0) return base; + if ((soff-offset) == 0) return base; /* Calculate the space needed for the offset. */ unsigned min_wid = num_bits(-offset); /* We need enough space for the larger of the offset or the @@ -304,7 +307,7 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, base = tmp; } /* Normalize the expression. */ - base = make_add_expr(base, -offset); + base = make_add_expr(base, soff-offset); } return base; @@ -325,6 +328,21 @@ NetExpr *normalize_variable_base(NetExpr *base, return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); } +NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, + const NetNet*reg) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size()+1 == packed_dims.size()); + + // Get the canonical offset of the slice within which we are + // addressing. We need that address as a slice offset to + // calculate the proper complete address + const NetNet::range_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.lsb); + + return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); +} + NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, const NetNet*reg, unsigned long&lwid) { diff --git a/netmisc.h b/netmisc.h index 91d1fcfd9..45b9238c2 100644 --- a/netmisc.h +++ b/netmisc.h @@ -99,10 +99,15 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); * the provided vector/array information. */ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, - unsigned long wid, bool is_up); + unsigned long wid, bool is_up, + long slice_off =0); extern NetExpr*normalize_variable_base(NetExpr *base, const list&dims, unsigned long wid, bool is_up); + +extern NetExpr*normalize_variable_bit_base(const list&indices, NetExpr *base, + const NetNet*reg); + extern NetExpr*normalize_variable_slice_base(const list&indices, NetExpr *base, const NetNet*reg, unsigned long&lwid); extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, From c1b73c83f49cf555ee8cba1edb33b5e6e35334b9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 Feb 2012 11:16:31 -0800 Subject: [PATCH 49/88] Respond better to some error/sorry situations. --- elab_expr.cc | 8 +++++++- elab_lval.cc | 9 ++++++++- netmisc.cc | 8 ++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d7d6c35de..4bffc326e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3293,6 +3293,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, return ss; } + if (net->sig()->packed_dims().size() > 1) { + cerr << get_fileline() << ": sorry: Indexed part select of packed arrays not supported here." << endl; + des->errors += 1; + return net; + } + base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true); NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP); @@ -3551,7 +3557,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, list prefix_indices; bool rc = evaluate_index_prefix(des, scope, prefix_indices, path_.back().index); - ivl_assert(*this, rc); + if (!rc) return 0; // If this is a part select of a signal, then make a new // temporary signal that is connected to just the diff --git a/elab_lval.cc b/elab_lval.cc index b34143a80..95c0167c6 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -359,7 +359,7 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, { listprefix_indices; bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); - ivl_assert(*this, rc); + if (!rc) return false; const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -597,6 +597,13 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } } } else { + if (reg->packed_dims().size() > 1) { + cerr << get_fileline() << ": sorry: " + << "Indexed part select of packed arrays not supported nere." << endl; + des->errors += 1; + return false; + } + /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { base = normalize_variable_base(base, reg->packed_dims(), diff --git a/netmisc.cc b/netmisc.cc index d4285c82e..8a08a48ff 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -937,13 +937,13 @@ bool evaluate_index_prefix(Design*des, NetScope*scope, assert(icur != indices.end()); assert(icur->sel == index_component_t::SEL_BIT); NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true); - ivl_assert(*icur->msb, texpr); + long tmp; - if (!eval_as_long(tmp, texpr)) { + if (texpr == 0 || !eval_as_long(tmp, texpr)) { cerr << icur->msb->get_fileline() << ": error: " - "Array index expressions must be constant." << endl; + "Array index expressions must be constant here." << endl; des->errors += 1; - return 0; + return false; } prefix_indices .push_back(tmp); From 5e067bd6517d0a2ab0c6c2d7b8b9318f37967dc3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 Feb 2012 12:03:43 -0800 Subject: [PATCH 50/88] Handle constant indexed part selects. --- elab_expr.cc | 22 ++++++++++++++-------- elab_lval.cc | 7 ++++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 4bffc326e..79783a58f 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3238,26 +3238,32 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetExpr*ex; if (base_c->value().is_defined()) { long lsv = base_c->value().as_long(); + long offset = 0; + // Get the signal range. + const list&packed = net->sig()->packed_dims(); + ivl_assert(*this, packed.size() == prefix_indices.size()+1); + + // We want the last range, which is where we work. + const NetNet::range_t&rng = packed.back(); + if (rng.msb < rng.lsb) { + offset = -wid + 1; + } + + long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv); // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sig()->sb_to_idx(prefix_indices, lsv) == 0 && - wid == net->vector_width()) { + if (rel_base == 0 && wid == net->vector_width()) { delete base; net->cast_signed(false); return net; } - long offset = 0; - if (net->msi() < net->lsi()) { - offset = -wid + 1; - } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset)); + ex = new NetEConst(verinum(rel_base + offset)); if (warn_ob_select) { - long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset; if (rel_base < 0) { cerr << get_fileline() << ": warning: " << net->name(); diff --git a/elab_lval.cc b/elab_lval.cc index 95c0167c6..8171d5b0c 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -543,11 +543,12 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, if (base_c->value().is_defined()) { long lsv = base_c->value().as_long(); long offset = 0; - // This is a work-around for limited dimenions support. + // Get the signal range. const list&packed = reg->packed_dims(); - ivl_assert(*this, packed.size() == 1); - const NetNet::range_t&rng = packed.back(); + ivl_assert(*this, packed.size() == prefix_indices.size()+1); + // We want the last range, which is where we work. + const NetNet::range_t&rng = packed.back(); if (((rng.msb < rng.lsb) && use_sel == index_component_t::SEL_IDX_UP) || ((rng.msb > rng.lsb) && From 391073a750400b32f028fbcd5f82ed7048a70e25 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 12 Feb 2012 13:21:30 -0800 Subject: [PATCH 51/88] Update __vpiNamedEvent to remove struct and remove extra class statements The clang compiler does not like using struct to reference a class object. This patch removes all the struct keywords for __vpiNamedEvent objects since they are now a class and can be called without a struct/class qualifier. This patch also removes all the extra class qualifiers from the rest of the source code. --- functor.cc | 36 ++++++++++++++++++------------------ synth.cc | 18 +++++++++--------- synth2.cc | 6 +++--- vvp/array.cc | 2 +- vvp/compile.cc | 10 +++++----- vvp/event.cc | 14 +++++++------- vvp/sfunc.cc | 2 +- vvp/stop.cc | 6 +++--- vvp/vpi_callback.cc | 6 ++++-- vvp/vpi_const.cc | 6 +++--- vvp/vpi_event.cc | 2 +- vvp/vpi_scope.cc | 2 +- vvp/vpi_tasks.cc | 2 +- vvp/vthread.cc | 8 ++++---- vvp/vvp_net.cc | 10 +++++----- 15 files changed, 66 insertions(+), 64 deletions(-) diff --git a/functor.cc b/functor.cc index 6d5bcebb0..8e128dbe5 100644 --- a/functor.cc +++ b/functor.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,71 +28,71 @@ functor_t::~functor_t() { } -void functor_t::event(class Design*, class NetEvent*) +void functor_t::event(Design*, NetEvent*) { } -void functor_t::signal(class Design*, class NetNet*) +void functor_t::signal(Design*, NetNet*) { } -void functor_t::process(class Design*, class NetProcTop*) +void functor_t::process(Design*, NetProcTop*) { } -void functor_t::lpm_abs(class Design*, class NetAbs*) +void functor_t::lpm_abs(Design*, NetAbs*) { } -void functor_t::lpm_add_sub(class Design*, class NetAddSub*) +void functor_t::lpm_add_sub(Design*, NetAddSub*) { } -void functor_t::lpm_compare(class Design*, class NetCompare*) +void functor_t::lpm_compare(Design*, NetCompare*) { } -void functor_t::lpm_const(class Design*, class NetConst*) +void functor_t::lpm_const(Design*, NetConst*) { } -void functor_t::lpm_divide(class Design*, class NetDivide*) +void functor_t::lpm_divide(Design*, NetDivide*) { } -void functor_t::lpm_literal(class Design*, class NetLiteral*) +void functor_t::lpm_literal(Design*, NetLiteral*) { } -void functor_t::lpm_modulo(class Design*, class NetModulo*) +void functor_t::lpm_modulo(Design*, NetModulo*) { } -void functor_t::lpm_ff(class Design*, class NetFF*) +void functor_t::lpm_ff(Design*, NetFF*) { } -void functor_t::lpm_logic(class Design*, class NetLogic*) +void functor_t::lpm_logic(Design*, NetLogic*) { } -void functor_t::lpm_mult(class Design*, class NetMult*) +void functor_t::lpm_mult(Design*, NetMult*) { } -void functor_t::lpm_mux(class Design*, class NetMux*) +void functor_t::lpm_mux(Design*, NetMux*) { } -void functor_t::lpm_pow(class Design*, class NetPow*) +void functor_t::lpm_pow(Design*, NetPow*) { } -void functor_t::sign_extend(class Design*, class NetSignExtend*) +void functor_t::sign_extend(Design*, NetSignExtend*) { } -void functor_t::lpm_ureduce(class Design*, class NetUReduce*) +void functor_t::lpm_ureduce(Design*, NetUReduce*) { } diff --git a/synth.cc b/synth.cc index 98d992098..0617bae76 100644 --- a/synth.cc +++ b/synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -114,12 +114,12 @@ class synth_f : public functor_t { public: synth_f() { top_ = NULL; } - void process(class Design*, class NetProcTop*); + void process(Design*, NetProcTop*); private: - void proc_always_(class Design*); - void proc_initial_(class Design*); - void proc_final_(class Design*); + void proc_always_(Design*); + void proc_initial_(Design*); + void proc_final_(Design*); NetProcTop*top_; }; @@ -129,7 +129,7 @@ class synth_f : public functor_t { * Look at a process, and divide the problem into always and initial * threads. */ -void synth_f::process(class Design*des, class NetProcTop*top) +void synth_f::process(Design*des, NetProcTop*top) { top_ = top; switch (top->type()) { @@ -145,19 +145,19 @@ void synth_f::process(class Design*des, class NetProcTop*top) } } -void synth_f::proc_always_(class Design*des) +void synth_f::proc_always_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } -void synth_f::proc_initial_(class Design*des) +void synth_f::proc_initial_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } -void synth_f::proc_final_(class Design*des) +void synth_f::proc_final_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); diff --git a/synth2.cc b/synth2.cc index 3a4b5367c..9adc21f5d 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2012 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 @@ -900,7 +900,7 @@ bool NetProcTop::synth_sync(Design*des) class synth2_f : public functor_t { public: - void process(class Design*, class NetProcTop*); + void process(Design*, NetProcTop*); private: }; @@ -910,7 +910,7 @@ class synth2_f : public functor_t { * Look at a process. If it is asynchronous, then synthesize it as an * asynchronous process and delete the process itself for its gates. */ -void synth2_f::process(class Design*des, class NetProcTop*top) +void synth2_f::process(Design*des, NetProcTop*top) { if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0) return; diff --git a/vvp/array.cc b/vvp/array.cc index 78d2e54d2..463458380 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -104,7 +104,7 @@ struct __vpiArray : public __vpiHandle { vvp_realarray_t *valsr; struct __vpiArrayWord*vals_words; - class vvp_fun_arrayport*ports_; + vvp_fun_arrayport*ports_; struct __vpiCallback *vpi_callbacks; bool signed_flag; bool swap_addr; diff --git a/vvp/compile.cc b/vvp/compile.cc index 89fe73717..955dc5425 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -342,14 +342,14 @@ vvp_net_t* vvp_net_lookup(const char*label) * this call is its last chance. If it cannot complete the operation, * it must print an error message and return false. */ -static class resolv_list_s*resolv_list = 0; +static resolv_list_s*resolv_list = 0; resolv_list_s::~resolv_list_s() { free(label_); } -void resolv_submit(class resolv_list_s*cur) +void resolv_submit(resolv_list_s*cur) { if (cur->resolve()) { delete cur; @@ -636,13 +636,13 @@ void compile_cleanup(void) } do { - class resolv_list_s *res = resolv_list; + resolv_list_s *res = resolv_list; resolv_list = 0x0; last = nerrs == lnerrs; lnerrs = nerrs; nerrs = 0; while (res) { - class resolv_list_s *cur = res; + resolv_list_s *cur = res; res = res->next; if (cur->resolve(last)) delete cur; diff --git a/vvp/event.cc b/vvp/event.cc index 81fc84bf7..8797f64f3 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -71,7 +71,7 @@ bool evctl::dec_and_run() return ecount_ == 0; } -evctl_real::evctl_real(class __vpiHandle*handle, double value, +evctl_real::evctl_real(__vpiHandle*handle, double value, unsigned long ecount) :evctl(ecount) { @@ -88,7 +88,7 @@ void evctl_real::run_run() vpi_put_value(handle_, &val, 0, vpiNoDelay); } -void schedule_evctl(class __vpiHandle*handle, double value, +void schedule_evctl(__vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount) { // Get the functor we are going to wait on. @@ -655,7 +655,7 @@ void vvp_fun_event_or_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } } -vvp_named_event::vvp_named_event(class __vpiHandle*h) +vvp_named_event::vvp_named_event(__vpiHandle*h) { handle_ = h; } @@ -664,7 +664,7 @@ vvp_named_event::~vvp_named_event() { } -vvp_named_event_sa::vvp_named_event_sa(class __vpiHandle*h) +vvp_named_event_sa::vvp_named_event_sa(__vpiHandle*h) : vvp_named_event(h), threads_(0) { } @@ -693,7 +693,7 @@ void vvp_named_event_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, obj->run_vpi_callbacks(); } -vvp_named_event_aa::vvp_named_event_aa(class __vpiHandle*h) +vvp_named_event_aa::vvp_named_event_aa(__vpiHandle*h) : vvp_named_event(h) { context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); @@ -853,9 +853,9 @@ void compile_named_event(char*label, char*name) } #ifdef CHECK_WITH_VALGRIND -void named_event_delete(class __vpiHandle*handle) +void named_event_delete(__vpiHandle*handle) { - struct __vpiNamedEvent *obj = (struct __vpiNamedEvent *) handle; + __vpiNamedEvent *obj = (__vpiNamedEvent *) handle; while (obj->callbacks) { struct __vpiCallback*tmp = obj->callbacks->next; diff --git a/vvp/sfunc.cc b/vvp/sfunc.cc index 1a00ab1d3..9afb148ea 100644 --- a/vvp/sfunc.cc +++ b/vvp/sfunc.cc @@ -74,7 +74,7 @@ void sfunc_core::recv_vec4_from_inputs(unsigned port) void sfunc_core::recv_real_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - class __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); + __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); assert(obj); obj->value = value_r(port); diff --git a/vvp/stop.cc b/vvp/stop.cc index 1313d9700..647a8a5da 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -74,7 +74,7 @@ static bool interact_flag = true; static void cmd_call(unsigned argc, char*argv[]) { - class __vpiHandle**table; + __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -212,7 +212,7 @@ static void cmd_help(unsigned, char*[]); static void cmd_list(unsigned, char*[]) { - class __vpiHandle**table; + __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -314,7 +314,7 @@ static void cmd_push(unsigned argc, char* argv[]) { for (unsigned idx = 1 ; idx < argc ; idx += 1) { - class __vpiHandle**table; + __vpiHandle**table; unsigned ntable; struct __vpiScope*child = 0; diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 5b05d48b4..3dd441caf 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -49,8 +49,10 @@ * event. This member is only used for things like cbReadOnlySync. */ +class sync_callback; + struct sync_cb : public vvp_gen_event_s { - class sync_callback*handle; + sync_callback*handle; bool sync_flag; ~sync_cb () { } @@ -244,7 +246,7 @@ static value_callback* make_value_change(p_cb_data data) break; case vpiNamedEvent: - struct __vpiNamedEvent*nev; + __vpiNamedEvent*nev; nev = dynamic_cast<__vpiNamedEvent*>(data->obj); nev->add_vpi_callback(obj); break; diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 532fb4424..f75d540b7 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -240,7 +240,7 @@ __vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) vpiHandle vpip_make_string_const(char*text, bool persistent_flag) { - class __vpiStringConst*obj; + __vpiStringConst*obj; obj = persistent_flag? new __vpiStringConst(text) : new __vpiStringConstTEMP(text); @@ -314,7 +314,7 @@ vpiHandle __vpiStringParam::vpi_handle(int code) vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { - class __vpiStringParam*obj = new __vpiStringParam(text, name); + __vpiStringParam*obj = new __vpiStringParam(text, name); obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; @@ -649,7 +649,7 @@ void __vpiRealConst::vpi_get_value(p_vpi_value val) vpiHandle vpip_make_real_const(double value) { - class __vpiRealConst*obj = new __vpiRealConst(value); + __vpiRealConst*obj = new __vpiRealConst(value); return obj; } diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 1bd3032fc..3b650dc91 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -71,7 +71,7 @@ vpiHandle __vpiNamedEvent::vpi_handle(int code) vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { - struct __vpiNamedEvent*obj = new __vpiNamedEvent(vpip_peek_current_scope(), name); + __vpiNamedEvent*obj = new __vpiNamedEvent(vpip_peek_current_scope(), name); obj->funct = funct; diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 6b45e8307..a93e2aa0a 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -41,7 +41,7 @@ vpiHandle vpip_make_root_iterator(void) vpip_root_table_ptr, false); } -void vpip_make_root_iterator(class __vpiHandle**&table, unsigned&ntable) +void vpip_make_root_iterator(__vpiHandle**&table, unsigned&ntable) { table = vpip_root_table_ptr; ntable = vpip_root_table_cnt; diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 59750325e..9c6029649 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -733,7 +733,7 @@ static void cleanup_vpi_call_args(unsigned argc, vpiHandle*argv) * vbit is also a non-zero value, the address in thread space of the result. */ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, - class vvp_net_t*fnet, + vvp_net_t*fnet, bool func_as_task_err, bool func_as_task_warn, unsigned argc, vpiHandle*argv, long file_idx, long lineno) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 0e10fe99f..86e1d44ff 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1173,7 +1173,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - class __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1192,7 +1192,7 @@ bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - class __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1206,7 +1206,7 @@ bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t cp) { assert(thr->event != 0); unsigned index = cp->bit_idx[0]; - class __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; // If the count is zero then just put the value. if (thr->ecount == 0) { @@ -3184,7 +3184,7 @@ bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t cp) bool of_LOAD_WR(vthread_t thr, vvp_code_t cp) { - class __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index aadaa61c9..569f83ba7 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -449,7 +449,7 @@ int edge(vvp_bit4_t from, vvp_bit4_t to) void vvp_send_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&val) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -461,7 +461,7 @@ void vvp_send_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&val) void vvp_send_real(vvp_net_ptr_t ptr, double val, vvp_context_t context) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -473,7 +473,7 @@ void vvp_send_real(vvp_net_ptr_t ptr, double val, vvp_context_t context) void vvp_send_long(vvp_net_ptr_t ptr, long val) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -486,7 +486,7 @@ void vvp_send_long(vvp_net_ptr_t ptr, long val) void vvp_send_long_pv(vvp_net_ptr_t ptr, long val, unsigned base, unsigned wid) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) From 77f168cf2850a9f8919322fff3d86d65d61501ba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 Feb 2012 14:52:47 -0800 Subject: [PATCH 52/88] Support non-constant indexed part select of packed arrays. --- elab_expr.cc | 11 +++++------ elab_lval.cc | 16 +++++----------- netmisc.cc | 16 ++++++++++++++++ netmisc.h | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 79783a58f..63105d7f8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3299,13 +3299,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, return ss; } - if (net->sig()->packed_dims().size() > 1) { - cerr << get_fileline() << ": sorry: Indexed part select of packed arrays not supported here." << endl; - des->errors += 1; - return net; - } - base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true); + ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size()); + + // Convert the non-constant part select index expression into + // an expression that returns a canonical base. + base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, true); NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP); ss->set_line(*this); diff --git a/elab_lval.cc b/elab_lval.cc index 8171d5b0c..6376c05e1 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -598,22 +598,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } } } else { - if (reg->packed_dims().size() > 1) { - cerr << get_fileline() << ": sorry: " - << "Indexed part select of packed arrays not supported nere." << endl; - des->errors += 1; - return false; - } - + ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size()); /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { - base = normalize_variable_base(base, reg->packed_dims(), - wid, true); + base = normalize_variable_part_base(prefix_indices, base, + reg, wid, true); sel_type = IVL_SEL_IDX_UP; } else { // This is assumed to be a SEL_IDX_DO. - base = normalize_variable_base(base, reg->packed_dims(), - wid, false); + base = normalize_variable_part_base(prefix_indices, base, + reg, wid, false); sel_type = IVL_SEL_IDX_DOWN; } } diff --git a/netmisc.cc b/netmisc.cc index 8a08a48ff..504b58dcb 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -343,6 +343,22 @@ NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); } +NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, + const NetNet*reg, + unsigned long wid, bool is_up) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size()+1 == packed_dims.size()); + + // Get the canonical offset of the slice within which we are + // addressing. We need that address as a slice offset to + // calculate the proper complete address + const NetNet::range_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.lsb); + + return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off); +} + NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, const NetNet*reg, unsigned long&lwid) { diff --git a/netmisc.h b/netmisc.h index 45b9238c2..5e96d3c8d 100644 --- a/netmisc.h +++ b/netmisc.h @@ -105,11 +105,43 @@ extern NetExpr*normalize_variable_base(NetExpr *base, const list&dims, unsigned long wid, bool is_up); +/* + * Calculate a canonicalizing expression for a bit select, when the + * base expression is the last index of an otherwise complete bit + * select. For example: + * reg [3:0][7:0] foo; + * ... foo[1][x] ... + * base is (x) and the generated expression will be (x+8). + */ extern NetExpr*normalize_variable_bit_base(const list&indices, NetExpr *base, const NetNet*reg); +/* + * This is similar to normalize_variable_bit_base, but the tail index + * it a base and width, instead of a bit. This is used for handling + * indexed part selects: + * reg [3:0][7:0] foo; + * ... foo[1][x +: 2] + * base is (x), wid input is (2), and is_up is (true). The output + * expression is (x+8). + */ +extern NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, + const NetNet*reg, + unsigned long wid, bool is_up); +/* + * Calculate a canonicalizing expression for a slice select. The + * indices array is less then needed to fully address a bit, so the + * result is a slice of the packed array. The return value is an + * expression that gets to the base of the slice, and (lwid) becomes + * the width of the slice, in bits. For example: + * reg [4:1][7:0] foo + * ...foo[x]... + * base is (x) and the generated expression will be (x*8 - 8), with + * lwid set to (8). + */ extern NetExpr*normalize_variable_slice_base(const list&indices, NetExpr *base, const NetNet*reg, unsigned long&lwid); + extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, unsigned count); From fec1c1efde0c393de6aa5610b7839528380d6802 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 12 Feb 2012 16:19:58 -0800 Subject: [PATCH 53/88] Handle r-value constant slice selects. --- elab_expr.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 63105d7f8..2de3748e5 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3454,6 +3454,29 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, } long msv = msc->value().as_long(); + + const list& sig_packed = net->sig()->packed_dims(); + if (prefix_indices.size()+2 <= sig_packed.size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // ... x[2] ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + unsigned long lwid; + long idx; + rc = net->sig()->sb_to_slice(prefix_indices, msv, idx, lwid); + + // Make an expression out of the index + NetEConst*idx_c = new NetEConst(verinum(idx)); + idx_c->set_line(*net); + + NetESelect*res = new NetESelect(net, idx_c, lwid); + res->set_line(*net); + return res; + } + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { From 0aefcf9b484746f3cd8be94c0152266a02d10b21 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Thu, 16 Feb 2012 09:37:51 -0800 Subject: [PATCH 54/88] Trivial fixes to grammar, spelling, whitespace --- ivl_target.h | 2 +- vpi/vhdl_table.c | 2 +- vvp/array.cc | 2 +- vvp/vpi_const.cc | 4 ++-- vvp/vvp_net_sig.cc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ivl_target.h b/ivl_target.h index eda6861f9..32eb0e307 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -2013,7 +2013,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * is the compressed operator used it statements like this: * foo += * The ivl_stmt_opcode() returns null (0) if this is not a compressed - * assignment statment. + * assignment statement. * * - IVL_ST_CASSIGN * This reflects a procedural continuous assignment to an l-value. The diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index e2bb3e8a1..694522119 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -104,7 +104,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_register_cb(&cb); vpi_put_userdata(sys, mon); - /* Check that there are no more then one argument. */ + /* Check that there is no more than one argument. */ arg = vpi_scan(argv); if (arg != 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), diff --git a/vvp/array.cc b/vvp/array.cc index 463458380..958c83001 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -955,7 +955,7 @@ static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) vpip_vec4_get_value(tmp, obj->part_wid, parent->signed_flag, vp); } } - + void array_set_word(vvp_array_t arr, unsigned address, unsigned part_off, diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index f75d540b7..2b95fe644 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -660,7 +660,7 @@ struct __vpiRealParam : public __vpiRealConst { int vpi_get(int code); char*vpi_get_str(int code); vpiHandle vpi_handle(int code); - + struct __vpiScope* scope; unsigned file_idx; unsigned lineno; @@ -713,7 +713,7 @@ vpiHandle __vpiRealParam::vpi_handle(int code) return 0; } } - + vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index f0f7423ff..ce47a0959 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -46,7 +46,7 @@ template vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(const T&val if (!test_force_mask_is_zero()) { // Some bits are being forced. Go through the // force_mask_ and force value to see which bits are - // propogated and which are kept from the forced + // propagated and which are kept from the forced // value. Update the filter with the filtered result and // return REPL to indicate that some bits have changed, // or STOP if no bits change. From 5880a3ad8f7a72e7700f94e885d103ec4b8d9736 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 18 Feb 2012 10:02:54 -0800 Subject: [PATCH 55/88] Parse program blocks / Fix module end-name syntax. --- parse.y | 112 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 34 deletions(-) diff --git a/parse.y b/parse.y index 149f19af7..49499db6a 100644 --- a/parse.y +++ b/parse.y @@ -460,7 +460,7 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable real_variable +%type register_variable net_variable real_variable endname_opt %type register_variable_list net_variable_list %type real_variable_list list_of_identifiers %type list_of_port_identifiers @@ -535,6 +535,7 @@ static void current_task_set_statement(vector*s) %type specify_edge_path specify_edge_path_decl %type atom2_type +%type module_start module_end %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ @@ -2680,40 +2681,83 @@ local_timeunit_prec_decl section, with optional ports, then an optional list of module items, and finally an end marker. */ -module : attribute_list_opt module_start IDENTIFIER - { pform_startmodule($3, @2.text, @2.first_line, $1); } - module_parameter_port_list_opt - module_port_list_opt - module_attribute_foreign ';' - { pform_module_set_ports($6); } - local_timeunit_prec_decl_opt - { have_timeunit_decl = true; // Every thing past here is - have_timeprec_decl = true; // a check! - pform_check_timeunit_prec(); - } - module_item_list_opt - K_endmodule - { Module::UCDriveType ucd; - switch (uc_drive) { - case UCD_NONE: - default: - ucd = Module::UCD_NONE; - break; - case UCD_PULL0: - ucd = Module::UCD_PULL0; - break; - case UCD_PULL1: - ucd = Module::UCD_PULL1; - break; - } - pform_endmodule($3, in_celldefine, ucd); - delete[]$3; - have_timeunit_decl = false; // We will allow decls again. - have_timeprec_decl = false; - } - ; +module + : attribute_list_opt module_start IDENTIFIER + { pform_startmodule($3, @2.text, @2.first_line, $1); } + module_parameter_port_list_opt + module_port_list_opt + module_attribute_foreign ';' + { pform_module_set_ports($6); } + local_timeunit_prec_decl_opt + { have_timeunit_decl = true; // Every thing past here is + have_timeprec_decl = true; // a check! + pform_check_timeunit_prec(); + } + module_item_list_opt + module_end endname_opt + { Module::UCDriveType ucd; + // The lexor detected `unconnected_drive directives and + // marked what it found in the uc_drive variable. Use that + // to generate a UCD flag for the module. + switch (uc_drive) { + case UCD_NONE: + default: + ucd = Module::UCD_NONE; + break; + case UCD_PULL0: + ucd = Module::UCD_PULL0; + break; + case UCD_PULL1: + ucd = Module::UCD_PULL1; + break; + } + // Check that program/endprogram and module/endmodule + // keywords match. + if ($2 != $13) { + switch ($2) { + case K_module: + yyerror(@13, "error: module not closed by endmodule."); + break; + case K_program: + yyerror(@13, "error: program not closed by endprogram."); + break; + default: + break; + } + } + if ($14 && (strcmp($3,$14) != 0)) { + yyerror(@14, "error: End name doesn't match module/program name"); + } + if ($2 == K_program) { + yyerror(@2, "sorry: Program blocks not supported yet."); + } + pform_endmodule($3, in_celldefine, ucd); + delete[]$3; + if ($14) delete[]$14; + have_timeunit_decl = false; // We will allow decls again. + have_timeprec_decl = false; + } + ; -module_start : K_module | K_macromodule ; + /* Modules start with module/macromodule or program keyword, and end + with the endmodule or endprogram keyword. The syntax for modules + and programs is almost identical, so let semantics sort out the + differences. */ +module_start + : K_module { $$ = K_module; } + | K_macromodule { $$ = K_module; } + | K_program { $$ = K_program; } + ; + +module_end + : K_endmodule { $$ = K_module; } + | K_endprogram { $$ = K_program; } + ; + +endname_opt + : ':' IDENTIFIER { $$ = $2; } + | { $$ = 0; } + ; module_attribute_foreign : K_PSTAR IDENTIFIER K_integer IDENTIFIER '=' STRING ';' K_STARP { $$ = 0; } From 8456252c0cbf00630f4f4a6521631a1f4824ff93 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 10:29:50 -0800 Subject: [PATCH 56/88] More class syntax Part of ongoing parser work to support SystemVerilog classes. --- parse.y | 662 ++++++++++++++++++++------------------------------ parse_misc.cc | 12 +- parse_misc.h | 2 +- pform.cc | 21 ++ pform.h | 7 + pform_types.h | 7 + 6 files changed, 306 insertions(+), 405 deletions(-) diff --git a/parse.y b/parse.y index 49499db6a..01a496634 100644 --- a/parse.y +++ b/parse.y @@ -49,8 +49,9 @@ static struct { ivl_variable_type_t var_type; bool sign_flag; list* range; + data_type_t* data_type; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, false, 0}; + IVL_VT_NO_TYPE, false, 0, 0}; /* The task and function rules need to briefly hold the pointer to the task/function that is currently in progress. */ @@ -106,7 +107,7 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { list*range = new list; @@ -447,8 +448,8 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number %type unsigned_signed_opt signed_unsigned_opt -%type K_packed_opt K_reg_opt -%type udp_reg_opt edge_operator automatic_opt +%type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt +%type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry @@ -472,7 +473,7 @@ static void current_task_set_statement(vector*s) %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign %type parameter_value_range parameter_value_ranges %type parameter_value_ranges_opt -%type value_range_expression +%type task_port_decl_expr_opt value_range_expression %type enum_name_list enum_name %type enum_data_type @@ -514,7 +515,7 @@ static void current_task_set_statement(vector*s) %type dimensions_opt dimensions %type net_type var_type net_type_opt %type gatetype switchtype -%type port_type +%type port_direction port_direction_opt %type primitive_type primitive_type_opt bit_logic %type parameter_value_opt @@ -573,6 +574,73 @@ source_file | source_file description ; +class_declaration /* IEEE1800-2005: A.1.2 */ + : K_virtual_opt K_class IDENTIFIER ';' + class_items_opt K_endclass endname_opt + { // Process a class + if ($7 && strcmp($3,$7)!=0) { + yyerror(@7, "error: Class end name doesn't match class name."); + delete[]$7; + } + yyerror(@2, "sorry: Class declarations not supported yet."); + } + ; + +class_items_opt + : class_items + | + ; + +class_items + : class_items class_item + | class_item + ; + +class_item /* IEEE1800-2005: A.1.8 */ + + /* class_constructor_declaration */ + : K_function K_new '(' task_port_decl_list_opt ')' ';' + K_endfunction endnew_opt + + /* Class properties... */ + + | data_type list_of_variable_decl_assignments ';' + + /* Here are some error matching rules to help recover from various + syntax errors within a class declaration. */ + + | K_function K_new error K_endfunction endnew_opt + { yyerror(@1, "error: I give up on this class constructor declaration."); + yyerrok; + } + + ; + +data_type /* IEEE1800-2005: A.2.2.1 */ + : struct_data_type + { $$ = $1; } + | enum_data_type + { $$ = $1; } + | atom2_type signed_unsigned_opt + { atom2_type_t*tmp = new atom2_type_t($1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | TYPE_IDENTIFIER + { $$ = $1; } + | K_string + { yyerror(@1, "sorry: String data type not supported."); + $$ = 0; + } + ; + +endnew_opt : ':' K_new | ; + +implicit_class_handle /* IEEE1800-2005: A.8.4 */ + : K_this + | K_super + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -703,11 +771,6 @@ block_item_decl if ($1) delete $1; } - | attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';' - { pform_set_integer_2atom($2, $3, $4); - if ($1) delete $1; - } - /* variable declarations. Note that data_type can be 0 if we are recovering from an error. */ @@ -782,21 +845,27 @@ block_item_decls_opt | ; -data_type - : struct_data_type - { $$ = $1; } - | enum_data_type - { $$ = $1; } - | TYPE_IDENTIFIER - { $$ = $1; } - ; - + /* Type declarations are parsed here. The rule actions call pform + functions that add the declaration to the current lexical scope. */ type_declaration : K_typedef data_type IDENTIFIER ';' { perm_string name = lex_strings.make($3); pform_set_typedef(name, $2); delete[]$3; } + + /* These are forward declarations... */ + + | K_typedef K_class IDENTIFIER ';' + { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + | K_typedef K_enum IDENTIFIER ';' + { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } + | K_typedef K_struct IDENTIFIER ';' + { yyerror(@1, "sorry: Struct forward declarations not supported yet.") } + | K_typedef K_union IDENTIFIER ';' + { yyerror(@1, "sorry: Union forward declarations not supported yet.") } + | K_typedef IDENTIFIER ';' + { yyerror(@1, "sorry: Class forward declarations not supported yet.") } ; /* The structure for an enumeration data type is the keyword "enum", @@ -2620,19 +2689,28 @@ atom2_type assignments. It is more limited than the general expr_primary rule to reflect the rules for assignment l-values. */ lpvalue - : hierarchy_identifier - { PEIdent*tmp = new PEIdent(*$1); - FILE_NAME(tmp, @1); - $$ = tmp; - delete $1; - } - | '{' expression_list_proper '}' - { PEConcat*tmp = new PEConcat(*$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } - ; + : hierarchy_identifier + { PEIdent*tmp = new PEIdent(*$1); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $1; + } + + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: implicit class handles (this/super) not supported."); + PEIdent*tmp = new PEIdent(*$3); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $3; + } + + | '{' expression_list_proper '}' + { PEConcat*tmp = new PEConcat(*$2); + FILE_NAME(tmp, @1); + delete $2; + $$ = tmp; + } + ; /* Continuous assignments have a list of individual assignments. */ @@ -2694,7 +2772,7 @@ module pform_check_timeunit_prec(); } module_item_list_opt - module_end endname_opt + module_end { Module::UCDriveType ucd; // The lexor detected `unconnected_drive directives and // marked what it found in the uc_drive variable. Use that @@ -2725,18 +2803,25 @@ module break; } } - if ($14 && (strcmp($3,$14) != 0)) { - yyerror(@14, "error: End name doesn't match module/program name"); - } if ($2 == K_program) { yyerror(@2, "sorry: Program blocks not supported yet."); } pform_endmodule($3, in_celldefine, ucd); delete[]$3; - if ($14) delete[]$14; have_timeunit_decl = false; // We will allow decls again. have_timeprec_decl = false; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($15 && (strcmp($3,$15) != 0)) { + yyerror(@15, "error: End name doesn't match module/program name"); + } + if ($15) delete[]$15; + } ; /* Modules start with module/macromodule or program keyword, and end @@ -2890,7 +2975,7 @@ module_item delete $4; } - | port_type unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' + | port_direction unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' { pform_set_port_type(@1, $5, $3, $2, $1); } @@ -2898,7 +2983,7 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | port_type net_type unsigned_signed_opt range_opt list_of_identifiers ';' + | port_direction net_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, $1, IVL_VT_NO_TYPE, 0, SR_BOTH); } @@ -2919,7 +3004,7 @@ module_item delete $5; } - | port_type K_wreal list_of_identifiers ';' + | port_direction K_wreal list_of_identifiers ';' { pform_makewire(@1, 0, true, $3, NetNet::WIRE, $1, IVL_VT_REAL, 0, SR_BOTH); } @@ -2940,7 +3025,7 @@ module_item yyerror(@2, "error: reg variables cannot be inouts."); } - | port_type unsigned_signed_opt range_opt delay3_opt error ';' + | port_direction unsigned_signed_opt range_opt delay3_opt error ';' { yyerror(@1, "error: Invalid variable list" " in port declaration."); if ($3) delete $3; @@ -3072,6 +3157,8 @@ module_item | attribute_list_opt K_analog analog_statement { pform_make_analog_behavior(@2, IVL_PR_ALWAYS, $3); } + | class_declaration + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -3080,7 +3167,7 @@ module_item statements in the task body. But we continue to accept it as an extension. */ - | K_task automatic_opt IDENTIFIER ';' + | K_task K_automatic_opt IDENTIFIER ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3098,7 +3185,7 @@ module_item delete $7; } - | K_task automatic_opt IDENTIFIER '(' + | K_task K_automatic_opt IDENTIFIER '(' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3117,7 +3204,7 @@ module_item delete $10; } - | K_task automatic_opt IDENTIFIER '(' ')' ';' + | K_task K_automatic_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); current_task = pform_push_task_scope(@1, $3, $2); } @@ -3137,7 +3224,7 @@ module_item delete $9; } - | K_task automatic_opt IDENTIFIER error K_endtask + | K_task K_automatic_opt IDENTIFIER error K_endtask { assert(current_task == 0); delete[]$3; @@ -3148,7 +3235,7 @@ module_item definitions in the func_body to take on the scope of the function instead of the module. */ - | K_function automatic_opt function_range_or_type_opt IDENTIFIER ';' + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -3175,7 +3262,7 @@ module_item delete[]$4; } - | K_function automatic_opt function_range_or_type_opt IDENTIFIER + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } @@ -3206,7 +3293,7 @@ module_item yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); } } - | K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction { /* */ if (current_function) { pform_pop_scope(); @@ -3347,11 +3434,6 @@ module_item { pform_set_timeprecision($2, true, true); } ; -automatic_opt - : K_automatic { $$ = true; } - | { $$ = false;} - ; - generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } generate_case_items @@ -3962,11 +4044,16 @@ port_reference_list } ; -port_type - : K_input { $$ = NetNet::PINPUT; } - | K_output { $$ = NetNet::POUTPUT; } - | K_inout { $$ = NetNet::PINOUT; } - ; +port_direction /* IEEE1800-2005 A.1.3 */ + : K_input { $$ = NetNet::PINPUT; } + | K_output { $$ = NetNet::POUTPUT; } + | K_inout { $$ = NetNet::PINOUT; } + ; + +port_direction_opt + : port_direction { $$ = $1; } + | { $$ = NetNet::PINPUT; } + ; range : '[' expression ':' expression ']' @@ -5024,24 +5111,8 @@ task_item ; task_port_item - : K_input K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINOUT, + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports($1, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, $3, $4, $5, @@ -5052,26 +5123,9 @@ task_port_item /* When the port is an integer, infer a signed vector of the integer shape. Generate a range ([31:0]) to make it work. */ - | K_input K_integer list_of_identifiers ';' + | port_direction K_integer list_of_identifiers ';' { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, range_stub, $3, @1.text, @1.first_line, true); $$ = tmp; @@ -5079,26 +5133,9 @@ task_port_item /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_time list_of_identifiers ';' + | port_direction K_time list_of_identifiers ';' { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, range_stub, $3, @1.text, @1.first_line); $$ = tmp; @@ -5106,31 +5143,13 @@ task_port_item /* Ports can be real or realtime. */ - | K_input real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - ; + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, + 0, $3, @1.text, @1.first_line); + $$ = tmp; + } + + ; task_item_list : task_item_list task_item @@ -5152,173 +5171,56 @@ task_item_list_opt task_port_decl - : K_input K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } + : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, $3, + $4, list_from_identifier($5), + @1.text, @1.first_line); + $$ = tmp; + } - | K_output K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_input bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_output bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::POUTPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_inout bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINOUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } + | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = $2; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports($1, $2, $3, + $4, list_from_identifier($5), + @1.text, @1.first_line); + $$ = tmp; + } /* Ports can be integer with a width of [31:0]. */ - | K_input K_integer IDENTIFIER + | port_direction_opt K_integer IDENTIFIER { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, + range_stub, + list_from_identifier($3), + @1.text, @1.first_line, true); $$ = tmp; } /* Ports can be time with a width of [63:0] (unsigned). */ - | K_input K_time IDENTIFIER + | port_direction_opt K_time IDENTIFIER { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = false; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, + svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, range_stub, list_from_identifier($3), @1.text, @1.first_line); @@ -5327,90 +5229,40 @@ task_port_decl /* Ports can be real or realtime. */ - | K_input real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } + | port_direction_opt real_or_realtime IDENTIFIER + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_REAL; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, + 0, list_from_identifier($3), + @1.text, @1.first_line); + $$ = tmp; + } - /* Ports can be 2-value atom types. */ - - | K_input atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; + | port_direction_opt data_type IDENTIFIER task_port_decl_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); + port_declaration_context.range = 0; + port_declaration_context.data_type = $2; + svector*tmp = pform_make_task_ports(@1, $1, $2, + list_from_identifier($3)); $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port default expressions not supported yet."); + delete $4; + } } - | K_output atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } + ; - | K_inout atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } -; +task_port_decl_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; task_port_decl_list_opt : task_port_decl_list { $$ = $1; } @@ -5418,40 +5270,40 @@ task_port_decl_list_opt ; task_port_decl_list - : task_port_decl_list ',' task_port_decl - { svector*tmp = new svector(*$1, *$3); - delete $1; - delete $3; - $$ = tmp; - } - | task_port_decl - { $$ = $1; } - | task_port_decl_list ',' IDENTIFIER - { svector*new_decl - = pform_make_task_ports( - port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3), - @3.text, @3.first_line); - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - | task_port_decl_list ',' - { - yyerror(@2, "error: NULL port declarations are not " - "allowed."); - } - | task_port_decl_list ';' - { - yyerror(@2, "error: ';' is an invalid port declaration " - "separator."); - } - ; - ; + : task_port_decl_list ',' task_port_decl + { svector*tmp = new svector(*$1, *$3); + delete $1; + delete $3; + $$ = tmp; + } + | task_port_decl + { $$ = $1; } + | task_port_decl_list ',' IDENTIFIER + { // The declaration is already parsed, apply it to IDENTIFIER + svector*new_decl; + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + assert(port_declaration_context.data_type); + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.data_type, + list_from_identifier($3)); + } else { + new_decl = pform_make_task_ports(port_declaration_context.port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + list_from_identifier($3), + @3.text, @3.first_line); + } + svector*tmp = new svector(*$1, *new_decl); + delete $1; + delete new_decl; + $$ = tmp; + } + | task_port_decl_list ',' + { yyerror(@2, "error: NULL port declarations are not allowed."); } + | task_port_decl_list ';' + { yyerror(@2, "error: ';' is an invalid port declaration separator."); } + ; udp_body : K_table { lex_start_table(); } @@ -5703,5 +5555,11 @@ udp_primitive } ; -K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; -K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; + /* Many keywords can be optional in the syntax, although their + presence is significant. This is a fairly common pattern so + collect those rules here. */ + +K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ; +K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; +K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; +K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/parse_misc.cc b/parse_misc.cc index ed631d0b3..241341564 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -20,6 +20,8 @@ # include "config.h" # include "parse_misc.h" +# include +# include # include extern const char*vl_file; @@ -42,10 +44,16 @@ void VLerror(const char*msg) cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl; } -void VLerror(const YYLTYPE&loc, const char*msg) +void VLerror(const YYLTYPE&loc, const char*msg, ...) { + va_list ap; + va_start(ap, msg); + + fprintf(stderr, "%s:%d: ", loc.text, loc.first_line); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + error_count += 1; - cerr << loc << ": " << msg << endl; based_size = 0; /* Clear the base information if we have an error. */ } diff --git a/parse_misc.h b/parse_misc.h index e9d642dfc..6d1aed925 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -56,7 +56,7 @@ extern YYLTYPE yylloc; */ extern int VLlex(); extern void VLerror(const char*msg); -extern void VLerror(const YYLTYPE&loc, const char*msg); +extern void VLerror(const YYLTYPE&loc, const char*msg, ...) __attribute__((format(printf,2,3))); #define yywarn VLwarn extern void VLwarn(const YYLTYPE&loc, const char*msg); diff --git a/pform.cc b/pform.cc index 9716ffdd9..4f349e9af 100644 --- a/pform.cc +++ b/pform.cc @@ -2193,6 +2193,22 @@ svector*pform_make_task_ports(NetNet::PortType pt, return res; } +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names) +{ + atom2_type_t*atype = dynamic_cast (vtype); + if (atype == 0) { + VLerror(loc, "sorry: Given type not supported here."); + return 0; + } + + list*range_tmp = make_range_from_width(atype->type_code); + return pform_make_task_ports(pt, IVL_VT_BOOL, atype->signed_flag, + range_tmp, names, loc.text, loc.first_line); +} + void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { @@ -2541,6 +2557,11 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list */ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names) { + if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { + pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names); + return; + } + if (struct_type_t*struct_type = dynamic_cast (data_type)) { pform_set_struct_type(struct_type, names); return; diff --git a/pform.h b/pform.h index b32ccce70..bc0c7115d 100644 --- a/pform.h +++ b/pform.h @@ -117,6 +117,8 @@ struct lgate { unsigned lineno; }; +extern std::list* make_range_from_width(uint64_t wid); + /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ extern void pform_bind_attributes(map&attributes, @@ -392,6 +394,11 @@ extern svector*pform_make_task_ports(NetNet::PortType pt, unsigned lineno, bool isint = false); +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names); + /* * These are functions that the outside-the-parser code uses the do diff --git a/pform_types.h b/pform_types.h index 354353dd4..047592edf 100644 --- a/pform_types.h +++ b/pform_types.h @@ -100,6 +100,13 @@ struct struct_type_t : public data_type_t { std::auto_ptr< list > members; }; +struct atom2_type_t : public data_type_t { + inline explicit atom2_type_t(int tc, bool flag) + : type_code(tc), signed_flag(flag) { } + int type_code; + bool signed_flag; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 6b4251626b17d9714d280381438f193fd21a76aa Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 17:31:15 -0800 Subject: [PATCH 57/88] Parse array literals / rearrange task declaration rules. --- lexor.lex | 2 +- parse.y | 573 ++++++++++++++++++++++++++++++-------------------- pform.cc | 11 +- pform.h | 5 +- pform_dump.cc | 10 + 5 files changed, 361 insertions(+), 240 deletions(-) diff --git a/lexor.lex b/lexor.lex index 259a8fcd1..b44d47166 100644 --- a/lexor.lex +++ b/lexor.lex @@ -191,7 +191,7 @@ TU [munpf] ">>>=" { return K_RSS_EQ; } "++" { return K_INCR; } "--" {return K_DECR; } - +"'{" { return K_LP; } /* Watch out for the tricky case of (*). Cannot parse this as "(*" and ")", but since I know that this is really ( * ), replace it diff --git a/parse.y b/parse.y index 01a496634..31d8fcd27 100644 --- a/parse.y +++ b/parse.y @@ -355,7 +355,7 @@ static void current_task_set_statement(vector*s) %token BASED_NUMBER DEC_NUMBER %token REALTIME %token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR -%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG +%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG /* K_CONTRIBUTE is <+, the contribution assign. */ %token K_CONTRIBUTE %token K_PO_POS K_PO_NEG K_POW @@ -473,13 +473,13 @@ static void current_task_set_statement(vector*s) %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign %type parameter_value_range parameter_value_ranges %type parameter_value_ranges_opt -%type task_port_decl_expr_opt value_range_expression +%type tf_port_item_expr_opt value_range_expression %type enum_name_list enum_name %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item task_port_decl task_port_decl_list task_port_decl_list_opt +%type task_port_item tf_port_item tf_port_list tf_port_list_opt %type function_item function_item_list %type port_name parameter_value_byname @@ -495,7 +495,7 @@ static void current_task_set_statement(vector*s) %type gate_instance_list %type hierarchy_identifier -%type expression expr_primary expr_mintypmax +%type assignment_pattern expression expr_primary expr_mintypmax %type lpvalue %type branch_probe_expression %type delay_value delay_value_simple @@ -511,7 +511,7 @@ static void current_task_set_statement(vector*s) %type struct_union_member_list %type struct_data_type -%type range range_opt +%type range range_opt variable_dimension %type dimensions_opt dimensions %type net_type var_type net_type_opt %type gatetype switchtype @@ -574,6 +574,21 @@ source_file | source_file description ; +assignment_pattern /* IEEE1800-2005: A.6.7.1 */ + : K_LP expression_list_proper '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + | K_LP '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + ; + class_declaration /* IEEE1800-2005: A.1.2 */ : K_virtual_opt K_class IDENTIFIER ';' class_items_opt K_endclass endname_opt @@ -599,13 +614,22 @@ class_items class_item /* IEEE1800-2005: A.1.8 */ /* class_constructor_declaration */ - : K_function K_new '(' task_port_decl_list_opt ')' ';' + : K_function K_new '(' tf_port_list_opt ')' ';' + statement_list_or_null K_endfunction endnew_opt + { yyerror(@1, "sorry: Class constructors not supported yet."); + yyerrok; + } /* Class properties... */ | data_type list_of_variable_decl_assignments ';' + + /* Class methods... */ + + | task_declaration + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -657,6 +681,297 @@ real_or_realtime | K_realtime ; + /* The task declaration rule matches the task declaration + header, then pushes the function scope. This causes the + definitions in the task_body to take on the scope of the task + instead of the module. */ + +task_declaration /* IEEE1800-2005: A.2.7 */ + + : K_task K_automatic_opt IDENTIFIER ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + task_item_list_opt + statement_or_null_list + K_endtask + { current_task->set_ports($6); + current_task_set_statement($7); + pform_pop_scope(); + current_task = 0; + delete[]$3; + if ($7->size() > 1 && !gn_system_verilog()) { + yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $7; + } + + | K_task K_automatic_opt IDENTIFIER '(' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + tf_port_list ')' ';' + block_item_decls_opt + statement_or_null_list + K_endtask + { current_task->set_ports($6); + current_task_set_statement($10); + pform_pop_scope(); + current_task = 0; + delete[]$3; + if ($10->size() > 1 && !gn_system_verilog()) { + yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $10; + } + + | K_task K_automatic_opt IDENTIFIER '(' ')' ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + block_item_decls_opt + statement_or_null_list + K_endtask + { current_task->set_ports(0); + current_task_set_statement($9); + pform_pop_scope(); + current_task = 0; + cerr << @3 << ": warning: task definition for \"" << $3 + << "\" has an empty port declaration list!" << endl; + delete[]$3; + if ($9->size() > 1 && !gn_system_verilog()) { + yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $9; + } + + | K_task K_automatic_opt IDENTIFIER error K_endtask + { + assert(current_task == 0); + delete[]$3; + } + + ; + + + /* These rules for tf_port_item are slightly expanded from the + strict rules in the LRM to help with LALR parsing. + + NOTE: Some of these rules should be folded into the "data_type" + variant which uses the data_type rule to match data type + declarations. That some rules do not use the data_type production + is a consequence of legacy. */ + +tf_port_item /* IEEE1800-2005: A.2.7 */ + + : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports(@5, $1, IVL_VT_LOGIC, $3, + $4, list_from_identifier($5)); + $$ = tmp; + if ($6) { + yyerror(@6, "sorry: Port variable dimensions not supported yet."); + delete $6; + } + if ($7) { + yyerror(@7, "sorry: Port default expressions not supported yet."); + delete $7; + } + } + + | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = $2; + port_declaration_context.sign_flag = $3; + delete port_declaration_context.range; + port_declaration_context.range = copy_range($4); + svector*tmp = pform_make_task_ports(@5, $1, $2, $3, + $4, list_from_identifier($5)); + $$ = tmp; + if ($6) { + yyerror(@6, "sorry: Port variable dimensions not supported yet."); + delete $6; + } + if ($7) { + yyerror(@7, "sorry: Port default expressions not supported yet."); + delete $7; + } + } + + /* Ports can be integer with a width of [31:0]. */ + + | port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(integer_width); + port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = true; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, true, + range_stub, + list_from_identifier($3), true); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(64); + port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, false, + range_stub, + list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Ports can be real or realtime. */ + + | port_direction_opt real_or_realtime IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_REAL; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_REAL, false, + 0, list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + | port_direction_opt data_type IDENTIFIER range_opt tf_port_item_expr_opt + { port_declaration_context.port_type = $1; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + port_declaration_context.data_type = $2; + svector*tmp = pform_make_task_ports(@3, $1, $2, + list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + ; + + /* This rule matches the [ = ] part of the tf_port_item rules. */ + +tf_port_item_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + +tf_port_list /* IEEE1800-2005: A.2.7 */ + + : tf_port_list ',' tf_port_item + { svector*tmp; + if ($3) { + tmp = new svector(*$1, *$3); + delete $1; + delete $3; + } else { + tmp = $1; + } + $$ = tmp; + } + + | tf_port_item + { $$ = $1; } + + /* This rule handles the special case of a set of port items leading + an undecorated identifier. Undeconated identifiers in this case + pick up the details from the list to its lift. */ + + | tf_port_list ',' IDENTIFIER + { // The declaration is already parsed, apply it to IDENTIFIER + svector*new_decl; + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + assert(port_declaration_context.data_type); + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.data_type, + list_from_identifier($3)); + } else { + new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + list_from_identifier($3)); + } + svector*tmp = new svector(*$1, *new_decl); + delete $1; + delete new_decl; + $$ = tmp; + } + + /* Rules to handle some errors in tf_port_list items. */ + + | error ',' tf_port_item + { yyerror(@2, "error: Syntax error in task/function port declaration."); + $$ = $3; + } + | tf_port_list ',' + { yyerror(@2, "error: NULL port declarations are not allowed."); + $$ = $1; + } + | tf_port_list ';' + { yyerror(@2, "error: ';' is an invalid port declaration separator."); + $$ = $1; + } + ; + + +variable_dimension /* IEEE1800-2005: A.2.5 */ + : '[' expression ':' expression ']' + { list*tmp = new list; + tmp->push_back($2); + tmp->push_back($4); + $$ = tmp; + } + | '[' ']' + { list*tmp = new list; + tmp->push_back(0); + tmp->push_back(0); + $$ = tmp; + } +; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -2079,6 +2394,12 @@ expr_primary $$ = base; } } + + /* Aggregate literals are primaries. */ + + | assignment_pattern + { $$ = $1; } + ; /* A function_item_list borrows the task_port_item run to match @@ -3159,76 +3480,7 @@ module_item | class_declaration - /* The task declaration rule matches the task declaration - header, then pushes the function scope. This causes the - definitions in the task_body to take on the scope of the task - instead of the module. Note that these runs accept for the task - body statement_or_null, although the standard does not allow null - statements in the task body. But we continue to accept it as an - extension. */ - - | K_task K_automatic_opt IDENTIFIER ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_item_list_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($7); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($7->size() > 1 && !gn_system_verilog()) { - yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $7; - } - - | K_task K_automatic_opt IDENTIFIER '(' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_port_decl_list ')' ';' - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($10); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($10->size() > 1 && !gn_system_verilog()) { - yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $10; - } - - | K_task K_automatic_opt IDENTIFIER '(' ')' ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports(0); - current_task_set_statement($9); - pform_pop_scope(); - current_task = 0; - cerr << @3 << ": warning: task definition for \"" << $3 - << "\" has an empty port declaration list!" << endl; - delete[]$3; - if ($9->size() > 1 && !gn_system_verilog()) { - yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $9; - } - - | K_task K_automatic_opt IDENTIFIER error K_endtask - { - assert(current_task == 0); - delete[]$3; - } + | task_declaration /* The function declaration rule matches the function declaration header, then pushes the function scope. This causes the @@ -3266,7 +3518,7 @@ module_item { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - '(' task_port_decl_list_opt ')' ';' + '(' tf_port_list_opt ')' ';' block_item_decls_opt statement_list K_endfunction @@ -4055,17 +4307,12 @@ port_direction_opt | { $$ = NetNet::PINPUT; } ; + /* The range is a list of variable dimensions. */ range - : '[' expression ':' expression ']' - { list*tmp = new list; - tmp->push_back($2); - tmp->push_back($4); - $$ = tmp; - } - | range '[' expression ':' expression ']' + : variable_dimension + | range variable_dimension { list*tmp = $1; - tmp->push_back($3); - tmp->push_back($5); + if ($2) tmp->splice(tmp->end(), *$2); $$ = tmp; } ; @@ -5112,11 +5359,10 @@ task_item task_port_item : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports($1, + { svector*tmp = pform_make_task_ports(@1, $1, $2 ? IVL_VT_LOGIC : IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); + $3, $4, $5); $$ = tmp; } @@ -5125,9 +5371,8 @@ task_port_item | port_direction K_integer list_of_identifiers ';' { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); $$ = tmp; } @@ -5135,17 +5380,16 @@ task_port_item | port_direction K_time list_of_identifiers ';' { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); $$ = tmp; } /* Ports can be real or realtime. */ | port_direction real_or_realtime list_of_identifiers ';' - { svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, - 0, $3, @1.text, @1.first_line); + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); $$ = tmp; } @@ -5169,142 +5413,11 @@ task_item_list_opt { $$ = 0; } ; -task_port_decl - - : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports($1, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be integer with a width of [31:0]. */ - - | port_direction_opt K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | port_direction_opt K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports($1, IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | port_direction_opt real_or_realtime IDENTIFIER - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp = pform_make_task_ports($1, IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - | port_direction_opt data_type IDENTIFIER task_port_decl_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = $2; - svector*tmp = pform_make_task_ports(@1, $1, $2, - list_from_identifier($3)); - $$ = tmp; - if ($4) { - yyerror(@4, "sorry: Port default expressions not supported yet."); - delete $4; - } - } - - ; - -task_port_decl_expr_opt - : '=' expression { $$ = $2; } - | { $$ = 0; } - ; - -task_port_decl_list_opt - : task_port_decl_list { $$ = $1; } +tf_port_list_opt + : tf_port_list { $$ = $1; } | { $$ = 0; } ; -task_port_decl_list - : task_port_decl_list ',' task_port_decl - { svector*tmp = new svector(*$1, *$3); - delete $1; - delete $3; - $$ = tmp; - } - | task_port_decl - { $$ = $1; } - | task_port_decl_list ',' IDENTIFIER - { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - assert(port_declaration_context.data_type); - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.data_type, - list_from_identifier($3)); - } else { - new_decl = pform_make_task_ports(port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3), - @3.text, @3.first_line); - } - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - | task_port_decl_list ',' - { yyerror(@2, "error: NULL port declarations are not allowed."); } - | task_port_decl_list ';' - { yyerror(@2, "error: ';' is an invalid port declaration separator."); } - ; - udp_body : K_table { lex_start_table(); } udp_entry_list diff --git a/pform.cc b/pform.cc index 4f349e9af..9629be7bc 100644 --- a/pform.cc +++ b/pform.cc @@ -2145,13 +2145,12 @@ void pform_set_port_type(perm_string name, NetNet::PortType pt, * constraints as those of tasks, so this works fine. Functions have * no output or inout ports. */ -svector*pform_make_task_ports(NetNet::PortType pt, +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, list*range, list*names, - const char* file, - unsigned lineno, bool isint) { assert(names); @@ -2168,7 +2167,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, curw->set_port_type(pt); } else { curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype); - FILE_NAME(curw, file, lineno); + FILE_NAME(curw, loc); pform_put_wire_in_scope(name, curw); } @@ -2205,8 +2204,8 @@ svector*pform_make_task_ports(const struct vlltype&loc, } list*range_tmp = make_range_from_width(atype->type_code); - return pform_make_task_ports(pt, IVL_VT_BOOL, atype->signed_flag, - range_tmp, names, loc.text, loc.first_line); + return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, + range_tmp, names); } void pform_set_attrib(perm_string name, perm_string key, char*value) diff --git a/pform.h b/pform.h index bc0c7115d..19b0f72b5 100644 --- a/pform.h +++ b/pform.h @@ -385,13 +385,12 @@ extern void pform_make_pgassign_list(list*alist, /* Given a port type and a list of names, make a list of wires that can be used as task port information. */ -extern svector*pform_make_task_ports(NetNet::PortType pt, +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, list*range, list*names, - const char* file, - unsigned lineno, bool isint = false); extern svector*pform_make_task_ports(const struct vlltype&loc, diff --git a/pform_dump.cc b/pform_dump.cc index 9d13320f1..ac34927a4 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -860,6 +860,10 @@ void PTask::dump(ostream&out, unsigned ind) const out << pscope_name() << ";" << endl; if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { + if ((*ports_)[idx] == 0) { + out << setw(ind) << "" << "ERROR PORT" << endl; + continue; + } out << setw(ind) << ""; switch ((*ports_)[idx]->get_port_type()) { case NetNet::PINPUT: @@ -871,6 +875,12 @@ void PTask::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << "inout "; break; + case NetNet::PIMPLICIT: + out << "PIMPLICIT"; + break; + case NetNet::NOT_A_PORT: + out << "NOT_A_PORT"; + break; default: assert(0); break; From f8e346f1086aa5c41a8bf17ebc08d6da1345c45f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 19 Feb 2012 18:54:58 -0800 Subject: [PATCH 58/88] Implement increment/decrement statements. During parse/pform processing, convert increment statements to the equivalent compressed assignment statement. This is less weird for elaboration processing and better expresses what is going on. --- PExpr.h | 4 +++ parse.y | 97 +++++++++++++++++++++++++++++++++++--------------------- pform.cc | 37 +++++++++++++++++++++ pform.h | 7 ++++ 4 files changed, 109 insertions(+), 36 deletions(-) diff --git a/PExpr.h b/PExpr.h index 7691b44d1..03c9e3284 100644 --- a/PExpr.h +++ b/PExpr.h @@ -509,6 +509,10 @@ class PEUnary : public PExpr { unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; + public: + inline char get_op() const { return op_; } + inline PExpr*get_expr() const { return expr_; } + private: NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const; diff --git a/parse.y b/parse.y index 31d8fcd27..38dc2d0bb 100644 --- a/parse.y +++ b/parse.y @@ -496,7 +496,7 @@ static void current_task_set_statement(vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type lpvalue +%type inc_or_dec_expression lpvalue %type branch_probe_expression %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list @@ -665,6 +665,35 @@ implicit_class_handle /* IEEE1800-2005: A.8.4 */ | K_super ; + /* SystemVerilog adds support for the increment/decrement + expressions, which look like a++, --a, etc. These are primaries + but are in their own rules because they can also be + statements. Note that the operator can only take l-value + expressions. */ + +inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ + : K_INCR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('I', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_INCR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('i', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_DECR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('D', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_DECR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('d', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -1790,32 +1819,10 @@ branch_probe_expression expression : expr_primary { $$ = $1; } + | inc_or_dec_expression + { $$ = $1; } | '+' expr_primary %prec UNARY_PREC { $$ = $2; } - | K_INCR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('I', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_INCR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('i', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_DECR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('D', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_DECR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('d', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } | '-' expr_primary %prec UNARY_PREC { PEUnary*tmp = new PEUnary('-', $2); FILE_NAME(tmp, @2); @@ -4897,7 +4904,7 @@ spec_notifier ; -statement +statement /* This is roughly statement_item in the LRM */ /* assign and deassign statements are procedural code to do structural assignments, and to turn that structural assignment @@ -5094,16 +5101,29 @@ statement { $$ = 0; yyerror(@1, "error: Error in while loop condition."); } - | compressed_statement ';' - { $$ = $1; } - | delay1 statement_or_null - { PExpr*del = $1->front(); - assert($1->size() == 1); - delete $1; - PDelayStatement*tmp = new PDelayStatement(del, $2); - FILE_NAME(tmp, @1); - $$ = tmp; - } + + /* SytemVerilog adds the compressed_statement */ + + | compressed_statement ';' + { $$ = $1; } + + /* increment/decrement expressions can also be statements. When used + as statements, we can rewrite a++ as a += 1, and so on. */ + + | inc_or_dec_expression ';' + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + + /* */ + + | delay1 statement_or_null + { PExpr*del = $1->front(); + assert($1->size() == 1); + delete $1; + PDelayStatement*tmp = new PDelayStatement(del, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | event_control attribute_list_opt statement_or_null { PEventStatement*tmp = $1; if (tmp == 0) { @@ -5129,6 +5149,9 @@ statement tmp->set_statement($6); $$ = tmp; } + + /* Various assignment statements */ + | lpvalue '=' expression ';' { PAssign*tmp = new PAssign($1,$3); FILE_NAME(tmp, @1); @@ -5184,6 +5207,8 @@ statement FILE_NAME(tmp, @1); $$ = tmp; } + + | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); diff --git a/pform.cc b/pform.cc index 9629be7bc..cd909fb74 100644 --- a/pform.cc +++ b/pform.cc @@ -2208,6 +2208,43 @@ svector*pform_make_task_ports(const struct vlltype&loc, range_tmp, names); } +/* + * The parser calls this in the rule that matches increment/decrement + * statements. The rule that does the matching creates a PEUnary with + * all the information we need, but here we convert that expression to + * a compressed assignment statement. + */ +PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp) +{ + PEUnary*expu = dynamic_cast (exp); + ivl_assert(*exp, expu != 0); + + char use_op = 0; + switch (expu->get_op()) { + case 'i': + case 'I': + use_op = '+'; + break; + case 'd': + case 'D': + use_op = '-'; + break; + default: + ivl_assert(*exp, 0); + break; + } + + PExpr*lval = expu->get_expr(); + PExpr*rval = new PENumber(new verinum((uint64_t)1, 1)); + FILE_NAME(rval, loc); + + PAssign*tmp = new PAssign(lval, use_op, rval); + FILE_NAME(tmp, loc); + + delete exp; + return tmp; +} + void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { diff --git a/pform.h b/pform.h index 19b0f72b5..addf61c94 100644 --- a/pform.h +++ b/pform.h @@ -398,6 +398,13 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, data_type_t*vtype, list*names); +/* + * The parser uses this function to convert a unary + * increment/decrement expression to the equivilent compressed + * assignment statement. + */ +extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, + PExpr*exp); /* * These are functions that the outside-the-parser code uses the do From 51ef5419696cbaa97eb43ee6038d0e842b53b553 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 22 Feb 2012 10:20:49 -0800 Subject: [PATCH 59/88] Fix compile on cygwin and fix a few compile warnings. This patch fixes a few compile warnings and adds the new packed routines to the ivl.def file so that this links correctly on cygwin. --- elab_expr.cc | 4 ++-- elab_lval.cc | 4 ++-- ivl.def | 3 +++ pform_struct_type.cc | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 2de3748e5..980446132 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -1420,7 +1420,7 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, } static NetExpr* check_for_struct_members(const LineInfo*li, - Design*des, NetScope*scope, + Design*des, NetScope*, NetNet*net, perm_string method_name) { netstruct_t*type = net->struct_type(); diff --git a/elab_lval.cc b/elab_lval.cc index 6376c05e1..4e5934841 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -622,7 +622,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } bool PEIdent::elaborate_lval_net_packed_member_(Design*des, - NetScope*scope, + NetScope*, NetAssign_*lv, const perm_string&member_name) const { diff --git a/ivl.def b/ivl.def index 4e57899c5..603c116e8 100644 --- a/ivl.def +++ b/ivl.def @@ -230,6 +230,9 @@ ivl_signal_msb ivl_signal_name ivl_signal_nex ivl_signal_npath +ivl_signal_packed_dimensions +ivl_signal_packed_lsb +ivl_signal_packed_msb ivl_signal_path ivl_signal_port ivl_signal_scope diff --git a/pform_struct_type.cc b/pform_struct_type.cc index 1e07db36d..1fe44bbe8 100644 --- a/pform_struct_type.cc +++ b/pform_struct_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 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 @@ -79,7 +79,7 @@ static void pform_makewire(const struct vlltype&li, struct_type_t*struct_type, NetNet::PortType ptype, perm_string name, - list*attr) + list*) { ivl_variable_type_t base_type = figure_struct_base_type(struct_type); From 952b84fba3cf36a81ef9bf1822c0ff94e89fd404 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 22 Feb 2012 15:08:24 -0800 Subject: [PATCH 60/88] Fix signed/unsigned compare warning Fix a signed/unsigned comparison warning on RHEL 5. --- elab_lval.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index 4e5934841..b10656442 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -480,7 +480,7 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, // Special case: The range winds up selecting the entire // vector. Treat this as no part select at all. - if (loff == 0 && moff == (reg->vector_width()-1)) { + if (loff == 0 && moff == (long)(reg->vector_width()-1)) { return true; } @@ -489,7 +489,7 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, converted to normalized form so is relative the variable pins. */ - if (loff < 0 || moff >= (signed)reg->vector_width()) { + if (loff < 0 || moff >= (long)reg->vector_width()) { cerr << get_fileline() << ": warning: Part select " << reg->name() << "[" << msb<<":"< Date: Wed, 22 Feb 2012 17:26:14 -0800 Subject: [PATCH 61/88] Remove some more warnings in pform.cc Ubuntu 11.10 (gcc/clang) Remove a few more warnings from the gcc and clang compilers on Ubuntu 11.10. --- pform.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pform.cc b/pform.cc index 9716ffdd9..fc36f160d 100644 --- a/pform.cc +++ b/pform.cc @@ -413,7 +413,7 @@ data_type_t* pform_test_type_identifier(const char*txt) // If there is no lexical_scope yet, then there is NO WAY the // identifier can be a type_identifier. if (lexical_scope == 0) - return false; + return 0; perm_string name = lex_strings.make(txt); map::iterator cur = lexical_scope->typedefs.find(name); @@ -1972,9 +1972,7 @@ void pform_makewire(const vlltype&li, perm_string name, { PWire*cur = pform_get_or_make_wire(li, name, type, pt, dt); - bool new_wire_flag = false; if (! cur) { - new_wire_flag = true; cur = new PWire(name, type, pt, dt); FILE_NAME(cur, li.text, li.first_line); } From cad7c74680dc2f4c0bf75e7a026e6f4c20d4c791 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 24 Feb 2012 17:04:49 -0800 Subject: [PATCH 62/88] System Verilog supports closing names after endtask keyword. --- parse.y | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/parse.y b/parse.y index 38dc2d0bb..b3b23c72e 100644 --- a/parse.y +++ b/parse.y @@ -728,12 +728,26 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement($7); pform_pop_scope(); current_task = 0; - delete[]$3; if ($7->size() > 1 && !gn_system_verilog()) { yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); } delete $7; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($10 && (strcmp($3,$10) != 0)) { + yyerror(@10, "error: End name doesn't match module/program name"); + } + if ($10 && !gn_system_verilog()) { + yyerror(@10, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($10) delete[]$10; + } | K_task K_automatic_opt IDENTIFIER '(' { assert(current_task == 0); @@ -747,12 +761,26 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement($10); pform_pop_scope(); current_task = 0; - delete[]$3; if ($10->size() > 1 && !gn_system_verilog()) { yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); } delete $10; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($13 && (strcmp($3,$13) != 0)) { + yyerror(@13, "error: End name doesn't match module/program name"); + } + if ($13 && !gn_system_verilog()) { + yyerror(@13, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($13) delete[]$13; + } | K_task K_automatic_opt IDENTIFIER '(' ')' ';' { assert(current_task == 0); @@ -767,17 +795,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task = 0; cerr << @3 << ": warning: task definition for \"" << $3 << "\" has an empty port declaration list!" << endl; - delete[]$3; if ($9->size() > 1 && !gn_system_verilog()) { yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); } delete $9; } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($12 && (strcmp($3,$12) != 0)) { + yyerror(@12, "error: End name doesn't match module/program name"); + } + if ($12 && !gn_system_verilog()) { + yyerror(@12, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($12) delete[]$12; + } | K_task K_automatic_opt IDENTIFIER error K_endtask { assert(current_task == 0); + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($7 && (strcmp($3,$7) != 0)) { + yyerror(@7, "error: End name doesn't match module/program name"); + } + if ($7 && !gn_system_verilog()) { + yyerror(@7, "error: Task end names require System Verilog."); + } delete[]$3; + if ($7) delete[]$7; } ; From d000147392379075e2f5fcb69d1f7bc5994d74af Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 09:28:20 -0800 Subject: [PATCH 63/88] Parse for declarations, implement for_step statements. for-statement declarations still generate a "sorry" message, but the for_step statements work in general now. --- Statement.cc | 5 +- Statement.h | 5 +- elaborate.cc | 29 ++--------- parse.y | 134 ++++++++++++++++++++++++++++++++------------------ pform_dump.cc | 4 +- 5 files changed, 98 insertions(+), 79 deletions(-) diff --git a/Statement.cc b/Statement.cc index e726099bb..a99e8b37e 100644 --- a/Statement.cc +++ b/Statement.cc @@ -276,9 +276,8 @@ PForever::~PForever() } PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st) -: name1_(n1), expr1_(e1), cond_(cond), name2_(n2), expr2_(e2), - statement_(st) + Statement*step, Statement*st) +: name1_(n1), expr1_(e1), cond_(cond), step_(step), statement_(st) { } diff --git a/Statement.h b/Statement.h index cef5833c1..5caf9644d 100644 --- a/Statement.h +++ b/Statement.h @@ -403,7 +403,7 @@ class PForStatement : public Statement { public: PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st); + Statement*step, Statement*body); ~PForStatement(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -417,8 +417,7 @@ class PForStatement : public Statement { PExpr*cond_; - PExpr* name2_; - PExpr* expr2_; + Statement*step_; Statement*statement_; }; diff --git a/elaborate.cc b/elaborate.cc index e2bf04e64..ba5d8f019 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3780,8 +3780,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const const PEIdent*id1 = dynamic_cast(name1_); assert(id1); - const PEIdent*id2 = dynamic_cast(name2_); - assert(id2); NetBlock*top = new NetBlock(NetBlock::SEQU, 0); top->set_line(*this); @@ -3826,32 +3824,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const body->append(tmp); - /* Elaborate the increment assignment statement at the end of - the for loop. This is also a very specific assignment - statement. Put this into the "body" block. */ - sig = des->find_signal(scope, id2->path()); - if (sig == 0) { - cerr << get_fileline() << ": error: Unable to find variable " - << id2->path() << " in for-loop increment expression." << endl; - des->errors += 1; - return body; - } - - assert(sig); - lv = new NetAssign_(sig); - - /* Make the r-value of the increment assignment, and size it - properly. Then use it to build the assignment statement. */ - etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(), - expr2_); - + /* Now elaborate the for_step statement. I really should do + some error checking here to make sure the step statement + really does step the variable. */ if (debug_elaborate) { - cerr << get_fileline() << ": debug: FOR increment assign: " + cerr << get_fileline() << ": debug: Elaborate for_step statement " << sig->name() << " = " << *etmp << endl; } - NetAssign*step = new NetAssign(lv, etmp); - step->set_line(*this); + NetProc*step = step_->elaborate(des, scope); body->append(step); diff --git a/parse.y b/parse.y index b3b23c72e..5118dd2c6 100644 --- a/parse.y +++ b/parse.y @@ -524,6 +524,7 @@ static void current_task_set_statement(vector*s) %type event_expression %type event_control %type statement statement_or_null compressed_statement +%type loop_statement for_step %type statement_list statement_or_null_list %type statement_list_or_null @@ -660,6 +661,19 @@ data_type /* IEEE1800-2005: A.2.2.1 */ endnew_opt : ':' K_new | ; +for_step /* IEEE1800-2005: A.6.8 */ + : lpvalue '=' expression + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | inc_or_dec_expression + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + | compressed_statement + { $$ = $1; } + ; + + implicit_class_handle /* IEEE1800-2005: A.8.4 */ : K_this | K_super @@ -694,6 +708,66 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; + /* Loop statements are kinds of statements. */ + +loop_statement /* IEEE1800-2005: A.6.8 */ + : K_for '(' lpvalue '=' expression ';' expression ';' for_step ')' + statement_or_null + { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@3, "sorry: for_variable_declaration not supported"); + } + + | K_forever statement_or_null + { PForever*tmp = new PForever($2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_repeat '(' expression ')' statement_or_null + { PRepeat*tmp = new PRepeat($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_while '(' expression ')' statement_or_null + { PWhile*tmp = new PWhile($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + /* Error forms for loop statements. */ + + | K_for '(' lpvalue '=' expression ';' expression ';' error ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop step assignment."); + } + + | K_for '(' lpvalue '=' expression ';' error ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop condition expression."); + } + + | K_for '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Incomprehensible for loop."); + } + + | K_while '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in while loop condition."); + } + + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -710,6 +784,16 @@ real_or_realtime | K_realtime ; + /* Many places where statements are allowed can actually take a + statement or a null statement marked with a naked semi-colon. */ + +statement_or_null /* IEEE1800-2005: A.6.4 */ + : statement + { $$ = $1; } + | ';' + { $$ = 0; } + ; + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -5079,16 +5163,9 @@ statement /* This is roughly statement_item in the LRM */ delete $2; $$ = tmp; } - | K_forever statement - { PForever*tmp = new PForever($2); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_repeat '(' expression ')' statement - { PRepeat*tmp = new PRepeat($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } + + | loop_statement { $$ = $1; } + | K_case '(' expression ')' case_items K_endcase { PCase*tmp = new PCase(NetCase::EQ, $3, $5); FILE_NAME(tmp, @1); @@ -5128,36 +5205,6 @@ statement /* This is roughly statement_item in the LRM */ { yyerror(@1, "error: Malformed conditional expression."); $$ = $5; } - | K_for '(' lpvalue '=' expression ';' expression ';' - lpvalue '=' expression ')' statement - { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11, $13); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_for '(' lpvalue '=' expression ';' expression ';' - error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop step assignment."); - } - | K_for '(' lpvalue '=' expression ';' error ';' - lpvalue '=' expression ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop condition expression."); - } - | K_for '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Incomprehensible for loop."); - } - | K_while '(' expression ')' statement - { PWhile*tmp = new PWhile($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_while '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in while loop condition."); - } - /* SytemVerilog adds the compressed_statement */ | compressed_statement ';' @@ -5406,13 +5453,6 @@ statement_list } ; -statement_or_null - : statement - { $$ = $1; } - | ';' - { $$ = 0; } - ; - statement_or_null_list : statement_or_null_list statement_or_null { vector*tmp = $1; diff --git a/pform_dump.cc b/pform_dump.cc index ac34927a4..d9fa1286e 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -774,8 +774,8 @@ void PForever::dump(ostream&out, unsigned ind) const void PForStatement::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_ - << "; " << *cond_ << "; " << *name2_ << " = " << *expr2_ << - ")" << endl; + << "; " << *cond_ << "; )" << endl; + step_->dump(out, ind+6); statement_->dump(out, ind+3); } From dd3a7411cd099843bf510bd779a87200e2d934fd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 10:19:48 -0800 Subject: [PATCH 64/88] Parse SystemVerilog ref ports. --- design_dump.cc | 3 +++ elab_net.cc | 4 ++++ elab_sig.cc | 8 ++++++++ elaborate.cc | 14 ++++++++++++++ netlist.h | 2 +- parse.y | 32 +++++++++++++++++++++----------- pform_dump.cc | 3 +++ 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 5da7f9047..e3d14f3b0 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -221,6 +221,9 @@ void NetNet::dump_net(ostream&o, unsigned ind) const case NetNet::PINOUT: o << " inout"; break; + case NetNet::PREF: + o <<" ref"; + break; } if (ivl_discipline_t dis = get_discipline()) diff --git a/elab_net.cc b/elab_net.cc index 98180dab5..221769451 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -702,6 +702,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const case NetNet::PINPUT: case NetNet::POUTPUT: case NetNet::PINOUT: + case NetNet::PREF: break; /* If the name matches, but the signal is not a port, @@ -769,6 +770,9 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const sig = tmp; break; + case NetNet::PREF: + // For the purposes of module ports, treat ref ports + // just like inout ports. case NetNet::PINOUT: ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(), swid, lidx); diff --git a/elab_sig.cc b/elab_sig.cc index 336a8e97e..42ed8c355 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -85,6 +85,14 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const PWire*cur = (*wt).second; NetNet*sig = cur->elaborate_sig(des, scope); + if (sig && (sig->scope() == scope) + && (sig->port_type() == NetNet::PREF)) { + + cerr << cur->get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + } + /* If the signal is an input and is also declared as a reg, then report an error. */ diff --git a/elaborate.cc b/elaborate.cc index ba5d8f019..e256a4df8 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1069,6 +1069,10 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, ivl_assert(*this, 0); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; + default: ivl_assert(*this, 0); } @@ -1506,6 +1510,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else { /* Port type must be OUTPUT here. */ + ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); /* Output from module. Elaborate the port expression as the l-value of a continuous @@ -1640,6 +1645,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* This may not be correct! */ as_signed = prts[0]->get_signed() && sig->get_signed(); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; default: ivl_assert(*this, 0); } @@ -1786,6 +1794,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } break; + case NetNet::PREF: + cerr << get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + break; + case NetNet::PIMPLICIT: cerr << get_fileline() << ": internal error: " << "Unexpected IMPLICIT port" << endl; diff --git a/netlist.h b/netlist.h index 36f531dac..a99a41730 100644 --- a/netlist.h +++ b/netlist.h @@ -561,7 +561,7 @@ class NetNet : public NetObj { SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, UNRESOLVED_WIRE }; - enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; + enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF }; struct range_t { inline range_t() : msb(0), lsb(0) { } diff --git a/parse.y b/parse.y index 5118dd2c6..81c71d14e 100644 --- a/parse.y +++ b/parse.y @@ -777,6 +777,27 @@ number : BASED_NUMBER based_size = 0; } ; +port_direction /* IEEE1800-2005 A.1.3 */ + : K_input { $$ = NetNet::PINPUT; } + | K_output { $$ = NetNet::POUTPUT; } + | K_inout { $$ = NetNet::PINOUT; } + | K_ref + { $$ = NetNet::PREF; + if (!gn_system_verilog()) { + yyerror(@1, "error: Reference ports (ref) require SystemVerilog."); + $$ = NetNet::PINPUT; + } + } + ; + + /* port_direction_opt is used in places where the prot direction is + option, and defaults to input. */ + +port_direction_opt + : port_direction { $$ = $1; } + | { $$ = NetNet::PINPUT; } + ; + /* real and realtime are exactly the same so save some code * with a common matching rule. */ real_or_realtime @@ -4443,17 +4464,6 @@ port_reference_list } ; -port_direction /* IEEE1800-2005 A.1.3 */ - : K_input { $$ = NetNet::PINPUT; } - | K_output { $$ = NetNet::POUTPUT; } - | K_inout { $$ = NetNet::PINOUT; } - ; - -port_direction_opt - : port_direction { $$ = $1; } - | { $$ = NetNet::PINPUT; } - ; - /* The range is a list of variable dimensions. */ range : variable_dimension diff --git a/pform_dump.cc b/pform_dump.cc index d9fa1286e..1ca78a67e 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -336,6 +336,9 @@ void PWire::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << " inout"; break; + case NetNet::PREF: + out << " ref"; + break; case NetNet::NOT_A_PORT: break; } From 410350ae5a28d907bc9868240cc39cce1cebfc0f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 25 Feb 2012 22:05:00 -0800 Subject: [PATCH 65/88] Rework data_type parsing to bring integer vectors into data_type_t method. This adds the vector_type_t and real_type_t types to handle vector and real types in tf_port items. This cleans up a lot of the parsing for these items. --- parse.y | 221 ++++++++++++-------------------------------------- pform.cc | 46 ++++++++--- pform.h | 5 +- pform_types.h | 13 +++ 4 files changed, 101 insertions(+), 184 deletions(-) diff --git a/parse.y b/parse.y index 81c71d14e..eaf4064d5 100644 --- a/parse.y +++ b/parse.y @@ -157,7 +157,7 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -static list* copy_range(list* orig) +list* copy_range(list* orig) { list*copy = 0; @@ -317,7 +317,7 @@ static void current_task_set_statement(vector*s) NetNet::Type nettype; PGBuiltin::Type gatetype; NetNet::PortType porttype; - ivl_variable_type_t datatype; + ivl_variable_type_t vartype; PWire*wire; svector*wires; @@ -461,9 +461,9 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable real_variable endname_opt +%type register_variable net_variable endname_opt %type register_variable_list net_variable_list -%type real_variable_list list_of_identifiers +%type list_of_identifiers %type list_of_port_identifiers %type net_decl_assign net_decl_assigns @@ -506,7 +506,7 @@ static void current_task_set_statement(vector*s) %type variable_decl_assignment %type list_of_variable_decl_assignments -%type data_type +%type data_type data_type_or_implicit %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -516,7 +516,8 @@ static void current_task_set_statement(vector*s) %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt -%type primitive_type primitive_type_opt bit_logic +%type primitive_type primitive_type_opt bit_logic +%type integer_vector_type %type parameter_value_opt %type function_range_or_type_opt @@ -536,7 +537,7 @@ static void current_task_set_statement(vector*s) %type specify_simple_path specify_simple_path_decl %type specify_edge_path specify_edge_path_decl -%type atom2_type +%type atom2_type non_integer_type %type module_start module_end %token K_TAND @@ -642,7 +643,17 @@ class_item /* IEEE1800-2005: A.1.8 */ ; data_type /* IEEE1800-2005: A.2.2.1 */ - : struct_data_type + : integer_vector_type unsigned_signed_opt range_opt + { vector_type_t*tmp = new vector_type_t($1, $2, $3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | struct_data_type { $$ = $1; } | enum_data_type { $$ = $1; } @@ -659,6 +670,16 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; +data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ + : data_type + { $$ = $1; } + | unsigned_signed_opt range_opt + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + endnew_opt : ':' K_new | ; for_step /* IEEE1800-2005: A.6.8 */ @@ -708,6 +729,13 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; +integer_vector_type /* IEEE1800-2005: A.2.2.1 */ + : K_reg { $$ = IVL_VT_LOGIC; } + | K_bit { $$ = IVL_VT_BOOL; } + | K_logic { $$ = IVL_VT_LOGIC; } + | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -768,6 +796,12 @@ loop_statement /* IEEE1800-2005: A.6.8 */ ; +non_integer_type /* IEEE1800-2005: A.2.2.1 */ + : K_real { $$ = K_real; } + | K_realtime { $$ = K_real; } + | K_shortreal { $$ = K_shortreal; } + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -954,47 +988,9 @@ task_declaration /* IEEE1800-2005: A.2.7 */ tf_port_item /* IEEE1800-2005: A.2.7 */ - : port_direction K_reg_opt unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports(@5, $1, IVL_VT_LOGIC, $3, - $4, list_from_identifier($5)); - $$ = tmp; - if ($6) { - yyerror(@6, "sorry: Port variable dimensions not supported yet."); - delete $6; - } - if ($7) { - yyerror(@7, "sorry: Port default expressions not supported yet."); - delete $7; - } - } - - | port_direction_opt bit_logic unsigned_signed_opt range_opt IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = pform_make_task_ports(@5, $1, $2, $3, - $4, list_from_identifier($5)); - $$ = tmp; - if ($6) { - yyerror(@6, "sorry: Port variable dimensions not supported yet."); - delete $6; - } - if ($7) { - yyerror(@7, "sorry: Port default expressions not supported yet."); - delete $7; - } - } - /* Ports can be integer with a width of [31:0]. */ - | port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt + : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(integer_width); port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_LOGIC; @@ -1038,28 +1034,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - /* Ports can be real or realtime. */ - - | port_direction_opt real_or_realtime IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_REAL, false, - 0, list_from_identifier($3)); - $$ = tmp; - if ($4) { - yyerror(@4, "sorry: Port variable dimensions not supported yet."); - delete $4; - } - if ($5) { - yyerror(@5, "sorry: Port default expressions not supported yet."); - delete $5; - } - } - - | port_direction_opt data_type IDENTIFIER range_opt tf_port_item_expr_opt + | port_direction data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt { port_declaration_context.port_type = $1; port_declaration_context.var_type = IVL_VT_NO_TYPE; port_declaration_context.sign_flag = false; @@ -1111,7 +1086,7 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ | tf_port_list ',' IDENTIFIER { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; + svector*new_decl; if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { assert(port_declaration_context.data_type); new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, @@ -1226,47 +1201,12 @@ attribute rule has presumably set up the scope. */ block_item_decl - : attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt range - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($6, $5, $4, dtype); - if ($1) delete $1; - } - /* This differs from the above pattern only in the absence of the - range. This is the rule for a scalar. */ - - | attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($5, 0, $4, dtype); - if ($1) delete $1; - } - - | attribute_list_opt K_bit unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_BOOL); - if ($1) delete $1; - } - - | attribute_list_opt K_logic unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_LOGIC); - if ($1) delete $1; - } /* Integer atom declarations are simpler in that they do not have all the trappings of a general variable declaration. All of that is implicit in the "integer" of the declaration. */ - | attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' + : attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' { pform_set_reg_integer($4); if ($1) delete $1; } @@ -1284,15 +1224,10 @@ block_item_decl if ($1) delete $1; } - /* real declarations are fairly simple as there is no range of - signed flag in the declaration. Create the real as a NetNet::REG - 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_reg data_type register_variable_list ';' + { if ($3) pform_set_data_type(@3, $3, $4); + if ($1) delete $1; + } | K_event list_of_identifiers ';' { pform_make_events($2, @1.text, @1.first_line); @@ -1307,12 +1242,6 @@ block_item_decl /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - - | attribute_list_opt K_reg error ';' - { yyerror(@2, "error: syntax error in reg variable list."); - yyerrok; - if ($1) delete $1; - } | attribute_list_opt K_integer error ';' { yyerror(@2, "error: syntax error in integer variable list."); yyerrok; @@ -1322,14 +1251,7 @@ block_item_decl { yyerror(@2, "error: syntax error in time variable list."); yyerrok; } - | attribute_list_opt K_real error ';' - { yyerror(@2, "error: syntax error in real variable list."); - yyerrok; - } - | attribute_list_opt K_realtime error ';' - { yyerror(@2, "error: syntax error in realtime variable list."); - yyerrok; - } + | K_parameter error ';' { yyerror(@1, "error: syntax error in parameter list."); yyerrok; @@ -3531,7 +3453,7 @@ module_item /* block_item_decl rule is shared with task blocks and named begin/end. */ - | block_item_decl + | block_item_decl /* */ @@ -4648,45 +4570,6 @@ variable_decl_assignment } ; -real_variable - : IDENTIFIER dimensions_opt - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - if ($2 != 0) { - index_component_t index; - if ($2->size() > 1) { - yyerror(@2, "sorry: only 1 dimensional arrays " - "are currently supported."); - } - index = $2->front(); - pform_set_reg_idx(name, index.msb, index.lsb); - delete $2; - } - $$ = $1; - } - | IDENTIFIER '=' expression - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - pform_make_reginit(@1, name, $3); - $$ = $1; - } - ; - -real_variable_list - : real_variable - { list*tmp = new list; - tmp->push_back(lex_strings.make($1)); - $$ = tmp; - delete[]$1; - } - | real_variable_list ',' real_variable - { list*tmp = $1; - tmp->push_back(lex_strings.make($3)); - $$ = tmp; - delete[]$3; - } - ; - net_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); diff --git a/pform.cc b/pform.cc index cd909fb74..2a8653c60 100644 --- a/pform.cc +++ b/pform.cc @@ -1527,10 +1527,10 @@ static void pform_set_net_range(perm_string name, cur->set_data_type(dt); } -void pform_set_net_range(list*names, - list*range, - bool signed_flag, - ivl_variable_type_t dt) +static void pform_set_net_range(list*names, + list*range, + bool signed_flag, + ivl_variable_type_t dt) { assert((range == 0) || (range->size()%2 == 0)); @@ -2197,15 +2197,27 @@ svector*pform_make_task_ports(const struct vlltype&loc, data_type_t*vtype, list*names) { - atom2_type_t*atype = dynamic_cast (vtype); - if (atype == 0) { - VLerror(loc, "sorry: Given type not supported here."); - return 0; + if (atom2_type_t*atype = dynamic_cast (vtype)) { + list*range_tmp = make_range_from_width(atype->type_code); + return pform_make_task_ports(loc, pt, IVL_VT_BOOL, + atype->signed_flag, + range_tmp, names); } - list*range_tmp = make_range_from_width(atype->type_code); - return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, - range_tmp, names); + if (vector_type_t*vec_type = dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, vec_type->base_type, + vec_type->signed_flag, + copy_range(vec_type->pdims.get()), + names); + } + + if (real_type_t*real_type = dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, IVL_VT_REAL, + true, 0, names); + } + + VLerror(loc, "sorry: Given type not supported here."); + return 0; } /* @@ -2608,6 +2620,18 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + pform_set_net_range(names, vec_type->pdims.get(), + vec_type->signed_flag, + vec_type->base_type); + return; + } + + if (real_type_t*real_type = dynamic_cast (data_type)) { + pform_set_net_range(names, 0, true, IVL_VT_REAL); + return; + } + assert(0); } diff --git a/pform.h b/pform.h index addf61c94..0e2613715 100644 --- a/pform.h +++ b/pform.h @@ -118,6 +118,7 @@ struct lgate { }; extern std::list* make_range_from_width(uint64_t wid); +extern list* copy_range(list* orig); /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ @@ -286,10 +287,6 @@ extern void pform_set_port_type(const struct vlltype&li, extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, const char*file, unsigned lineno); -extern void pform_set_net_range(list*names, - list*, - bool signed_flag, - ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); diff --git a/pform_types.h b/pform_types.h index 047592edf..8ec228eaa 100644 --- a/pform_types.h +++ b/pform_types.h @@ -107,6 +107,19 @@ struct atom2_type_t : public data_type_t { bool signed_flag; }; +struct vector_type_t : public data_type_t { + inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, list*pd) + : base_type(bt), signed_flag(sf), pdims(pd) { } + ivl_variable_type_t base_type; + bool signed_flag; + std::auto_ptr< list > pdims; +}; + +struct real_type_t : public data_type_t { + inline explicit real_type_t(int tc) : type_code(tc) { } + int type_code; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 481a9dec69f6bb05e6266b41780be4d2debbc678 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 10:57:03 -0800 Subject: [PATCH 66/88] More rework to canonicalize tf_port_item rules. --- parse.y | 121 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/parse.y b/parse.y index eaf4064d5..d75a8fbe1 100644 --- a/parse.y +++ b/parse.y @@ -447,7 +447,7 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number -%type unsigned_signed_opt signed_unsigned_opt +%type signing unsigned_signed_opt signed_unsigned_opt %type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 @@ -670,18 +670,34 @@ data_type /* IEEE1800-2005: A.2.2.1 */ } ; + /* The data_type_or_implicit rule is a little more complex then the + rule documented in the IEEE format syntax in order to allow for + signaling the special case that the data_type is completely + absent. The context may need that information to decide to resort + to left context. */ + data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ : data_type { $$ = $1; } - | unsigned_signed_opt range_opt + | signing range_opt { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); FILE_NAME(tmp, @1); $$ = tmp; } + | range + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | + { $$ = 0; } ; + /* This implements the [ : INDENTIFIER ] part of the constructure + rule documented in IEEE1800-2005: A.1.8 */ endnew_opt : ':' K_new | ; + for_step /* IEEE1800-2005: A.6.8 */ : lpvalue '=' expression { PAssign*tmp = new PAssign($1,$3); @@ -824,12 +840,13 @@ port_direction /* IEEE1800-2005 A.1.3 */ } ; - /* port_direction_opt is used in places where the prot direction is - option, and defaults to input. */ + /* port_direction_opt is used in places where the port direction is + optional. The default direction is selected by the context, + which needs to notice the PIMPLICIT direction. */ port_direction_opt : port_direction { $$ = $1; } - | { $$ = NetNet::PINPUT; } + | { $$ = NetNet::PIMPLICIT; } ; /* real and realtime are exactly the same so save some code @@ -839,6 +856,11 @@ real_or_realtime | K_realtime ; +signing /* IEEE1800-2005: A.2.2.1 */ + : K_signed { $$ = true; } + | K_unsigned { $$ = false; } + ; + /* Many places where statements are allowed can actually take a statement or a null statement marked with a naked semi-colon. */ @@ -992,7 +1014,9 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = $1; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = true; delete port_declaration_context.range; @@ -1015,13 +1039,15 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = $1; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; port_declaration_context.var_type = IVL_VT_LOGIC; port_declaration_context.sign_flag = false; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, false, - range_stub, + svector*tmp = pform_make_task_ports(@3, use_port_type, IVL_VT_LOGIC, + false, range_stub, list_from_identifier($3)); $$ = tmp; if ($4) { @@ -1034,15 +1060,43 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - | port_direction data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt - { port_declaration_context.port_type = $1; - port_declaration_context.var_type = IVL_VT_NO_TYPE; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - port_declaration_context.data_type = $2; - svector*tmp = pform_make_task_ports(@3, $1, $2, - list_from_identifier($3)); + | port_direction_opt data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt + { svector*tmp; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + list* ilist = list_from_identifier($3); + + if (($2 == 0) && ($1==NetNet::PIMPLICIT)) { + // Detect special case this is an undecorated + // identifier and we need to get the declaration from + // left context. + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.data_type, + ilist); + } else { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + ilist); + } + + } else { + // Otherwise, the decorations for this identifier + // indicate the type. Save the type for any right + // context thta may come later. + port_declaration_context.port_type = use_port_type; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + if ($2 == 0) { + $2 = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME($2, @3); + } + port_declaration_context.data_type = $2; + tmp = pform_make_task_ports(@3, $1, $2, ilist); + } $$ = tmp; if ($4) { yyerror(@4, "sorry: Port variable dimensions not supported yet."); @@ -1067,12 +1121,14 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ : tf_port_list ',' tf_port_item { svector*tmp; - if ($3) { + if ($1 && $3) { tmp = new svector(*$1, *$3); delete $1; delete $3; - } else { + } else if ($1) { tmp = $1; + } else { + tmp = $3; } $$ = tmp; } @@ -1080,31 +1136,6 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ | tf_port_item { $$ = $1; } - /* This rule handles the special case of a set of port items leading - an undecorated identifier. Undeconated identifiers in this case - pick up the details from the list to its lift. */ - - | tf_port_list ',' IDENTIFIER - { // The declaration is already parsed, apply it to IDENTIFIER - svector*new_decl; - if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { - assert(port_declaration_context.data_type); - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.data_type, - list_from_identifier($3)); - } else { - new_decl = pform_make_task_ports(@3, port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3)); - } - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - /* Rules to handle some errors in tf_port_list items. */ | error ',' tf_port_item From ebda9777ccedec5c32b8211e5e85e75b53ffe419 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 11:28:44 -0800 Subject: [PATCH 67/88] Parse foreach loops. --- parse.y | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/parse.y b/parse.y index d75a8fbe1..dbe116041 100644 --- a/parse.y +++ b/parse.y @@ -463,7 +463,7 @@ static void current_task_set_statement(vector*s) %type register_variable net_variable endname_opt %type register_variable_list net_variable_list -%type list_of_identifiers +%type list_of_identifiers loop_variables %type list_of_port_identifiers %type net_decl_assign net_decl_assigns @@ -786,6 +786,14 @@ loop_statement /* IEEE1800-2005: A.6.8 */ $$ = tmp; } + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null + { yyerror(@1, "sorry: foreach loops not supported"); + delete[]$3; + delete $5; + delete $8; + $$ = 0; + } + /* Error forms for loop statements. */ | K_for '(' lpvalue '=' expression ';' expression ';' error ')' @@ -810,6 +818,25 @@ loop_statement /* IEEE1800-2005: A.6.8 */ yyerror(@1, "error: Error in while loop condition."); } + | K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null + { $$ = 0; + yyerror(@4, "error: Errors in foreach loop variables list."); + } + ; + +loop_variables /* IEEE1800-2005: A.6.8 */ + : loop_variables ',' IDENTIFIER + { list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + delete[]$3; + $$ = tmp; + } + | IDENTIFIER + { list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + delete[]$1; + $$ = tmp; + } ; non_integer_type /* IEEE1800-2005: A.2.2.1 */ From f33086fed4e4d07ffb78f109a55c873d3c7565ec Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 18:45:22 -0800 Subject: [PATCH 68/88] Parse dynamic_array_new statements. --- parse.y | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/parse.y b/parse.y index dbe116041..d6f195985 100644 --- a/parse.y +++ b/parse.y @@ -496,7 +496,7 @@ static void current_task_set_statement(vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type inc_or_dec_expression lpvalue +%type dynamic_array_new inc_or_dec_expression lpvalue %type branch_probe_expression %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list @@ -697,6 +697,19 @@ data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ rule documented in IEEE1800-2005: A.1.8 */ endnew_opt : ':' K_new | ; + /* The dynamic_array_new rule is kinda like an expression, but it is + treated differently by rules that use this "expression". Watch out! */ + +dynamic_array_new /* IEEE1800-2005: A.2.4 */ + : K_new '[' expression ']' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + | K_new '[' expression ']' '(' expression ')' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + ; for_step /* IEEE1800-2005: A.6.8 */ : lpvalue '=' expression @@ -5262,6 +5275,16 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + /* The IEEE1800 standard defines dynamic_array_new assignment as a + different rule from regular assignment. That implies that the + dynamic_array_new is not an expression in general, which makes + some sense. Elaboration should make sure the lpvalue is an array name. */ + + | lpvalue '=' dynamic_array_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; From 68eab8c66482b0eccc0aa1e6a824d322362c3d7b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 26 Feb 2012 19:16:10 -0800 Subject: [PATCH 69/88] Parse function declarations in classes. Also add support for function end names when parsing SystemVerilog. --- parse.y | 187 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 74 deletions(-) diff --git a/parse.y b/parse.y index d6f195985..628def334 100644 --- a/parse.y +++ b/parse.y @@ -632,6 +632,8 @@ class_item /* IEEE1800-2005: A.1.8 */ | task_declaration + | function_declaration + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -724,6 +726,116 @@ for_step /* IEEE1800-2005: A.6.8 */ ; + /* The function declaration rule matches the function declaration + header, then pushes the function scope. This causes the + definitions in the func_body to take on the scope of the function + instead of the module. */ +function_declaration /* IEEE1800-2005: A.2.6 */ + : K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + function_item_list statement_list + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + assert($8 && $8->size() > 0); + if ($8->size() == 1) { + current_function->set_statement((*$8)[0]); + delete $8; + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @8); + tmp->set_statement( *$8 ); + current_function->set_statement(tmp); + delete $8; + if (!gn_system_verilog()) { + yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); + } + } + pform_pop_scope(); + current_function = 0; + } + endname_opt + { // Last step: check any closing name. + if ($11 && (strcmp($4,$11) != 0)) { + yyerror(@11, "error: End name doesn't match function name"); + } + if ($11 && !gn_system_verilog()) { + yyerror(@11, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($11) delete[]$11; + } + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + '(' tf_port_list_opt ')' ';' + block_item_decls_opt + statement_list + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + assert($11 && $11->size() > 0); + if ($11->size() == 1) { + current_function->set_statement((*$11)[0]); + delete $11; + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @11); + tmp->set_statement( *$11 ); + current_function->set_statement(tmp); + delete $11; + if (!gn_system_verilog()) { + yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); + } + } + pform_pop_scope(); + current_function = 0; + if ($7==0 && !gn_system_verilog()) { + yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); + } + } + endname_opt + { // Last step: check any closing name. + if ($14 && (strcmp($4,$14) != 0)) { + yyerror(@14, "error: End name doesn't match function name"); + } + if ($14 && !gn_system_verilog()) { + yyerror(@14, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($14) delete[]$14; + } + + /* Detect and recover from some errors. */ + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction + { /* */ + if (current_function) { + pform_pop_scope(); + current_function = 0; + } + assert(current_function == 0); + yyerror(@1, "error: Syntax error defining function."); + yyerrok; + } + endname_opt + { // Last step: check any closing name. + if ($8 && (strcmp($4,$8) != 0)) { + yyerror(@4, "error: End name doesn't match function name"); + } + if ($8 && !gn_system_verilog()) { + yyerror(@8, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($8) delete[]$8; + } + + ; + implicit_class_handle /* IEEE1800-2005: A.8.4 */ : K_this | K_super @@ -3643,80 +3755,7 @@ module_item | task_declaration - /* The function declaration rule matches the function declaration - header, then pushes the function scope. This causes the - definitions in the func_body to take on the scope of the function - instead of the module. */ - - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - function_item_list statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($8 && $8->size() > 0); - if ($8->size() == 1) { - current_function->set_statement((*$8)[0]); - delete $8; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @8); - tmp->set_statement( *$8 ); - current_function->set_statement(tmp); - delete $8; - if (!gn_system_verilog()) { - yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - } - - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - '(' tf_port_list_opt ')' ';' - block_item_decls_opt - statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($11 && $11->size() > 0); - if ($11->size() == 1) { - current_function->set_statement((*$11)[0]); - delete $11; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @11); - tmp->set_statement( *$11 ); - current_function->set_statement(tmp); - delete $11; - if (!gn_system_verilog()) { - yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - if ($7==0 && !gn_system_verilog()) { - yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); - } - } - | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction - { /* */ - if (current_function) { - pform_pop_scope(); - current_function = 0; - } - assert(current_function == 0); - yyerror(@1, "error: Syntax error defining function."); - yyerrok; - delete[]$4; - } + | function_declaration /* A generate region can contain further module items. Actually, it is supposed to be limited to certain kinds of module items, but From dbc58838d5cde832c0201f74578c620146bcd6f2 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 1 Mar 2012 18:17:52 -0800 Subject: [PATCH 70/88] Parse class extends syntax and property qualifiers. --- parse.y | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/parse.y b/parse.y index 628def334..15b6685c8 100644 --- a/parse.y +++ b/parse.y @@ -462,6 +462,7 @@ static void current_task_set_statement(vector*s) %type udp_initial_expr_opt %type register_variable net_variable endname_opt +%type class_declaration_extends_opt %type register_variable_list net_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers @@ -592,23 +593,44 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class IDENTIFIER ';' - class_items_opt K_endclass endname_opt + : K_virtual_opt K_class IDENTIFIER class_declaration_extends_opt ';' + class_items_opt K_endclass { // Process a class - if ($7 && strcmp($3,$7)!=0) { - yyerror(@7, "error: Class end name doesn't match class name."); - delete[]$7; + if ($4) { + yyerror(@4, "sorry: Class extends not supported yet."); + delete[]$4; } yyerror(@2, "sorry: Class declarations not supported yet."); } + endname_opt + { + if ($9 && strcmp($3,$9)!=0) { + yyerror(@9, "error: Class end name doesn't match class name."); + delete[]$9; + } + delete[]$3; + } ; -class_items_opt + /* This rule implements [ extends class_type ] in the + class_declaration. It is not a rule of its own in the LRM. */ + +class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ + : K_extends IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + + /* The class_items_opt and class_items rules together implement the + rule snippet { class_item } (zero or more class_item) of the + class_declaration. */ +class_items_opt /* IEEE1800-2005: A.1.2 */ : class_items | ; -class_items +class_items /* IEEE1800-2005: A.1.2 */ : class_items class_item | class_item ; @@ -625,7 +647,7 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Class properties... */ - | data_type list_of_variable_decl_assignments ';' + | property_qualifier_opt data_type list_of_variable_decl_assignments ';' /* Class methods... */ @@ -642,6 +664,17 @@ class_item /* IEEE1800-2005: A.1.8 */ yyerrok; } + | error ';' + { yyerror(@2, "error: invalid class item."); + yyerrok; + } + + ; + +class_item_qualifier /* IEEE1800-2005 A.1.8 */ + : K_static + | K_protected + | K_local ; data_type /* IEEE1800-2005: A.2.2.1 */ @@ -1001,6 +1034,30 @@ port_direction_opt | { $$ = NetNet::PIMPLICIT; } ; + /* The property_qualifier rule is as literally described in the LRM, + but the use is usually as { property_qualifier }, which is + implemented bt the property_qualifier_opt rule below. */ + +property_qualifier /* IEEE1800-2005 A.1.8 */ + : class_item_qualifier + | random_qualifier + ; + +property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ + : property_qualifier_list + | + ; + +property_qualifier_list /* IEEE1800-2005 A.1.8 */ + : property_qualifier_list property_qualifier + | property_qualifier + ; + +random_qualifier /* IEEE1800-2005 A.1.8 */ + : K_rand + | K_randc + ; + /* real and realtime are exactly the same so save some code * with a common matching rule. */ real_or_realtime From 64ea3288233b3701f60d1e54550f1a654159fdbc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 1 Mar 2012 18:48:16 -0800 Subject: [PATCH 71/88] Parse dynamic array declarations. --- parse.y | 84 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/parse.y b/parse.y index 15b6685c8..02a458b28 100644 --- a/parse.y +++ b/parse.y @@ -982,6 +982,56 @@ loop_statement /* IEEE1800-2005: A.6.8 */ } ; + +/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ +list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */ + : variable_decl_assignment + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | list_of_variable_decl_assignments ',' variable_decl_assignment + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +variable_decl_assignment /* IEEE1800-2005 A.2.3 */ + : IDENTIFIER dimensions_opt + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + if ($2) { + tmp->index = *$2; + delete $2; + } + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' expression + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->expr .reset($3); + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '[' ']' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Dynamic arrays not yet supported here."); + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '[' '$' ']' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Queue dimensions not yet supported here."); + delete[]$1; + $$ = tmp; + } + ; + + loop_variables /* IEEE1800-2005: A.6.8 */ : loop_variables ',' IDENTIFIER { list*tmp = $1; @@ -4703,40 +4753,6 @@ register_variable_list } ; -/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ -list_of_variable_decl_assignments - : variable_decl_assignment - { list*tmp = new list; - tmp->push_back($1); - $$ = tmp; - } - | list_of_variable_decl_assignments ',' variable_decl_assignment - { list*tmp = $1; - tmp->push_back($3); - $$ = tmp; - } - ; - -variable_decl_assignment - : IDENTIFIER dimensions_opt - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - if ($2) { - tmp->index = *$2; - delete $2; - } - delete[]$1; - $$ = tmp; - } - | IDENTIFIER '=' expression - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - tmp->expr .reset($3); - delete[]$1; - $$ = tmp; - } - ; - net_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); From f749867369a26bb52c7b9d3ba8af9c19b601eeac Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 2 Mar 2012 18:34:43 -0800 Subject: [PATCH 72/88] Rework rules for variable_dimensions, and support more syntax. --- PTask.h | 4 +- elab_scope.cc | 9 +- elab_sig.cc | 33 +++--- parse.y | 316 ++++++++++++++++++++++++-------------------------- pform.cc | 77 ++++++------ pform.h | 26 ++--- pform_types.h | 11 +- 7 files changed, 229 insertions(+), 247 deletions(-) diff --git a/PTask.h b/PTask.h index b06375dfc..4cd6a9a22 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ #ifndef __PTask_H #define __PTask_H /* - * Copyright (c) 1999-2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2008,2010,2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -46,7 +46,7 @@ enum PTaskFuncEnum { struct PTaskFuncArg { PTaskFuncEnum type; - vector*range; + std::list*range; }; /* diff --git a/elab_scope.cc b/elab_scope.cc index a93c9a08c..efce812c6 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -133,9 +133,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { bool rc_flag; - assert(enum_type->range->size() == 2); - NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1); + assert(enum_type->range->size() == 1); + index_component_t index = enum_type->range->front(); + NetExpr*msb_ex = elab_and_eval(des, scope, index.msb, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, index.lsb, -1); long msb = 0; rc_flag = eval_as_long(msb, msb_ex); diff --git a/elab_sig.cc b/elab_sig.cc index 42ed8c355..1a00cb786 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -476,15 +476,12 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_REG: case PTF_REG_S: if (return_type_.range) { - ivl_assert(*this, return_type_.range->size() == 2); + ivl_assert(*this, return_type_.range->size() == 1); + index_component_t index = return_type_.range->front(); - NetExpr*me = elab_and_eval(des, scope, - return_type_.range->at(0), -1, - true); + NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); assert(me); - NetExpr*le = elab_and_eval(des, scope, - return_type_.range->at(1), -1, - true); + NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); assert(le); long mnum = 0, lnum = 0; @@ -550,17 +547,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_ATOM2: case PTF_ATOM2_S: - ivl_assert(*this, return_type_.range != 0); long use_wid; { - NetExpr*me = elab_and_eval(des, scope, - (*return_type_.range)[0], -1, - true); - assert(me); - NetExpr*le = elab_and_eval(des, scope, - (*return_type_.range)[1], -1, - true); - assert(le); + ivl_assert(*this, return_type_.range->size() == 1); + index_component_t index = return_type_.range->front(); + NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); + ivl_assert(*this, me); + NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); + ivl_assert(*this, le); long mnum = 0, lnum = 0; if ( ! get_const_argument(me, mnum) ) { @@ -805,9 +799,10 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, long use_msb = 0; long use_lsb = 0; if (curp->range.get() && ! curp->range->empty()) { - ivl_assert(*curp, curp->range->size() == 2); - PExpr*msb_pex = curp->range->front(); - PExpr*lsb_pex = curp->range->back(); + ivl_assert(*curp, curp->range->size() == 1); + index_component_t index = curp->range->front(); + PExpr*msb_pex = index.msb; + PExpr*lsb_pex = index.lsb; NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); ivl_assert(*curp, tmp); diff --git a/parse.y b/parse.y index 02a458b28..411875217 100644 --- a/parse.y +++ b/parse.y @@ -38,7 +38,7 @@ extern void lex_end_table(); bool have_timeunit_decl = false; bool have_timeprec_decl = false; -static list* param_active_range = 0; +static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -48,7 +48,7 @@ static struct { NetNet::PortType port_type; ivl_variable_type_t var_type; bool sign_flag; - list* range; + list* range; data_type_t* data_type; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, false, 0, 0}; @@ -98,8 +98,7 @@ static list >* make_port_list(char*id, PExpr*expr) delete[]id; return tmp; } -static list >* make_port_list(list >*tmp, +static list >* make_port_list(list >*tmp, char*id, PExpr*expr) { tmp->push_back(make_pair(lex_strings.make(id), expr)); @@ -107,16 +106,19 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { - list*range = new list; + list*range = new list; - range->push_back(new PENumber(new verinum(wid-1, integer_width))); - range->push_back(new PENumber(new verinum((uint64_t)0, integer_width))); + index_component_t tmp; + tmp.msb = new PENumber(new verinum(wid-1, integer_width)); + tmp.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + range->push_back(tmp); return range; } +#if 0 /* * Make a range vector from an existing pair of expressions. */ @@ -129,7 +131,8 @@ static vector* make_range_vector(list*that) delete that; return tmp; } - +#endif +#if 0 /* * Make a range vector from a width. Generate the msb and lsb * expressions to get the canonical range for the given width. @@ -141,7 +144,7 @@ static vector* make_range_vector(uint64_t wid) tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); return tmp; } - +#endif static list* list_from_identifier(char*id) { list*tmp = new list; @@ -157,12 +160,12 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -list* copy_range(list* orig) +list* copy_range(list* orig) { - list*copy = 0; + list*copy = 0; if (orig) - copy = new list (*orig); + copy = new list (*orig); return copy; } @@ -512,8 +515,8 @@ static void current_task_set_statement(vector*s) %type struct_union_member_list %type struct_data_type -%type range range_opt variable_dimension -%type dimensions_opt dimensions +%type range range_opt +%type dimensions_opt dimensions variable_dimension %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt @@ -1015,13 +1018,6 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } - | IDENTIFIER '[' ']' - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - yyerror("sorry: Dynamic arrays not yet supported here."); - delete[]$1; - $$ = tmp; - } | IDENTIFIER '[' '$' ']' { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = lex_strings.make($1); @@ -1272,7 +1268,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be integer with a width of [31:0]. */ : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1297,7 +1293,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1414,18 +1410,39 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ variable_dimension /* IEEE1800-2005: A.2.5 */ : '[' expression ':' expression ']' - { list*tmp = new list; - tmp->push_back($2); - tmp->push_back($4); + { list *tmp = new list; + index_component_t index; + index.sel = index_component_t::SEL_PART; + index.msb = $2; + index.lsb = $4; + tmp->push_back(index); + $$ = tmp; + } + | '[' expression ']' + { // SystemVerilog canonical range + if (generation_flag < GN_VER2005_SV) { + warn_count += 1; + cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " + << "Use at least -g2005-sv to remove this warning." << endl; + } + list *tmp = new list; + index_component_t index; + index.sel = index_component_t::SEL_PART; + index.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + index.msb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); + tmp->push_back(index); $$ = tmp; } | '[' ']' - { list*tmp = new list; - tmp->push_back(0); - tmp->push_back(0); + { list *tmp = new list; + index_component_t index; + index.msb = 0; + index.lsb = 0; + yyerror("sorry: Dynamic array ranges not supported."); + tmp->push_back(index); $$ = tmp; } -; + ; /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a @@ -2822,20 +2839,21 @@ gate_instance $$ = tmp; } - | IDENTIFIER range '(' expression_list_with_nuls ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' expression_list_with_nuls ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } + | '(' expression_list_with_nuls ')' { lgate*tmp = new lgate; tmp->name = ""; @@ -2847,50 +2865,50 @@ gate_instance /* Degenerate modules can have no ports. */ - | IDENTIFIER range - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = 0; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = 0; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } /* Modules can also take ports by port-name expressions. */ - | IDENTIFIER '(' port_name_list ')' - { lgate*tmp = new lgate; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $3; - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - $$ = tmp; - } + | IDENTIFIER '(' port_name_list ')' + { lgate*tmp = new lgate; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $3; + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + $$ = tmp; + } - | IDENTIFIER range '(' port_name_list ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' port_name_list ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } | IDENTIFIER '(' error ')' { lgate*tmp = new lgate; @@ -3143,7 +3161,7 @@ port_declaration K_input atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINPUT, @@ -3289,7 +3307,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -3308,7 +3326,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER '=' expression { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -4606,9 +4624,13 @@ port_reference_list /* The range is a list of variable dimensions. */ range : variable_dimension + { $$ = $1; } | range variable_dimension - { list*tmp = $1; - if ($2) tmp->splice(tmp->end(), *$2); + { list*tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } $$ = tmp; } ; @@ -4623,88 +4645,54 @@ dimensions_opt | dimensions { $$ = $1; } dimensions - : '[' expression ':' expression ']' - { list *tmp = new list; - index_component_t index; - index.msb = $2; - index.lsb = $4; - tmp->push_back(index); - $$ = tmp; - } - | '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = new list; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ':' expression ']' - { list *tmp = $1; - index_component_t index; - index.msb = $3; - index.lsb = $5; - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = $1; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $3, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } + : variable_dimension + { $$ = $1; } + | dimensions variable_dimension + { list *tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } + $$ = tmp; + } + ; /* This is used to express the return type of a function. */ function_range_or_type_opt : unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($1) - $$.type = PTF_REG_S; - if ($2) - $$.range = make_range_vector($2); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($1) + $$.type = PTF_REG_S; + if ($2) + $$.range = $2; + } | K_reg unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($2) + $$.type = PTF_REG_S; + if ($3) + $$.range = $3; + } | bit_logic unsigned_signed_opt range_opt - { - /* the default type is bit/logic unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is bit/logic unsigned and no range */ + $$.type = PTF_REG; + $$.range = 0; + if ($2) + $$.type = PTF_REG_S; + if ($3) + $$.range = $3; + } | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } | K_time { $$.range = 0; $$.type = PTF_TIME; } - | atom2_type { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_signed { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_unsigned { $$.range = make_range_vector($1); $$.type = PTF_ATOM2; } + | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } ; /* The register_variable rule is matched only when I am parsing @@ -5577,7 +5565,7 @@ task_port_item shape. Generate a range ([31:0]) to make it work. */ | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, range_stub, $3, true); $$ = tmp; @@ -5586,7 +5574,7 @@ task_port_item /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, range_stub, $3); $$ = tmp; diff --git a/pform.cc b/pform.cc index 2a8653c60..d500bf7ff 100644 --- a/pform.cc +++ b/pform.cc @@ -1480,16 +1480,15 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } -static void ranges_from_list(list&rlist, const list*range) +static void ranges_from_list(list&rlist, + const list*range) { - // There must be an even number of expressions in the - // range. The parser will assure that for us. - assert(range->size()%2 == 0); - list::const_iterator rcur = range->begin(); - while (rcur != range->end()) { + // Convert a list of index_component_t to PWire::range_t. + for (list::const_iterator rcur = range->begin() + ; rcur != range->end() ; ++rcur) { PWire::range_t rng; - rng.msb = *rcur; ++rcur; - rng.lsb = *rcur; ++rcur; + rng.msb = rcur->msb; + rng.lsb = rcur->lsb; rlist.push_back(rng); } } @@ -1500,7 +1499,7 @@ static void ranges_from_list(list&rlist, const list*rang * and the name that I receive only has the tail component. */ static void pform_set_net_range(perm_string name, - const list*range, + const list*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) @@ -1528,12 +1527,10 @@ static void pform_set_net_range(perm_string name, } static void pform_set_net_range(list*names, - list*range, + list*range, bool signed_flag, ivl_variable_type_t dt) { - assert((range == 0) || (range->size()%2 == 0)); - for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; @@ -1601,8 +1598,8 @@ static void pform_makegate(PGBuiltin::Type type, perm_string dev_name = lex_strings.make(info.name); PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay); - if (info.range[0]) - cur->set_range(info.range[0], info.range[1]); + if (info.range.msb) + cur->set_range(info.range.msb, info.range.lsb); // The pform_makegates() that calls me will take care of // deleting the attr pointer, so tell the @@ -1741,7 +1738,7 @@ void pform_make_modgates(perm_string type, if (cur.parms_by_name) { pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } else if (cur.parms) { @@ -1755,14 +1752,14 @@ void pform_make_modgates(perm_string type, } pform_make_modgate(type, cur_name, overrides, cur.parms, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } else { list*wires = new list; pform_make_modgate(type, cur_name, overrides, wires, - cur.range[0], cur.range[1], + cur.range.msb, cur.range.lsb, cur.file, cur.lineno); } } @@ -1875,7 +1872,7 @@ void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr) { PWire*cur = pform_get_wire_in_scope(name); @@ -2011,7 +2008,7 @@ void pform_makewire(const vlltype&li, perm_string name, * pform_makewire above. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -2038,7 +2035,7 @@ void pform_makewire(const vlltype&li, * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -2149,7 +2146,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint) { @@ -2198,7 +2195,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, list*names) { if (atom2_type_t*atype = dynamic_cast (vtype)) { - list*range_tmp = make_range_from_width(atype->type_code); + list*range_tmp = make_range_from_width(atype->type_code); return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, range_tmp, names); @@ -2211,7 +2208,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, names); } - if (real_type_t*real_type = dynamic_cast (vtype)) { + if (/*real_type_t*real_type = */ dynamic_cast (vtype)) { return pform_make_task_ports(loc, pt, IVL_VT_REAL, true, 0, names); } @@ -2325,7 +2322,7 @@ LexicalScope::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, list*range, PExpr*expr, + bool signed_flag, list*range, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; @@ -2360,11 +2357,12 @@ void pform_set_parameter(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + index_component_t index = range->front(); + assert(index.msb); + assert(index.lsb); + parm.msb = index.msb; + parm.lsb = index.lsb; } else { parm.msb = 0; parm.lsb = 0; @@ -2378,7 +2376,7 @@ void pform_set_parameter(const struct vlltype&loc, void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr) + bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; @@ -2408,11 +2406,12 @@ void pform_set_localparam(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + index_component_t index = range->front(); + assert(index.msb); + assert(index.lsb); + parm.msb = index.msb; + parm.lsb = index.lsb; } else { parm.msb = 0; parm.lsb = 0; @@ -2511,7 +2510,7 @@ extern void pform_module_specify_path(PSpecPath*obj) void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType pt) { @@ -2627,7 +2626,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { pform_set_net_range(names, 0, true, IVL_VT_REAL); return; } @@ -2645,7 +2644,7 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, cur->set_signed(enum_type->signed_flag); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); + assert(enum_type->range->size() == 1); listrlist; ranges_from_list(rlist, enum_type->range.get()); cur->set_range(rlist, SR_NET); @@ -2659,7 +2658,7 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, listbase_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); + assert(enum_type->range->size() == 1); // Add the file and line information to the enumeration type. FILE_NAME(&(enum_type->li), li); diff --git a/pform.h b/pform.h index 0e2613715..85039e7df 100644 --- a/pform.h +++ b/pform.h @@ -101,24 +101,22 @@ struct net_decl_assign_t { /* The lgate is gate instantiation information. */ struct lgate { - lgate(int =0) + inline lgate(int =0) : parms(0), parms_by_name(0), file(NULL), lineno(0) - { range[0] = 0; - range[1] = 0; - } + { } string name; list*parms; list*parms_by_name; - PExpr*range[2]; + index_component_t range; const char* file; unsigned lineno; }; -extern std::list* make_range_from_width(uint64_t wid); -extern list* copy_range(list* orig); +extern std::list* make_range_from_width(uint64_t wid); +extern std::list* copy_range(std::list* orig); /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ @@ -161,7 +159,7 @@ extern void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -241,7 +239,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name, /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -258,7 +256,7 @@ extern void pform_makewire(const struct vlltype&li, /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -281,7 +279,7 @@ extern void pform_make_reginit(const struct vlltype&li, it. The second form takes a single name. */ extern void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType); extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, @@ -316,13 +314,13 @@ extern void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*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, bool signed_flag, - list*range, + list*range, PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); @@ -386,7 +384,7 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint = false); diff --git a/pform_types.h b/pform_types.h index 8ec228eaa..ab700cadc 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef __pform_types_H #define __pform_types_H /* - * Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2012 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 @@ -84,14 +84,14 @@ struct data_type_t : public LineInfo { struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; }; struct struct_member_t : public LineInfo { ivl_variable_type_t type; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; }; @@ -108,11 +108,12 @@ struct atom2_type_t : public data_type_t { }; struct vector_type_t : public data_type_t { - inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, list*pd) + inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, + std::list*pd) : base_type(bt), signed_flag(sf), pdims(pd) { } ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > pdims; + std::auto_ptr< list > pdims; }; struct real_type_t : public data_type_t { From 31d4aa9a77636c80f9617b2e73ba996eea3432ba Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 2 Mar 2012 21:16:53 -0800 Subject: [PATCH 73/88] Handle complexities of class name pre-declarations Class names can be declared early, before definitions, so that the name can be used as a type name. This thus allows class definitions to be separate from the declaration. This creates some complexity in the parser, since the lexor knows about the class names. --- lexor.lex | 2 +- parse.y | 118 +++++++++++++++++++++++++++++++++----------------- parse_misc.h | 2 + pform_types.h | 7 +++ 4 files changed, 88 insertions(+), 41 deletions(-) diff --git a/lexor.lex b/lexor.lex index b44d47166..64d6f2e3c 100644 --- a/lexor.lex +++ b/lexor.lex @@ -51,7 +51,7 @@ */ extern YYLTYPE yylloc; -static char* strdupnew(char const *str) +char* strdupnew(char const *str) { return str ? strcpy(new char [strlen(str)+1], str) : 0; } diff --git a/parse.y b/parse.y index 411875217..6874ba872 100644 --- a/parse.y +++ b/parse.y @@ -118,33 +118,6 @@ list* make_range_from_width(uint64_t wid) return range; } -#if 0 -/* - * Make a range vector from an existing pair of expressions. - */ -static vector* make_range_vector(list*that) -{ - assert(that->size() == 2); - vector*tmp = new vector (2); - tmp->at(0) = that->front(); - tmp->at(1) = that->back(); - delete that; - return tmp; -} -#endif -#if 0 -/* - * Make a range vector from a width. Generate the msb and lsb - * expressions to get the canonical range for the given width. - */ -static vector* make_range_vector(uint64_t wid) -{ - vector*tmp = new vector (2); - tmp->at(0) = new PENumber(new verinum(wid-1, integer_width)); - tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); - return tmp; -} -#endif static list* list_from_identifier(char*id) { list*tmp = new list; @@ -342,6 +315,7 @@ static void current_task_set_statement(vector*s) struct_type_t*struct_type; data_type_t*data_type; + class_type_t*class_type; verinum* number; @@ -464,8 +438,7 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable endname_opt -%type class_declaration_extends_opt +%type register_variable net_variable endname_opt class_declaration_endname_opt %type register_variable_list net_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers @@ -511,6 +484,8 @@ static void current_task_set_statement(vector*s) %type list_of_variable_decl_assignments %type data_type data_type_or_implicit +%type class_declaration_extends_opt +%type class_identifier %type struct_union_member %type struct_union_member_list %type struct_data_type @@ -596,30 +571,71 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ ; class_declaration /* IEEE1800-2005: A.1.2 */ - : K_virtual_opt K_class IDENTIFIER class_declaration_extends_opt ';' + : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' class_items_opt K_endclass - { // Process a class + { // Process a class. if ($4) { yyerror(@4, "sorry: Class extends not supported yet."); - delete[]$4; } yyerror(@2, "sorry: Class declarations not supported yet."); } - endname_opt - { - if ($9 && strcmp($3,$9)!=0) { + class_declaration_endname_opt + { // Wrap up the class. + if ($9 && $3 && $3->name != $9) { yyerror(@9, "error: Class end name doesn't match class name."); delete[]$9; } - delete[]$3; } ; +class_identifier + : IDENTIFIER + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($1); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$1; + $$ = tmp; + } + | TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast($1); + if (tmp == 0) { + yyerror(@1, "Type name is not a predeclared class name."); + } + $$ = tmp; + } + ; + + /* The endname after a class declaration is a little tricky because + the class name is detected by the lexor as a TYPE_IDENTIFER if it + does indeed match a name. */ +class_declaration_endname_opt + : ':' TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast ($2); + if (tmp == 0) { + yyerror(@2, "error: class declaration endname is not a class name\n"); + $$ = 0; + } else { + $$ = strdupnew(tmp->name.str()); + } + } + | ':' IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + /* This rule implements [ extends class_type ] in the - class_declaration. It is not a rule of its own in the LRM. */ + class_declaration. It is not a rule of its own in the LRM. + + Note that for this to be correct, the identifier after the + extends keyword must be a class name. Therefore, match + TYPE_IDENTIFIER instead of IDENTIFIER, and this rule will return + a data_type. */ class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ - : K_extends IDENTIFIER + : K_extends TYPE_IDENTIFIER { $$ = $2; } | { $$ = 0; } @@ -662,6 +678,16 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ + | property_qualifier_opt data_type error ';' + { yyerror(@3, "error: Errors in variable names after data type."); + yyerrok; + } + + | property_qualifier_opt IDENTIFIER error ';' + { yyerror(@3, "error: %s doesn't name a type.", $2); + yyerrok; + } + | K_function K_new error K_endfunction endnew_opt { yyerror(@1, "error: I give up on this class constructor declaration."); yyerrok; @@ -1591,7 +1617,13 @@ type_declaration /* These are forward declarations... */ | K_typedef K_class IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($3); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$3; + } | K_typedef K_enum IDENTIFIER ';' { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } | K_typedef K_struct IDENTIFIER ';' @@ -1599,7 +1631,13 @@ type_declaration | K_typedef K_union IDENTIFIER ';' { yyerror(@1, "sorry: Union forward declarations not supported yet.") } | K_typedef IDENTIFIER ';' - { yyerror(@1, "sorry: Class forward declarations not supported yet.") } + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($2); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$2; + } ; /* The structure for an enumeration data type is the keyword "enum", diff --git a/parse_misc.h b/parse_misc.h index 6d1aed925..037fefffe 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -95,4 +95,6 @@ extern verinum*make_unsized_binary(const char*txt); extern verinum*make_unsized_octal(const char*txt); extern verinum*make_unsized_hex(const char*txt); +extern char* strdupnew(char const *str); + #endif diff --git a/pform_types.h b/pform_types.h index ab700cadc..5e5a4a48f 100644 --- a/pform_types.h +++ b/pform_types.h @@ -121,6 +121,13 @@ struct real_type_t : public data_type_t { int type_code; }; +struct class_type_t : public data_type_t { + inline explicit class_type_t(perm_string n) + : name(n) { } + + perm_string name; +}; + /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name From 0e01dcf2b957f00c12233a7551c906c1733fc3d5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 Mar 2012 19:33:16 -0800 Subject: [PATCH 74/88] Miscellaneous SystemVerilog syntax. ... and sorry messages. --- PTask.h | 4 +- elab_sig.cc | 9 +++ parse.y | 161 +++++++++++++++++++++++++++++++++----------------- pform.cc | 15 +++-- pform_dump.cc | 8 ++- 5 files changed, 136 insertions(+), 61 deletions(-) diff --git a/PTask.h b/PTask.h index 4cd6a9a22..249573213 100644 --- a/PTask.h +++ b/PTask.h @@ -41,7 +41,9 @@ enum PTaskFuncEnum { PTF_REALTIME, PTF_TIME, PTF_ATOM2, - PTF_ATOM2_S + PTF_ATOM2_S, + PTF_STRING, + PTF_VOID }; struct PTaskFuncArg { diff --git a/elab_sig.cc b/elab_sig.cc index 1a00cb786..9c799dccd 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -582,6 +582,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->data_type(IVL_VT_BOOL); break; + case PTF_STRING: + cerr << get_fileline() << ": sorry: String functions are not supported yet" << endl; + break; + + case PTF_VOID: + // Void functions have no return value, so there is no + // signal to create here. + break; + default: if (ports_) { cerr << get_fileline() << ": internal error: I don't know " diff --git a/parse.y b/parse.y index 6874ba872..b237a6caa 100644 --- a/parse.y +++ b/parse.y @@ -505,8 +505,7 @@ static void current_task_set_statement(vector*s) %type event_control %type statement statement_or_null compressed_statement %type loop_statement for_step -%type statement_list statement_or_null_list -%type statement_list_or_null +%type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -656,11 +655,23 @@ class_items /* IEEE1800-2005: A.1.2 */ class_item /* IEEE1800-2005: A.1.8 */ - /* class_constructor_declaration */ - : K_function K_new '(' tf_port_list_opt ')' ';' - statement_list_or_null + /* IEEE1800 A.1.8: class_constructor_declaration */ + : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + statement_or_null_list_opt K_endfunction endnew_opt - { yyerror(@1, "sorry: Class constructors not supported yet."); + { yyerror(@3, "sorry: Class constructors not supported yet."); + yyerrok; + } + + /* IEEE1800 A.1.8: class_constructor_declaration with a call to + parent constructor. Note that the implicit_class_handle must + be K_super ("this.new" makes little sense) but that would + cause a conflict. */ + | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + implicit_class_handle '.' K_new '(' ')' + statement_or_null_list_opt + K_endfunction endnew_opt + { yyerror(@3, "sorry: Class constructors not supported yet."); yyerrok; } @@ -671,9 +682,9 @@ class_item /* IEEE1800-2005: A.1.8 */ /* Class methods... */ - | task_declaration + | method_qualifier_opt task_declaration - | function_declaration + | method_qualifier_opt function_declaration /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -688,7 +699,7 @@ class_item /* IEEE1800-2005: A.1.8 */ yyerrok; } - | K_function K_new error K_endfunction endnew_opt + | method_qualifier_opt K_function K_new error K_endfunction endnew_opt { yyerror(@1, "error: I give up on this class constructor declaration."); yyerrok; } @@ -797,7 +808,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - function_item_list statement_list + function_item_list statement_or_null_list K_endfunction { current_function->set_ports($7); current_function->set_return($3); @@ -836,7 +847,7 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } '(' tf_port_list_opt ')' ';' block_item_decls_opt - statement_list + statement_or_null_list K_endfunction { current_function->set_ports($7); current_function->set_return($3); @@ -1044,6 +1055,13 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } + | IDENTIFIER '=' K_new '(' ')' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Class initialization assignment not supported here."); + delete[]$1; + $$ = tmp; + } | IDENTIFIER '[' '$' ']' { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = lex_strings.make($1); @@ -1069,6 +1087,17 @@ loop_variables /* IEEE1800-2005: A.6.8 */ } ; +method_qualifier /* IEEE1800-2005: A.1.8 */ + : K_virtual + | class_item_qualifier + ; + +method_qualifier_opt + : method_qualifier + | + ; + + non_integer_type /* IEEE1800-2005: A.2.2.1 */ : K_real { $$ = K_real; } | K_realtime { $$ = K_real; } @@ -1389,6 +1418,19 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } + | port_direction_opt data_type_or_implicit IDENTIFIER '[' '$' ']' + { yyerror(@5, "sorry: Queues not supported here."); + delete[]$3; + $$ = 0; + } + + /* Rules to match error cases... */ + + | port_direction_opt data_type_or_implicit IDENTIFIER error + { yyerror(@3, "error: Error in task/function port item after port name %s.", $3); + yyerrok; + $$ = 0; + } ; /* This rule matches the [ = ] part of the tf_port_item rules. */ @@ -2612,6 +2654,11 @@ expr_primary } } + | implicit_class_handle + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + /* Many of the VAMS built-in functions are available as builtin functions with $system_function equivalents. */ @@ -4695,7 +4742,9 @@ dimensions } ; - /* This is used to express the return type of a function. */ + /* This is used to express the return type of a function. This is + not quite right, and should be replaced with a variant that uses + the data_type rule. This will get us by for now. */ function_range_or_type_opt : unsigned_signed_opt range_opt { /* the default type is reg unsigned and no range */ @@ -4727,7 +4776,9 @@ function_range_or_type_opt | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } + | K_string { $$.range = 0; $$.type = PTF_STRING; } | K_time { $$.range = 0; $$.type = PTF_TIME; } + | K_void { $$.range = 0; $$.type = PTF_VOID; } | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } @@ -5191,7 +5242,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_begin statement_list K_end + | K_begin statement_or_null_list K_end { PBlock*tmp = new PBlock(PBlock::BL_SEQ); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -5204,7 +5255,7 @@ statement /* This is roughly statement_item in the LRM */ current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_end + statement_or_null_list_opt K_end { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -5227,7 +5278,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } - | K_fork statement_list K_join + | K_fork statement_or_null_list K_join { PBlock*tmp = new PBlock(PBlock::BL_PAR); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -5240,7 +5291,7 @@ statement /* This is roughly statement_item in the LRM */ current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_join + statement_or_null_list_opt K_join { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -5362,6 +5413,7 @@ statement /* This is roughly statement_item in the LRM */ FILE_NAME(tmp, @1); $$ = tmp; } + | error '=' expression ';' { yyerror(@2, "Syntax in assignment statement l-value."); yyerrok; @@ -5446,25 +5498,46 @@ statement /* This is roughly statement_item in the LRM */ delete[]$1; $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' - { PCallTask*tmp = new PCallTask(*$1, *$3); - FILE_NAME(tmp, @1); - delete $1; - delete $3; - $$ = tmp; - } + + | hierarchy_identifier '(' expression_list_proper ')' ';' + { PCallTask*tmp = new PCallTask(*$1, *$3); + FILE_NAME(tmp, @1); + delete $1; + delete $3; + $$ = tmp; + } + + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';' + { PCallTask*tmp = new PCallTask(*$3, *$5); + yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); + FILE_NAME(tmp, @1); + delete $3; + delete $5; + $$ = tmp; + } /* NOTE: The standard doesn't really support an empty argument list between parentheses, but it seems natural, and people commonly want it. So accept it explicitly. */ - | hierarchy_identifier '(' ')' ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } + | hierarchy_identifier '(' ')' ';' + { listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + + + | implicit_class_handle '.' hierarchy_identifier '(' ')' ';' + { listpt; + yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); + PCallTask*tmp = new PCallTask(*$3, pt); + FILE_NAME(tmp, @3); + delete $3; + $$ = tmp; + } + | hierarchy_identifier ';' { listpt; PCallTask*tmp = new PCallTask(*$1, pt); @@ -5537,34 +5610,14 @@ compressed_statement } ; -statement_list_or_null - : statement_list_or_null statement - { vector*tmp = $1; - if (tmp) { - tmp->push_back($2); - } else { - tmp = new vector(1); - tmp->at(0) = $2; - } - $$ = tmp; - } + +statement_or_null_list_opt + : statement_or_null_list + { $$ = $1; } | { $$ = 0; } ; -statement_list - : statement_list statement - { vector*tmp = $1; - tmp->push_back($2); - $$ = tmp; - } - | statement - { vector*tmp = new vector(1); - tmp->at(0) = $1; - $$ = tmp; - } - ; - statement_or_null_list : statement_or_null_list statement_or_null { vector*tmp = $1; diff --git a/pform.cc b/pform.cc index d500bf7ff..99d44719e 100644 --- a/pform.cc +++ b/pform.cc @@ -416,11 +416,16 @@ data_type_t* pform_test_type_identifier(const char*txt) return false; perm_string name = lex_strings.make(txt); - map::iterator cur = lexical_scope->typedefs.find(name); - if (cur != lexical_scope->typedefs.end()) - return cur->second; - else - return 0; + map::iterator cur; + LexicalScope*cur_scope = lexical_scope; + do { + cur = cur_scope->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return cur->second; + + cur_scope = cur_scope->parent_scope(); + } while (cur_scope); + return 0; } static void pform_put_behavior_in_scope(PProcess*pp) diff --git a/pform_dump.cc b/pform_dump.cc index 1ca78a67e..6f1840842 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -812,7 +812,13 @@ void PFunction::dump(ostream&out, unsigned ind) const out << "int unsigned "; break; case PTF_ATOM2_S: - cout << "int signed "; + out << "int signed "; + break; + case PTF_STRING: + out << "string "; + break; + case PTF_VOID: + out << "void "; break; } From 8c2e4a089241ad2404d9d4fbff7671a6b3d4ffa8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 Mar 2012 20:04:07 -0800 Subject: [PATCH 75/88] Support tasks with no behavioral statements (System Verilog) --- parse.y | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/parse.y b/parse.y index b237a6caa..f9cfbfa17 100644 --- a/parse.y +++ b/parse.y @@ -230,15 +230,37 @@ static long check_enum_seq_value(const YYLTYPE&loc, verinum *arg, bool zero_ok) return value; } -static void current_task_set_statement(vector*s) +static void current_task_set_statement(const YYLTYPE&loc, vector*s) { + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty tasks requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_task->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ if (s->size() == 1) { current_task->set_statement((*s)[0]); return; } + if (!gn_system_verilog()) { + yyerror(loc, "error: Task body with multiple statements requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); tmp->set_statement(*s); current_task->set_statement(tmp); } @@ -1193,10 +1215,10 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task = pform_push_task_scope(@1, $3, $2); } task_item_list_opt - statement_or_null_list + statement_or_null_list_opt K_endtask { current_task->set_ports($6); - current_task_set_statement($7); + current_task_set_statement(@3, $7); pform_pop_scope(); current_task = 0; if ($7->size() > 1 && !gn_system_verilog()) { @@ -1226,16 +1248,13 @@ task_declaration /* IEEE1800-2005: A.2.7 */ } tf_port_list ')' ';' block_item_decls_opt - statement_or_null_list + statement_or_null_list_opt K_endtask { current_task->set_ports($6); - current_task_set_statement($10); + current_task_set_statement(@3, $10); pform_pop_scope(); current_task = 0; - if ($10->size() > 1 && !gn_system_verilog()) { - yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $10; + if ($10) delete $10; } endname_opt { // Last step: check any closing name. This is done late so @@ -1261,7 +1280,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ statement_or_null_list K_endtask { current_task->set_ports(0); - current_task_set_statement($9); + current_task_set_statement(@3, $9); pform_pop_scope(); current_task = 0; cerr << @3 << ": warning: task definition for \"" << $3 From da743c3b2cb4f273e4dfbc59b93f5f5baed8f5bb Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 9 Mar 2012 18:54:05 -0800 Subject: [PATCH 76/88] Bunches more SystemVerilog syntax. --- parse.y | 293 ++++++++++++++++++++++++++++++++++++++++---------- pform.cc | 75 +++++++------ pform.h | 3 +- pform_dump.cc | 5 +- 4 files changed, 285 insertions(+), 91 deletions(-) diff --git a/parse.y b/parse.y index f9cfbfa17..6bcfffff2 100644 --- a/parse.y +++ b/parse.y @@ -265,6 +265,41 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) current_task->set_statement(tmp); } +static void current_function_set_statement(const YYLTYPE&loc, vector*s) +{ + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty functions requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_function->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ + assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ + if (s->size() == 1) { + current_function->set_statement((*s)[0]); + return; + } + + if (!gn_system_verilog()) { + yyerror(loc, "error: Function body with multiple statements requires SystemVerilog."); + } + + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + tmp->set_statement(*s); + current_function->set_statement(tmp); +} + %} %union { @@ -447,7 +482,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type from_exclude %type number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt -%type K_automatic_opt K_packed_opt K_reg_opt K_virtual_opt +%type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -495,8 +530,8 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type hierarchy_identifier %type assignment_pattern expression expr_primary expr_mintypmax -%type dynamic_array_new inc_or_dec_expression lpvalue -%type branch_probe_expression +%type class_new dynamic_array_new inc_or_dec_expression inside_expression lpvalue +%type branch_probe_expression streaming_concatenation %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper @@ -526,7 +561,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %type event_expression %type event_control %type statement statement_or_null compressed_statement -%type loop_statement for_step +%type loop_statement for_step jump_statement %type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -543,7 +578,7 @@ static void current_task_set_statement(const YYLTYPE&loc, vector*s) %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ -%right '?' ':' +%right '?' ':' K_inside %left K_LOR %left K_LAND %left '|' @@ -609,6 +644,11 @@ class_declaration /* IEEE1800-2005: A.1.2 */ } ; +class_constraint /* IEEE1800-2005: A.1.8 */ + : constraint_prototype + | constraint_declaration + ; + class_identifier : IDENTIFIER { // Create a synthetic typedef for the class name so that the @@ -690,7 +730,7 @@ class_item /* IEEE1800-2005: A.1.8 */ be K_super ("this.new" makes little sense) but that would cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' - implicit_class_handle '.' K_new '(' ')' + implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -708,6 +748,11 @@ class_item /* IEEE1800-2005: A.1.8 */ | method_qualifier_opt function_declaration + + /* Class constraints... */ + + | class_constraint + /* Here are some error matching rules to help recover from various syntax errors within a class declaration. */ @@ -739,6 +784,65 @@ class_item_qualifier /* IEEE1800-2005 A.1.8 */ | K_local ; +class_new /* IEEE1800-2005 A.2.4 */ + : K_new '(' ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + | K_new '(' expression_list_proper ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + ; + +constraint_block_item /* IEEE1800-2005 A.1.9 */ + : constraint_expression + ; + +constraint_block_item_list + : constraint_block_item_list constraint_block_item + | constraint_block_item + ; + +constraint_block_item_list_opt + : + | constraint_block_item_list + ; + +constraint_declaration /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER '{' constraint_block_item_list_opt '}' + { yyerror(@2, "sorry: Constraint declarations not supported.") } + + /* Error handling rules... */ + + | K_static_opt K_constraint IDENTIFIER '{' error '}' + { yyerror(@4, "error: Errors in the constraint block item list."); } + ; + +constraint_expression /* IEEE1800-2005 A.1.9 */ + : expression ';' + | expression K_dist '{' '}' ';' + | expression K_TRIGGER constraint_set + | K_if '(' expression ')' constraint_set %prec less_than_K_else + | K_if '(' expression ')' constraint_set K_else constraint_set + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' constraint_set + ; + +constraint_expression_list /* */ + : constraint_expression_list constraint_expression + | constraint_expression + ; + +constraint_prototype /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER ';' + { yyerror(@2, "sorry: Constraint prototypes not supported.") } + ; + +constraint_set /* IEEE1800-2005 A.1.9 */ + : constraint_expression + | '{' constraint_expression_list '}' + ; + data_type /* IEEE1800-2005: A.2.2.1 */ : integer_vector_type unsigned_signed_opt range_opt { vector_type_t*tmp = new vector_type_t($1, $2, $3); @@ -830,24 +934,11 @@ function_declaration /* IEEE1800-2005: A.2.6 */ { assert(current_function == 0); current_function = pform_push_function_scope(@1, $4, $2); } - function_item_list statement_or_null_list + function_item_list statement_or_null_list_opt K_endfunction { current_function->set_ports($7); current_function->set_return($3); - assert($8 && $8->size() > 0); - if ($8->size() == 1) { - current_function->set_statement((*$8)[0]); - delete $8; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @8); - tmp->set_statement( *$8 ); - current_function->set_statement(tmp); - delete $8; - if (!gn_system_verilog()) { - yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); - } - } + current_function_set_statement($8? @8 : @4, $8); pform_pop_scope(); current_function = 0; } @@ -869,24 +960,11 @@ function_declaration /* IEEE1800-2005: A.2.6 */ } '(' tf_port_list_opt ')' ';' block_item_decls_opt - statement_or_null_list + statement_or_null_list_opt K_endfunction { current_function->set_ports($7); current_function->set_return($3); - assert($11 && $11->size() > 0); - if ($11->size() == 1) { - current_function->set_statement((*$11)[0]); - delete $11; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @11); - tmp->set_statement( *$11 ); - current_function->set_statement(tmp); - delete $11; - if (!gn_system_verilog()) { - yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); - } - } + current_function_set_statement($11? @11 : @4, $11); pform_pop_scope(); current_function = 0; if ($7==0 && !gn_system_verilog()) { @@ -965,6 +1043,13 @@ inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ } ; +inside_expression /* IEEE1800-2005 A.8.3 */ + : expression K_inside '{' open_range_list '}' + { yyerror(@2, "sorry: \"inside\" expressions not supported yet."); + $$ = 0; + } + ; + integer_vector_type /* IEEE1800-2005: A.2.2.1 */ : K_reg { $$ = IVL_VT_LOGIC; } | K_bit { $$ = IVL_VT_BOOL; } @@ -972,6 +1057,21 @@ integer_vector_type /* IEEE1800-2005: A.2.2.1 */ | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ ; +jump_statement /* IEEE1800-2005: A.6.5 */ + : K_break ';' + { yyerror(@1, "sorry: break statements not supported."); + $$ = 0; + } + | K_return ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + | K_return expression ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + ; + /* Loop statements are kinds of statements. */ loop_statement /* IEEE1800-2005: A.6.8 */ @@ -1084,13 +1184,6 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } - | IDENTIFIER '[' '$' ']' - { decl_assignment_t*tmp = new decl_assignment_t; - tmp->name = lex_strings.make($1); - yyerror("sorry: Queue dimensions not yet supported here."); - delete[]$1; - $$ = tmp; - } ; @@ -1135,6 +1228,11 @@ number : BASED_NUMBER based_size = 0; } ; +open_range_list /* IEEE1800-2005 A.2.11 */ + : open_range_list ',' value_range + | value_range + ; + port_direction /* IEEE1800-2005 A.1.3 */ : K_input { $$ = NetNet::PINPUT; } | K_output { $$ = NetNet::POUTPUT; } @@ -1203,6 +1301,33 @@ statement_or_null /* IEEE1800-2005: A.6.4 */ { $$ = 0; } ; +stream_expression + : expression + ; + +stream_expression_list + : stream_expression_list ',' stream_expression + | stream_expression + ; + +stream_operator + : K_LS + | K_RS + ; + +streaming_concatenation /* IEEE1800-2005: A.8.1 */ + : '{' stream_operator '{' stream_expression_list '}' '}' + { /* streaming concatenation is a SystemVerilog thing. */ + if (gn_system_verilog()) { + yyerror(@2, "sorry: Streaming concatenation not supported."); + $$ = 0; + } else { + yyerror(@2, "error: Streaming concatenation requires SystemVerilog"); + $$ = 0; + } + } + ; + /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the definitions in the task_body to take on the scope of the task @@ -1350,7 +1475,8 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ port_declaration_context.sign_flag = true; delete port_declaration_context.range; port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(@3, $1, IVL_VT_LOGIC, true, + svector*tmp = pform_make_task_ports(@3, use_port_type, + IVL_VT_LOGIC, true, range_stub, list_from_identifier($3), true); $$ = tmp; @@ -1424,7 +1550,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ FILE_NAME($2, @3); } port_declaration_context.data_type = $2; - tmp = pform_make_task_ports(@3, $1, $2, ilist); + tmp = pform_make_task_ports(@3, use_port_type, $2, ilist); } $$ = tmp; if ($4) { @@ -1437,12 +1563,6 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ } } - | port_direction_opt data_type_or_implicit IDENTIFIER '[' '$' ']' - { yyerror(@5, "sorry: Queues not supported here."); - delete[]$3; - $$ = 0; - } - /* Rules to match error cases... */ | port_direction_opt data_type_or_implicit IDENTIFIER error @@ -1495,6 +1615,13 @@ tf_port_list /* IEEE1800-2005: A.2.7 */ ; +value_range /* IEEE1800-2005: A.8.3 */ + : expression + { } + | '[' expression ':' expression ']' + { } + ; + variable_dimension /* IEEE1800-2005: A.2.5 */ : '[' expression ':' expression ']' { list *tmp = new list; @@ -1529,6 +1656,20 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ tmp->push_back(index); $$ = tmp; } + | '[' '$' ']' + { // SystemVerilog queue + list *tmp = new list; + index_component_t index; + index.msb = 0; + index.lsb = 0; + if (gn_system_verilog()) { + yyerror("sorry: Dynamic array ranges not supported."); + } else { + yyerror("error: Queue declarations require System Verilog."); + } + tmp->push_back(index); + $$ = tmp; + } ; /* Verilog-2001 supports attribute lists, which can be attached to a @@ -2306,10 +2447,12 @@ branch_probe_expression ; expression - : expr_primary - { $$ = $1; } - | inc_or_dec_expression - { $$ = $1; } + : expr_primary + { $$ = $1; } + | inc_or_dec_expression + { $$ = $1; } + | inside_expression + { $$ = $1; } | '+' expr_primary %prec UNARY_PREC { $$ = $2; } | '-' expr_primary %prec UNARY_PREC @@ -2678,6 +2821,11 @@ expr_primary $$ = 0; } + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + /* Many of the VAMS built-in functions are available as builtin functions with $system_function equivalents. */ @@ -2881,6 +3029,16 @@ expr_primary yyerrok; } + | '{' '}' + { // This is the empty queue syntax. + if (gn_system_verilog()) { + yyerror(@1, "sorry: Expty queue expressions not supported."); + } else { + yyerror(@1, "error: Concatenations are not allowed to be empty."); + } + $$ = 0; + } + /* Cast expressions are primaries */ | DEC_NUMBER '\'' '(' expression ')' @@ -2901,6 +3059,14 @@ expr_primary | assignment_pattern { $$ = $1; } + /* SystemVerilog supports streaming concatenation */ + | streaming_concatenation + { $$ = $1; } + + | K_null + { yyerror("sorry: null expressions not supported yet."); + $$ = 0; + } ; /* A function_item_list borrows the task_port_item run to match @@ -3533,6 +3699,11 @@ lpvalue delete $2; $$ = tmp; } + + | streaming_concatenation + { yyerror(@1, "sorry: streaming concatenation not supported in l-values."); + $$ = 0; + } ; @@ -5338,6 +5509,8 @@ statement /* This is roughly statement_item in the LRM */ | loop_statement { $$ = $1; } + | jump_statement { $$ = $1; } + | K_case '(' expression ')' case_items K_endcase { PCase*tmp = new PCase(NetCase::EQ, $3, $5); FILE_NAME(tmp, @1); @@ -5495,6 +5668,15 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + /* The class new and dynamic array new expressions are special, so + sit in rules of their own. */ + + | lpvalue '=' class_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); @@ -5980,4 +6162,5 @@ udp_primitive K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ; K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; +K_static_opt : K_static { $$ = true; } | { $$ = false; } ; K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/pform.cc b/pform.cc index 99d44719e..a8569ff01 100644 --- a/pform.cc +++ b/pform.cc @@ -2075,39 +2075,6 @@ void pform_makewire(const vlltype&li, } } -void pform_set_port_type(perm_string name, NetNet::PortType pt, - const char*file, unsigned lineno) -{ - PWire*cur = pform_get_wire_in_scope(name); - if (cur == 0) { - cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); - FILE_NAME(cur, file, lineno); - pform_put_wire_in_scope(name, cur); - } - - switch (cur->get_port_type()) { - case NetNet::PIMPLICIT: - if (! cur->set_port_type(pt)) - VLerror("error setting port direction."); - break; - - case NetNet::NOT_A_PORT: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " is not in the port list." - << endl; - error_count += 1; - break; - - default: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " already has a port declaration." - << endl; - error_count += 1; - break; - } - -} - /* * This function is called by the parser to create task ports. The * resulting wire (which should be a register) is put into a list to @@ -2155,6 +2122,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, list*names, bool isint) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(names); svector*res = new svector(0); for (list::iterator cur = names->begin() @@ -2513,12 +2481,48 @@ extern void pform_module_specify_path(PSpecPath*obj) pform_cur_module->specify_paths.push_back(obj); } + +static void pform_set_port_type(perm_string name, NetNet::PortType pt, + const char*file, unsigned lineno) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur == 0) { + cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); + FILE_NAME(cur, file, lineno); + pform_put_wire_in_scope(name, cur); + } + + switch (cur->get_port_type()) { + case NetNet::PIMPLICIT: + if (! cur->set_port_type(pt)) + VLerror("error setting port direction."); + break; + + case NetNet::NOT_A_PORT: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " is not in the port list." + << endl; + error_count += 1; + break; + + default: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " already has a port declaration." + << endl; + error_count += 1; + break; + } + +} + void pform_set_port_type(const struct vlltype&li, list*names, list*range, bool signed_flag, NetNet::PortType pt) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); + for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; @@ -2636,6 +2640,11 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + VLerror(li, "sorry: Class types not supported."); + return; + } + assert(0); } diff --git a/pform.h b/pform.h index 85039e7df..6af305314 100644 --- a/pform.h +++ b/pform.h @@ -282,8 +282,7 @@ extern void pform_set_port_type(const struct vlltype&li, list*range, bool signed_flag, NetNet::PortType); -extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, - const char*file, unsigned lineno); + extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); diff --git a/pform_dump.cc b/pform_dump.cc index 6f1840842..808ba4372 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -577,7 +577,10 @@ void PAssign::dump(ostream&out, unsigned ind) const if (delay_) out << "#" << *delay_ << " "; if (count_) out << "repeat(" << *count_ << ") "; if (event_) out << *event_ << " "; - out << *rval() << ";" << " /* " << get_fileline() << " */" << endl; + PExpr*rexpr = rval(); + if (rexpr) out << *rval() << ";"; + else out << ";"; + out << " /* " << get_fileline() << " */" << endl; } void PAssignNB::dump(ostream&out, unsigned ind) const From dbc6f0cff2ef726ee5ab8e4b01131c927a202216 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 10 Mar 2012 09:50:41 -0800 Subject: [PATCH 77/88] Parse SystemVerilog syntax for task calls. Tasks call arguments may be dropped in favor of default values. Allow for that in the syntax. This requires a little handling of the non-SystemVerilog case during elaboration. --- Statement.h | 12 ---- elaborate.cc | 45 +++++++++++--- parse.y | 170 +++++++++++++++++++++++++-------------------------- 3 files changed, 121 insertions(+), 106 deletions(-) diff --git a/Statement.h b/Statement.h index 5caf9644d..049aa118e 100644 --- a/Statement.h +++ b/Statement.h @@ -196,18 +196,6 @@ class PCallTask : public Statement { const pform_name_t& path() const; - unsigned nparms() const { return parms_.size(); } - - PExpr*&parm(unsigned idx) - { assert(idx < parms_.size()); - return parms_[idx]; - } - - PExpr* parm(unsigned idx) const - { assert(idx < parms_.size()); - return parms_[idx]; - } - virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; diff --git a/elaborate.cc b/elaborate.cc index e256a4df8..cd3ef2d73 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2825,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const des->errors += 1; } - unsigned parm_count = nparms(); + unsigned parm_count = parms_.size(); /* Catch the special case that the system task has no parameters. The "()" string will be parsed as a single empty parameter, when we really mean no parameters at all. */ - if ((nparms() == 1) && (parm(0) == 0)) + if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; svectoreparms (parm_count); @@ -2838,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const perm_string name = peek_tail_name(path_); for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { - PExpr*ex = parm(idx); + PExpr*ex = parms_[idx]; if (ex != 0) { eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex); } else { @@ -2930,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); - if (nparms() != def->port_count()) { + + unsigned parm_count = parms_.size(); + + // Handle special case that the definition has no arguments + // but the parser found a simgle nul argument. This is an + // argument of the parser allowing for the possibility of + // default values for argumets: The parser cannot tell the + // difference between "func()" and "func()". + if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0) + parm_count = 0; + + if (parm_count != def->port_count()) { cerr << get_fileline() << ": error: Port count mismatch in call to ``" - << path_ << "''. Got " << nparms() + << path_ << "''. Got " << parm_count << " ports, expecting " << def->port_count() << " ports." << endl; des->errors += 1; return 0; @@ -2942,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const /* Handle non-automatic tasks with no parameters specially. There is no need to make a sequential block to hold the generated code. */ - if ((nparms() == 0) && !task->is_auto()) { + if ((parm_count == 0) && !task->is_auto()) { cur = new NetUTask(task); cur->set_line(*this); return cur; @@ -2974,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression the r-value. We know by definition that the port is a reg type, so this elaboration is pretty obvious. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { + + if (parms_[idx] == 0 && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Missing argument " << (idx+1) + << " of call to task." << endl; + des->errors += 1; + continue; + } + + if (parms_[idx] == 0) { + cerr << get_fileline() << ": sorry: " + << "Implicit arguments (arg " << (idx+1) + << ") not supported." << endl; + des->errors += 1; + continue; + } NetNet*port = def->port(idx); assert(port->port_type() != NetNet::NOT_A_PORT); @@ -2985,7 +3012,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const unsigned wid = count_lval_width(lv); ivl_variable_type_t lv_type = lv->expr_type(); - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -3015,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression that can be a target to a procedural assignment, including a memory word. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { NetNet*port = def->port(idx); diff --git a/parse.y b/parse.y index 6bcfffff2..79a1ae6c4 100644 --- a/parse.y +++ b/parse.y @@ -513,8 +513,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item tf_port_item tf_port_list tf_port_list_opt -%type function_item function_item_list +%type tf_port_declaration tf_port_item tf_port_list tf_port_list_opt +%type function_item function_item_list function_item_list_opt %type port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -719,6 +719,7 @@ class_item /* IEEE1800-2005: A.1.8 */ /* IEEE1800 A.1.8: class_constructor_declaration */ : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt statement_or_null_list_opt K_endfunction endnew_opt { yyerror(@3, "sorry: Class constructors not supported yet."); @@ -730,6 +731,7 @@ class_item /* IEEE1800-2005: A.1.8 */ be K_super ("this.new" makes little sense) but that would cause a conflict. */ | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' statement_or_null_list_opt K_endfunction endnew_opt @@ -1454,6 +1456,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */ ; +tf_port_declaration /* IEEE1800-2005: A.2.7 */ + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, + $2 ? IVL_VT_LOGIC : + IVL_VT_NO_TYPE, + $3, $4, $5); + $$ = tmp; + } + + /* When the port is an integer, infer a signed vector of the integer + shape. Generate a range ([31:0]) to make it work. */ + + | port_direction K_integer list_of_identifiers ';' + { list*range_stub = make_range_from_width(integer_width); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); + $$ = tmp; + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction K_time list_of_identifiers ';' + { list*range_stub = make_range_from_width(64); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); + $$ = tmp; + } + + /* Ports can be real or realtime. */ + + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); + $$ = tmp; + } + + ; + + /* These rules for tf_port_item are slightly expanded from the strict rules in the LRM to help with LALR parsing. @@ -3071,26 +3112,34 @@ expr_primary /* A function_item_list borrows the task_port_item run to match declarations of ports. We check later to make sure there are no - output or inout ports actually used. */ + output or inout ports actually used. + + The function_item is the same as tf_item_declaration. */ +function_item_list_opt + : function_item_list { $$ = $1; } + | { $$ = 0; } + ; + function_item_list - : function_item - { $$ = $1; } - | function_item_list function_item - { if ($1 && $2) { - svector*tmp = new svector(*$1, *$2); - delete $1; - delete $2; - $$ = tmp; - } else if ($1) { - $$ = $1; - } else { - $$ = $2; - } - } - ; + : function_item + { $$ = $1; } + | function_item_list function_item + { /* */ + if ($1 && $2) { + svector*tmp = new svector(*$1, *$2); + delete $1; + delete $2; + $$ = tmp; + } else if ($1) { + $$ = $1; + } else { + $$ = $2; + } + } + ; function_item - : task_port_item + : tf_port_declaration { $$ = $1; } | block_item_decl { $$ = 0; } @@ -5700,7 +5749,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' + | hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$1, *$3); FILE_NAME(tmp, @1); delete $1; @@ -5708,7 +5757,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - | implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';' + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$3, *$5); yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); FILE_NAME(tmp, @1); @@ -5717,11 +5766,7 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - /* NOTE: The standard doesn't really support an empty argument list - between parentheses, but it seems natural, and people commonly - want it. So accept it explicitly. */ - - | hierarchy_identifier '(' ')' ';' + | hierarchy_identifier ';' { listpt; PCallTask*tmp = new PCallTask(*$1, pt); FILE_NAME(tmp, @1); @@ -5729,29 +5774,22 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } - - | implicit_class_handle '.' hierarchy_identifier '(' ')' ';' - { listpt; - yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); - PCallTask*tmp = new PCallTask(*$3, pt); - FILE_NAME(tmp, @3); - delete $3; + | hierarchy_identifier '(' error ')' ';' + { yyerror(@3, "error: Syntax error in task arguments."); + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; $$ = tmp; } - | hierarchy_identifier ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } - | error ';' - { yyerror(@2, "error: malformed statement"); - yyerrok; - $$ = new PNoop; - } - ; + | error ';' + { yyerror(@2, "error: malformed statement"); + yyerrok; + $$ = new PNoop; + } + + ; compressed_statement : lpvalue K_PLUS_EQ expression @@ -5841,47 +5879,9 @@ analog_statement other block items. */ task_item : block_item_decl { $$ = new svector(0); } - | task_port_item { $$ = $1; } + | tf_port_declaration { $$ = $1; } ; -task_port_item - : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5); - $$ = tmp; - } - - /* When the port is an integer, infer a signed vector of the integer - shape. Generate a range ([31:0]) to make it work. */ - - | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, - range_stub, $3, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, - range_stub, $3); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | port_direction real_or_realtime list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, - 0, $3); - $$ = tmp; - } - - ; - task_item_list : task_item_list task_item { svector*tmp = new svector(*$1, *$2); From b80afdf1f17aee33403e78de685d184fd29152bf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 10 Mar 2012 10:27:02 -0800 Subject: [PATCH 78/88] SystemVerilog randomize method syntax. --- parse.y | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/parse.y b/parse.y index 79a1ae6c4..5be1b2eca 100644 --- a/parse.y +++ b/parse.y @@ -5757,6 +5757,23 @@ statement /* This is roughly statement_item in the LRM */ $$ = tmp; } + | hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';' + { /* ....randomize with { } */ + if ($1 && peek_tail_name(*$1) == "randomize") { + if (!gn_system_verilog()) + yyerror(@2, "error: Randomize with constraint requires SystemVerilog."); + else + yyerror(@2, "sorry: Randomize with constraint not supported."); + } else { + yyerror(@2, "error: Constraint block can only be applied to randomize method."); + } + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' { PCallTask*tmp = new PCallTask(*$3, *$5); yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); From b0d61813b23c56c0033d313bbca0ee4282d45bfc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 11 Mar 2012 13:18:24 -0700 Subject: [PATCH 79/88] Get the scope of class methods right Class methods belong in a class scope, not the containing module. So create a lexical scope that carries tasks and functions and create a PClass to represent classes. --- Makefile.in | 5 +++-- Module.cc | 2 +- Module.h | 6 +----- PClass.cc | 30 ++++++++++++++++++++++++++++++ PClass.h | 40 ++++++++++++++++++++++++++++++++++++++++ PScope.cc | 15 +++++++++++++++ PScope.h | 19 +++++++++++++++++++ parse.y | 15 +++++++++------ pform.cc | 45 ++++++++++++++++++++++++++++++++++++--------- pform.h | 6 ++++++ pform_pclass.cc | 37 +++++++++++++++++++++++++++++++++++++ 11 files changed, 197 insertions(+), 23 deletions(-) create mode 100644 PClass.cc create mode 100644 PClass.h create mode 100644 pform_pclass.cc diff --git a/Makefile.in b/Makefile.in index ba3663735..7bd62d4f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,9 +110,10 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_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_struct_type.o pform_types.o \ + pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \ + pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ - Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \ + Attrib.o HName.o Module.o PClass.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 $M $(FF) $(TT) diff --git a/Module.cc b/Module.cc index 40871d059..66efe26b0 100644 --- a/Module.cc +++ b/Module.cc @@ -28,7 +28,7 @@ list Module::user_defparms; /* n is a permallocated string. */ Module::Module(perm_string n) -: PScope(n) +: PScopeExtra(n) { library_flag = false; is_cell = false; diff --git a/Module.h b/Module.h index 307836edf..a791a6be2 100644 --- a/Module.h +++ b/Module.h @@ -49,7 +49,7 @@ class NetScope; * therefore the handle for grasping the described circuit. */ -class Module : public PScope, public LineInfo { +class Module : public PScopeExtra, public LineInfo { /* The module ports are in general a vector of port_t objects. Each port has a name and an ordered list of @@ -112,10 +112,6 @@ class Module : public PScope, public LineInfo { bool time_from_timescale; bool timescale_warn_done; - /* Task definitions within this module */ - map tasks; - map funcs; - /* The module has a list of generate schemes that appear in the module definition. These are used at elaboration time. */ list generate_schemes; diff --git a/PClass.cc b/PClass.cc new file mode 100644 index 000000000..9a9a62355 --- /dev/null +++ b/PClass.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 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 "PClass.h" + +PClass::PClass(perm_string name, LexicalScope*parent) +: PScopeExtra(name, parent) +{ +} + + +PClass::~PClass() +{ +} diff --git a/PClass.h b/PClass.h new file mode 100644 index 000000000..b4578ad68 --- /dev/null +++ b/PClass.h @@ -0,0 +1,40 @@ +#ifndef __PClass_H +#define __PClass_H +/* + * Copyright (c) 2012 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 "PScope.h" +# include "LineInfo.h" +# include "StringHeap.h" + +/* + * SystemVerilog supports class declarations with their own lexical + * scope, etc. The parser arranges for these to be created and + * collected. + */ + +class PClass : public PScopeExtra, public LineInfo { + + public: + explicit PClass (perm_string name, LexicalScope*parent); + ~PClass(); + +}; + +#endif diff --git a/PScope.cc b/PScope.cc index f23a506ee..0e5dd4abe 100644 --- a/PScope.cc +++ b/PScope.cc @@ -41,3 +41,18 @@ PWire* LexicalScope::wires_find(perm_string name) else return (*cur).second; } + +PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) +: PScope(n, parent) +{ +} + +PScopeExtra::PScopeExtra(perm_string n) +: PScope(n) +{ +} + +PScopeExtra::~PScopeExtra() +{ +} + diff --git a/PScope.h b/PScope.h index d2b0feb53..e14cb6b4e 100644 --- a/PScope.h +++ b/PScope.h @@ -27,8 +27,10 @@ class PEvent; class PExpr; +class PFunction; class AProcess; class PProcess; +class PTask; class PWire; class Design; @@ -150,4 +152,21 @@ class PScope : public LexicalScope { perm_string name_; }; +/* + * Some scopes can carry definitions. These include Modules and PClass + * scopes. These derive from PScopeExtra so that they hold the maps of + * extra definitions. + */ +class PScopeExtra : public PScope { + + public: + PScopeExtra(perm_string, LexicalScope*parent); + PScopeExtra(perm_string); + ~PScopeExtra(); + + /* Task definitions within this module */ + map tasks; + map funcs; +}; + #endif diff --git a/parse.y b/parse.y index 5be1b2eca..6b97c6364 100644 --- a/parse.y +++ b/parse.y @@ -628,18 +628,21 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ class_declaration /* IEEE1800-2005: A.1.2 */ : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' - class_items_opt K_endclass - { // Process a class. + { pform_start_class_declaration(@2, $3); if ($4) { yyerror(@4, "sorry: Class extends not supported yet."); } + } + class_items_opt K_endclass + { // Process a class. + pform_end_class_declaration(); yyerror(@2, "sorry: Class declarations not supported yet."); } class_declaration_endname_opt { // Wrap up the class. - if ($9 && $3 && $3->name != $9) { - yyerror(@9, "error: Class end name doesn't match class name."); - delete[]$9; + if ($10 && $3 && $3->name != $10) { + yyerror(@10, "error: Class end name doesn't match class name."); + delete[]$10; } } ; @@ -1348,7 +1351,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */ current_task_set_statement(@3, $7); pform_pop_scope(); current_task = 0; - if ($7->size() > 1 && !gn_system_verilog()) { + if ($7 && $7->size() > 1 && !gn_system_verilog()) { yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); } delete $7; diff --git a/pform.cc b/pform.cc index a8569ff01..d34877855 100644 --- a/pform.cc +++ b/pform.cc @@ -23,6 +23,7 @@ # include "pform.h" # include "parse_misc.h" # include "parse_api.h" +# include "PClass.h" # include "PEvent.h" # include "PUdp.h" # include "PGenerate.h" @@ -267,12 +268,30 @@ void pform_pop_scope() lexical_scope = lexical_scope->parent_scope(); } +PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) +{ + PClass*class_scope = new PClass(name, lexical_scope); + FILE_NAME(class_scope, loc); + + lexical_scope = class_scope; + return class_scope; +} + PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string task_name = lex_strings.make(name); PTask*task = new PTask(task_name, lexical_scope, is_auto); FILE_NAME(task, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != @@ -286,15 +305,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) pform_cur_generate->tasks[task->pscope_name()] = task; } else { // Check if the task is already in the dictionary. - if (pform_cur_module->tasks.find(task->pscope_name()) != - pform_cur_module->tasks.end()) { + if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->tasks[task->pscope_name()] = task; + scopex->tasks[task->pscope_name()] = task; } + lexical_scope = task; return task; @@ -307,6 +326,15 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, PFunction*func = new PFunction(func_name, lexical_scope, is_auto); FILE_NAME(func, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != @@ -320,14 +348,13 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, pform_cur_generate->funcs[func->pscope_name()] = func; } else { // Check if the function is already in the dictionary. - if (pform_cur_module->funcs.find(func->pscope_name()) != - pform_cur_module->funcs.end()) { + if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->funcs[func->pscope_name()] = func; + scopex->funcs[func->pscope_name()] = func; } lexical_scope = func; @@ -2640,7 +2667,7 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list (data_type)) { + if (/*class_type_t*class_type =*/ dynamic_cast (data_type)) { VLerror(li, "sorry: Class types not supported."); return; } diff --git a/pform.h b/pform.h index 6af305314..941f5f7d3 100644 --- a/pform.h +++ b/pform.h @@ -58,6 +58,7 @@ class PGate; class PExpr; class PSpecPath; +class PClass; struct vlltype; /* @@ -168,6 +169,10 @@ extern Module::port_t* pform_module_port_reference(perm_string name, extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); +extern void pform_start_class_declaration(const struct vlltype&loc, + class_type_t*type); +extern void pform_end_class_declaration(void); + extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, @@ -187,6 +192,7 @@ extern void pform_make_udp(perm_string name, */ extern void pform_pop_scope(); +extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name); extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto); extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name, diff --git a/pform_pclass.cc b/pform_pclass.cc new file mode 100644 index 000000000..935734a62 --- /dev/null +++ b/pform_pclass.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 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 "pform.h" +# include "PClass.h" + +static PClass*pform_cur_class = 0; + +void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type) +{ + PClass*class_scope = pform_push_class_scope(loc, type->name); + assert(pform_cur_class == 0); + pform_cur_class = class_scope; +} + +void pform_end_class_declaration(void) +{ + assert(pform_cur_class); + pform_cur_class = 0; + pform_pop_scope(); +} From 5dbe68829636b138b34ff4bda9c4b5a8b28ee5ab Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 11 Mar 2012 15:08:42 -0700 Subject: [PATCH 80/88] Allow variable initialization in any scope. This is a SystemVerilog feature, so only allow it when compiling SystemVerilog files. --- pform.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pform.cc b/pform.cc index d34877855..d6acae6d4 100644 --- a/pform.cc +++ b/pform.cc @@ -1864,8 +1864,8 @@ void pform_make_pgassign_list(list*alist, void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr) { - if (! pform_at_module_level()) { - VLerror(li, "variable declaration assignments are only " + if (! pform_at_module_level() && !gn_system_verilog()) { + VLerror(li, "error: variable declaration assignments are only " "allowed at the module level."); delete expr; return; From 327194cd408b2a297a386851a65a29235fe0d63f Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Fri, 9 Mar 2012 23:04:52 +0000 Subject: [PATCH 81/88] Fix for pr3499807. If a tranif gate has a delay, the vvp code generator needs to generate a unique label for the island port used for the tranif enable, to prevent a name collision if the undelayed signal is also connected to the island. Also add an assertion in vvp to catch bugs like this. --- tgt-vvp/draw_switch.c | 12 ++++++------ vvp/vvp_island.cc | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index d62ae102c..59d60614b 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2010,2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -38,7 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw) ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); ivl_expr_t decay_exp= ivl_switch_delay(sw, 2); - /* We do not support tran delays. */ if ((rise_exp || fall_exp || decay_exp) && (!number_is_immediate(rise_exp, 64, 0) || number_is_unknown(rise_exp) || @@ -76,15 +75,16 @@ void draw_switch_in_scope(ivl_switch_t sw) processing doesn't have to deal with it. */ const char*raw = draw_net_input(enable); + snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw); + str_e = str_e_buf; + fprintf(vvp_out, "%s/d .delay 1 " "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", - raw, get_number_immediate64(rise_exp), + str_e, get_number_immediate64(rise_exp), get_number_immediate64(fall_exp), get_number_immediate64(decay_exp), raw); - fprintf(vvp_out, "p%p .import I%p, %s/d;\n", enable, island, raw); - snprintf(str_e_buf, sizeof str_e_buf, "p%p", enable); - str_e = str_e_buf; + fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e); } else if (enable) { str_e = draw_island_net_input(island, enable); diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index 49c167e75..f799d9809 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2010,2012 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 @@ -94,6 +94,9 @@ void vvp_island::add_port(const char*key, vvp_net_t*net) if (ports_ == 0) ports_ = new symbol_map_s; + // each port should have a unique label + assert(ports_->sym_get_value(key) == 0); + ports_->sym_set_value(key, net); } From b85e7efca86757c4a752bbba5de2127fe9df0a13 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 1 Apr 2012 12:27:28 -0700 Subject: [PATCH 82/88] For a delayed vpi_put_value() copy any pointer data members. When vpi_put_value() is asked to delay the assignment any pointer data needs to be duplicated so that the caller can clean up the locally allocated memory without causing memory access problems. Also update word calculation to match the next patch. --- vvp/vpi_priv.cc | 62 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 0d82b5575..309993783 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -690,7 +690,7 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width, vp->format = vpiVectorVal; case vpiVectorVal: { - unsigned hwid = (width - 1)/32 + 1; + unsigned hwid = (width + 31)/32; rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); s_vpi_vecval *op = (p_vpi_vecval)rbuf; @@ -755,7 +755,7 @@ void vpip_vec2_get_value(const vvp_vector2_t&word_val, unsigned width, break; case vpiVectorVal: { - unsigned hwid = (width - 1)/32 + 1; + unsigned hwid = (width + 31)/32; rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); s_vpi_vecval *op = (p_vpi_vecval)rbuf; @@ -948,15 +948,54 @@ void vpip_put_value_event::run_run() case vpiStringVal: free(value.value.str); break; - /* If these are ever copied then free them too. */ + /* Free the copied time structure. */ case vpiTimeVal: + free(value.value.time); + break; + /* Free the copied vector structure. */ case vpiVectorVal: + free(value.value.vector); + break; + /* Free the copied strength structure. */ case vpiStrengthVal: + free(value.value.strength); + break; + /* Everything else is static in the structure. */ default: break; } } +/* Make a copy of a pointer to a time structure. */ +static t_vpi_time *timedup(t_vpi_time *val) +{ + t_vpi_time *rtn; + rtn = (t_vpi_time *) malloc(sizeof(t_vpi_time)); + *rtn = *val; + return rtn; +} + +/* Make a copy of a pointer to a vector value structure. */ +static t_vpi_vecval *vectordup(t_vpi_vecval *val, PLI_INT32 size) +{ + unsigned num_bytes; + t_vpi_vecval *rtn; + assert(size > 0); + num_bytes = ((size + 31)/32)*sizeof(t_vpi_vecval); + rtn = (t_vpi_vecval *) malloc(num_bytes); + memcpy(rtn, val, num_bytes); + return rtn; +} + +/* Make a copy of a pointer to a strength structure. */ +static t_vpi_strengthval *strengthdup(t_vpi_strengthval *val) +{ + t_vpi_strengthval *rtn; + rtn = (t_vpi_strengthval *) malloc(sizeof(t_vpi_strengthval)); + *rtn = *val; + return rtn; +} + vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, s_vpi_time*when, PLI_INT32 flags) { @@ -999,8 +1038,10 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, vpip_put_value_event*put = new vpip_put_value_event; put->handle = obj; put->value = *vp; + /* Since this is a scheduled put event we must copy any pointer + * data to keep it available until the event is actually run. */ switch (put->value.format) { - /* If this is scheduled make a copy of the string. */ + /* Copy the string items. */ case vpiBinStrVal: case vpiOctStrVal: case vpiDecStrVal: @@ -1008,10 +1049,21 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, case vpiStringVal: put->value.value.str = strdup(put->value.value.str); break; - /* Do these also need to be copied? */ + /* Copy a time pointer item. */ case vpiTimeVal: + put->value.value.time = timedup(put->value.value.time); + break; + /* Copy a vector pointer item. */ case vpiVectorVal: + put->value.value.vector = vectordup(put->value.value.vector, + vpi_get(vpiSize, obj)); + break; + /* Copy a strength pointer item. */ case vpiStrengthVal: + put->value.value.strength = + strengthdup(put->value.value.strength); + break; + /* Everything thing else is already in the structure. */ default: break; } From c222169608850fb877c45056d08f32f2ff897920 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 1 Apr 2012 12:29:08 -0700 Subject: [PATCH 83/88] Update vecval size calculation in vvp and vpi code. The standard specifies that the size of a vecval should be calculated as (size - 1)/32 + 1. When size is a PLI_INT32 this is needed to prevent an overflow, but when the size is unsigned this can be simplified to (size + 31)/32 since the size must fit into an integer, but we have an extra significant bit in an unsigned so no overflow can happen. This patch changes the code to use the correct version of the equation depending on the context. The previous patch does this in vvp/vpi_priv.cc --- vpi/sys_fileio.c | 5 +++-- vvp/vpi_const.cc | 18 +++++++++--------- vvp/vpi_signal.cc | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 305775390..667d78fef 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -680,7 +680,8 @@ static PLI_INT32 sys_fread_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_free_object(argv); } - words = (width+31)/32; + assert(width > 0); + words = (width - 1)/32 + 1; vector = calloc(words, sizeof(s_vpi_vecval)); bpe = (width+7)/8; diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 2b95fe644..f7ca58757 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -121,7 +121,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) { unsigned uint_value; p_vpi_vecval vecp; - int size = strlen(value_); + unsigned size = strlen(value_); char*rbuf = 0; char*cp; @@ -145,7 +145,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) } rbuf = need_result_buf(size + 1, RBUF_VAL); uint_value = 0; - for(int i=0; i=0; bit--){ + for(unsigned i=0; i=0; bit -= 1){ *cp++ = "01"[ (value_[i]>>bit)&1 ]; } } @@ -168,8 +168,8 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) case vpiHexStrVal: rbuf = need_result_buf(2 * size + 1, RBUF_VAL); cp = rbuf; - for(int i=0; i=0; nibble--){ + for(unsigned i=0; i=0; nibble -= 1){ *cp++ = "0123456789abcdef"[ (value_[i]>>(nibble*4))&15 ]; } } @@ -184,8 +184,8 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) case vpiIntVal: vp->value.integer = 0; - for(int i=0; i=0; bit--){ + for(unsigned i=0; i=0; bit -= 1){ vp->value.integer <<= 1; vp->value.integer += (value_[i]>>bit)&1; } @@ -200,7 +200,7 @@ void __vpiStringConst::vpi_get_value(p_vpi_value vp) uint_value = 0; vecp = vp->value.vector; vecp->aval = vecp->bval = 0; - for(int i=0; iaval |= value_[i] << uint_value*8; uint_value += 1; if (uint_value > 3) { diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index dd821c6c4..3478fed40 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -467,7 +467,7 @@ static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid, { long end = base + (signed)wid; unsigned int obit = 0; - unsigned hwid = (wid - 1)/32 + 1; + unsigned hwid = (wid + 31)/32; s_vpi_vecval *op = (p_vpi_vecval) need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); From 42239a84982ef4b55cdeb296e24c793beaf9f38f Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 2 Apr 2012 19:53:04 -0700 Subject: [PATCH 84/88] Add code to test the width of individual structure elements. This patch adds code to correctly set the type and width of individual structure elements. Note the sign information is not currently available. --- elab_expr.cc | 62 +++++++++++++++++++++++++++++++++++++++++++++------- netstruct.h | 5 ++++- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 980446132..992fc5d0e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1419,24 +1419,38 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, return sys_expr; } -static NetExpr* check_for_struct_members(const LineInfo*li, - Design*des, NetScope*, - NetNet*net, perm_string method_name) +/* + * If the method matches a structure member then return the member otherwise + * return 0. Also return the offset of the member. + */ +static const netstruct_t::member_t*get_struct_member(const LineInfo*li, + Design*des, NetScope*, + NetNet*net, + perm_string method_name, + unsigned long&off) { netstruct_t*type = net->struct_type(); ivl_assert(*li, type); if (! type->packed()) { - cerr << li->get_fileline() << ": sorry: unpacked structures not supported here. " + cerr << li->get_fileline() + << ": sorry: unpacked structures not supported here. " << "Method=" << method_name << endl; des->errors += 1; return 0; } + return type->packed_member(method_name, off); +} + +static NetExpr* check_for_struct_members(const LineInfo*li, + Design*des, NetScope*, + NetNet*net, perm_string method_name) +{ unsigned long off; - const netstruct_t::member_t*mem = type->packed_member(method_name, off); - if (mem == 0) - return 0; + const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net, + method_name, off); + if (mem == 0) return 0; if (debug_elaborate) { cerr << li->get_fileline() << ": debug: Found struct member " <name @@ -2010,7 +2024,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) const NetExpr*ex1, *ex2; - symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2); + NetScope*found_in = symbol_search(0, des, scope, path_, net, par, eve, + ex1, ex2); // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the @@ -2146,6 +2161,37 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } + // If this is SystemVerilog then maybe this is a structure element. + if (gn_system_verilog() && found_in==0 && path_.size() >= 2) { + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + found_in = symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + // Check to see if we have a net and if so is it a structure? + if (net != 0) { + // If this net is a struct, the method name may be + // a struct member. + if (net->struct_type() != 0) { + ivl_assert(*this, use_path.back().index.empty()); + + const netstruct_t::member_t*mem; + unsigned long unused; + mem = get_struct_member(this, des, scope, net, + method_name, unused); + if (mem) { + expr_type_ = mem->data_type(); + expr_width_ = mem->width(); + min_width_ = expr_width_; + signed_flag_ = mem->get_signed(); + return expr_width_; + } + } + } + } + // Not a net, and not a parameter? Give up on the type, but // set the width to 0. expr_type_ = IVL_VT_NO_TYPE; diff --git a/netstruct.h b/netstruct.h index 6dc3a439f..b84df6a4a 100644 --- a/netstruct.h +++ b/netstruct.h @@ -1,7 +1,7 @@ #ifndef __netstruct_H #define __netstruct_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -32,6 +32,9 @@ class netstruct_t : public LineInfo { long msb; long lsb; long width() const; + ivl_variable_type_t data_type() const { return type; }; + // We need to keep the individual element sign information. + bool get_signed() const { return false; }; }; public: From 2b5c82d141a6ee46cc08f22cb1fc8fbf7d296a80 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 9 Apr 2012 16:00:08 -0700 Subject: [PATCH 85/88] SystemVerilog unbased literals cannot take a size. The SystemVerilog unbased literals (e.g. '0, '1, etc.) are expected to be used standalone and cannot take a size. This patch modifies the parsing code to give a good error message when this is done. --- lexor.lex | 7 +++++-- parse.y | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lexor.lex b/lexor.lex index 64d6f2e3c..0c4bc92d3 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -377,8 +377,11 @@ TU [munpf] << "Using SystemVerilog 'N bit vector. Use at least " << "-g2005-sv to remove this warning." << endl; } + generation_t generation_save = generation_flag; + generation_flag = GN_VER2005_SV; yylval.number = make_unsized_binary(yytext); - return BASED_NUMBER; } + generation_flag = generation_save; + return UNBASED_NUMBER; } [0-9][0-9_]* { yylval.number = make_unsized_dec(yytext); diff --git a/parse.y b/parse.y index 6b97c6364..a777700df 100644 --- a/parse.y +++ b/parse.y @@ -386,7 +386,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %token TYPE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER -%token BASED_NUMBER DEC_NUMBER +%token BASED_NUMBER DEC_NUMBER UNBASED_NUMBER %token REALTIME %token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR %token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG @@ -1231,6 +1231,12 @@ number : BASED_NUMBER | DEC_NUMBER BASED_NUMBER { $$ = pform_verinum_with_size($1,$2, @2.text, @2.first_line); based_size = 0; } + | UNBASED_NUMBER + { $$ = $1; based_size = 0;} + | DEC_NUMBER UNBASED_NUMBER + { yyerror(@1, "error: Unbased SystemVerilog literal cannot have " + "a size."); + $$ = $1; based_size = 0;} ; open_range_list /* IEEE1800-2005 A.2.11 */ From bb1036b55c924a6070aab92289867edf2b24b7fb Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Fri, 6 Apr 2012 16:38:38 -0700 Subject: [PATCH 86/88] Spelling refresh --- elab_lval.cc | 2 +- ivl_target.h | 2 +- lexor.lex | 2 +- netmisc.h | 2 +- parse.y | 2 +- pform.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elab_lval.cc b/elab_lval.cc index b10656442..2cfb98016 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -200,7 +200,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, // Special case: The l-value is an entire memory, or array // slice. This is, in fact, an error in l-values. Detect the - // situation by noting if the index count is less then the + // situation by noting if the index count is less than the // array dimensions (unpacked). if (reg->array_dimensions() > name_tail.index.size()) { cerr << get_fileline() << ": error: Cannot assign to array " diff --git a/ivl_target.h b/ivl_target.h index 32eb0e307..fddcf86f5 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1800,7 +1800,7 @@ extern int ivl_scope_time_units(ivl_scope_t net); * dimension. * * The ivl_signal_msb/ivl_signal_lsb functions are deprecated - * versions that only work with variables that have less then two + * versions that only work with variables that have less than two * dimensions. They will return msb==lsb==0 for scalars. * * ivl_signal_port diff --git a/lexor.lex b/lexor.lex index 0c4bc92d3..01a891437 100644 --- a/lexor.lex +++ b/lexor.lex @@ -309,7 +309,7 @@ TU [munpf] } } - /* If this identifer names a previously declared type, then + /* If this identifier names a previously declared type, then return this as a TYPE_IDENTIFIER instead. */ if (rc == IDENTIFIER && gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { diff --git a/netmisc.h b/netmisc.h index 5e96d3c8d..7f34131fa 100644 --- a/netmisc.h +++ b/netmisc.h @@ -130,7 +130,7 @@ extern NetExpr *normalize_variable_part_base(const list&indices, NetExpr*b unsigned long wid, bool is_up); /* * Calculate a canonicalizing expression for a slice select. The - * indices array is less then needed to fully address a bit, so the + * indices array is less than needed to fully address a bit, so the * result is a slice of the packed array. The return value is an * expression that gets to the base of the slice, and (lwid) becomes * the width of the slice, in bits. For example: diff --git a/parse.y b/parse.y index a777700df..792f36508 100644 --- a/parse.y +++ b/parse.y @@ -672,7 +672,7 @@ class_identifier ; /* The endname after a class declaration is a little tricky because - the class name is detected by the lexor as a TYPE_IDENTIFER if it + the class name is detected by the lexor as a TYPE_IDENTIFIER if it does indeed match a name. */ class_declaration_endname_opt : ':' TYPE_IDENTIFIER diff --git a/pform.h b/pform.h index 941f5f7d3..d3e51bf93 100644 --- a/pform.h +++ b/pform.h @@ -400,7 +400,7 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, /* * The parser uses this function to convert a unary - * increment/decrement expression to the equivilent compressed + * increment/decrement expression to the equivalent compressed * assignment statement. */ extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, From 13348ba7ac867a50afe09810b921e37bcfbf2e4e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 10 Apr 2012 14:29:28 -0700 Subject: [PATCH 87/88] Ranges are ranges, not expression lists. This is a cleanup in preparation for better support of range lists. (cherry picked from commit 8f7cf3255acad55841f8b3725e3786ef49daad68) Conflicts: PTask.h elab_scope.cc elab_sig.cc parse.y pform.cc pform.h pform_types.h Signed-off-by: Stephen Williams --- PTask.h | 2 +- PWire.cc | 2 +- PWire.h | 11 ++--- elab_scope.cc | 6 +-- elab_sig.cc | 52 +++++++++++--------- parse.y | 128 +++++++++++++++++++++++++------------------------- pform.cc | 109 +++++++++++++++++------------------------- pform.h | 25 +++++----- pform_dump.cc | 8 ++-- pform_types.h | 11 +++-- 10 files changed, 170 insertions(+), 184 deletions(-) diff --git a/PTask.h b/PTask.h index 249573213..aeb30419d 100644 --- a/PTask.h +++ b/PTask.h @@ -48,7 +48,7 @@ enum PTaskFuncEnum { struct PTaskFuncArg { PTaskFuncEnum type; - std::list*range; + std::list*range; }; /* diff --git a/PWire.cc b/PWire.cc index e5402a6cc..4539bba17 100644 --- a/PWire.cc +++ b/PWire.cc @@ -192,7 +192,7 @@ void PWire::set_range_scalar(PWSRType type) } } -void PWire::set_range(const list&rlist, PWSRType type) +void PWire::set_range(const list&rlist, PWSRType type) { switch (type) { case SR_PORT: diff --git a/PWire.h b/PWire.h index 5b6606fae..23c496ba5 100644 --- a/PWire.h +++ b/PWire.h @@ -51,11 +51,6 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH}; * the wire name. */ class PWire : public LineInfo { - public: - struct range_t { - PExpr*msb; - PExpr*lsb; - }; public: PWire(perm_string name, @@ -81,7 +76,7 @@ class PWire : public LineInfo { ivl_variable_type_t get_data_type() const; void set_range_scalar(PWSRType type); - void set_range(const std::list&ranges, PWSRType type); + void set_range(const std::list&ranges, PWSRType type); void set_memory_idx(PExpr*ldx, PExpr*rdx); @@ -112,9 +107,9 @@ class PWire : public LineInfo { // bit. The first item in the list is the first range, and so // on. For example "reg [3:0][7:0] ..." will contains the // range_t object for [3:0] first and [7:0] last. - std::listport_; + std::listport_; bool port_set_; - std::listnet_; + std::listnet_; bool net_set_; bool is_scalar_; unsigned error_cnt_; diff --git a/elab_scope.cc b/elab_scope.cc index efce812c6..02d46659f 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -134,9 +134,9 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, { bool rc_flag; assert(enum_type->range->size() == 1); - index_component_t index = enum_type->range->front(); - NetExpr*msb_ex = elab_and_eval(des, scope, index.msb, -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, index.lsb, -1); + pform_range_t&range = enum_type->range->front(); + NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1); long msb = 0; rc_flag = eval_as_long(msb, msb_ex); diff --git a/elab_sig.cc b/elab_sig.cc index 9c799dccd..ca7a1ac73 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -477,11 +477,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_REG_S: if (return_type_.range) { ivl_assert(*this, return_type_.range->size() == 1); - index_component_t index = return_type_.range->front(); + pform_range_t&return_range = return_type_.range->front(); - NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); + NetExpr*me = elab_and_eval(des, scope, + return_range.first, -1, + true); assert(me); - NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); + NetExpr*le = elab_and_eval(des, scope, + return_range.second, -1, + true); assert(le); long mnum = 0, lnum = 0; @@ -550,10 +554,14 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const long use_wid; { ivl_assert(*this, return_type_.range->size() == 1); - index_component_t index = return_type_.range->front(); - NetExpr*me = elab_and_eval(des, scope, index.msb, -1, true); + pform_range_t&return_range = return_type_.range->front(); + NetExpr*me = elab_and_eval(des, scope, + return_range.first, -1, + true); ivl_assert(*this, me); - NetExpr*le = elab_and_eval(des, scope, index.lsb, -1, true); + NetExpr*le = elab_and_eval(des, scope, + return_range.second, -1, + true); ivl_assert(*this, le); long mnum = 0, lnum = 0; @@ -809,9 +817,9 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, long use_lsb = 0; if (curp->range.get() && ! curp->range->empty()) { ivl_assert(*curp, curp->range->size() == 1); - index_component_t index = curp->range->front(); - PExpr*msb_pex = index.msb; - PExpr*lsb_pex = index.lsb; + pform_range_t&rangep = curp->range->front(); + PExpr*msb_pex = rangep.first; + PExpr*lsb_pex = rangep.second; NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); ivl_assert(*curp, tmp); @@ -842,34 +850,34 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, static bool evaluate_ranges(Design*des, NetScope*scope, list&llist, - const list&rlist) + const list&rlist) { bool bad_msb = false, bad_lsb = false; - for (list::const_iterator cur = rlist.begin() + for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { NetNet::range_t lrng; - NetExpr*texpr = elab_and_eval(des, scope, cur->msb, -1, true); + NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); if (! eval_as_long(lrng.msb, texpr)) { - cerr << cur->msb->get_fileline() << ": error: " + cerr << cur->first->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << cur->msb->get_fileline() << " : " + cerr << cur->first->get_fileline() << " : " "This MSB expression violates the rule: " - << *cur->msb << endl; + << *cur->first << endl; des->errors += 1; bad_msb = true; } delete texpr; - texpr = elab_and_eval(des, scope, cur->lsb, -1, true); + texpr = elab_and_eval(des, scope, cur->second, -1, true); if (! eval_as_long(lrng.lsb, texpr)) { - cerr << cur->lsb->get_fileline() << ": error: " + cerr << cur->second->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << cur->lsb->get_fileline() << " : " + cerr << cur->second->get_fileline() << " : " "This LSB expression violates the rule: " - << *cur->lsb << endl; + << *cur->second << endl; des->errors += 1; bad_lsb = true; } @@ -1007,7 +1015,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* Vectored port with a scalar net/etc. definition */ if (net_.empty()) { - cerr << port_.front().msb->get_fileline() + cerr << port_.front().first->get_fileline() << ": error: Vectored port ``" << name_ << "'' " << plist << " has a scalar net declaration at " @@ -1018,11 +1026,11 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* Both vectored, but they have different ranges. */ if (!port_.empty() && !net_.empty()) { - cerr << port_.front().msb->get_fileline() + cerr << port_.front().first->get_fileline() << ": error: Vectored port ``" << name_ << "'' " << plist << " has a net declaration " << nlist - << " at " << net_.front().msb->get_fileline() + << " at " << net_.front().first->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; diff --git a/parse.y b/parse.y index 6b97c6364..1058767bb 100644 --- a/parse.y +++ b/parse.y @@ -38,7 +38,7 @@ extern void lex_end_table(); bool have_timeunit_decl = false; bool have_timeprec_decl = false; -static list* param_active_range = 0; +static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -48,8 +48,8 @@ static struct { NetNet::PortType port_type; ivl_variable_type_t var_type; bool sign_flag; - list* range; data_type_t* data_type; + list* range; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, false, 0, 0}; @@ -106,16 +106,28 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { - list*range = new list; + pform_range_t range; + range.first = new PENumber(new verinum(wid-1, integer_width)); + range.second = new PENumber(new verinum((uint64_t)0, integer_width)); - index_component_t tmp; - tmp.msb = new PENumber(new verinum(wid-1, integer_width)); - tmp.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); - range->push_back(tmp); + list*rlist = new list; + rlist->push_back(range); + return rlist; +} - return range; +static list* make_range_from_pair(list*rpair) +{ + pform_range_t range; + assert(rpair && rpair->size() == 2); + range.first = rpair->front(); + range.second = rpair->back(); + delete rpair; + + list*rlist = new list; + rlist->push_back(range); + return rlist; } static list* list_from_identifier(char*id) @@ -133,12 +145,12 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -list* copy_range(list* orig) +list* copy_range(list* orig) { - list*copy = 0; + list*copy = 0; if (orig) - copy = new list (*orig); + copy = new list (*orig); return copy; } @@ -341,6 +353,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector named_pexpr_t*named_pexpr; list*named_pexprs; struct parmvalue_t*parmvalue; + list*ranges; PExpr*expr; list*exprs; @@ -547,8 +560,9 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type struct_union_member_list %type struct_data_type -%type range range_opt -%type dimensions_opt dimensions variable_dimension +%type range range_opt variable_dimension +%type dimensions_opt dimensions + %type net_type var_type net_type_opt %type gatetype switchtype %type port_direction port_direction_opt @@ -1472,7 +1486,7 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */ shape. Generate a range ([31:0]) to make it work. */ | port_direction K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, range_stub, $3, true); $$ = tmp; @@ -1481,7 +1495,7 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */ /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, range_stub, $3); $$ = tmp; @@ -1511,7 +1525,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be integer with a width of [31:0]. */ : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(integer_width); + { list*range_stub = make_range_from_width(integer_width); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1537,7 +1551,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */ /* Ports can be time with a width of [63:0] (unsigned). */ | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt - { list*range_stub = make_range_from_width(64); + { list*range_stub = make_range_from_width(64); NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; port_declaration_context.port_type = use_port_type; @@ -1668,11 +1682,8 @@ value_range /* IEEE1800-2005: A.8.3 */ variable_dimension /* IEEE1800-2005: A.2.5 */ : '[' expression ':' expression ']' - { list *tmp = new list; - index_component_t index; - index.sel = index_component_t::SEL_PART; - index.msb = $2; - index.lsb = $4; + { list *tmp = new list; + pform_range_t index ($2,$4); tmp->push_back(index); $$ = tmp; } @@ -1683,29 +1694,24 @@ variable_dimension /* IEEE1800-2005: A.2.5 */ cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " << "Use at least -g2005-sv to remove this warning." << endl; } - list *tmp = new list; - index_component_t index; - index.sel = index_component_t::SEL_PART; - index.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.msb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); + list *tmp = new list; + pform_range_t index; + index.first = new PENumber(new verinum((uint64_t)0, integer_width)); + index.second = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); tmp->push_back(index); $$ = tmp; } | '[' ']' - { list *tmp = new list; - index_component_t index; - index.msb = 0; - index.lsb = 0; + { list *tmp = new list; + pform_range_t index (0,0); yyerror("sorry: Dynamic array ranges not supported."); tmp->push_back(index); $$ = tmp; } | '[' '$' ']' { // SystemVerilog queue - list *tmp = new list; - index_component_t index; - index.msb = 0; - index.lsb = 0; + list *tmp = new list; + pform_range_t index (0,0); if (gn_system_verilog()) { yyerror("sorry: Dynamic array ranges not supported."); } else { @@ -1898,7 +1904,7 @@ enum_data_type enum_type->names .reset($3); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = true; - enum_type->range.reset( make_range_from_width(32) ); + enum_type->range.reset(make_range_from_width(32)); $$ = enum_type; } | K_enum atom2_type signed_unsigned_opt '{' enum_name_list '}' @@ -1907,7 +1913,7 @@ enum_data_type enum_type->names .reset($5); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; - enum_type->range.reset( make_range_from_width($2) ); + enum_type->range.reset(make_range_from_width($2)); $$ = enum_type; } | K_enum K_integer signed_unsigned_opt '{' enum_name_list '}' @@ -1916,7 +1922,7 @@ enum_data_type enum_type->names .reset($5); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( make_range_from_width(integer_width) ); + enum_type->range.reset(make_range_from_width(integer_width)); $$ = enum_type; } | K_enum K_logic unsigned_signed_opt range '{' enum_name_list '}' @@ -1925,7 +1931,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } | K_enum K_reg unsigned_signed_opt range '{' enum_name_list '}' @@ -1934,7 +1940,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } | K_enum K_bit unsigned_signed_opt range '{' enum_name_list '}' @@ -1943,7 +1949,7 @@ enum_data_type enum_type->names .reset($6); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } ; @@ -2066,7 +2072,7 @@ struct_union_member { struct_member_t*tmp = new struct_member_t; FILE_NAME(tmp, @2); tmp->type = IVL_VT_BOOL; - tmp->range .reset( make_range_from_width($2) ); + tmp->range .reset(make_range_from_width($2)); tmp->names .reset($3); $$ = tmp; } @@ -3163,7 +3169,7 @@ gate_instance | IDENTIFIER range '(' expression_list_with_nuls ')' { lgate*tmp = new lgate; - list*rng = $2; + list*rng = $2; tmp->name = $1; tmp->parms = $4; tmp->range = rng->front(); @@ -3189,7 +3195,7 @@ gate_instance | IDENTIFIER range { lgate*tmp = new lgate; - list*rng = $2; + list*rng = $2; tmp->name = $1; tmp->parms = 0; tmp->parms_by_name = 0; @@ -3218,7 +3224,7 @@ gate_instance | IDENTIFIER range '(' port_name_list ')' { lgate*tmp = new lgate; - list*rng = $2; + list*rng = $2; tmp->name = $1; tmp->parms = 0; tmp->parms_by_name = $4; @@ -3483,7 +3489,7 @@ port_declaration K_input atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list* use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINPUT, @@ -3629,7 +3635,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -3648,7 +3654,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER '=' expression { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -4953,7 +4959,7 @@ range : variable_dimension { $$ = $1; } | range variable_dimension - { list*tmp = $1; + { list*tmp = $1; if ($2) { tmp->splice(tmp->end(), *$2); delete $2; @@ -4975,7 +4981,7 @@ dimensions : variable_dimension { $$ = $1; } | dimensions variable_dimension - { list *tmp = $1; + { list *tmp = $1; if ($2) { tmp->splice(tmp->end(), *$2); delete $2; @@ -4991,29 +4997,23 @@ function_range_or_type_opt : unsigned_signed_opt range_opt { /* the default type is reg unsigned and no range */ $$.type = PTF_REG; - $$.range = 0; + $$.range = $2; if ($1) $$.type = PTF_REG_S; - if ($2) - $$.range = $2; } | K_reg unsigned_signed_opt range_opt { /* the default type is reg unsigned and no range */ $$.type = PTF_REG; - $$.range = 0; + $$.range = $3; if ($2) $$.type = PTF_REG_S; - if ($3) - $$.range = $3; } | bit_logic unsigned_signed_opt range_opt { /* the default type is bit/logic unsigned and no range */ $$.type = PTF_REG; - $$.range = 0; + $$.range = $3; if ($2) $$.type = PTF_REG_S; - if ($3) - $$.range = $3; } | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } @@ -5037,13 +5037,13 @@ register_variable pform_makewire(@1, ident_name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); if ($2 != 0) { - index_component_t index; + pform_range_t index; if ($2->size() > 1) { yyerror(@2, "sorry: only 1 dimensional arrays " "are currently supported."); } index = $2->front(); - pform_set_reg_idx(ident_name, index.msb, index.lsb); + pform_set_reg_idx(ident_name, index.first, index.second); delete $2; } $$ = $1; @@ -5078,13 +5078,13 @@ net_variable pform_makewire(@1, name, NetNet::IMPLICIT, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); if ($2 != 0) { - index_component_t index; + pform_range_t index; if ($2->size() > 1) { yyerror(@2, "sorry: only 1 dimensional arrays " "are currently supported."); } index = $2->front(); - pform_set_reg_idx(name, index.msb, index.lsb); + pform_set_reg_idx(name, index.first, index.second); delete $2; } $$ = $1; diff --git a/pform.cc b/pform.cc index 27226ae78..7fb93e9c2 100644 --- a/pform.cc +++ b/pform.cc @@ -1512,26 +1512,13 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } -static void ranges_from_list(list&rlist, - const list*range) -{ - // Convert a list of index_component_t to PWire::range_t. - for (list::const_iterator rcur = range->begin() - ; rcur != range->end() ; ++rcur) { - PWire::range_t rng; - rng.msb = rcur->msb; - rng.lsb = rcur->lsb; - rlist.push_back(rng); - } -} - /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, * and the name that I receive only has the tail component. */ static void pform_set_net_range(perm_string name, - const list*range, + const list*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) @@ -1548,9 +1535,7 @@ static void pform_set_net_range(perm_string name, cur->set_range_scalar(rt); } else { - list rlist; - ranges_from_list(rlist, range); - cur->set_range(rlist, rt); + cur->set_range(*range, rt); } cur->set_signed(signed_flag); @@ -1558,10 +1543,10 @@ static void pform_set_net_range(perm_string name, cur->set_data_type(dt); } -static void pform_set_net_range(list*names, - list*range, - bool signed_flag, - ivl_variable_type_t dt) +void pform_set_net_range(list*names, + list*range, + bool signed_flag, + ivl_variable_type_t dt) { for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { @@ -1630,8 +1615,8 @@ static void pform_makegate(PGBuiltin::Type type, perm_string dev_name = lex_strings.make(info.name); PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay); - if (info.range.msb) - cur->set_range(info.range.msb, info.range.lsb); + if (info.range.first) + cur->set_range(info.range.first, info.range.second); // The pform_makegates() that calls me will take care of // deleting the attr pointer, so tell the @@ -1770,7 +1755,7 @@ void pform_make_modgates(perm_string type, if (cur.parms_by_name) { pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, - cur.range.msb, cur.range.lsb, + cur.range.first, cur.range.second, cur.file, cur.lineno); } else if (cur.parms) { @@ -1784,14 +1769,14 @@ void pform_make_modgates(perm_string type, } pform_make_modgate(type, cur_name, overrides, cur.parms, - cur.range.msb, cur.range.lsb, + cur.range.first, cur.range.second, cur.file, cur.lineno); } else { list*wires = new list; pform_make_modgate(type, cur_name, overrides, wires, - cur.range.msb, cur.range.lsb, + cur.range.first, cur.range.second, cur.file, cur.lineno); } } @@ -1904,7 +1889,7 @@ void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr) { PWire*cur = pform_get_wire_in_scope(name); @@ -1930,9 +1915,7 @@ void pform_module_define_port(const struct vlltype&li, cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - list rlist; - ranges_from_list(rlist, range); - cur->set_range(rlist, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); + cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } pform_bind_attributes(cur->attributes, attr); @@ -2038,7 +2021,7 @@ void pform_makewire(const vlltype&li, perm_string name, * pform_makewire above. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -2065,7 +2048,7 @@ void pform_makewire(const vlltype&li, * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -2143,7 +2126,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint) { @@ -2171,9 +2154,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, /* If there is a range involved, it needs to be set. */ if (range) { - list rlist; - ranges_from_list(rlist, range); - curw->set_range(rlist, SR_PORT); + curw->set_range(*range, SR_PORT); } svector*tmp = new svector(*res, curw); @@ -2193,7 +2174,7 @@ svector*pform_make_task_ports(const struct vlltype&loc, list*names) { if (atom2_type_t*atype = dynamic_cast (vtype)) { - list*range_tmp = make_range_from_width(atype->type_code); + list*range_tmp = make_range_from_width(atype->type_code); return pform_make_task_ports(loc, pt, IVL_VT_BOOL, atype->signed_flag, range_tmp, names); @@ -2320,7 +2301,7 @@ LexicalScope::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, list*range, PExpr*expr, + bool signed_flag, list*range, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; @@ -2356,11 +2337,11 @@ void pform_set_parameter(const struct vlltype&loc, parm.type = type; if (range) { assert(range->size() == 1); - index_component_t index = range->front(); - assert(index.msb); - assert(index.lsb); - parm.msb = index.msb; - parm.lsb = index.lsb; + pform_range_t&rng = range->front(); + assert(rng.first); + assert(rng.second); + parm.msb = rng.first; + parm.lsb = rng.second; } else { parm.msb = 0; parm.lsb = 0; @@ -2374,7 +2355,7 @@ void pform_set_parameter(const struct vlltype&loc, void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr) + bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; @@ -2405,11 +2386,11 @@ void pform_set_localparam(const struct vlltype&loc, parm.type = type; if (range) { assert(range->size() == 1); - index_component_t index = range->front(); - assert(index.msb); - assert(index.lsb); - parm.msb = index.msb; - parm.lsb = index.lsb; + pform_range_t&rng = range->front(); + assert(rng.first); + assert(rng.second); + parm.msb = rng.first; + parm.lsb = rng.second; } else { parm.msb = 0; parm.lsb = 0; @@ -2542,7 +2523,7 @@ static void pform_set_port_type(perm_string name, NetNet::PortType pt, void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType pt) { @@ -2565,10 +2546,10 @@ static void pform_set_reg_integer(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - PWire::range_t rng; - rng.msb = new PENumber(new verinum(integer_width-1, integer_width)); - rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); - listrlist; + pform_range_t rng; + rng.first = new PENumber(new verinum(integer_width-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; rlist.push_back(rng); cur->set_range(rlist, SR_NET); cur->set_signed(true); @@ -2589,10 +2570,10 @@ static void pform_set_reg_time(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - PWire::range_t rng; - rng.msb = new PENumber(new verinum(TIME_WIDTH-1, integer_width)); - rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); - listrlist; + pform_range_t rng; + rng.first = new PENumber(new verinum(TIME_WIDTH-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; rlist.push_back(rng); cur->set_range(rlist, SR_NET); } @@ -2614,10 +2595,10 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin cur->set_signed(signed_flag); - PWire::range_t rng; - rng.msb = new PENumber(new verinum(width-1, integer_width)); - rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); - listrlist; + pform_range_t rng; + rng.first = new PENumber(new verinum(width-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; rlist.push_back(rng); cur->set_range(rlist, SR_NET); } @@ -2684,9 +2665,7 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, assert(enum_type->range.get() != 0); assert(enum_type->range->size() == 1); - listrlist; - ranges_from_list(rlist, enum_type->range.get()); - cur->set_range(rlist, SR_NET); + cur->set_range(*enum_type->range, SR_NET); cur->set_enumeration(enum_type); } diff --git a/pform.h b/pform.h index 941f5f7d3..1ca9aa802 100644 --- a/pform.h +++ b/pform.h @@ -110,14 +110,14 @@ struct lgate { list*parms; list*parms_by_name; - index_component_t range; + pform_range_t range; const char* file; unsigned lineno; }; -extern std::list* make_range_from_width(uint64_t wid); -extern std::list* copy_range(std::list* orig); +extern std::list* make_range_from_width(uint64_t wid); +extern std::list* copy_range(std::list* orig); /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ @@ -160,7 +160,7 @@ extern void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -245,7 +245,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name, /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -262,7 +262,7 @@ extern void pform_makewire(const struct vlltype&li, /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -285,11 +285,14 @@ extern void pform_make_reginit(const struct vlltype&li, it. The second form takes a single name. */ extern void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType); - +extern void pform_set_net_range(list*names, + list*, + bool signed_flag, + ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); @@ -319,13 +322,13 @@ extern void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*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, bool signed_flag, - list*range, + list*range, PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); @@ -389,7 +392,7 @@ extern svector*pform_make_task_ports(const struct vlltype&loc, NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, bool isint = false); diff --git a/pform_dump.cc b/pform_dump.cc index 808ba4372..f5859b69a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -358,9 +358,9 @@ void PWire::dump(ostream&out, unsigned ind) const out << " port"; } else { out << " port"; - for (list::const_iterator cur = port_.begin() + for (list::const_iterator cur = port_.begin() ; cur != port_.end() ; ++cur) - out << "[" << *cur->msb << ":" << *cur->lsb << "]"; + out << "[" << *cur->first << ":" << *cur->second << "]"; } } if (net_set_) { @@ -368,9 +368,9 @@ void PWire::dump(ostream&out, unsigned ind) const out << " net"; } else { out << " net"; - for (list::const_iterator cur = net_.begin() + for (list::const_iterator cur = net_.begin() ; cur != net_.end() ; ++cur) - out << "[" << *cur->msb << ":" << *cur->lsb << "]"; + out << "[" << *cur->first << ":" << *cur->second << "]"; } } diff --git a/pform_types.h b/pform_types.h index 5e5a4a48f..ed3f20f53 100644 --- a/pform_types.h +++ b/pform_types.h @@ -37,6 +37,7 @@ class PExpr; typedef named named_number_t; typedef named named_pexpr_t; +typedef std::pair pform_range_t; struct index_component_t { enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; @@ -59,7 +60,7 @@ struct name_component_t { struct decl_assignment_t { perm_string name; - std::listindex; + std::listindex; std::auto_ptr expr; }; @@ -84,14 +85,14 @@ struct data_type_t : public LineInfo { struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; }; struct struct_member_t : public LineInfo { ivl_variable_type_t type; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; }; @@ -109,11 +110,11 @@ struct atom2_type_t : public data_type_t { struct vector_type_t : public data_type_t { inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, - std::list*pd) + std::list*pd) : base_type(bt), signed_flag(sf), pdims(pd) { } ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > pdims; + std::auto_ptr< list > pdims; }; struct real_type_t : public data_type_t { From 761a38d0a8c198d8e12d37c06d6c10c409991959 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 11 Apr 2012 09:13:14 -0700 Subject: [PATCH 88/88] Spelling fix --- elab_net.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index 221769451..a39ccfe74 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -480,7 +480,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, if ((struct_type = sig->struct_type()) && !method_name.nil()) { // Detect the variable is a structure and there was a - // methos name detected. + // method name detected. if (debug_elaborate) cerr << get_fileline() << ": debug: " << "Signal " << sig->name() << " is a structure, "