vlog95: Convert compiler translation back to wait and strength fixes.

This patch adds the ability to translate the code produced by the
compiler for a wait statement back into a wait statement. It also
reworks the strength emitting code to only emit a single strength
for the pull gates and fixes a bug in the strength emitting code.
This commit is contained in:
Cary R 2011-02-02 13:04:06 -08:00 committed by Stephen Williams
parent b08120e223
commit 05a00ff631
3 changed files with 132 additions and 68 deletions

View File

@ -237,6 +237,8 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
msb = ivl_signal_msb(sig);
lsb = ivl_signal_lsb(sig);
}
// HERE: If this is a constant then it was likely a parameter reference.
// We need to find the appropriate parameter and use it instead.
emit_expr(scope, sig_expr, wid);
if (width == 1) {
fprintf(vlog_out, "[");

View File

@ -225,28 +225,42 @@ static unsigned emit_drive(ivl_drive_t drive)
return 0;
}
static void emit_gate_strength(ivl_net_logic_t nlogic)
/*
* If the strength type is 2 then emit both strengths. If it is 1 then only
* emit the 1 strength (pullup) and if it is 0 only emit the 0 strength
* (pulldown).
*/
static void emit_gate_strength(ivl_net_logic_t nlogic, unsigned strength_type)
{
assert(strength_type <= 2);
ivl_drive_t drive1 = ivl_logic_drive1(nlogic);
ivl_drive_t drive0 = ivl_logic_drive0(nlogic);
if ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG)) {
fprintf(vlog_out, " (");
if (emit_drive(drive1)) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
"1 drive (%d)\n", ivl_logic_file(nlogic),
ivl_logic_lineno(nlogic), (int)drive1);
vlog_errors += 1;
if (strength_type > 0) {
if (emit_drive(drive1)) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
"1 drive (%d)\n",
ivl_logic_file(nlogic),
ivl_logic_lineno(nlogic), (int)drive1);
vlog_errors += 1;
}
fprintf(vlog_out, "1");
}
fprintf(vlog_out, "1, ");
if (emit_drive(drive0)) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
"0 drive (%d)\n", ivl_logic_file(nlogic),
ivl_logic_lineno(nlogic), (int)drive0);
vlog_errors += 1;
if (strength_type == 2) fprintf(vlog_out, ", ");
if ((strength_type & 0x01) == 0) {
if (emit_drive(drive0)) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
"0 drive (%d)\n",
ivl_logic_file(nlogic),
ivl_logic_lineno(nlogic), (int)drive0);
vlog_errors += 1;
}
fprintf(vlog_out, "0");
}
fprintf(vlog_out, "0)");
fprintf(vlog_out, ")");
}
}
@ -264,7 +278,6 @@ static void emit_lpm_strength(ivl_lpm_t lpm)
vlog_errors += 1;
}
fprintf(vlog_out, "1, ");
emit_drive(drive0);
if (emit_drive(drive0)) {
fprintf(vlog_out, "<invalid>");
fprintf(stderr, "%s:%u: vlog95 error: Unsupported LPM "
@ -742,7 +755,7 @@ static void emit_bufz(ivl_scope_t scope, ivl_net_logic_t nlogic)
{
assert(ivl_logic_pins(nlogic) == 2);
fprintf(vlog_out, "assign");
emit_gate_strength(nlogic);
emit_gate_strength(nlogic, 2);
emit_delay(scope,
ivl_logic_delay(nlogic, 0),
ivl_logic_delay(nlogic, 1),
@ -757,7 +770,7 @@ static void emit_bufz(ivl_scope_t scope, ivl_net_logic_t nlogic)
static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic)
{
unsigned idx, count, dly_count;
unsigned idx, count, dly_count, strength_type = 2;
fprintf(vlog_out, "%*c", indent, ' ');
switch (ivl_logic_type(nlogic)) {
case IVL_LO_AND:
@ -819,10 +832,12 @@ static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic)
case IVL_LO_PULLDOWN:
fprintf(vlog_out, "pulldown");
dly_count = 0;
strength_type = 0;
break;
case IVL_LO_PULLUP:
fprintf(vlog_out, "pullup");
dly_count = 0;
strength_type = 1;
break;
case IVL_LO_RCMOS:
fprintf(vlog_out, "rcmos");
@ -855,7 +870,7 @@ static void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic)
dly_count = 0;
break;
}
emit_gate_strength(nlogic);
emit_gate_strength(nlogic, strength_type);
if (dly_count) emit_delay(scope,
ivl_logic_delay(nlogic, 0),
ivl_logic_delay(nlogic, 1),

View File

@ -139,6 +139,67 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt)
return wid;
}
/*
* Icarus translated <var> = <delay> <value> into
* begin
* <tmp> = <value>;
* <delay> <var> = <tmp>;
* end
* This routine looks for this pattern and turns it back into the
* appropriate blocking assignment.
*/
static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned wid;
ivl_statement_t assign, delay, delayed_assign;
ivl_lval_t lval;
ivl_expr_t rval;
ivl_signal_t lsig, rsig;
/* We must have two block elements. */
if (ivl_stmt_block_count(stmt) != 2) return 0;
/* The first must be an assign. */
assign = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
/* The second must be a delayx. */
delay = ivl_stmt_block_stmt(stmt, 1);
if (ivl_statement_type(delay) != IVL_ST_DELAYX) return 0;
/* The statement for the delayx must be an assign. */
delayed_assign = ivl_stmt_sub_stmt(delay);
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
/* The L-value must be a single signal. */
if (ivl_stmt_lvals(assign) != 1) return 0;
lval = ivl_stmt_lval(assign, 0);
/* It must not have an array select. */
if (ivl_lval_idx(lval)) return 0;
/* It must not have a non-zero base. */
if (ivl_lval_part_off(lval)) return 0;
lsig = ivl_lval_sig(lval);
/* It must not be part of the signal. */
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
/* The R-value must be a single signal. */
rval = ivl_stmt_rval(delayed_assign);
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
/* It must not be an array word. */
if (ivl_expr_oper1(rval)) return 0;
rsig = ivl_expr_signal(rval);
/* And finally the two signals must be the same. */
if (lsig != rsig) return 0;
/* The pattern matched so generate the appropriate code. */
fprintf(vlog_out, "%*c", get_indent(), ' ');
// HERE: Do we need to calculate the width? The compiler should have already
// done this for us.
wid = emit_stmt_lval(scope, delayed_assign);
fprintf(vlog_out, " = #(");
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay));
fprintf(vlog_out, ") ");
emit_expr(scope, ivl_stmt_rval(assign), wid);
fprintf(vlog_out, ";\n");
return 1;
}
/*
* Icarus translated <var> = <event> <value> into
* begin
@ -215,63 +276,48 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
}
/*
* Icarus translated <var> = <delay> <value> into
* Icarus translated wait(<expr) <stmt> into
* begin
* <tmp> = <value>;
* <delay> <var> = <tmp>;
* while (<expr> !== 1'b1) @(<expr sensitivities>);
* <stmt>
* end
* This routine looks for this pattern and turns it back into the
* appropriate blocking assignment.
* This routine looks for this pattern and turns it back into a
* wait statement.
*/
static unsigned find_delayed_assign(ivl_scope_t scope, ivl_statement_t stmt)
static unsigned find_wait(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned wid;
ivl_statement_t assign, delay, delayed_assign;
ivl_lval_t lval;
ivl_expr_t rval;
ivl_signal_t lsig, rsig;
ivl_statement_t while_wait, wait, wait_stmt;
ivl_expr_t while_expr, expr;
const char *bits;
/* We must have two block elements. */
if (ivl_stmt_block_count(stmt) != 2) return 0;
/* The first must be an assign. */
assign = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
/* The second must be a delayx. */
delay = ivl_stmt_block_stmt(stmt, 1);
if (ivl_statement_type(delay) != IVL_ST_DELAYX) return 0;
/* The statement for the delayx must be an assign. */
delayed_assign = ivl_stmt_sub_stmt(delay);
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
/* The L-value must be a single signal. */
if (ivl_stmt_lvals(assign) != 1) return 0;
lval = ivl_stmt_lval(assign, 0);
/* It must not have an array select. */
if (ivl_lval_idx(lval)) return 0;
/* It must not have a non-zero base. */
if (ivl_lval_part_off(lval)) return 0;
lsig = ivl_lval_sig(lval);
/* It must not be part of the signal. */
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
/* The R-value must be a single signal. */
rval = ivl_stmt_rval(delayed_assign);
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
/* It must not be an array word. */
if (ivl_expr_oper1(rval)) return 0;
rsig = ivl_expr_signal(rval);
/* And finally the two signals must be the same. */
if (lsig != rsig) return 0;
/* The first must be a while. */
while_wait = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
/* That has a wait with a NOOP statement. */
wait = ivl_stmt_sub_stmt(while_wait);
if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
wait_stmt = ivl_stmt_sub_stmt(wait);
if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
/* Check that the while condition has the correct form. */
while_expr = ivl_stmt_cond_expr(while_wait);
if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
if (ivl_expr_opcode(while_expr) != 'N') return 0;
/* And has a second operator that is a constant 1'b1. */
expr = ivl_expr_oper2(while_expr);
if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
if (ivl_expr_width(expr) != 1) return 0;
bits = ivl_expr_bits(expr);
if (*bits != '1') return 0;
// HERE: There is no easy way to verify that the @ sensitivity list
// matches the first expression so we don't check for that yet.
/* The pattern matched so generate the appropriate code. */
fprintf(vlog_out, "%*c", get_indent(), ' ');
// HERE: Do we need to calculate the width? The compiler should have already
// done this for us.
wid = emit_stmt_lval(scope, delayed_assign);
fprintf(vlog_out, " = #(");
emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay));
fprintf(vlog_out, ") ");
emit_expr(scope, ivl_stmt_rval(assign), wid);
fprintf(vlog_out, ";\n");
fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
emit_expr(scope, ivl_expr_oper1(while_expr), 0);
fprintf(vlog_out, ")");
single_indent = 1;
emit_stmt(scope, ivl_stmt_block_stmt(stmt, 1));
return 1;
}
@ -782,6 +828,7 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
} else {
if (find_delayed_assign(scope, stmt)) break;
if (find_event_assign(scope, stmt)) break;
if (find_wait(scope, stmt)) break;
emit_stmt_block(scope, stmt);
}
break;