Rewire real value expressions to use a stack instead of register space.

This will hopefully improve performance slightly, but also this
intended as a model for what to do when I get around to doing the
same thing to other data types.
This commit is contained in:
Stephen Williams 2012-10-22 17:20:43 -07:00
parent 0339f5ed57
commit a5fd5363b3
19 changed files with 711 additions and 700 deletions

View File

@ -46,13 +46,11 @@ static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
{
int res = draw_eval_real(expr);
/* ports cannot be arrays. */
assert(ivl_signal_dimensions(port) == 0);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
clr_word(res);
draw_eval_real(expr);
fprintf(vvp_out, " %%store/real v%p_0;\n", port);
}
static void function_argument_bool(ivl_signal_t port, ivl_expr_t expr)
@ -160,11 +158,10 @@ struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid)
return res;
}
int draw_ufunc_real(ivl_expr_t expr)
void draw_ufunc_real(ivl_expr_t expr)
{
ivl_scope_t def = ivl_expr_def(expr);
ivl_signal_t retval = ivl_scope_port(def, 0);
int res = 0;
unsigned idx;
/* If this is an automatic function, allocate the local storage. */
@ -188,13 +185,11 @@ int draw_ufunc_real(ivl_expr_t expr)
assert(ivl_signal_dimensions(retval) == 0);
/* Load the result into a word. */
res = allocate_word();
fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, retval);
fprintf(vvp_out, " %%load/real v%p_0;\n", retval);
/* If this is an automatic function, free the local storage. */
if (ivl_scope_is_auto(def)) {
fprintf(vvp_out, " %%free S_%p;\n", def);
}
return res;
}

View File

