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:
parent
9d765820bf
commit
9a4cd1af32
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
26
vvp/event.cc
26
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<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);
|
||||
|
|
|
|||
18
vvp/event.h
18
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue