Merge branch 'master' into verilog-ams
[sverilog.git] / eval.cc
blob41cb60a5b17f76dda9e17726d21b4a5acbd78a9b
1 /*
2 * Copyright (c) 1998-1999 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 # include "config.h"
22 # include <cstring>
23 # include <iostream>
25 # include "PExpr.h"
26 # include "netlist.h"
27 # include "netmisc.h"
28 # include "compiler.h"
30 verinum* PExpr::eval_const(Design*, NetScope*) const
32 return 0;
35 verinum* PEBinary::eval_const(Design*des, NetScope*scope) const
37 verinum*l = left_->eval_const(des, scope);
38 if (l == 0) return 0;
39 verinum*r = right_->eval_const(des, scope);
40 if (r == 0) {
41 delete l;
42 return 0;
44 verinum*res;
46 switch (op_) {
47 case '+': {
48 if (l->is_defined() && r->is_defined()) {
49 res = new verinum(*l + *r);
50 } else {
51 res = new verinum(verinum::Vx, l->len());
53 break;
55 case '-': {
56 if (l->is_defined() && r->is_defined()) {
57 res = new verinum(*l - *r);
58 } else {
59 res = new verinum(verinum::Vx, l->len());
61 break;
63 case '*': {
64 if (l->is_defined() && r->is_defined()) {
65 res = new verinum(*l * *r);
66 } else {
67 res = new verinum(verinum::Vx, l->len());
69 break;
71 case '/': {
72 if (l->is_defined() && r->is_defined()) {
73 long lv = l->as_long();
74 long rv = r->as_long();
75 res = new verinum(lv / rv, l->len());
76 } else {
77 res = new verinum(verinum::Vx, l->len());
79 break;
81 case '%': {
82 if (l->is_defined() && r->is_defined()) {
83 long lv = l->as_long();
84 long rv = r->as_long();
85 res = new verinum(lv % rv, l->len());
86 } else {
87 res = new verinum(verinum::Vx, l->len());
89 break;
91 case '>': {
92 if (l->is_defined() && r->is_defined()) {
93 long lv = l->as_long();
94 long rv = r->as_long();
95 res = new verinum(lv > rv, l->len());
96 } else {
97 res = new verinum(verinum::Vx, l->len());
99 break;
101 case '<': {
102 if (l->is_defined() && r->is_defined()) {
103 long lv = l->as_long();
104 long rv = r->as_long();
105 res = new verinum(lv < rv, l->len());
106 } else {
107 res = new verinum(verinum::Vx, l->len());
109 break;
111 case 'l': { // left shift (<<)
112 assert(r->is_defined());
113 unsigned long rv = r->as_ulong();
114 res = new verinum(verinum::V0, l->len());
115 if (rv < res->len()) {
116 unsigned cnt = res->len() - rv;
117 for (unsigned idx = 0 ; idx < cnt ; idx += 1)
118 res->set(idx+rv, l->get(idx));
120 break;
122 case 'r': { // right shift (>>)
123 assert(r->is_defined());
124 unsigned long rv = r->as_ulong();
125 res = new verinum(verinum::V0, l->len());
126 if (rv < res->len()) {
127 unsigned cnt = res->len() - rv;
128 for (unsigned idx = 0 ; idx < cnt ; idx += 1)
129 res->set(idx, l->get(idx+rv));
131 break;
134 default:
135 delete l;
136 delete r;
137 return 0;
140 delete l;
141 delete r;
142 return res;
144 verinum* PEConcat::eval_const(Design*des, NetScope*scope) const
146 verinum*accum = parms_[0]->eval_const(des, scope);
147 if (accum == 0)
148 return 0;
150 for (unsigned idx = 1 ; idx < parms_.count() ; idx += 1) {
152 verinum*tmp = parms_[idx]->eval_const(des, scope);
153 if (tmp == 0) {
154 delete accum;
155 return 0;
157 assert(tmp);
159 *accum = concat(*accum, *tmp);
160 delete tmp;
163 return accum;
168 * Evaluate an identifier as a constant expression. This is only
169 * possible if the identifier is that of a parameter.
171 verinum* PEIdent::eval_const(Design*des, NetScope*scope) const
173 assert(scope);
174 NetNet*net;
175 NetEvent*eve;
176 const NetExpr*expr;
178 const name_component_t&name_tail = path_.back();
180 // Handle the special case that this ident is a genvar
181 // variable name. In that case, the genvar meaning preempts
182 // everything and we just return that value immediately.
183 if (scope->genvar_tmp
184 && strcmp(name_tail.name,scope->genvar_tmp) == 0) {
185 return new verinum(scope->genvar_tmp_val);
188 symbol_search(des, scope, path_, net, expr, eve);
190 if (expr == 0)
191 return 0;
193 const NetEConst*eval = dynamic_cast<const NetEConst*>(expr);
194 if (eval == 0) {
195 cerr << get_fileline() << ": internal error: Unable to evaluate "
196 << "constant expression (parameter=" << path_
197 << "): " << *expr << endl;
198 return 0;
201 assert(eval);
203 if (!name_tail.index.empty())
204 return 0;
207 return new verinum(eval->value());
210 verinum* PEFNumber::eval_const(Design*, NetScope*) const
212 long val = value_->as_long();
213 return new verinum(val);
216 verinum* PENumber::eval_const(Design*, NetScope*) const
218 return new verinum(value());
221 verinum* PEString::eval_const(Design*, NetScope*) const
223 return new verinum(string(text_));
226 verinum* PETernary::eval_const(Design*des, NetScope*scope) const
228 verinum*test = expr_->eval_const(des, scope);
229 if (test == 0)
230 return 0;
232 verinum::V bit = test->get(0);
233 delete test;
234 switch (bit) {
235 case verinum::V0:
236 return fal_->eval_const(des, scope);
237 case verinum::V1:
238 return tru_->eval_const(des, scope);
239 default:
240 return 0;
241 // XXXX It is possible to handle this case if both fal_
242 // and tru_ are constant. Someday...
246 verinum* PEUnary::eval_const(Design*des, NetScope*scope) const
248 verinum*val = expr_->eval_const(des, scope);
249 if (val == 0)
250 return 0;
252 switch (op_) {
253 case '+':
254 return val;
256 case '-': {
257 /* We need to expand the value a bit if we are
258 taking the 2's complement so that we are
259 guaranteed to not overflow. */
260 verinum tmp ((uint64_t)0, val->len()+1);
261 for (unsigned idx = 0 ; idx < val->len() ; idx += 1)
262 tmp.set(idx, val->get(idx));
264 *val = v_not(tmp) + verinum(verinum::V1, 1);
265 val->has_sign(true);
266 return val;
270 delete val;
271 return 0;