@ -31,9 +31,12 @@ struct args_info {
char*text;
int vec_flag; /* True if the vec must be released. */
struct vector_info vec;
/* String Stack position if this argument is a calculated string. */
int str_flag;
unsigned str_stack;
/* True if this argument is a calculated string. */
char str_flag;
/* True if this argument is a calculated real. */
char real_flag;
/* Stack position if this argument is a calculated string. */
unsigned stack;
struct args_info *child; /* Arguments can be nested. */
};
@ -284,6 +287,7 @@ static void draw_vpi_taskfunc_args(const char*call_string,
going to need. We'll need this for making stack references,
and also to clean out the stack when done. */
unsigned str_stack_need = 0;
unsigned real_stack_need = 0;
/* Figure out how many expressions are going to be evaluated
for this task call. I won't need to evaluate expressions
@ -392,11 +396,14 @@ static void draw_vpi_taskfunc_args(const char*call_string,
ivl_expr_signed(expr)? "s" : "u");
break;
case IVL_VT_REAL:
args[idx].vec_flag = 1;
args[idx].vec.base = draw_eval_real(expr);
draw_eval_real(expr);
args[idx].vec_flag = 0;
args[idx].vec.base = 0;
args[idx].vec.wid = 0;
snprintf(buffer, sizeof buffer,
"W<%u,r>", args[idx].vec.base);
args[idx].str_flag = 0;
args[idx].real_flag = 1;
args[idx].stack = real_stack_need;
real_stack_need += 1;
break;
case IVL_VT_STRING:
/* Eval the string into the stack, and tell VPI
@ -406,7 +413,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
args[idx].vec.base = 0;
args[idx].vec.wid = 0;
args[idx].str_flag = 1;
args[idx].str_stack = str_stack_need;
args[idx].stack = str_stack_need;
args[idx].real_flag = 0;
str_stack_need += 1;
buffer[0] = 0;
break;
@ -425,8 +433,11 @@ static void draw_vpi_taskfunc_args(const char*call_string,
/* If this is a string stack reference, then
calculate the stack depth and use that to
generate the completed string. */
unsigned pos = str_stack_need - args[idx].str_stack - 1;
unsigned pos = str_stack_need - args[idx].stack - 1;
fprintf(vvp_out, ", S<%u,str>",pos);
} else if (args[idx].real_flag) {
unsigned pos = real_stack_need - args[idx].stack - 1;
fprintf(vvp_out, ", W<%u,r>",pos);
} else {
fprintf(vvp_out, ", %s", args[idx].text);
}
@ -450,10 +461,8 @@ static void draw_vpi_taskfunc_args(const char*call_string,
free(args);
fprintf(vvp_out, " {%u %u}", real_stack_need, str_stack_need);
fprintf(vvp_out, ";\n");
if (str_stack_need > 0)
fprintf(vvp_out, " %%pop/str %u;\n", str_stack_need);
}
void draw_vpi_task_call(ivl_statement_t tnet)
@ -474,7 +483,7 @@ void draw_vpi_task_call(ivl_statement_t tnet)
}
if (parm_count == 0) {
fprintf(vvp_out, " %s %u %u \"%s\";\n", command,
fprintf(vvp_out, " %s %u %u \"%s\" {0 0};\n", command,
ivl_file_table_index(ivl_stmt_file(tnet)),
ivl_stmt_lineno(tnet), ivl_stmt_name(tnet));
} else {
@ -509,16 +518,13 @@ struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
return res;
}
int draw_vpi_rfunc_call(ivl_expr_t fnet)
void draw_vpi_rfunc_call(ivl_expr_t fnet)
{
char call_string[1024];
int res = allocate_word();
sprintf(call_string, " %%vpi_func/r %u %u \"%s\", %d",
sprintf(call_string, " %%vpi_func/r %u %u \"%s\"",
ivl_file_table_index(ivl_expr_file(fnet)),
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res);
ivl_expr_lineno(fnet), ivl_expr_name(fnet));
draw_vpi_taskfunc_args(call_string, 0, fnet);
return res;
}

View File

@ -277,8 +277,6 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
*/
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
{
int word;
switch (ivl_expr_value(expr)) {
case IVL_VT_BOOL:
@ -287,9 +285,8 @@ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
break;
case IVL_VT_REAL:
word = draw_eval_real(expr);
fprintf(vvp_out, " %%cvt/sr %u, %d;\n", ix, word);
clr_word(word);
draw_eval_real(expr);
fprintf(vvp_out, " %%cvt/sr %u;\n", ix);
break;
default:
@ -428,19 +425,15 @@ static struct vector_info draw_eq_immediate(ivl_expr_t expr, unsigned ewid,
static struct vector_info draw_binary_expr_eq_real(ivl_expr_t expr)
{
struct vector_info res;
int lword, rword;
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
lword = draw_eval_real(ivl_expr_oper1(expr));
rword = draw_eval_real(ivl_expr_oper2(expr));
draw_eval_real(ivl_expr_oper1(expr));
draw_eval_real(ivl_expr_oper2(expr));
clr_word(lword);
clr_word(rword);
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
fprintf(vvp_out, " %%cmp/wr;\n");
switch (ivl_expr_opcode(expr)) {
case 'e':
@ -834,36 +827,39 @@ static struct vector_info draw_binary_expr_le_real(ivl_expr_t expr)
ivl_expr_t le = ivl_expr_oper1(expr);
ivl_expr_t re = ivl_expr_oper2(expr);
int lword = draw_eval_real(le);
int rword = draw_eval_real(re);
res.base = allocate_vector(1);
res.wid = 1;
assert(res.base);
clr_word(lword);
clr_word(rword);
switch (ivl_expr_opcode(expr)) {
case '<':
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
draw_eval_real(le);
draw_eval_real(re);
fprintf(vvp_out, " %%cmp/wr;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
case 'L': /* <= */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
draw_eval_real(le);
draw_eval_real(re);
fprintf(vvp_out, " %%cmp/wr;\n");
fprintf(vvp_out, " %%or 5, 4, 1;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
case '>':
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword);
draw_eval_real(re);
draw_eval_real(le);
fprintf(vvp_out, " %%cmp/wr;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
case 'G': /* >= */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword);
draw_eval_real(re);
draw_eval_real(le);
fprintf(vvp_out, " %%cmp/wr;\n");
fprintf(vvp_out, " %%or 5, 4, 1;\n");
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
break;
@ -2353,13 +2349,9 @@ static void draw_signal_dest(ivl_expr_t expr, struct vector_info res,
if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
int tmp;
assert(add_index < 0);
tmp = allocate_word();
fprintf(vvp_out, " %%load/wr %d, v%p_%u;\n", tmp, sig, word);
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, tmp, res.wid);
clr_word(tmp);
fprintf(vvp_out, " %%load/real v%p_%u;\n", sig, word);
fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid);
} else if (add_index >= 0) {
@ -3069,7 +3061,7 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid)
res.base = allocate_vector(wid);
res.wid = wid;
assert(res.base);
fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u;\n",
fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u {0 0};\n",
ivl_file_table_index(ivl_expr_file(expr)),
ivl_expr_lineno(expr), ivl_expr_name(expr),
res.base, res.wid);
@ -3242,7 +3234,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
struct vector_info res;
ivl_expr_t sub = ivl_expr_oper1(expr);
const char *rop = 0;
int word, inv = 0;
int inv = 0;
switch (ivl_expr_opcode(expr)) {
case '&': rop = "and"; break;
@ -3471,11 +3463,10 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
break;
case IVL_VT_REAL:
word = draw_eval_real(sub);
draw_eval_real(sub);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%cvt/vr %d, %d, %u;\n", res.base, word, wid);
clr_word(word);
fprintf(vvp_out, " %%cvt/vr %d, %u;\n", res.base, wid);
break;
default:
@ -3485,12 +3476,10 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
case 'v': /* Cast a real value to an integer. */
assert(ivl_expr_value(sub) == IVL_VT_REAL);
word = draw_eval_real(sub);
draw_eval_real(sub);
res.base = allocate_vector(wid);
res.wid = wid;
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, word,
res.wid);
clr_word(word);
fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid);
break;
case 'r': /* Handled in eval_real.c. */

View File

@ -52,10 +52,8 @@ void clr_word(int res)
word_alloc_mask &= ~ (1U << res);
}
static int draw_binary_real(ivl_expr_t expr)
static void draw_binary_real(ivl_expr_t expr)
{
int l, r = -1;
switch (ivl_expr_opcode(expr)) {
case 'E':
case 'N':
@ -72,93 +70,52 @@ static int draw_binary_real(ivl_expr_t expr)
assert(0);
}
l = draw_eval_real(ivl_expr_oper1(expr));
r = draw_eval_real(ivl_expr_oper2(expr));
draw_eval_real(ivl_expr_oper1(expr));
draw_eval_real(ivl_expr_oper2(expr));
switch (ivl_expr_opcode(expr)) {
case '+':
fprintf(vvp_out, " %%add/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%add/wr;\n");
break;
case '-':
fprintf(vvp_out, " %%sub/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%sub/wr;\n");
break;
case '*':
fprintf(vvp_out, " %%mul/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%mul/wr;\n");
break;
case '/':
fprintf(vvp_out, " %%div/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%div/wr;\n");
break;
case '%':
fprintf(vvp_out, " %%mod/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%mod/wr;\n");
break;
case 'p':
fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%pow/wr;\n");
break;
case 'm': { /* min(l,r) */
unsigned lab_out = local_count++;
unsigned lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 4;\n", thread_count,
lab_out);
/* If l is NaN, the go out and accept r as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 4;\n", thread_count,
lab_r);
/* If l <= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count,
lab_out);
/* At this point we know we want r as the result. */
fprintf(vvp_out, "T_%u.%u %%mov/wr %d, %d;\n", thread_count,
lab_r, l, r);
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
break;
}
case 'm':
fprintf(vvp_out, " %%min/wr;\n");
break;
case 'M': { /* max(l,r) */
unsigned lab_out = local_count++;
unsigned lab_r = local_count++;
/* If r is NaN, the go out and accept l as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", r, r);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 4;\n", thread_count,
lab_out);
/* If l is NaN, the go out and accept r as result. */
fprintf(vvp_out, " %%cmp/wr %d, %d; Is NaN?\n", l, l);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 4;\n", thread_count,
lab_r);
/* if l >= r then go out. */
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r);
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count,
lab_out);
fprintf(vvp_out, "T_%u.%u %%mov/wr %d, %d;\n", thread_count,
lab_r, l, r);
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
break;
}
case 'M':
fprintf(vvp_out, " %%max/wr;\n");
break;
default:
fprintf(stderr, "XXXX draw_binary_real(%c)\n",
ivl_expr_opcode(expr));
assert(0);
}
if (r >= 0) clr_word(r);
return l;
}
static int draw_number_real(ivl_expr_t expr)
static void draw_number_real(ivl_expr_t expr)
{
unsigned int idx;
int res = allocate_word();
const char*bits = ivl_expr_bits(expr);
unsigned wid = ivl_expr_width(expr);
unsigned long mant = 0;
@ -204,14 +161,12 @@ static int draw_number_real(ivl_expr_t expr)
if (negate)
vexp |= 0x4000;
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu (wid=%u)\n",
res, mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
return res;
fprintf(vvp_out, " %%pushi/real %lu, %d; load(num)= %c%lu (wid=%u)\n",
mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
}
static int draw_realnum_real(ivl_expr_t expr)
static void draw_realnum_real(ivl_expr_t expr)
{
int res = allocate_word();
double value = ivl_expr_dvalue(expr);
double fract;
@ -222,18 +177,18 @@ static int draw_realnum_real(ivl_expr_t expr)
/* Handle the special case that the value is +-inf. */
if (isinf(value)) {
if (value > 0)
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=+inf\n",
res, 0x3fff);
fprintf(vvp_out, " %%pushi/real 0, %d; load=+inf\n",
0x3fff);
else
fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=-inf\n",
res, 0x7fff);
return res;
fprintf(vvp_out, " %%pushi/real 0, %d; load=-inf\n",
0x7fff);
return;
}
/* Handle the special case that the value is NaN. */
if (value != value) {
fprintf(vvp_out, " %%loadi/wr %d, 1, %d; load=NaN\n",
res, 0x3fff);
return res;
fprintf(vvp_out, " %%pushi/real 1, %d; load=NaN\n",
0x3fff);
return;
}
if (value < 0) {
@ -251,8 +206,8 @@ static int draw_realnum_real(ivl_expr_t expr)
assert(vexp < 0x2000);
vexp += sign;
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%#g\n",
res, mant, vexp, ivl_expr_dvalue(expr));
fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n",
mant, vexp, ivl_expr_dvalue(expr));
/* Capture the residual bits, if there are any. Note that an
IEEE754 mantissa has 52 bits, 31 of which were accounted
@ -268,59 +223,51 @@ static int draw_realnum_real(ivl_expr_t expr)
vexp += sign;
if (mant != 0) {
int tmp_word = allocate_word();
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%#g\n",
tmp_word, mant, vexp, ivl_expr_dvalue(expr));
fprintf(vvp_out, " %%add/wr %d, %d;\n", res, tmp_word);
clr_word(tmp_word);
fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n",
mant, vexp, ivl_expr_dvalue(expr));
fprintf(vvp_out, " %%add/wr;\n");
}
return res;
}
/*
* The real value of a logic expression is the integer value of the
* expression converted to real.
*/
static int draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
static void draw_real_logic_expr(ivl_expr_t expr, int stuff_ok_flag)
{
int res = allocate_word();
struct vector_info sv = draw_eval_expr(expr, stuff_ok_flag);
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
if (sv.wid > 64) {
fprintf(vvp_out, " %%cvt/rv%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n",
sign_flag, sv.base, sv.wid);
} else {
int res = allocate_word();
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
if (ivl_expr_signed(expr))
fprintf(vvp_out, " %%cvt/rs %d, %d;\n", res, res);
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
else
fprintf(vvp_out, " %%cvt/ru %d, %d;\n", res, res);
fprintf(vvp_out, " %%cvt/ru %d;\n", res);
clr_word(res);
}
clr_vector(sv);
return res;
}
static int draw_sfunc_real(ivl_expr_t expr)
static void draw_sfunc_real(ivl_expr_t expr)
{
int res;
switch (ivl_expr_value(expr)) {
case IVL_VT_REAL:
if (ivl_expr_parms(expr) == 0) {
res = allocate_word();
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\", %d;\n",
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0};\n",
ivl_file_table_index(ivl_expr_file(expr)),
ivl_expr_lineno(expr), ivl_expr_name(expr), res);
ivl_expr_lineno(expr), ivl_expr_name(expr));
} else {
res = draw_vpi_rfunc_call(expr);
draw_vpi_rfunc_call(expr);
}
break;
@ -328,55 +275,53 @@ static int draw_sfunc_real(ivl_expr_t expr)
/* If the value of the sfunc is a vector, then evaluate
it as a vector, then convert the result to a real
(via an index register) for the result. */
res = draw_real_logic_expr(expr, 0);
draw_real_logic_expr(expr, 0);
break;
default:
assert(0);
res = -1;
}
return res;
}
static int draw_signal_real_real(ivl_expr_t expr)
static void draw_signal_real_real(ivl_expr_t expr)
{
ivl_signal_t sig = ivl_expr_signal(expr);
int res = allocate_word();
if (ivl_signal_dimensions(sig) == 0) {
fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig);
return res;
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
return;
}
ivl_expr_t word_ex = ivl_expr_oper1(expr);
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix);
fprintf(vvp_out, " %%load/ar v%p, %d;\n", sig, word_ix);
clr_word(word_ix);
return res;
}
static int draw_signal_real(ivl_expr_t expr)
static void draw_signal_real(ivl_expr_t expr)
{
ivl_signal_t sig = ivl_expr_signal(expr);
switch (ivl_signal_data_type(sig)) {
case IVL_VT_LOGIC:
return draw_real_logic_expr(expr, 0);
draw_real_logic_expr(expr, 0);
return;
case IVL_VT_REAL:
return draw_signal_real_real(expr);
draw_signal_real_real(expr);
return;
default:
fprintf(stderr, "vvp.tgt error: signal_data_type=%d\n",
ivl_signal_data_type(sig));
assert(0);
return -1;
return;
}
}
/* If we have nested ternary operators they are likely tail recursive.
* This code is structured to allow this recursion without overflowing
* the available thread words. */
static int draw_ternary_real(ivl_expr_t expr)
static void draw_ternary_real(ivl_expr_t expr)
{
ivl_expr_t cond = ivl_expr_oper1(expr);
ivl_expr_t true_ex = ivl_expr_oper2(expr);
@ -385,11 +330,8 @@ static int draw_ternary_real(ivl_expr_t expr)
struct vector_info tst;
unsigned lab_true = local_count++;
unsigned lab_move = local_count++;
unsigned lab_out = local_count++;
int tru, fal, res;
/* Evaluate the ternary condition. */
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
if ((tst.base >= 4) && (tst.wid > 1)) {
@ -410,127 +352,59 @@ static int draw_ternary_real(ivl_expr_t expr)
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u;\n",
thread_count, lab_true, tst.base);
/* Evaluate the false expression and copy it to the result word. */
fal = draw_eval_real(false_ex);
res = allocate_word();
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
clr_word(fal);
/* Evaluate the false expression. */
draw_eval_real(false_ex);
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %u; End of false expr.\n",
thread_count, lab_out, tst.base);
/* Evaluate the true expression. */
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_true);
tru = draw_eval_real(true_ex);
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %u; End of true expr.\n",
thread_count, lab_move, tst.base);
/* If the conditional is undefined then blend the real words. */
fprintf(vvp_out, " %%blend/wr %d, %d;\n", res, tru);
draw_eval_real(true_ex);
fprintf(vvp_out, " %%blend/wr;\n");
fprintf(vvp_out, " %%jmp T_%u.%u; End of blend\n",
thread_count, lab_out);
/* If we only need the true result then copy it to the result word. */
fprintf(vvp_out, "T_%u.%u ; Move true result.\n",
thread_count, lab_move);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
clr_word(tru);
/* Evaluate the true expression. */
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_true);
draw_eval_real(true_ex);
/* This is the out label. */
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
clr_vector(tst);
return res;
}
static int increment(ivl_expr_t e, int s, bool pre)
static void increment(ivl_expr_t e, bool pre)
{
ivl_signal_t sig;
int r;
int one;
sig = ivl_expr_signal(e);
r = s;
/* create a temporary word to hold value 1.0 */
one = allocate_word();
fprintf(vvp_out, " %%loadi/wr %d, 1, 0x1000; load 1.0\n", one);
if (!pre) {
/*
* post-increment must return the non-incremented value.
* Therefore, copy the current value in a new word and return
* it.
*/
r = allocate_word();
fprintf(vvp_out, " %%mov/wr %d, %d;\n", r, s);
}
fprintf(vvp_out, " %%add/wr %d, %d;\n", s, one);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", sig, s);
return r;
ivl_signal_t sig = ivl_expr_signal(e);
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
if (!pre) fprintf(vvp_out, " %%dup/real;\n");
fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n");
fprintf(vvp_out, " %%add/wr;\n");
if ( pre) fprintf(vvp_out, " %%dup/real;\n");
fprintf(vvp_out, " %%store/real v%p_0;\n", sig);
}
static inline int pre_increment(ivl_expr_t e, int s)
static void decrement(ivl_expr_t e, bool pre)
{
return increment(e, s, true);
ivl_signal_t sig = ivl_expr_signal(e);
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
if (!pre) fprintf(vvp_out, " %%dup/real;\n");
fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n");
fprintf(vvp_out, " %%sub/wr;\n");
if ( pre) fprintf(vvp_out, " %%dup/real;\n");
fprintf(vvp_out, " %%store/real v%p_0;\n", sig);
}
static inline int post_increment(ivl_expr_t e, int s)
{
return increment(e, s, false);
}
static int decrement(ivl_expr_t e, int s, bool pre)
{
ivl_signal_t sig;
int r;
int one;
sig = ivl_expr_signal(e);
r = s;
/* create a temporary word to hold value 1.0 */
one = allocate_word();
fprintf(vvp_out, " %%loadi/wr %d, 1, 0x1000; load 1.0\n", one);
if (!pre) {
/*
* post-decrement must return the non-incremented value.
* Therefore, copy the current value in a new word and return
* it.
*/
r = allocate_word();
fprintf(vvp_out, " %%mov/wr %d, %d;\n", r, s);
}
fprintf(vvp_out, " %%sub/wr %d, %d;\n", s, one);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", sig, s);
return r;
}
static inline int pre_decrement(ivl_expr_t e, int s)
{
return decrement(e, s, true);
}
static inline int post_decrement(ivl_expr_t e, int s)
{
return decrement(e, s, false);
}
static int draw_unary_real(ivl_expr_t expr)
static void draw_unary_real(ivl_expr_t expr)
{
ivl_expr_t sube;
int sub;
/* If the opcode is a ~ or a ! then the sub expression must not be
* a real expression, so use vector evaluation and then convert
* that result to a real value. */
if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
return draw_real_logic_expr(expr, STUFF_OK_XZ);
draw_real_logic_expr(expr, STUFF_OK_XZ);
return;
}
sube = ivl_expr_oper1(expr);
@ -541,30 +415,28 @@ static int draw_unary_real(ivl_expr_t expr)
assert(ivl_expr_value(sube) != IVL_VT_REAL);
res = draw_eval_expr(sube, 1);
if (ivl_expr_signed(sube)) suffix = "/s";
sub = allocate_word();
fprintf(vvp_out, " %%cvt/rv%s %d, %u, %u;\n", suffix, sub,
res.base, res.wid);
fprintf(vvp_out, " %%cvt/rv%s %u, %u;\n", suffix, res.base, res.wid);
clr_vector(res);
return sub;
return;
}
sub = draw_eval_real(sube);
if (ivl_expr_opcode(expr) == '+')
return sub;
if (ivl_expr_opcode(expr) == '+') {
draw_eval_real(sube);
return;
}
if (ivl_expr_opcode(expr) == '-') {
int res = allocate_word();
fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0\n", res);
fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub);
clr_word(sub);
return res;
fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n");
draw_eval_real(sube);
fprintf(vvp_out, " %%sub/wr;\n");
return;
}
if (ivl_expr_opcode(expr) == 'm') { /* abs() */
fprintf(vvp_out, " %%abs/wr %d, %d;\n", sub, sub);
return sub;
draw_eval_real(sube);
fprintf(vvp_out, " %%abs/wr;\n");
return;
}
if (ivl_expr_opcode(expr) == 'v') { /* Handled in eval_expr.c. */
@ -573,70 +445,71 @@ static int draw_unary_real(ivl_expr_t expr)
assert(0);
}
switch (ivl_expr_opcode(expr)) {
case 'I':
return pre_increment(sube, sub);
switch (ivl_expr_opcode(expr)) {
case 'I':
increment(sube, true);
return;
case 'i':
increment(sube, false);
return;
case 'i':
return post_increment(sube, sub);
case 'D':
return pre_decrement(sube, sub);
case 'd':
return post_decrement(sube, sub);
case 'D':
decrement(sube, true);
return;
case 'd':
decrement(sube, false);
return;
}
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
ivl_expr_opcode(expr));
assert(0);
return 0;
}
int draw_eval_real(ivl_expr_t expr)
void draw_eval_real(ivl_expr_t expr)
{
int res = 0;
/* If this expression/sub-expression is not real then we need
* to evaluate it as a bit value and then convert the bit based
* result to a real value. This is required to get integer
* division to work correctly. */
if (ivl_expr_value(expr) != IVL_VT_REAL) {
return draw_real_logic_expr(expr, STUFF_OK_XZ);
draw_real_logic_expr(expr, STUFF_OK_XZ);
return;
}
switch (ivl_expr_type(expr)) {
case IVL_EX_BINARY:
res = draw_binary_real(expr);
draw_binary_real(expr);
break;
case IVL_EX_NUMBER:
res = draw_number_real(expr);
draw_number_real(expr);
break;
case IVL_EX_REALNUM:
res = draw_realnum_real(expr);
draw_realnum_real(expr);
break;
case IVL_EX_SFUNC:
res = draw_sfunc_real(expr);
draw_sfunc_real(expr);
break;
case IVL_EX_SIGNAL:
res = draw_signal_real(expr);
draw_signal_real(expr);
break;
case IVL_EX_TERNARY:
res = draw_ternary_real(expr);
draw_ternary_real(expr);
break;
case IVL_EX_UFUNC:
res = draw_ufunc_real(expr);
draw_ufunc_real(expr);
break;
case IVL_EX_UNARY:
res = draw_unary_real(expr);
draw_unary_real(expr);
break;
default:
@ -645,22 +518,23 @@ int draw_eval_real(ivl_expr_t expr)
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
clr_vector(sv);
res = allocate_word();
int res = allocate_word();
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
fprintf(vvp_out, " %%cvt/rs %d, %d;\n", res, res);
fprintf(vvp_out, " %%cvt/rs %d;\n", res);
clr_word(res);
} else {
fprintf(stderr, "XXXX Evaluate real expression (%d)\n",
ivl_expr_type(expr));
fprintf(vvp_out, " ; XXXX Evaluate real expression (%d)\n",
ivl_expr_type(expr));
return 0;
return;
}
break;
}
return res;
}

