Add bit/part select release for constants and add an error check.
This patch adds functionality to do a bit or part select release when a constant value is forced to the net/register. It also adds an error message when the user tries to force a signal to a bit/part select. This is not currently handled by the run time, so is now caught in the compiler (tgt-vvp). Where when this functionality is needed, it will be easy to know what to do instead of trying to track down some odd runtime functionality. What this all means is that you can force a signal to an entire signal or you can force a constant to any part of a signal (bit, part or entire) and release any of the above. Technically the release of a constant value does not have to match the force. The runtime verifies that if you are releasing a signal driver it is being done as a full release. I don't see an easy way to check this in the compiler. To fix the signal deficiencies we need to rework the force_link code to allow multiple drivers and partial unlinking. Much of this is in the runtime, but the %force/link operator may also need to be changed like I did to the %release opcode.
This commit is contained in:
parent
cc28a9a734
commit
234648231b
|
|
@ -1467,7 +1467,7 @@ static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
|||
|
||||
if ((!number_is_unknown(exp)) && number_is_immediate(exp, 16)) {
|
||||
int val = get_number_immediate(exp);
|
||||
fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid);
|
||||
fprintf(vvp_out, " %%movi %u, %d, %u;\n", res.base, val, wid);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -820,7 +820,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
|||
if (part_off != 0 || use_wid != ivl_signal_width(lsig)) {
|
||||
|
||||
command_name = command_name_x0;
|
||||
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
|
||||
fprintf(vvp_out, " %%ix/load 0, %u;\n", part_off);
|
||||
|
||||
} else {
|
||||
/* Do not support bit or part selects of l-values yet. */
|
||||
|
|
@ -831,7 +831,7 @@ static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
|||
assert((roff + use_wid) <= rvec.wid);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name,
|
||||
fprintf(vvp_out, " %s v%p_%lu, %u, %u;\n", command_name,
|
||||
lsig, use_word, rvec.base+roff, use_wid);
|
||||
|
||||
if (rvec.base >= 4)
|
||||
|
|
@ -870,6 +870,17 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|||
lval = ivl_stmt_lval(net, 0);
|
||||
lsig = ivl_lval_sig(lval);
|
||||
|
||||
/* We do not currently support driving a signal to a bit or
|
||||
* part select (this could give us multiple drivers). */
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
if (ivl_signal_width(lsig) > ivl_signal_width(rsig) ||
|
||||
(part_off_ex && get_number_immediate(part_off_ex) != 0)) {
|
||||
fprintf(stderr, "%s:%u: vvp-tgt sorry: cannot %s signal to "
|
||||
"a bit/part select.\n", ivl_expr_file(rval),
|
||||
ivl_expr_lineno(rval), command_name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* At least for now, only handle force to fixed words of an array. */
|
||||
if ((lword_idx = ivl_lval_idx(lval)) != 0) {
|
||||
assert(number_is_immediate(lword_idx, 8*sizeof(unsigned long)));
|
||||
|
|
@ -884,7 +895,7 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|||
assert(ivl_signal_array_count(rsig) == 1);
|
||||
use_rword = 0;
|
||||
|
||||
fprintf(vvp_out, " %s/link", command_name);
|
||||
fprintf(vvp_out, " %s/link", command_name);
|
||||
fprintf(vvp_out, " v%p_%lu", lsig, use_lword);
|
||||
fprintf(vvp_out, ", v%p_%lu;\n", rsig, use_rword);
|
||||
}
|
||||
|
|
@ -1172,11 +1183,13 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
unsigned long use_word = 0;
|
||||
assert(lsig != 0);
|
||||
assert(ivl_lval_mux(lval) == 0);
|
||||
if (ivl_lval_part_off(lval) != 0) {
|
||||
fprintf(stderr, "%s:%u: sorry (vvp-tgt): Release of part/"
|
||||
"bit select is not supported.\n",
|
||||
ivl_stmt_file(net), ivl_stmt_lineno(net));
|
||||
exit(1);
|
||||
|
||||
unsigned use_wid = ivl_lval_width(lval);
|
||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
||||
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);
|
||||
}
|
||||
|
||||
switch (ivl_signal_type(lsig)) {
|
||||
|
|
@ -1195,8 +1208,8 @@ static int show_stmt_release(ivl_statement_t net)
|
|||
|
||||
/* Generate the appropriate release statement for this
|
||||
l-value. */
|
||||
fprintf(vvp_out, " %%release/%s v%p_%lu;\n",
|
||||
opcode, lsig, use_word);
|
||||
fprintf(vvp_out, " %%release/%s v%p_%lu, %u, %u;\n",
|
||||
opcode, lsig, use_word, part_off, use_wid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -1584,4 +1597,3 @@ int draw_func_definition(ivl_scope_t scope)
|
|||
thread_count += 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%release/net",of_RELEASE_NET,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
||||
{ "%release/reg",of_RELEASE_REG,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
||||
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/mv", of_SET_MV, 3, {OA_MEM_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
|
|
|
|||
|
|
@ -586,8 +586,8 @@ This opcode raises <bit-l> (real) to the power of <bit-r> (real). The
|
|||
result replaces the left operand.
|
||||
|
||||
|
||||
* %release/net <functor-label>
|
||||
* %release/reg <functor-label>
|
||||
* %release/net <functor-label>, <base>, <width>
|
||||
* %release/reg <functor-label>, <base>, <width>
|
||||
|
||||
Release the force on the signal that is represented by the functor
|
||||
<functor-label>. The force was previously activated with a %force/v
|
||||
|
|
@ -598,6 +598,10 @@ output of the signal after the release is complete. The %release/reg
|
|||
sends the release command with reg semantics: the signal holds its
|
||||
forced value until another value propagates through.
|
||||
|
||||
The <base> and <width> are used to determine what part of the signal
|
||||
will be released. For a full release the <base> is 0 and <width> is
|
||||
the entire signal width.
|
||||
|
||||
* %set/v <var-label>, <bit>, <wid>
|
||||
|
||||
This sets a vector to a variable, and is used to implement blocking
|
||||
|
|
|
|||
|
|
@ -3238,17 +3238,34 @@ bool of_POW_WR(vthread_t thr, vvp_code_t cp)
|
|||
bool of_RELEASE_NET(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_base*sig = reinterpret_cast<vvp_fun_signal_base*>(net->fun);
|
||||
vvp_fun_signal_vec*sig = reinterpret_cast<vvp_fun_signal_vec*>(net->fun);
|
||||
assert(sig);
|
||||
|
||||
/* XXXX Release for %force/link not yet implemented. */
|
||||
if (sig->force_link)
|
||||
if (base >= sig->size()) return true;
|
||||
if (base+width > sig->size()) width = sig->size() - base;
|
||||
|
||||
bool full_sig = base == 0 && width == sig->size();
|
||||
|
||||
if (sig->force_link) {
|
||||
if (!full_sig) {
|
||||
fprintf(stderr, "Sorry: when a signal is forcing a "
|
||||
"net, I cannot release part of it.\n");
|
||||
exit(1);
|
||||
}
|
||||
unlink_force(net);
|
||||
}
|
||||
assert(sig->force_link == 0);
|
||||
|
||||
/* Do we release all or part of the net? */
|
||||
vvp_net_ptr_t ptr (net, 3);
|
||||
vvp_send_long(ptr, 2);
|
||||
if (full_sig) {
|
||||
vvp_send_long(ptr, 2);
|
||||
} else {
|
||||
vvp_send_long_pv(ptr, 2, base, width);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3257,20 +3274,37 @@ bool of_RELEASE_NET(vthread_t thr, vvp_code_t cp)
|
|||
bool of_RELEASE_REG(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_base*sig = reinterpret_cast<vvp_fun_signal_base*>(net->fun);
|
||||
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();
|
||||
|
||||
// This is the net that is forcing me...
|
||||
if (vvp_net_t*src = sig->force_link) {
|
||||
if (!full_sig) {
|
||||
fprintf(stderr, "Sorry: when a signal is forcing a "
|
||||
"register, I cannot release part of it.\n");
|
||||
exit(1);
|
||||
}
|
||||
// And this is the pointer to be removed.
|
||||
vvp_net_ptr_t dst_ptr (net, 2);
|
||||
unlink_from_driver(src, dst_ptr);
|
||||
}
|
||||
|
||||
// Send a command to this signal to unforce itself.
|
||||
/* Do we release all or part of the net? */
|
||||
vvp_net_ptr_t ptr (net, 3);
|
||||
vvp_send_long(ptr, 3);
|
||||
if (full_sig) {
|
||||
vvp_send_long(ptr, 3);
|
||||
} else {
|
||||
vvp_send_long_pv(ptr, 3, base, width);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,6 +202,19 @@ void vvp_send_long(vvp_net_ptr_t ptr, long val)
|
|||
}
|
||||
}
|
||||
|
||||
void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
|
||||
unsigned base, unsigned wid)
|
||||
{
|
||||
while (struct vvp_net_t*cur = ptr.ptr()) {
|
||||
vvp_net_ptr_t next = cur->port[ptr.port()];
|
||||
|
||||
if (cur->fun)
|
||||
cur->fun->recv_long_pv(ptr, val, base, wid);
|
||||
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
|
||||
void vvp_vector4_t::copy_bits(const vvp_vector4_t&that)
|
||||
{
|
||||
unsigned bits_to_copy = (that.size_ < size_) ? that.size_ : size_;
|
||||
|
|
@ -1603,6 +1616,13 @@ void vvp_net_fun_t::recv_long(vvp_net_ptr_t, long)
|
|||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_net_fun_t::recv_long_pv(vvp_net_ptr_t, long, unsigned, unsigned)
|
||||
{
|
||||
fprintf(stderr, "internal error: %s: recv_long_pv not implemented\n",
|
||||
typeid(*this).name());
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* **** vvp_fun_drive methods **** */
|
||||
|
||||
vvp_fun_drive::vvp_fun_drive(vvp_bit4_t init, unsigned str0, unsigned str1)
|
||||
|
|
@ -1673,6 +1693,37 @@ void vvp_fun_signal_base::recv_long(vvp_net_ptr_t ptr, long bit)
|
|||
}
|
||||
}
|
||||
|
||||
void vvp_fun_signal_base::recv_long_pv(vvp_net_ptr_t ptr, long bit,
|
||||
unsigned base, unsigned wid)
|
||||
{
|
||||
switch (ptr.port()) {
|
||||
case 3: // Command port
|
||||
switch (bit) {
|
||||
case 1: // deassign command
|
||||
fprintf(stderr, "Sorry: cannot deassign a partial signal\n");
|
||||
assert(0);
|
||||
deassign();
|
||||
break;
|
||||
case 2: // release/net
|
||||
release_pv(ptr, true, base, wid);
|
||||
break;
|
||||
case 3: // release/reg
|
||||
release_pv(ptr, false, base, wid);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported command %ld.\n", bit);
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Other ports are errors.
|
||||
fprintf(stderr, "Unsupported port type %d.\n", ptr.port());
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vvp_fun_signal::vvp_fun_signal(unsigned wid, vvp_bit4_t init)
|
||||
: bits4_(wid, init)
|
||||
{
|
||||
|
|
@ -1810,6 +1861,19 @@ void vvp_fun_signal::release(vvp_net_ptr_t ptr, bool net)
|
|||
}
|
||||
}
|
||||
|
||||
void vvp_fun_signal::release_pv(vvp_net_ptr_t ptr, bool net,
|
||||
unsigned base, unsigned wid)
|
||||
{
|
||||
assert(bits4_.size() >= base + wid);
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
force_mask_.set_bit(base+idx, 0);
|
||||
if (!net) bits4_.set_bit(base+idx, force_.value(base+idx));
|
||||
}
|
||||
|
||||
if (net) calculate_output_(ptr);
|
||||
}
|
||||
|
||||
unsigned vvp_fun_signal::size() const
|
||||
{
|
||||
if (force_mask_.size())
|
||||
|
|
@ -1930,6 +1994,19 @@ void vvp_fun_signal8::release(vvp_net_ptr_t ptr, bool net)
|
|||
}
|
||||
}
|
||||
|
||||
void vvp_fun_signal8::release_pv(vvp_net_ptr_t ptr, bool net,
|
||||
unsigned base, unsigned wid)
|
||||
{
|
||||
assert(bits8_.size() >= base + wid);
|
||||
|
||||
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
||||
force_mask_.set_bit(base+idx, 0);
|
||||
if (!net) bits8_.set_bit(base+idx, force_.value(base+idx));
|
||||
}
|
||||
|
||||
if (net) calculate_output_(ptr);
|
||||
}
|
||||
|
||||
unsigned vvp_fun_signal8::size() const
|
||||
{
|
||||
if (force_mask_.size())
|
||||
|
|
@ -2031,6 +2108,13 @@ void vvp_fun_signal_real::release(vvp_net_ptr_t ptr, bool net)
|
|||
}
|
||||
}
|
||||
|
||||
void vvp_fun_signal_real::release_pv(vvp_net_ptr_t ptr, bool net,
|
||||
unsigned base, unsigned wid)
|
||||
{
|
||||
fprintf(stderr, "Error: cannot take bit/part select of a real value!\n");
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* **** vvp_wide_fun_* methods **** */
|
||||
|
||||
vvp_wide_fun_core::vvp_wide_fun_core(vvp_net_t*net, unsigned nports)
|
||||
|
|
|
|||
|
|
@ -639,6 +639,8 @@ class vvp_net_fun_t {
|
|||
// Part select variants of above
|
||||
virtual void recv_vec4_pv(vvp_net_ptr_t p, const vvp_vector4_t&bit,
|
||||
unsigned base, unsigned wid, unsigned vwid);
|
||||
virtual void recv_long_pv(vvp_net_ptr_t port, long bit,
|
||||
unsigned base, unsigned wid);
|
||||
|
||||
private: // not implemented
|
||||
vvp_net_fun_t(const vvp_net_fun_t&);
|
||||
|
|
@ -816,6 +818,8 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
|
|||
public:
|
||||
vvp_fun_signal_base();
|
||||
void recv_long(vvp_net_ptr_t port, long bit);
|
||||
void recv_long_pv(vvp_net_ptr_t port, long bit,
|
||||
unsigned base, unsigned wid);
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -834,6 +838,8 @@ class vvp_fun_signal_base : public vvp_net_fun_t, public vvp_vpi_callback {
|
|||
|
||||
void deassign();
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -870,6 +876,8 @@ class vvp_fun_signal : public vvp_fun_signal_vec {
|
|||
|
||||
// Commands
|
||||
void release(vvp_net_ptr_t port, bool net);
|
||||
void release_pv(vvp_net_ptr_t port, bool net,
|
||||
unsigned base, unsigned wid);
|
||||
|
||||
void get_value(struct t_vpi_value*value);
|
||||
|
||||
|
|
@ -900,6 +908,8 @@ class vvp_fun_signal8 : public vvp_fun_signal_vec {
|
|||
|
||||
// Commands
|
||||
void release(vvp_net_ptr_t port, bool net);
|
||||
void release_pv(vvp_net_ptr_t port, bool net,
|
||||
unsigned base, unsigned wid);
|
||||
|
||||
void get_value(struct t_vpi_value*value);
|
||||
|
||||
|
|
@ -923,6 +933,8 @@ class vvp_fun_signal_real : public vvp_fun_signal_base {
|
|||
|
||||
// Commands
|
||||
void release(vvp_net_ptr_t port, bool net);
|
||||
void release_pv(vvp_net_ptr_t port, bool net,
|
||||
unsigned base, unsigned wid);
|
||||
|
||||
void get_value(struct t_vpi_value*value);
|
||||
|
||||
|
|
@ -1024,6 +1036,8 @@ inline void vvp_send_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&val)
|
|||
extern void vvp_send_vec8(vvp_net_ptr_t ptr, vvp_vector8_t val);
|
||||
extern void vvp_send_real(vvp_net_ptr_t ptr, double val);
|
||||
extern void vvp_send_long(vvp_net_ptr_t ptr, long val);
|
||||
extern void vvp_send_long_pv(vvp_net_ptr_t ptr, long val,
|
||||
unsigned base, unsigned width);
|
||||
|
||||
/*
|
||||
* Part-vector versions of above functions. This function uses the
|
||||
|
|
|
|||
Loading…
Reference in New Issue