From b416176c4def2b8721f0bca5cba90c152c96f2f6 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 19 Dec 2009 23:34:54 +0000 Subject: [PATCH] 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. --- tgt-vvp/eval_expr.c | 2 +- tgt-vvp/eval_real.c | 118 +++++++++++++----------------------------- tgt-vvp/vvp_process.c | 2 +- vvp/codes.h | 8 ++- vvp/compile.cc | 8 ++- vvp/opcodes.txt | 32 +++++++++--- vvp/vthread.cc | 47 +++++++++++++++-- 7 files changed, 119 insertions(+), 98 deletions(-) diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index ebe9bb03f..b40d0de6c 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -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: diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 23ebcac4f..a946de4e2 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -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", diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index ed00cf696..3fb3cd384 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -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; } diff --git a/vvp/codes.h b/vvp/codes.h index 3e721d51a..d822bb044 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 71515761f..41dd826dd 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index a89c0d91a..6a2351fae 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -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 , -* %cvt/ri , -* %cvt/vr , , +* %cvt/sr , +* %cvt/rs , -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 , +* %cvt/ru , + +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 , , +* %cvt/rv/s , , + +The %cvt/rv instruction converts a thread vector starting at and +with the width to a real word . 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 , , The %cvt/vr opcode converts a real word to a thread vector starting at and with the width . Non-integer precision is diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 55362c6cb..8e698ffdd 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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; }