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:
Martin Whitaker 2016-05-10 22:16:40 +01:00
parent 0c66116f51
commit 61c82d2cb0
7 changed files with 156 additions and 22 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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