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