1 /*
2 * Generate code to convert between VHDL types.
3 *
4 * Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "vhdl_syntax.hh"
22
23 #include "vhdl_target.h"
24 #include "support.hh"
25
26 #include <cassert>
27 #include <iostream>
28
cast(const vhdl_type * to)29 vhdl_expr *vhdl_expr::cast(const vhdl_type *to)
30 {
31 #if 0
32 std::cout << "Cast: from=" << type_->get_string()
33 << " (" << type_->get_width() << ") "
34 << " to=" << to->get_string() << " ("
35 << to->get_width() << ")" << std::endl;
36 #endif
37
38 // If this expression hasn't been given a type then
39 // we can't generate any type conversion code
40 if (NULL == type_)
41 return this;
42
43 if (to->get_name() == type_->get_name()) {
44 if (to->get_width() == type_->get_width())
45 return this; // Identical
46 else
47 return resize(to->get_width());
48 }
49 else {
50 switch (to->get_name()) {
51 case VHDL_TYPE_BOOLEAN:
52 return to_boolean();
53 case VHDL_TYPE_INTEGER:
54 return to_integer();
55 case VHDL_TYPE_UNSIGNED:
56 case VHDL_TYPE_SIGNED:
57 case VHDL_TYPE_STD_LOGIC_VECTOR:
58 return to_vector(to->get_name(), to->get_width());
59 case VHDL_TYPE_STD_LOGIC:
60 return to_std_logic();
61 case VHDL_TYPE_STD_ULOGIC:
62 return to_std_ulogic();
63 case VHDL_TYPE_STRING:
64 return to_string();
65 default:
66 assert(false);
67 }
68 }
69 assert(false);
70 return NULL;
71 }
72
73 /*
74 * Generate code to cast an expression to a vector type (std_logic_vector,
75 * signed, unsigned).
76 */
to_vector(vhdl_type_name_t name,int w)77 vhdl_expr *vhdl_expr::to_vector(vhdl_type_name_t name, int w)
78 {
79 if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
80 vhdl_expr *others = w == 1 ? NULL : new vhdl_const_bit('0');
81 vhdl_bit_spec_expr *bs =
82 new vhdl_bit_spec_expr(new vhdl_type(name, w - 1, 0), others);
83 bs->add_bit(0, this);
84
85 return bs;
86 }
87 else {
88 // We have to cast the expression before resizing or the
89 // wrong sign bit may be extended (i.e. when casting between
90 // signed/unsigned *and* resizing)
91 vhdl_type *t = new vhdl_type(name, w - 1, 0);
92 vhdl_fcall *conv = new vhdl_fcall(t->get_string().c_str(), t);
93 conv->add_expr(this);
94
95 if (w != type_->get_width())
96 return conv->resize(w);
97 else
98 return conv;
99 }
100 }
101
102 /*
103 * Convert a generic expression to an Integer.
104 */
to_integer()105 vhdl_expr *vhdl_expr::to_integer()
106 {
107 vhdl_fcall *conv;
108 if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
109 require_support_function(SF_LOGIC_TO_INTEGER);
110 conv = new vhdl_fcall(support_function::function_name(SF_LOGIC_TO_INTEGER),
111 vhdl_type::integer());
112 }
113 else
114 conv = new vhdl_fcall("To_Integer", vhdl_type::integer());
115
116 conv->add_expr(this);
117
118 return conv;
119 }
120
to_string()121 vhdl_expr *vhdl_expr::to_string()
122 {
123 bool numeric = type_->get_name() == VHDL_TYPE_UNSIGNED
124 || type_->get_name() == VHDL_TYPE_SIGNED;
125
126 if (numeric) {
127 vhdl_fcall *image = new vhdl_fcall("integer'image", vhdl_type::string());
128 image->add_expr(this->cast(vhdl_type::integer()));
129 return image;
130 }
131 else {
132 // Assume type'image exists
133 vhdl_fcall *image = new vhdl_fcall(type_->get_string() + "'image",
134 vhdl_type::string());
135 image->add_expr(this);
136 return image;
137 }
138 }
139
140 /*
141 * Convert a generic expression to a Boolean.
142 */
to_boolean()143 vhdl_expr *vhdl_expr::to_boolean()
144 {
145 if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
146 // '1' is true all else are false
147 vhdl_const_bit *one = new vhdl_const_bit('1');
148 return new vhdl_binop_expr
149 (this, VHDL_BINOP_EQ, one, vhdl_type::boolean());
150 }
151 else if (type_->get_name() == VHDL_TYPE_UNSIGNED) {
152 // Need to use a support function for this conversion
153 require_support_function(SF_UNSIGNED_TO_BOOLEAN);
154
155 vhdl_fcall *conv =
156 new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_BOOLEAN),
157 vhdl_type::boolean());
158 conv->add_expr(this);
159 return conv;
160 }
161 else if (type_->get_name() == VHDL_TYPE_SIGNED) {
162 require_support_function(SF_SIGNED_TO_BOOLEAN);
163
164 vhdl_fcall *conv =
165 new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_BOOLEAN),
166 vhdl_type::boolean());
167 conv->add_expr(this);
168 return conv;
169 }
170 assert(false);
171 return NULL;
172 }
173
174 /*
175 * Generate code to convert and expression to std_logic.
176 */
to_std_logic()177 vhdl_expr *vhdl_expr::to_std_logic()
178 {
179 if (type_->get_name() == VHDL_TYPE_BOOLEAN) {
180 require_support_function(SF_BOOLEAN_TO_LOGIC);
181
182 vhdl_fcall *ah =
183 new vhdl_fcall(support_function::function_name(SF_BOOLEAN_TO_LOGIC),
184 vhdl_type::std_logic());
185 ah->add_expr(this);
186
187 return ah;
188 }
189 else if (type_->get_name() == VHDL_TYPE_SIGNED) {
190 require_support_function(SF_SIGNED_TO_LOGIC);
191
192 vhdl_fcall *ah =
193 new vhdl_fcall(support_function::function_name(SF_SIGNED_TO_LOGIC),
194 vhdl_type::std_logic());
195 ah->add_expr(this);
196
197 return ah;
198 }
199 else if (type_->get_name() == VHDL_TYPE_UNSIGNED) {
200 require_support_function(SF_UNSIGNED_TO_LOGIC);
201
202 vhdl_fcall *ah =
203 new vhdl_fcall(support_function::function_name(SF_UNSIGNED_TO_LOGIC),
204 vhdl_type::std_logic());
205 ah->add_expr(this);
206
207 return ah;
208 }
209 assert(false);
210 return NULL;
211 }
212
to_std_ulogic()213 vhdl_expr *vhdl_expr::to_std_ulogic()
214 {
215 if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
216 vhdl_fcall *f = new vhdl_fcall("std_logic", vhdl_type::std_logic());
217 f->add_expr(this);
218 return f;
219 }
220 else
221 assert(false);
222 return NULL;
223 }
224
225 /*
226 * Change the width of a signed/unsigned type.
227 */
resize(int newwidth)228 vhdl_expr *vhdl_expr::resize(int newwidth)
229 {
230 vhdl_type *rtype;
231 assert(type_);
232 if (type_->get_name() == VHDL_TYPE_SIGNED)
233 rtype = vhdl_type::nsigned(newwidth);
234 else if (type_->get_name() == VHDL_TYPE_UNSIGNED)
235 rtype = vhdl_type::nunsigned(newwidth);
236 else if (type_->get_name() == VHDL_TYPE_STD_LOGIC) {
237 // Pad it with zeros
238 vhdl_expr* zeros = new vhdl_const_bits(string(newwidth - 1, '0').c_str(),
239 newwidth - 1, false, true);
240
241 vhdl_binop_expr* concat =
242 new vhdl_binop_expr(zeros, VHDL_BINOP_CONCAT, this,
243 vhdl_type::nunsigned(newwidth));
244 return concat;
245 }
246 else
247 return this; // Doesn't make sense to resize non-vector type
248
249 vhdl_fcall *resizef = new vhdl_fcall("Resize", rtype);
250 resizef->add_expr(this);
251 resizef->add_expr(new vhdl_const_int(newwidth));
252
253 return resizef;
254 }
255
to_vector(vhdl_type_name_t name,int w)256 vhdl_expr *vhdl_const_int::to_vector(vhdl_type_name_t name, int w)
257 {
258 if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) {
259
260 const char *fname = name == VHDL_TYPE_SIGNED
261 ? "To_Signed" : "To_Unsigned";
262 vhdl_fcall *conv = new vhdl_fcall(fname, new vhdl_type(name, w - 1, 0));
263 conv->add_expr(this);
264 conv->add_expr(new vhdl_const_int(w));
265
266 return conv;
267 }
268 else
269 return vhdl_expr::to_vector(name, w);
270 }
271
bits_to_int() const272 int64_t vhdl_const_bits::bits_to_int() const
273 {
274 char msb = value_[value_.size() - 1];
275 int64_t result = 0, bit;
276 for (int i = sizeof(int64_t)*8 - 1; i >= 0; i--) {
277 if (i > (int)value_.size() - 1)
278 bit = (msb == '1' && signed_) ? 1 : 0;
279 else
280 bit = value_[i] == '1' ? 1 : 0;
281 result = (result << 1) | bit;
282 }
283
284 return result;
285 }
286
to_std_logic()287 vhdl_expr *vhdl_const_bits::to_std_logic()
288 {
289 // VHDL won't let us cast directly between a vector and
290 // a scalar type
291 // But we don't need to here as we have the bits available
292
293 // Take the least significant bit
294 char lsb = value_[0];
295
296 return new vhdl_const_bit(lsb);
297 }
298
sign_bit() const299 char vhdl_const_bits::sign_bit() const
300 {
301 return signed_ ? value_[value_.length()-1] : '0';
302 }
303
to_vector(vhdl_type_name_t name,int w)304 vhdl_expr *vhdl_const_bits::to_vector(vhdl_type_name_t name, int w)
305 {
306 if (name == VHDL_TYPE_STD_LOGIC_VECTOR) {
307 // Don't need to do anything
308 return this;
309 }
310 else if (name == VHDL_TYPE_SIGNED || name == VHDL_TYPE_UNSIGNED) {
311 // Extend with sign bit
312 value_.resize(w, sign_bit());
313 return this;
314 }
315 assert(false);
316 return NULL;
317 }
318
to_integer()319 vhdl_expr *vhdl_const_bits::to_integer()
320 {
321 return new vhdl_const_int(bits_to_int());
322 }
323
resize(int w)324 vhdl_expr *vhdl_const_bits::resize(int w)
325 {
326 // Rather than generating a call to Resize, when can just sign-extend
327 // the bits here. As well as looking better, this avoids any ambiguity
328 // between which of the signed/unsigned versions of Resize to use.
329
330 value_.resize(w, sign_bit());
331 return this;
332 }
333
to_integer()334 vhdl_expr *vhdl_const_bit::to_integer()
335 {
336 return new vhdl_const_int(bit_ == '1' ? 1 : 0);
337 }
338
to_boolean()339 vhdl_expr *vhdl_const_bit::to_boolean()
340 {
341 return new vhdl_const_bool(bit_ == '1');
342 }
343
to_std_ulogic()344 vhdl_expr *vhdl_const_bit::to_std_ulogic()
345 {
346 return this;
347 }
348
to_vector(vhdl_type_name_t name,int w)349 vhdl_expr *vhdl_const_bit::to_vector(vhdl_type_name_t name, int w)
350 {
351 // Zero-extend this bit to the correct width
352 return (new vhdl_const_bits(&bit_, 1, name == VHDL_TYPE_SIGNED))->resize(w);
353 }
354