/* * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf * * 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 "kernel/cellaigs.h" YOSYS_NAMESPACE_BEGIN AigNode::AigNode() { portbit = -1; inverter = false; left_parent = -1; right_parent = -1; } bool AigNode::operator==(const AigNode &other) const { if (portname != other.portname) return false; if (portbit != other.portbit) return false; if (inverter != other.inverter) return false; if (left_parent != other.left_parent) return false; if (right_parent != other.right_parent) return false; return true; } unsigned int AigNode::hash() const { unsigned int h = mkhash_init; h = mkhash(portname.hash(), portbit); h = mkhash(h, inverter); h = mkhash(h, left_parent); h = mkhash(h, right_parent); return h; } bool Aig::operator==(const Aig &other) const { return name == other.name; } unsigned int Aig::hash() const { return hash_ops::hash(name); } struct AigMaker { Aig *aig; Cell *cell; idict aig_indices; int the_true_node; int the_false_node; AigMaker(Aig *aig, Cell *cell) : aig(aig), cell(cell) { the_true_node = -1; the_false_node = -1; } int node2index(const AigNode &node) { if (node.left_parent > node.right_parent) { AigNode n(node); std::swap(n.left_parent, n.right_parent); return node2index(n); } if (!aig_indices.count(node)) { aig_indices.expect(node, GetSize(aig->nodes)); aig->nodes.push_back(node); } return aig_indices.at(node); } int bool_node(bool value) { AigNode node; node.inverter = value; return node2index(node); } int inport(IdString portname, int portbit = 0, bool inverter = false) { if (portbit >= GetSize(cell->getPort(portname))) { if (cell->parameters.count(portname.str() + "_SIGNED") && cell->getParam(portname.str() + "_SIGNED").as_bool()) return inport(portname, GetSize(cell->getPort(portname))-1, inverter); return bool_node(inverter); } AigNode node; node.portname = portname; node.portbit = portbit; node.inverter = inverter; return node2index(node); } vector inport_vec(IdString portname, int width) { vector vec; for (int i = 0; i < width; i++) vec.push_back(inport(portname, i)); return vec; } int not_inport(IdString portname, int portbit = 0) { return inport(portname, portbit, true); } int not_gate(int A) { AigNode node(aig_indices[A]); node.outports.clear(); node.inverter = !node.inverter; return node2index(node); } int and_gate(int A, int B, bool inverter = false) { if (A == B) return inverter ? not_gate(A) : A; const AigNode &nA = aig_indices[A]; const AigNode &nB = aig_indices[B]; AigNode nB_inv(nB); nB_inv.inverter = !nB_inv.inverter; if (nA == nB_inv) return bool_node(inverter); bool nA_bool = nA.portbit < 0 && nA.left_parent < 0 && nA.right_parent < 0; bool nB_bool = nB.portbit < 0 && nB.left_parent < 0 && nB.right_parent < 0; if (nA_bool && nB_bool) { bool bA = nA.inverter; bool bB = nB.inverter; return bool_node(inverter != (bA && bB)); } if (nA_bool) { bool bA = nA.inverter; if (inverter) return bA ? not_gate(B) : bool_node(true); return bA ? B : bool_node(false); } if (nB_bool) { bool bB = nB.inverter; if (inverter) return bB ? not_gate(A) : bool_node(true); return bB ? A : bool_node(false); } AigNode node; node.inverter = inverter; node.left_parent = A; node.right_parent = B; return node2index(node); } int nand_gate(int A, int B) { return and_gate(A, B, true); } int or_gate(int A, int B) { return nand_gate(not_gate(A), not_gate(B)); } int nor_gate(int A, int B) { return and_gate(not_gate(A), not_gate(B)); } int xor_gate(int A, int B) { return nor_gate(and_gate(A, B), nor_gate(A, B)); } int xnor_gate(int A, int B) { return or_gate(and_gate(A, B), nor_gate(A, B)); } int andnot_gate(int A, int B) { return and_gate(A, not_gate(B)); } int ornot_gate(int A, int B) { return or_gate(A, not_gate(B)); } int mux_gate(int A, int B, int S) { return or_gate(and_gate(A, not_gate(S)), and_gate(B, S)); } vector adder(const vector &A, const vector &B, int carry, vector *X = nullptr, vector *CO = nullptr) { vector Y(GetSize(A)); log_assert(GetSize(A) == GetSize(B)); for (int i = 0; i < GetSize(A); i++) { Y[i] = xor_gate(xor_gate(A[i], B[i]), carry); carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry)); if (X != nullptr) X->at(i) = xor_gate(A[i], B[i]); if (CO != nullptr) CO->at(i) = carry; } return Y; } void outport(int node, IdString portname, int portbit = 0) { if (portbit < GetSize(cell->getPort(portname))) aig->nodes.at(node).outports.push_back(pair(portname, portbit)); } void outport_bool(int node, IdString portname) { outport(node, portname); for (int i = 1; i < GetSize(cell->getPort(portname)); i++) outport(bool_node(false), portname, i); } void outport_vec(const vector &vec, IdString portname) { for (int i = 0; i < GetSize(vec); i++) outport(vec.at(i), portname, i); } }; Aig::Aig(Cell *cell) { if (cell->type[0] != '$') return; AigMaker mk(this, cell); name = cell->type.str(); string mkname_last; bool mkname_a_signed = false; bool mkname_b_signed = false; bool mkname_is_signed = false; cell->parameters.sort(); for (auto p : cell->parameters) { if (p.first == ID(A_WIDTH) && mkname_a_signed) { name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); } else if (p.first == ID(B_WIDTH) && mkname_b_signed) { name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); } else { mkname_last = name; name += stringf(":%d", p.second.as_int()); } mkname_a_signed = false; mkname_b_signed = false; mkname_is_signed = false; if (p.first == ID(A_SIGNED)) { mkname_a_signed = true; mkname_is_signed = p.second.as_bool(); } if (p.first == ID(B_SIGNED)) { mkname_b_signed = true; mkname_is_signed = p.second.as_bool(); } } if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_))) { for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { int A = mk.inport(ID::A, i); int Y = cell->type.in(ID($not), ID($_NOT_)) ? mk.not_gate(A) : A; mk.outport(Y, ID::Y, i); } goto optimize; } if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_), ID($or), ID($_OR_), ID($_NOR_), ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) { for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { int A = mk.inport(ID::A, i); int B = mk.inport(ID::B, i); int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) : cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) : cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) : cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B)
/*
 *  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 */