Add force/release and assign/deassign for real values.
This patch adds assign/deassign for real variables and force/release for real variables and nets.
This commit is contained in:
parent
23e60aa381
commit
6eb9825ab7
|
|
@ -801,6 +801,37 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void force_real_to_lval(ivl_statement_t net, int res)
|
||||
{
|
||||
const char*command_name;
|
||||
|
||||
switch (ivl_statement_type(net)) {
|
||||
case IVL_ST_CASSIGN:
|
||||
command_name = "%cassign/wr";
|
||||
break;
|
||||
case IVL_ST_FORCE:
|
||||
command_name = "%force/wr";
|
||||
break;
|
||||
default:
|
||||
command_name = "ERROR";
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
ivl_signal_t lsig = ivl_lval_sig(lval);
|
||||
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
/* L-Value must be a signal: reg or wire */
|
||||
assert(lsig != 0);
|
||||
|
||||
fprintf(vvp_out, " %s v%p_0, %d;\n", command_name, lsig, res);
|
||||
|
||||
}
|
||||
|
||||
static void force_vector_to_lval(ivl_statement_t net, struct vector_info rvec)
|
||||
{
|
||||
unsigned lidx;
|
||||
|
|
@ -936,16 +967,28 @@ static void force_link_rval(ivl_statement_t net, ivl_expr_t rval)
|
|||
static int show_stmt_cassign(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval;
|
||||
struct vector_info rvec;
|
||||
ivl_signal_t sig;
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
int res;
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
res = draw_eval_real(ivl_stmt_rval(net));
|
||||
clr_word(res);
|
||||
|
||||
force_real_to_lval(net, res);
|
||||
} else {
|
||||
struct vector_info rvec;
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
}
|
||||
|
||||
force_link_rval(net, rval);
|
||||
|
||||
|
|
@ -959,6 +1002,18 @@ static int show_stmt_cassign(ivl_statement_t net)
|
|||
*/
|
||||
static int show_stmt_deassign(ivl_statement_t net)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
fprintf(vvp_out, " %%deassign/wr v%p_0;\n", sig);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned lidx;
|
||||
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
|
|
@ -1115,16 +1170,28 @@ static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
|
|||
static int show_stmt_force(ivl_statement_t net)
|
||||
{
|
||||
ivl_expr_t rval;
|
||||
struct vector_info rvec;
|
||||
ivl_signal_t sig;
|
||||
|
||||
rval = ivl_stmt_rval(net);
|
||||
assert(rval);
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
int res;
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
res = draw_eval_real(ivl_stmt_rval(net));
|
||||
clr_word(res);
|
||||
|
||||
force_real_to_lval(net, res);
|
||||
} else {
|
||||
struct vector_info rvec;
|
||||
|
||||
rvec = draw_eval_expr(rval, STUFF_OK_47);
|
||||
|
||||
/* Write out initial continuous assign instructions to assign
|
||||
the expression value to the l-value. */
|
||||
force_vector_to_lval(net, rvec);
|
||||
}
|
||||
|
||||
force_link_rval(net, rval);
|
||||
|
||||
|
|
@ -1213,6 +1280,22 @@ static int show_stmt_noop(ivl_statement_t net)
|
|||
|
||||
static int show_stmt_release(ivl_statement_t net)
|
||||
{
|
||||
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
|
||||
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
||||
unsigned type = 0;
|
||||
|
||||
assert(ivl_stmt_lvals(net) == 1);
|
||||
ivl_lval_t lval = ivl_stmt_lval(net, 0);
|
||||
assert(ivl_lval_width(lval) == 1);
|
||||
assert(ivl_lval_part_off(lval) == 0);
|
||||
assert(ivl_lval_idx(lval) == 0);
|
||||
|
||||
if (ivl_signal_type(sig) == IVL_SIT_REG) type = 1;
|
||||
|
||||
fprintf(vvp_out, " %%release/wr v%p_0, %u;\n", sig, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned lidx;
|
||||
|
||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
||||
|
|
|
|||
|
|
@ -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_WR(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);
|
||||
|
|
@ -66,6 +67,7 @@ extern bool of_CVT_IR(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_CVT_RI(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CVT_VR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELAYX(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -75,6 +77,7 @@ extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_END(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORCE_X0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_FORK(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_INV(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -121,6 +124,7 @@ extern bool of_POW(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_MV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -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/wr",of_CASSIGN_WR,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} },
|
||||
{ "%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} },
|
||||
|
|
@ -115,6 +116,7 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%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,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%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} },
|
||||
|
|
@ -123,6 +125,7 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} },
|
||||
{ "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
|
||||
|
|
@ -168,6 +171,7 @@ const static struct opcode_table_s opcode_table[] = {
|
|||
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, 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} },
|
||||
{ "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%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} },
|
||||
|
|
|
|||
|
|
@ -168,6 +168,11 @@ variable. This is similar to %set, but it uses the cassign port
|
|||
signal responds differently. See "VARIABLE STATEMENTS" in the
|
||||
README.txt file.
|
||||
|
||||
* %cassign/wr <var-label>, <bit>
|
||||
|
||||
Perform a continuous assign of a constant real value to the target
|
||||
variable. See %cassign/v above.
|
||||
|
||||
* %cassign/x0 <label>, <bit>, <wid>
|
||||
|
||||
Perform continuous assign of a constant value to part of the target
|
||||
|
|
@ -255,6 +260,10 @@ 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.
|
||||
|
||||
* %deassign/wr <var-label>
|
||||
|
||||
The same as %deassign above except this is used for real variables.
|
||||
|
||||
* %delay <delay>
|
||||
|
||||
This opcode pauses the thread, and causes it to be rescheduled for a
|
||||
|
|
@ -300,6 +309,10 @@ 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.
|
||||
|
||||
* %force/wr <var-label>, <bit>
|
||||
|
||||
Force a constant real value to the target variable. See %force/v above.
|
||||
|
||||
* %force/x0 <label>, <bit>, <wid>
|
||||
|
||||
Force a constant value to part of the target variable. This is similar
|
||||
|
|
@ -619,6 +632,13 @@ 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.
|
||||
|
||||
* %release/wr <functor-label>, <type>
|
||||
|
||||
Release the force on the real signal that is represented by the functor
|
||||
<functor-label>. The force was previously activated with a %force/wr
|
||||
statement. The <type> is 0 for nets and 1 for registers. See the other
|
||||
%release commands above.
|
||||
|
||||
* %set/v <var-label>, <bit>, <wid>
|
||||
|
||||
This sets a vector to a variable, and is used to implement blocking
|
||||
|
|
|
|||
|
|
@ -845,6 +845,18 @@ bool of_CASSIGN_V(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_CASSIGN_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
double value = thr->words[cp->bit_idx[0]].w_real;
|
||||
|
||||
/* Set the value into port 1 of the destination. */
|
||||
vvp_net_ptr_t ptr (net, 1);
|
||||
vvp_send_real(ptr, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
|
|
@ -1241,6 +1253,20 @@ bool of_DEASSIGN(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
|
||||
vvp_fun_signal_real*sig = reinterpret_cast<vvp_fun_signal_real*>(net->fun);
|
||||
assert(sig);
|
||||
|
||||
vvp_net_ptr_t ptr (net, 3);
|
||||
vvp_send_long(ptr, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The delay takes two 32bit numbers to make up a 64bit time.
|
||||
*
|
||||
|
|
@ -1833,6 +1859,19 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_FORCE_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
double value = thr->words[cp->bit_idx[0]].w_real;
|
||||
|
||||
/* Set the value into port 2 of the destination. */
|
||||
vvp_net_ptr_t ptr (net, 2);
|
||||
vvp_send_real(ptr, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool of_FORCE_X0(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
|
|
@ -3380,6 +3419,28 @@ bool of_RELEASE_REG(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* The type is 1 for registers and 0 for everything else. */
|
||||
bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t*net = cp->net;
|
||||
unsigned type = cp->bit_idx[0];
|
||||
|
||||
vvp_fun_signal_real*sig = reinterpret_cast<vvp_fun_signal_real*>(net->fun);
|
||||
assert(sig);
|
||||
|
||||
// This is the net that is forcing me...
|
||||
if (vvp_net_t*src = sig->force_link) {
|
||||
// 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.
|
||||
vvp_net_ptr_t ptr (net, 3);
|
||||
vvp_send_long(ptr, 2 + type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This implements the "%set/av <label>, <bit>, <wid>" instruction. In
|
||||
|
|
|
|||
Loading…
Reference in New Issue