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