View File

@ -530,7 +530,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
result to a vector. Then store that vector into the
l-value. */
if (ivl_expr_value(rval) == IVL_VT_REAL) {
int word = draw_eval_real(rval);
draw_eval_real(rval);
/* This is the accumulated with of the l-value of the
assignment. */
unsigned wid = ivl_stmt_lwidth(net);
@ -546,10 +546,7 @@ static int show_stmt_assign_vector(ivl_statement_t net)
vvp_errors += 1;
}
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
res.base, word, res.wid);
clr_word(word);
fprintf(vvp_out, " %%cvt/vr %u, %u;\n", res.base, res.wid);
} else {
res = draw_eval_expr(rval, 0);
@ -696,13 +693,12 @@ static int show_stmt_assign_vector(ivl_statement_t net)
*/
static int show_stmt_assign_sig_real(ivl_statement_t net)
{
int res;
ivl_lval_t lval;
ivl_signal_t var;
assert(ivl_stmt_opcode(net) == 0);
res = draw_eval_real(ivl_stmt_rval(net));
draw_eval_real(ivl_stmt_rval(net));
assert(ivl_stmt_lvals(net) == 1);
lval = ivl_stmt_lval(net, 0);
@ -710,8 +706,7 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
assert(var != 0);
if (ivl_signal_dimensions(var) == 0) {
clr_word(res);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res);
fprintf(vvp_out, " %%store/real v%p_0;\n", var);
return 0;
}
@ -723,9 +718,8 @@ static int show_stmt_assign_sig_real(ivl_statement_t net)
int word_ix = allocate_word();
draw_eval_expr_into_integer(word_ex, word_ix);
// Generate an assignment to write to the array.
fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res);
fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix);
clr_word(res);
clr_word(word_ix);
return 0;

View File

