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)
|
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) {
|
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
||||||
/* Look in the current scope. */
|
/* Look in the current scope. */
|
||||||
if (emit_param_name_in_scope(scope, expr)) return;
|
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)
|
static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
{
|
{
|
||||||
ivl_expr_t sel_expr = ivl_expr_oper2(expr);
|
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);
|
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||||
fprintf(vlog_out, ")" );
|
fprintf(vlog_out, ")" );
|
||||||
} else {
|
} else {
|
||||||
emit_select_name(scope, sig_expr, wid);
|
/* A bit select. */
|
||||||
if (width == 1) {
|
if (width == 1) {
|
||||||
|
emit_select_name(scope, sig_expr, wid);
|
||||||
fprintf(vlog_out, "[");
|
fprintf(vlog_out, "[");
|
||||||
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
emit_scaled_expr(scope, sel_expr, msb, lsb);
|
||||||
fprintf(vlog_out, "]");
|
fprintf(vlog_out, "]");
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -353,42 +353,21 @@ void emit_scaled_range(ivl_scope_t scope, ivl_expr_t expr, unsigned width,
|
||||||
int msb, int lsb)
|
int msb, int lsb)
|
||||||
{
|
{
|
||||||
if (msb >= lsb) {
|
if (msb >= lsb) {
|
||||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
int rtype;
|
||||||
int rtype;
|
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
"range value");
|
||||||
"range value");
|
if (rtype) return;
|
||||||
if (rtype) return;
|
value += lsb;
|
||||||
value += lsb;
|
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
value + (int64_t)(width - 1), value);
|
||||||
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 {
|
} else {
|
||||||
if (ivl_expr_type(expr) == IVL_EX_NUMBER) {
|
int rtype;
|
||||||
int rtype;
|
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
||||||
int64_t value = get_valid_int64_from_number(expr, &rtype,
|
"range value");
|
||||||
"range value");
|
if (rtype) return;
|
||||||
if (rtype) return;
|
value = (int64_t)lsb - value;
|
||||||
value = (int64_t)lsb - value;
|
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
||||||
fprintf(vlog_out, "[%"PRId64":%"PRId64"]",
|
value - (int64_t)(width - 1), value);
|
||||||
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_expr_t array_idx = ivl_lval_idx(lval);
|
||||||
ivl_signal_t sig = ivl_lval_sig(lval);
|
|
||||||
unsigned width = ivl_lval_width(lval);
|
|
||||||
int msb, lsb;
|
|
||||||
assert(width > 0);
|
|
||||||
emit_scope_module_path(scope, ivl_signal_scope(sig));
|
emit_scope_module_path(scope, ivl_signal_scope(sig));
|
||||||
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
fprintf(vlog_out, "%s", ivl_signal_basename(sig));
|
||||||
/* Check to see if we have an array word access. */
|
if (array_idx) {
|
||||||
expr = ivl_lval_idx(lval);
|
int msb, lsb;
|
||||||
if (expr) {
|
|
||||||
assert(ivl_signal_dimensions(sig));
|
assert(ivl_signal_dimensions(sig));
|
||||||
fprintf(vlog_out, "[");
|
fprintf(vlog_out, "[");
|
||||||
/* For an array the LSB/MSB order is not important. They are
|
/* For an array the LSB/MSB order is not important. They are
|
||||||
* always accessed from base counting up. */
|
* always accessed from base counting up. */
|
||||||
lsb = ivl_signal_array_base(sig);
|
lsb = ivl_signal_array_base(sig);
|
||||||
msb = lsb + ivl_signal_array_count(sig) - 1;
|
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, "]");
|
fprintf(vlog_out, "]");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If there are no selects then just return. */
|
static void emit_stmt_lval_ips(ivl_scope_t scope, ivl_lval_t lval,
|
||||||
if (width == ivl_signal_width(sig)) return;
|
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. */
|
/* We have some kind of select. */
|
||||||
lsb = ivl_signal_lsb(sig);
|
lsb = ivl_signal_lsb(sig);
|
||||||
msb = ivl_signal_msb(sig);
|
msb = ivl_signal_msb(sig);
|
||||||
|
sel_expr = ivl_lval_part_off(lval);
|
||||||
|
assert(sel_expr);
|
||||||
|
/* A bit select. */
|
||||||
if (width == 1) {
|
if (width == 1) {
|
||||||
|
emit_stmt_lval_name(scope, lval, sig);
|
||||||
fprintf(vlog_out, "[");
|
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, "]");
|
fprintf(vlog_out, "]");
|
||||||
} else {
|
} 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