From 234648231bea6952b0879fb21ec48e4520dece42 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 11 Mar 2008 16:04:00 -0700 Subject: [PATCH] Add bit/part select release for constants and add an error check. This patch adds functionality to do a bit or part select release when a constant value is forced to the net/register. It also adds an error message when the user tries to force a signal to a bit/part select. This is not currently handled by the run time, so is now caught in the compiler (tgt-vvp). Where when this functionality is needed, it will be easy to know what to do instead of trying to track down some odd runtime functionality. What this all means is that you can force a signal to an entire signal or you can force a constant to any part of a signal (bit, part or entire) and release any of the above. Technically the release of a constant value does not have to match the force. The runtime verifies that if you are releasing a signal driver it is being done as a full release. I don't see an easy way to check this in the compiler. To fix the signal deficiencies we need to rework the force_link code to allow multiple drivers and partial unlinking. Much of this is in the runtime, but the %force/link operator may also need to be changed like I did to the %release opcode. --- tgt-vvp/eval_expr.c | 2 +- tgt-vvp/vvp_process.c | 34 ++++++++++++------ vvp/compile.cc | 4 +-- vvp/opcodes.txt | 8 +++-- vvp/vthread.cc | 46 ++++++++++++++++++++---- vvp/vvp_net.cc | 84 +++++++++++++++++++++++++++++++++++++++++++ vvp/vvp_net.h | 14 ++++++++ 7 files changed, 170 insertions(+), 22 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 4d11e7167..4a6d09d8b 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1467,7 +1467,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid) if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) { int val = get_number_immediate(exp); - fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid); + fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid); return res; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index e21d1675d..1ec7785a0 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -820,7 +820,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) if (part_off != 0 || use_wid != ivl_signal_width(lsig)) { command_name = command_name_x0; - fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off); + fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off); } else { /* Do not support bit or part selects of l-values yet. */ @@ -831,7 +831,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec) assert((roff + use_wid) <= rvec.wid); } - fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name, + fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name, lsig, use_word, rvec.base+roff, use_wid); if (rvec.base >= 4) @@ -870,6 +870,17 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) lval = ivl_stmt_lval(net, 0); lsig = ivl_lval_sig(lval); + /* We do not currently support driving a signal to a bit or + * part select (this could give us multiple drivers). */ + ivl_expr_t part_off_ex = ivl_lval_part_off(lval); + if (ivl_signal_width(lsig) > ivl_signal_width(rsig) || + (part_off_ex && get_number_immediate(part_off_ex) != 0)) { + fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot %s signal to " + "a bit/part select.\n", ivl_expr_file(rval), + ivl_expr_lineno(rval), command_name); + exit(1); + } + /* At least for now, only handle force to fixed words of an array. */ if ((lword_idx = ivl_lval_idx(lval)) != 0) { assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long))); @@ -884,7 +895,7 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval) assert(ivl_signal_array_count(rsig) == 1); use_rword = 0; - fprintf(vvp_out, " %s/link", command_name); + fprintf(vvp_out, " %s/link", command_name); fprintf(vvp_out, " v%p_%lu", lsig, use_lword); fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword); } @@ -1172,11 +1183,13 @@ static int show_stmt_release(ivl_statement_t net) unsigned long use_word = 0; assert(lsig != 0); assert(ivl_lval_mux(lval) == 0); - if (ivl_lval_part_off(lval) != 0) { - fprintf(stderr, "%s:%u: sorry (vvp-tgt): Release of part/" - "bit select is not supported.\n", - ivl_stmt_file(net), ivl_stmt_lineno(net)); - exit(1); + + unsigned use_wid = ivl_lval_width(lval); + ivl_expr_t part_off_ex = ivl_lval_part_off(lval); + unsigned part_off = 0; + if (part_off_ex != 0) { + assert(number_is_immediate(part_off_ex, 64)); + part_off = get_number_immediate(part_off_ex); } switch (ivl_signal_type(lsig)) { @@ -1195,8 +1208,8 @@ static int show_stmt_release(ivl_statement_t net) /* Generate the appropriate release statement for this l-value. */ - fprintf(vvp_out, " %%release/%s v%p_%lu;\n", - opcode, lsig, use_word); + fprintf(vvp_out, " %%release/%s v%p_%lu, %u, %u;\n", + opcode, lsig, use_word, part_off, use_wid); } return 0; @@ -1584,4 +1597,3 @@ int draw_func_definition(ivl_scope_t scope) thread_count += 1; return rc; } - diff --git a/vvp/compile.cc b/vvp/compile.cc index 29e887a24..3068380a2 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -164,8 +164,8 @@ const static struct opcode_table_s opcode_table[] = { { "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, - { "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, - { "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} }, + { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, + { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} }, { "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} }, { "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 7628ed62e..d5679909a 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -586,8 +586,8 @@ This opcode raises (real) to the power of (real). The result replaces the left operand. -* %release/net -* %release/reg +* %release/net , , +* %release/reg , , Release the force on the signal that is represented by the functor . The force was previously activated with a %force/v @@ -598,6 +598,10 @@ output of the signal after the release is complete. The %release/reg sends the release command with reg semantics: the signal holds its forced value until another value propagates through. +The and are used to determine what part of the signal +will be released. For a full release the is 0 and is +the entire signal width. + * %set/v , , This sets a vector to a variable, and is used to implement blocking diff --git a/vvp/vthread.cc b/vvp/vthread.cc index e4932ffb8..09ea32382 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -3238,17 +3238,34 @@ bool of_POW_WR(vthread_t thr, vvp_code_t cp) bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) { vvp_net_t*net = cp->net; + unsigned base = cp->bit_idx[0]; + unsigned width = cp->bit_idx[1]; - vvp_fun_signal_base*sig = reinterpret_cast(net->fun); + vvp_fun_signal_vec*sig = reinterpret_cast(net->fun); assert(sig); - /* XXXX Release for %force/link not yet implemented. */ - if (sig->force_link) + if (base >= sig->size()) return true; + if (base+width > sig->size()) width = sig->size() - base; + + bool full_sig = base == 0 && width == sig->size(); + + if (sig->force_link) { + if (!full_sig) { + fprintf(stderr, "Sorry: when a signal is forcing a " + "net, I cannot release part of it.\n"); + exit(1); + } unlink_force(net); + } assert(sig->force_link == 0); + /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 3); - vvp_send_long(ptr, 2); + if (full_sig) { + vvp_send_long(ptr, 2); + } else { + vvp_send_long_pv(ptr, 2, base, width); + } return true; } @@ -3257,20 +3274,37 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp) bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp) { vvp_net_t*net = cp->net; + unsigned base = cp->bit_idx[0]; + unsigned width = cp->bit_idx[1]; - vvp_fun_signal_base*sig = reinterpret_cast(net->fun); + vvp_fun_signal_vec*sig = reinterpret_cast(net->fun); assert(sig); + if (base >= sig->size()) return true; + if (base+width > sig->size()) width = sig->size() - base; + + bool full_sig = base == 0 && width == sig->size(); + // This is the net that is forcing me... if (vvp_net_t*src = sig->force_link) { + if (!full_sig) { + fprintf(stderr, "Sorry: when a signal is forcing a " + "register, I cannot release part of it.\n"); + exit(1); + } // And this is the pointer to be removed. vvp_net_ptr_t dst_ptr (net, 2); unlink_from_driver(src, dst_ptr); } // Send a command to this signal to unforce itself. + /* Do we release all or part of the net? */ vvp_net_ptr_t ptr (net, 3); - vvp_send_long(ptr, 3); + if (full_sig) { + vvp_send_long(ptr, 3); + } else { + vvp_send_long_pv(ptr, 3, base, width); + } return true; } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 788d99c20..638bcdbe5 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -202,6 +202,19 @@ 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 (struct vvp_net_t*cur = ptr.ptr()) { + vvp_net_ptr_t next = cur->port[ptr.port()]; + + if (cur->fun) + cur->fun->recv_long_pv(ptr, val, base, wid); + + ptr = next; + } +} + void vvp_vector4_t::copy_bits(const vvp_vector4_t&that) { unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_; @@ -1603,6 +1616,13 @@ void vvp_net_fun_t::recv_long(vvp_net_ptr_t, long) assert(0); } +void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned) +{ + fprintf(stderr, "internal error: %s: recv_long_pv not implemented\n", + typeid(*this).name()); + assert(0); +} + /* **** vvp_fun_drive methods **** */ vvp_fun_drive::vvp_fun_drive(vvp_bit4_t init, unsigned str0, unsigned str1) @@ -1673,6 +1693,37 @@ void vvp_fun_signal_base::recv_long(vvp_net_ptr_t ptr, long bit) } } +void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit, + unsigned base, unsigned wid) +{ + switch (ptr.port()) { + case 3: // Command port + switch (bit) { + case 1: // deassign command + fprintf(stderr, "Sorry: cannot deassign a partial signal\n"); + assert(0); + deassign(); + break; + case 2: // release/net + release_pv(ptr, true, base, wid); + break; + case 3: // release/reg + release_pv(ptr, false, base, wid); + break; + default: + fprintf(stderr, "Unsupported command %ld.\n", bit); + assert(0); + break; + } + break; + + default: // Other ports are errors. + fprintf(stderr, "Unsupported port type %d.\n", ptr.port()); + assert(0); + break; + } +} + vvp_fun_signal::vvp_fun_signal(unsigned wid, vvp_bit4_t init) : bits4_(wid, init) { @@ -1810,6 +1861,19 @@ void vvp_fun_signal::release(vvp_net_ptr_t ptr, bool net) } } +void vvp_fun_signal::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(bits4_.size() >= base + wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 0); + if (!net) bits4_.set_bit(base+idx, force_.value(base+idx)); + } + + if (net) calculate_output_(ptr); +} + unsigned vvp_fun_signal::size() const { if (force_mask_.size()) @@ -1930,6 +1994,19 @@ void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net) } } +void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + assert(bits8_.size() >= base + wid); + + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + force_mask_.set_bit(base+idx, 0); + if (!net) bits8_.set_bit(base+idx, force_.value(base+idx)); + } + + if (net) calculate_output_(ptr); +} + unsigned vvp_fun_signal8::size() const { if (force_mask_.size()) @@ -2031,6 +2108,13 @@ void vvp_fun_signal_real::release(vvp_net_ptr_t ptr, bool net) } } +void vvp_fun_signal_real::release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) +{ + fprintf(stderr, "Error: cannot take bit/part select of a real value!\n"); + assert(0); +} + /* **** vvp_wide_fun_* methods **** */ vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 8b163f803..e8d2f0221 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -639,6 +639,8 @@ class vvp_net_fun_t { // Part select variants of above virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit, unsigned base, unsigned wid, unsigned vwid); + virtual void recv_long_pv(vvp_net_ptr_t port, long bit, + unsigned base, unsigned wid); private: // not implemented vvp_net_fun_t(const vvp_net_fun_t&); @@ -816,6 +818,8 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback { public: vvp_fun_signal_base(); void recv_long(vvp_net_ptr_t port, long bit); + void recv_long_pv(vvp_net_ptr_t port, long bit, + unsigned base, unsigned wid); public: @@ -834,6 +838,8 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback { void deassign(); virtual void release(vvp_net_ptr_t ptr, bool net) =0; + virtual void release_pv(vvp_net_ptr_t ptr, bool net, + unsigned base, unsigned wid) =0; }; /* @@ -870,6 +876,8 @@ class vvp_fun_signal : public vvp_fun_signal_vec { // Commands void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); void get_value(struct t_vpi_value*value); @@ -900,6 +908,8 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec { // Commands void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); void get_value(struct t_vpi_value*value); @@ -923,6 +933,8 @@ class vvp_fun_signal_real : public vvp_fun_signal_base { // Commands void release(vvp_net_ptr_t port, bool net); + void release_pv(vvp_net_ptr_t port, bool net, + unsigned base, unsigned wid); void get_value(struct t_vpi_value*value); @@ -1024,6 +1036,8 @@ inline void vvp_send_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val) extern void vvp_send_vec8(vvp_net_ptr_t ptr, vvp_vector8_t val); extern void vvp_send_real(vvp_net_ptr_t ptr, double val); extern void vvp_send_long(vvp_net_ptr_t ptr, long val); +extern void vvp_send_long_pv(vvp_net_ptr_t ptr, long val, + unsigned base, unsigned width); /* * Part-vector versions of above functions. This function uses the