1 /*
2 * Copyright CERN 2016-2018
3 * @author Maciej Suminski (maciej.suminski@cern.ch)
4 *
5 * This source code is free software; you can redistribute it
6 * and/or modify it in source code form under the terms of the GNU
7 * General Public License as published by the Free Software
8 * Foundation; either version 2 of the License, or (at your option)
9 * 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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include "std_funcs.h"
22 #include "std_types.h"
23 #include "scope.h"
24
25 static std::map<perm_string,SubHeaderList> std_subprograms;
26
register_std_subprogram(SubprogramHeader * header)27 void register_std_subprogram(SubprogramHeader*header)
28 {
29 std_subprograms[header->name()].push_back(header);
30 }
31
32 // Special case: to_integer function
33 class SubprogramToInteger : public SubprogramStdHeader {
34 public:
SubprogramToInteger()35 SubprogramToInteger()
36 : SubprogramStdHeader(perm_string::literal("to_integer"), NULL, &primitive_REAL) {
37 ports_ = new list<InterfacePort*>();
38 ports_->push_back(new InterfacePort(&primitive_INTEGER));
39 }
40
emit_name(const std::vector<Expression * > & argv,std::ostream & out,Entity * ent,ScopeBase * scope) const41 int emit_name(const std::vector<Expression*>&argv,
42 std::ostream&out, Entity*ent, ScopeBase*scope) const {
43 bool signed_flag = false;
44
45 // to_integer converts unsigned to natural
46 // signed to integer
47 // try to determine the converted type
48 const VType*type = argv[0]->probe_type(ent, scope);
49 const VTypeArray*array = dynamic_cast<const VTypeArray*>(type);
50
51 if(array) {
52 signed_flag = array->signed_vector();
53 } else {
54 cerr << get_fileline() << ": sorry: Could not determine the "
55 << "expression sign. Output may be erroneous." << endl;
56 return 1;
57 }
58
59 out << (signed_flag ? "$signed" : "$unsigned");
60 return 0;
61 }
62 };
63
64 // Special case: size casting (e.g. conv_std_logic_vector() / resize()).
65 class SubprogramSizeCast : public SubprogramStdHeader {
66 public:
SubprogramSizeCast(perm_string nam,const VType * base,const VType * target)67 explicit SubprogramSizeCast(perm_string nam, const VType*base, const VType*target)
68 : SubprogramStdHeader(nam, NULL, target) {
69 ports_ = new list<InterfacePort*>();
70 ports_->push_back(new InterfacePort(base));
71 ports_->push_back(new InterfacePort(&primitive_NATURAL));
72 }
73
emit_name(const std::vector<Expression * > &,std::ostream &,Entity *,ScopeBase *) const74 int emit_name(const std::vector<Expression*>&,
75 std::ostream&, Entity*, ScopeBase*) const {
76 return 0;
77 }
78
emit_args(const std::vector<Expression * > & argv,std::ostream & out,Entity * ent,ScopeBase * scope) const79 int emit_args(const std::vector<Expression*>&argv,
80 std::ostream&out, Entity*ent, ScopeBase*scope) const {
81 int64_t new_size, old_size;
82
83 const VType*type = argv[0]->probe_type(ent, scope);
84
85 if(!type) {
86 cerr << get_fileline() << ": sorry: Could not determine "
87 << "the argument type. Size casting impossible." << endl;
88 return 1;
89 }
90
91 old_size = type->get_width(scope);
92
93 if(old_size <= 0) {
94 cerr << get_fileline() << ": sorry: Could not determine "
95 << "the argument size. Size casting impossible." << endl;
96 return 1;
97 }
98
99 if(!argv[1]->evaluate(ent, scope, new_size)) {
100 cerr << get_fileline() << ": sorry: Could not evaluate the requested"
101 << "expression size. Size casting impossible." << endl;
102 return 1;
103 }
104
105
106 out << new_size << "'(" << old_size << "'(";
107
108 if(const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type))
109 out << (arr->signed_vector() ? "$signed" : "$unsigned");
110
111 out << "(";
112 bool res = argv[0]->emit(out, ent, scope);
113 out << ")))";
114
115 return res;
116 }
117 };
118
119 class SubprogramReadWrite : public SubprogramBuiltin {
120 public:
SubprogramReadWrite(perm_string nam,perm_string newnam,bool hex=false)121 SubprogramReadWrite(perm_string nam, perm_string newnam, bool hex = false)
122 : SubprogramBuiltin(nam, newnam, NULL, NULL), hex_format_(hex) {
123 ports_ = new list<InterfacePort*>();
124 ports_->push_back(new InterfacePort(&primitive_STRING));
125 ports_->push_back(new InterfacePort(NULL));
126 }
127
128 // Format types handled by $ivlh_read/write (see vpi/vhdl_textio.c)
129 enum format_t { FORMAT_STD, FORMAT_BOOL, FORMAT_TIME, FORMAT_HEX, FORMAT_STRING };
130
emit_args(const std::vector<Expression * > & argv,std::ostream & out,Entity * ent,ScopeBase * scope) const131 int emit_args(const std::vector<Expression*>&argv,
132 std::ostream&out, Entity*ent, ScopeBase*scope) const {
133
134 int errors = 0;
135
136 for(int i = 0; i < 2; ++i) {
137 errors += argv[i]->emit(out, ent, scope);
138 out << ", ";
139 }
140
141 const VType*arg_type = argv[1]->probe_type(ent, scope);
142
143 while(const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(arg_type))
144 arg_type = tdef->peek_definition();
145
146 // Pick the right format
147 if(hex_format_) {
148 out << FORMAT_HEX;
149 } else if(arg_type) {
150 if(arg_type->type_match(&primitive_TIME)) {
151 out << FORMAT_TIME;
152 } else if(arg_type->type_match(&type_BOOLEAN)) {
153 out << FORMAT_BOOL;
154 } else if(arg_type->type_match(&primitive_CHARACTER)) {
155 out << FORMAT_STRING;
156 } else {
157 const VTypeArray*arr = dynamic_cast<const VTypeArray*>(arg_type);
158
159 if(arr && arr->element_type() == &primitive_CHARACTER)
160 out << FORMAT_STRING;
161 else
162 out << FORMAT_STD;
163 }
164 } else {
165 out << FORMAT_STD;
166 }
167
168 return errors;
169 }
170
171 private:
172 bool hex_format_;
173 };
174
preload_std_funcs(void)175 void preload_std_funcs(void)
176 {
177 list<InterfacePort*>*args;
178
179 /* function now */
180 SubprogramBuiltin*fn_now = new SubprogramBuiltin(perm_string::literal("now"),
181 perm_string::literal("$time"), NULL, NULL);
182 register_std_subprogram(fn_now);
183
184 /* numeric_std library
185 * function unsigned
186 */
187 args = new list<InterfacePort*>();
188 args->push_back(new InterfacePort(&primitive_INTEGER));
189 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"),
190 perm_string::literal("$unsigned"),
191 args, &primitive_UNSIGNED));
192
193 args = new list<InterfacePort*>();
194 args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
195 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("unsigned"),
196 perm_string::literal("$unsigned"),
197 args, &primitive_UNSIGNED));
198
199 /* function integer
200 */
201 args = new list<InterfacePort*>();
202 args->push_back(new InterfacePort(&primitive_REAL));
203 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("integer"),
204 perm_string::literal("int'"),
205 args, &primitive_INTEGER));
206
207 /* function std_logic_vector
208 Special case: The std_logic_vector function casts its
209 argument to std_logic_vector. Internally, we don't
210 have to do anything for that to work.
211 */
212 args = new list<InterfacePort*>();
213 args->push_back(new InterfacePort(&primitive_SIGNED));
214 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("std_logic_vector"),
215 empty_perm_string,
216 args, &primitive_STDLOGIC_VECTOR));
217
218 args = new list<InterfacePort*>();
219 args->push_back(new InterfacePort(&primitive_UNSIGNED));
220 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("std_logic_vector"),
221 empty_perm_string,
222 args, &primitive_STDLOGIC_VECTOR));
223
224 /* numeric_std library
225 * function shift_left (arg: unsigned; count: natural) return unsigned;
226 * function shift_left (arg: signed; count: natural) return signed;
227 */
228 args = new list<InterfacePort*>();
229 args->push_back(new InterfacePort(&primitive_UNSIGNED));
230 args->push_back(new InterfacePort(&primitive_NATURAL));
231 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"),
232 perm_string::literal("$ivlh_shift_left"),
233 args, &primitive_UNSIGNED));
234
235 args = new list<InterfacePort*>();
236 args->push_back(new InterfacePort(&primitive_SIGNED));
237 args->push_back(new InterfacePort(&primitive_NATURAL));
238 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_left"),
239 perm_string::literal("$ivlh_shift_left"),
240 args, &primitive_SIGNED));
241
242 /* numeric_std library
243 * function shift_right (arg: unsigned; count: natural) return unsigned;
244 * function shift_right (arg: signed; count: natural) return signed;
245 */
246 args = new list<InterfacePort*>();
247 args->push_back(new InterfacePort(&primitive_UNSIGNED));
248 args->push_back(new InterfacePort(&primitive_NATURAL));
249 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_right"),
250 perm_string::literal("$ivlh_shift_right"),
251 args, &primitive_UNSIGNED));
252
253 args = new list<InterfacePort*>();
254 args->push_back(new InterfacePort(&primitive_SIGNED));
255 args->push_back(new InterfacePort(&primitive_NATURAL));
256 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("shift_right"),
257 perm_string::literal("$ivlh_shift_right"),
258 args, &primitive_SIGNED));
259
260 /* function resize
261 */
262 register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"),
263 &primitive_UNSIGNED, &primitive_UNSIGNED));
264
265 register_std_subprogram(new SubprogramSizeCast(perm_string::literal("resize"),
266 &primitive_SIGNED, &primitive_SIGNED));
267
268 /* std_logic_arith library
269 * function conv_std_logic_vector(arg: integer; size: integer) return std_logic_vector;
270 */
271 register_std_subprogram(new SubprogramSizeCast(
272 perm_string::literal("conv_std_logic_vector"),
273 &primitive_INTEGER, &primitive_STDLOGIC_VECTOR));
274
275 /* numeric_bit library
276 * function to_integer (arg: unsigned) return natural;
277 */
278 args = new list<InterfacePort*>();
279 args->push_back(new InterfacePort(&primitive_UNSIGNED));
280 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"),
281 perm_string::literal("$unsigned"),
282 args, &primitive_NATURAL));
283
284 /* numeric_bit library
285 * function to_integer (arg: signed) return integer;
286 */
287 args = new list<InterfacePort*>();
288 args->push_back(new InterfacePort(&primitive_SIGNED));
289 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_integer"),
290 perm_string::literal("$signed"),
291 args, &primitive_INTEGER));
292
293 /* std_logic_1164 library
294 * function to_bit (signal s : std_ulogic) return bit;
295 */
296 args = new list<InterfacePort*>();
297 args->push_back(new InterfacePort(&primitive_STDLOGIC));
298 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_bit"),
299 empty_perm_string,
300 args, &primitive_BIT));
301
302 /* std_logic_1164 library
303 * function to_bitvector (signal s : std_logic_vector) return bit_vector;
304 * function to_bitvector (signal s : std_ulogic_vector) return bit_vector;
305 */
306 args = new list<InterfacePort*>();
307 args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
308 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_bitvector"),
309 empty_perm_string,
310 args, &primitive_BIT_VECTOR));
311
312 /* std_logic_1164 library
313 * function rising_edge (signal s : std_ulogic) return boolean;
314 */
315 args = new list<InterfacePort*>();
316 args->push_back(new InterfacePort(&primitive_STDLOGIC));
317 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("rising_edge"),
318 perm_string::literal("$ivlh_rising_edge"),
319 args, &type_BOOLEAN));
320
321 /* std_logic_1164 library
322 * function falling_edge (signal s : std_ulogic) return boolean;
323 */
324 args = new list<InterfacePort*>();
325 args->push_back(new InterfacePort(&primitive_STDLOGIC));
326 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("falling_edge"),
327 perm_string::literal("$ivlh_falling_edge"),
328 args, &type_BOOLEAN));
329
330 /* reduce_pack library
331 * function or_reduce(arg : std_logic_vector) return std_logic;
332 */
333 args = new list<InterfacePort*>();
334 args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
335 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("or_reduce"),
336 perm_string::literal("|"),
337 args, &primitive_STDLOGIC));
338
339 /* reduce_pack library
340 * function and_reduce(arg : std_logic_vector) return std_logic;
341 */
342 args = new list<InterfacePort*>();
343 args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
344 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("and_reduce"),
345 perm_string::literal("&"),
346 args, &primitive_STDLOGIC));
347
348 /* fixed_pkg library
349 * function to_unsigned (
350 * arg : ufixed; -- fixed point input
351 * constant size : natural) -- length of output
352 * return unsigned;
353 */
354 args = new list<InterfacePort*>();
355 args->push_back(new InterfacePort(&primitive_REAL));
356 args->push_back(new InterfacePort(&primitive_NATURAL));
357 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"),
358 perm_string::literal("$ivlh_to_unsigned"),
359 args, &primitive_UNSIGNED));
360 /* numeric_std library
361 * function to_unsigned(arg, size : natural) return unsigned;
362 */
363 args = new list<InterfacePort*>();
364 args->push_back(new InterfacePort(&primitive_NATURAL));
365 args->push_back(new InterfacePort(&primitive_NATURAL));
366 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"),
367 perm_string::literal("$ivlh_to_unsigned"),
368 args, &primitive_UNSIGNED));
369
370 /* numeric_std library
371 * function to_unsigned(arg : std_logic_vector, size : natural) return unsigned;
372 */
373 args = new list<InterfacePort*>();
374 args->push_back(new InterfacePort(&primitive_STDLOGIC_VECTOR));
375 args->push_back(new InterfacePort(&primitive_NATURAL));
376 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("to_unsigned"),
377 perm_string::literal("$ivlh_to_unsigned"),
378 args, &primitive_UNSIGNED));
379
380 /* procedure file_open (file f: text; filename: in string, file_open_kind: in mode);
381 */
382 args = new list<InterfacePort*>();
383 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
384 args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
385 args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
386 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"),
387 perm_string::literal("$ivlh_file_open"),
388 args, NULL));
389
390 /* procedure file_open (status: out file_open_status, file f: text; filename: in string, file_open_kind: in mode);
391 */
392 args = new list<InterfacePort*>();
393 args->push_back(new InterfacePort(&type_FILE_OPEN_STATUS, PORT_OUT));
394 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
395 args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
396 args->push_back(new InterfacePort(&type_FILE_OPEN_KIND, PORT_IN));
397 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_open"),
398 perm_string::literal("$ivlh_file_open"),
399 args, NULL));
400
401 /* std.textio library
402 * procedure file_close (file f: text);
403 */
404 args = new list<InterfacePort*>();
405 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
406 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("file_close"),
407 perm_string::literal("$fclose"),
408 args, NULL));
409
410 /* std.textio library
411 * procedure read (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
412 */
413 register_std_subprogram(new SubprogramReadWrite(perm_string::literal("read"),
414 perm_string::literal("$ivlh_read")));
415
416 /* std.textio library
417 * procedure write (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
418 */
419 register_std_subprogram(new SubprogramReadWrite(perm_string::literal("write"),
420 perm_string::literal("$ivlh_write")));
421
422 /* std.textio library
423 * procedure hread (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
424 */
425 register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hread"),
426 perm_string::literal("$ivlh_read"), true));
427
428 /* std.textio library
429 * procedure hwrite (l: inout line; value: out bit/bit_vector/boolean/character/integer/real/string/time);
430 */
431 register_std_subprogram(new SubprogramReadWrite(perm_string::literal("hwrite"),
432 perm_string::literal("$ivlh_write"), true));
433
434 /* std.textio library
435 * procedure readline (file f: text; l: inout line);
436 */
437 args = new list<InterfacePort*>();
438 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
439 args->push_back(new InterfacePort(&primitive_STRING, PORT_OUT));
440 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("readline"),
441 perm_string::literal("$ivlh_readline"),
442 args, NULL));
443
444 /* std.textio library
445 * procedure writeline (file f: text; l: inout line);
446 */
447 args = new list<InterfacePort*>();
448 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
449 args->push_back(new InterfacePort(&primitive_STRING, PORT_IN));
450 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("writeline"),
451 perm_string::literal("$ivlh_writeline"),
452 args, NULL));
453
454 /* function endline (file f: text) return boolean;
455 */
456 args = new list<InterfacePort*>();
457 args->push_back(new InterfacePort(&primitive_INTEGER, PORT_IN));
458 register_std_subprogram(new SubprogramBuiltin(perm_string::literal("endfile"),
459 perm_string::literal("$feof"),
460 args, &type_BOOLEAN));
461 }
462
delete_std_funcs()463 void delete_std_funcs()
464 {
465 for(std::map<perm_string,SubHeaderList>::iterator cur = std_subprograms.begin();
466 cur != std_subprograms.end(); ++cur) {
467 for(SubHeaderList::const_iterator it = cur->second.begin();
468 it != cur->second.end(); ++it) {
469 delete *it;
470 }
471 }
472 }
473
find_std_subprogram(perm_string name)474 SubHeaderList find_std_subprogram(perm_string name)
475 {
476 map<perm_string,SubHeaderList>::const_iterator cur = std_subprograms.find(name);
477 if(cur != std_subprograms.end())
478 return cur->second;
479
480 return SubHeaderList();
481 }
482