diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/design.cc | 1 | ||||
| -rw-r--r-- | common/design.h | 119 | ||||
| -rw-r--r-- | common/pybindings.cc | 121 | ||||
| -rw-r--r-- | common/pybindings.h | 123 | ||||
| -rw-r--r-- | common/pycontainers.h | 129 | ||||
| -rw-r--r-- | common/rulecheck.cc | 1 | 
6 files changed, 367 insertions, 127 deletions
| diff --git a/common/design.cc b/common/design.cc index 7ba6a9b1..6ab122df 100644 --- a/common/design.cc +++ b/common/design.cc @@ -18,4 +18,3 @@   */  #include "design.h" - diff --git a/common/design.h b/common/design.h index 314c2fd7..f4c24f15 100644 --- a/common/design.h +++ b/common/design.h @@ -20,50 +20,52 @@  #ifndef DESIGN_H  #define DESIGN_H -#include <stdint.h>  #include <assert.h> -#include <vector> +#include <stdint.h>  #include <string> -#include <unordered_set>  #include <unordered_map> +#include <unordered_set> +#include <vector>  // replace with proper IdString later  typedef std::string IdString;  // replace with haslib later -template<typename T> using pool = std::unordered_set<T>; -template<typename T, typename U> using dict = std::unordered_map<T, U>; +template <typename T> using pool = std::unordered_set<T>; +template <typename T, typename U> using dict = std::unordered_map<T, U>;  using std::vector;  struct GraphicElement  { -	// This will control colour, and there should be separate -	// visibility controls in some cases also -	enum { -		// Wires entirely inside tiles, e.g. between switchbox and bels -		G_LOCAL_WIRES, -		// Standard inter-tile routing -		G_GENERAL_WIRES, -		// Special inter-tile wires, e.g. carry chains -		G_DEDICATED_WIRES, -		G_BEL_OUTLINE, -		G_SWITCHBOX_OUTLINE, -		G_TILE_OUTLINE, -		G_BEL_PINS, -		G_SWITCHBOX_PINS, -		G_BEL_MISC, -		G_TILE_MISC, -	} style; - -	enum { -		G_LINE, -		G_BOX, -		G_CIRCLE, -		G_LABEL -	} type; - -	float x1, y1, x2, y2, z; -	std::string text; +    // This will control colour, and there should be separate +    // visibility controls in some cases also +    enum +    { +        // Wires entirely inside tiles, e.g. between switchbox and bels +        G_LOCAL_WIRES, +        // Standard inter-tile routing +        G_GENERAL_WIRES, +        // Special inter-tile wires, e.g. carry chains +        G_DEDICATED_WIRES, +        G_BEL_OUTLINE, +        G_SWITCHBOX_OUTLINE, +        G_TILE_OUTLINE, +        G_BEL_PINS, +        G_SWITCHBOX_PINS, +        G_BEL_MISC, +        G_TILE_MISC, +    } style; + +    enum +    { +        G_LINE, +        G_BOX, +        G_CIRCLE, +        G_LABEL +    } type; + +    float x1, y1, x2, y2, z; +    std::string text;  };  #include "chip.h" @@ -72,56 +74,57 @@ struct CellInfo;  struct PortRef  { -	CellInfo *cell; -	IdString port; +    CellInfo *cell; +    IdString port;  };  struct NetInfo  { -	IdString			name; -	PortRef				driver; -	vector<PortRef>			users; -	dict<IdString, std::string>	attrs; +    IdString name; +    PortRef driver; +    vector<PortRef> users; +    dict<IdString, std::string> attrs; -	// wire -> (uphill_wire, delay) -	dict<WireId, std::pair<WireId, DelayInfo>>	wires; +    // wire -> (uphill_wire, delay) +    dict<WireId, std::pair<WireId, DelayInfo>> wires;  };  enum PortType  { -	PORT_IN = 0, -	PORT_OUT = 1, -	PORT_INOUT = 2 +    PORT_IN = 0, +    PORT_OUT = 1, +    PORT_INOUT = 2  };  struct PortInfo  { -	IdString name; -	NetInfo *net; -	PortType type; +    IdString name; +    NetInfo *net; +    PortType type;  };  struct CellInfo  { -	IdString			name, type; -	dict<IdString, PortInfo>	ports; -	dict<IdString, std::string>	attrs, params; +    IdString name, type; +    dict<IdString, PortInfo> ports; +    dict<IdString, std::string> attrs, params; -	BelId bel; -	// cell_port -> bel_pin -	dict<IdString, IdString>	pins; +    BelId bel; +    // cell_port -> bel_pin +    dict<IdString, IdString> pins;  };  struct Design  { -	struct Chip chip; +    struct Chip chip; -	Design(ChipArgs args) : chip(args) { -		// ... -	} +    Design(ChipArgs args) : chip(args) +    { +        // ... +    } -	dict<IdString, NetInfo*>	nets; -	dict<IdString, CellInfo*>	cells; +    dict<IdString, NetInfo *> nets; +    dict<IdString, CellInfo *> cells;  };  #endif diff --git a/common/pybindings.cc b/common/pybindings.cc index 556e838e..5c86720e 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -18,24 +18,89 @@   *   */ - -#include "design.h"  #include "chip.h" +#include "design.h" +#include "emb.h" + +// include after design.h/chip.h  #include "pybindings.h" -// Required to determine concatenated module name (which differs for different archs) -#define PASTER(x, y) x ## _ ## y -#define EVALUATOR(x, y)  PASTER(x,y) +// Required to determine concatenated module name (which differs for different +// archs) +#define PASTER(x, y) x##_##y +#define EVALUATOR(x, y) PASTER(x, y)  #define MODULE_NAME EVALUATOR(nextpnrpy, ARCHNAME)  #define PYINIT_MODULE_NAME EVALUATOR(&PyInit_nextpnrpy, ARCHNAME)  #define STRINGIFY(x) #x  #define TOSTRING(x) STRINGIFY(x) -// Architecture-specific bindings should be created in the below function, which must be implemented in all -// architectures +// Architecture-specific bindings should be created in the below function, which +// must be implemented in all architectures  void arch_wrap_python(); -BOOST_PYTHON_MODULE (MODULE_NAME) { +bool operator==(const PortRef &a, const PortRef &b) +{ +    return (a.cell == b.cell) && (a.port == b.port); +} + +BOOST_PYTHON_MODULE(MODULE_NAME) +{ +    class_<GraphicElement>("GraphicElement") +            .def_readwrite("style", &GraphicElement::style) +            .def_readwrite("type", &GraphicElement::type) +            .def_readwrite("x1", &GraphicElement::x1) +            .def_readwrite("y1", &GraphicElement::y1) +            .def_readwrite("x2", &GraphicElement::x2) +            .def_readwrite("y2", &GraphicElement::y2) +            .def_readwrite("text", &GraphicElement::text); + +    class_<PortRef>("PortRef") +            .def_readwrite("cell", &PortRef::cell) +            .def_readwrite("port", &PortRef::port); + +    class_<NetInfo, NetInfo *>("NetInfo") +            .def_readwrite("name", &NetInfo::name) +            .def_readwrite("driver", &NetInfo::driver) +            .def_readwrite("users", &NetInfo::users) +            .def_readwrite("attrs", &NetInfo::attrs) +            .def_readwrite("wires", &NetInfo::wires); + +    WRAP_MAP(decltype(NetInfo::attrs), "IdStrMap"); + +    class_<vector<PortRef>>("PortRefVector") +            .def(vector_indexing_suite<vector<PortRef>>()); + +    enum_<PortType>("PortType") +            .value("PORT_IN", PORT_IN) +            .value("PORT_OUT", PORT_OUT) +            .value("PORT_INOUT", PORT_INOUT) +            .export_values(); + +    class_<PortInfo>("PortInfo") +            .def_readwrite("name", &PortInfo::name) +            .def_readwrite("net", &PortInfo::net) +            .def_readwrite("type", &PortInfo::type); + +    class_<CellInfo, CellInfo *>("CellInfo") +            .def_readwrite("name", &CellInfo::name) +            .def_readwrite("type", &CellInfo::type) +            .def_readwrite("ports", &CellInfo::ports) +            .def_readwrite("attrs", &CellInfo::attrs) +            .def_readwrite("params", &CellInfo::params) +            .def_readwrite("bel", &CellInfo::bel) +            .def_readwrite("pins", &CellInfo::pins); + +    WRAP_MAP(decltype(CellInfo::ports), "IdPortMap"); +    // WRAP_MAP(decltype(CellInfo::pins), "IdIdMap"); + +    class_<Design, Design *>("Design", no_init) +            .def_readwrite("chip", &Design::chip) +            .def_readwrite("nets", &Design::nets) +            .def_readwrite("cells", &Design::cells); + +    WRAP_MAP(decltype(Design::nets), "IdNetMap"); +    WRAP_MAP(decltype(Design::cells), "IdCellMap"); +      arch_wrap_python();  } @@ -44,35 +109,47 @@ void arch_appendinittab()      PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME);  } -void execute_python_file(const char *executable, const char* python_file) +static wchar_t *program; + +void init_python(const char *executable)  { -    wchar_t *program = Py_DecodeLocale(executable, NULL); +    program = Py_DecodeLocale(executable, NULL);      if (program == NULL) {          fprintf(stderr, "Fatal error: cannot decode executable filename\n");          exit(1);      } -    try  -    {		 +    try {          PyImport_AppendInittab(TOSTRING(MODULE_NAME), PYINIT_MODULE_NAME); +        emb::append_inittab();          Py_SetProgramName(program);          Py_Initialize(); +        PyImport_ImportModule(TOSTRING(MODULE_NAME)); +    } catch (boost::python::error_already_set const &) { +        // Parse and output the exception +        std::string perror_str = parse_python_exception(); +        std::cout << "Error in Python: " << perror_str << std::endl; +    } +} + +void deinit_python() +{ +    Py_Finalize(); +    PyMem_RawFree(program); +} -        FILE* fp = fopen(python_file, "r");	 +void execute_python_file(const char *python_file) +{ +    try { +        FILE *fp = fopen(python_file, "r");          if (fp == NULL) { -            fprintf(stderr, "Fatal error: file not found %s\n",python_file); +            fprintf(stderr, "Fatal error: file not found %s\n", python_file);              exit(1);          } -        PyRun_SimpleFile(fp , python_file); +        PyRun_SimpleFile(fp, python_file);          fclose(fp); - -        Py_Finalize(); -        PyMem_RawFree(program); -    }  -    catch(boost::python::error_already_set const &) -    { +    } catch (boost::python::error_already_set const &) {          // Parse and output the exception          std::string perror_str = parse_python_exception();          std::cout << "Error in Python: " << perror_str << std::endl;      }  } - diff --git a/common/pybindings.h b/common/pybindings.h index f594784c..bb060718 100644 --- a/common/pybindings.h +++ b/common/pybindings.h @@ -20,67 +20,98 @@  #ifndef COMMON_PYBINDINGS_H  #define COMMON_PYBINDINGS_H -#include <utility> -#include <stdexcept> + +#include "pycontainers.h" + +#include <Python.h>  #include <boost/python.hpp> -#include <boost/python/suite/indexing/vector_indexing_suite.hpp> -#include <boost/python/suite/indexing/map_indexing_suite.hpp>  #include <boost/python/suite/indexing/map_indexing_suite.hpp> - +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <stdexcept> +#include <utility>  using namespace boost::python; +  /* -A wrapper for a Pythonised nextpnr Iterator. The actual class wrapped is a -pair<Iterator, Iterator> containing (current, end) -*/ - -template<typename T> -struct iterator_wrapper { -    typedef decltype(*(std::declval<T>())) value_t; - -    static value_t next(std::pair<T, T> &iter) { -        if (iter.first != iter.second) { -            value_t val = *iter.first; -            ++iter.first; -            return val; -        } else { -            PyErr_SetString(PyExc_StopIteration, "End of range reached"); -            boost::python::throw_error_already_set(); -            // Should be unreachable, but prevent control may reach end of non-void -            throw std::runtime_error("unreachable"); +A wrapper to enable custom type/ID to/from string conversions + */ +template <typename T> struct string_wrapper +{ +    template <typename F> struct from_pystring_converter +    { +        from_pystring_converter() +        { +            converter::registry::push_back(&convertible, &construct, +                                           boost::python::type_id<T>()); +        }; + +        static void *convertible(PyObject *object) +        { +            return PyUnicode_Check(object) ? object : 0;          } -    } -    static void wrap(const char *python_name) { -        class_<std::pair<T, T>>(python_name, no_init) -                .def("__next__", next); -    } -}; +        static void construct(PyObject *object, +                              converter::rvalue_from_python_stage1_data *data) +        { +            const wchar_t *value = PyUnicode_AsUnicode(object); +            const std::wstring value_ws(value); +            if (value == 0) +                throw_error_already_set(); +            void *storage = +                    ((boost::python::converter::rvalue_from_python_storage<T> *) +                             data) +                            ->storage.bytes; +            new (storage) T(fn(std::string(value_ws.begin(), value_ws.end()))); +            data->convertible = storage; +        } -/* -A wrapper for a nextpnr Range. Ranges should have two functions, begin() -and end() which return iterator-like objects supporting ++, * and != -Full STL iterator semantics are not required, unlike the standard Boost wrappers -*/ +        static F fn; +    }; -template<typename T> -struct range_wrapper { -    typedef decltype(std::declval<T>().begin()) iterator_t; +    template <typename F> struct to_str_wrapper +    { +        static F fn; -    static std::pair<iterator_t, iterator_t> iter(T &range) { -        return std::make_pair(range.begin(), range.end()); -    } +        std::string str(T &x) { return fn(x); } +    }; -    static void wrap(const char *range_name, const char *iter_name) { -        class_<T>(range_name, no_init) -                .def("__iter__", iter); -        iterator_wrapper<iterator_t>().wrap(iter_name); +    template <typename F1, typename F2> +    static void wrap(const char *type_name, F1 to_str_fn, F2 from_str_fn) +    { +        from_pystring_converter<F2>::fn = from_str_fn; +        from_pystring_converter<F2>(); +        to_str_wrapper<F1>::fn = to_str_fn; +        class_<T>(type_name, no_init).def("__str__", to_str_wrapper<F1>::str); +    }; +}; + +std::string parse_python_exception(); + +template <typename Tn> void python_export_global(const char *name, Tn &x) +{ +    PyObject *m, *d; +    m = PyImport_AddModule("__main__"); +    if (m == NULL) +        return; +    d = PyModule_GetDict(m); +    try { +        PyObject *p = incref(object(boost::ref(x)).ptr()); +        PyDict_SetItemString(d, name, p); +    } catch (boost::python::error_already_set const &) { +        // Parse and output the exception +        std::string perror_str = parse_python_exception(); +        std::cout << "Error in Python: " << perror_str << std::endl; +        std::terminate();      }  }; -#define WRAP_RANGE(t) range_wrapper<t##Range>().wrap(#t "Range", #t "Iterator") +void init_python(const char *executable); + +void deinit_python(); + +void execute_python_file(const char *python_file); -void execute_python_file(const char *executable, const char* python_file);  std::string parse_python_exception(); +  void arch_appendinittab();  #endif /* end of include guard: COMMON_PYBINDINGS_HH */ diff --git a/common/pycontainers.h b/common/pycontainers.h new file mode 100644 index 00000000..6e2cdea9 --- /dev/null +++ b/common/pycontainers.h @@ -0,0 +1,129 @@ +/* + *  nextpnr -- Next Generation Place and Route + * + *  Copyright (C) 2018  Clifford Wolf <clifford@clifford.at> + *  Copyright (C) 2018  David Shah <dave@ds0.me> + * + *  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. + * + */ + +#ifndef COMMON_PYCONTAINERS_H +#define COMMON_PYCONTAINERS_H + +#include <utility> +#include <stdexcept> +#include <type_traits> +#include <boost/python.hpp> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> +#include <boost/python/suite/indexing/map_indexing_suite.hpp> +#include <boost/python/suite/indexing/map_indexing_suite.hpp> + +using namespace boost::python; + +/* +A wrapper for a Pythonised nextpnr Iterator. The actual class wrapped is a +pair<Iterator, Iterator> containing (current, end) +*/ + +template<typename T, typename P> +struct iterator_wrapper { +	typedef decltype(*(std::declval<T>())) value_t; + +	static value_t next(std::pair <T, T> &iter) { +		if (iter.first != iter.second) { +			value_t val = *iter.first; +			++iter.first; +			return val; +		} else { +			PyErr_SetString(PyExc_StopIteration, "End of range reached"); +			boost::python::throw_error_already_set(); +			// Should be unreachable, but prevent control may reach end of non-void +			throw std::runtime_error("unreachable"); +		} +	} + +	static void wrap(const char *python_name) { +		class_ < std::pair < T, T >> (python_name, no_init) +				.def("__next__", next, P()); +	} +}; + +/* +A wrapper for a nextpnr Range. Ranges should have two functions, begin() +and end() which return iterator-like objects supporting ++, * and != +Full STL iterator semantics are not required, unlike the standard Boost wrappers +*/ + +template<typename T, typename P = return_value_policy<return_by_value>> +struct range_wrapper { +	typedef decltype(std::declval<T>().begin()) iterator_t; + +	static std::pair <iterator_t, iterator_t> iter(T &range) { +		return std::make_pair(range.begin(), range.end()); +	} + +	static void wrap(const char *range_name, const char *iter_name) { +		class_<T>(range_name, no_init) +				.def("__iter__", iter); +		iterator_wrapper<iterator_t, P>().wrap(iter_name); +	} +	typedef iterator_wrapper<iterator_t, P> iter_wrap; +}; + +#define WRAP_RANGE(t) range_wrapper<t##Range>().wrap(#t "Range", #t "Iterator") + +/* +Wrapper for a map, either an unordered_map, regular map or dict + */ +inline void KeyError() { PyErr_SetString(PyExc_KeyError, "Key not found"); } + +template<typename T> +struct map_wrapper { +	typedef typename std::remove_cv<typename std::remove_reference<typename T::key_type>::type>::type K; +	typedef typename T::mapped_type V; +	typedef typename T::value_type KV; + +	static V &get(T &x, K const &i) { +		if (x.find(i) != x.end()) return x.at(i); +		KeyError(); +		std::terminate(); +	} + +	static void set(T &x, K const &i, V const &v) { +		x[i] = v; +	} + +	static void del(T const &x, K const &i) { +		if (x.find(i) != x.end()) x.erase(i); +		else KeyError(); +		std::terminate(); +	} + +	static void wrap(const char *map_name, const char *kv_name, const char *iter_name) { +		class_<KV>(kv_name) +				.def_readonly("first", &KV::first) +				.def_readwrite("second", &KV::second); +		typedef range_wrapper<T, return_value_policy<copy_non_const_reference>> rw; +		typename rw::iter_wrap().wrap(iter_name); +		class_<T>(map_name, no_init) +		        .def("__iter__", rw::iter) +				.def("__len__", &T::size) +				.def("__getitem__", get, return_internal_reference<>()) +				.def("__setitem__", set, with_custodian_and_ward<1,2>()); +	} +}; + +#define WRAP_MAP(t, name) map_wrapper<t>().wrap(#name, #name "KeyValue", #name "Iterator") + +#endif diff --git a/common/rulecheck.cc b/common/rulecheck.cc index b81695b9..28d4b6b7 100644 --- a/common/rulecheck.cc +++ b/common/rulecheck.cc @@ -57,5 +57,6 @@ bool	check_all_nets_driven(Design *design) {  	}  	if (debug) log_info("  Verified!\n"); +	return true;  } | 