@ -100,7 +100,7 @@ extern int draw_scope(ivl_scope_t scope, ivl_scope_t parent);
extern void draw_lpm_mux(ivl_lpm_t net);
extern struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid);
extern int draw_ufunc_real(ivl_expr_t expr);
extern void draw_ufunc_real(ivl_expr_t expr);
extern void pad_expr_in_place(ivl_expr_t expr, struct vector_info res,
unsigned swid);
@ -129,7 +129,7 @@ extern void draw_vpi_task_call(ivl_statement_t net);
extern struct vector_info draw_vpi_func_call(ivl_expr_t expr,
unsigned wid);
extern int draw_vpi_rfunc_call(ivl_expr_t expr);
extern void draw_vpi_rfunc_call(ivl_expr_t expr);
/*
* Enumeration draw routine.
@ -298,11 +298,10 @@ extern long get_number_immediate(ivl_expr_t ex);
extern uint64_t get_number_immediate64(ivl_expr_t ex);
/*
* draw_eval_real evaluates real value expressions. The return code
* from the function is the index of the word register that contains
* the result.
* draw_eval_real evaluates real value expressions. The result of the
* evaluation is the real result in the top of the real expression stack.
*/
extern int draw_eval_real(ivl_expr_t ex);
extern void draw_eval_real(ivl_expr_t ex);
/*
* draw_eval_bool64 evaluates a bool expression. The return code from

View File

@ -39,9 +39,10 @@ unsigned transient_id = 0;
* executable code for the processes.
*/
/* Support a non-blocking assignment to a real array word. */
/* Support a non-blocking assignment to a real array word. The real
value to be written is already in the top of the stack. */
static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
unsigned bit, uint64_t delay,
uint64_t delay,
ivl_expr_t dexp, unsigned nevents)
{
unsigned skip_assign = transient_id++;
@ -62,12 +63,12 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
/* Calculated delay... */
int delay_index = allocate_word();
draw_eval_expr_into_integer(dexp, delay_index);
fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig,
delay_index, bit);
fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig,
delay_index);
clr_word(delay_index);
} else if (nevents != 0) {
/* Event control delay... */
fprintf(vvp_out, " %%assign/ar/e v%p, %u;\n", lsig, bit);
fprintf(vvp_out, " %%assign/ar/e v%p;\n", lsig);
} else {
/* Constant delay... */
unsigned long low_d = delay % UINT64_C(0x100000000);
@ -81,12 +82,12 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out, " %%assign/ar/d v%p, %d, %u;\n", lsig,
delay_index, bit);
fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig,
delay_index);
clr_word(delay_index);
} else {
fprintf(vvp_out, " %%assign/ar v%p, %lu, %u;\n",
lsig, low_d, bit);
fprintf(vvp_out, " %%assign/ar v%p, %lu;\n",
lsig, low_d);
}
}
@ -376,8 +377,6 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
ivl_expr_t del = ivl_stmt_delay_expr(net);
/* variables for the selection of word from an array. */
unsigned long use_word = 0;
/* thread address for a word value. */
int word;
uint64_t delay = 0;
unsigned nevents = ivl_stmt_nevent(net);
@ -395,13 +394,12 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
}
/* Evaluate the r-value */
word = draw_eval_real(rval);
draw_eval_real(rval);
if (ivl_signal_dimensions(sig) > 0) {
ivl_expr_t word_ix = ivl_lval_idx(lval);
assert(word_ix);
assign_to_array_r_word(sig, word_ix, word, delay, del, nevents);
clr_word(word);
assign_to_array_r_word(sig, word_ix, delay, del, nevents);
return 0;
}
@ -410,12 +408,12 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
assert(nevents == 0);
int delay_index = allocate_word();
draw_eval_expr_into_integer(del, delay_index);
fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %d;\n",
sig, use_word, delay_index, word);
fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d;\n",
sig, use_word, delay_index);
clr_word(delay_index);
} else if (nevents) {
fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %d;\n",
sig, use_word, word);
fprintf(vvp_out, " %%assign/wr/e v%p_%lu;\n",
sig, use_word);
} else {
unsigned long low_d = delay % UINT64_C(0x100000000);
unsigned long hig_d = delay / UINT64_C(0x100000000);
@ -428,17 +426,15 @@ static int show_stmt_assign_nb_real(ivl_statement_t net)
int delay_index = allocate_word();
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
delay_index, low_d, hig_d);
fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %d;\n",
sig, use_word, delay_index, word);
fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d;\n",
sig, use_word, delay_index);
clr_word(delay_index);
} else {
fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %d;\n",
sig, use_word, low_d, word);
fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu;\n",
sig, use_word, low_d);
}
}
clr_word(word);
return 0;
}
@ -525,7 +521,7 @@ static int show_stmt_assign_nb(ivl_statement_t net)
value. Evaluate the real expression, then convert the
result to a vector. */
if (ivl_expr_value(rval) == IVL_VT_REAL) {
int word = draw_eval_real(rval);
draw_eval_real(rval);
/* This is the accumulated with of the l-value of the
assignment. */
wid = ivl_stmt_lwidth(net);
@ -541,10 +537,8 @@ static int show_stmt_assign_nb(ivl_statement_t net)
vvp_errors += 1;
}
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n",
res.base, word, res.wid);
clr_word(word);
fprintf(vvp_out, " %%cvt/vr %u, %u;\n",
res.base, res.wid);
} else {
res = draw_eval_expr(rval, 0);
@ -747,7 +741,6 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
ivl_expr_t expr = ivl_stmt_cond_expr(net);
int cond = draw_eval_real(expr);
unsigned count = ivl_stmt_case_count(net);
unsigned local_base = local_count;
@ -756,6 +749,11 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
show_stmt_file_line(net, "Case statement.");
/* Build the reference value into the top of the stack. All
the case comparisons will make duplicates of this value in
order to do their tests. */
draw_eval_real(expr);
local_count += count + 1;
/* First draw the branch table. All the non-default cases
@ -765,26 +763,23 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
for (idx = 0 ; idx < count ; idx += 1) {
ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
int cvec;
if (cex == 0) {
default_case = idx;
continue;
}
cvec = draw_eval_real(cex);
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", cond, cvec);
/* The referene value... */
fprintf(vvp_out, " %%dup/real;\n");
/* The guard value... */
draw_eval_real(cex);
/* The comparison. */
fprintf(vvp_out, " %%cmp/wr;\n");
fprintf(vvp_out, " %%jmp/1 T_%u.%u, 4;\n",
thread_count, local_base+idx);
/* Done with the guard expression value. */
clr_word(cvec);
}
/* Done with the case expression. */
clr_word(cond);
/* Emit code for the case default. The above jump table will
fall through to this statement. */
if (default_case < count) {
@ -812,11 +807,15 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
/* The out of the case. */
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+count);
fprintf(vvp_out, " %%pop/real 1;\n");
return rc;
}
static void force_real_to_lval(ivl_statement_t net, int res)
/*
* The real value is already pushed to the top of the real value stack.
*/
static void force_real_to_lval(ivl_statement_t net)
{
const char*command_name;
ivl_lval_t lval;
@ -845,7 +844,7 @@ static void force_real_to_lval(ivl_statement_t net, int res)
/* 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);
fprintf(vvp_out, " %s v%p_0;\n", command_name, lsig);
}
@ -1049,12 +1048,10 @@ static int show_stmt_cassign(ivl_statement_t net)
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
int res;
res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);
draw_eval_real(ivl_stmt_rval(net));
force_real_to_lval(net);
force_real_to_lval(net, res);
} else {
struct vector_info rvec;
@ -1230,9 +1227,8 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
}
case IVL_VT_REAL: {
int word = draw_eval_real(expr);
fprintf(vvp_out, " %%cvt/ur 0, %d;\n", word);
clr_word(word);
draw_eval_real(expr);
fprintf(vvp_out, " %%cvt/ur 0;\n");
break;
}
@ -1272,12 +1268,10 @@ static int show_stmt_force(ivl_statement_t net)
sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
int res;
res = draw_eval_real(ivl_stmt_rval(net));
clr_word(res);
draw_eval_real(ivl_stmt_rval(net));
force_real_to_lval(net);
force_real_to_lval(net, res);
} else {
struct vector_info rvec;

View File

@ -93,6 +93,7 @@ extern bool of_DISABLE(vthread_t thr, vvp_code_t code);
extern bool of_DIV(vthread_t thr, vvp_code_t code);
extern bool of_DIV_S(vthread_t thr, vvp_code_t code);
extern bool of_DIV_WR(vthread_t thr, vvp_code_t code);
extern bool of_DUP_REAL(vthread_t thr, vvp_code_t code);
extern bool of_END(vthread_t thr, vvp_code_t code);
extern bool of_EVCTL(vthread_t thr, vvp_code_t code);
extern bool of_EVCTLC(vthread_t thr, vvp_code_t code);
@ -126,18 +127,18 @@ extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_DAR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VEC(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VP0(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_WR(vthread_t thr, vvp_code_t code);
extern bool of_LOAD_X1P(vthread_t thr, vvp_code_t code);
extern bool of_LOADI_WR(vthread_t thr, vvp_code_t code);
extern bool of_MAX_WR(vthread_t thr, vvp_code_t code);
extern bool of_MIN_WR(vthread_t thr, vvp_code_t code);
extern bool of_MOD(vthread_t thr, vvp_code_t code);
extern bool of_MOD_S(vthread_t thr, vvp_code_t code);
extern bool of_MOD_WR(vthread_t thr, vvp_code_t code);
extern bool of_MOV(vthread_t thr, vvp_code_t code);
extern bool of_MOV_WR(vthread_t thr, vvp_code_t code);
extern bool of_MOV_WU(vthread_t thr, vvp_code_t code);
extern bool of_MOVI(vthread_t thr, vvp_code_t code);
extern bool of_MUL(vthread_t thr, vvp_code_t code);
@ -152,27 +153,29 @@ extern bool of_NORR(vthread_t thr, vvp_code_t code);
extern bool of_OR(vthread_t thr, vvp_code_t code);
extern bool of_ORR(vthread_t thr, vvp_code_t code);
extern bool of_PAD(vthread_t thr, vvp_code_t code);
extern bool of_POP_REAL(vthread_t thr, vvp_code_t code);
extern bool of_POP_STR(vthread_t thr, vvp_code_t code);
extern bool of_POW(vthread_t thr, vvp_code_t code);
extern bool of_POW_S(vthread_t thr, vvp_code_t code);
extern bool of_POW_WR(vthread_t thr, vvp_code_t code);
extern bool of_PUSHI_STR(vthread_t thr, vvp_code_t code);
extern bool of_PUSHI_REAL(vthread_t thr, vvp_code_t code);
extern bool of_PUSHV_STR(vthread_t thr, vvp_code_t code);
extern bool of_PUTC_STR_V(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_AR(vthread_t thr, vvp_code_t code);
extern bool of_SET_AV(vthread_t thr, vvp_code_t code);
extern bool of_SET_DAR(vthread_t thr, vvp_code_t code);
extern bool of_SET_VEC(vthread_t thr, vvp_code_t code);
extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0(vthread_t thr, vvp_code_t code);
extern bool of_SET_X0_X(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTL_I0(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTR_I0(vthread_t thr, vvp_code_t code);
extern bool of_SHIFTR_S_I0(vthread_t thr, vvp_code_t code);
extern bool of_STORE_OBJ(vthread_t thr, vvp_code_t code);
extern bool of_STORE_REAL(vthread_t thr, vvp_code_t code);
extern bool of_STORE_REALA(vthread_t thr, vvp_code_t code);
extern bool of_STORE_STR(vthread_t thr, vvp_code_t code);
extern bool of_SUB(vthread_t thr, vvp_code_t code);
extern bool of_SUB_WR(vthread_t thr, vvp_code_t code);

View File

@ -84,17 +84,17 @@ struct opcode_table_s {
};
static const struct opcode_table_s opcode_table[] = {
{ "%abs/wr", of_ABS_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%abs/wr", of_ABS_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%add", of_ADD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%add/wr", of_ADD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%add/wr", of_ADD_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%addi", of_ADDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%alloc", of_ALLOC, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%and", of_AND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%and/r", of_ANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%andi", of_ANDI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%assign/ar",of_ASSIGN_AR,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/ar/d",of_ASSIGN_ARD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/ar/e",of_ASSIGN_ARE,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
{ "%assign/ar",of_ASSIGN_AR,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
{ "%assign/ar/d",of_ASSIGN_ARD,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
{ "%assign/ar/e",of_ASSIGN_ARE,1,{OA_ARR_PTR,OA_NONE, OA_NONE} },
{ "%assign/av",of_ASSIGN_AV,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/av/d",of_ASSIGN_AVD,3,{OA_ARR_PTR,OA_BIT1, OA_BIT2} },
{ "%assign/av/e",of_ASSIGN_AVE,2,{OA_ARR_PTR,OA_BIT1, OA_NONE} },
@ -104,22 +104,22 @@ static const struct opcode_table_s opcode_table[] = {
{ "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
{ "%assign/v0/x1/e",of_ASSIGN_V0X1E,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
{ "%assign/wr", of_ASSIGN_WR, 3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} },
{ "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} },
{ "%assign/wr/e",of_ASSIGN_WRE,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
{ "%assign/wr", of_ASSIGN_WR, 2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
{ "%assign/wr/d",of_ASSIGN_WRD,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} },
{ "%assign/wr/e",of_ASSIGN_WRE,1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%blend/wr", of_BLEND_WR,2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%blend/wr", of_BLEND_WR,0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%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/wr",of_CASSIGN_WR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%cast2", of_CAST2, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/str",of_CMPSTR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/wr", of_CMPWR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%cmp/ws", of_CMPWS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/wu", of_CMPWU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cmp/x", of_CMPX, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -128,13 +128,13 @@ static const struct opcode_table_s opcode_table[] = {
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%concat/str",of_CONCAT_STR,0,{OA_NONE, OA_NONE, OA_NONE} },
{ "%concati/str",of_CONCATI_STR,1,{OA_STRING,OA_NONE, OA_NONE} },
{ "%cvt/rs", of_CVT_RS, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ru", of_CVT_RU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/rv", of_CVT_RV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cvt/rv/s", of_CVT_RV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cvt/sr", of_CVT_SR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ur", of_CVT_UR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/vr", of_CVT_VR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cvt/rs", of_CVT_RS, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%cvt/ru", of_CVT_RU, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%cvt/rv", of_CVT_RV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/rv/s", of_CVT_RV_S,2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/sr", of_CVT_SR, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%cvt/ur", of_CVT_UR, 1, {OA_BIT1, OA_NONE, OA_NONE} },
{ "%cvt/vr", of_CVT_VR, 2, {OA_BIT1, OA_NUMBER, OA_NONE} },
{ "%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} },
@ -142,7 +142,8 @@ static const struct opcode_table_s opcode_table[] = {
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%div", of_DIV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%div/wr", of_DIV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%div/wr", of_DIV_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%dup/real", of_DUP_REAL,0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%evctl", of_EVCTL, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%evctl/c",of_EVCTLC, 0, {OA_NONE, OA_NONE, OA_NONE} },
@ -150,7 +151,7 @@ static const struct opcode_table_s opcode_table[] = {
{ "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, 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/wr",of_FORCE_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%force/x0",of_FORCE_X0,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%free", of_FREE, 1, {OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
@ -168,28 +169,28 @@ static const struct opcode_table_s opcode_table[] = {
{ "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} },
{ "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%join/detach",of_JOIN_DETACH,1,{OA_NUMBER,OA_NONE, OA_NONE} },
{ "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/ar",of_LOAD_AR,2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
{ "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/avx.p",of_LOAD_AVX_P,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} },
{ "%load/dar",of_LOAD_DAR,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/str",of_LOAD_STR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },
{ "%load/real", of_LOAD_REAL,1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%load/v", of_LOAD_VEC,3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/vp0",of_LOAD_VP0,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/vp0/s",of_LOAD_VP0_S,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%load/wr",of_LOAD_WR,2, {OA_BIT1, OA_VPI_PTR, OA_BIT2} },
{ "%load/x1p",of_LOAD_X1P,3,{OA_BIT1, OA_FUNC_PTR, OA_BIT2} },
{ "%loadi/wr",of_LOADI_WR,3,{OA_BIT1, OA_NUMBER, OA_BIT2} },
{ "%max/wr", of_MAX_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%min/wr", of_MIN_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mod/s", of_MOD_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mod/wr", of_MOD_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%mod/wr", of_MOD_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mov/wr", of_MOV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%mov/wu", of_MOV_WU, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%movi", of_MOVI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%mul/wr", of_MUL_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nand", of_NAND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%nand/r", of_NANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
@ -200,29 +201,31 @@ static const struct opcode_table_s opcode_table[] = {
{ "%or", of_OR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%or/r", of_ORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pad", of_PAD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pop/str",of_POP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%pop/real",of_POP_REAL,1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%pop/str", of_POP_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
{ "%pow", of_POW, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/s", of_POW_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%pushi/str",of_PUSHI_STR,1,{OA_STRING, OA_NONE, OA_NONE} },
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%pushi/real",of_PUSHI_REAL,2,{OA_BIT1, OA_BIT2, OA_NONE} },
{ "%pushi/str", of_PUSHI_STR, 1,{OA_STRING, OA_NONE, OA_NONE} },
{ "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} },
{ "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} },
{ "%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/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} },
{ "%set/dar",of_SET_DAR,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} },
{ "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} },
{ "%store/obj",of_STORE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/str",of_STORE_STR,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/obj", of_STORE_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/real", of_STORE_REAL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%store/reala",of_STORE_REALA,2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
{ "%store/str", of_STORE_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
{ "%sub", of_SUB, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%sub/wr", of_SUB_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%sub/wr", of_SUB_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
{ "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%substr/v",of_SUBSTR_V,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
@ -1788,7 +1791,8 @@ void compile_file_line(char*label, long file_idx, long lineno,
void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno,
unsigned argc, vpiHandle*argv)
unsigned argc, vpiHandle*argv,
unsigned real_stack, unsigned string_stack)
{
if (label)
compile_codelabel(label);
@ -1801,7 +1805,8 @@ void compile_vpi_call(char*label, char*name,
store that handle in the instruction. */
code->handle = vpip_build_vpi_call(name, 0, 0, 0,
func_as_task_err, func_as_task_warn,
argc, argv, file_idx, lineno);
argc, argv, real_stack, string_stack,
file_idx, lineno);
if (code->handle == 0)
compile_errors += 1;
@ -1812,7 +1817,9 @@ void compile_vpi_call(char*label, char*name,
void compile_vpi_func_call(char*label, char*name,
unsigned vbit, int vwid,
long file_idx, long lineno,
unsigned argc, vpiHandle*argv)
unsigned argc, vpiHandle*argv,
unsigned real_stack,
unsigned string_stack)
{
if (label)
compile_codelabel(label);
@ -1824,7 +1831,8 @@ void compile_vpi_func_call(char*label, char*name,
/* Create a vpiHandle that bundles the call information, and
store that handle in the instruction. */
code->handle = vpip_build_vpi_call(name, vbit, vwid, 0, true, false,
argc, argv, file_idx, lineno);
argc, argv, real_stack, string_stack,
file_idx, lineno);
if (code->handle == 0)
compile_errors += 1;

View File

@ -413,7 +413,9 @@ extern void compile_file_line(char*label, long file_idx, long lineno,
extern void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno,
unsigned argc, vpiHandle*argv);
unsigned argc, vpiHandle*argv,
unsigned real_stack,
unsigned string_stack);
/* Compile a function call. The vbit and vwid encode the return
type. If the vwid >0, the return type is a vector. If the vwid is
@ -422,7 +424,9 @@ extern void compile_vpi_call(char*label, char*name,
extern void compile_vpi_func_call(char*label, char*name,
unsigned vbit, int vwid,
long file_idx, long lineno,
unsigned argc, vpiHandle*argv);
unsigned argc, vpiHandle*argv,
unsigned real_stack,
unsigned string_stack);
extern void print_vpi_call_errors();
extern void compile_fork(char*label, struct symb_s targ_s,

View File

@ -50,8 +50,8 @@ See also the %sub instruction.
* %add/wr <bit-l>, <bit-r>
This is the real valued version of the %add instruction. The arguments
are word indices of the operands. The right operand is added into the
left operand.
are popped from the stack, right operand then left, and the result
pushed in place
See also the %sub/wr instruction.
@ -78,14 +78,14 @@ means the following:
1 and 1 --> 1
otherwise x
* %assign/ar <array-label>, <delay>, <bit>
* %assign/ar/d <array-label>, <delayx>, <bit>
* %assign/ar/e <array-label>, <bit>
* %assign/ar <array-label>, <delay>
* %assign/ar/d <array-label>, <delayx>
* %assign/ar/e <array-label>
The %assign/ar instruction assigns a real value to a word in the
labeled real array. The <delay> is the delay in simulation time to
the assignment (0 for non-blocking assignment) and <bit> is the
index register that contains the value to write.
the assignment (0 for non-blocking assignment) and the value is popped
from the real value stack.
The memory word address is read from index register 3. The address is
in canonical form.
@ -152,13 +152,13 @@ This is similar to the %assign/v0 instruction, but adds the index-1
index register with the canonical index of the destination where the
vector is to be written. This allows for part writes into the vector.
* %assign/wr <vpi-label>, <delay>, <index>
* %assign/wr/d <vpi-label>, <delayx>, <index>
* %assign/wr/e <vpi-label>, <index>
* %assign/wr <vpi-label>, <delay>
* %assign/wr/d <vpi-label>, <delayx>
* %assign/wr/e <vpi-label>
This instruction provides a non-blocking assign of the real value
given in <index> to the real object addressed by the <vpi-label>
label after the given <delay>.
label after the given <delay>. The real value is popped from the stack.
The %assign/wr/d variation gets the delay from integer register
<delayx>.
@ -194,10 +194,11 @@ manner like the expression (x ? <a> : <b>). The truth table is:
In other words, if the bits are identical, then take that
value. Otherwise, the value is x.
* %blend/wr <bit-l>, <bit-r>
* %blend/wr
This instruction blends real values for the ternary operator. If the
values match return that otherwise return 0.0.
values match return that otherwise return 0.0. Two values are popped
from the stack, one is pushed back.
* %breakpoint
@ -217,10 +218,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>
* %cassign/wr <var-label>
Perform a continuous assign of a constant real value to the target
variable. See %cassign/v above.
variable. See %cassign/v above. The value is popped from the real
value stack.
* %cassign/x0 <label>, <bit>, <wid>
@ -273,9 +275,12 @@ These instructions are similar to the %cmp instructions above, except
that the right hand operand is an immediate value. This is a positive
number that the vector is compared with.
* %cmp/wr <bit-l>, <bit-r>
* %cmp/wr
[compare real values.]
Compare real values for equality and less-then. This opcode pops to
values from the real-value stack and writes the comparison result to
bits 4/5. The expressions (a < b) and (a==b) are calculated, with (b)
poped from the stack first, then (a).
* %cmp/ws <bit-l>, <bit-r>
* %cmp/wu <bit-l>, <bit-r>
@ -313,37 +318,40 @@ of it as possing the tail, then the head, concatenating them, and
pushing the result. The stack starts with two strings in the stack,
and ends with one string in the stack.
* %cvt/sr <bit-l>, <bit-r>
* %cvt/rs <bit-l>, <bit-r>
* %cvt/sr <bit-l>
* %cvt/rs <bit-l>
Copy a word from r to l, converting it from real to signed integer (sr)
or signed integer to real (rs) in the process. The source and destination
may be the same word address, leading to a convert in place. Precision
may be lost in the conversion.
* %cvt/ur <bit-l>, <bit-r>
* %cvt/ru <bit-l>, <bit-r>
The %cvt/sr <bit-l> gets the real value from the top of the real value
stack (and pops the value) and writes it to the indexed register.
* %cvt/ur <bit-l>
* %cvt/ru <bit-r>
Copy a word from r to l, converting it from real to unsigned integer (ur)
or signed integer to real (ru) in the process. The source and destination
may be the same word address, leading to a convert in place. Precision
may be lost in the conversion.
* %cvt/rv <bit-l>, <bit-r>, <wid>
* %cvt/rv/s <bit-l>, <bit-r>, <wid>
* %cvt/rv <bit-r>, <wid>
* %cvt/rv/s <bit-r>, <wid>
The %cvt/rv instruction converts a thread vector starting at <bit-r> and
with the width <wid> to a real word <bit-l>. Precision may be lost in
the conversion.
The %cvt/rv instruction converts a thread vector starting at <bit-r>
and with the width <wid> to a real word. Push the result onto the real
value stack. Precision may be lost in the conversion.
The %cvt/rv/s instruction is the same as %cvt/rv, but treats the thread
vector as a signed value.
* %cvt/vr <bit-l>, <bit-r>, <wid>
* %cvt/vr <bit-l>, <wid>
The %cvt/vr opcode converts a real word <bit-r> to a thread vector
The %cvt/vr opcode converts a real word from the stack to a thread vector
starting at <bit-l> and with the width <wid>. Non-integer precision is
lost in the conversion.
lost in the conversion, and the real value is popped from the stack.
* %deassign <var-label>, <base>, <width>
@ -397,12 +405,17 @@ the bits in either vector are x or z, the entire result is x.
The %div/s instruction is the same as %div, but does signed division.
* %div/wr <bit-l>, <bit-r>
* %div/wr
This opcode divides the left operand by the right operand. If the
right operand is 0, then the result is NaN.
* dup/real
These opcodes duplicate the value on the top of the stack for the
corresponding type.
* %evctl <functor-label> <idx>
* %evctl/c
* %evctl/s <functor-label> <idx>
@ -442,9 +455,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/wr <var-label>
Force a constant real value to the target variable. See %force/v above.
Force a constant real value to the target variable. See %force/v
above. The value is popped from the real value stack.
* %force/x0 <label>, <bit>, <wid>
@ -606,6 +620,12 @@ index is implicitly extracted from index register 3.
(See also %set/dar)
* %load/real <vpi-label>
The %load/real instruction reads a real value from the vpi-like object
and pushes it to the top of the real value stack.
* %load/v <bit>, <functor-label>, <wid>
This instruction loads a vector value from the given functor node into
@ -630,11 +650,7 @@ The <wid> is, line the %load/v, the result width. But unlike the
%load/v, the vector is padded with 0s (%load/vp0) or sign extended
(%load/vp0/s) to the desired width.
* %load/wr <bit>, <vpi-label>
* %load/ar <bit>, <array-label>, <index>
The %load/wr instruction reads a real value from the vpi-like object
to a word register <bit>.
* %load/ar <array-label>, <index>
The %load/ar instruction reads a real value from an array. The <index>
is the index register that contains the canonical word address into
@ -669,6 +685,13 @@ If <exp>==0x3fff and <mant> == 0, the value is +inf.
If <exp>==0x7fff and <mant> == 0, the value is -inf.
If <exp>==0x3fff and <mant> != 0, the value is NaN.
* %max/wr
* %min/wr
This instruction pops the top two values from the real stack and
pushes back the max(min) value. Avoid returning NaN by selecting the
other if either is NaN.
* %mod <bit-l>, <bit-r>, <wid>
* %mod/s <bit-l>, <bit-r>, <wid>
@ -679,12 +702,11 @@ replaced with the result.
The /s form does signed %.
* %mod/wr <bit-l>, <bit-r>
* %mod/wr
This opcode is the real-valued modulus of the two real values.
* %mov <dst>, <src>, <wid>
* %mov/wr <dst>, <src>
* %mov/wu <dst>, <src>
* %movi <dst>, <value>, <wid>
@ -706,10 +728,9 @@ are x or z, the result is x. Otherwise, the result is the arithmetic
product.
* %mul/wr <bit-l>, <bit-r>
* %mul/wr
This opcode multiplies two real words together. The result replaces
the left operand.
This opcode multiplies two real words together.
* %muli <bit-l>, <imm>, <wid>
@ -792,6 +813,7 @@ the source bit. The <dst> may not be 0-3. This is useful for zero
or sign extending a vector.
* %pop/str <num>
* %pop/real <num>
Pop this many items from the string stack. This is the opposite of the
%pushX/str opcode which pushes a string to the stack. The %pop/str is
@ -808,10 +830,22 @@ to calculate the result so may not produce exact results. The result
replaces the left operand.
* %pow/wr <bit-l>, <bit-r>
* %pow/wr
This opcode raises <bit-l> (real) to the power of <bit-r> (real). The
result replaces the left operand.
This opcode raises the left operand by the right operand, and pushes
the result.
* %pushi/real <mant>, <exp>
This opcode loads an immediate value, floating point, into the real
value stack. The mantissa is an unsigned integer value, up to 32 bits,
that multiplied by 2**(<exp>-0x1000) to make a real value. The sign
bit is OR-ed into the <exp> value at bit 0x4000, and is removed from
the <exp> before calculating the real value.
If <exp>==0x3fff and <mant> == 0, the value is +inf.
If <exp>==0x7fff and <mant> == 0, the value is -inf.
If <exp>==0x3fff and <mant> != 0, the value is NaN.
* %pushi/str <text>
@ -874,19 +908,6 @@ width is implied from the <wid> that is the argument. This is the part
The address (in canonical form) is precalculated and loaded into index
register 3. This is the address of the word within the array.
* %set/wr <vpi-label>, <bit>
* %set/ar <array-label>, <index>, <bit>
The %set/wr instruction writes a real word to the specified VPI-like
object.
The %set/ar instruction writes a real work to the specified array
word. The <array-label> addresses the array, and the <index> is the
name of the index register to address into the word. The index
register must contain an integer value that is the canonical address
of the array word. The <bit> is the index register that contains the
real value word to write.
* %set/x0 <var-label>, <bit>, <wid>
This sets the part of a signal vector, the address calculated by
@ -930,6 +951,15 @@ For a negative shift %shiftr/i0 will pad the value with 'bx.
This pops the top of the object stack and writes it to the object
variable given by the label.
* %store/real <var-label>
* %store/reala <var-label> <index>
This pops the top of the real variable stack and write it to the
object variable given bu the label.
The areal version is similar, but writes to a real array using the
index in the index register <index>
* %store/str <var-label>
This pops the top of the string stack and writes it to the string
@ -955,12 +985,11 @@ the <wid> of the left vector. The result replaces the left vector.
See also the %addi instruction.
* %sub/wr <bit-l>, <bit-r>
* %sub/wr
This instruction operates on real values in word registers. The right
indexed value is subtracted from the left indexed value, and the
result placed in the left index.
value is popped, the left value is popped, the right is subtracted
from the left, and the result pushed.
* %substr/v <bit-l>, <sel>, <wid>
@ -972,15 +1001,18 @@ that holds the index. This is the general method for getting string
values into the vector space. The string value is NOT popped.
* %vpi_call <name> [, ...]
* %vpi_call <name> [, ...] {<real> <str>}
This instruction makes a call to a system task that was declared using
VPI. The operands are compiled down to a vpiHandle for the call. The
instruction contains only the vpiHandle for the call. See the vpi.txt
file for more on system task/function calls.
The {...} part is stack information. This tells the run-time how many
stack items the call uses so that it knows how many to pop off the
stack when the call returns.
* %vpi_func <name>, <dst>, <wid> [, ...]
* %vpi_func <name>, <dst>, <wid> [, ...] {<real> <str>}
This instruction is similar to %vpi_call, except that it is for
calling system functions. The difference here is the <dst> and <wid>
@ -988,6 +1020,11 @@ parameters that specify where the return value is to go. The normal
means that the VPI code uses to write the return value causes those
bits to go here.
The {...} part is stack information. This tells the run-time how many
stack items the call uses so that it knows how many to pop off the
stack when the call returns. The function call will pop the real and
string stacks, and will push any return value.
* %wait <functor-label>

View File

@ -575,31 +575,34 @@ statement
after the name, and is used for function calls. */
/* This version does not allow a function to be called as a task. */
| label_opt K_vpi_call T_NUMBER T_NUMBER T_STRING argument_opt ';'
{ compile_vpi_call($1, $5, true, false, $3, $4,
$6.argc, $6.argv); }
| label_opt K_vpi_call T_NUMBER T_NUMBER T_STRING
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_call($1, $5, true, false, $3, $4,
$6.argc, $6.argv, $8, $9); }
/* This version allows a function to be called as a task, but prints a
* warning message. */
| label_opt K_vpi_call_w T_NUMBER T_NUMBER T_STRING argument_opt ';'
{ compile_vpi_call($1, $5, false, true, $3, $4,
$6.argc, $6.argv); }
| label_opt K_vpi_call_w T_NUMBER T_NUMBER T_STRING
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_call($1, $5, false, true, $3, $4,
$6.argc, $6.argv, $8, $9); }
/* This version allows a function to be called as a task and does not
* print a message. */
| label_opt K_vpi_call_i T_NUMBER T_NUMBER T_STRING argument_opt ';'
{ compile_vpi_call($1, $5, false, false, $3, $4,
$6.argc, $6.argv); }
| label_opt K_vpi_call_i T_NUMBER T_NUMBER T_STRING
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_call($1, $5, false, false, $3, $4,
$6.argc, $6.argv, $8, $9); }
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING ','
T_NUMBER ',' T_NUMBER argument_opt ';'
{ compile_vpi_func_call($1, $5, $7, $9, $3, $4,
$10.argc, $10.argv); }
| label_opt K_vpi_func T_NUMBER T_NUMBER T_STRING ','
T_NUMBER ',' T_NUMBER argument_opt '{' T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_func_call($1, $5, $7, $9, $3, $4,
$10.argc, $10.argv, $12, $13); }
| label_opt K_vpi_func_r T_NUMBER T_NUMBER T_STRING ',' T_NUMBER
argument_opt ';'
{ compile_vpi_func_call($1, $5, $7, -vpiRealConst, $3, $4,
$8.argc, $8.argv); }
| label_opt K_vpi_func_r T_NUMBER T_NUMBER T_STRING
argument_opt '{' T_NUMBER T_NUMBER '}' ';'
{ compile_vpi_func_call($1, $5, 0, -vpiRealConst, $3, $4,
$6.argc, $6.argv, $8, $9); }
/* %disable statements are instructions that takes a scope reference
as an operand. It therefore is parsed uniquely. */

