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:
parent
2bef6b8624
commit
a337a9388b
16
elab_lval.cc
16
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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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} },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue