Remove dead code for allocate_vec handling.
This commit is contained in:
parent
e4b862f3d1
commit
62fce50f8c
|
|
@ -156,9 +156,6 @@ void draw_ufunc_vec4(ivl_expr_t expr)
|
||||||
/* Take in arguments to function and call function code. */
|
/* Take in arguments to function and call function code. */
|
||||||
draw_ufunc_preamble(expr);
|
draw_ufunc_preamble(expr);
|
||||||
|
|
||||||
/* Fresh basic block starts after the join. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
assert(ivl_signal_dimensions(retval) == 0);
|
assert(ivl_signal_dimensions(retval) == 0);
|
||||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", retval);
|
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", retval);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -323,222 +323,6 @@ static ivl_type_t draw_lval_expr(ivl_lval_t lval)
|
||||||
return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval));
|
return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void set_vec_to_lval_slice_nest(ivl_lval_t lval, unsigned bit, unsigned wid)
|
|
||||||
{
|
|
||||||
ivl_lval_t lval_nest = ivl_lval_nest(lval);
|
|
||||||
ivl_type_t ltype = draw_lval_expr(lval_nest);
|
|
||||||
assert(ivl_type_base(ltype) == IVL_VT_CLASS);
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n",
|
|
||||||
ivl_lval_property_idx(lval), bit, wid);
|
|
||||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
|
|
||||||
{
|
|
||||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
|
||||||
ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
|
|
||||||
unsigned long part_off = 0;
|
|
||||||
|
|
||||||
/* Although Verilog doesn't support it, we'll handle
|
|
||||||
here the case of an l-value part select of an array
|
|
||||||
word if the address is constant. */
|
|
||||||
ivl_expr_t word_ix = ivl_lval_idx(lval);
|
|
||||||
unsigned long use_word = 0;
|
|
||||||
|
|
||||||
/* If the l-value is nested, then it is something like a class
|
|
||||||
with a chain of member names, so handle that elsewhere. */
|
|
||||||
if (ivl_lval_nest(lval)) {
|
|
||||||
set_vec_to_lval_slice_nest(lval, bit, wid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part_off_ex == 0) {
|
|
||||||
part_off = 0;
|
|
||||||
} else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
|
|
||||||
!number_is_unknown(part_off_ex)) {
|
|
||||||
part_off = get_number_immediate(part_off_ex);
|
|
||||||
part_off_ex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the word index is a constant expression, then evaluate
|
|
||||||
it to select the word, and pay no further heed to the
|
|
||||||
expression itself. Out-of-bounds and undefined indices are
|
|
||||||
converted to a canonical index of 'bx during elaboration,
|
|
||||||
and we don't try to optimise that case. */
|
|
||||||
if (word_ix && number_is_immediate(word_ix, IMM_WID, 0) &&
|
|
||||||
!number_is_unknown(word_ix)) {
|
|
||||||
use_word = get_number_immediate(word_ix);
|
|
||||||
assert(use_word < ivl_signal_array_count(sig));
|
|
||||||
word_ix = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (part_off_ex && ivl_signal_dimensions(sig) == 0) {
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
|
|
||||||
/* There is a mux expression, so this must be a write to
|
|
||||||
a bit-select l-val. Presumably, the x0 index register
|
|
||||||
has been loaded wit the result of the evaluated
|
|
||||||
part select base expression. */
|
|
||||||
assert(!word_ix);
|
|
||||||
|
|
||||||
draw_eval_expr_into_integer(part_off_ex, 0);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
} else if (part_off_ex && ivl_signal_dimensions(sig) > 0) {
|
|
||||||
|
|
||||||
/* 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, %d;\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);
|
|
||||||
}
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
|
|
||||||
} else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig))
|
|
||||||
&& ivl_signal_dimensions(sig) > 0) {
|
|
||||||
|
|
||||||
/* Here we have a part select write into an array word. */
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
if (word_ix) {
|
|
||||||
draw_eval_expr_into_integer(word_ix, 3);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
} else {
|
|
||||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
|
||||||
}
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
if (word_ix) /* Only need this label if word_ix is set. */
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
|
|
||||||
} else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
|
|
||||||
/* There is no mux expression, but a constant part
|
|
||||||
offset. Load that into index x0 and generate a
|
|
||||||
vector set instruction. */
|
|
||||||
assert(ivl_lval_width(lval) == wid);
|
|
||||||
|
|
||||||
/* If the word index is a constant, then we can write
|
|
||||||
directly to the word and save the index
|
|
||||||
calculation. Also, note the special case that we are
|
|
||||||
writing to a UWIRE. In that case, use the %force/x0
|
|
||||||
instruction to get the desired effect. */
|
|
||||||
if (word_ix == 0 && ivl_signal_type(sig)==IVL_SIT_UWIRE) {
|
|
||||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%force/x0 v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
|
|
||||||
} else if (word_ix == 0) {
|
|
||||||
fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
unsigned index_reg = 3;
|
|
||||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
}
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
} else if (ivl_signal_dimensions(sig) > 0) {
|
|
||||||
|
|
||||||
/* If the word index is a constant, then we can write
|
|
||||||
directly to the word and save the index calculation. */
|
|
||||||
if (word_ix == 0) {
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
|
||||||
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
unsigned skip_set = transient_id++;
|
|
||||||
unsigned index_reg = 3;
|
|
||||||
draw_eval_expr_into_integer(word_ix, index_reg);
|
|
||||||
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
|
|
||||||
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
|
|
||||||
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
|
|
||||||
sig, bit, wid);
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", skip_set);
|
|
||||||
}
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n",
|
|
||||||
sig, use_word, bit, wid);
|
|
||||||
/* save_signal width of 0 CLEARS the signal from the
|
|
||||||
lookaside. */
|
|
||||||
save_signal_lookaside(bit, sig, use_word, 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if 0
|
|
||||||
/*
|
|
||||||
* This is a private function to generate %set code for the
|
|
||||||
* statement. At this point, the r-value is evaluated and stored in
|
|
||||||
* the res vector, I just need to generate the %set statements for the
|
|
||||||
* l-values of the assignment.
|
|
||||||
*/
|
|
||||||
static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
|
|
||||||
{
|
|
||||||
unsigned wid = res.wid;
|
|
||||||
unsigned lidx;
|
|
||||||
unsigned cur_rbit = 0;
|
|
||||||
|
|
||||||
for (lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) {
|
|
||||||
unsigned bidx;
|
|
||||||
unsigned bit_limit = wid - cur_rbit;
|
|
||||||
|
|
||||||
ivl_lval_t lval = ivl_stmt_lval(net, lidx);
|
|
||||||
|
|
||||||
/* Reduce bit_limit to the width of this l-value. */
|
|
||||||
if (bit_limit > ivl_lval_width(lval))
|
|
||||||
bit_limit = ivl_lval_width(lval);
|
|
||||||
|
|
||||||
/* This is the address within the larger r-value of the
|
|
||||||
bit that this l-value takes. */
|
|
||||||
bidx = res.base < 4? res.base : (res.base+cur_rbit);
|
|
||||||
|
|
||||||
set_vec_to_lval_slice(lval, bidx, bit_limit);
|
|
||||||
|
|
||||||
/* Now we've consumed this many r-value bits for the
|
|
||||||
current l-value. */
|
|
||||||
cur_rbit += bit_limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store a vector from the vec4 stack to the statement l-values. This
|
* Store a vector from the vec4 stack to the statement l-values. This
|
||||||
* all assumes that the value to be assigned is already on the top of
|
* all assumes that the value to be assigned is already on the top of
|
||||||
|
|
|
||||||
175
tgt-vvp/vector.c
175
tgt-vvp/vector.c
|
|
@ -18,178 +18,3 @@
|
||||||
|
|
||||||
# include "vvp_priv.h"
|
# include "vvp_priv.h"
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
|
||||||
/* Maximum vector bits in a thread. If a thread co-processor is
|
|
||||||
* implemented, this value may need to be reduced. At that time
|
|
||||||
* wider operations will need to be partitioned. For example
|
|
||||||
* shift operations on WIDE (say > 64k bit) registers.
|
|
||||||
*/
|
|
||||||
#define MAX_VEC (256*1024)
|
|
||||||
|
|
||||||
static struct allocation_score_s {
|
|
||||||
ivl_expr_t exp;
|
|
||||||
ivl_signal_t sig;
|
|
||||||
unsigned sig_word;
|
|
||||||
unsigned exp_bit : 24;
|
|
||||||
unsigned sig_bit : 24;
|
|
||||||
unsigned alloc : 8;
|
|
||||||
} allocation_map[MAX_VEC] = { {0, 0, 0, 0, 0, 0} };
|
|
||||||
|
|
||||||
/* This is the largest bit to have lookaside values. */
|
|
||||||
static unsigned lookaside_top = 0;
|
|
||||||
|
|
||||||
static __inline__ ivl_expr_t peek_exp(unsigned addr)
|
|
||||||
{
|
|
||||||
return allocation_map[addr].exp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ unsigned peek_exp_bit(unsigned addr)
|
|
||||||
{
|
|
||||||
return allocation_map[addr].exp_bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void set_exp(unsigned addr, ivl_expr_t expr, unsigned ebit)
|
|
||||||
{
|
|
||||||
allocation_map[addr].exp = expr;
|
|
||||||
allocation_map[addr].exp_bit = ebit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static __inline__ void set_sig(unsigned addr, ivl_signal_t expr,
|
|
||||||
unsigned sig_word, unsigned ebit)
|
|
||||||
{
|
|
||||||
allocation_map[addr].sig = expr;
|
|
||||||
allocation_map[addr].sig_word = sig_word;
|
|
||||||
allocation_map[addr].sig_bit = ebit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This clears a vector that was previously allocated by
|
|
||||||
* allocate_vector. That is, it unmarks all the bits of the map that
|
|
||||||
* represent this vector.
|
|
||||||
*
|
|
||||||
* If the vector is based in one of 4 constant bit values, then there
|
|
||||||
* are no bits to clear. If the vector is based in the 4-8 result
|
|
||||||
* area, then someone is broken.
|
|
||||||
*/
|
|
||||||
void clr_vector(struct vector_info vec)
|
|
||||||
{
|
|
||||||
unsigned idx;
|
|
||||||
if (vec.base < 4)
|
|
||||||
return;
|
|
||||||
assert(vec.base >= 8);
|
|
||||||
for (idx = 0 ; idx < vec.wid ; idx += 1) {
|
|
||||||
assert( allocation_map[vec.base+idx].alloc > 0);
|
|
||||||
allocation_map[vec.base+idx].alloc -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static unsigned allocate_vector_no_lookaside(unsigned wid, int skip_lookaside)
|
|
||||||
{
|
|
||||||
unsigned base = 8;
|
|
||||||
unsigned idx = 0;
|
|
||||||
|
|
||||||
while (idx < wid) {
|
|
||||||
if (base+idx >= MAX_VEC)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
assert((base + idx) < MAX_VEC);
|
|
||||||
if ((allocation_map[base+idx].alloc > 0)
|
|
||||||
|| (skip_lookaside && peek_exp(base+idx))) {
|
|
||||||
base = base + idx + 1;
|
|
||||||
idx = 0;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (idx = 0 ; idx < wid ; idx += 1) {
|
|
||||||
allocation_map[base+idx].alloc += 1;
|
|
||||||
set_exp(base+idx, 0, 0);
|
|
||||||
set_sig(base+idx, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This unconditionally allocates a stretch of bits from the register
|
|
||||||
* set. It never returns a bit addressed <8 (0-3 are constant, 4-7 are
|
|
||||||
* condition codes).
|
|
||||||
*
|
|
||||||
* First try to allocate a vector without interfering with any bits
|
|
||||||
* cached by the lookaside buffer. If that doesn't work, then try
|
|
||||||
* again without worrying about trashing lookaside results. This
|
|
||||||
* should lead to preferentially allocating new bits instead of
|
|
||||||
* constantly overwriting intermediate results.
|
|
||||||
*
|
|
||||||
* If there is no space for a vector of the given width, then give up
|
|
||||||
* and return 0.
|
|
||||||
*/
|
|
||||||
unsigned allocate_vector(unsigned wid)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
unsigned base = allocate_vector_no_lookaside(wid, 1);
|
|
||||||
|
|
||||||
if (base == 0)
|
|
||||||
base = allocate_vector_no_lookaside(wid, 0);
|
|
||||||
return base;
|
|
||||||
#else
|
|
||||||
assert(0);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This clears the expression cache of the allocation map. It is
|
|
||||||
* called to prevent reuse of existing expressions, normally at the
|
|
||||||
* start of a basic block, but also at the end of thread processing.
|
|
||||||
*/
|
|
||||||
void clear_expression_lookaside(void)
|
|
||||||
{
|
|
||||||
unsigned idx;
|
|
||||||
|
|
||||||
for (idx = 0 ; idx < lookaside_top ; idx += 1) {
|
|
||||||
set_exp(idx, 0, 0);
|
|
||||||
set_sig(idx, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
lookaside_top = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void clear_signal_lookaside_bit(unsigned idx, ivl_signal_t sig, unsigned sig_word)
|
|
||||||
{
|
|
||||||
if (allocation_map[idx].alloc > 0)
|
|
||||||
return;
|
|
||||||
if (allocation_map[idx].sig != sig)
|
|
||||||
return;
|
|
||||||
if (allocation_map[idx].sig_word != sig_word)
|
|
||||||
return;
|
|
||||||
|
|
||||||
set_sig(idx, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_signal_lookaside(unsigned addr, ivl_signal_t sig, unsigned sig_word, unsigned wid)
|
|
||||||
{
|
|
||||||
unsigned idx;
|
|
||||||
/* Don't bind any of the low bits to a signal. */
|
|
||||||
if (addr < 8 && wid > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert((addr+wid) <= MAX_VEC);
|
|
||||||
|
|
||||||
for (idx = 8 ; idx < addr ; idx += 1)
|
|
||||||
clear_signal_lookaside_bit(idx, sig, sig_word);
|
|
||||||
|
|
||||||
for (idx = 0 ; idx < wid ; idx += 1)
|
|
||||||
set_sig(addr+idx, sig, sig_word, idx);
|
|
||||||
|
|
||||||
if ((addr+wid) > lookaside_top)
|
|
||||||
lookaside_top = addr+wid;
|
|
||||||
|
|
||||||
for (idx = addr+wid ; idx < lookaside_top ; idx += 1)
|
|
||||||
clear_signal_lookaside_bit(idx, sig, sig_word);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -207,57 +207,6 @@ extern const char*draw_input_from_net(ivl_nexus_t nex);
|
||||||
*/
|
*/
|
||||||
extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
||||||
|
|
||||||
/*
|
|
||||||
* These functions manage vector allocation in the thread register
|
|
||||||
* space. They presume that we work on one thread at a time, to
|
|
||||||
* completion.
|
|
||||||
*
|
|
||||||
* allocate_vector
|
|
||||||
* Return the base of an allocated vector in the thread. The bits
|
|
||||||
* are marked allocated in the process.
|
|
||||||
*
|
|
||||||
* clr_vector
|
|
||||||
* Clear a vector previously allocated.
|
|
||||||
*
|
|
||||||
* The thread vector allocator also keeps a lookaside of expression
|
|
||||||
* results that are stored in register bit. This lookaside can be used
|
|
||||||
* by the code generator to notice that certain expression bits are
|
|
||||||
* already calculated, and can be reused.
|
|
||||||
*
|
|
||||||
* clear_expression_lookaside
|
|
||||||
* Clear the lookaside tables for the current thread. This must be
|
|
||||||
* called before starting a new thread, and around basic blocks
|
|
||||||
* that are entered from unknown places.
|
|
||||||
*
|
|
||||||
* save_expression_lookaside
|
|
||||||
* Mark the given expression as available in the given register
|
|
||||||
* bits. This remains until the lookaside is cleared. This does not
|
|
||||||
* clear the allocation, it is still necessary to call clr_vector.
|
|
||||||
*
|
|
||||||
* save_signal_lookaside
|
|
||||||
* Mark the given signal as available in the given register bits.
|
|
||||||
* This is different from a given expression, in that the signal
|
|
||||||
* lookaside is in addition to the expression lookaside. The signal
|
|
||||||
* lookaside is specifically to save on unnecessary loads of a
|
|
||||||
* signal recently written.
|
|
||||||
*
|
|
||||||
* allocate_vector_exp
|
|
||||||
* This function attempts to locate the expression in the
|
|
||||||
* lookaside. If it finds it, return a reallocated base for the
|
|
||||||
* expression. Otherwise, return 0.
|
|
||||||
*
|
|
||||||
* The allocate_vector and allocate_vector_exp calls must have
|
|
||||||
* matching call to clr_vector. Although the allocate_vector will
|
|
||||||
* never reallocate a vector already allocated, the allocate_vector_exp
|
|
||||||
* might, so it is possible for allocations to nest in that
|
|
||||||
* manner. The exclusive_flag to allocate_vector_exp will prevent
|
|
||||||
* nested allocations. This is needed where the expression result is
|
|
||||||
* expected to be overwritten.
|
|
||||||
*/
|
|
||||||
extern unsigned allocate_vector(unsigned wid);
|
|
||||||
extern void clr_vector(struct vector_info vec);
|
|
||||||
|
|
||||||
extern void clear_expression_lookaside(void);
|
|
||||||
|
|
||||||
extern int number_is_unknown(ivl_expr_t ex);
|
extern int number_is_unknown(ivl_expr_t ex);
|
||||||
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
|
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,6 @@ static void assign_to_array_r_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||||
fprintf(vvp_out, "t_%u ;\n", end_assign);
|
fprintf(vvp_out, "t_%u ;\n", end_assign);
|
||||||
if (nevents != 0) fprintf(vvp_out, " %%evctl/c;\n");
|
if (nevents != 0) fprintf(vvp_out, " %%evctl/c;\n");
|
||||||
|
|
||||||
clear_expression_lookaside();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||||
|
|
@ -200,7 +199,6 @@ static void assign_to_array_word(ivl_signal_t lsig, ivl_expr_t word_ix,
|
||||||
clr_flag(error_flag);
|
clr_flag(error_flag);
|
||||||
if (part_off_reg)
|
if (part_off_reg)
|
||||||
clr_word(part_off_reg);
|
clr_word(part_off_reg);
|
||||||
clear_expression_lookaside();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -580,8 +578,7 @@ static int show_stmt_assign_nb(ivl_statement_t net)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{ struct vector_info res = {0,0};
|
{ unsigned wid;
|
||||||
unsigned wid;
|
|
||||||
unsigned lidx;
|
unsigned lidx;
|
||||||
unsigned cur_rbit = 0;
|
unsigned cur_rbit = 0;
|
||||||
/* Handle the special case that the expression is a real
|
/* Handle the special case that the expression is a real
|
||||||
|
|
@ -593,19 +590,7 @@ static int show_stmt_assign_nb(ivl_statement_t net)
|
||||||
assignment. */
|
assignment. */
|
||||||
wid = ivl_stmt_lwidth(net);
|
wid = ivl_stmt_lwidth(net);
|
||||||
|
|
||||||
res.base = allocate_vector(wid);
|
fprintf(vvp_out, " %%cvt/vr %u;\n", wid);
|
||||||
res.wid = wid;
|
|
||||||
|
|
||||||
if (res.base == 0) {
|
|
||||||
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
||||||
"Unable to allocate %u thread bits for "
|
|
||||||
"r-value expression.\n", ivl_expr_file(rval),
|
|
||||||
ivl_expr_lineno(rval), wid);
|
|
||||||
vvp_errors += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(vvp_out, " %%cvt/vr %u, %u;\n",
|
|
||||||
res.base, res.wid);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
wid = ivl_stmt_lwidth(net);
|
wid = ivl_stmt_lwidth(net);
|
||||||
|
|
@ -637,9 +622,6 @@ static int show_stmt_assign_nb(ivl_statement_t net)
|
||||||
cur_rbit += bit_limit;
|
cur_rbit += bit_limit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.base > 3)
|
|
||||||
clr_vector(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -679,17 +661,12 @@ static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
|
||||||
fprintf(vvp_out, " .scope S_%p;\n", subscope);
|
fprintf(vvp_out, " .scope S_%p;\n", subscope);
|
||||||
fprintf(vvp_out, "t_%u ;\n", sub_id);
|
fprintf(vvp_out, "t_%u ;\n", sub_id);
|
||||||
|
|
||||||
/* The statement within the fork is in a new thread, so no
|
|
||||||
expression lookaside is valid. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
rc = show_stmt_block(net, subscope);
|
rc = show_stmt_block(net, subscope);
|
||||||
fprintf(vvp_out, " %%end;\n");
|
fprintf(vvp_out, " %%end;\n");
|
||||||
/* Return to the previous scope. */
|
/* Return to the previous scope. */
|
||||||
fprintf(vvp_out, " .scope S_%p;\n", scope);
|
fprintf(vvp_out, " .scope S_%p;\n", scope);
|
||||||
|
|
||||||
fprintf(vvp_out, "t_%u %%join;\n", out_id);
|
fprintf(vvp_out, "t_%u %%join;\n", out_id);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
@ -775,7 +752,6 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx);
|
||||||
clear_expression_lookaside();
|
|
||||||
rc += show_statement(cst, sscope);
|
rc += show_statement(cst, sscope);
|
||||||
|
|
||||||
/* Statement is done, jump to the out of the case. */
|
/* Statement is done, jump to the out of the case. */
|
||||||
|
|
@ -791,8 +767,6 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
the stack, but we are done with it now. Pop it. */
|
the stack, but we are done with it now. Pop it. */
|
||||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||||
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -857,7 +831,6 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_base+idx);
|
||||||
clear_expression_lookaside();
|
|
||||||
rc += show_statement(cst, sscope);
|
rc += show_statement(cst, sscope);
|
||||||
|
|
||||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count,
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count,
|
||||||
|
|
@ -1277,16 +1250,13 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
if (ivl_stmt_cond_false(net)) {
|
if (ivl_stmt_cond_false(net)) {
|
||||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_out);
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_out);
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
rc += show_statement(ivl_stmt_cond_false(net), sscope);
|
rc += show_statement(ivl_stmt_cond_false(net), sscope);
|
||||||
|
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_false);
|
||||||
clear_expression_lookaside();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
@ -1312,8 +1282,6 @@ static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
show_stmt_file_line(net, "Delay statement.");
|
show_stmt_file_line(net, "Delay statement.");
|
||||||
|
|
||||||
fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
|
fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
|
||||||
/* Lots of things can happen during a delay. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
rc += show_statement(stmt, sscope);
|
rc += show_statement(stmt, sscope);
|
||||||
|
|
||||||
|
|
@ -1357,9 +1325,6 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
fprintf(vvp_out, " %%delayx %d;\n", use_idx);
|
fprintf(vvp_out, " %%delayx %d;\n", use_idx);
|
||||||
clr_word(use_idx);
|
clr_word(use_idx);
|
||||||
|
|
||||||
/* Lots of things can happen during a delay. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
rc += show_statement(stmt, sscope);
|
rc += show_statement(stmt, sscope);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
@ -1396,7 +1361,6 @@ static int show_stmt_do_while(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
because it can be entered from above or from the bottom of
|
because it can be entered from above or from the bottom of
|
||||||
the loop. */
|
the loop. */
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
/* Draw the body of the loop. */
|
/* Draw the body of the loop. */
|
||||||
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
rc += show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||||
|
|
@ -1520,7 +1484,6 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
/* Generate the sub-threads themselves. */
|
/* Generate the sub-threads themselves. */
|
||||||
for (idx = 0 ; idx < (join_count + join_detach_count) ; idx += 1) {
|
for (idx = 0 ; idx < (join_count + join_detach_count) ; idx += 1) {
|
||||||
fprintf(vvp_out, "t_%u ;\n", id_base+idx);
|
fprintf(vvp_out, "t_%u ;\n", id_base+idx);
|
||||||
clear_expression_lookaside();
|
|
||||||
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
|
rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
|
||||||
fprintf(vvp_out, " %%end;\n");
|
fprintf(vvp_out, " %%end;\n");
|
||||||
}
|
}
|
||||||
|
|
@ -1529,7 +1492,6 @@ static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
|
|
||||||
/* This is the label for the out. Use this to branch around
|
/* This is the label for the out. Use this to branch around
|
||||||
the implementations of all the child threads. */
|
the implementations of all the child threads. */
|
||||||
clear_expression_lookaside();
|
|
||||||
fprintf(vvp_out, "t_%u ;\n", out);
|
fprintf(vvp_out, "t_%u ;\n", out);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
@ -1700,7 +1662,7 @@ static int show_stmt_utask(ivl_statement_t net)
|
||||||
vvp_mangle_id(ivl_scope_name(task)));
|
vvp_mangle_id(ivl_scope_name(task)));
|
||||||
fprintf(vvp_out, ", S_%p;\n", task);
|
fprintf(vvp_out, ", S_%p;\n", task);
|
||||||
fprintf(vvp_out, " %%join;\n");
|
fprintf(vvp_out, " %%join;\n");
|
||||||
clear_expression_lookaside();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1733,9 +1695,6 @@ static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
fprintf(vvp_out, ";\n %%wait Ewait_%u;\n", cascade_counter);
|
fprintf(vvp_out, ";\n %%wait Ewait_%u;\n", cascade_counter);
|
||||||
cascade_counter += 1;
|
cascade_counter += 1;
|
||||||
}
|
}
|
||||||
/* Always clear the expression lookaside after a
|
|
||||||
%wait. Anything can happen while the thread is waiting. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
return show_statement(ivl_stmt_sub_stmt(net), sscope);
|
return show_statement(ivl_stmt_sub_stmt(net), sscope);
|
||||||
}
|
}
|
||||||
|
|
@ -1753,7 +1712,7 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
because it can be entered from above or from the bottom of
|
because it can be entered from above or from the bottom of
|
||||||
the loop. */
|
the loop. */
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, top_label);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
/* Draw the evaluation of the condition expression, and test
|
/* Draw the evaluation of the condition expression, and test
|
||||||
the result. If the expression evaluates to false, then
|
the result. If the expression evaluates to false, then
|
||||||
|
|
@ -1776,7 +1735,7 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
|
||||||
test is repeated, and also draw the out label. */
|
test is repeated, and also draw the out label. */
|
||||||
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label);
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, top_label);
|
||||||
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, out_label);
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, out_label);
|
||||||
clear_expression_lookaside();
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1859,10 +1818,6 @@ static int show_system_task_call(ivl_statement_t net)
|
||||||
|
|
||||||
draw_vpi_task_call(net);
|
draw_vpi_task_call(net);
|
||||||
|
|
||||||
/* VPI calls can manipulate anything, so clear the expression
|
|
||||||
lookahead table after the call. */
|
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2414,7 +2369,6 @@ int draw_process(ivl_process_t net, void*x)
|
||||||
/* Generate the entry label. Just give the thread a number so
|
/* Generate the entry label. Just give the thread a number so
|
||||||
that we ar certain the label is unique. */
|
that we ar certain the label is unique. */
|
||||||
fprintf(vvp_out, "T_%u ;\n", thread_count);
|
fprintf(vvp_out, "T_%u ;\n", thread_count);
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
/* Draw the contents of the thread. */
|
/* Draw the contents of the thread. */
|
||||||
rc += show_statement(stmt, scope);
|
rc += show_statement(stmt, scope);
|
||||||
|
|
@ -2463,7 +2417,6 @@ int draw_task_definition(ivl_scope_t scope)
|
||||||
ivl_statement_t def = ivl_scope_def(scope);
|
ivl_statement_t def = ivl_scope_def(scope);
|
||||||
|
|
||||||
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
assert(def);
|
assert(def);
|
||||||
rc += show_statement(def, scope);
|
rc += show_statement(def, scope);
|
||||||
|
|
@ -2480,7 +2433,6 @@ int draw_func_definition(ivl_scope_t scope)
|
||||||
ivl_statement_t def = ivl_scope_def(scope);
|
ivl_statement_t def = ivl_scope_def(scope);
|
||||||
|
|
||||||
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
fprintf(vvp_out, "TD_%s ;\n", vvp_mangle_id(ivl_scope_name(scope)));
|
||||||
clear_expression_lookaside();
|
|
||||||
|
|
||||||
assert(def);
|
assert(def);
|
||||||
rc += show_statement(def, scope);
|
rc += show_statement(def, scope);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue