/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Claire Xenia Wolf * Copyright (C) 2018 gatecat * * 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 #include #include #include #include #include "nextpnr.h" #include "pywrappers.h" NEXTPNR_NAMESPACE_BEGIN namespace py = pybind11; inline void KeyError() { PyErr_SetString(PyExc_KeyError, "Key not found"); throw py::error_already_set(); } /* A wrapper for a Pythonised nextpnr Iterator. The actual class wrapped is a pair containing (current, end), wrapped in a ContextualWrapper */ template > struct iterator_wrapper { typedef decltype(*(std::declval())) value_t; typedef PythonConversion::ContextualWrapper> wrapped_iter_t; using return_t = typename value_conv::ret_type; static return_t next(wrapped_iter_t &iter) { if (iter.base.first != iter.base.second) { return_t val = value_conv()(iter.ctx, *iter.base.first); ++iter.base.first; return val; } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); throw py::error_already_set(); } } static void wrap(py::module &m, const char *python_name) { py::class_(m, python_name).def("__next__", next, P); } }; /* A pair that doesn't automatically become a tuple */ template struct iter_pair { iter_pair(){}; iter_pair(const Ta &first, const Tb &second) : first(first), second(second){}; Ta first; Tb second; }; /* 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 > struct range_wrapper { typedef decltype(std::declval().begin()) iterator_t; typedef decltype(*(std::declval())) value_t; typedef typename PythonConversion::ContextualWrapper wrapped_range; typedef typename PythonConversion::ContextualWrapper> wrapped_pair; static wrapped_pair iter(wrapped_range &range) { return wrapped_pair(range.ctx, std::make_pair(range.base.begin(), range.base.end())); } static std::string repr(wrapped_range &range) { PythonConversion::string_converter conv; bool first = true; std::stringstream ss; ss << "["; for (const auto &item : range.base) { if (!first) ss << ", "; ss << "'" << conv.to_str(range.ctx, item) << "'"; first = false; } ss << "]"; return ss.str(); } static void wrap(py::module &m, const char *range_name, const char *iter_name) { py::class_(m, range_name).def("__iter__", iter).def("__repr__", repr); iterator_wrapper().wrap(m, iter_name); } typedef iterator_wrapper iter_wrap; }; #define WRAP_RANGE(m, t, conv) \ range_wrapper().wrap(m, #t "Range", #t "Iterator") /* A wrapper for a vector or similar structure. With support for conversion */ template > struct vector_wrapper { typedef decltype(std::declval().begin()) iterator_t; typedef decltype(*(std::declval())) value_t; typedef typename PythonConversion::ContextualWrapper wrapped_vector; typedef typename PythonConversion::ContextualWrapper> wrapped_pair; using return_t = typename value_conv::ret_type; static wrapped_pair iter(wrapped_vector &range) { return wrapped_pair(range.ctx, std::make_pair(range.base.begin(), range.base.end())); } static std::string repr(wrappe
#!/bin/bash

set -e

transp_list="0 1"
abits_list="1 2 4 8 10 16 20"
dbits_list="1 2 4 8 10 16 20 24 30 32 40 48 50 56 60 64 70 72 80"

use_xsim=false
unisims=/opt/Xilinx/Vivado/2014.4/data/verilog/src/unisims

echo "all: all_list" > bram1.mk
all_list=""

for transp in $transp_list; do
for abits in $abits_list; do
for dbits in $dbits_list; do
	if [ $(( (1 << $abits) * $dbits )) -gt 1000000 ]; then continue; fi
	id=`printf "%d%02d%02d" $transp $abits $dbits`
	echo "Creating bram1_$id.."
	rm -rf bram1_$id
	mkdir -p bram1_$id
	cp bram1.v bram1_tb.v bram1_$id/
	sed -i "/parameter/ s,ABITS *= *[0-9]*,ABITS = $abits," bram1_$id/*.v
	sed -i "/parameter/ s,DBITS *= *[0-9]*,DBITS = $dbits," bram1_$id/*.v
	sed -i "/parameter/ s,TRANSP *= *[0-9]*,TRANSP = $transp," bram1_$id/*.v
	{
		echo "set -e"
		echo "../../../../yosys -q -lsynth.log -p 'synth_xilinx -top bram1; write_verilog synth.v' bram1.v"
		if $use_xsim; then
			echo "xvlog --work gold bram1_tb.v bram1.v > gold.txt"
			echo "xvlog --work gate bram1_tb.v synth.v > gate.txt"
			echo "xelab -R gold.bram1_tb >> gold.txt"
			echo "xelab -L unisim -R gate.bram1_tb >> gate.txt"
		else
			echo "iverilog -o bram1_tb_gold bram1_tb.v bram1.v > gold.txt 2>&1"
			echo "iverilog -o bram1_tb_gate bram1_tb.v synth.v -y $unisims $unisims/../glbl.v > gate.txt 2>&1"
			echo "./bram1_tb_gold >> gold.txt"
			echo "./bram1_tb_gate >> gate.txt"
		fi
		echo "../bram1_cmp <( grep '#OUT#' gold.txt; ) <( grep '#OUT#' gate.txt; )"
	} > bram1_$id/run.sh
	{
		echo "bram1_$id/ok:"
		echo "	@cd bram1_$id && bash run.sh"
		echo "	@echo -n '[$id]'"
		echo "	@touch \$@"
	} >> bram1.mk
	all_list="$all_list bram1_$id/ok"
done; done; done

cc -o bram1_cmp ../../../tests/tools/cmp_tbdata.c
echo all_list: $(echo $all_list | tr ' ' '\n' | sort -R) >> bram1.mk

echo "Testing..."
${MAKE:-make} -f bram1.mk
echo

echo "Used bram types:"
grep -h 'Mapping to bram type' bram1_*/synth.log | sort | uniq -c

echo "Cleaning up..."
rm -rf bram1_cmp bram1.mk bram1_[0-9]*/
static bool contains(wrapped_map &x, std::string const &i) { K k = PythonConversion::string_converter().from_str(x.ctx, i); return x.base.count(k); } static void wrap(py::module &m, const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) { map_pair_wrapper_uptr::wrap(m, kv_name, kv_iter_name); typedef range_wrapper> rw; typename rw::iter_wrap().wrap(m, iter_name); py::class_(m, map_name) .def("__iter__", rw::iter) .def("__len__", len) .def("__contains__", contains) .def("__getitem__", get) .def("__setitem__", set, py::keep_alive<1, 2>()); } }; #define WRAP_MAP(m, t, conv, name) \ map_wrapper().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") #define WRAP_MAP_UPTR(m, t, name) \ map_wrapper_uptr().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") NEXTPNR_NAMESPACE_END #endif