Add unlimited tail recursion for the real ternary operator.

This patch modifies the real ternary operator code to support
unlimited tail recursion without overflowing the thread
registers. Head recursion is still limited by the available
registers.

It fixes the thread word checks to use a new define that has
the correct number of thread words (16). It adds a message
instead of just an assert if the thread words are exhausted.

And it also changes some of the error messages to use vvp.tgt
in the message to be consistent with the other messages.
This commit is contained in:
Cary R 2010-07-07 14:33:10 -07:00 committed by Stephen Williams
parent fb1853144b
commit a8198b38fb
4 changed files with 49 additions and 35 deletions

View File

@ -498,7 +498,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
}
fprintf(stderr, "internal error: no input to nexus.\n");
fprintf(stderr, "vvp.tgt error: no input to nexus.\n");
assert(0);
return strdup("C<z>");
}

View File

@ -504,7 +504,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr,
case 'e': /* == */
if (lv.wid != rv.wid) {
fprintf(stderr,"internal error: operands of == "
fprintf(stderr,"vvp.tgt error: operands of == "
" have different widths: %u vs %u\n",
lv.wid, rv.wid);
}
@ -519,7 +519,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr,
case 'N': /* !== */
if (lv.wid != rv.wid) {
fprintf(stderr,"internal error: operands of !== "
fprintf(stderr,"vvp.tgt error: operands of !== "
" have different widths: %u vs %u\n",
lv.wid, rv.wid);
}
@ -536,7 +536,7 @@ static struct vector_info draw_binary_expr_eq(ivl_expr_t expr,
case 'n': /* != */
if (lv.wid != rv.wid) {
fprintf(stderr,"internal error: operands of != "
fprintf(stderr,"vvp.tgt error: operands of != "
" have different widths: %u vs %u\n",
lv.wid, rv.wid);
}
@ -2383,7 +2383,7 @@ static struct vector_info draw_select_signal(ivl_expr_t expr,
/* Try the special case that the part is at the beginning of
the signal (or the entire width). Just load the early bits
in one go. */
if (number_is_immediate(bit_idx, 32, 0)
if (number_is_immediate(bit_idx, IMM_WID, 0)
&& !number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0
&& (ivl_expr_width(sube) >= bit_wid)) {
@ -2448,7 +2448,7 @@ static void draw_select_signal_dest(ivl_expr_t expr,
value in place, directly. */
if ((ivl_signal_dimensions(sig) == 0)
&& (ivl_expr_width(sube) >= dest.wid)
&& number_is_immediate(bit_idx, 32, 0)
&& number_is_immediate(bit_idx, IMM_WID, 0)
&& ! number_is_unknown(bit_idx)
&& get_number_immediate(bit_idx) == 0) {
unsigned use_word = 0;
@ -3136,13 +3136,13 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
break;
case 'r': /* Handled in eval_real.c. */
fprintf(stderr, "vvp error: integer -> real cast in integer "
fprintf(stderr, "vvp.tgt error: integer -> real cast in integer "
"context.\n");
assert(0);
break;
default:
fprintf(stderr, "vvp error: unhandled unary operator: %c\n",
fprintf(stderr, "vvp.tgt error: unhandled unary operator: %c\n",
ivl_expr_opcode(expr));
assert(0);
}
@ -3201,7 +3201,7 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned wid,
switch (ivl_expr_type(expr)) {
default:
case IVL_EX_NONE:
fprintf(stderr, "%s:%u: vvp-tgt error: unhandled expr. type: "
fprintf(stderr, "%s:%u: vvp.tgt error: unhandled expr. type: "
"%u at %s:%d\n", ivl_expr_file(expr), ivl_expr_lineno(expr),
ivl_expr_type(expr), __FILE__, __LINE__);
exit(1);
@ -3209,7 +3209,7 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t expr, unsigned wid,
res.wid = 0;
break;
case IVL_EX_EVENT:
fprintf(stderr, "%s:%u: vvp-tgt error: A named event is not "
fprintf(stderr, "%s:%u: vvp.tgt error: A named event is not "
"handled in this context (expression).\n",
ivl_expr_file(expr), ivl_expr_lineno(expr));
exit(1);

View File

@ -31,19 +31,22 @@ static unsigned long word_alloc_mask = 0x0f;
int allocate_word()
{
int res = 4;
int max = IMM_WID;
int max = WORD_COUNT;
while (res < max && (1U << res) & word_alloc_mask)
res += 1;
assert(res < max);
if (res >= max) {
fprintf(stderr, "vvp.tgt error: Thread words exhausted.\n");
exit(1);
}
word_alloc_mask |= 1U << res;
return res;
}
void clr_word(int res)
{
int max = IMM_WID;
int max = WORD_COUNT;
assert(res < max);
word_alloc_mask &= ~ (1U << res);
}
@ -193,7 +196,7 @@ static int draw_number_real(ivl_expr_t expr)
if (bits[idx] == '0')
continue;
fprintf(stderr, "internal error: mantissa doesn't fit!\n");
fprintf(stderr, "vvp.tgt error: mantissa doesn't fit!\n");
assert(0);
}
@ -363,13 +366,16 @@ static int draw_signal_real(ivl_expr_t expr)
case IVL_VT_REAL:
return draw_signal_real_real(expr);
default:
fprintf(stderr, "internal error: signal_data_type=%d\n",
fprintf(stderr, "vvp.tgt error: signal_data_type=%d\n",
ivl_signal_data_type(sig));
assert(0);
return -1;
}
}
/* If we have nested ternary operators they are likely tail recursive.
* This code is structured to allow this recursion without overflowing
* the available thread words. */
static int draw_ternary_real(ivl_expr_t expr)
{
ivl_expr_t cond = ivl_expr_oper1(expr);
@ -379,12 +385,12 @@ static int draw_ternary_real(ivl_expr_t expr)
struct vector_info tst;
unsigned lab_true = local_count++;
unsigned lab_false = local_count++;
unsigned lab_move = local_count++;
unsigned lab_out = local_count++;
int tru, fal;
int res = allocate_word();
int tru, fal, res;
/* Evaluate the ternary condition. */
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
if ((tst.base >= 4) && (tst.wid > 1)) {
struct vector_info tmp;
@ -400,29 +406,34 @@ static int draw_ternary_real(ivl_expr_t expr)
tst.wid = 1;
}
fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
/* Evaluate the true expression second. */
fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u;\n",
thread_count, lab_true, tst.base);
tru = draw_eval_real(true_ex);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u; End of true expr.\n",
thread_count, lab_out, tst.base);
clr_word(tru);
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_true);
/* Evaluate the false expression and copy it to the result word. */
fal = draw_eval_real(false_ex);
res = allocate_word();
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
clr_word(fal);
fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u; End of false expr.\n",
thread_count, lab_false, tst.base);
thread_count, lab_out, tst.base);
fprintf(vvp_out, " %%blend/wr %d, %d;\n", res, fal);
/* Evaluate the true expression. */
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_true);
tru = draw_eval_real(true_ex);
fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u; End of true expr.\n",
thread_count, lab_move, tst.base);
/* If the conditional is undefined then blend the real words. */
fprintf(vvp_out, " %%blend/wr %d, %d;\n", res, tru);
fprintf(vvp_out, " %%jmp T_%d.%d; End of blend\n",
thread_count, lab_out);
fprintf(vvp_out, "T_%d.%d ; Move false result.\n",
thread_count, lab_false);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
clr_word(fal);
/* If we only need the true result then copy it to the result word. */
fprintf(vvp_out, "T_%d.%d ; Move true result.\n",
thread_count, lab_move);
fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
clr_word(tru);
/* This is the out label. */
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
@ -479,12 +490,12 @@ static int draw_unary_real(ivl_expr_t expr)
}
if (ivl_expr_opcode(expr) == 'i') { /* Handled in eval_expr.c. */
fprintf(stderr, "vvp error: real -> integer cast in real "
fprintf(stderr, "vvp.tgt error: real -> integer cast in real "
"context.\n");
assert(0);
}
fprintf(stderr, "vvp error: unhandled real unary operator: %c.\n",
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
ivl_expr_opcode(expr));
assert(0);
}

View File

@ -45,6 +45,9 @@ struct vector_info {
/* Width limit for typical immediate arguments. */
# define IMM_WID 32
/* The number of words available in a thread. */
# define WORD_COUNT 16
/*
* Mangle all non-symbol characters in an identifier, quotes in names
*/