/* * Copyright (c) 2000 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) & !defined(macintosh) #ident "$Id: t-dll-expr.cc,v 1.26 2002/06/16 20:39:12 steve Exp $" #endif # include "config.h" # include # include "t-dll.h" # include "netlist.h" # include #ifdef HAVE_MALLOC_H # include #endif # include /* * These methods implement the expression scan that generates the * ivl_expr_t representing the expression. Each method leaves the * expr_ member filled with the ivl_expr_t that represents it. Each * method expects that the expr_ member empty (0) when it starts. */ /* * This function takes an expression in the expr_ member that is * already built up, and adds a subtraction of the given constant. */ void dll_target::sub_off_from_expr_(long off) { assert(expr_ != 0); char*bits; ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (off & 1)? '1' : '0'; off >>= 1; } /* Now make the subtractor (x-4 in the above example) that has as input A the index expression and input B the constant to subtract. */ ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->u_.binary_.op_ = '-'; tmps->u_.binary_.lef_ = expr_; tmps->u_.binary_.rig_ = tmpc; /* Replace (x) with (x-off) */ expr_ = tmps; } void dll_target::mul_expr_by_const_(long val) { assert(expr_ != 0); char*bits; ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->width_ = expr_->width_; tmpc->signed_ = expr_->signed_; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (val & 1)? '1' : '0'; val >>= 1; } /* Now make the subtractor (x-4 in the above example) that has as input A the index expression and input B the constant to subtract. */ ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->width_ = tmpc->width_; tmps->signed_ = tmpc->signed_; tmps->u_.binary_.op_ = '*'; tmps->u_.binary_.lef_ = expr_; tmps->u_.binary_.rig_ = tmpc; /* Replace (x) with (x*valf) */ expr_ = tmps; } void dll_target::expr_binary(const NetEBinary*net) { assert(expr_ == 0); net->left()->expr_scan(this); ivl_expr_t left = expr_; expr_ = 0; net->right()->expr_scan(this); ivl_expr_t rght = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_BINARY; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.binary_.op_ = net->op(); expr_->u_.binary_.lef_ = left; expr_->u_.binary_.rig_ = rght; } void dll_target::expr_concat(const NetEConcat*net) { assert(expr_ == 0); ivl_expr_t cur = new struct ivl_expr_s; assert(cur); cur->type_ = IVL_EX_CONCAT; cur->width_= net->expr_width(); cur->u_.concat_.rept = net->repeat(); cur->u_.concat_.parms = net->nparms(); cur->u_.concat_.parm = new ivl_expr_t [net->nparms()]; for (unsigned idx = 0 ; idx < net->nparms() ; idx += 1) { expr_ = 0; net->parm(idx)->expr_scan(this); assert(expr_); cur->u_.concat_.parm[idx] = expr_; } expr_ = cur; } void dll_target::expr_memory(const NetEMemory*net) { assert(expr_ == 0); if (net->index()) { net->index()->expr_scan(this); assert(expr_); } ivl_expr_t cur = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(cur); cur->type_ = IVL_EX_MEMORY; cur->width_= net->expr_width(); cur->signed_ = net->has_sign()? 1 : 0; cur->u_.memory_.mem_ = lookup_memory_(net->memory()); cur->u_.memory_.idx_ = expr_; expr_ = cur; } void dll_target::expr_const(const NetEConst*net) { assert(expr_ == 0); ivl_expr_t idx = 0; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); if (net->value().is_string()) { expr_->type_ = IVL_EX_STRING; expr_->width_= net->expr_width(); expr_->u_.string_.value_ =strdup(net->value().as_string().c_str()); } else { verinum val = net->value(); unsigned idx; char*bits; expr_->type_ = IVL_EX_NUMBER; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.number_.bits_ = bits = (char*)malloc(expr_->width_); for (idx = 0 ; idx < expr_->width_ ; idx += 1) switch (val.get(idx)) { case verinum::V0: bits[idx] = '0'; break; case verinum::V1: bits[idx] = '1'; break; case verinum::Vx: bits[idx] = 'x'; break; case verinum::Vz: bits[idx] = 'z'; break; default: assert(0); } } } void dll_target::expr_scope(const NetEScope*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_SCOPE; expr_->u_.scope_.scope = lookup_scope_(net->scope()); } void dll_target::expr_select(const NetESelect*net) { assert(expr_ == 0); net->sub_expr()->expr_scan(this); ivl_expr_t left = expr_; expr_ = 0; net->select()->expr_scan(this); ivl_expr_t rght = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_SELECT; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.binary_.lef_ = left; expr_->u_.binary_.rig_ = rght; } void dll_target::expr_sfunc(const NetESFunc*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_SFUNC; expr->width_= net->expr_width(); expr->u_.sfunc_.name_ = strdup(net->name()); unsigned cnt = net->nparms(); expr->u_.sfunc_.parms = cnt; expr->u_.sfunc_.parm = new ivl_expr_t[cnt]; /* make up the parameter expressions. */ for (unsigned idx = 0 ; idx < cnt ; idx += 1) { net->parm(idx)->expr_scan(this); assert(expr_); expr->u_.sfunc_.parm[idx] = expr_; expr_ = 0; } expr_ = expr; } void dll_target::expr_ternary(const NetETernary*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_TERNARY; expr->width_ = net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; net->cond_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.cond = expr_; expr_ = 0; net->true_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.true_e = expr_; expr_ = 0; net->false_expr()->expr_scan(this); assert(expr_); expr->u_.ternary_.false_e = expr_; expr_ = expr; } void dll_target::expr_signal(const NetESignal*net) { assert(expr_ == 0); expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr_); expr_->type_ = IVL_EX_SIGNAL; expr_->width_= net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.signal_.sig = find_signal(des_, net->sig()); expr_->u_.signal_.lsi = net->lsi(); expr_->u_.signal_.msi = net->msi(); } void dll_target::expr_subsignal(const NetEBitSel*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_BITSEL; expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->u_.bitsel_.sig = find_signal(des_, net->sig()); assert(expr->u_.bitsel_.sig->lsb_index == net->sig()->lsb()); net->index()->expr_scan(this); assert(expr_); expr->u_.bitsel_.bit = expr_; /* If the lsb of the signal is not 0, then we are about to lose the proper offset to the normalized vector. Modify the expression to subtract the offset: reg [7:4] a; ... = a[x]; becomes reg [3:0] a; ... = a[x-4]; to reflect the normalizing of vectors that is done by the compiler. */ if (expr->u_.bitsel_.sig->lsb_index != 0) { /* Create in tmpc the constant offset (4 in the above example) to be subtracted from the index. */ char*bits; long lsb = expr->u_.bitsel_.sig->lsb_index; ivl_expr_t tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->width_ = expr->u_.bitsel_.bit->width_; tmpc->signed_ = net->index()->has_sign()? 1 : 0; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (lsb & 1)? '1' : '0'; lsb >>= 1; } /* Now make the subtractor (x-4 in the above example) that has as input A the index expression and input B the constant to subtract. */ ivl_expr_t tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->width_ = tmpc->width_; tmps->signed_ = net->index()->has_sign()? 1 : 0; tmps->u_.binary_.op_ = '-'; tmps->u_.binary_.lef_ = expr->u_.bitsel_.bit; tmps->u_.binary_.rig_ = tmpc; /* Replace (x) with (x-4) */ expr->u_.bitsel_.bit = tmps; /* If the index item distance (the distance to the next most significant bit) is not 1, then multiply the previous result to convert the index. */ if (expr->u_.bitsel_.sig->lsb_dist != 1) { long dist = expr->u_.bitsel_.sig->lsb_dist; tmpc = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmpc->type_ = IVL_EX_NUMBER; tmpc->width_ = expr->u_.bitsel_.bit->width_; tmpc->signed_ = 1; tmpc->u_.number_.bits_ = bits = (char*)malloc(tmpc->width_); for (unsigned idx = 0 ; idx < tmpc->width_ ; idx += 1) { bits[idx] = (dist & 1)? '1' : '0'; dist >>= 1; } tmps = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); tmps->type_ = IVL_EX_BINARY; tmps->width_ = tmpc->width_; tmps->signed_ = 1; tmps->u_.binary_.op_ = '*'; tmps->u_.binary_.lef_ = expr->u_.bitsel_.bit; tmps->u_.binary_.rig_ = tmpc; expr->u_.bitsel_.bit = tmps; } } expr_ = expr; } void dll_target::expr_ufunc(const NetEUFunc*net) { assert(expr_ == 0); ivl_expr_t expr = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(expr); expr->type_ = IVL_EX_UFUNC; expr->width_= net->expr_width(); expr->signed_ = net->has_sign()? 1 : 0; expr->u_.ufunc_.def = lookup_scope_(net->func()); assert(expr->u_.ufunc_.def->type_ == IVL_SCT_FUNCTION); unsigned cnt = net->parm_count(); expr->u_.ufunc_.parms = cnt; expr->u_.ufunc_.parm = new ivl_expr_t[cnt]; /* make up the parameter expressions. */ for (unsigned idx = 0 ; idx < cnt ; idx += 1) { net->parm(idx)->expr_scan(this); assert(expr_); expr->u_.ufunc_.parm[idx] = expr_; expr_ = 0; } expr_ = expr; } void dll_target::expr_unary(const NetEUnary*net) { assert(expr_ == 0); net->expr()->expr_scan(this); assert(expr_); ivl_expr_t sub = expr_; expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); expr_->type_ = IVL_EX_UNARY; expr_->width_ = net->expr_width(); expr_->signed_ = net->has_sign()? 1 : 0; expr_->u_.unary_.op_ = net->op(); expr_->u_.unary_.sub_ = sub; } /* * $Log: t-dll-expr.cc,v $ * Revision 1.26 2002/06/16 20:39:12 steve * Normalize run-time index expressions for bit selects * * Revision 1.25 2002/06/16 19:19:16 steve * Generate runtime code to normalize indices. * * Revision 1.24 2002/05/29 22:05:54 steve * Offset lvalue index expressions. * * Revision 1.23 2002/04/14 02:56:19 steve * Support signed expressions through to VPI. * * Revision 1.22 2002/01/28 00:52:41 steve * Add support for bit select of parameters. * This leads to a NetESelect node and the * vvp code generator to support that. * * Revision 1.21 2001/12/31 00:08:14 steve * Support $signed cast of expressions. * * Revision 1.20 2001/10/23 04:22:41 steve * Support bit selects of non-0 lsb for vectors. * * Revision 1.19 2001/10/19 21:53:24 steve * Support multiple root modules (Philip Blundell) * * Revision 1.18 2001/09/15 18:27:04 steve * Make configure detect malloc.h * * Revision 1.17 2001/07/27 04:51:44 steve * Handle part select expressions as variants of * NetESignal/IVL_EX_SIGNAL objects, instead of * creating new and useless temporary signals. * * Revision 1.16 2001/07/25 03:10:49 steve * Create a config.h.in file to hold all the config * junk, and support gcc 3.0. (Stephan Boettcher) * * Revision 1.15 2001/07/22 00:17:49 steve * Support the NetESubSignal expressions in vvp.tgt. * * Revision 1.14 2001/07/07 20:20:10 steve * Pass parameters to system functions. * * Revision 1.13 2001/05/17 04:37:02 steve * Behavioral ternary operators for vvp. * * Revision 1.12 2001/05/08 23:59:33 steve * Add ivl and vvp.tgt support for memories in * expressions and l-values. (Stephan Boettcher) */