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:
parent
0339f5ed57
commit
a5fd5363b3
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
13
vvp/codes.h
13
vvp/codes.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
165
vvp/opcodes.txt
165
vvp/opcodes.txt
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
37
vvp/parse.y
37
vvp/parse.y
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
395
vvp/vthread.cc
395
vvp/vthread.cc
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue