Fix using array elements in expressions with an array element lval.
When you have an expression like this (extreme example): a[idx[1]][idx[2]*4 +: 4] <= #(idx[3]) 4'ha; where a is a reg array and idx is a reg or net array. The retrieval of idx[2] was clobbering index register 3, which was set before evaluating the part offset expression, then used in the %set/av of the array value. (likewise for idx[1] and idx[3]]) To avoid this issue, this patch adds and uses a new instruction %ix/mov which simply copies one indexed register to another. When necessary, expressions are first evaluated into temporary registers to avoid clobbering, then moved in to place before the %*/av instruction.
This commit is contained in:
parent
ec8081f983
commit
51ca2d1243
|
|
@ -380,13 +380,18 @@ static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
|||
/* Here we have a part select write into an array word. */
|
||||
unsigned skip_set = transient_id++;
|
||||
if (word_ix) {
|
||||
int part_off_reg = allocate_word();
|
||||
draw_eval_expr_into_integer(part_off_ex, part_off_reg);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/mov 1, %u;\n", part_off_reg);
|
||||
clr_word(part_off_reg);
|
||||
} else {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
||||
}
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
||||
sig, bit, wid);
|
||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
||||
|
|
|
|||
|
|
@ -46,15 +46,22 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
ivl_expr_t dexp, unsigned nevents)
|
||||
{
|
||||
unsigned end_assign = transient_id++;
|
||||
int word_ix_reg = 3;
|
||||
|
||||
/* if we have to evaluate a delay expression, evaluate word index into
|
||||
temp register */
|
||||
if (dexp != 0) {
|
||||
word_ix_reg = allocate_word();
|
||||
}
|
||||
|
||||
/* This code is common to all the different types of array delays. */
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
|
||||
get_number_immediate(word_ix));
|
||||
fprintf(vvp_out, " %%ix/load %u, %lu, 0; address\n",
|
||||
word_ix_reg, get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
draw_eval_expr_into_integer(word_ix, word_ix_reg);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
unsigned do_assign = transient_id++;
|
||||
fprintf(vvp_out, " %%jmp/0 t_%u, 4;\n", do_assign);
|
||||
|
|
@ -67,8 +74,10 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
fprintf(vvp_out, " %%ix/mov 3, %u;\n", word_ix_reg);
|
||||
fprintf(vvp_out, " %%assign/ar/d v%p, %d;\n", lsig,
|
||||
delay_index);
|
||||
clr_word(word_ix_reg);
|
||||
clr_word(delay_index);
|
||||
} else if (nevents != 0) {
|
||||
/* Event control delay... */
|
||||
|
|
@ -107,8 +116,11 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
unsigned nevents)
|
||||
{
|
||||
unsigned skip_assign = transient_id++;
|
||||
|
||||
int word_ix_reg = 3;
|
||||
int part_off_reg = 1;
|
||||
int delay_index;
|
||||
unsigned long part_off = 0;
|
||||
|
||||
if (part_off_ex == 0) {
|
||||
part_off = 0;
|
||||
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
||||
|
|
@ -117,34 +129,54 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
part_off_ex = 0;
|
||||
}
|
||||
|
||||
if (dexp != 0) {
|
||||
word_ix_reg = allocate_word();
|
||||
part_off_reg = allocate_word();
|
||||
} else if (part_off_ex) {
|
||||
word_ix_reg = allocate_word();
|
||||
}
|
||||
|
||||
/* This code is common to all the different types of array delays. */
|
||||
if (number_is_immediate(word_ix, IMM_WID, 0) &&
|
||||
!number_is_unknown(word_ix)) {
|
||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0; address\n",
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, 0; address\n", word_ix_reg,
|
||||
get_number_immediate(word_ix));
|
||||
} else {
|
||||
/* Calculate array word index into index register 3 */
|
||||
draw_eval_expr_into_integer(word_ix, 3);
|
||||
/* Calculate array word index into word index register */
|
||||
draw_eval_expr_into_integer(word_ix, word_ix_reg);
|
||||
/* Skip assignment if word expression is not defined. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
}
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u, 0; word width\n", width);
|
||||
if (part_off_ex) {
|
||||
draw_eval_expr_into_integer(part_off_ex, 1);
|
||||
draw_eval_expr_into_integer(part_off_ex, part_off_reg);
|
||||
/* If the index expression has XZ bits, skip the assign. */
|
||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_assign);
|
||||
if (dexp == 0) {
|
||||
fprintf(vvp_out, " %%ix/mov 3, %u;\n", word_ix_reg);
|
||||
clr_word(word_ix_reg);
|
||||
}
|
||||
} else {
|
||||
/* Store word part select into index 1 */
|
||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0; part off\n", part_off);
|
||||
/* Store word part select into part_off_reg */
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, 0; part off\n",
|
||||
part_off_reg, part_off);
|
||||
}
|
||||
|
||||
if (dexp != 0) {
|
||||
/* Calculated delay... */
|
||||
int delay_index = allocate_word();
|
||||
delay_index = allocate_word();
|
||||
draw_eval_expr_into_integer(dexp, delay_index);
|
||||
}
|
||||
|
||||
/* Store expression width into index word 0 */
|
||||
fprintf(vvp_out, " %%ix/load 0, %u, 0; word width\n", width);
|
||||
|
||||
if (dexp != 0) {
|
||||
fprintf(vvp_out, " %%ix/mov 1, %u;\n", part_off_reg);
|
||||
fprintf(vvp_out, " %%ix/mov 3, %u;\n", word_ix_reg);
|
||||
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
|
||||
delay_index, bit);
|
||||
clr_word(part_off_reg);
|
||||
clr_word(word_ix_reg);
|
||||
clr_word(delay_index);
|
||||
} else if (nevents != 0) {
|
||||
/* Event control delay... */
|
||||
|
|
@ -159,7 +191,7 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
|||
* delay we need to put it into an index register.
|
||||
*/
|
||||
if (hig_d != 0) {
|
||||
int delay_index = allocate_word();
|
||||
delay_index = allocate_word();
|
||||
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n",
|
||||
delay_index, low_d, hig_d);
|
||||
fprintf(vvp_out, " %%assign/av/d v%p, %d, %u;\n", lsig,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ 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);
|
||||
extern bool of_IX_SUB(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_IX_MOV(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%ix/getv/s",of_IX_GETV_S,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} },
|
||||
{ "%ix/load",of_IX_LOAD,3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/mov", of_IX_MOV, 2, {OA_BIT1, OA_BIT2, OA_NONE} },
|
||||
{ "%ix/mul", of_IX_MUL, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%ix/sub", of_IX_SUB, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%jmp", of_JMP, 1, {OA_CODE_PTR, OA_NONE, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -553,6 +553,10 @@ register by the immediate value. The 64 bit immediate value is built
|
|||
from the two 32 bit chunks <low> and <high> (see %ix/load above).
|
||||
The <idx> value selects the index register.
|
||||
|
||||
* %ix/mov <dst>, <src>
|
||||
|
||||
This instruction simply sets the index register <dst> to the value of
|
||||
the index register <src>.
|
||||
|
||||
* %jmp <code-label>
|
||||
|
||||
|
|
|
|||
|
|
@ -2828,6 +2828,12 @@ bool of_IX_LOAD(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_IX_MOV(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
thr->words[cp->bit_idx[0]].w_int = thr->words[cp->bit_idx[1]].w_int;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load a vector into an index register. The format of the
|
||||
* opcode is:
|
||||
|
|
|
|||
Loading…
Reference in New Issue