diff --git a/elaborate.cc b/elaborate.cc index 9509d11ae..0815917c2 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2265,6 +2265,12 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const ivl_assert(*this, rv->expr_width() >= wid); } + if (lv->expr_type() == IVL_VT_BOOL && rv->expr_type() != IVL_VT_BOOL) { + if (debug_elaborate) + cerr << get_fileline() << ": debug: Cast expression to int2" << endl; + rv = cast_to_int2(rv); + } + NetAssign*cur = new NetAssign(lv, rv); cur->set_line(*this); @@ -3562,6 +3568,14 @@ NetForce* PForce::elaborate(Design*des, NetScope*scope) const rexp->set_width(lwid, true); rexp = pad_to_width(rexp, lwid, *this); + if (ltype==IVL_VT_BOOL && rexp->expr_type()!=IVL_VT_BOOL) { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Cast force rvalue to int2" << endl; + } + rexp = cast_to_int2(rexp); + } + dev = new NetForce(lval, rexp); if (debug_elaborate) { diff --git a/netmisc.cc b/netmisc.cc index 2fa69b191..73d1f3b58 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -176,6 +176,14 @@ NetNet* cast_to_real(Design*des, NetScope*scope, NetNet*src) return tmp; } +NetExpr* cast_to_int2(NetExpr*expr) +{ + NetECast*cast = new NetECast('2', expr); + cast->set_line(*expr); + cast->cast_signed(expr->has_sign()); + return cast; +} + /* * Add a signed constant to an existing expression. Generate a new * NetEBAdd node that has the input expression and an expression made diff --git a/netmisc.h b/netmisc.h index bfc4fa37d..3d88ca8aa 100644 --- a/netmisc.h +++ b/netmisc.h @@ -78,6 +78,8 @@ extern NetNet*cast_to_int4(Design*des, NetScope*scope, NetNet*src, unsigned wid) extern NetNet*cast_to_int2(Design*des, NetScope*scope, NetNet*src, unsigned wid); extern NetNet*cast_to_real(Design*des, NetScope*scope, NetNet*src); +extern NetExpr*cast_to_int2(NetExpr*expr); + /* * Take the input expression and return a variation that assures that * the expression is 1-bit wide and logical. This reflects the needs diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index cf3847614..219ffede9 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -3125,6 +3125,21 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid) local_count += 1; break; + case '2': /* Cast logic to bool */ + assert(ivl_expr_value(sub) == IVL_VT_LOGIC); + res = draw_eval_expr_wid(sub, wid, 0); + + /* Handle special case that value is 0 or 1. */ + if (res.base == 0 || res.base == 1) + break; + if (res.base == 2 || res.base == 2) { + res.base = 0; + break; + } + + fprintf(vvp_out, " %%cast2 %d, %d, %u;\n", res.base, res.base, res.wid); + break; + case 'i': /* Cast a real value to an integer. */ assert(ivl_expr_value(sub) == IVL_VT_REAL); word = draw_eval_real(sub); diff --git a/vvp/codes.h b/vvp/codes.h index d822bb044..2d4a86466 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -64,6 +64,7 @@ extern bool of_CASSIGN_LINK(vthread_t thr, vvp_code_t code); extern bool of_CASSIGN_V(vthread_t thr, vvp_code_t code); extern bool of_CASSIGN_WR(vthread_t thr, vvp_code_t code); extern bool of_CASSIGN_X0(vthread_t thr, vvp_code_t code); +extern bool of_CAST2(vthread_t thr, vvp_code_t code); extern bool of_CMPIS(vthread_t thr, vvp_code_t code); extern bool of_CMPIU(vthread_t thr, vvp_code_t code); extern bool of_CMPS(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 383a74189..87a841f5a 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -107,6 +107,7 @@ const static struct opcode_table_s opcode_table[] = { { "%cassign/v",of_CASSIGN_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%cassign/wr",of_CASSIGN_WR,2,{OA_FUNC_PTR,OA_BIT1, OA_NONE} }, { "%cassign/x0",of_CASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, + { "%cast2", of_CAST2, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/s", of_CMPS, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/u", of_CMPU, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%cmp/wr", of_CMPWR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 7ea27d598..6a55fbd7f 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -217,6 +217,12 @@ cassign port (port-1) of the signal 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. +* %cast2 , , + +Convert the source vector, of type logic, to a bool vector by +changing all the X and Z bits to 0. The source and destinations may +overlap. + * %cmp/u , , * %cmp/s , , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index e70a366e2..4dfc7ab73 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1385,6 +1385,34 @@ bool of_CASSIGN_X0(vthread_t thr, vvp_code_t cp) return true; } +bool of_CAST2(vthread_t thr, vvp_code_t cp) +{ + unsigned dst = cp->bit_idx[0]; + unsigned src = cp->bit_idx[1]; + unsigned wid = cp->number; + + thr_check_addr(thr, dst+wid-1); + thr_check_addr(thr, src+wid-1); + + vvp_vector4_t res; + switch (src) { + case 0: + case 2: + case 3: + res = vvp_vector4_t(wid, BIT4_0); + break; + case 1: + res = vvp_vector4_t(wid, BIT4_1); + break; + default: + res = vector2_to_vector4(vvp_vector2_t(vthread_bits_to_vector(thr, src, wid)), wid); + break; + } + + thr->bits4.set_vec(dst, res); + return true; +} + bool of_CMPS(vthread_t thr, vvp_code_t cp) { vvp_bit4_t eq = BIT4_1;