From de7fff8ac69400880156e528428a6cbef74d2782 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 27 May 2008 20:06:58 -0700 Subject: [PATCH 01/98] Elaborate tran devices (switches) This takes the support for switch modeling to the code generator. Add error messages in the vvp code generator for lack of support. --- ivl.def | 6 ++++-- ivl_target.h | 3 +++ t-dll-api.cc | 10 ++++++++++ t-dll.cc | 3 +++ tgt-vvp/Makefile.in | 2 +- tgt-vvp/draw_switch.c | 33 +++++++++++++++++++++++++++++++++ tgt-vvp/vvp_priv.h | 5 +++++ tgt-vvp/vvp_scope.c | 5 +++++ 8 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tgt-vvp/draw_switch.c diff --git a/ivl.def b/ivl.def index 48b798910..7d0751006 100644 --- a/ivl.def +++ b/ivl.def @@ -222,10 +222,12 @@ ivl_switch_a ivl_switch_b ivl_switch_basename ivl_switch_enable +ivl_switch_file +ivl_switch_lineno ivl_switch_scope ivl_switch_type -ivl_switch_attr_cnt; -ivl_switch_attr_val; +ivl_switch_attr_cnt +ivl_switch_attr_val ivl_udp_init ivl_udp_name diff --git a/ivl_target.h b/ivl_target.h index a39366a18..7f09116ea 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1879,6 +1879,9 @@ extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net); extern unsigned ivl_switch_attr_cnt(ivl_switch_t net); extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx); +extern const char* ivl_switch_file(ivl_switch_t net); +extern unsigned ivl_switch_lineno(ivl_switch_t net); + #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) #else diff --git a/t-dll-api.cc b/t-dll-api.cc index aa2733854..cbfbf7e84 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2181,3 +2181,13 @@ extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net) { return net->pins[2]; } + +extern "C" const char* ivl_switch_file(ivl_switch_t net) +{ + return net->file; +} + +extern "C" unsigned ivl_switch_lineno(ivl_switch_t net) +{ + return net->lineno; +} diff --git a/t-dll.cc b/t-dll.cc index 15cc19eac..2fd382f29 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1063,6 +1063,9 @@ bool dll_target::tran(const NetTran*net) obj->pins[2] = 0; } + obj->file = net->get_file(); + obj->lineno = net->get_lineno(); + switch_attributes(obj, net); scope_add_switch(obj->scope, obj); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index c9b6b5098..79664e616 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -51,7 +51,7 @@ dep: $(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vvp.o draw_mux.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \ +O = vvp.o draw_mux.o draw_switch.o draw_ufunc.o draw_vpi.o eval_bool.o eval_expr.o \ eval_real.o modpath.o vector.o \ vvp_process.o vvp_scope.o diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c new file mode 100644 index 000000000..0cbc88e3d --- /dev/null +++ b/tgt-vvp/draw_switch.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vvp_priv.h" +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include +# include + +void draw_switch_in_scope(ivl_switch_t sw) +{ + fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n", + ivl_switch_file(sw), ivl_switch_lineno(sw)); + vvp_errors += 1; +} diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 53c31618e..ffb2f12d3 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -104,6 +104,11 @@ extern struct vector_info draw_vpi_func_call(ivl_expr_t exp, unsigned wid); extern int draw_vpi_rfunc_call(ivl_expr_t exp); +/* + * Switches (tran) + */ +extern void draw_switch_in_scope(ivl_switch_t sw); + /* * Given a nexus, draw a string that represents the functor output * that feeds the nexus. This function can be used to get the input to diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7900c30fb..9499efe4d 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -2569,6 +2569,11 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) draw_lpm_in_scope(lpm); } + for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) { + ivl_switch_t sw = ivl_scope_switch(net, idx); + draw_switch_in_scope(sw); + } + if (ivl_scope_type(net) == IVL_SCT_TASK) draw_task_definition(net); From 9aa610f489ae0e22bc87952d404ae334b1e68573 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 28 May 2008 08:47:28 -0700 Subject: [PATCH 02/98] Fix handling of 32bit IMM in %addi on 32bit machines The handling of immediate add used to do 16bits at a time. When it went up to 32bits, the need to work in chunks vanished, but the chunk handling was still there, this time shifting by 32, which causes problems on 32bit machines. Simplify the %addi handling to avoid this. --- tgt-vvp/eval_expr.c | 74 +++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index e1fb2013c..3bcbf2717 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1197,23 +1197,50 @@ static struct vector_info draw_add_immediate(ivl_expr_t le, imm = get_number_immediate(re); - /* Now generate enough %addi instructions to add the entire - immediate value to the destination. The adds are done IMM_WID - bits at a time, but +1 bits are done to push the carry into - the higher bits if needed. */ - { unsigned base; - for (base = 0 ; base < lv.wid ; base += IMM_WID) { - unsigned long tmp = imm & 0xffffffffUL; - unsigned add_wid = lv.wid - base; + /* This shouldn't generally happen, because the elaborator + should take care of simple constant propagation like this, + but it doesn't have to and it is easy to catch here. */ + if (imm == 0) + return lv; - imm >>= IMM_WID; + switch (lv.base) { + case 0: /* Left expression is 0. */ + lv.base = allocate_vector(wid); + if (lv.base == 0) { + fprintf(stderr, "%s:%u: vvp.tgt error: " + "Unable to allocate %u thread bits " + "for result of addition.\n", + ivl_expr_file(re), ivl_expr_lineno(re), wid); + vvp_errors += 1; + } + fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid); + break; - fprintf(vvp_out, " %%addi %u, %lu, %u;\n", - lv.base+base, tmp, add_wid); + case 1: /* Left expression is 1...1 (i.e. -1) */ + imm -= 1; + if (imm == 0) { + lv.base = 0; + } else { + lv.base = allocate_vector(wid); + if (lv.base == 0) { + fprintf(stderr, "%s:%u: vvp.tgt error: " + "Unable to allocate %u thread bits " + "for result of addition.\n", + ivl_expr_file(re), ivl_expr_lineno(re), wid); + vvp_errors += 1; + } + fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid); + } + break; - if (imm == 0) - break; - } + case 2: /* Left expression is X or Z */ + case 3: + lv.base = 2; + break; + + default: /* The regular case. */ + fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid); + break; } return lv; @@ -1234,7 +1261,8 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le, assert(lv.wid == wid); imm = get_number_immediate(re); - assert( (imm & ~0xffffffffUL) == 0 ); + if (imm == 0) + return lv; switch (lv.base) { case 0: @@ -1248,21 +1276,21 @@ static struct vector_info draw_sub_immediate(ivl_expr_t le, vvp_errors += 1; } - fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid); + fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid); lv.base = tmp; - fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid); - return lv; + fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid); + break; case 2: case 3: lv.base = 2; - return lv; + break; default: - fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid); + fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid); + break; } - return lv; } @@ -1277,8 +1305,10 @@ static struct vector_info draw_mul_immediate(ivl_expr_t le, assert(lv.wid == wid); imm = get_number_immediate(re); + if (imm == 0) + return lv; - fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid); + fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid); return lv; } From 653e2661b2202a2acea91fb2f34256d2f938da72 Mon Sep 17 00:00:00 2001 From: Cary R Date: Fri, 23 May 2008 10:01:54 -0700 Subject: [PATCH 03/98] The no git code also check for an existing version.h My previous patch always used an empty file if git was not available. This patch extends this to use the existing version.h file if it exists (snapshot, etc.) --- Makefile.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 3df9bb21b..6bde10e07 100644 --- a/Makefile.in +++ b/Makefile.in @@ -188,7 +188,13 @@ iverilog-vpi.pdf: iverilog-vpi.ps .PHONY: version.h version.h: ifeq ($(GIT),none) - @echo '#define VERSION_TAG ""' > $@; + @if test -r $(srcdir)/$@; then \ + echo "Using $(srcdir)/$@ for VERSION_TAG"; \ + diff $(srcdir)/$@ $@ > /dev/null 2>&1 || cp $(srcdir)/$@ $@; \ + else \ + echo "Using empty VERSION_TAG"; \ + echo '#define VERSION_TAG ""' > $@; \ + fi else @if test -d $(srcdir)/.git; then \ echo "Using git-describe for VERSION_TAG"; \ From b2bdce98abc16c6301cdfcd348dfa7a8711d49f1 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 26 May 2008 11:14:59 -0700 Subject: [PATCH 04/98] It is an error for the concatenation repeat to be undefined. Print an error message if the concatenation repeat expression is undefined. --- elab_expr.cc | 9 +++++++++ elab_net.cc | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 90c1937fc..d452b31e4 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -716,6 +716,15 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, des->errors += 1; } + if (!rep->value().is_defined()) { + cerr << get_fileline() << ": error: Concatenation repeat " + << "may not be undefined (" << rep->value() + << ")." << endl; + des->errors += 1; + concat_depth -= 1; + return 0; + } + if (rep->value().is_negative()) { cerr << get_fileline() << ": error: Concatenation repeat " << "may not be negative (" << rep->value().as_long() diff --git a/elab_net.cc b/elab_net.cc index 97fcb76cd..2e9224483 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1578,6 +1578,14 @@ NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope, return 0; } + if (!erep->value().is_defined()) { + cerr << get_fileline() << ": error: Concatenation repeat " + << "may not be undefined (" << erep->value() + << ")." << endl; + des->errors += 1; + return 0; + } + if (erep->value().is_negative()) { cerr << get_fileline() << ": error: Concatenation repeat " << "may not be negative (" << erep->value().as_long() From 7a1180868add9cae9328a4e2e933af9e155b68c7 Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 26 May 2008 13:57:10 -0700 Subject: [PATCH 05/98] Remove definition for non-existent routines. ivl_switch_scope, ivl_switch_attr_cnt and ivl_switch_attr_val are non-existent routines and should not be in ivl.def. I also removed them from ivl_target.h. Cygwin expects that if a routine is listed in ivl.def that it will find a real implementation. --- ivl.def | 3 --- ivl_target.h | 7 ------- 2 files changed, 10 deletions(-) diff --git a/ivl.def b/ivl.def index 48b798910..16989795a 100644 --- a/ivl.def +++ b/ivl.def @@ -222,10 +222,7 @@ ivl_switch_a ivl_switch_b ivl_switch_basename ivl_switch_enable -ivl_switch_scope ivl_switch_type -ivl_switch_attr_cnt; -ivl_switch_attr_val; ivl_udp_init ivl_udp_name diff --git a/ivl_target.h b/ivl_target.h index a39366a18..13477eb62 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1854,9 +1854,6 @@ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net); * ivl_switch_basename * This is the name given to the device in the source code. * - * ivl_switch_scope - * The scope where the switch device appears. - * * ivl_switch_a * ivl_switch_b * The a and b ports are the two ports of the switch. @@ -1871,14 +1868,10 @@ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net); */ extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net); extern const char*ivl_switch_basename(ivl_switch_t net); -extern ivl_scope_t ivl_switch_scope(ivl_switch_t net); extern ivl_nexus_t ivl_switch_a(ivl_switch_t net); extern ivl_nexus_t ivl_switch_b(ivl_switch_t net); extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net); -extern unsigned ivl_switch_attr_cnt(ivl_switch_t net); -extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx); - #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) #else From f04fb0fc450b460ad8a52beb0f00db7f16228fc1 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 27 May 2008 15:11:17 -0700 Subject: [PATCH 06/98] System functions have a default return value. If a system function does not call vpi_put_value it is supposed to have a default return value of 0. This patch adds this functionality. --- vvp/vpi_priv.h | 1 + vvp/vpi_tasks.cc | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index fc43caeff..ab4e11658 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -368,6 +368,7 @@ struct __vpiSysTaskCall { class vvp_net_t*fnet; unsigned file_idx; unsigned lineno; + bool put_value; }; extern struct __vpiSysTaskCall*vpip_cur_task; diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index f82a43c41..fdad4ffc3 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -167,6 +167,8 @@ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + rfp->put_value = true; + assert(rfp->vbit >= 4); switch (vp->format) { @@ -271,6 +273,8 @@ static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int) struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + rfp->put_value = true; + /* Make sure this is a real valued function. */ assert(rfp->vwid == -vpiRealConst); @@ -297,6 +301,8 @@ static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int) struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + rfp->put_value = true; + unsigned vwid = (unsigned) rfp->vwid; vvp_vector4_t val (vwid); @@ -384,8 +390,10 @@ 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; - double val; + rfp->put_value = true; + + double val; switch (vp->format) { case vpiRealVal: @@ -563,6 +571,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; obj->userdata = 0; + obj->put_value = false; compile_compiletf(obj); @@ -590,8 +599,23 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) if (vpip_cur_task->defn->info.calltf) { assert(vpi_mode_flag == VPI_MODE_NONE); vpi_mode_flag = VPI_MODE_CALLTF; + vpip_cur_task->put_value = false; vpip_cur_task->defn->info.calltf(vpip_cur_task->defn->info.user_data); 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 && + !vpip_cur_task->put_value) { + s_vpi_value val; + if (vpip_cur_task->vwid == -vpiRealConst) { + val.format = vpiRealVal; + val.value.real = 0.0; + } else { + val.format = vpiIntVal; + val.value.integer = 0; + } + vpi_put_value(ref, &val, 0, vpiNoDelay); + } } } From 2fab3159dda33872d9e306913cc7d5ad03b85bbe Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 27 May 2008 14:29:08 -0700 Subject: [PATCH 07/98] Add smart part select for system functions &PV<>. This patch adds a smart part select that allows system functions to have full access to the real bits of the part select. --- tgt-vvp/draw_vpi.c | 109 +++++ vpi/sys_display.c | 2 + vpi_user.h | 6 +- vvp/lexor.lex | 8 +- vvp/parse.y | 9 +- vvp/vpi_priv.h | 14 + vvp/vpi_signal.cc | 876 ++++++++++++++++++++++++++++------------- vvp/vpi_vthr_vector.cc | 2 +- 8 files changed, 753 insertions(+), 273 deletions(-) diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index ab290867c..2930c6a21 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -29,6 +29,82 @@ #define snprintf _snprintf #endif +/* + * Check to see if the expression (number) can be correctly represented + * with a long variable. + */ +static int is_constant_number(ivl_expr_t ex) +{ + /* Make sure this matches the return type of constant_number(). */ + unsigned lim_wid = 8*sizeof(long); + const char*bits; + char pad_bit = '0'; + unsigned idx; + unsigned nbits = ivl_expr_width(ex); + + if (ivl_expr_type(ex) != IVL_EX_NUMBER + && ivl_expr_type(ex) != IVL_EX_ULONG) + return 0; + + bits = ivl_expr_bits(ex); + + /* For unsigned values the effective MSB and on must be '0'. */ + if (!ivl_expr_signed(ex)) lim_wid -= 1; + + /* For negative values the pad bit is '1'. */ + if (ivl_expr_signed(ex) && bits[nbits-1]=='1') { + pad_bit = '1'; + } + + /* For the number to fit in the variable all the upper bits must + * match the pad bits. */ + for (idx = lim_wid ; idx < nbits ; idx += 1) { + if (bits[idx] != pad_bit) return 0; + } + + return 1; +} + +/* + * Convert the expression (number) to a long value. + */ +static long get_constant_number(ivl_expr_t ex) +{ + long rtn = 0; + + switch (ivl_expr_type(ex)) { + case IVL_EX_ULONG: + rtn = (signed)ivl_expr_value(ex); + break; + case IVL_EX_NUMBER: { + unsigned idx; + const char*bits = ivl_expr_bits(ex); + unsigned nbits = ivl_expr_width(ex); + char pad_bit = bits[nbits-1]; + /* Define all the bits in the long (negative numbers). */ + for (idx = 0 ; idx < 8*sizeof(long) ; idx += 1) { + char bit; + if (idx < nbits) bit = bits[idx]; + else bit = pad_bit; + switch (bit) { + case '0': + break; + case '1': + rtn |= 1 << idx; + break; + default: + assert(0); + } + } + break; + } + default: + assert(0); + } + + return rtn; +} + static const char* magic_sfuncs[] = { "$time", "$stime", @@ -217,6 +293,39 @@ static void draw_vpi_taskfunc_args(const char*call_string, continue; } + case IVL_EX_SELECT: { + ivl_expr_t vexpr = ivl_expr_oper1(expr); + assert(vexpr); + + /* This code is only for signals. */ + if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL) break; + + /* The signal is part of an array. */ + /* Add &APV<> code here when it is finished. */ + if (ivl_expr_oper1(vexpr)) break; + + ivl_expr_t bexpr = ivl_expr_oper2(expr); + assert(bexpr); + + /* This is a constant bit/part select. */ + if (is_constant_number(bexpr)) { + snprintf(buffer, sizeof buffer, "&PV", + ivl_expr_signal(vexpr), + get_constant_number(bexpr), + ivl_expr_width(expr)); + /* This is an indexed bit/part select. */ + } else { + struct vector_info rv; + rv = draw_eval_expr(bexpr, STUFF_OK_XZ); + snprintf(buffer, sizeof buffer, "&PV", + ivl_expr_signal(vexpr), + rv.base, rv.wid, + ivl_expr_width(expr)); + } + args[idx].text = strdup(buffer); + continue; + } + /* Everything else will need to be evaluated and passed as a constant to the vpi task. */ default: diff --git a/vpi/sys_display.c b/vpi/sys_display.c index c291d00e3..8b559fb15 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -827,6 +827,7 @@ static void do_display(unsigned int mcd, struct strobe_cb_info*info) case vpiReg: case vpiIntegerVar: case vpiMemoryWord: + case vpiPartSelect: do_display_numeric(mcd, info, item); break; @@ -1836,6 +1837,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) case vpiReg: case vpiIntegerVar: case vpiMemoryWord: + case vpiPartSelect: width = get_numeric(&result, info, item); rtn = realloc(rtn, (size+width)*sizeof(char)); memcpy(rtn+size-1, result, width); diff --git a/vpi_user.h b/vpi_user.h index 0087b52b5..6aba54f7f 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -279,6 +279,7 @@ typedef struct t_vpi_delay { #define vpiNamedFork 35 #define vpiNet 36 #define vpiParameter 41 +#define vpiPartSelect 42 #define vpiPathTerm 43 #define vpiRealVar 47 #define vpiReg 48 @@ -297,6 +298,7 @@ typedef struct t_vpi_delay { #define vpiModPathIn 95 #define vpiModPathOut 96 #define vpiVariables 100 +#define vpiExpr 102 #define vpiCallback 1000 @@ -346,8 +348,8 @@ typedef struct t_vpi_delay { # define vpiSysFuncReal vpiRealFunc # define vpiSysFuncTime vpiTimeFunc # define vpiSysFuncSized vpiSizedFunc -#define vpiSigned 65 -#define vpiExpr 102 +#define vpiConstantSelect 53 +#define vpiSigned 65 /* IVL private properties */ #define _vpiNexusId 0x1000000 diff --git a/vvp/lexor.lex b/vvp/lexor.lex index c3488bb72..0a266b389 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -173,6 +173,11 @@ "%disable" { return K_disable; } "%fork" { return K_fork; } + /* Handle the specialized variable access functions. */ + +"&A" { return K_A; } +"&PV" { return K_PV; } + "%"[.$_/a-zA-Z0-9]+ { yylval.text = strdup(yytext); assert(yylval.text); @@ -186,9 +191,6 @@ yylval.numb = strtol(yytext, 0, 0); return T_NUMBER; } - -"&A" { return K_A; } - /* Handle some specialized constant/literals as symbols. */ "C4<"[01xz]*">" { diff --git a/vvp/parse.y b/vvp/parse.y index dd8a2b22d..729a0158d 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -77,7 +77,7 @@ static struct __vpiModPath*modpath_dst = 0; %token K_EVENT K_EVENT_OR K_EXTEND_S K_FUNCTOR K_MODPATH K_NET K_NET_S K_NET_R %token K_NET8 K_NET8_S %token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV -%token K_PART_V K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR +%token K_PART_V K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR %token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT %token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS %token K_THREAD K_TIMESCALE K_UFUNC @@ -790,9 +790,14 @@ argument } | K_A '<' T_SYMBOL ',' T_NUMBER '>' { $$ = vpip_make_vthr_A($3, $5); } + | K_PV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_PV($3, $5, $7); } + | K_PV '<' T_SYMBOL ',' '-' T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_PV($3, -$6, $8); } + | K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_PV($3, $5, $6, $8); } ; - /* functor operands can only be a list of symbols. */ symbols : symbol diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index ab4e11658..be3f42bef 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -220,6 +220,20 @@ extern vpiHandle vpip_make_reg(const char*name, int msb, int lsb, extern vpiHandle vpip_make_net(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 + * a simple variable or constant array word. + */ +struct __vpiPV { + struct __vpiHandle base; + vpiHandle parent; + vvp_net_t*net; + int tbase; + unsigned twid, width; +}; +extern vpiHandle vpip_make_PV(char*name, int base, int width); +extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, int width); + /* * This function safely converts a vpiHandle back to a * __vpiSignal. Return a nil if the type is not appropriate. diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 7f09be83f..f1efa7f36 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -48,7 +48,7 @@ * draw_tt.c program. */ extern const char hex_digits[256]; -extern const char oct_digits[256]; +extern const char oct_digits[64]; /* * The string values need a result buf to hold the results. This @@ -109,6 +109,385 @@ char *generic_get_str(int code, vpiHandle ref, const char *name, const char *ind return res; } +/* + * The standard formating/conversion routines. + * They work with full or partial signals. + */ + +static void format_vpiBinStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + char *rbuf = need_result_buf(wid+1, RBUF_VAL); + long offset = wid - 1 + base; + long end = base + (signed)wid; + long ssize = (signed)sig->size(); + + for (long idx = base ; idx < end ; idx += 1) { + if (idx < 0 || idx >= ssize) { + rbuf[offset-idx] = 'x'; + } else { + rbuf[offset-idx] = vvp_bit4_to_ascii(sig->value(idx)); + } + } + rbuf[wid] = 0; + + vp->value.str = rbuf; +} + +static void format_vpiOctStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + unsigned dwid = (wid + 2) / 3; + char *rbuf = need_result_buf(dwid+1, RBUF_VAL); + long end = base + (signed)wid; + long ssize = (signed)sig->size(); + unsigned val = 0; + + rbuf[dwid] = 0; + for (long idx = base ; idx < end ; idx += 1) { + unsigned bit = 0; + if (idx < 0 || idx >= ssize) { + bit = 2; // BIT4_X + } else { + switch (sig->value(idx)) { + case BIT4_0: + bit = 0; + break; + case BIT4_1: + bit = 1; + break; + case BIT4_X: + bit = 2; + break; + case BIT4_Z: + bit = 3; + break; + } + } + val |= bit << 2*((idx-base) % 3); + + if ((idx-base) % 3 == 2) { + dwid -= 1; + rbuf[dwid] = oct_digits[val]; + val = 0; + } + } + + /* Fill in X or Z if they are the only thing in the value. */ + switch (wid % 3) { + case 1: + if (val == 2) val = 42; + else if (val == 3) val = 63; + break; + case 2: + if (val == 10) val = 42; + else if (val == 15) val = 63; + break; + } + + if (dwid > 0) rbuf[0] = oct_digits[val]; + + vp->value.str = rbuf; +} + +static void format_vpiHexStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + unsigned dwid = (wid + 3) / 4; + char *rbuf = need_result_buf(dwid+1, RBUF_VAL); + long end = base + (signed)wid; + long ssize = (signed)sig->size(); + unsigned val = 0; + + rbuf[dwid] = 0; + for (long idx = base ; idx < end ; idx += 1) { + unsigned bit = 0; + if (idx < 0 || idx >= ssize) { + bit = 2; // BIT4_X + } else { + switch (sig->value(idx)) { + case BIT4_0: + bit = 0; + break; + case BIT4_1: + bit = 1; + break; + case BIT4_X: + bit = 2; + break; + case BIT4_Z: + bit = 3; + break; + } + } + val |= bit << 2*((idx-base) % 4); + + if ((idx-base) % 4 == 3) { + dwid -= 1; + rbuf[dwid] = hex_digits[val]; + val = 0; + } + } + + /* Fill in X or Z if they are the only thing in the value. */ + switch (wid % 4) { + case 1: + if (val == 2) val = 170; + else if (val == 3) val = 255; + break; + case 2: + if (val == 10) val = 170; + else if (val == 15) val = 255; + break; + case 3: + if (val == 42) val = 170; + else if (val == 63) val = 255; + break; + } + + if (dwid > 0) rbuf[0] = hex_digits[val]; + + vp->value.str = rbuf; +} + +static void format_vpiDecStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + int signed_flag, s_vpi_value*vp) +{ + unsigned hwid = (sig->size()+2) / 3 + 1; + char *rbuf = need_result_buf(hwid, RBUF_VAL); + long ssize = (signed)sig->size(); + long end = base + (signed)wid; + + /* Do we have an end outside of the real signal vector. */ + if (base < 0 || end > ssize) { + bool all_x = true; + if (end > ssize) end = ssize; + if (base < 0) base = 0; + for (long idx = base ; idx < end ; idx += 1) { + if (sig->value(idx) != BIT4_X) { + all_x = false; + break; + } + } + + if (all_x) { + rbuf[0] = 'x'; + } else { + rbuf[0] = 'X'; + } + rbuf[1] = 0; + + vp->value.str = rbuf; + return; + } + + vvp_vector4_t vec4; + if (base == 0 && end == ssize) { + vec4 = sig->vec4_value(); + } else { + vec4 = sig->vec4_value().subvalue(base, wid); + } + + vpip_vec4_to_dec_str(vec4, rbuf, hwid, signed_flag); + + vp->value.str = rbuf; +} + +static void format_vpiIntVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + unsigned iwid = 8 * sizeof(vp->value.integer); + long ssize = (signed)sig->size(); + + if (wid > iwid) wid = iwid; + long end = base + (signed)wid; + if (end > ssize) end = ssize; + + vp->value.integer = 0; + for (long idx = (base < 0) ? 0 : base ; idx < end ; idx += 1) { + if (sig->value(idx) == BIT4_1) { + vp->value.integer |= 1<<(idx-base); + } + } +} + +static void format_vpiRealVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + int signed_flag, s_vpi_value*vp) +{ + vvp_vector4_t vec4(wid); + long ssize = (signed)sig->size(); + long end = base + (signed)wid; + if (end > ssize) end = ssize; + + for (long idx = (base < 0) ? 0 : base ; idx < end ; idx += 1) { + vec4.set_bit(idx-base, sig->value(idx)); + } + + vp->value.real = 0.0; + vector4_to_value(vec4, vp->value.real, signed_flag); +} + +static void format_vpiStringVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + /* The result will use a character for each 8 bits of the + vector. Add one extra character for the highest bits that + don't form an 8 bit group. */ + char *rbuf = need_result_buf(wid/8 + ((wid&7)!=0) + 1, RBUF_VAL); + char *cp = rbuf; + + char tmp = 0; + for (long idx = base+(signed)wid-1; idx >= base; idx -= 1) { + tmp <<= 1; + + if (idx >=0 && idx < (signed)sig->size() && + sig->value(idx) == BIT4_1) { + tmp |= 1; + } + + if (((idx-base)&7)==0){ + /* Skip leading nulls. */ + if (tmp == 0 && cp == rbuf) + continue; + + /* Nulls in the middle get turned into spaces. */ + *cp++ = tmp ? tmp : ' '; + tmp = 0; + } + } + *cp++ = 0; + + vp->value.str = rbuf; +} + +static void format_vpiScalarVal(vvp_fun_signal_vec*sig, int base, + s_vpi_value*vp) +{ + if (base >= 0 && base < (signed)sig->size()) { + switch (sig->value(base)) { + case BIT4_0: + vp->value.scalar = vpi0; + break; + case BIT4_1: + vp->value.scalar = vpi1; + break; + case BIT4_X: { + vvp_scalar_t strn = sig->scalar_value(base); + if (strn.strength0() == 1) vp->value.scalar = vpiH; + else if (strn.strength1() == 1) vp->value.scalar = vpiL; + else vp->value.scalar = vpiX; + break; + } + case BIT4_Z: + vp->value.scalar = vpiZ; + break; + } + } else { + vp->value.scalar = vpiX; + } +} + +static void format_vpiStrengthVal(vvp_fun_signal_vec*sig, int base, + unsigned wid, s_vpi_value*vp) +{ + long end = base + (signed)wid; + s_vpi_strengthval*op; + + op = (s_vpi_strengthval*) + need_result_buf(wid * sizeof(s_vpi_strengthval), RBUF_VAL); + + for (long idx = base ; idx < end ; idx += 1) { + if (idx >=0 && idx < (signed)sig->size()) { + vvp_scalar_t val = sig->scalar_value(idx); + + /* vvp_scalar_t strengths are 0-7, but the vpi strength + is bit0-bit7. This gets the vpi form of the strengths + from the vvp_scalar_t strengths. */ + unsigned s0 = 1 << val.strength0(); + unsigned s1 = 1 << val.strength1(); + + switch (val.value()) { + case BIT4_0: + op[idx-base].logic = vpi0; + op[idx-base].s0 = s0|s1; + op[idx-base].s1 = 0; + break; + + case BIT4_1: + op[idx-base].logic = vpi1; + op[idx-base].s0 = 0; + op[idx-base].s1 = s0|s1; + break; + + case BIT4_X: + op[idx-base].logic = vpiX; + op[idx-base].s0 = s0; + op[idx-base].s1 = s1; + break; + + case BIT4_Z: + op[idx-base].logic = vpiZ; + op[idx-base].s0 = vpiHiZ; + op[idx-base].s1 = vpiHiZ; + break; + } + } else { + op[idx-base].logic = vpiX; + op[idx-base].s0 = vpiStrongDrive; + op[idx-base].s1 = vpiStrongDrive; + } + } + + vp->value.strength = op; +} + +static void format_vpiVectorVal(vvp_fun_signal_vec*sig, int base, unsigned wid, + s_vpi_value*vp) +{ + long end = base + (signed)wid; + unsigned int obit = 0; + unsigned hwid = (wid - 1)/32 + 1; + + s_vpi_vecval *op = (p_vpi_vecval) + need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); + vp->value.vector = op; + + op->aval = op->bval = 0; + for (long idx = base ; idx < end ; idx += 1) { + if (base >= 0 && base < (signed)sig->size()) { + switch (sig->value(idx)) { + case BIT4_0: + op->aval &= ~(1 << obit); + op->bval &= ~(1 << obit); + break; + case BIT4_1: + op->aval |= (1 << obit); + op->bval &= ~(1 << obit); + break; + case BIT4_X: + op->aval |= (1 << obit); + op->bval |= (1 << obit); + break; + case BIT4_Z: + op->aval &= ~(1 << obit); + op->bval |= (1 << obit); + break; + } + } else { /* BIT4_X */ + op->aval |= (1 << obit); + op->bval |= (1 << obit); + } + + obit++; + if (!(obit % 32)) { + op += 1; + if ((op - vp->value.vector) < (ptrdiff_t)hwid) + op->aval = op->bval = 0; + obit = 0; + } + } +} + struct __vpiSignal* vpip_signal_from_handle(vpiHandle ref) { if ((ref->vpi_type->type_code != vpiNet) @@ -245,65 +624,6 @@ static vpiHandle signal_iterate(int code, vpiHandle ref) return 0; } - -static char *signal_vpiDecStrVal(struct __vpiSignal*rfp, s_vpi_value*vp) -{ - vvp_fun_signal_vec*vsig = dynamic_cast(rfp->node->fun); - assert(vsig); - - unsigned hwid = (vsig->size()+2) / 3 + 1; - char *rbuf = need_result_buf(hwid, RBUF_VAL); - - vpip_vec4_to_dec_str(vsig->vec4_value(), rbuf, hwid, rfp->signed_flag); - - return rbuf; -} - - -static char *signal_vpiStringVal(struct __vpiSignal*rfp, s_vpi_value*vp) -{ - unsigned wid = (rfp->msb >= rfp->lsb) - ? (rfp->msb - rfp->lsb + 1) - : (rfp->lsb - rfp->msb + 1); - - vvp_fun_signal*vsig = dynamic_cast(rfp->node->fun); - - /* The result will use a character for each 8 bits of the - vector. Add one extra character for the highest bits that - don't form an 8 bit group. */ - char *rbuf = need_result_buf(wid/8 + ((wid&7)!=0) + 1, RBUF_VAL); - char *cp = rbuf; - - char tmp = 0; - int bitnr; - for(bitnr=wid-1; bitnr>=0; bitnr--){ - tmp <<= 1; - - switch (vsig->value(bitnr)) { - case BIT4_0: - break; - case BIT4_1: - tmp |= 1; - break; - default: - break; - } - - if ((bitnr&7)==0){ - /* Skip leading nulls. */ - if (tmp == 0 && cp == rbuf) - continue; - - /* Nulls in the middle get turned into spaces. */ - *cp++ = tmp? tmp : ' '; - tmp = 0; - } - } - *cp++ = 0; - - return rbuf; -} - static unsigned signal_width(const struct __vpiSignal*rfp) { unsigned wid = (rfp->msb >= rfp->lsb) @@ -313,97 +633,6 @@ static unsigned signal_width(const struct __vpiSignal*rfp) return wid; } -static void signal_get_IntVal(struct __vpiSignal*rfp, s_vpi_value*vp) -{ - unsigned wid = signal_width(rfp); - unsigned iwid = 8 * sizeof vp->value.integer; - vvp_fun_signal_vec*vsig = dynamic_cast(rfp->node->fun); - - if (wid > iwid) { - wid = iwid; - } - vp->value.integer = 0; - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - switch (vsig->value(idx)) { - case BIT4_0: - break; - case BIT4_1: - vp->value.integer |= 1<(rfp->node->fun); - - switch (vsig->value(0)) { - case BIT4_0: - vp->value.scalar = vpi0; - break; - case BIT4_1: - vp->value.scalar = vpi1; - break; - case BIT4_X: - vp->value.scalar = vpiX; - break; - case BIT4_Z: - vp->value.scalar = vpiZ; - break; - } -} - -static void signal_get_StrengthVal(struct __vpiSignal*rfp, s_vpi_value*vp) -{ - vvp_fun_signal_vec*vsig = dynamic_cast(rfp->node->fun); - unsigned wid = signal_width(rfp); - s_vpi_strengthval*op; - - op = (s_vpi_strengthval*) - need_result_buf(wid * sizeof(s_vpi_strengthval), RBUF_VAL); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - vvp_scalar_t val = vsig->scalar_value(idx); - - /* vvp_scalar_t strengths are 0-7, but the vpi strength - is bit0-bit7. This gets the vpi form of the strengths - from the vvp_scalar_t strengths. */ - unsigned s0 = 1 << val.strength0(); - unsigned s1 = 1 << val.strength1(); - - switch (val.value()) { - case BIT4_0: - op[idx].logic = vpi0; - op[idx].s0 = s0|s1; - op[idx].s1 = 0; - break; - case BIT4_1: - op[idx].logic = vpi1; - op[idx].s0 = 0; - op[idx].s1 = s0|s1; - break; - case BIT4_X: - op[idx].logic = vpiX; - op[idx].s0 = s0; - op[idx].s1 = s1; - break; - case BIT4_Z: - op[idx].logic = vpiZ; - op[idx].s0 = vpiHiZ; - op[idx].s1 = vpiHiZ; - break; - } - } - - vp->value.strength = op; -} - /* * The get_value method reads the values of the functors and returns * the vector to the caller. This causes no side-effect, and reads the @@ -421,146 +650,48 @@ static void signal_get_value(vpiHandle ref, s_vpi_value*vp) vvp_fun_signal_vec*vsig = dynamic_cast(rfp->node->fun); assert(vsig); - char *rbuf = 0; - switch (vp->format) { case vpiIntVal: - signal_get_IntVal(rfp, vp); + format_vpiIntVal(vsig, 0, wid, vp); break; case vpiScalarVal: - signal_get_ScalarVal(rfp, vp); + format_vpiScalarVal(vsig, 0, vp); break; case vpiStrengthVal: - signal_get_StrengthVal(rfp, vp); + format_vpiStrengthVal(vsig, 0, wid, vp); break; case vpiBinStrVal: - rbuf = need_result_buf(wid+1, RBUF_VAL); - - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - rbuf[wid-idx-1] = vvp_bit4_to_ascii(vsig->value(idx)); - } - rbuf[wid] = 0; - vp->value.str = rbuf; + format_vpiBinStrVal(vsig, 0, wid, vp); break; case vpiHexStrVal: { - unsigned hwid = (wid + 3) / 4; - - rbuf = need_result_buf(hwid+1, RBUF_VAL); - rbuf[hwid] = 0; - - vpip_vec4_to_hex_str(vsig->vec4_value(), rbuf, hwid+1, false); - vp->value.str = rbuf; - break; + format_vpiHexStrVal(vsig, 0, wid, vp); + break; } - case vpiOctStrVal: { - unsigned hval, hwid; - hwid = (wid + 2) / 3; - - rbuf = need_result_buf(hwid+1, RBUF_VAL); - rbuf[hwid] = 0; - hval = 0; - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - unsigned tmp = 0; - switch (vsig->value(idx)) { - case BIT4_0: - tmp = 0; - break; - case BIT4_1: - tmp = 1; - break; - case BIT4_Z: - tmp = 3; - break; - case BIT4_X: - tmp = 2; - break; - } - hval = hval | (tmp << 2*(idx % 3)); - - if (idx%3 == 2) { - hwid -= 1; - rbuf[hwid] = oct_digits[hval]; - hval = 0; - } - } - - if (hwid > 0) { - hwid -= 1; - rbuf[hwid] = oct_digits[hval]; - unsigned padd = 0; - switch(rbuf[hwid]) { - case 'X': padd = 2; break; - case 'Z': padd = 3; break; - } - if (padd) { - for (unsigned idx = wid % 3; idx < 3; idx += 1) { - hval = hval | padd << 2*idx; - } - rbuf[hwid] = oct_digits[hval]; - } - } - vp->value.str = rbuf; - break; - } + case vpiOctStrVal: + format_vpiOctStrVal(vsig, 0, wid, vp); + break; case vpiDecStrVal: - vp->value.str = signal_vpiDecStrVal(rfp, vp); + format_vpiDecStrVal(vsig, 0, wid, rfp->signed_flag, vp); break; case vpiStringVal: - vp->value.str = signal_vpiStringVal(rfp, vp); + format_vpiStringVal(vsig, 0, wid, vp); break; - case vpiVectorVal: { - unsigned int obit = 0; - unsigned hwid = (wid - 1)/32 + 1; - - rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); - s_vpi_vecval *op = (p_vpi_vecval)rbuf; - vp->value.vector = op; - - op->aval = op->bval = 0; - for (unsigned idx = 0 ; idx < wid ; idx += 1) { - switch (vsig->value(idx)) { - case BIT4_0: - op->aval &= ~(1 << obit); - op->bval &= ~(1 << obit); - break; - case BIT4_1: - op->aval |= (1 << obit); - op->bval &= ~(1 << obit); - break; - case BIT4_X: - op->aval |= (1 << obit); - op->bval |= (1 << obit); - break; - case BIT4_Z: - op->aval &= ~(1 << obit); - op->bval |= (1 << obit); - break; - } - obit++; - if (!(obit % 32)) { - op += 1; - if ((op - vp->value.vector) < (ptrdiff_t)hwid) - op->aval = op->bval = 0; - obit = 0; - } - } - break; - } + case vpiVectorVal: + format_vpiVectorVal(vsig, 0, wid, vp); + break; case vpiRealVal: { - bool flag = rfp->signed_flag; - vp->value.real = 0.0; - vector4_to_value(vsig->vec4_value(), vp->value.real, flag); - break; + format_vpiRealVal(vsig, 0, wid, rfp->signed_flag, vp); + break; } default: @@ -812,3 +943,218 @@ vpiHandle vpip_make_net(const char*name, int msb, int lsb, return &obj->base; } + +static int PV_get_base(struct __vpiPV*rfp) +{ + if (rfp->twid == 0) return rfp->tbase; + + int tval = 0; + for (unsigned idx = 0 ; idx < rfp->twid ; idx += 1) { + vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread, + rfp->tbase + idx); + if (bit == BIT4_1) { + tval |= 1<vpi_type->type_code == vpiPartSelect); + struct __vpiPV*rfp = (struct __vpiPV*)ref; + + int rval = 0; + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! + + case vpiSigned: + return 0; // A part/bit select is always unsigned! + + case vpiSize: + return rfp->width; + + case vpiConstantSelect: + return rfp->twid == 0; + + case vpiLeftRange: rval += rfp->width; + case vpiRightRange: + rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp); + return rval; + + default: + fprintf(stderr, "PV_get: property %d is unknown\n", code); + } + + return 0; +} + +static char* PV_get_str(int code, vpiHandle ref) +{ + assert(ref->vpi_type->type_code == vpiPartSelect); + struct __vpiPV*rfp = (struct __vpiPV*)ref; + + switch (code) { + case vpiFile: // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + + case vpiName: + case vpiFullName: { + const char*nm = vpi_get_str(code, rfp->parent); + char full[1024+strlen(nm)]; + sprintf(full, "%s[%d:%d]", nm, vpi_get(vpiLeftRange, ref), + vpi_get(vpiRightRange, ref)); + return simple_set_rbuf_str(full); + } + + default: + fprintf(stderr, "PV_get_str: property %d is unknown\n", code); + } + + return 0; +} + +static void PV_get_value(vpiHandle ref, p_vpi_value vp) +{ + assert(ref->vpi_type->type_code == vpiPartSelect); + struct __vpiPV*rfp = (struct __vpiPV*)ref; + + vvp_fun_signal_vec*sig = dynamic_cast(rfp->net->fun); + assert(sig); + + switch (vp->format) { + + case vpiIntVal: + format_vpiIntVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiBinStrVal: + format_vpiBinStrVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiOctStrVal: + format_vpiOctStrVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiHexStrVal: + format_vpiHexStrVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiDecStrVal: + format_vpiDecStrVal(sig, PV_get_base(rfp), rfp->width, 0, vp); + break; + + case vpiStringVal: + format_vpiStringVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiScalarVal: + format_vpiScalarVal(sig, PV_get_base(rfp), vp); + break; + + case vpiStrengthVal: + format_vpiStrengthVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiVectorVal: + format_vpiVectorVal(sig, PV_get_base(rfp), rfp->width, vp); + break; + + case vpiRealVal: + format_vpiRealVal(sig, PV_get_base(rfp), rfp->width, 0, vp); + break; + + default: + fprintf(stderr, "vvp internal error: PV_get_value: " + "value type %u not implemented. Signal is %s.\n", + vp->format, vpi_get_str(vpiFullName, rfp->parent)); + assert(0); + } +} + +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; + vvp_fun_signal_vec*sig = reinterpret_cast(rfp->net); + assert(sig); + + unsigned width = rfp->width; + int base = PV_get_base(rfp); + if (base >= (signed) sig->size()) return 0; + if (base < 0) { + width += base; + base = 0; + } + if (base+width > sig->size()) width = sig->size() - base; + + bool full_sig = base == 0 && width == sig->size(); + + vvp_net_ptr_t ptr (rfp->net, 0); + +/* We only support integer values. */ + assert(vp->format == vpiIntVal); + if (full_sig) { + vvp_send_long(ptr, vp->value.integer); + } else { + vvp_send_long_pv(ptr, vp->value.integer, base, width); + } + + return 0; +} + +static vpiHandle PV_get_handle(int code, vpiHandle ref) +{ + assert(ref->vpi_type->type_code==vpiPartSelect); + struct __vpiPV*rfp = (struct __vpiPV*)ref; + + switch (code) { + + case vpiParent: + return rfp->parent; + break; + } + + return 0; +} + +static const struct __vpirt vpip_PV_rt = { + vpiPartSelect, + PV_get, + PV_get_str, + PV_get_value, + PV_put_value, + PV_get_handle, + 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; + obj->parent = vvp_lookup_handle(var); + obj->tbase = base; + obj->twid = 0; + obj->width = (unsigned) width; + obj->net = (vvp_net_t*) malloc(sizeof(vvp_net_t)); + functor_ref_lookup(&obj->net, var); + + return &obj->base; +} + +vpiHandle vpip_make_PV(char*var, int tbase, int twid, int width) +{ + struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); + obj->base.vpi_type = &vpip_PV_rt; + obj->parent = vvp_lookup_handle(var); + obj->tbase = tbase; + obj->twid = (unsigned) twid; + obj->width = (unsigned) width; + obj->net = (vvp_net_t*) malloc(sizeof(vvp_net_t)); + functor_ref_lookup(&obj->net, var); + + return &obj->base; +} diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 72a043fe5..85082b935 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -67,7 +67,7 @@ void set_bit(struct __vpiVThrVec *rfp, unsigned idx, vvp_bit4_t bit) extern const char hex_digits[256]; -extern const char oct_digits[256]; +extern const char oct_digits[64]; /* * vpi_get From 6f308131021fadb20bdda0284df2dada65b4e019 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 29 May 2008 13:52:12 -0700 Subject: [PATCH 08/98] Prevent overflow when parsing 32bit values The source can carry 32bit numbers. Watch out that they are handled all the way through to the compiled results on 32bit systems. --- vvp/lexor.lex | 4 ++-- vvp/parse.y | 2 +- vvp/vthread.cc | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 0a266b389..fb2ec4ade 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -184,11 +184,11 @@ return T_INSTR; } [0-9][0-9]* { - yylval.numb = strtol(yytext, 0, 0); + yylval.numb = strtoul(yytext, 0, 0); return T_NUMBER; } "0x"[0-9a-fA-F]+ { - yylval.numb = strtol(yytext, 0, 0); + yylval.numb = strtoul(yytext, 0, 0); return T_NUMBER; } /* Handle some specialized constant/literals as symbols. */ diff --git a/vvp/parse.y b/vvp/parse.y index 729a0158d..fd12da226 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -47,7 +47,7 @@ static struct __vpiModPath*modpath_dst = 0; %union { char*text; char **table; - long numb; + unsigned long numb; bool flag; comp_operands_t opa; diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 5f82644ba..8b3b693fa 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1102,7 +1102,7 @@ static bool of_CMPIU_the_hard_way(vthread_t thr, vvp_code_t cp) { unsigned idx1 = cp->bit_idx[0]; - unsigned imm = cp->bit_idx[1]; + unsigned long imm = cp->bit_idx[1]; unsigned wid = cp->number; if (idx1 >= 4) thr_check_addr(thr, idx1+wid-1); @@ -1116,8 +1116,8 @@ static bool of_CMPIU_the_hard_way(vthread_t thr, vvp_code_t cp) vvp_bit4_t eq = BIT4_0; for (unsigned idx = 0 ; idx < wid ; idx += 1) { - vvp_bit4_t rv = (imm & 1)? BIT4_1 : BIT4_0; - imm >>= 1; + vvp_bit4_t rv = (imm & 1UL)? BIT4_1 : BIT4_0; + imm >>= 1UL; if (bit4_is_xz(lv)) { eq = BIT4_X; From 6f0d98cf186ddae536e1e5c9952f334f0242984f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 29 May 2008 14:00:03 -0700 Subject: [PATCH 09/98] Constrain multiply word to prevent overflow. The multiply runs does not need to do all the combinations of digit products, because the higher ones cannot add into the result. Fix the iteration to limit the scan. --- vvp/vthread.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 5f82644ba..b170cb01f 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3032,7 +3032,7 @@ bool of_MUL(vthread_t thr, vvp_code_t cp) res[idx] = 0; for (unsigned mul_a = 0 ; mul_a < words ; mul_a += 1) { - for (unsigned mul_b = 0 ; mul_b < words ; mul_b += 1) { + for (unsigned mul_b = 0 ; mul_b < (words-mul_a) ; mul_b += 1) { unsigned long sum; unsigned long tmp = multiply_with_carry(ap[mul_a], bp[mul_b], sum); unsigned base = mul_a + mul_b; From a8f492776aa38ff1358e8fc3cd13ace415dcee3b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 29 May 2008 14:00:32 -0700 Subject: [PATCH 10/98] Check range of immediate value. --- tgt-vvp/eval_expr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 3bcbf2717..d4f341cd7 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -92,6 +92,7 @@ unsigned long get_number_immediate(ivl_expr_t ex) case '0': break; case '1': + assert(idx < 8*sizeof(imm)); imm |= 1UL << idx; break; default: From fd6f0174351867d5e3e36eed8c6e81a9d1c0e6b7 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 29 May 2008 17:28:12 -0700 Subject: [PATCH 11/98] Get very subtle handling of part select into ports correct. The code generator was reading the wrong node of a bi-directional part select. This happens exclusively with part selects passed to bi-directional ports, so was rare. The result was that the non-part selected part may get an incorrect value. --- tgt-vvp/vvp_scope.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7900c30fb..f8e0829a1 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -733,7 +733,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) return strdup(tmp); } else if (ivl_lpm_data(lpm,0) == nex) { char tmp[128]; - snprintf(tmp, sizeof tmp, "L_%p/V", lpm); + snprintf(tmp, sizeof tmp, "L_%p/i", lpm); return strdup(tmp); } break; From 052870c0e5a103757e784582d91d66fdcf3c9908 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 31 May 2008 21:45:55 -0700 Subject: [PATCH 12/98] And the vvp_island infrastructure to the vvp runtime. The vvp_island classes are added, as well as support for tranif nodes that use this concept. The result is a working implementation for tranif0 and tranif1. In the process, the symbol table functions were cleaned up and made into templates for better type safety, and the vvp_net_ptr_t was generalized so that it can be used by the branches in the island implementation. Also fix up the array handling to use the better symbol table support, and to remember to clear its own table when linking is done. --- vvp/Makefile.in | 2 +- vvp/array.cc | 24 ++- vvp/compile.cc | 2 + vvp/compile.h | 12 ++ vvp/lexor.lex | 7 + vvp/parse.y | 27 ++- vvp/symbols.cc | 155 +++++--------- vvp/symbols.h | 88 ++++---- vvp/vvp_island.cc | 518 ++++++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_island.h | 27 +++ vvp/vvp_net.h | 83 +++----- 11 files changed, 730 insertions(+), 215 deletions(-) create mode 100644 vvp/vvp_island.cc create mode 100644 vvp/vvp_island.h diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 39663272e..ab1e8b227 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -79,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \ concat.o \ dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \ ufunc.o codes.o \ -vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \ +vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \ event.o logic.o delay.o words.o $V ifeq (@WIN32@,yes) diff --git a/vvp/array.cc b/vvp/array.cc index 3593bbda5..d094d14b0 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -30,7 +30,7 @@ # include "compile.h" # include -static symbol_table_t array_table =0; +static symbol_map_s* array_table =0; class vvp_fun_arrayport; static void array_attach_port(vvp_array_t, vvp_fun_arrayport*); @@ -40,8 +40,8 @@ vvp_array_t array_find(const char*label) if (array_table == 0) return 0; - symbol_value_t v = sym_get_value(array_table, label); - return (vvp_array_t)v.ptr; + vvp_array_t v = array_table->sym_get_value(label); + return v; } /* @@ -604,12 +604,10 @@ static vpiHandle vpip_make_array(char*label, const char*name, /* Add this symbol to the array_symbols table for later lookup. */ if (!array_table) - array_table = new_symbol_table(); + array_table = new symbol_map_s; assert(!array_find(label)); - symbol_value_t v; - v.ptr = obj; - sym_set_value(array_table, label, v); + array_table->sym_set_value(label, obj); /* Add this into the table of VPI objects. This is used for contexts that try to look up VPI objects in @@ -909,9 +907,7 @@ void compile_array_alias(char*label, char*name, char*src) assert(array_table); assert(!array_find(label)); - symbol_value_t v; - v.ptr = obj; - sym_set_value(array_table, label, v); + array_table->sym_set_value(label, obj); compile_vpi_symbol(label, &obj->base); vpip_attach_to_current_scope(&obj->base); @@ -936,3 +932,11 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) return &(obj->base); } + +void compile_array_cleanup(void) +{ + if (array_table) { + delete array_table; + array_table = 0; + } +} diff --git a/vvp/compile.cc b/vvp/compile.cc index 4ad8bf17d..898a88b74 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -645,6 +645,8 @@ void compile_cleanup(void) delete_symbol_table(sym_functors); sym_functors = 0; + compile_island_cleanup(); + if (verbose_flag) { fprintf(stderr, " ... Compiletf functions\n"); fflush(stderr); diff --git a/vvp/compile.h b/vvp/compile.h index 2795d0761..cf96c17e7 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -335,6 +335,8 @@ extern void compile_array_port(char*label, char*name, char*addr); /* Index is a constant address */ extern void compile_array_port(char*label, char*name, long addr); +extern void compile_array_cleanup(void); + /* * Compile the .ufunc statement. */ @@ -451,4 +453,14 @@ extern void compile_aliasw(char*label, char*array_symbol, unsigned long array_addr, int msb, int lsb, unsigned argc, struct symb_s*argv); +extern void compile_island(char*label, char*type); +extern void compile_island_port(char*label, char*island, char*src); +extern void compile_island_import(char*label, char*island, char*src); +extern void compile_island_export(char*label, char*island); + +extern void compile_island_tranif(int sense, char*island, + char*ba, char*bb, char*src); + +extern void compile_island_cleanup(void); + #endif diff --git a/vvp/lexor.lex b/vvp/lexor.lex index fb2ec4ade..db79e4645 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -124,8 +124,11 @@ ".dff" { return K_DFF; } ".event" { return K_EVENT; } ".event/or" { return K_EVENT_OR; } +".export" { return K_EXPORT; } ".extend/s" { return K_EXTEND_S; } ".functor" { return K_FUNCTOR; } +".import" { return K_IMPORT; } +".island" { return K_ISLAND; } ".modpath" { return K_MODPATH; } ".net" { return K_NET; } ".net8" { return K_NET8; } @@ -138,6 +141,7 @@ ".part" { return K_PART; } ".part/pv" { return K_PART_PV; } ".part/v" { return K_PART_V; } +".port" { return K_PORT; } ".reduce/and" { return K_REDUCE_AND; } ".reduce/or" { return K_REDUCE_OR; } ".reduce/xor" { return K_REDUCE_XOR; } @@ -153,6 +157,9 @@ ".shift/rs" { return K_SHIFTRS; } ".thread" { return K_THREAD; } ".timescale" { return K_TIMESCALE; } +".tran" { return K_TRAN; } +".tranif0" { return K_TRANIF0; } +".tranif1" { return K_TRANIF1; } ".ufunc" { return K_UFUNC; } ".var" { return K_VAR; } ".var/real" { return K_VAR_R; } diff --git a/vvp/parse.y b/vvp/parse.y index fd12da226..d51c7ab2b 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -74,13 +74,14 @@ static struct __vpiModPath*modpath_dst = 0; %token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R %token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S %token K_CONCAT K_DEBUG K_DELAY K_DFF -%token K_EVENT K_EVENT_OR K_EXTEND_S K_FUNCTOR K_MODPATH K_NET K_NET_S K_NET_R +%token K_EVENT K_EVENT_OR K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND +%token K_MODPATH K_NET K_NET_S K_NET_R %token K_NET8 K_NET8_S %token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV -%token K_PART_V K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR +%token K_PART_V K_PORT K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR %token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT %token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS -%token K_THREAD K_TIMESCALE K_UFUNC +%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_UFUNC %token K_UDP K_UDP_C K_UDP_S %token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r %token K_disable K_fork @@ -673,6 +674,26 @@ statement | T_LABEL K_PARAM_REAL T_STRING T_NUMBER T_NUMBER',' T_SYMBOL ';' { compile_param_real($1, $3, $7, $4, $5); } + /* Islands */ + + | T_LABEL K_ISLAND T_SYMBOL ';' + { compile_island($1, $3); } + + | T_LABEL K_PORT T_SYMBOL ',' T_SYMBOL ';' + { compile_island_port($1, $3, $5); } + + | T_LABEL K_IMPORT T_SYMBOL ',' T_SYMBOL ';' + { compile_island_import($1, $3, $5); } + + | T_LABEL K_EXPORT T_SYMBOL ';' + { compile_island_export($1, $3); } + + | K_TRANIF0 T_SYMBOL ',' T_SYMBOL T_SYMBOL ',' T_SYMBOL ';' + { compile_island_tranif(0, $2, $4, $5, $7); } + + | K_TRANIF1 T_SYMBOL ',' T_SYMBOL T_SYMBOL ',' T_SYMBOL ';' + { compile_island_tranif(1, $2, $4, $5, $7); } + /* Oh and by the way, empty statements are OK as well. */ | ';' diff --git a/vvp/symbols.cc b/vvp/symbols.cc index caa72ac81..9c8896386 100644 --- a/vvp/symbols.cc +++ b/vvp/symbols.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: symbols.cc,v 1.12 2004/10/04 01:10:59 steve Exp $" -#endif # include "symbols.h" # include @@ -42,26 +39,20 @@ struct key_strings { char data[64*1024 - sizeof(struct key_strings*)]; }; -struct symbol_table_s { - struct tree_node_*root; - struct key_strings*str_chunk; - unsigned str_used; -}; - -static char*key_strdup(struct symbol_table_s*tab, const char*str) +char*symbol_table_s::key_strdup_(const char*str) { unsigned len = strlen(str); - assert( (len+1) <= sizeof tab->str_chunk->data ); + assert( (len+1) <= sizeof str_chunk->data ); - if ( (len+1) > (sizeof tab->str_chunk->data - tab->str_used) ) { + if ( (len+1) > (sizeof str_chunk->data - str_used) ) { key_strings*tmp = new key_strings; - tmp->next = tab->str_chunk; - tab->str_chunk = tmp; - tab->str_used = 0; + tmp->next = str_chunk; + str_chunk = tmp; + str_used = 0; } - char*res = tab->str_chunk->data + tab->str_used; - tab->str_used += len + 1; + char*res = str_chunk->data + str_used; + str_used += len + 1; strcpy(res, str); return res; } @@ -111,19 +102,16 @@ static inline char* node_last_key(struct tree_node_*node) * a root node, and initializing the pointers and members of the root * node. */ -symbol_table_t new_symbol_table(void) +symbol_table_s::symbol_table_s() { - symbol_table_t tbl = new struct symbol_table_s; - tbl->root = new struct tree_node_; - tbl->root->leaf_flag = false; - tbl->root->count = 0; - tbl->root->parent = 0; + root = new struct tree_node_; + root->leaf_flag = false; + root->count = 0; + root->parent = 0; - tbl->str_chunk = new key_strings; - tbl->str_chunk->next = 0; - tbl->str_used = 0; - - return tbl; + str_chunk = new key_strings; + str_chunk->next = 0; + str_used = 0; } static void delete_symbol_node(struct tree_node_*cur) @@ -136,18 +124,6 @@ static void delete_symbol_node(struct tree_node_*cur) delete cur; } -void delete_symbol_table(symbol_table_t tab) -{ - delete_symbol_node(tab->root); - while (tab->str_chunk) { - key_strings*tmp = tab->str_chunk; - tab->str_chunk = tmp->next; - delete tmp; - } - - delete tab; -} - /* Do as split_leaf_ does, but for nodes. */ static void split_node_(struct tree_node_*cur) { @@ -286,9 +262,9 @@ static struct tree_node_* split_leaf_(struct tree_node_*cur) * true. */ -static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, - const char*key, symbol_value_t val, - bool force_flag) +symbol_value_t symbol_table_s::find_value_(struct tree_node_*cur, + const char*key, symbol_value_t val, + bool force_flag) { if (cur->leaf_flag) { @@ -297,7 +273,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, /* If we run out of keys in the leaf, then add this at the end of the leaf. */ if (idx == cur->count) { - cur->leaf[idx].key = key_strdup(tbl, key); + cur->leaf[idx].key = key_strdup_(key); cur->leaf[idx].val = val; cur->count += 1; if (cur->count == leaf_width) @@ -323,7 +299,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, for (unsigned tmp = cur->count; tmp > idx; tmp -= 1) cur->leaf[tmp] = cur->leaf[tmp-1]; - cur->leaf[idx].key = key_strdup(tbl, key); + cur->leaf[idx].key = key_strdup_(key); cur->leaf[idx].val = val; cur->count += 1; if (cur->count == leaf_width) @@ -343,17 +319,17 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, for (;;) { int rc = strcmp(key, node_last_key(cur->child[idx])); if (rc == 0) { - return find_value_(tbl, cur->child[idx], + return find_value_(cur->child[idx], key, val, force_flag); } if (rc > 0) { min = idx + 1; if (min == cur->count) - return find_value_(tbl, cur->child[idx], + return find_value_(cur->child[idx], key, val, force_flag); if (min == max) - return find_value_(tbl, cur->child[max], + return find_value_(cur->child[max], key, val, force_flag); idx = min + (max-min)/2; @@ -361,7 +337,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, } else { max = idx; if (idx == min) - return find_value_(tbl, cur->child[idx], + return find_value_(cur->child[idx], key, val, force_flag); idx = min + (max-min)/2; } @@ -375,90 +351,57 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur, } } -void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val) +void symbol_table_s::sym_set_value(const char*key, symbol_value_t val) { - if (tbl->root->count == 0) { + if (root->count == 0) { /* Handle the special case that this is the very first value in the symbol table. Create the first leaf node and initialize the pointers. */ struct tree_node_*cur = new struct tree_node_; cur->leaf_flag = true; - cur->parent = tbl->root; + cur->parent = root; cur->count = 1; - cur->leaf[0].key = key_strdup(tbl, key); + cur->leaf[0].key = key_strdup_(key); cur->leaf[0].val = val; - tbl->root->count = 1; - tbl->root->child[0] = cur; + root->count = 1; + root->child[0] = cur; } else { - find_value_(tbl, tbl->root, key, val, true); + find_value_(root, key, val, true); } } -symbol_value_t sym_get_value(symbol_table_t tbl, const char*key) +symbol_value_t symbol_table_s::sym_get_value(const char*key) { symbol_value_t def; def.num = 0; - if (tbl->root->count == 0) { + if (root->count == 0) { /* Handle the special case that this is the very first value in the symbol table. Create the first leaf node and initialize the pointers. */ struct tree_node_*cur = new struct tree_node_; cur->leaf_flag = true; - cur->parent = tbl->root; + cur->parent = root; cur->count = 1; - cur->leaf[0].key = key_strdup(tbl, key); + cur->leaf[0].key = key_strdup_(key); cur->leaf[0].val = def; - tbl->root->count = 1; - tbl->root->child[0] = cur; + root->count = 1; + root->child[0] = cur; return cur->leaf[0].val; } else { - return find_value_(tbl, tbl->root, key, def, false); + return find_value_(root, key, def, false); } } - -/* - * $Log: symbols.cc,v $ - * Revision 1.12 2004/10/04 01:10:59 steve - * Clean up spurious trailing white space. - * - * Revision 1.11 2003/02/09 23:33:26 steve - * Spelling fixes. - * - * Revision 1.10 2002/08/12 01:35:08 steve - * conditional ident string using autoconfig. - * - * Revision 1.9 2002/07/15 00:21:42 steve - * Fix initialization of symbol table string heap. - * - * Revision 1.8 2002/07/09 03:20:51 steve - * Fix split of root btree node. - * - * Revision 1.7 2002/07/05 04:40:59 steve - * Symbol table uses more efficient key string allocator, - * and remove all the symbol tables after compile is done. - * - * Revision 1.6 2002/07/05 02:50:58 steve - * Remove the vpi object symbol table after compile. - * - * Revision 1.5 2002/05/29 05:37:35 steve - * Use binary search to speed up deep lookups. - * - * Revision 1.4 2001/11/02 04:48:03 steve - * Implement split_node for symbol table (hendrik) - * - * Revision 1.3 2001/05/09 04:23:19 steve - * Now that the interactive debugger exists, - * there is no use for the output dump. - * - * Revision 1.2 2001/03/18 00:37:55 steve - * Add support for vpi scopes. - * - * Revision 1.1 2001/03/11 00:29:39 steve - * Add the vvp engine to cvs. - * - */ +symbol_table_s::~symbol_table_s() +{ + delete_symbol_node(root); + while (str_chunk) { + key_strings*tmp = str_chunk; + str_chunk = tmp->next; + delete tmp; + } +} diff --git a/vvp/symbols.h b/vvp/symbols.h index 3c6540c27..5b426dfda 100644 --- a/vvp/symbols.h +++ b/vvp/symbols.h @@ -1,7 +1,7 @@ #ifndef __symbols_H #define __symbols_H /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: symbols.h,v 1.5 2004/12/11 02:31:30 steve Exp $" -#endif /* * The symbol_table_t is intended as a means to hold and quickly index @@ -46,7 +43,7 @@ * try to look inside. The actual implementation is given in the * symbols.cc source file. */ -typedef struct symbol_table_s *symbol_table_t; +typedef class symbol_table_s *symbol_table_t; typedef struct symbol_value_s { union { @@ -56,6 +53,32 @@ typedef struct symbol_value_s { }; } symbol_value_t; + +class symbol_table_s { + public: + explicit symbol_table_s(); + virtual ~symbol_table_s(); + + // This method locates the value in the symbol table and sets its + // value. If the key doesn't yet exist, create it. + void sym_set_value(const char*key, symbol_value_t val); + + // This method locates the value in the symbol table and returns + // it. If the value does not exist, create it, initialize it with + // zero and return the zero value. + symbol_value_t sym_get_value(const char*key); + + private: + struct tree_node_*root; + struct key_strings*str_chunk; + unsigned str_used; + + symbol_value_t find_value_(struct tree_node_*cur, + const char*key, symbol_value_t val, + bool force_flag); + char*key_strdup_(const char*str); +}; + /* * Create a new symbol table or release an existing one. A new symbol * table has no keys and no values. As a symbol table is built up, it @@ -63,41 +86,32 @@ typedef struct symbol_value_s { * the delete_symbol_table method will delete the table, including all * the space for the keys. */ -extern symbol_table_t new_symbol_table(void); -extern void delete_symbol_table(symbol_table_t tbl); +inline symbol_table_t new_symbol_table(void) { return new symbol_table_s; } +inline void delete_symbol_table(symbol_table_t tbl) { delete tbl; } + +// These are obsolete, and here only to support older code. +inline void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val) +{ tbl->sym_set_value(key, val); } + +inline symbol_value_t sym_get_value(symbol_table_t tbl, const char*key) +{ return tbl->sym_get_value(key); } /* - * This method locates the value in the symbol table and sets its - * value. If the key doesn't yet exist, create it. + * This template is a type-safe interface to the symbol table. */ -void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val); +template class symbol_map_s : private symbol_table_s { -/* - * This method locates the value in the symbol table and returns - * it. If the value does not exist, create it, initialize it with - * zero and return the zero value. - */ -symbol_value_t sym_get_value(symbol_table_t tbl, const char*key); + public: + void sym_set_value(const char*key, T*val) + { symbol_value_t tmp; + tmp.ptr = val; + symbol_table_s::sym_set_value(key, tmp); + } + + T* sym_get_value(const char*key) + { symbol_value_t val = symbol_table_s::sym_get_value(key); + return reinterpret_cast(val.ptr); + } +}; -/* - * $Log: symbols.h,v $ - * Revision 1.5 2004/12/11 02:31:30 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.4 2002/08/12 01:35:08 steve - * conditional ident string using autoconfig. - * - * Revision 1.3 2001/05/09 04:23:19 steve - * Now that the interactive debugger exists, - * there is no use for the output dump. - * - * Revision 1.2 2001/03/18 00:37:55 steve - * Add support for vpi scopes. - * - * Revision 1.1 2001/03/11 00:29:39 steve - * Add the vvp engine to cvs. - * - */ #endif diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc new file mode 100644 index 000000000..2188fe4e7 --- /dev/null +++ b/vvp/vvp_island.cc @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vvp_island.h" +# include "compile.h" +# include "symbols.h" +# include "schedule.h" +# include +# include +# include +# include +#ifdef HAVE_MALLOC_H +# include +#endif + +/* +* Islands are mutually connected bidirectional meshes that have a +* discipline other then the implicit ddiscipline of the rest of the +* run time. +* +* In the vvp input, an island is created with this record: +* +*