diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index f1fc3bbaf..e73bd6a8f 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -263,7 +263,7 @@ static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr) static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { - /* A select of a number is reall a parameter select. */ + /* A select of a number is really a parameter select. */ if (ivl_expr_type(expr) == IVL_EX_NUMBER) { /* Look in the current scope. */ if (emit_param_name_in_scope(scope, expr)) return; @@ -285,6 +285,50 @@ static void emit_select_name(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) } } +/* + * Emit an indexed part select as a concatenation of bit selects. + */ +static void emit_expr_ips(ivl_scope_t scope, ivl_expr_t sig_expr, + ivl_expr_t sel_expr, unsigned wid, + unsigned msb, unsigned lsb) +{ + unsigned idx; + if ((msb >= lsb) && (lsb != 0)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 sorry: Variable indexed part " + "select lsb must be zero.\n", + ivl_expr_file(sel_expr), + ivl_expr_lineno(sel_expr)); + vlog_errors += 1; + return; + } + if (msb < lsb) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 sorry: Variable indexed part " + "selects must be little endian.\n", + ivl_expr_file(sel_expr), + ivl_expr_lineno(sel_expr)); + vlog_errors += 1; + return; + } + fprintf(vlog_out, "{"); + for (idx = wid - 1; idx > 0; idx -= 1) { + emit_select_name(scope, sig_expr, wid); + fprintf(vlog_out, "["); +// HERE: Ideally we should simplify the scaled expression and the addition +// of the idx value. Also we should simplify any offset with the base +// expression as a compiler enhancement. All this will require a +// modified/updated version of emit_scaled_expr(). We can remove the +// above fails when this is finished. + emit_scaled_expr(scope, sel_expr, msb, lsb); + fprintf(vlog_out, " + %u], ", idx); + } + emit_select_name(scope, sig_expr, wid); + fprintf(vlog_out, "["); + emit_scaled_expr(scope, sel_expr, msb, lsb); + fprintf(vlog_out, "]}"); +} + static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_expr_t sel_expr = ivl_expr_oper2(expr); @@ -308,13 +352,23 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) emit_scaled_expr(scope, sel_expr, msb, lsb); fprintf(vlog_out, ")" ); } else { - emit_select_name(scope, sig_expr, wid); + /* A bit select. */ if (width == 1) { + emit_select_name(scope, sig_expr, wid); fprintf(vlog_out, "["); emit_scaled_expr(scope, sel_expr, msb, lsb); fprintf(vlog_out, "]"); } else { - emit_scaled_range(scope, sel_expr, width, msb, lsb); + if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) { + /* A constant part select. */ + emit_select_name(scope, sig_expr, wid); + emit_scaled_range(scope, sel_expr, width, + msb, lsb); + } else { + /* An indexed part select. */ + emit_expr_ips(scope, sig_expr, sel_expr, width, + msb, lsb); + } } } } else { diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index af09b7932..e9a947a13 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -353,42 +353,21 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width, int msb, int lsb) { if (msb >= lsb) { - if (ivl_expr_type(expr) == IVL_EX_NUMBER) { - int rtype; - int64_t value = get_valid_int64_from_number(expr, &rtype, - "range value"); - if (rtype) return; - value += lsb; - fprintf(vlog_out, "[%"PRId64":%"PRId64"]", - value + (int64_t)(width - 1), value); - } else { -// HERE: Need to scale the select expression and create a concatenation of -// variable bit selects for that. We need the signal name as well. -// As an optimization determine if this is an up or down to simplify -// the generated expression. - fprintf(vlog_out, "[:]"); - fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects " - "are not currently supported.\n", - ivl_expr_file(expr), ivl_expr_lineno(expr)); - vlog_errors += 1; - } + int rtype; + int64_t value = get_valid_int64_from_number(expr, &rtype, + "range value"); + if (rtype) return; + value += lsb; + fprintf(vlog_out, "[%"PRId64":%"PRId64"]", + value + (int64_t)(width - 1), value); } else { - if (ivl_expr_type(expr) == IVL_EX_NUMBER) { - int rtype; - int64_t value = get_valid_int64_from_number(expr, &rtype, - "range value"); - if (rtype) return; - value = (int64_t)lsb - value; - fprintf(vlog_out, "[%"PRId64":%"PRId64"]", - value - (int64_t)(width - 1), value); - } else { -// HERE: Do basically the same as above. - fprintf(vlog_out, "[:]"); - fprintf(stderr, "%s:%u: vlog95 error: Indexed part-selects " - "are not currently supported.\n", - ivl_expr_file(expr), ivl_expr_lineno(expr)); - vlog_errors += 1; - } + int rtype; + int64_t value = get_valid_int64_from_number(expr, &rtype, + "range value"); + if (rtype) return; + value = (int64_t)lsb - value; + fprintf(vlog_out, "[%"PRId64":%"PRId64"]", + value - (int64_t)(width - 1), value); } } diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 20ae4fa21..ddd5bf618 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -86,40 +86,102 @@ static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt) } } -static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) +static void emit_stmt_lval_name(ivl_scope_t scope, ivl_lval_t lval, + ivl_signal_t sig) { - ivl_expr_t expr; - ivl_signal_t sig = ivl_lval_sig(lval); - unsigned width = ivl_lval_width(lval); - int msb, lsb; - assert(width > 0); + ivl_expr_t array_idx = ivl_lval_idx(lval); emit_scope_module_path(scope, ivl_signal_scope(sig)); fprintf(vlog_out, "%s", ivl_signal_basename(sig)); - /* Check to see if we have an array word access. */ - expr = ivl_lval_idx(lval); - if (expr) { + if (array_idx) { + int msb, lsb; assert(ivl_signal_dimensions(sig)); fprintf(vlog_out, "["); /* For an array the LSB/MSB order is not important. They are * always accessed from base counting up. */ lsb = ivl_signal_array_base(sig); msb = lsb + ivl_signal_array_count(sig) - 1; - emit_scaled_expr(scope, expr, msb, lsb); + emit_scaled_expr(scope, array_idx, msb, lsb); fprintf(vlog_out, "]"); } +} - /* If there are no selects then just return. */ - if (width == ivl_signal_width(sig)) return; +static void emit_stmt_lval_ips(ivl_scope_t scope, ivl_lval_t lval, + ivl_signal_t sig, ivl_expr_t sel_expr, + unsigned wid, unsigned msb, unsigned lsb) +{ + unsigned idx; + if ((msb >= lsb) && (lsb != 0)) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 sorry: Variable indexed part " + "select lsb must be zero.\n", + ivl_expr_file(sel_expr), + ivl_expr_lineno(sel_expr)); + vlog_errors += 1; + return; + } + if (msb < lsb) { + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 sorry: Variable indexed part " + "selects must be little endian.\n", + ivl_expr_file(sel_expr), + ivl_expr_lineno(sel_expr)); + vlog_errors += 1; + return; + } + + fprintf(vlog_out, "{"); + for (idx = wid - 1; idx > 0; idx -= 1) { + emit_stmt_lval_name(scope, lval, sig); + fprintf(vlog_out, "["); +// HERE: Ideally we should simplify the scaled expression and the addition +// of the idx value. Also we should simplify any offset with the base +// expression as a compiler enhancement. All this will require a +// modified/updated version of emit_scaled_expr(). We can remove the +// above fails when this is finished. + emit_scaled_expr(scope, sel_expr, msb, lsb); + fprintf(vlog_out, " + %u], ", idx); + } + emit_stmt_lval_name(scope, lval, sig); + fprintf(vlog_out, "["); + emit_scaled_expr(scope, sel_expr, msb, lsb); + fprintf(vlog_out, "]}"); +} + +static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) +{ + ivl_signal_t sig = ivl_lval_sig(lval); + ivl_expr_t sel_expr; + unsigned width = ivl_lval_width(lval); + int msb, lsb; + assert(width > 0); + + /* If there are no selects then just print the name. */ + if (width == ivl_signal_width(sig)) { + emit_stmt_lval_name(scope, lval, sig); + return; + } /* We have some kind of select. */ lsb = ivl_signal_lsb(sig); msb = ivl_signal_msb(sig); + sel_expr = ivl_lval_part_off(lval); + assert(sel_expr); + /* A bit select. */ if (width == 1) { + emit_stmt_lval_name(scope, lval, sig); fprintf(vlog_out, "["); - emit_scaled_expr(scope, ivl_lval_part_off(lval), msb, lsb); + emit_scaled_expr(scope, sel_expr, msb, lsb); fprintf(vlog_out, "]"); } else { - emit_scaled_range(scope, ivl_lval_part_off(lval), width, msb, lsb); + /* A constant part select. */ + if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) { + emit_stmt_lval_name(scope, lval, sig); + emit_scaled_range(scope, sel_expr, width, msb, lsb); + /* An indexed part select. */ + } else { + emit_stmt_lval_ips(scope, lval, sig, sel_expr, width, + msb, lsb); + } } }