View File

@ -147,6 +147,8 @@ void compile_sfunc(char*label, char*name, char*format_string,
unsigned argc, struct symb_s*argv,
char*trigger_label)
{
unsigned real_stack = 0;
unsigned string_stack = 0;
vpiHandle*vpi_argv = new vpiHandle[argc];
int width_code = make_vpi_argv(argc, vpi_argv, format_string);
delete[] format_string;
@ -155,6 +157,7 @@ void compile_sfunc(char*label, char*name, char*format_string,
vpiHandle sys = vpip_build_vpi_call(name, 0, width_code, ptr,
true, false, argc, vpi_argv,
real_stack, string_stack,
file_idx, lineno);
assert(sys);

View File

@ -173,6 +173,7 @@ static void cmd_call(unsigned argc, char*argv[])
vpiHandle call_handle = vpip_build_vpi_call(argv[0], 0, 0, 0,
true, false,
vpi_argc, vpi_argv,
0, 0,
1, 0);
if (call_handle == 0)
goto out;

View File

@ -551,6 +551,9 @@ struct __vpiSysTaskCall : public __vpiHandle {
struct __vpiUserSystf*defn;
unsigned nargs;
vpiHandle*args;
/* Stack consumed by this call */
unsigned real_stack;
unsigned string_stack;
/* Support for vpi_get_userdata. */
void*userdata;
/* These represent where in the vthread to put the return value. */
@ -561,7 +564,11 @@ struct __vpiSysTaskCall : public __vpiHandle {
unsigned lineno;
bool put_value;
protected:
inline __vpiSysTaskCall() { }
inline __vpiSysTaskCall()
{
real_stack = 0;
string_stack = 0;
}
};
extern struct __vpiSysTaskCall*vpip_cur_task;
@ -675,6 +682,8 @@ extern vpiHandle vpip_build_vpi_call(const char*name,
bool func_as_task_warn,
unsigned argc,
vpiHandle*argv,
unsigned real_stack,
unsigned string_stack,
long file_idx,
long lineno);

View File

@ -29,12 +29,15 @@
#ifdef CHECK_WITH_VALGRIND
# include "vvp_cleanup.h"
#endif
# include <iostream>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <cassert>
# include "ivl_alloc.h"
using namespace std;
inline __vpiUserSystf::__vpiUserSystf()
{ }
@ -282,32 +285,6 @@ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int)
return 0;
}
static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int)
{
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
rfp->put_value = true;
/* Make sure this is a real valued function. */
assert(rfp->vwid == -vpiRealConst);
double val = 0.0;
switch (vp->format) {
case vpiRealVal:
val = vp->value.real;
break;
default:
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
assert(0);
}
vthread_put_real(vpip_current_vthread, rfp->vbit, val);
return 0;
}
static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int)
{
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
@ -458,14 +435,32 @@ struct sysfunc_real : public __vpiSysTaskCall {
int get_type_code(void) const { return vpiSysFuncCall; }
int vpi_get(int code) { return sysfunc_get(code, this); }
char* vpi_get_str(int code) { return systask_get_str(code, this); }
vpiHandle vpi_put_value(p_vpi_value val, int flags)
{ return sysfunc_put_real_value(this, val, flags); }
vpiHandle vpi_put_value(p_vpi_value val, int flags);
vpiHandle vpi_handle(int code)
{ return systask_handle(code, this); }
vpiHandle vpi_iterate(int code)
{ return systask_iter(code, this); }
double return_value_;
};
vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
{
put_value = true;
return_value_ = 0.0;
switch (vp->format) {
case vpiRealVal:
return_value_ = vp->value.real;
break;
default:
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
assert(0);
}
return 0;
}
struct sysfunc_4net : public __vpiSysTaskCall {
inline sysfunc_4net() { }
int get_type_code(void) const { return vpiSysFuncCall; }
@ -738,6 +733,7 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
vvp_net_t*fnet,
bool func_as_task_err, bool func_as_task_warn,
unsigned argc, vpiHandle*argv,
unsigned real_stack, unsigned string_stack,
long file_idx, long lineno)
{
assert(!(func_as_task_err && func_as_task_warn));
@ -819,6 +815,8 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid,
obj->defn = defn;
obj->nargs = argc;
obj->args = argv;
obj->real_stack = real_stack;
obj->string_stack = string_stack;
obj->vbit = vbit;
obj->vwid = vwid;
obj->fnet = fnet;
@ -905,6 +903,17 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
}
vpi_put_value(ref, &val, 0, vpiNoDelay);
}
if (vpip_cur_task->real_stack > 0)
vthread_pop_real(thr, vpip_cur_task->real_stack);
if (vpip_cur_task->string_stack > 0)
vthread_pop_str(thr, vpip_cur_task->string_stack);
/* If the function has a real value, then push the value
to the thread stack. */
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
vthread_push_real(thr, func_real->return_value_);
}
}
}

