From 9a4cd1af32da4ebc78969b110ebb681bb2125830 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 2 Sep 2009 20:04:34 -0700 Subject: [PATCH] Add support for non-blocking assignment to real arrays. This patch adds support for the various types of non-blocking assignments to real arrays. --- tgt-vvp/vvp_process.c | 80 +++++++++++++++++++++++++++++++++++-------- vvp/codes.h | 5 ++- vvp/compile.cc | 3 ++ vvp/event.cc | 26 ++++++++++++++ vvp/event.h | 18 ++++++++++ vvp/main.cc | 2 ++ vvp/opcodes.txt | 22 +++++++++++- vvp/schedule.cc | 45 +++++++++++++++++++++++- vvp/schedule.h | 7 +++- vvp/statistics.h | 3 +- vvp/vthread.cc | 62 +++++++++++++++++++++++++++++++++ 11 files changed, 253 insertions(+), 20 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index fba9f3a64..37d87ec69 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -224,6 +224,63 @@ static void set_to_lvariable(ivl_lval_t lval, } } +/* Support a non-blocking assignment to a real array word. */ +static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix, + unsigned bit, uint64_t delay, + ivl_expr_t dexp, unsigned nevents) +{ + unsigned skip_assign = transient_id++; + + /* This code is common to all the different types of array delays. */ + if (number_is_immediate(word_ix, IMM_WID, 0)) { + assert(! number_is_unknown(word_ix)); + fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n", + get_number_immediate(word_ix)); + } else { + /* Calculate array word index into index register 3 */ + draw_eval_expr_into_integer(word_ix, 3); + /* Skip assignment if word expression is not defined. */ + fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign); + } + + if (dexp != 0) { + /* Calculated delay... */ + int delay_index = allocate_word(); + draw_eval_expr_into_integer(dexp, delay_index); + fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig, + delay_index, bit); + clr_word(delay_index); + } else if (nevents != 0) { + /* Event control delay... */ + fprintf(vvp_out, " %%assign/ar/e v%p, %u;\n", lsig, bit); + } else { + /* Constant delay... */ + unsigned long low_d = delay % UINT64_C(0x100000000); + unsigned long hig_d = delay / UINT64_C(0x100000000); + + /* + * The %assign can only take a 32 bit delay. For a larger + * delay we need to put it into an index register. + */ + if (hig_d != 0) { + int delay_index = allocate_word(); + fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", + delay_index, low_d, hig_d); + fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig, + delay_index, bit); + clr_word(delay_index); + } else { + fprintf(vvp_out, " %%assign/ar v%p, %lu, %u;\n", + lsig, low_d, bit); + } + } + + fprintf(vvp_out, "t_%u ;\n", skip_assign); + if (nevents != 0) fprintf(vvp_out, " %%evctl/c;\n"); + + clear_expression_lookaside(); +} + static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix, unsigned bit, uint64_t delay, ivl_expr_t dexp, ivl_expr_t part_off_ex, unsigned width, @@ -648,21 +705,6 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) sig = ivl_lval_sig(lval); assert(sig); - if (ivl_signal_dimensions(sig) > 0) { - word_ix = ivl_lval_idx(lval); - assert(word_ix); - assert(number_is_immediate(word_ix, IMM_WID, 0)); - assert(! number_is_unknown(word_ix)); - use_word = get_number_immediate(word_ix); - /* This method no longer works since variable arrays do not - * support _ access any more. We need real - * array specific opcodes (%assign/ar, etc.). */ - fprintf(stderr, "%s:%u: vvp-tgt sorry: non-blocking assignment " - "to a real array word is not supported.\n", - ivl_expr_file(rval), ivl_expr_lineno(rval)); - exit(1); - } - if (del && (ivl_expr_type(del) == IVL_EX_DELAY)) { assert(number_is_immediate(del, 64, 0)); delay = ivl_expr_delay_val(del); @@ -672,6 +714,14 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* Evaluate the r-value */ word = draw_eval_real(rval); + if (ivl_signal_dimensions(sig) > 0) { + word_ix = ivl_lval_idx(lval); + assert(word_ix); + assign_to_array_r_word(sig, word_ix, word, delay, del, nevents); + clr_word(word); + return 0; + } + /* We need to calculate the delay expression. */ if (del) { assert(nevents == 0); diff --git a/vvp/codes.h b/vvp/codes.h index eff9a2b14..5558119c6 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -1,7 +1,7 @@ #ifndef __codes_H #define __codes_H /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -40,6 +40,9 @@ extern bool of_ALLOC(vthread_t thr, vvp_code_t code); extern bool of_AND(vthread_t thr, vvp_code_t code); extern bool of_ANDI(vthread_t thr, vvp_code_t code); extern bool of_ANDR(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_AR(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_ARE(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_AV(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_AVD(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_AVE(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 2f718395a..d694bf820 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -87,6 +87,9 @@ const static struct opcode_table_s opcode_table[] = { { "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%andi", of_ANDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, + { "%assign/ar",of_ASSIGN_AR,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/ar/d",of_ASSIGN_ARD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/ar/e",of_ASSIGN_ARE,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} }, { "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, { "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} }, { "%assign/av/e",of_ASSIGN_AVE,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} }, diff --git a/vvp/event.cc b/vvp/event.cc index 3a6f95a67..550325e4f 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -159,6 +159,32 @@ void schedule_evctl(vvp_array_t memory, unsigned index, ep->last = &((*(ep->last))->next); } +evctl_array_r::evctl_array_r(vvp_array_t memory, unsigned index, + double value, unsigned long ecount) +:evctl(ecount) +{ + mem_ = memory; + idx_ = index; + value_ = value; +} + +void evctl_array_r::run_run() +{ + array_set_word(mem_, idx_, value_); +} + +void schedule_evctl(vvp_array_t memory, unsigned index, + double value, + 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_array_r(memory, index, value, 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 fd7ac81ae..55582d79b 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -81,6 +81,20 @@ class evctl_array : public evctl { unsigned off_; }; +class evctl_array_r : public evctl { + + public: + explicit evctl_array_r(vvp_array_t memory, unsigned index, + double value, unsigned long ecount); + virtual ~evctl_array_r() {} + virtual void run_run(); + + private: + vvp_array_t mem_; + unsigned idx_; + double value_; +}; + extern void schedule_evctl(struct __vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount); @@ -92,6 +106,10 @@ extern void schedule_evctl(vvp_array_t memory, unsigned index, const vvp_vector4_t&value, unsigned offset, vvp_net_t*event, unsigned long ecount); +extern void schedule_evctl(vvp_array_t memory, unsigned index, + double value, + vvp_net_t*event, unsigned long ecount); + /* * Event / edge detection functors */ diff --git a/vvp/main.cc b/vvp/main.cc index 76d66a168..d0cca4e40 100644 --- a/vvp/main.cc +++ b/vvp/main.cc @@ -422,6 +422,8 @@ int main(int argc, char*argv[]) count_assign_real_pool()); vpi_mcd_printf(1, " ...assign(word) pool=%lu\n", count_assign_aword_pool()); + vpi_mcd_printf(1, " ...assign(word/r) pool=%lu\n", + count_assign_arword_pool()); vpi_mcd_printf(1, " %8lu other events (pool=%lu)\n", count_gen_events, count_gen_pool()); } diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index a9634f318..54e49c152 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -65,6 +65,26 @@ means the following: 1 and 1 --> 1 otherwise x +* %assign/ar , , +* %assign/ar/d , , +* %assign/ar/e , + +The %assign/ar instruction assigns a real value to a word in the +labeled real array. The is the delay in simulation time to +the assignment (0 for non-blocking assignment) and is the +index register that contains the value to write. + +The memory word address is read from index register 3. The address is +in canonical form. + +The %assign/ar/d variation reads the delay from an integer register that +is given by the value. This should not be 3 or the index, +of course, since these registers contain the word address and the value. + +The %assign/ar/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. + * %assign/av , , * %assign/av/d , , * %assign/av/e , @@ -851,7 +871,7 @@ and leaves the result in the vector. xor is this: /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 diff --git a/vvp/schedule.cc b/vvp/schedule.cc index aca2ba308..f9ba88888 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -257,6 +257,37 @@ void assign_array_word_s::operator delete(void*ptr) unsigned long count_assign_aword_pool(void) { return array_w_heap.pool; } +struct assign_array_r_word_s : public event_s { + vvp_array_t mem; + unsigned adr; + double val; + void run_run(void); + + static void* operator new(size_t); + static void operator delete(void*); +}; + +void assign_array_r_word_s::run_run(void) +{ + count_assign_events += 1; + array_set_word(mem, adr, val); +} +static const size_t ARRAY_R_W_CHUNK_COUNT = 8192 / sizeof(struct assign_array_r_word_s); +static slab_t array_r_w_heap; + +inline void* assign_array_r_word_s::operator new(size_t size) +{ + assert(size == sizeof(assign_array_r_word_s)); + return array_r_w_heap.alloc_slab(); +} + +void assign_array_r_word_s::operator delete(void*ptr) +{ + array_r_w_heap.free_slab(ptr); +} + +unsigned long count_assign_arword_pool(void) { return array_r_w_heap.pool; } + struct generic_event_s : public event_s { vvp_gen_event_t obj; bool delete_obj_when_done; @@ -609,6 +640,18 @@ void schedule_assign_array_word(vvp_array_t mem, schedule_event_(cur, delay, SEQ_NBASSIGN); } +void schedule_assign_array_word(vvp_array_t mem, + unsigned word_addr, + double val, + vvp_time64_t delay) +{ + struct assign_array_r_word_s*cur = new struct assign_array_r_word_s; + cur->mem = mem; + cur->adr = word_addr; + cur->val = val; + schedule_event_(cur, delay, SEQ_NBASSIGN); +} + void schedule_set_vector(vvp_net_ptr_t ptr, const vvp_vector4_t&bit) { struct assign_vector4_event_s*cur = new struct assign_vector4_event_s(bit); diff --git a/vvp/schedule.h b/vvp/schedule.h index 391643d2f..fcb1111b0 100644 --- a/vvp/schedule.h +++ b/vvp/schedule.h @@ -1,7 +1,7 @@ #ifndef __schedule_H #define __schedule_H /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 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 @@ -57,6 +57,11 @@ extern void schedule_assign_array_word(vvp_array_t mem, unsigned off, vvp_vector4_t val, vvp_time64_t delay); + +extern void schedule_assign_array_word(vvp_array_t mem, + unsigned word_address, + double val, + vvp_time64_t delay); /* * This is very similar to schedule_assign_vector, but generates an * event in the active queue. It is used at link time to assign a diff --git a/vvp/statistics.h b/vvp/statistics.h index cc5876120..aa7bf0386 100644 --- a/vvp/statistics.h +++ b/vvp/statistics.h @@ -1,7 +1,7 @@ #ifndef __statistics_H #define __statistics_H /* - * Copyright (c) 2002-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2009 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 @@ -47,6 +47,7 @@ extern unsigned long count_assign4_pool(void); extern unsigned long count_assign8_pool(void); extern unsigned long count_assign_real_pool(void); extern unsigned long count_assign_aword_pool(void); +extern unsigned long count_assign_arword_pool(void); extern unsigned long count_gen_events; extern unsigned long count_gen_pool(void); diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 03e4124a1..13744c924 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -815,6 +815,68 @@ bool of_ADDI(vthread_t thr, vvp_code_t cp) return true; } +/* %assign/ar , , + * Generate an assignment event to a real array. Index register 3 + * contains the canonical address of the word in the memory. + * is the delay in simulation time. is the index register + * containing the real value. + */ +bool of_ASSIGN_AR(vthread_t thr, vvp_code_t cp) +{ + long adr = thr->words[3].w_int; + unsigned delay = cp->bit_idx[0]; + double value = thr->words[cp->bit_idx[1]].w_real; + + if (adr >= 0) { + schedule_assign_array_word(cp->array, adr, value, delay); + } + + return true; +} + +/* %assign/ar/d , , + * Generate an assignment event to a real array. Index register 3 + * contains the canonical address of the word in the memory. + * is the integer register that contains the delay value. + * is the index register containing the real value. + */ +bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t cp) +{ + long adr = thr->words[3].w_int; + vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_int; + double value = thr->words[cp->bit_idx[1]].w_real; + + if (adr >= 0) { + schedule_assign_array_word(cp->array, adr, value, delay); + } + + return true; +} + +/* %assign/ar/e , + * Generate an assignment event to a real array. Index register 3 + * contains the canonical address of the word in the memory. + * is the index register containing the real value. The event + * information is contained in the thread event control registers + * and is set with %evctl. + */ +bool of_ASSIGN_ARE(vthread_t thr, vvp_code_t cp) +{ + long adr = thr->words[3].w_int; + double value = thr->words[cp->bit_idx[0]].w_real; + + if (adr >= 0) { + if (thr->ecount == 0) { + schedule_assign_array_word(cp->array, adr, value, 0); + } else { + schedule_evctl(cp->array, adr, value, thr->event, + thr->ecount); + } + } + + return true; +} + /* %assign/av , , * This generates an assignment event to an array. Index register 0 * contains the width of the vector (and the word) and index register