diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 990b89d02..f3a00ac7c 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -293,7 +293,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, static void assign_to_lvector(ivl_lval_t lval, unsigned bit, unsigned delay, ivl_expr_t dexp, - unsigned width) + unsigned width, unsigned nevents) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); @@ -303,6 +303,14 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, const unsigned long use_word = 0; if (ivl_signal_dimensions(sig) > 0) { + + if (nevents) { + fprintf(stderr, "vvp-tgt sorry: non-blocking event " + "controls are not supported on arrays!\n"); + exit(1); + } + assert(nevents == 0); + assert(word_ix); assign_to_array_word(sig, word_ix, bit, delay, dexp, part_off_ex, width); return; @@ -320,16 +328,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, if (part_off_ex) { unsigned skip_assign = transient_id++; - if (dexp == 0) { - /* Constant delay... */ - draw_eval_expr_into_integer(part_off_ex, 1); - /* If the index expression has XZ bits, skip the assign. */ - fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); - fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", - sig, use_word, delay, bit); - fprintf(vvp_out, "t_%u ;\n", skip_assign); - } else { + if (dexp != 0) { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); @@ -341,6 +340,24 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, sig, use_word, delay_index, bit); fprintf(vvp_out, "t_%u ;\n", skip_assign); clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", + sig, use_word, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); + } else { + /* Constant delay... */ + draw_eval_expr_into_integer(part_off_ex, 1); + /* If the index expression has XZ bits, skip the assign. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); + fprintf(vvp_out, "t_%u ;\n", skip_assign); } } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { @@ -349,14 +366,7 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, single-bit set instruction. */ assert(ivl_lval_width(lval) == width); - if (dexp == 0) { - /* Constant delay... */ - fprintf(vvp_out, " %%ix/load 0, %u;\n", width); - fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); - fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", - sig, use_word, delay, bit); - - } else { + if (dexp != 0) { /* Calculated delay... */ int delay_index = allocate_word(); draw_eval_expr_into_integer(dexp, delay_index); @@ -365,14 +375,33 @@ static void assign_to_lvector(ivl_lval_t lval, unsigned bit, fprintf(vvp_out, " %%assign/v0/x1/d v%p_%lu, %d, %u;\n", sig, use_word, delay_index, bit); clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); + fprintf(vvp_out, " %%assign/v0/x1/e v%p_%lu, %u;\n", + sig, use_word, bit); + } else { + /* Constant delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%ix/load 1, %u;\n", part_off); + fprintf(vvp_out, " %%assign/v0/x1 v%p_%lu, %u, %u;\n", + sig, use_word, delay, bit); } } else if (dexp != 0) { + /* Calculated delay... */ draw_eval_expr_into_integer(dexp, 1); fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%assign/v0/d v%p_%lu, 1, %u;\n", sig, use_word, bit); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%ix/load 0, %u;\n", width); + fprintf(vvp_out, " %%assign/v0/e v%p_%lu, %u;\n", + sig, use_word, bit); } else { + /* Constant delay... */ fprintf(vvp_out, " %%ix/load 0, %u;\n", width); fprintf(vvp_out, " %%assign/v0 v%p_%lu, %u, %u;\n", sig, use_word, delay, bit); @@ -562,7 +591,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* We need to calculate the delay expression. */ if (del) { - assert(nevents == 0 && ivl_stmt_cond_expr(net) == 0); + assert(nevents == 0); int delay_index = allocate_word(); draw_eval_expr_into_integer(del, delay_index); fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", @@ -629,6 +658,8 @@ static int show_stmt_assign_nb(ivl_statement_t net) } else { fprintf(vvp_out, " %%evctl/i %s, %lu;\n", name, count); } + } else { + assert(ivl_stmt_cond_expr(net) == 0); } unsigned long delay = 0; @@ -644,16 +675,6 @@ static int show_stmt_assign_nb(ivl_statement_t net) } } - if (nevents) { - fprintf(stderr, "%s:%u: vvp-tgt sorry: non-blocking ", - ivl_stmt_file(net), ivl_stmt_lineno(net)); - if (ivl_stmt_cond_expr(net)) { - fprintf(stderr, "repeat "); - } - fprintf(stderr, "event controls are not supported!\n"); - exit(1); - } - if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); del = 0; @@ -675,7 +696,7 @@ static int show_stmt_assign_nb(ivl_statement_t net) unsigned bidx; bidx = res.base < 4? res.base : (res.base+cur_rbit); - assign_to_lvector(lval, bidx, delay, del, bit_limit); + assign_to_lvector(lval, bidx, delay, del, bit_limit, nevents); cur_rbit += bit_limit; diff --git a/vvp/codes.h b/vvp/codes.h index 1c5d87d4f..2b2d580a2 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -45,8 +45,10 @@ extern bool of_ASSIGN_D(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_MV(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_V0E(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 821d7852f..d1155750e 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -90,8 +90,10 @@ const static struct opcode_table_s opcode_table[] = { { "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0",of_ASSIGN_V0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/v0/e",of_ASSIGN_V0E,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} }, { "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, + { "%assign/v0/x1/e",of_ASSIGN_V0X1E,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, { "%assign/wr", of_ASSIGN_WR, 3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, { "%assign/wr/e",of_ASSIGN_WRE,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} }, diff --git a/vvp/event.cc b/vvp/event.cc index 60f9dd620..0c44b68e7 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -62,6 +62,16 @@ evctl::evctl(unsigned long ecount) next = 0; } +bool evctl::dec_and_run() +{ + assert(ecount_ != 0); + + ecount_ -= 1; + if (ecount_ == 0) run_run(); + + return ecount_ == 0; +} + evctl_real::evctl_real(struct __vpiHandle*handle, double value, unsigned long ecount) :evctl(ecount) @@ -70,21 +80,13 @@ evctl_real::evctl_real(struct __vpiHandle*handle, double value, value_ = value; } -bool evctl_real::dec_and_run() +void evctl_real::run_run() { - assert(ecount_ != 0); + t_vpi_value val; - ecount_ -= 1; - - if (ecount_ == 0) { - t_vpi_value val; - - val.format = vpiRealVal; - val.value.real = value_; - vpi_put_value(handle_, &val, 0, vpiNoDelay); - } - - return ecount_ == 0; + val.format = vpiRealVal; + val.value.real = value_; + vpi_put_value(handle_, &val, 0, vpiNoDelay); } void schedule_evctl(struct __vpiHandle*handle, double value, @@ -98,6 +100,37 @@ void schedule_evctl(struct __vpiHandle*handle, double value, ep->last = &((*(ep->last))->next); } +evctl_vector::evctl_vector(vvp_net_ptr_t ptr, const vvp_vector4_t&value, + unsigned off, unsigned wid, unsigned long ecount) +:evctl(ecount), value_(value) +{ + ptr_ = ptr; + off_ = off; + wid_ = wid; +} + +void evctl_vector::run_run() +{ + if (wid_ != 0) { + vvp_send_vec4_pv(ptr_, value_, off_, value_.size(), wid_); + } else { + vvp_send_vec4(ptr_, value_); + } +} + +void schedule_evctl(vvp_net_ptr_t ptr, const vvp_vector4_t&value, + unsigned offset, unsigned wid, + vvp_net_t*event, unsigned long ecount) +{ + // Get the functor we are going to wait on. + waitable_hooks_s*ep = dynamic_cast (event->fun); + assert(ep); + // Now add this call to the end of the event list. + *(ep->last) = new evctl_vector(ptr, value, offset, wid, ecount); + ep->last = &((*(ep->last))->next); +} + + inline vvp_fun_edge::edge_t VVP_EDGE(vvp_bit4_t from, vvp_bit4_t to) { return 1 << ((from << 2) | to); diff --git a/vvp/event.h b/vvp/event.h index 0cea1a184..49af1f31e 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -26,7 +26,8 @@ class evctl { public: explicit evctl(unsigned long ecount); - virtual bool dec_and_run() = 0; + bool dec_and_run(); + virtual void run_run() = 0; virtual ~evctl() {} evctl*next; @@ -40,16 +41,35 @@ class evctl_real : public evctl { explicit evctl_real(struct __vpiHandle*handle, double value, unsigned long ecount); virtual ~evctl_real() {} - bool dec_and_run(); + void run_run(); private: __vpiHandle*handle_; double value_; }; +class evctl_vector : public evctl { + + public: + explicit evctl_vector(vvp_net_ptr_t ptr, const vvp_vector4_t&value, + unsigned off, unsigned wid, unsigned long ecount); + virtual ~evctl_vector() {} + void run_run(); + + private: + vvp_net_ptr_t ptr_; + vvp_vector4_t value_; + unsigned off_; + unsigned wid_; +}; + extern void schedule_evctl(struct __vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount); +extern void schedule_evctl(vvp_net_ptr_t ptr, const vvp_vector4_t&value, + unsigned offset, unsigned wid, + vvp_net_t*event, unsigned long ecount); + /* * Event / edge detection functors */ diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index b7b117fc6..325e5dfbd 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -82,6 +82,7 @@ word address. * %assign/v0 , , * %assign/v0/d , , +* %assign/v0/e , The %assign/v0 instruction is a vector version of non-blocking assignment. The is the number of clock ticks in the future @@ -93,11 +94,16 @@ The %assign/v0/d variation gets the delay instead from an integer register that is given by the value. This should not be 0, of course, because integer 0 is taken with the vector width. +The %assign/v0/e variation uses the information in the thread +event control registers to determine when to perform the assign. +%evctl is used to set the event control information. + The references a .var object that can receive non-blocking assignments. For blocking assignments, see %set/v. * %assign/v0/x1 , , * %assign/v0/x1/d , , +* %assign/v0/x1/e , This is similar to the %assign/v0 instruction, but adds the index-1 index register with the canonical index of the destination where the diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 0743aa723..4775c816a 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -744,6 +744,33 @@ bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t cp) return true; } +/* + * This is %assign/v0/e