View File

@ -531,7 +531,7 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp)
will not have access to the proper value. Punt and return a
0.0 value instead. */
if (vpip_current_vthread)
val = vthread_get_real(vpip_current_vthread, obj->index);
val = vthread_get_real_stack(vpip_current_vthread, obj->index);
switch (vp->format) {

View File

@ -96,9 +96,27 @@ struct vthread_s {
union {
int64_t w_int;
uint64_t w_uint;
double w_real;
} words[16];
private:
vector<double> stack_real_;
public:
inline double pop_real(void)
{
assert(stack_real_.size() > 0);
double val = stack_real_.back();
stack_real_.pop_back();
return val;
}
inline void push_real(double val)
{ stack_real_.push_back(val); }
inline double peek_real(unsigned depth)
{
assert(depth < stack_real_.size());
unsigned use_index = stack_real_.size()-1-depth;
return stack_real_[use_index];
}
/* Strings are operated on using a forth-like operator
set. Items at the top of the stack (back()) are the objects
operated on except for special cases. New objects are
@ -182,14 +200,24 @@ void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit)
thr_put_bit(thr, addr, bit);
}
double vthread_get_real(struct vthread_s*thr, unsigned addr)
void vthread_push_real(struct vthread_s*thr, double val)
{
return thr->words[addr].w_real;
thr->push_real(val);
}
void vthread_put_real(struct vthread_s*thr, unsigned addr, double val)
void vthread_pop_real(struct vthread_s*thr, unsigned depth)
{
thr->words[addr].w_real = val;
while (depth > 0) {
(void) thr->pop_real();
depth -= 1;
}
}
void vthread_pop_str(struct vthread_s*thr, unsigned depth)
{
for (unsigned idx = 0 ; idx < depth ; idx += 1) {
thr->stack_str.pop_back();
}
}
string vthread_get_str_stack(struct vthread_s*thr, unsigned depth)
@ -199,6 +227,11 @@ string vthread_get_str_stack(struct vthread_s*thr, unsigned depth)
return thr->stack_str[use_index];
}
double vthread_get_real_stack(struct vthread_s*thr, unsigned depth)
{
return thr->peek_real(depth);
}
template <class T> T coerce_to_width(const T&that, unsigned width)
{
if (that.size() == width)
@ -624,12 +657,9 @@ vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx)
return vvp_get_context_item(running_thread->rd_context, context_idx);
}
bool of_ABS_WR(vthread_t thr, vvp_code_t cp)
bool of_ABS_WR(vthread_t thr, vvp_code_t)
{
unsigned dst = cp->bit_idx[0];
unsigned src = cp->bit_idx[1];
thr->words[dst].w_real = fabs(thr->words[src].w_real);
thr->push_real( fabs(thr->pop_real()) );
return true;
}
@ -745,11 +775,11 @@ bool of_ADD(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_ADD_WR(vthread_t thr, vvp_code_t cp)
bool of_ADD_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = l + r;
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(l + r);
return true;
}
@ -800,7 +830,7 @@ bool of_ADDI(vthread_t thr, vvp_code_t cp)
return true;
}
/* %assign/ar <array>, <delay>, <bit>
/* %assign/ar <array>, <delay>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory. <delay>
* is the delay in simulation time. <bit> is the index register
@ -810,7 +840,7 @@ bool of_ASSIGN_AR(vthread_t thr, vvp_code_t cp)
{
long adr = thr->words[3].w_int;
unsigned delay = cp->bit_idx[0];
double value = thr->words[cp->bit_idx[1]].w_real;
double value = thr->pop_real();
if (adr >= 0) {
schedule_assign_array_word(cp->array, adr, value, delay);
@ -819,17 +849,16 @@ bool of_ASSIGN_AR(vthread_t thr, vvp_code_t cp)
return true;
}
/* %assign/ar/d <array>, <delay_idx>, <bit>
/* %assign/ar/d <array>, <delay_idx>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory.
* <delay_idx> is the integer register that contains the delay value.
* <bit> is the index register containing the real value.
*/
bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t cp)
{
long adr = thr->words[3].w_int;
vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_uint;
double value = thr->words[cp->bit_idx[1]].w_real;
double value = thr->pop_real();
if (adr >= 0) {
schedule_assign_array_word(cp->array, adr, value, delay);
@ -838,7 +867,7 @@ bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t cp)
return true;
}
/* %assign/ar/e <array>, <bit>
/* %assign/ar/e <array>
* Generate an assignment event to a real array. Index register 3
* contains the canonical address of the word in the memory. <bit>
* is the index register containing the real value. The event
@ -848,7 +877,7 @@ bool of_ASSIGN_ARD(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_ARE(vthread_t thr, vvp_code_t cp)
{
long adr = thr->words[3].w_int;
double value = thr->words[cp->bit_idx[0]].w_real;
double value = thr->pop_real();
if (adr >= 0) {
if (thr->ecount == 0) {
@ -1175,7 +1204,7 @@ bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t cp)
}
/*
* This is %assign/wr <vpi-label>, <delay>, <index>
* This is %assign/wr <vpi-label>, <delay>
*
* This assigns (after a delay) a value to a real variable. Use the
* vpi_put_value function to do the assign, with the delay written
@ -1184,7 +1213,7 @@ bool of_ASSIGN_V0X1E(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp)
{
unsigned delay = cp->bit_idx[0];
unsigned index = cp->bit_idx[1];
double value = thr->pop_real();
s_vpi_time del;
del.type = vpiSimTime;
@ -1194,7 +1223,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp)
t_vpi_value val;
val.format = vpiRealVal;
val.value.real = thr->words[index].w_real;
val.value.real = value;
vpi_put_value(tmp, &val, &del, vpiTransportDelay);
return true;
@ -1203,7 +1232,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp)
{
vvp_time64_t delay = thr->words[cp->bit_idx[0]].w_uint;
unsigned index = cp->bit_idx[1];
double value = thr->pop_real();
s_vpi_time del;
del.type = vpiSimTime;
@ -1213,7 +1242,7 @@ bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp)
t_vpi_value val;
val.format = vpiRealVal;
val.value.real = thr->words[index].w_real;
val.value.real = value;
vpi_put_value(tmp, &val, &del, vpiTransportDelay);
return true;
@ -1222,7 +1251,7 @@ bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp)
bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t cp)
{
assert(thr->event != 0);
unsigned index = cp->bit_idx[0];
double value = thr->pop_real();
__vpiHandle*tmp = cp->handle;
// If the count is zero then just put the value.
@ -1230,11 +1259,10 @@ bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t cp)
t_vpi_value val;
val.format = vpiRealVal;
val.value.real = thr->words[index].w_real;
val.value.real = value;
vpi_put_value(tmp, &val, 0, vpiNoDelay);
} else {
schedule_evctl(tmp, thr->words[index].w_real, thr->event,
thr->ecount);
schedule_evctl(tmp, value, thr->event, thr->ecount);
}
thr->event = 0;
@ -1277,11 +1305,11 @@ bool of_BLEND(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_BLEND_WR(vthread_t thr, vvp_code_t cp)
bool of_BLEND_WR(vthread_t thr, vvp_code_t)
{
double t = thr->words[cp->bit_idx[0]].w_real;
double f = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = (t == f) ? t : 0.0;
double f = thr->pop_real();
double t = thr->pop_real();
thr->push_real((t == f) ? t : 0.0);
return true;
}
@ -1359,7 +1387,7 @@ bool of_CASSIGN_V(vthread_t thr, vvp_code_t cp)
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;
double value = thr->pop_real();
/* Set the value into port 1 of the destination. */
vvp_net_ptr_t ptr (net, 1);
@ -1760,10 +1788,10 @@ bool of_CMPX(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_CMPWR(vthread_t thr, vvp_code_t cp)
bool of_CMPWR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
double r = thr->pop_real();
double l = thr->pop_real();
vvp_bit4_t eq = (l == r)? BIT4_1 : BIT4_0;
vvp_bit4_t lt = (l < r)? BIT4_1 : BIT4_0;
@ -1852,43 +1880,52 @@ bool of_CONCATI_STR(vthread_t thr, vvp_code_t cp)
bool of_CVT_RS(vthread_t thr, vvp_code_t cp)
{
int64_t r = thr->words[cp->bit_idx[1]].w_int;
thr->words[cp->bit_idx[0]].w_real = (double)(r);
int64_t r = thr->words[cp->bit_idx[0]].w_int;
thr->push_real( (double)(r) );
return true;
}
bool of_CVT_RU(vthread_t thr, vvp_code_t cp)
{
uint64_t r = thr->words[cp->bit_idx[1]].w_uint;
thr->words[cp->bit_idx[0]].w_real = (double)(r);
uint64_t r = thr->words[cp->bit_idx[0]].w_uint;
thr->push_real( (double)(r) );
return true;
}
bool of_CVT_RV(vthread_t thr, vvp_code_t cp)
{
unsigned base = cp->bit_idx[1];
unsigned wid = cp->number;
unsigned base = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vector4_to_value(vector, thr->words[cp->bit_idx[0]].w_real, false);
double val;
vector4_to_value(vector, val, false);
thr->push_real(val);
return true;
}
bool of_CVT_RV_S(vthread_t thr, vvp_code_t cp)
{
unsigned base = cp->bit_idx[1];
unsigned wid = cp->number;
unsigned base = cp->bit_idx[0];
unsigned wid = cp->bit_idx[1];
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vector4_to_value(vector, thr->words[cp->bit_idx[0]].w_real, true);
double val;
vector4_to_value(vector, val, true);
thr->push_real(val);
return true;
}
/*
* %cvt/sr <idx>
* Pop the top value from the real stack, convert it to a 64bit signed
* and save it to the indexed register.
*/
bool of_CVT_SR(vthread_t thr, vvp_code_t cp)
{
double r = thr->words[cp->bit_idx[1]].w_real;
double r = thr->pop_real();
thr->words[cp->bit_idx[0]].w_int = i64round(r);
return true;
@ -1896,7 +1933,7 @@ bool of_CVT_SR(vthread_t thr, vvp_code_t cp)
bool of_CVT_UR(vthread_t thr, vvp_code_t cp)
{
double r = thr->words[cp->bit_idx[1]].w_real;
double r = thr->pop_real();
if (r >= 0.0)
thr->words[cp->bit_idx[0]].w_uint = (uint64_t)floor(r+0.5);
else
@ -1905,12 +1942,16 @@ bool of_CVT_UR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %cvt/vr <bit> <wid>
*/
bool of_CVT_VR(vthread_t thr, vvp_code_t cp)
{
double r = thr->words[cp->bit_idx[1]].w_real;
double r = thr->pop_real();
unsigned base = cp->bit_idx[0];
unsigned wid = cp->number;
vvp_vector4_t tmp(wid, r);
/* Make sure there is enough space for the new vector. */
thr_check_addr(thr, base+wid-1);
thr->bits4.set_vec(base, tmp);
@ -2387,15 +2428,21 @@ bool of_DIV_S(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_DIV_WR(vthread_t thr, vvp_code_t cp)
bool of_DIV_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = l / r;
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(l / r);
return true;
}
bool of_DUP_REAL(vthread_t thr, vvp_code_t)
{
thr->push_real(thr->peek_real(0));
return true;
}
/*
* This terminates the current thread. If there is a parent who is
* waiting for me to die, then I schedule it. At any rate, I mark
@ -2563,7 +2610,7 @@ bool of_FORCE_V(vthread_t thr, vvp_code_t cp)
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;
double value = thr->pop_real();
net->force_real(value, vvp_vector2_t(vvp_vector2_t::FILL1, 1));
@ -3036,12 +3083,11 @@ bool of_JOIN_DETACH(vthread_t thr, vvp_code_t cp)
}
/*
* %load/ar <bit>, <array-label>, <index>;
* %load/ar <array-label>, <index>;
*/
bool of_LOAD_AR(vthread_t thr, vvp_code_t cp)
{
unsigned bit = cp->bit_idx[0];
unsigned idx = cp->bit_idx[1];
unsigned idx = cp->bit_idx[0];
unsigned adr = thr->words[idx].w_int;
double word;
@ -3052,7 +3098,7 @@ bool of_LOAD_AR(vthread_t thr, vvp_code_t cp)
word = array_get_word_r(cp->array, adr);
}
thr->words[bit].w_real = word;
thr->push_real(word);
return true;
}
@ -3257,6 +3303,23 @@ bool of_LOAD_AVX_P(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %load/real <var-label>
*/
bool of_LOAD_REAL(vthread_t thr, vvp_code_t cp)
{
__vpiHandle*tmp = cp->handle;
t_vpi_value val;
val.format = vpiRealVal;
vpi_get_value(tmp, &val);
thr->push_real(val.value.real);
return true;
}
bool of_LOAD_STR(vthread_t thr, vvp_code_t cp)
{
vvp_net_t*net = cp->net;
@ -3365,19 +3428,6 @@ bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_LOAD_WR(vthread_t thr, vvp_code_t cp)
{
__vpiHandle*tmp = cp->handle;
t_vpi_value val;
val.format = vpiRealVal;
vpi_get_value(tmp, &val);
thr->words[cp->bit_idx[0]].w_real = val.value.real;
return true;
}
/*
* %load/x16 <bit>, <functor>, <wid>
*
@ -3416,37 +3466,6 @@ bool of_LOAD_X1P(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_LOADI_WR(vthread_t thr, vvp_code_t cp)
{
unsigned idx = cp->bit_idx[0];
double mant = cp->number;
int exp = cp->bit_idx[1];
// Detect +infinity
if (exp==0x3fff && cp->number==0) {
thr->words[idx].w_real = INFINITY;
return true;
}
// Detect -infinity
if (exp==0x7fff && cp->number==0) {
thr->words[idx].w_real = -INFINITY;
return true;
}
// Detect NaN
if (exp==0x3fff) {
thr->words[idx].w_real = nan("");
return true;
}
double sign = (exp & 0x4000)? -1.0 : 1.0;
exp &= 0x1fff;
mant = sign * ldexp(mant, exp - 0x1000);
thr->words[idx].w_real = mant;
return true;
}
static void do_verylong_mod(vthread_t thr, vvp_code_t cp,
bool left_is_neg, bool right_is_neg)
{
@ -3572,6 +3591,36 @@ static void do_verylong_mod(vthread_t thr, vvp_code_t cp,
return;
}
bool of_MAX_WR(vthread_t thr, vvp_code_t)
{
double r = thr->pop_real();
double l = thr->pop_real();
if (r != r)
thr->push_real(l);
else if (l != l)
thr->push_real(r);
else if (r < l)
thr->push_real(l);
else
thr->push_real(r);
return true;
}
bool of_MIN_WR(vthread_t thr, vvp_code_t)
{
double r = thr->pop_real();
double l = thr->pop_real();
if (r != r)
thr->push_real(l);
else if (l != l)
thr->push_real(r);
else if (r < l)
thr->push_real(r);
else
thr->push_real(l);
return true;
}
bool of_MOD(vthread_t thr, vvp_code_t cp)
{
assert(cp->bit_idx[0] >= 4);
@ -3684,13 +3733,13 @@ bool of_MOD_S(vthread_t thr, vvp_code_t cp)
}
/*
* %mod/wr <dest>, <src>
* %mod/wr
*/
bool of_MOD_WR(vthread_t thr, vvp_code_t cp)
bool of_MOD_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = fmod(l,r);
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(fmod(l,r));
return true;
}
@ -3760,17 +3809,8 @@ bool of_PAD(vthread_t thr, vvp_code_t cp)
}
/*
* %mov/wr <dst>, <src>
* %mov/wu <dst>, <src>
*/
bool of_MOV_WR(vthread_t thr, vvp_code_t cp)
{
unsigned dst = cp->bit_idx[0];
unsigned src = cp->bit_idx[1];
thr->words[dst].w_real = thr->words[src].w_real;
return true;
}
bool of_MOV_WU(vthread_t thr, vvp_code_t cp)
{
unsigned dst = cp->bit_idx[0];
@ -3863,11 +3903,11 @@ bool of_MUL(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_MUL_WR(vthread_t thr, vvp_code_t cp)
bool of_MUL_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = l * r;
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(l * r);
return true;
}
@ -4203,6 +4243,18 @@ bool of_NOR(vthread_t thr, vvp_code_t cp)
return cp->opcode(thr, cp);
}
/*
* %pop/real <number>
*/
bool of_POP_REAL(vthread_t thr, vvp_code_t cp)
{
unsigned cnt = cp->number;
for (unsigned idx = 0 ; idx < cnt ; idx += 1) {
(void) thr->pop_real();
}
return true;
}
/*
* %pop/str <number>
*/
@ -4289,15 +4341,46 @@ bool of_POW_S(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_POW_WR(vthread_t thr, vvp_code_t cp)
bool of_POW_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = pow(l, r);
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(pow(l,r));
return true;
}
bool of_PUSHI_REAL(vthread_t thr, vvp_code_t cp)
{
double mant = cp->bit_idx[0];
uint32_t imant = cp->bit_idx[0];
int exp = cp->bit_idx[1];
// Detect +infinity
if (exp==0x3fff && imant==0) {
thr->push_real(INFINITY);
return true;
}
// Detect -infinity
if (exp==0x7fff && imant==0) {
thr->push_real(-INFINITY);
return true;
}
// Detect NaN
if (exp==0x3fff) {
thr->push_real(nan(""));
return true;
}
double sign = (exp & 0x4000)? -1.0 : 1.0;
exp &= 0x1fff;
mant = sign * ldexp(mant, exp - 0x1000);
thr->push_real(mant);
return true;
}
bool of_PUSHI_STR(vthread_t thr, vvp_code_t cp)
{
const char*text = cp->text;
@ -4452,24 +4535,6 @@ bool of_RELEASE_WR(vthread_t, vvp_code_t cp)
return true;
}
/*
* %set/av <label>, <index>, <bit>
*
* Write the real value in register <bit> to the array indexed by the
* integer value addressed bin index register <index>.
*/
bool of_SET_AR(vthread_t thr, vvp_code_t cp)
{
unsigned idx = cp->bit_idx[0];
unsigned bit = cp->bit_idx[1];
unsigned adr = thr->words[idx].w_int;
double value = thr->words[bit].w_real;
array_set_word(cp->array, adr, value);
return true;
}
/*
* This implements the "%set/av <label>, <bit>, <wid>" instruction. In
* this case, the <label> is an array label, and the <bit> and <wid>
@ -4538,15 +4603,6 @@ bool of_SET_VEC(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_SET_WORDR(vthread_t thr, vvp_code_t cp)
{
/* set the value into port 0 of the destination. */
vvp_net_ptr_t ptr (cp->net, 0);
vvp_send_real(ptr, thr->words[cp->bit_idx[0]].w_real, thr->wt_context);
return true;
}
/*
* Implement the %set/x instruction:
@ -4763,6 +4819,29 @@ bool of_STORE_OBJ(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_STORE_REAL(vthread_t thr, vvp_code_t cp)
{
double val = thr->pop_real();
/* set the value into port 0 of the destination. */
vvp_net_ptr_t ptr (cp->net, 0);
vvp_send_real(ptr, val, thr->wt_context);
return true;
}
/*
* %store/reala <var-label> <index>
*/
bool of_STORE_REALA(vthread_t thr, vvp_code_t cp)
{
unsigned idx = cp->bit_idx[0];
unsigned adr = thr->words[idx].w_int;
double val = thr->pop_real();
array_set_word(cp->array, adr, val);
return true;
}
bool of_STORE_STR(vthread_t thr, vvp_code_t cp)
{
@ -4815,11 +4894,11 @@ bool of_SUB(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_SUB_WR(vthread_t thr, vvp_code_t cp)
bool of_SUB_WR(vthread_t thr, vvp_code_t)
{
double l = thr->words[cp->bit_idx[0]].w_real;
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_real = l - r;
double r = thr->pop_real();
double l = thr->pop_real();
thr->push_real(l - r);
return true;
}

View File

@ -116,13 +116,17 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx);
extern vvp_bit4_t vthread_get_bit(struct vthread_s*thr, unsigned addr);
extern void vthread_put_bit(struct vthread_s*thr, unsigned addr, vvp_bit4_t bit);
extern double vthread_get_real(struct vthread_s*thr, unsigned addr);
extern void vthread_put_real(struct vthread_s*thr, unsigned addr, double val);
extern void vthread_push_real(struct vthread_s*thr, double val);
extern void vthread_pop_str(struct vthread_s*thr, unsigned count);
extern void vthread_pop_real(struct vthread_s*thr, unsigned count);
/* Get the string from the requested position in the vthread string
stack. The top of the stack is depth==0, and items below are
depth==1, etc. */
extern std::string vthread_get_str_stack(struct vthread_s*thr, unsigned depth);
extern double vthread_get_real_stack(struct vthread_s*thr, unsigned depth);
/* This is used to actually delete a thread once we are done with it. */
extern void vthread_delete(vthread_t thr);