From 51ca2d12430c22a96636c856f1eb1373405ea2c6 Mon Sep 17 00:00:00 2001 From: Jared Casper Date: Tue, 30 Jul 2013 23:20:37 -0700 Subject: [PATCH] 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. --- tgt-vvp/stmt_assign.c | 9 +++++-- tgt-vvp/vvp_process.c | 60 +++++++++++++++++++++++++++++++++---------- vvp/codes.h | 1 + vvp/compile.cc | 1 + vvp/opcodes.txt | 4 +++ vvp/vthread.cc | 6 +++++ 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 430f61a42..a54c61feb 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -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); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 81c33d340..bfaa9ff83 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -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, diff --git a/vvp/codes.h b/vvp/codes.h index dfcfec87e..4bd5243da 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -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); diff --git a/vvp/compile.cc b/vvp/compile.cc index 1a360ff91..56ef37aad 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -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} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index d34a098ae..69c72ab59 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -553,6 +553,10 @@ register by the immediate value. The 64 bit immediate value is built from the two 32 bit chunks and (see %ix/load above). The value selects the index register. +* %ix/mov , + +This instruction simply sets the index register to the value of +the index register . * %jmp diff --git a/vvp/vthread.cc b/vvp/vthread.cc index b66928fe7..38d133774 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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: