vlog95: Add partial support for procedural variable indexed part selects.
This patch adds partial support of procedural variable indexed part selects (both R and L-value). The restriction is that this currently only works on a zero based little endian vector. I need to know if the select is an up or down select to correctly denormalize the base expression for the general case.
This commit is contained in:
parent
96a9cb8d54
commit
757611b8e9
|
|
@ -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, "<unsupported>");
|
||||
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, "<unsupported>");
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -353,7 +353,6 @@ 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");
|
||||
|
|
@ -362,18 +361,6 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width,
|
|||
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, "[<invalid>:<invalid>]");
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||
int rtype;
|
||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||
"range value");
|
||||
|
|
@ -381,14 +368,6 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width,
|
|||
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, "[<invalid>:<invalid>]");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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, "<unsupported>");
|
||||
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, "<unsupported>");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue