vlog95: Add support for translating some power expressions as a left shift.
If the left power operator expression is a numeric constant that has a value 2^n n>0 then we can use a left shift to calculate the result. This patch adds code to do this. All other power expressions are flagged as a compilation error.
This commit is contained in:
parent
5cec7e3870
commit
755d0b59d6
|
|
@ -16,10 +16,57 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
# include <inttypes.h>
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
# include "vlog95_priv.h"
|
# include "vlog95_priv.h"
|
||||||
|
|
||||||
// HERE: Do we need to use wid?
|
// HERE: Do we need to use wid in these routines? We should probably use
|
||||||
|
// it to verify that the expressions have the expected width.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can convert any 2^n ** <unsigned variable> expression to
|
||||||
|
* 1 << (n * <unsigned variable>). If the variable is signed then we need
|
||||||
|
* to add a check for less than zero and for that case return 0.
|
||||||
|
*/
|
||||||
|
static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
|
||||||
|
unsigned wid)
|
||||||
|
{
|
||||||
|
int rtype;
|
||||||
|
int64_t value, scale;
|
||||||
|
unsigned is_signed_rval = 0;
|
||||||
|
unsigned expr_wid;
|
||||||
|
ivl_expr_t lval = ivl_expr_oper1(expr);
|
||||||
|
ivl_expr_t rval = ivl_expr_oper2(expr);
|
||||||
|
/* The L-value must be a number. */
|
||||||
|
if (ivl_expr_type(lval) != IVL_EX_NUMBER) return 0;
|
||||||
|
/* The L-value must of the form 2^n. */
|
||||||
|
value = get_int64_from_number(lval, &rtype);
|
||||||
|
if (rtype) return 0;
|
||||||
|
expr_wid = ivl_expr_width(lval);
|
||||||
|
if (value < 2) return 0;
|
||||||
|
if (value % 2) return 0;
|
||||||
|
/* Generate the appropriate conversion. */
|
||||||
|
if (ivl_expr_signed(rval)) {
|
||||||
|
emit_expr(scope, rval, 0);
|
||||||
|
fprintf(vlog_out, " < 0 ? %u'h0 : (", expr_wid);
|
||||||
|
is_signed_rval = 1;
|
||||||
|
}
|
||||||
|
scale = value / 2;
|
||||||
|
fprintf(vlog_out, "%u'h1 << ", expr_wid);
|
||||||
|
if (scale != 1) {
|
||||||
|
if (is_signed_rval) {
|
||||||
|
fprintf(vlog_out, "(%"PRId64, scale);
|
||||||
|
} else {
|
||||||
|
fprintf(vlog_out, "(%u'h%"PRIx64,
|
||||||
|
ivl_expr_width(rval), scale);
|
||||||
|
}
|
||||||
|
fprintf(vlog_out, " * ");
|
||||||
|
}
|
||||||
|
emit_expr(scope, rval, 0);
|
||||||
|
if (scale != 1) fprintf(vlog_out, ")");
|
||||||
|
if (is_signed_rval) fprintf(vlog_out, ")");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
{
|
{
|
||||||
|
|
@ -97,14 +144,15 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
|
||||||
fprintf(vlog_out, ")");
|
fprintf(vlog_out, ")");
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
// HERE: We can convert 2 ** <r-val> to 1 << <r-val>
|
if (! emit_power_as_shift(scope, expr, wid)) {
|
||||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||||
fprintf(vlog_out, " ** ");
|
fprintf(vlog_out, " ** ");
|
||||||
emit_expr(scope, ivl_expr_oper2(expr), 0);
|
emit_expr(scope, ivl_expr_oper2(expr), 0);
|
||||||
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
|
fprintf(stderr, "%s:%u: vlog95 error: Power operator is not "
|
||||||
"supported.\n",
|
"supported.\n",
|
||||||
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
ivl_expr_file(expr), ivl_expr_lineno(expr));
|
||||||
vlog_errors += 1;
|
vlog_errors += 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
emit_expr(scope, ivl_expr_oper1(expr), wid);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue