diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index e01fbb97d..25cff0ae5 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -107,23 +107,71 @@ unsigned long get_number_immediate(ivl_expr_t ex) return imm; } +static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) +{ + switch (ivl_expr_type(expr)) { + + case IVL_EX_NUMBER: { + unsigned value = 0; + unsigned idx, nbits = ivl_expr_width(expr); + const char*bits = ivl_expr_bits(expr); + + for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) { + + case '0': + break; + case '1': + assert(idx < (8*sizeof value)); + value |= 1 << idx; + break; + default: + assert(0); + } + + fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value); + break; + } + + case IVL_EX_ULONG: + fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr)); + break; + + case IVL_EX_SIGNAL: { + ivl_signal_t sig = ivl_expr_signal(expr); + unsigned word = 0; + if (ivl_signal_array_count(sig) > 1) { + ivl_expr_t ixe = ivl_expr_oper1(expr); + assert(number_is_immediate(ixe, 8*sizeof(unsigned long))); + word = get_number_immediate(ixe); + } + fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); + break; + } + + default: { + struct vector_info rv; + rv = draw_eval_expr(expr, 0); + fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", + ix, rv.base, rv.wid); + clr_vector(rv); + break; + } + } +} + /* * This function, in addition to setting the value into index 0, sets * bit 4 to 1 if the value is unknown. */ void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix) { - struct vector_info vec; int word; switch (ivl_expr_value(expr)) { case IVL_VT_BOOL: case IVL_VT_LOGIC: - vec = draw_eval_expr(expr, 0); - fprintf(vvp_out, " %%ix/get %u, %u, %u;\n", - ix, vec.base, vec.wid); - clr_vector(vec); + eval_logic_into_integer(expr, ix); break; case IVL_VT_REAL: @@ -954,43 +1002,7 @@ static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid) /* Figure out the shift amount and load that into the index register. The value may be a constant, or may need to be evaluated at run time. */ - switch (ivl_expr_type(re)) { - - case IVL_EX_NUMBER: { - unsigned shift = 0; - unsigned idx, nbits = ivl_expr_width(re); - const char*bits = ivl_expr_bits(re); - - for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) { - - case '0': - break; - case '1': - assert(idx < (8*sizeof shift)); - shift |= 1 << idx; - break; - default: - assert(0); - } - - fprintf(vvp_out, " %%ix/load 0, %u;\n", shift); - break; - } - - case IVL_EX_ULONG: - fprintf(vvp_out, " %%ix/load 0, %lu;\n", ivl_expr_uvalue(re)); - break; - - default: { - struct vector_info rv; - rv = draw_eval_expr(re, 0); - fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", - rv.base, rv.wid); - clr_vector(rv); - break; - } - } - + eval_logic_into_integer(re,0); fprintf(vvp_out, " %s/i0 %u, %u;\n", opcode, lv.base, lv.wid); @@ -1850,11 +1862,14 @@ static struct vector_info draw_select_signal(ivl_expr_t sube, use_word = get_number_immediate(ix); } +#if 0 shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO); - fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid); if (shiv.base >= 8) clr_vector(shiv); +#else + draw_eval_expr_into_integer(bit_idx, 0); +#endif /* Try the special case that the base is 0 and the width exactly matches the signal. Just load the signal in one diff --git a/vvp/codes.h b/vvp/codes.h index 3e8bd4335..1a82b2ad1 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -81,6 +81,7 @@ extern bool of_FORK(vthread_t thr, vvp_code_t code); extern bool of_INV(vthread_t thr, vvp_code_t code); extern bool of_IX_ADD(vthread_t thr, vvp_code_t code); extern bool of_IX_GET(vthread_t thr, vvp_code_t code); +extern bool of_IX_GETV(vthread_t thr, vvp_code_t code); extern bool of_IX_GET_S(vthread_t thr, vvp_code_t code); extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code); extern bool of_IX_MUL(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 6fae6ded4..39bc2b063 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -127,6 +127,7 @@ const static struct opcode_table_s opcode_table[] = { { "%inv", of_INV, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%ix/add", of_IX_ADD, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, + { "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, { "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index ae3b420bb..2d087dcd1 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -333,6 +333,11 @@ bits. 5: (reserved) 6: (reserved) +* %ix/getv , + +This instruction is like the %ix/get instruction, except that is reads +directly from a functor label instead of from thread bits. It sets +bits 4/5/6 just line %ix/get. * %ix/load , @@ -416,6 +421,13 @@ from the least significant up to bits, is loaded starting at thread bit . It is an error for the width to not match the vector width at the functor. +* %load/vp0 , , + +This instruction is the same as %load/v above, except that it also +adds the integer value is index register 0 into the loaded value. The +addition is a verilog-style add, which means that if any of the input +bits are X or Z, the entire result is turned into a vector of X bits. + * %load/wr , This instruction reads a real value from the vpi-like object to a word diff --git a/vvp/vthread.cc b/vvp/vthread.cc index abfd580b7..855381e96 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1947,6 +1947,32 @@ bool of_IX_GET_S(vthread_t thr, vvp_code_t cp) return true; } +bool of_IX_GETV(vthread_t thr, vvp_code_t cp) +{ + unsigned index = cp->bit_idx[0]; + vvp_net_t*net = cp->net; + + vvp_fun_signal_vec*sig = dynamic_cast(net->fun); + if (sig == 0) { + cerr << "%%ix/getv error: Net arg not a vector signal? " + << typeid(*net->fun).name() << endl; + } + assert(sig); + + vvp_vector4_t vec = sig->vec4_value(); + unsigned long val; + bool known_flag = vector4_to_value(vec, val); + + if (known_flag) + thr->words[index].w_int = val; + else + thr->words[index].w_int = 0; + + /* Set bit 4 as a flag if the input is unknown. */ + thr_put_bit(thr, 4, known_flag? BIT4_0 : BIT4_1); + + return true; +} /* * The various JMP instruction work simply by pulling the new program