V0.9: 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:55:52 -07:00 committed by Stephen Williams
parent 86f4e9560e
commit 9d6d9fd9d6
4 changed files with 50 additions and 38 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -471,7 +471,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;
@ -2946,7 +2946,7 @@ static struct vector_info draw_unary_expr(ivl_expr_t expr, unsigned wid)
break;
default:
fprintf(stderr, "vvp error: unhandled unary: %c\n",
fprintf(stderr, "vvp.tgt error: unhandled unary operator: %c\n",
ivl_expr_opcode(expr));
assert(0);
}
@ -3005,7 +3005,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);
@ -3013,7 +3013,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);
}
@ -213,7 +216,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);
}
@ -388,13 +391,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);
@ -404,12 +410,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;
@ -425,29 +431,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);
@ -521,11 +532,9 @@ static int draw_unary_real(ivl_expr_t expr)
return sub;
}
fprintf(vvp_out, "; XXXX unary (%c) on sube in %d\n",
ivl_expr_opcode(expr), sub);
fprintf(stderr, "XXXX evaluate unary (%c) on sube in %d\n",
ivl_expr_opcode(expr), sub);
return 0;
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
ivl_expr_opcode(expr));
assert(0);
}
int draw_eval_real(ivl_expr_t expr)

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
*/