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:
parent
b08120e223
commit
05a00ff631
|
|
@ -237,6 +237,8 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
msb = ivl_signal_msb(sig);
|
msb = ivl_signal_msb(sig);
|
||||||
lsb = ivl_signal_lsb(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);
|
emit_expr(scope, sig_expr, wid);
|
||||||
if (width == 1) {
|
if (width == 1) {
|
||||||
fprintf(vlog_out, "[");
|
fprintf(vlog_out, "[");
|
||||||
|
|
|
||||||
|
|
@ -225,28 +225,42 @@ static unsigned emit_drive(ivl_drive_t drive)
|
||||||
return 0;
|
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 drive1 = ivl_logic_drive1(nlogic);
|
||||||
ivl_drive_t drive0 = ivl_logic_drive0(nlogic);
|
ivl_drive_t drive0 = ivl_logic_drive0(nlogic);
|
||||||
if ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG)) {
|
if ((drive1 != IVL_DR_STRONG) || (drive0 != IVL_DR_STRONG)) {
|
||||||
fprintf(vlog_out, " (");
|
fprintf(vlog_out, " (");
|
||||||
if (emit_drive(drive1)) {
|
if (strength_type > 0) {
|
||||||
fprintf(vlog_out, "<invalid>");
|
if (emit_drive(drive1)) {
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
|
fprintf(vlog_out, "<invalid>");
|
||||||
"1 drive (%d)\n", ivl_logic_file(nlogic),
|
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
|
||||||
ivl_logic_lineno(nlogic), (int)drive1);
|
"1 drive (%d)\n",
|
||||||
vlog_errors += 1;
|
ivl_logic_file(nlogic),
|
||||||
|
ivl_logic_lineno(nlogic), (int)drive1);
|
||||||
|
vlog_errors += 1;
|
||||||
|
}
|
||||||
|
fprintf(vlog_out, "1");
|
||||||
}
|
}
|
||||||
fprintf(vlog_out, "1, ");
|
if (strength_type == 2) fprintf(vlog_out, ", ");
|
||||||
if (emit_drive(drive0)) {
|
if ((strength_type & 0x01) == 0) {
|
||||||
fprintf(vlog_out, "<invalid>");
|
if (emit_drive(drive0)) {
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
|
fprintf(vlog_out, "<invalid>");
|
||||||
"0 drive (%d)\n", ivl_logic_file(nlogic),
|
fprintf(stderr, "%s:%u: vlog95 error: Unsupported gate "
|
||||||
ivl_logic_lineno(nlogic), (int)drive0);
|
"0 drive (%d)\n",
|
||||||
vlog_errors += 1;
|
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;
|
vlog_errors += 1;
|
||||||
}
|
}
|
||||||
fprintf(vlog_out, "1, ");
|
fprintf(vlog_out, "1, ");
|
||||||
emit_drive(drive0);
|
|
||||||
if (emit_drive(drive0)) {
|
if (emit_drive(drive0)) {
|
||||||
fprintf(vlog_out, "<invalid>");
|
fprintf(vlog_out, "<invalid>");
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Unsupported LPM "
|
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);
|
assert(ivl_logic_pins(nlogic) == 2);
|
||||||
fprintf(vlog_out, "assign");
|
fprintf(vlog_out, "assign");
|
||||||
emit_gate_strength(nlogic);
|
emit_gate_strength(nlogic, 2);
|
||||||
emit_delay(scope,
|
emit_delay(scope,
|
||||||
ivl_logic_delay(nlogic, 0),
|
ivl_logic_delay(nlogic, 0),
|
||||||
ivl_logic_delay(nlogic, 1),
|
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)
|
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, ' ');
|
fprintf(vlog_out, "%*c", indent, ' ');
|
||||||
switch (ivl_logic_type(nlogic)) {
|
switch (ivl_logic_type(nlogic)) {
|
||||||
case IVL_LO_AND:
|
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:
|
case IVL_LO_PULLDOWN:
|
||||||
fprintf(vlog_out, "pulldown");
|
fprintf(vlog_out, "pulldown");
|
||||||
dly_count = 0;
|
dly_count = 0;
|
||||||
|
strength_type = 0;
|
||||||
break;
|
break;
|
||||||
case IVL_LO_PULLUP:
|
case IVL_LO_PULLUP:
|
||||||
fprintf(vlog_out, "pullup");
|
fprintf(vlog_out, "pullup");
|
||||||
dly_count = 0;
|
dly_count = 0;
|
||||||
|
strength_type = 1;
|
||||||
break;
|
break;
|
||||||
case IVL_LO_RCMOS:
|
case IVL_LO_RCMOS:
|
||||||
fprintf(vlog_out, "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;
|
dly_count = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
emit_gate_strength(nlogic);
|
emit_gate_strength(nlogic, strength_type);
|
||||||
if (dly_count) emit_delay(scope,
|
if (dly_count) emit_delay(scope,
|
||||||
ivl_logic_delay(nlogic, 0),
|
ivl_logic_delay(nlogic, 0),
|
||||||
ivl_logic_delay(nlogic, 1),
|
ivl_logic_delay(nlogic, 1),
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,67 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
return wid;
|
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
|
* Icarus translated <var> = <event> <value> into
|
||||||
* begin
|
* 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
|
* begin
|
||||||
* <tmp> = <value>;
|
* while (<expr> !== 1'b1) @(<expr sensitivities>);
|
||||||
* <delay> <var> = <tmp>;
|
* <stmt>
|
||||||
* end
|
* end
|
||||||
* This routine looks for this pattern and turns it back into the
|
* This routine looks for this pattern and turns it back into a
|
||||||
* appropriate blocking assignment.
|
* 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 while_wait, wait, wait_stmt;
|
||||||
ivl_statement_t assign, delay, delayed_assign;
|
ivl_expr_t while_expr, expr;
|
||||||
ivl_lval_t lval;
|
const char *bits;
|
||||||
ivl_expr_t rval;
|
|
||||||
ivl_signal_t lsig, rsig;
|
|
||||||
|
|
||||||
/* We must have two block elements. */
|
/* We must have two block elements. */
|
||||||
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
if (ivl_stmt_block_count(stmt) != 2) return 0;
|
||||||
/* The first must be an assign. */
|
/* The first must be a while. */
|
||||||
assign = ivl_stmt_block_stmt(stmt, 0);
|
while_wait = ivl_stmt_block_stmt(stmt, 0);
|
||||||
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
|
if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
|
||||||
/* The second must be a delayx. */
|
/* That has a wait with a NOOP statement. */
|
||||||
delay = ivl_stmt_block_stmt(stmt, 1);
|
wait = ivl_stmt_sub_stmt(while_wait);
|
||||||
if (ivl_statement_type(delay) != IVL_ST_DELAYX) return 0;
|
if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
|
||||||
/* The statement for the delayx must be an assign. */
|
wait_stmt = ivl_stmt_sub_stmt(wait);
|
||||||
delayed_assign = ivl_stmt_sub_stmt(delay);
|
if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
|
||||||
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
|
/* Check that the while condition has the correct form. */
|
||||||
/* The L-value must be a single signal. */
|
while_expr = ivl_stmt_cond_expr(while_wait);
|
||||||
if (ivl_stmt_lvals(assign) != 1) return 0;
|
if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
|
||||||
lval = ivl_stmt_lval(assign, 0);
|
if (ivl_expr_opcode(while_expr) != 'N') return 0;
|
||||||
/* It must not have an array select. */
|
/* And has a second operator that is a constant 1'b1. */
|
||||||
if (ivl_lval_idx(lval)) return 0;
|
expr = ivl_expr_oper2(while_expr);
|
||||||
/* It must not have a non-zero base. */
|
if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
|
||||||
if (ivl_lval_part_off(lval)) return 0;
|
if (ivl_expr_width(expr) != 1) return 0;
|
||||||
lsig = ivl_lval_sig(lval);
|
bits = ivl_expr_bits(expr);
|
||||||
/* It must not be part of the signal. */
|
if (*bits != '1') return 0;
|
||||||
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
|
// HERE: There is no easy way to verify that the @ sensitivity list
|
||||||
/* The R-value must be a single signal. */
|
// matches the first expression so we don't check for that yet.
|
||||||
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. */
|
/* The pattern matched so generate the appropriate code. */
|
||||||
fprintf(vlog_out, "%*c", get_indent(), ' ');
|
fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
|
||||||
// HERE: Do we need to calculate the width? The compiler should have already
|
emit_expr(scope, ivl_expr_oper1(while_expr), 0);
|
||||||
// done this for us.
|
fprintf(vlog_out, ")");
|
||||||
wid = emit_stmt_lval(scope, delayed_assign);
|
single_indent = 1;
|
||||||
fprintf(vlog_out, " = #(");
|
emit_stmt(scope, ivl_stmt_block_stmt(stmt, 1));
|
||||||
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -782,6 +828,7 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
|
||||||
} else {
|
} else {
|
||||||
if (find_delayed_assign(scope, stmt)) break;
|
if (find_delayed_assign(scope, stmt)) break;
|
||||||
if (find_event_assign(scope, stmt)) break;
|
if (find_event_assign(scope, stmt)) break;
|
||||||
|
if (find_wait(scope, stmt)) break;
|
||||||
emit_stmt_block(scope, stmt);
|
emit_stmt_block(scope, stmt);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue