Merge branch 'master' into verilog-ams
[sverilog.git] / PDelays.cc
blobc547a2c088d1911af7da9a68dc199493bc1e3d4f
1 /*
2 * Copyright (c) 1999-2008 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 <iostream>
24 # include "PDelays.h"
25 # include "PExpr.h"
26 # include "verinum.h"
27 # include "netmisc.h"
29 PDelays::PDelays()
31 delete_flag_ = true;
32 for (unsigned idx = 0 ; idx < 3 ; idx += 1)
33 delay_[idx] = 0;
36 PDelays::~PDelays()
38 if (delete_flag_) {
39 for (unsigned idx = 0 ; idx < 3 ; idx += 1)
40 delete delay_[idx];
44 void PDelays::set_delay(PExpr*del)
46 assert(del);
47 assert(delay_[0] == 0);
48 delay_[0] = del;
49 delete_flag_ = true;
53 void PDelays::set_delays(const svector<PExpr*>*del, bool df)
55 assert(del);
56 assert(del->count() <= 3);
57 for (unsigned idx = 0 ; idx < del->count() ; idx += 1)
58 delay_[idx] = (*del)[idx];
60 delete_flag_ = df;
63 static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr)
66 NetExpr*dex = expr->elaborate_expr(des, scope, -1, false);
67 eval_expr(dex);
69 /* If the delay expression is a real constant or vector
70 constant, then evaluate it, scale it to the local time
71 units, and return an adjusted value. */
73 if (NetECReal*tmp = dynamic_cast<NetECReal*>(dex)) {
74 verireal fn = tmp->value();
76 int shift = scope->time_unit() - des->get_precision();
77 long delay = fn.as_long(shift);
78 if (delay < 0)
79 delay = 0;
81 delete tmp;
82 NetEConst*tmp2 = new NetEConst(verinum(delay));
83 tmp2->set_line(*expr);
84 return tmp2;
88 if (NetEConst*tmp = dynamic_cast<NetEConst*>(dex)) {
89 verinum fn = tmp->value();
91 unsigned long delay =
92 des->scale_to_precision(fn.as_ulong(), scope);
94 delete tmp;
95 NetEConst*tmp2 = new NetEConst(verinum(delay));
96 tmp2->set_line(*expr);
97 return tmp2;
100 /* Oops, cannot evaluate down to a constant. */
101 return dex;
104 static NetExpr* make_delay_nets(Design*des, NetExpr*expr)
106 if (dynamic_cast<NetESignal*> (expr))
107 return expr;
109 if (dynamic_cast<NetEConst*> (expr))
110 return expr;
112 NetNet*sig = expr->synthesize(des);
113 if (sig == 0) {
114 cerr << expr->get_fileline() << ": error: Expression " << *expr
115 << " is not suitable for delay expression." << endl;
116 return 0;
119 expr = new NetESignal(sig);
120 return expr;
123 void PDelays::eval_delays(Design*des, NetScope*scope,
124 NetExpr*&rise_time,
125 NetExpr*&fall_time,
126 NetExpr*&decay_time,
127 bool as_nets_flag) const
129 assert(scope);
132 if (delay_[0]) {
133 rise_time = calculate_val(des, scope, delay_[0]);
134 if (as_nets_flag)
135 rise_time = make_delay_nets(des, rise_time);
137 if (delay_[1]) {
138 fall_time = calculate_val(des, scope, delay_[1]);
139 if (as_nets_flag)
140 fall_time = make_delay_nets(des, fall_time);
142 if (delay_[2]) {
143 decay_time = calculate_val(des, scope, delay_[2]);
144 if (as_nets_flag)
145 decay_time = make_delay_nets(des, decay_time);
147 } else {
148 if (rise_time < fall_time)
149 decay_time = rise_time;
150 else
151 decay_time = fall_time;
153 } else {
154 assert(delay_[2] == 0);
155 fall_time = rise_time;
156 decay_time = rise_time;
158 } else {
159 rise_time = 0;
160 fall_time = 0;
161 decay_time = 0;