Add support for non-blocking assignment to real arrays.

This patch adds support for the various types of non-blocking
assignments to real arrays.
This commit is contained in:
Cary R 2009-09-02 20:04:34 -07:00 committed by Stephen Williams
parent 9d765820bf
commit 9a4cd1af32
11 changed files with 253 additions and 20 deletions

View File

@ -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 <variable_id>_<idx> 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);

View File

@ -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);

View File

@ -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} },

View File

@ -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<waitable_hooks_s*> (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);

View File

@ -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
*/

View File

@ -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());
}

View File

@ -65,6 +65,26 @@ means the following:
1 and 1 --> 1
otherwise x
* %assign/ar <array-label>, <delay>, <bit>
* %assign/ar/d <array-label>, <delayx>, <bit>
* %assign/ar/e <array-label>, <bit>
The %assign/ar instruction assigns a real value to a word in the
labeled real array. The <delay> is the delay in simulation time to
the assignment (0 for non-blocking assignment) and <bit> 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 <delayx> value. This should not be 3 or the <bit> 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 <array-label>, <delay>, <bit>
* %assign/av/d <array-label>, <delayx>, <bit>
* %assign/av/e <array-label>, <bit>
@ -851,7 +871,7 @@ and leaves the result in the <dst> 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

View File

@ -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<sizeof(assign_array_r_word_s),ARRAY_R_W_CHUNK_COUNT> 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);

View File

@ -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

View File

@ -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);

View File

@ -815,6 +815,68 @@ bool of_ADDI(vthread_t thr, vvp_code_t cp)
return true;
}
/* %assign/ar <array>, <delay>, <bit>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory. <delay>
* is the delay in simulation time. <bit> 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 <array>, <delay_idx>, <bit>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory.
* <delay_idx> is the integer register that contains the delay value.
* <bit> 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 <array>, <bit>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory. <bit>
* 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 <array>, <delay>, <bit>
* This generates an assignment event to an array. Index register 0
* contains the width of the vector (and the word) and index register