Fix for pr2913404.

In combination with the patch to make all operations on thread words
operate on 64-bit values, this patch ensures casts between real values
and large vector values work correctly.
This commit is contained in:
Martin Whitaker 2009-12-19 23:34:54 +00:00 committed by Stephen Williams
parent 13cad6f268
commit b416176c4d
7 changed files with 119 additions and 98 deletions

View File

@ -266,7 +266,7 @@ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
case IVL_VT_REAL:
word = draw_eval_real(expr);
clr_word(word);
fprintf(vvp_out, " %%cvt/ir %u, %u;\n", ix, word);
fprintf(vvp_out, " %%cvt/sr %u, %u;\n", ix, word);
break;
default:

View File

@ -274,11 +274,37 @@ static int draw_realnum_real(ivl_expr_t expr)
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)
{
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);
} else {
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);
else
fprintf(vvp_out, " %%cvt/ru %d, %d;\n", res, res);
}
clr_vector(sv);
return res;
}
static int draw_sfunc_real(ivl_expr_t expr)
{
struct vector_info sv;
int res;
const char*sign_flag = "";
switch (ivl_expr_value(expr)) {
@ -298,17 +324,7 @@ 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. */
sv = draw_eval_expr(expr, 0);
clr_vector(sv);
if (ivl_expr_signed(expr))
sign_flag = "/s";
res = allocate_word();
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
res = draw_real_logic_expr(expr, 0);
break;
default:
@ -319,25 +335,6 @@ static int draw_sfunc_real(ivl_expr_t expr)
return res;
}
/*
* The real value of a signal is the integer value of a signal
* converted to real.
*/
static int draw_signal_real_logic(ivl_expr_t expr)
{
int res = allocate_word();
struct vector_info sv = draw_eval_expr(expr, 0);
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u; logic signal as real\n",
sign_flag, res, sv.base, sv.wid);
clr_vector(sv);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
return res;
}
static int draw_signal_real_real(ivl_expr_t expr)
{
ivl_signal_t sig = ivl_expr_signal(expr);
@ -361,7 +358,7 @@ static int 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_signal_real_logic(expr);
return draw_real_logic_expr(expr, 0);
case IVL_VT_REAL:
return draw_signal_real_real(expr);
default:
@ -439,41 +436,11 @@ static int draw_unary_real(ivl_expr_t expr)
ivl_expr_t sube;
int sub;
/* If the opcode is a ~ then the sub expression must not be a
* real expression, so use vector evaluation and then convert
/* 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) == '~') {
struct vector_info vi;
int res;
const char*sign_flag;
vi = draw_eval_expr(expr, STUFF_OK_XZ);
res = allocate_word();
sign_flag = ivl_expr_signed(expr)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
}
if (ivl_expr_opcode(expr) == '!') {
struct vector_info vi;
int res;
const char*sign_flag;
vi = draw_eval_expr(expr, STUFF_OK_XZ);
res = allocate_word();
sign_flag = ivl_expr_signed(expr)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
return draw_real_logic_expr(expr, STUFF_OK_XZ);
}
sube = ivl_expr_oper1(expr);
@ -512,20 +479,7 @@ int draw_eval_real(ivl_expr_t expr)
* result to a real value. This is required to get integer
* division to work correctly. */
if (ivl_expr_value(expr) != IVL_VT_REAL) {
struct vector_info vi;
int res;
const char*sign_flag;
vi = draw_eval_expr(expr, STUFF_OK_XZ);
res = allocate_word();
sign_flag = ivl_expr_signed(expr)? "/s" : "";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", sign_flag, res,
vi.base, vi.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
clr_vector(vi);
return res;
return draw_real_logic_expr(expr, STUFF_OK_XZ);
}
switch (ivl_expr_type(expr)) {
@ -573,7 +527,7 @@ int draw_eval_real(ivl_expr_t expr)
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
sign_flag, res, sv.base, sv.wid);
fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
fprintf(vvp_out, " %%cvt/rs %d, %d;\n", res, res);
} else {
fprintf(stderr, "XXXX Evaluate real expression (%d)\n",

View File

@ -1455,7 +1455,7 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
case IVL_VT_REAL: {
int word = draw_eval_real(exp);
fprintf(vvp_out, " %%cvt/ir 0, %d;\n", word);
fprintf(vvp_out, " %%cvt/ur 0, %d;\n", word);
clr_word(word);
break;
}

View File

@ -73,8 +73,12 @@ extern bool of_CMPWS(vthread_t thr, vvp_code_t code);
extern bool of_CMPWU(vthread_t thr, vvp_code_t code);
extern bool of_CMPX(vthread_t thr, vvp_code_t code);
extern bool of_CMPZ(vthread_t thr, vvp_code_t code);
extern bool of_CVT_IR(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RI(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RS(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RU(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RV(vthread_t thr, vvp_code_t code);
extern bool of_CVT_RV_S(vthread_t thr, vvp_code_t code);
extern bool of_CVT_SR(vthread_t thr, vvp_code_t code);
extern bool of_CVT_UR(vthread_t thr, vvp_code_t code);
extern bool of_CVT_VR(vthread_t thr, vvp_code_t code);
extern bool of_DEASSIGN(vthread_t thr, vvp_code_t code);
extern bool of_DEASSIGN_WR(vthread_t thr, vvp_code_t code);

View File

@ -119,8 +119,12 @@ const static struct opcode_table_s opcode_table[] = {
{ "%cmp/z", of_CMPZ, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/s", of_CMPIS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cmpi/u", of_CMPIU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} },
{ "%cvt/ir", of_CVT_IR, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/ri", of_CVT_RI, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
{ "%cvt/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} },
{ "%deassign",of_DEASSIGN,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
{ "%deassign/wr",of_DEASSIGN_WR,1,{OA_FUNC_PTR, OA_NONE, OA_NONE} },

View File

@ -275,13 +275,33 @@ instruction will also treat x values in either operand as don't care.
Only bit 4 is set by these instructions.
* %cvt/ir <bit-l>, <bit-r>
* %cvt/ri <bit-l>, <bit-r>
* %cvt/vr <bit-l>, <bit-r>, <wid>
* %cvt/sr <bit-l>, <bit-r>
* %cvt/rs <bit-l>, <bit-r>
Copy a word from r to l, converting it from real to integer (ir) or
integer to real (ri) in the process. The source and destination may
be the same word address, leading to a convert in place.
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>
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>
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/s instruction is the same as %cvt/rv, but treats the thread
vector as a signed value.
* %cvt/vr <bit-l>, <bit-r>, <wid>
The %cvt/vr opcode converts a real word <bit-r> to a thread vector
starting at <bit-l> and with the width <wid>. Non-integer precision is

View File

@ -1774,7 +1774,43 @@ bool of_CMPZ(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_CVT_IR(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);
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);
return true;
}
bool of_CVT_RV(vthread_t thr, vvp_code_t cp)
{
unsigned base = cp->bit_idx[1];
unsigned wid = cp->number;
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vector4_to_value(vector, thr->words[cp->bit_idx[0]].w_real, false);
return true;
}
bool of_CVT_RV_S(vthread_t thr, vvp_code_t cp)
{
unsigned base = cp->bit_idx[1];
unsigned wid = cp->number;
vvp_vector4_t vector = vthread_bits_to_vector(thr, base, wid);
vector4_to_value(vector, thr->words[cp->bit_idx[0]].w_real, true);
return true;
}
bool of_CVT_SR(vthread_t thr, vvp_code_t cp)
{
double r = thr->words[cp->bit_idx[1]].w_real;
thr->words[cp->bit_idx[0]].w_int = i64round(r);
@ -1782,10 +1818,13 @@ bool of_CVT_IR(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_CVT_RI(vthread_t thr, vvp_code_t cp)
bool of_CVT_UR(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);
double r = thr->words[cp->bit_idx[1]].w_real;
if (r >= 0.0)
thr->words[cp->bit_idx[0]].w_uint = (uint64_t)floor(r+0.5);
else
thr->words[cp->bit_idx[0]].w_uint = (uint64_t)ceil(r-0.5);
return true;
}