diff --git a/elab_lval.cc b/elab_lval.cc index f3e56ed82..d9ad749a4 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -413,6 +413,22 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, lv->set_part(mux, lwid); } + } else if (reg->data_type() == IVL_VT_STRING) { + // Special case: This is a select of a string + // variable. The target of the assignment is a character + // select of a string. Force the r-value to be an 8bit + // vector and set the "part" to be the character select + // expression. The code generator knows what to do with + // this. + if (debug_elaborate) { + cerr << get_fileline() << ": debug: " + << "Bit select of string becomes character select." << endl; + } + if (mux) + lv->set_part(mux, 8); + else + lv->set_part(new NetEConst(verinum(lsb)), 8); + } else if (mux) { // Non-constant bit mux. Correct the mux for the range // of the vector, then set the l-value part select diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 93bd3099c..eaea27751 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -176,7 +176,9 @@ static void show_select_expression(ivl_expr_t net, unsigned ind) /* If the sub-expression is a STRING, then this is a substring and the code generator will handle it differently. */ - fprintf(out, "%*s\n", ind, "", width); + fprintf(out, "%*s\n", ind, "", width, width/8); + if (width%8 != 0) + fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, "", width); show_expression(oper1, ind+3); show_expression(oper2, ind+3); diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 7fe568a4d..619c058af 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -181,6 +181,12 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL && ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0; + /* If the expression is a substring expression, then + the xPV method of passing the argument will not work + and we have to resort to the default method. */ + if (ivl_expr_value(vexpr) == IVL_VT_STRING) + return 0; + /* The signal is part of an array. */ /* Add &APV<> code here when it is finished. */ bexpr = ivl_expr_oper2(expr); diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 3ef0d8cbe..c1f7abc4a 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -735,15 +735,34 @@ static int show_stmt_assign_sig_string(ivl_statement_t net) { ivl_lval_t lval = ivl_stmt_lval(net, 0); ivl_expr_t rval = ivl_stmt_rval(net); - ivl_signal_t var; + ivl_expr_t part = ivl_lval_part_off(lval); + ivl_signal_t var= ivl_lval_sig(lval); + assert(ivl_stmt_lvals(net) == 1); assert(ivl_stmt_opcode(net) == 0); + assert(ivl_lval_mux(lval) == 0); - var = ivl_lval_sig(lval); + /* Simplest case: no mux. Evaluate the r-value as a string and + store the result into the variable. Note that the + %store/str opcode pops the string result. */ + if (part == 0) { + draw_eval_string(rval); + fprintf(vvp_out, " %%store/str v%p_0;\n", var); + return 0; + } - draw_eval_string(rval); - fprintf(vvp_out, " %%store/str v%p_0;\n", var); + /* Calculate the character select for the word. */ + int mux_word = allocate_word(); + draw_eval_expr_into_integer(part, mux_word); + /* Evaluate the r-value as a vector. */ + struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ); + + assert(rvec.wid == 8); + fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base); + + clr_vector(rvec); + clr_word(mux_word); return 0; } diff --git a/vvp/codes.h b/vvp/codes.h index c611ae28a..4a51bbe5a 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -155,6 +155,7 @@ extern bool of_POW_S(vthread_t thr, vvp_code_t code); extern bool of_POW_WR(vthread_t thr, vvp_code_t code); extern bool of_PUSHI_STR(vthread_t thr, vvp_code_t code); extern bool of_PUSHV_STR(vthread_t thr, vvp_code_t code); +extern bool of_PUTC_STR_V(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index bb41277e4..0bafc3218 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -203,6 +203,7 @@ static const struct opcode_table_s opcode_table[] = { { "%pow/wr", of_POW_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%pushi/str",of_PUSHI_STR,1,{OA_STRING, OA_NONE, OA_NONE} }, { "%pushv/str", of_PUSHV_STR, 2, {OA_BIT1,OA_BIT2, OA_NONE} }, + { "%putc/str/v",of_PUTC_STR_V,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, diff --git a/vvp/vthread.cc b/vvp/vthread.cc index e4327d724..5c3ea7987 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -4279,6 +4279,55 @@ bool of_PUSHV_STR(vthread_t thr, vvp_code_t cp) return true; } +/* + * %putc/str/v , , + */ +bool of_PUTC_STR_V(vthread_t thr, vvp_code_t cp) +{ + unsigned muxr = cp->bit_idx[0]; + unsigned base = cp->bit_idx[1]; + + /* The mux is the index into the string. If it is <0, then + this operation cannot possible effect the string, so we are + done. */ + assert(muxr < 16); + int32_t mux = thr->words[muxr].w_int; + if (mux < 0) + return true; + + /* Extract the character from the vector space. If that byte + is null (8'hh00) then there is nothing more to do. */ + unsigned long*tmp = vector_to_array(thr, base, 8); + if (tmp == 0) + return true; + if (tmp[0] == 0) + return true; + + char tmp_val = tmp[0]&0xff; + + /* Get the existing value of the string. If we find that the + index is too big for the string, then give up. */ + vvp_net_t*net = cp->net; + vvp_fun_signal_string*fun = dynamic_cast (net->fun); + assert(fun); + + string val = fun->get_string(); + if (val.size() <= (size_t)mux) + return true; + + /* If the value to write is the same as the destination, then + stop now. */ + if (val[mux] == tmp_val) + return true; + + /* Finally, modify the string and write the new string to the + variable so that the new value propagates. */ + val[mux] = tmp_val; + vvp_send_string(vvp_net_ptr_t(cp->net, 0), val, thr->wt_context); + + return true; +} + /* * These implement the %release/net and %release/reg instructions. The * %release/net instruction applies to a net kind of functor by