aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast/dpicall.cc
blob: e241142d35268cacbcf9806c7bc547e6f354fe10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "ast.h"

#ifdef YOSYS_ENABLE_PLUGINS

#include <dlfcn.h>
#include <ffi.h>

YOSYS_NAMESPACE_BEGIN

typedef void (*ffi_fptr) ();

static ffi_fptr resolve_fn (std::string symbol_name)
{
	if (symbol_name.find(':') != std::string::npos)
	{
		int pos = symbol_name.find(':');
		std::string plugin_name = symbol_name.substr(0, pos);
		std::string real_symbol_name = symbol_name.substr(pos+1);

		while (loaded_plugin_aliases.count(plugin_name))
			plugin_name = loaded_plugin_aliases.at(plugin_name);

		if (loaded_plugins.count(plugin_name) == 0)
			log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());

		void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());

		if (symbol == nullptr)
			log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n",
					symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str());

		return (ffi_fptr) symbol;
	}

	for (auto &it : loaded_plugins) {
		void *symbol = dlsym(it.second, symbol_name.c_str());
		if (symbol != nullptr)
			return (ffi_fptr) symbol;
	}

	void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str());
	if (symbol != nullptr)
		return (ffi_fptr) symbol;

	log_error("unable to resolve '%s'.\n", symbol_name.c_str());
}

AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
{
	AST::AstNode *newNode = nullptr;
	union { double f64; float f32; int32_t i32; } value_store [args.size() + 1];
	ffi_type *types [args.size() + 1];
	void *values [args.size() + 1];
	ffi_cif cif;
	int status;

	log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());

	log_assert(GetSize(args) == GetSize(argtypes));
	for (int i = 0; i < GetSize(args); i++) {
		if (argtypes[i] == "real") {
			log("  arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
			value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
			values[i] = &value_store[i].f64;
			types[i] = &ffi_type_double;
		} else if (argtypes[i] == "shortreal") {
			log("  arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
			value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
			values[i] = &value_store[i].f32;
			types[i] = &ffi_type_double;
		} else if (argtypes[i] == "integer") {
			log("  arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
			value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
			values[i] = &value_store[i].i32;
			types[i] = &ffi_type_sint32;
		} else {
			log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
		}
	}

        if (rtype == "integer") {
                types[args.size()] = &ffi_type_slong;
                values[args.size()] = &value_store[args.size()].i32;
        } else if (rtype == "shortreal") {
                types[args.size()] = &ffi_type_float;
                values[args.size()] = &value_store[args.size()].f32;
        } else if (rtype == "real") {
                types[args.size()] = &ffi_type_double;
                values[args.size()] = &value_store[args.size()].f64;
        } else {
                log_error("invalid rtype '%s'.\n", rtype.c_str());
        }

        if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
                log_error("ffi_prep_cif failed: status %d.\n", status);

        ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);

	if (rtype == "real") {
		newNode = new AstNode(AST_REALVALUE);
		newNode->realvalue = value_store[args.size()].f64;
		log("  return realvalue: %g\n", newNode->asReal(true));
	} else if (rtype == "shortreal") {
		newNode = new AstNode(AST_REALVALUE);
		newNode->realvalue = value_store[args.size()].f32;
		log("  return realvalue: %g\n", newNode->asReal(true));
	} else {
		newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
		log("  return integer: %lld\n", (long long)newNode->asInt(true));
	}

	return newNode;
}

YOSYS_NAMESPACE_END

#else /* YOSYS_ENABLE_PLUGINS */

YOSYS_NAMESPACE_BEGIN

AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{
	log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}

YOSYS_NAMESPACE_END

#endif /* YOSYS_ENABLE_PLUGINS */
an class="p">(table, key, value) st_table *table; register char *key; int *value; { int hash_val; register st_table_entry *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr, last); if (ptr == NULL) { return 0; } else { if (value != 0) { *value = (long) ptr->record; } return 1; } } /* This macro does not check if memory allocation fails. Use at you own risk */ #define ADD_DIRECT(table, key, value, hash_val, new)\ {\ if (table->num_entries/table->num_bins >= table->max_density) {\ rehash(table);\ hash_val = do_hash(key,table);\ }\ \ new = ABC_ALLOC(st_table_entry, 1);\ \ new->key = key;\ new->record = value;\ new->next = table->bins[hash_val];\ table->bins[hash_val] = new;\ table->num_entries++;\ } int st_insert(table, key, value) register st_table *table; register char *key; char *value; { int hash_val; st_table_entry *new; register st_table_entry *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr, last); if (ptr == NULL) { if (table->num_entries/table->num_bins >= table->max_density) { if (rehash(table) == ST_OUT_OF_MEM) { return ST_OUT_OF_MEM; } hash_val = do_hash(key, table); } new = ABC_ALLOC(st_table_entry, 1); if (new == NULL) { return ST_OUT_OF_MEM; } new->key = key; new->record = value; new->next = table->bins[hash_val]; table->bins[hash_val] = new; table->num_entries++; return 0; } else { ptr->record = value; return 1; } } int st_add_direct(table, key, value) st_table *table; char *key; char *value; { int hash_val; st_table_entry *new; hash_val = do_hash(key, table); if (table->num_entries / table->num_bins >= table->max_density) { if (rehash(table) == ST_OUT_OF_MEM) { return ST_OUT_OF_MEM; } } hash_val = do_hash(key, table); new = ABC_ALLOC(st_table_entry, 1); if (new == NULL) { return ST_OUT_OF_MEM; } new->key = key; new->record = value; new->next = table->bins[hash_val]; table->bins[hash_val] = new; table->num_entries++; return 1; } int st_find_or_add(table, key, slot) st_table *table; char *key; char ***slot; { int hash_val; st_table_entry *new, *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr, last); if (ptr == NULL) { if (table->num_entries / table->num_bins >= table->max_density) { if (rehash(table) == ST_OUT_OF_MEM) { return ST_OUT_OF_MEM; } hash_val = do_hash(key, table); } new = ABC_ALLOC(st_table_entry, 1); if (new == NULL) { return ST_OUT_OF_MEM; } new->key = key; new->record = (char *) 0; new->next = table->bins[hash_val]; table->bins[hash_val] = new; table->num_entries++; if (slot != NULL) *slot = &new->record; return 0; } else { if (slot != NULL) *slot = &ptr->record; return 1; } } int st_find(table, key, slot) st_table *table; char *key; char ***slot; { int hash_val; st_table_entry *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr, last); if (ptr == NULL) { return 0; } else { if (slot != NULL) { *slot = &ptr->record; } return 1; } } static int rehash(table) register st_table *table; { register st_table_entry *ptr, *next, **old_bins; int i, old_num_bins, hash_val, old_num_entries; /* save old values */ old_bins = table->bins; old_num_bins = table->num_bins; old_num_entries = table->num_entries; /* rehash */ table->num_bins = (int)(table->grow_factor * old_num_bins); if (table->num_bins % 2 == 0) { table->num_bins += 1; } table->num_entries = 0; table->bins = ABC_ALLOC(st_table_entry *, table->num_bins); if (table->bins == NULL) { table->bins = old_bins; table->num_bins = old_num_bins; table->num_entries = old_num_entries; return ST_OUT_OF_MEM; } /* initialize */ for (i = 0; i < table->num_bins; i++) { table->bins[i] = 0; } /* copy data over */ for (i = 0; i < old_num_bins; i++) { ptr = old_bins[i]; while (ptr != NULL) { next = ptr->next; hash_val = do_hash(ptr->key, table); ptr->next = table->bins[hash_val]; table->bins[hash_val] = ptr; table->num_entries++; ptr = next; } } ABC_FREE(old_bins); return 1; } st_table * st_copy(old_table) st_table *old_table; { st_table *new_table; st_table_entry *ptr, *newptr, *next, *new; int i, j, num_bins = old_table->num_bins; new_table = ABC_ALLOC(st_table, 1); if (new_table == NULL) { return NULL; } *new_table = *old_table; new_table->bins = ABC_ALLOC(st_table_entry *, num_bins); if (new_table->bins == NULL) { ABC_FREE(new_table); return NULL; } for(i = 0; i < num_bins ; i++) { new_table->bins[i] = NULL; ptr = old_table->bins[i]; while (ptr != NULL) { new = ABC_ALLOC(st_table_entry, 1); if (new == NULL) { for (j = 0; j <= i; j++) { newptr = new_table->bins[j]; while (newptr != NULL) { next = newptr->next; ABC_FREE(newptr); newptr = next; } } ABC_FREE(new_table->bins); ABC_FREE(new_table); return NULL; } *new = *ptr; new->next = new_table->bins[i]; new_table->bins[i] = new; ptr = ptr->next; } } return new_table; } int st_delete(table, keyp, value) register st_table *table; register char **keyp; char **value; { int hash_val; char *key = *keyp; register st_table_entry *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr ,last); if (ptr == NULL) { return 0; } *last = ptr->next; if (value != NULL) *value = ptr->record; *keyp = ptr->key; ABC_FREE(ptr); table->num_entries--; return 1; } int st_delete_int(table, keyp, value) register st_table *table; register long *keyp; char **value; { int hash_val; char *key = (char *) *keyp; register st_table_entry *ptr, **last; hash_val = do_hash(key, table); FIND_ENTRY(table, hash_val, key, ptr ,last); if (ptr == NULL) { return 0; } *last = ptr->next; if (value != NULL) *value = ptr->record; *keyp = (long) ptr->key; ABC_FREE(ptr); table->num_entries--; return 1; } int st_foreach(table, func, arg) st_table *table; enum st_retval (*func)(); char *arg; { st_table_entry *ptr, **last; enum st_retval retval; int i; for(i = 0; i < table->num_bins; i++) { last = &table->bins[i]; ptr = *last; while (ptr != NULL) { retval = (*func)(ptr->key, ptr->record, arg); switch (retval) { case ST_CONTINUE: last = &ptr->next; ptr = *last; break; case ST_STOP: return 0; case ST_DELETE: *last = ptr->next; table->num_entries--; /* cstevens@ic */ ABC_FREE(ptr); ptr = *last; } } } return 1; } int st_strhash(string, modulus) register char *string; int modulus; { register int val = 0; register int c; while ((c = *string++) != '\0') { val = val*997 + c; } return ((val < 0) ? -val : val)%modulus; } int st_numhash(x, size) char *x; int size; { return ST_NUMHASH(x, size); } int st_ptrhash(x, size) char *x; int size; { return ST_PTRHASH(x, size); } int st_numcmp(x, y) char *x; char *y; { return ST_NUMCMP(x, y); } int st_ptrcmp(x, y) char *x; char *y; { return ST_NUMCMP(x, y); } st_generator * st_init_gen(table) st_table *table; { st_generator *gen; gen = ABC_ALLOC(st_generator, 1); if (gen == NULL) { return NULL; } gen->table = table; gen->entry = NULL; gen->index = 0; return gen; } int st_gen(gen, key_p, value_p) st_generator *gen; char **key_p; char **value_p; { register int i; if (gen->entry == NULL) { /* try to find next entry */ for(i = gen->index; i < gen->table->num_bins; i++) { if (gen->table->bins[i] != NULL) { gen->index = i+1; gen->entry = gen->table->bins[i]; break; } } if (gen->entry == NULL) { return 0; /* that's all folks ! */ } } *key_p = gen->entry->key; if (value_p != 0) { *value_p = gen->entry->record; } gen->entry = gen->entry->next; return 1; } int st_gen_int(gen, key_p, value_p) st_generator *gen; char **key_p; long *value_p; { register int i; if (gen->entry == NULL) { /* try to find next entry */ for(i = gen->index; i < gen->table->num_bins; i++) { if (gen->table->bins[i] != NULL) { gen->index = i+1; gen->entry = gen->table->bins[i]; break; } } if (gen->entry == NULL) { return 0; /* that's all folks ! */ } } *key_p = gen->entry->key; if (value_p != 0) { *value_p = (long) gen->entry->record; } gen->entry = gen->entry->next; return 1; } void st_free_gen(gen) st_generator *gen; { ABC_FREE(gen); }