Handle string[x] in l-values and system function arguments

When string[x] is an l-value, generate code to implement something
like the string.putc(x, ...) method.

Also handle when string[x] is the argument of a system task. In that
case resort to treating it as a calculated 8-bit vector, because that
is what it is.
This commit is contained in:
Stephen Williams 2012-07-01 11:44:47 -07:00
parent 2bef6b8624
commit a337a9388b
7 changed files with 99 additions and 5 deletions

View File

@ -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

View File

@ -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<substring: width=%u/8>\n", ind, "", width);
fprintf(out, "%*s<substring: width=%u bits, %u bytes>\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);

View File

@ -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);

View File

@ -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;
}
/* 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;
}

View File

@ -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);

View File

@ -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} },

View File

@ -4279,6 +4279,55 @@ bool of_PUSHV_STR(vthread_t thr, vvp_code_t cp)
return true;
}
/*
* %putc/str/v <var>, <muxr>, <base>
*/
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<vvp_fun_signal_string*> (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