Add assign/deassign to bit/part selects and other fixes

This patch adds the ability to assign/deassign a bit or part select.
It also cleans up the code and fixes some problem in the forcing of
strength aware nets.
This commit is contained in:
Cary R 2008-04-09 18:56:42 -07:00 committed by Stephen Williams
parent 321114e4db
commit 9bb8e8146f
7 changed files with 226 additions and 57 deletions

View File

@ -802,7 +802,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
switch (ivl_statement_type(net)) {
case IVL_ST_CASSIGN:
command_name = "%cassign/v";
command_name_x0 = "ERROR";
command_name_x0 = "%cassign/x0";
break;
case IVL_ST_FORCE:
command_name = "%force/v";
@ -842,12 +842,6 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
if (part_off != 0 || use_wid != ivl_signal_width(lsig)) {
if (ivl_statement_type(net) == IVL_ST_CASSIGN) {
fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot assign "
"signal to a bit/part select.\n",
ivl_stmt_file(net), ivl_stmt_lineno(net));
exit(1);
}
command_name = command_name_x0;
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
@ -967,15 +961,12 @@ static int show_stmt_deassign(ivl_statement_t net)
assert(lsig != 0);
assert(ivl_lval_mux(lval) == 0);
/* We do not currently support deassigning a bit or
* part select. */
unsigned use_wid = ivl_lval_width(lval);
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
if (ivl_signal_width(lsig) > ivl_lval_width(lval) ||
(part_off_ex && get_number_immediate(part_off_ex) != 0)) {
fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot deassign "
"a bit/part select.\n", ivl_stmt_file(net),
ivl_stmt_lineno(net));
exit(1);
unsigned part_off = 0;
if (part_off_ex != 0) {
assert(number_is_immediate(part_off_ex, 64));
part_off = get_number_immediate(part_off_ex);
}
if (word_idx != 0) {
@ -984,7 +975,8 @@ static int show_stmt_deassign(ivl_statement_t net)
}
fprintf(vvp_out, " %%deassign v%p_%lu;\n", lsig, use_word);
fprintf(vvp_out, " %%deassign v%p_%lu, %u, %u;\n",
lsig, use_word, part_off, use_wid);
}
return 0;

View File

@ -52,6 +52,7 @@ extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code);
extern bool of_BREAKPOINT(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code);
extern bool of_CASSIGN_X0(vthread_t thr, vvp_code_t code);
extern bool of_CMPIS(vthread_t thr, vvp_code_t code);
extern bool of_CMPIU(vthread_t thr, vvp_code_t code);
extern bool of_CMPS(vthread_t thr, vvp_code_t code);

View File

