diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index 260d575da..2c7e0c4e4 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -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, "["); diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 113cc6af4..929b4bda7 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -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, ""); - 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, ""); + 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, ""); - 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, ""); + 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, ""); 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), diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index f443ecb9d..b79d5cc1d 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -139,6 +139,67 @@ static unsigned emit_stmt_lval(ivl_scope_t scope, ivl_statement_t stmt) return wid; } +/* + * Icarus translated = into + * begin + * = ; + * = ; + * 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 = into * begin @@ -215,63 +276,48 @@ static unsigned find_event_assign(ivl_scope_t scope, ivl_statement_t stmt) } /* - * Icarus translated = into + * Icarus translated wait( into * begin - * = ; - * = ; + * while ( !== 1'b1) @(); + * * 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;