Handle mixed continuous and non-blocking assignments to same vector.
SystemVerilog allows a mixture of procedural and continuous assignments to be applied to different parts of the same vector. The previous attempt to make this work for non-blocking assignments was flawed (see preceding fix for vvp_fun_part_pv::recv_vec4_pv). Instead, handle this case by converting the non-blocking assignment into a delayed force statement, which matches the way mixed continuous and blocking assignments are handled.
This commit is contained in:
parent
0c66116f51
commit
61c82d2cb0
|
|
@ -225,6 +225,10 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
|
||||
const unsigned long use_word = 0;
|
||||
|
||||
const char*assign_op = "%assign";
|
||||
if (ivl_signal_type(sig) == IVL_SIT_UWIRE)
|
||||
assign_op = "%force";
|
||||
|
||||
// Detect the case that this is actually a non-blocking assign
|
||||
// to an array word. In that case, run off somewhere else to
|
||||
// deal with it.
|
||||
|
|
@ -263,8 +267,8 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
to know to skip the assign. */
|
||||
draw_eval_expr_into_integer(part_off_ex, offset_index);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%assign/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
sig, use_word, offset_index, delay_index);
|
||||
fprintf(vvp_out, " %s/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
assign_op, sig, use_word, offset_index, delay_index);
|
||||
|
||||
clr_word(offset_index);
|
||||
clr_word(delay_index);
|
||||
|
|
@ -273,8 +277,8 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
int offset_index = allocate_word();
|
||||
/* Event control delay... */
|
||||
draw_eval_expr_into_integer(part_off_ex, offset_index);
|
||||
fprintf(vvp_out, " %%assign/vec4/off/e v%p_%lu, %d;\n",
|
||||
sig, use_word, offset_index);
|
||||
fprintf(vvp_out, " %s/vec4/off/e v%p_%lu, %d;\n",
|
||||
assign_op, sig, use_word, offset_index);
|
||||
fprintf(vvp_out, " %%evctl/c;\n");
|
||||
|
||||
clr_word(offset_index);
|
||||
|
|
@ -292,8 +296,8 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
to know to skip the assign. */
|
||||
draw_eval_expr_into_integer(part_off_ex, offset_index);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%assign/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
sig, use_word, offset_index, delay_index);
|
||||
fprintf(vvp_out, " %s/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
assign_op, sig, use_word, offset_index, delay_index);
|
||||
clr_word(offset_index);
|
||||
clr_word(delay_index);
|
||||
}
|
||||
|
|
@ -306,8 +310,8 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
fprintf(vvp_out, " %%ix/load %d, %lu, 0;\n",
|
||||
offset_index, part_off);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%assign/vec4/off/e v%p_%lu, %d;\n",
|
||||
sig, use_word, offset_index);
|
||||
fprintf(vvp_out, " %s/vec4/off/e v%p_%lu, %d;\n",
|
||||
assign_op, sig, use_word, offset_index);
|
||||
fprintf(vvp_out, " %%evctl/c;\n");
|
||||
clr_word(offset_index);
|
||||
|
||||
|
|
@ -325,8 +329,8 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
delay_index, low_d, hig_d);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
}
|
||||
fprintf(vvp_out, " %%assign/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
sig, use_word, offset_index, delay_index);
|
||||
fprintf(vvp_out, " %s/vec4/off/d v%p_%lu, %d, %d;\n",
|
||||
assign_op, sig, use_word, offset_index, delay_index);
|
||||
clr_word(offset_index);
|
||||
clr_word(delay_index);
|
||||
}
|
||||
|
|
@ -335,13 +339,13 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
fprintf(vvp_out, " %%assign/vec4/d v%p_%lu, %d;\n",
|
||||
sig, use_word, delay_index);
|
||||
fprintf(vvp_out, " %s/vec4/d v%p_%lu, %d;\n",
|
||||
assign_op, sig, use_word, delay_index);
|
||||
clr_word(delay_index);
|
||||
} else if (nevents != 0) {
|
||||
/* Event control delay... */
|
||||
fprintf(vvp_out, " %%assign/vec4/e v%p_%lu;\n",
|
||||
sig, use_word);
|
||||
fprintf(vvp_out, " %s/vec4/e v%p_%lu;\n",
|
||||
assign_op, sig, use_word);
|
||||
fprintf(vvp_out, " %%evctl/c;\n");
|
||||
|
||||
} else {
|
||||
|
|
@ -353,12 +357,12 @@ static void assign_to_lvector(ivl_lval_t lval,
|
|||
int delay_index = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
|
||||
delay_index, low_d, hig_d);
|
||||
fprintf(vvp_out, " %%assign/vec4/d v%p_%lu, %d;\n",
|
||||
sig, use_word, delay_index);
|
||||
fprintf(vvp_out, " %s/vec4/d v%p_%lu, %d;\n",
|
||||
assign_op, sig, use_word, delay_index);
|
||||
clr_word(delay_index);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%assign/vec4 v%p_%lu, %lu;\n",
|
||||
sig, use_word, low_d);
|
||||
fprintf(vvp_out, " %s/vec4 v%p_%lu, %lu;\n",
|
||||
assign_op, sig, use_word, low_d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_codes_H
|
||||
#define IVL_codes_H
|
||||
/*
|
||||
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2016 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
|
||||
|
|
@ -118,6 +118,7 @@ extern bool of_FLAG_SET_VEC4(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_VEC4_OFF(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_VEC4_OFF_D(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FREE(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%force/link", of_FORCE_LINK,2,{OA_FUNC_PTR, OA_FUNC_PTR2, OA_NONE} },
|
||||
{ "%force/vec4", of_FORCE_VEC4, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%force/vec4/off",of_FORCE_VEC4_OFF,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%force/vec4/off/d",of_FORCE_VEC4_OFF_D,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%force/wr", of_FORCE_WR, 1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%fork", of_FORK, 2, {OA_CODE_PTR2,OA_VPI_PTR, OA_NONE} },
|
||||
{ "%free", of_FREE, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2016 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -528,15 +528,17 @@ writes the LSB to the selected flag.
|
|||
|
||||
* %force/vec4 <label>
|
||||
* %force/vec4/off <label>, <off>
|
||||
* %force/vec4/off/d <label>, <off>, <delay>
|
||||
|
||||
Perform a "force" assign of a values to the target variable. The value
|
||||
to be forced is popped from the vec4 stack and forced to the target
|
||||
variable. The /off variant forces a part of a vector. The width of the
|
||||
part comes from the width of the popped value, and the <off> is an
|
||||
index register that contains the canonical offset where the value
|
||||
sets written.
|
||||
gets written. The <delay> is an index register that contains the
|
||||
delay.
|
||||
|
||||
The %force/vec4/off instruction will test the value of flags[4], and if
|
||||
The %force/vec4/off instructions will test the value of flags[4], and if
|
||||
it is 1, will suppress the actual assignment. This is intended to help
|
||||
with detection of invalid index expressions.
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
# include "schedule.h"
|
||||
# include "vthread.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "vvp_net_sig.h"
|
||||
# include "slab.h"
|
||||
# include "compile.h"
|
||||
# include <new>
|
||||
|
|
@ -323,6 +324,78 @@ void assign_array_word_s::operator delete(void*ptr)
|
|||
|
||||
unsigned long count_assign_aword_pool(void) { return array_w_heap.pool; }
|
||||
|
||||
struct force_vector4_event_s : public event_s {
|
||||
/* The default constructor. */
|
||||
explicit force_vector4_event_s(const vvp_vector4_t&that): val(that) {
|
||||
net = NULL;
|
||||
base = 0;
|
||||
vwid = 0;
|
||||
}
|
||||
/* Where to do the force. */
|
||||
vvp_net_t*net;
|
||||
/* Value to force. */
|
||||
vvp_vector4_t val;
|
||||
/* Offset of the part into the destination. */
|
||||
unsigned base;
|
||||
/* Width of the destination vector. */
|
||||
unsigned vwid;
|
||||
|
||||
void run_run(void);
|
||||
void single_step_display(void);
|
||||
|
||||
static void* operator new(size_t);
|
||||
static void operator delete(void*);
|
||||
};
|
||||
|
||||
void force_vector4_event_s::run_run(void)
|
||||
{
|
||||
count_assign_events += 1;
|
||||
|
||||
unsigned wid = val.size();
|
||||
if ((base + wid) > vwid)
|
||||
wid = vwid - base;
|
||||
|
||||
// Make a mask of which bits are to be forced, 0 for unforced
|
||||
// bits and 1 for forced bits.
|
||||
vvp_vector2_t mask (vvp_vector2_t::FILL0, vwid);
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1)
|
||||
mask.set_bit(base+idx, 1);
|
||||
|
||||
vvp_vector4_t tmp (vwid, BIT4_Z);
|
||||
|
||||
// vvp_net_t::force_vec4 propagates all the bits of the
|
||||
// forced vector value, regardless of the mask. This
|
||||
// ensures the unforced bits retain their current value.
|
||||
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(net->fil);
|
||||
assert(sig);
|
||||
sig->vec4_value(tmp);
|
||||
|
||||
tmp.set_vec(base, val);
|
||||
net->force_vec4(tmp, mask);
|
||||
}
|
||||
|
||||
void force_vector4_event_s::single_step_display(void)
|
||||
{
|
||||
cerr << "force_vector4_event: Force val=" << val
|
||||
<< ", vwid=" << vwid << ", base=" << base << endl;
|
||||
}
|
||||
|
||||
static const size_t FORCE4_CHUNK_COUNT = 8192 / sizeof(struct force_vector4_event_s);
|
||||
static slab_t<sizeof(force_vector4_event_s),FORCE4_CHUNK_COUNT> force4_heap;
|
||||
|
||||
inline void* force_vector4_event_s::operator new(size_t size)
|
||||
{
|
||||
assert(size == sizeof(force_vector4_event_s));
|
||||
return force4_heap.alloc_slab();
|
||||
}
|
||||
|
||||
void force_vector4_event_s::operator delete(void*dptr)
|
||||
{
|
||||
force4_heap.free_slab(dptr);
|
||||
}
|
||||
|
||||
unsigned long count_force4_pool(void) { return force4_heap.pool; }
|
||||
|
||||
/*
|
||||
* This class supports the propagation of vec4 outputs from a
|
||||
* vvp_net_t object.
|
||||
|
|
@ -796,6 +869,18 @@ void schedule_assign_vector(vvp_net_ptr_t ptr,
|
|||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_force_vector(vvp_net_t*net,
|
||||
unsigned base, unsigned vwid,
|
||||
const vvp_vector4_t&bit,
|
||||
vvp_time64_t delay)
|
||||
{
|
||||
struct force_vector4_event_s*cur = new struct force_vector4_event_s(bit);
|
||||
cur->net = net;
|
||||
cur->base = base;
|
||||
cur->vwid = vwid;
|
||||
schedule_event_(cur, delay, SEQ_NBASSIGN);
|
||||
}
|
||||
|
||||
void schedule_propagate_vector(vvp_net_t*net,
|
||||
vvp_time64_t delay,
|
||||
const vvp_vector4_t&src)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,15 @@ extern void schedule_assign_array_word(vvp_array_t mem,
|
|||
unsigned word_address,
|
||||
double val,
|
||||
vvp_time64_t delay);
|
||||
|
||||
/*
|
||||
* Create an event to force the output of a net.
|
||||
*/
|
||||
extern void schedule_force_vector(vvp_net_t*net,
|
||||
unsigned base, unsigned vwid,
|
||||
const vvp_vector4_t&val,
|
||||
vvp_time64_t delay);
|
||||
|
||||
/*
|
||||
* Create an event to propagate the output of a net.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -2998,6 +2998,38 @@ bool of_FORCE_VEC4_OFF(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %force/vec4/off/d <net>, <off>, <del>
|
||||
*/
|
||||
bool of_FORCE_VEC4_OFF_D(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
|
||||
unsigned base_idx = cp->bit_idx[0];
|
||||
long base = thr->words[base_idx].w_int;
|
||||
|
||||
unsigned delay_idx = cp->bit_idx[1];
|
||||
vvp_time64_t delay = thr->words[delay_idx].w_uint;
|
||||
|
||||
vvp_vector4_t value = thr->pop_vec4();
|
||||
|
||||
assert(net->fil);
|
||||
|
||||
if (thr->flags[4] == BIT4_1)
|
||||
return true;
|
||||
|
||||
// This is the width of the target vector.
|
||||
unsigned use_size = net->fil->filter_size();
|
||||
|
||||
if (base >= (long)use_size)
|
||||
return true;
|
||||
if (base < -(long)use_size)
|
||||
return true;
|
||||
|
||||
schedule_force_vector(net, base, use_size, value, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_FORCE_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
|
|
|
|||
Loading…
Reference in New Issue