diff --git a/tgt-vvp/eval_vec4.c b/tgt-vvp/eval_vec4.c index 1b7a26025..a23e563a4 100644 --- a/tgt-vvp/eval_vec4.c +++ b/tgt-vvp/eval_vec4.c @@ -192,6 +192,9 @@ static void draw_binary_vec4_compare_class(ivl_expr_t expr) return; } + /* A signal/variable is compared to null. Implement this with + the %test_nul statement, which peeks at the variable + contents directly. */ if (ivl_expr_type(re)==IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_SIGNAL) { ivl_signal_t sig= ivl_expr_signal(le); @@ -210,8 +213,33 @@ static void draw_binary_vec4_compare_class(ivl_expr_t expr) return; } + if (ivl_expr_type(re)==IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_PROPERTY) { + ivl_signal_t sig = ivl_expr_signal(le); + unsigned pidx = ivl_expr_property_idx(le); + ivl_expr_t idx_expr = ivl_expr_oper1(le); + int idx = 0; + + /* If the property has an array index, then evaluate it + into an index register. */ + if ( idx_expr ) { + idx = allocate_word(); + draw_eval_expr_into_integer(idx_expr, idx); + } + + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%test_nul/prop %u, %d;\n", pidx, idx); + fprintf(vvp_out, " %%pop/obj 1, 0;\n"); + fprintf(vvp_out, " %%flag_get/vec4 4;\n"); + if (ivl_expr_opcode(expr) == 'n') + fprintf(vvp_out, " %%inv;\n"); + + if (idx != 0) clr_word(idx); + return; + } + fprintf(stderr, "SORRY: Compare class handles not implemented\n"); - fprintf(vvp_out, " ; XXXX compare class handles.\n"); + fprintf(vvp_out, " ; XXXX compare class handles. re-type=%d, le-type=%d\n", + ivl_expr_type(re), ivl_expr_type(le)); vvp_errors += 1; } diff --git a/vvp/codes.h b/vvp/codes.h index 918a2d106..38735fcae 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -245,6 +245,7 @@ extern bool of_SUBSTR_VEC4(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL_A(vthread_t thr, vvp_code_t code); extern bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t code); +extern bool of_TEST_NUL_PROP(vthread_t thr, vvp_code_t code); extern bool of_VPI_CALL(vthread_t thr, vvp_code_t code); extern bool of_WAIT(vthread_t thr, vvp_code_t code); extern bool of_WAIT_FORK(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 3ccd97d68..b03af1878 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -234,7 +234,7 @@ static const struct opcode_table_s opcode_table[] = { { "%pow", of_POW, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%pow/s", of_POW_S, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} }, - { "%prop/obj",of_PROP_OBJ,1, {OA_NUMBER, OA_NONE, OA_NONE} }, + { "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} }, { "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} }, { "%prop/v", of_PROP_V, 1, {OA_NUMBER, OA_NONE, OA_NONE} }, @@ -289,9 +289,10 @@ static const struct opcode_table_s opcode_table[] = { { "%subi", of_SUBI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%substr", of_SUBSTR, 2,{OA_BIT1, OA_BIT2, OA_NONE} }, { "%substr/vec4",of_SUBSTR_VEC4,2,{OA_BIT1, OA_BIT2, OA_NONE} }, - { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, - { "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, - { "%test_nul/obj",of_TEST_NUL_OBJ,0,{OA_NONE, OA_NONE, OA_NONE} }, + { "%test_nul", of_TEST_NUL, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} }, + { "%test_nul/a", of_TEST_NUL_A, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} }, + { "%test_nul/obj", of_TEST_NUL_OBJ, 0,{OA_NONE, OA_NONE, OA_NONE} }, + { "%test_nul/prop",of_TEST_NUL_PROP,2,{OA_NUMBER, OA_BIT1, OA_NONE} }, { "%wait", of_WAIT, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} }, { "%wait/fork",of_WAIT_FORK,0,{OA_NONE, OA_NONE, OA_NONE} }, { "%xnor", of_XNOR, 0, {OA_NONE, OA_NONE, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 078526c07..1be613dd8 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1046,7 +1046,7 @@ This opcode raises the left operand by the right operand, and pushes the result. * %prop/v -* %prop/obj +* %prop/obj , * %prop/r * %prop/str @@ -1362,6 +1362,7 @@ The string value is NOT popped. * %test_nul * %test_nul/obj +* %test_nul/prop , This instruction tests the contents of the addressed variable to see if it is null. If it is, set flag bit 4 to 1. Otherwise, set flag bit @@ -1370,6 +1371,10 @@ if it is null. If it is, set flag bit 4 to 1. Otherwise, set flag bit The %test_null/obj tests the object on the top of the stack, instead of any variable. The value in the stack is NOT popped. +The %test_nul/prop instruction tests an object property for nul. The +object with the property is peeked from the top of the object stack, +and the is the array index if the property is an array of objects. + This is intended to implement the SystemVerilog expression (==null), where is a class variable. diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2d90abdfc..4ee00bab1 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -288,6 +288,8 @@ void vthread_s::debug_dump(ostream&fd, const char*label) fd << "**** vec4 stack..." << endl; for (size_t idx = stack_vec4_.size() ; idx > 0 ; idx -= 1) fd << " " << (stack_vec4_.size()-idx) << ": " << stack_vec4_[idx-1] << endl; + fd << "**** str stack (" << stack_str_.size() << ")..." << endl; + fd << "**** obj stack (" << stack_obj_size_ << ")..." << endl; fd << "**** Done ****" << endl; } @@ -6642,6 +6644,33 @@ bool of_TEST_NUL_OBJ(vthread_t thr, vvp_code_t) return true; } +/* + * %test_nul/prop , + */ +bool of_TEST_NUL_PROP(vthread_t thr, vvp_code_t cp) +{ + unsigned pid = cp->number; + unsigned idx = cp->bit_idx[0]; + + if (idx != 0) { + assert(idx < vthread_s::WORDS_COUNT); + idx = thr->words[idx].w_uint; + } + + vvp_object_t&obj = thr->peek_object(); + vvp_cobject*cobj = obj.peek(); + + vvp_object_t val; + cobj->get_object(pid, val, idx); + + if (val.test_nil()) + thr->flags[4] = BIT4_1; + else + thr->flags[4] = BIT4_0; + + return true; +} + bool of_VPI_CALL(vthread_t thr, vvp_code_t cp) { vpip_execute_vpi_call(thr, cp->handle);