@ -101,6 +101,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%breakpoint", of_BREAKPOINT, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cassign/link",of_CASSIGN_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
{ "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
@ -113,7 +114,7 @@ const static struct opcode_table_s opcode_table[] = {
{ "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/vr", of_CVT_VR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%deassign",of_DEASSIGN,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%deassign",of_DEASSIGN,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%delay", of_DELAY, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },

View File

@ -168,6 +168,13 @@ variable. This is similar to %set, but it uses the cassign port
signal responds differently. See "VARIABLE STATEMENTS" in the
README.txt file.
* %cassign/x0 <label>, <bit>, <wid>
Perform continuous assign of a constant value to part of the target
variable. This is similar to %set/x instruction, but it uses the
cassign port (port-1) of the signal functor instead of the normal
assign port (port-0), so the signal responds differently. See
"VARIABLE STATEMENTS" and "NET STATEMENTS" in the README.txt file.
* %cmp/u <bit-l>, <bit-r>, <wid>
* %cmp/s <bit-l>, <bit-r>, <wid>
@ -239,11 +246,15 @@ The %cvt/vr opcode converts a real word <bit-r> to a thread vector
starting at <bit-l> and with the width <wid>. Non-integer precision is
lost in the conversion.
* %deassign <var-label>
* %deassign <var-label>, <base>, <width>
Deactivate and disconnect a procedural continuous assignment to a
variable. The <var-label> identifies the affected variable.
The <base> and <width> are used to determine what part of the signal
will be deactivated. For a full deactivation the <base> is 0 and
<width> is the entire signal width.
* %delay <delay>
This opcode pauses the thread, and causes it to be rescheduled for a
@ -291,8 +302,8 @@ in the README.txt file.
* %force/x0 <label>, <bit>, <wid>
Force a constant value to part target variable. This is similar to
%set/x instruction, but it uses the force port (port-2) of the signal
Force a constant value to part of the target variable. This is similar
to %set/x instruction, but it uses the force port (port-2) of the signal
functor instead of the normal assign port (port-0), so the signal
responds differently. See "VARIABLE STATEMENTS" and "NET STATEMENTS"
in the README.txt file.

View File

@ -845,6 +845,40 @@ bool of_CASSIGN_V(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
unsigned base = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
// Implicitly, we get the base into the target vector from the
// X0 register.
long index = thr->words[0].w_int;
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*> (net->fun);
if (index < 0 && (wid <= (unsigned)-index))
return true;
if (index >= (long)sig->size())
return true;
if (index < 0) {
wid -= (unsigned) -index;
index = 0;
}
if (index+wid > sig->size())
wid = sig->size() - index;
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vvp_net_ptr_t ptr (net, 1);
vvp_send_vec4_pv(ptr, vector, index, wid, sig->size());
return true;
}
bool of_CMPS(vthread_t thr, vvp_code_t cp)
{
vvp_bit4_t eq = BIT4_1;
@ -1185,9 +1219,24 @@ bool of_CVT_VR(vthread_t thr, vvp_code_t cp)
bool of_DEASSIGN(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
unsigned base = cp->bit_idx[0];
unsigned width = cp->bit_idx[1];
vvp_fun_signal_vec*sig = reinterpret_cast<vvp_fun_signal_vec*>(net->fun);
assert(sig);
if (base >= sig->size()) return true;
if (base+width > sig->size()) width = sig->size() - base;
bool full_sig = base == 0 && width == sig->size();
/* Do we release all or part of the net? */
vvp_net_ptr_t ptr (net, 3);
vvp_send_long(ptr, 1);
if (full_sig) {
vvp_send_long(ptr, 1);
} else {
vvp_send_long_pv(ptr, 1, base, width);
}
return true;
}
@ -1777,7 +1826,7 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
/* Collect the thread bits into a vector4 item. */
vvp_vector4_t value = vthread_bits_to_vector(thr, base, wid);
/* set the value into port 1 of the destination. */
/* Set the value into port 2 of the destination. */
vvp_net_ptr_t ptr (net, 2);
vvp_send_vec4(ptr, value);
@ -1787,7 +1836,7 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
bool of_FORCE_X0(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
unsigned bit = cp->bit_idx[0];
unsigned base = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
// Implicitly, we get the base into the target vector from the
@ -1810,19 +1859,14 @@ bool of_FORCE_X0(vthread_t thr, vvp_code_t cp)
if (index+wid > sig->size())
wid = sig->size() - index;
vvp_vector4_t bit_vec(wid);
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t bit_val = thr_get_bit(thr, bit);
bit_vec.set_bit(idx, bit_val);
if (bit >= 4)
bit += 1;
}
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vvp_net_ptr_t ptr (net, 2);
vvp_send_vec4_pv(ptr, bit_vec, index, wid, sig->size());
vvp_send_vec4_pv(ptr, vector, index, wid, sig->size());
return true;
}
/*
* The %fork instruction causes a new child to be created and pushed
* in front of any existing child. This causes the new child to be the

View File

@ -1133,6 +1133,18 @@ bool vvp_vector2_t::is_NaN() const
return wid_ == 0;
}
bool vvp_vector2_t::is_zero() const
{
const unsigned words = (wid_ + BITS_PER_WORD-1) / BITS_PER_WORD;
for (unsigned idx = 0; idx < words; idx += 1) {
if (vec_[idx] == 0) continue;
return false;
}
return true;
}
/*
* Basic idea from "Introduction to Programming using SML" by
* Michael R. Hansen and Hans Rischel page 261 and "Seminumerical
@ -1659,6 +1671,18 @@ vvp_fun_signal_base::vvp_fun_signal_base()
void vvp_fun_signal_base::deassign()
{
continuous_assign_active_ = false;
assign_mask_ = vvp_vector2_t();
}
void vvp_fun_signal_base::deassign_pv(unsigned base, unsigned wid)
{
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
assign_mask_.set_bit(base+idx, 0);
}
if (assign_mask_.is_zero()) {
assign_mask_ = vvp_vector2_t();
}
}
/*
@ -1700,9 +1724,7 @@ void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit,
case 3: // Command port
switch (bit) {
case 1: // deassign command
fprintf(stderr, "Sorry: cannot deassign a partial signal\n");
assert(0);
deassign();
deassign_pv(base, wid);
break;
case 2: // release/net
release_pv(ptr, true, base, wid);
@ -1745,22 +1767,34 @@ void vvp_fun_signal::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{
switch (ptr.port()) {
case 0: // Normal input (feed from net, or set from process)
/* If continuous assign is active, then this is a var
and the continuous assigned values overrides any
normal input. So process input only if continuous
assignment is not active. */
if (!continuous_assign_active_) {
/* If we don't have a continuous assign mask then just
copy the bits, otherwise we need to see if there are
any holes in the mask so we can set those bits. */
if (assign_mask_.size() == 0) {
if (needs_init_ || !bits4_.eeq(bit)) {
bits4_ = bit;
needs_init_ = false;
calculate_output_(ptr);
}
} else {
bool changed = false;
assert(bits4_.size() == assign_mask_.size());
for (unsigned idx = 0 ; idx < bit.size() ; idx += 1) {
if (idx >= bits4_.size()) break;
if (assign_mask_.value(idx)) continue;
bits4_.set_bit(idx, bit.value(idx));
changed = true;
}
if (changed) {
needs_init_ = false;
calculate_output_(ptr);
}
}
break;
case 1: // Continuous assign value
continuous_assign_active_ = true;
bits4_ = bit;
assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL1, size());
calculate_output_(ptr);
break;
@ -1792,17 +1826,41 @@ void vvp_fun_signal::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
switch (ptr.port()) {
case 0: // Normal input
if (! continuous_assign_active_) {
if (assign_mask_.size() == 0) {
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size())
break;
if (base+idx >= bits4_.size()) break;
bits4_.set_bit(base+idx, bit.value(idx));
}
needs_init_ = false;
calculate_output_(ptr);
} else {
bool changed = false;
assert(bits4_.size() == assign_mask_.size());
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size()) break;
if (assign_mask_.value(base+idx)) continue;
bits4_.set_bit(base+idx, bit.value(idx));
changed = true;
}
if (changed) {
needs_init_ = false;
calculate_output_(ptr);
}
}
break;
case 1: // Continuous assign value
if (assign_mask_.size() == 0)
assign_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size());
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits4_.size())
break;
bits4_.set_bit(base+idx, bit.value(idx));
assign_mask_.set_bit(base+idx, 1);
}
calculate_output_(ptr);
break;
case 2: // Force value
if (force_mask_.size() == 0)
@ -1870,6 +1928,7 @@ void vvp_fun_signal::release_pv(vvp_net_ptr_t ptr, bool net,
force_mask_.set_bit(base+idx, 0);
if (!net) bits4_.set_bit(base+idx, force_.value(base+idx));
}
if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t();
if (net) calculate_output_(ptr);
}
@ -1929,19 +1988,18 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
{
switch (ptr.port()) {
case 0: // Normal input (feed from net, or set from process)
if (!continuous_assign_active_) {
if (needs_init_ || !bits8_.eeq(bit)) {
bits8_ = bit;
needs_init_ = false;
calculate_output_(ptr);
}
if (needs_init_ || !bits8_.eeq(bit)) {
bits8_ = bit;
needs_init_ = false;
calculate_output_(ptr);
}
break;
case 1: // Continuous assign value
continuous_assign_active_ = true;
bits8_ = bit;
calculate_output_(ptr);
/* This is a procedural continuous assign and it can
* only be used on a register and a register is never
* strength aware. */
assert(0);
break;
case 2: // Force value
@ -1964,6 +2022,57 @@ void vvp_fun_signal8::recv_vec8(vvp_net_ptr_t ptr, vvp_vector8_t bit)
}
}
void vvp_fun_signal8::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid)
{
recv_vec8_pv(ptr, bit, base, wid, vwid);
}
void vvp_fun_signal8::recv_vec8_pv(vvp_net_ptr_t ptr, vvp_vector8_t bit,
unsigned base, unsigned wid, unsigned vwid)
{
assert(bit.size() == wid);
assert(bits8_.size() == vwid);
switch (ptr.port()) {
case 0: // Normal input
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
if (base+idx >= bits8_.size()) break;
bits8_.set_bit(base+idx, bit.value(idx));
}
needs_init_ = false;
calculate_output_(ptr);
break;
case 1: // Continuous assign value
/* This is a procedural continuous assign and it can
* only be used on a register and a register is never
* strength aware. */
assert(0);
break;
case 2: // Force value
if (force_mask_.size() == 0)
force_mask_ = vvp_vector2_t(vvp_vector2_t::FILL0, size());
if (force_.size() == 0)
force_ = vvp_vector8_t(vvp_vector4_t(vwid, BIT4_Z));
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
force_mask_.set_bit(base+idx, 1);
force_.set_bit(base+idx, bit.value(idx));
}
calculate_output_(ptr);
break;
default:
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
assert(0);
break;
}
}
void vvp_fun_signal8::calculate_output_(vvp_net_ptr_t ptr)
{
if (force_mask_.size()) {
@ -2003,6 +2112,7 @@ void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net,
force_mask_.set_bit(base+idx, 0);
if (!net) bits8_.set_bit(base+idx, force_.value(base+idx));
}
if (force_mask_.is_zero()) force_mask_ = vvp_vector2_t();
if (net) calculate_output_(ptr);
}
@ -2025,9 +2135,14 @@ vvp_bit4_t vvp_fun_signal8::value(unsigned idx) const
vvp_vector4_t vvp_fun_signal8::vec4_value() const
{
if (force_mask_.size())
return reduce4(force_);
else
if (force_mask_.size()) {
vvp_vector8_t bits (bits8_);
for (unsigned idx = 0 ; idx < bits.size() ; idx += 1) {
if (force_mask_.value(idx))
bits.set_bit(idx, force_.value(idx));
}
return reduce4(bits);
} else
return reduce4(bits8_);
}

View File

@ -306,6 +306,7 @@ class vvp_vector2_t {
vvp_vector2_t&operator = (const vvp_vector2_t&);
bool is_NaN() const;
bool is_zero() const;
unsigned size() const;
int value(unsigned idx) const;
void set_bit(unsigned idx, int bit);
@ -834,8 +835,10 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
bool needs_init_;
bool continuous_assign_active_;
vvp_vector2_t force_mask_;
vvp_vector2_t assign_mask_;
void deassign();
void deassign_pv(unsigned base, unsigned wid);
virtual void release(vvp_net_ptr_t ptr, bool net) =0;
virtual void release_pv(vvp_net_ptr_t ptr, bool net,
unsigned base, unsigned wid) =0;
@ -896,8 +899,10 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec {
void recv_vec8(vvp_net_ptr_t port, vvp_vector8_t bit);
// Part select variants of above
//void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
// unsigned base, unsigned wid, unsigned vwid);
void recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit,
unsigned base, unsigned wid, unsigned vwid);
void recv_vec8_pv(vvp_net_ptr_t port, vvp_vector8_t bit,
unsigned base, unsigned wid, unsigned vwid);
// Get information about the vector value.
unsigned size() const;