Improve write_verilog specify support
[yosys.git] / frontends / ast / dpicall.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "ast.h"
21
22 #ifdef YOSYS_ENABLE_PLUGINS
23
24 #include <dlfcn.h>
25 #include <ffi.h>
26
27 YOSYS_NAMESPACE_BEGIN
28
29 typedef void (*ffi_fptr) ();
30
31 static ffi_fptr resolve_fn (std::string symbol_name)
32 {
33 if (symbol_name.find(':') != std::string::npos)
34 {
35 int pos = symbol_name.find(':');
36 std::string plugin_name = symbol_name.substr(0, pos);
37 std::string real_symbol_name = symbol_name.substr(pos+1);
38
39 while (loaded_plugin_aliases.count(plugin_name))
40 plugin_name = loaded_plugin_aliases.at(plugin_name);
41
42 if (loaded_plugins.count(plugin_name) == 0)
43 log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());
44
45 void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());
46
47 if (symbol == nullptr)
48 log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n",
49 symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str());
50
51 return (ffi_fptr) symbol;
52 }
53
54 for (auto &it : loaded_plugins) {
55 void *symbol = dlsym(it.second, symbol_name.c_str());
56 if (symbol != nullptr)
57 return (ffi_fptr) symbol;
58 }
59
60 void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str());
61 if (symbol != nullptr)
62 return (ffi_fptr) symbol;
63
64 log_error("unable to resolve '%s'.\n", symbol_name.c_str());
65 }
66
67 AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
68 {
69 AST::AstNode *newNode = nullptr;
70 union { double f64; float f32; int32_t i32; } value_store [args.size() + 1];
71 ffi_type *types [args.size() + 1];
72 void *values [args.size() + 1];
73 ffi_cif cif;
74 int status;
75
76 log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
77
78 log_assert(GetSize(args) == GetSize(argtypes));
79 for (int i = 0; i < GetSize(args); i++) {
80 if (argtypes[i] == "real") {
81 log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
82 value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
83 values[i] = &value_store[i].f64;
84 types[i] = &ffi_type_double;
85 } else if (argtypes[i] == "shortreal") {
86 log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
87 value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
88 values[i] = &value_store[i].f32;
89 types[i] = &ffi_type_double;
90 } else if (argtypes[i] == "integer") {
91 log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
92 value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
93 values[i] = &value_store[i].i32;
94 types[i] = &ffi_type_sint32;
95 } else {
96 log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
97 }
98 }
99
100 if (rtype == "integer") {
101 types[args.size()] = &ffi_type_slong;
102 values[args.size()] = &value_store[args.size()].i32;
103 } else if (rtype == "shortreal") {
104 types[args.size()] = &ffi_type_float;
105 values[args.size()] = &value_store[args.size()].f32;
106 } else if (rtype == "real") {
107 types[args.size()] = &ffi_type_double;
108 values[args.size()] = &value_store[args.size()].f64;
109 } else {
110 log_error("invalid rtype '%s'.\n", rtype.c_str());
111 }
112
113 if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
114 log_error("ffi_prep_cif failed: status %d.\n", status);
115
116 ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);
117
118 if (rtype == "real") {
119 newNode = new AstNode(AST_REALVALUE);
120 newNode->realvalue = value_store[args.size()].f64;
121 log(" return realvalue: %g\n", newNode->asReal(true));
122 } else if (rtype == "shortreal") {
123 newNode = new AstNode(AST_REALVALUE);
124 newNode->realvalue = value_store[args.size()].f32;
125 log(" return realvalue: %g\n", newNode->asReal(true));
126 } else {
127 newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
128 log(" return integer: %lld\n", (long long)newNode->asInt(true));
129 }
130
131 return newNode;
132 }
133
134 YOSYS_NAMESPACE_END
135
136 #else /* YOSYS_ENABLE_PLUGINS */
137
138 YOSYS_NAMESPACE_BEGIN
139
140 AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
141 {
142 log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
143 }
144
145 YOSYS_NAMESPACE_END
146
147 #endif /* YOSYS_ENABLE_PLUGINS */
148