2023-12-09 01:36:48 +08:00
|
|
|
/*
|
|
|
|
* nextpnr -- Next Generation Place and Route
|
|
|
|
*
|
|
|
|
* Copyright (C) 2022 Lofty <lofty@yosyshq.com>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2024-01-03 23:07:22 +08:00
|
|
|
#include <array>
|
2024-01-03 23:04:29 +08:00
|
|
|
#include <numeric>
|
2023-12-09 01:36:48 +08:00
|
|
|
#include "log.h"
|
|
|
|
#include "nextpnr.h"
|
|
|
|
|
|
|
|
namespace {
|
2024-01-12 17:09:28 +08:00
|
|
|
USING_NEXTPNR_NAMESPACE;
|
|
|
|
|
|
|
|
template <typename T> static inline uint64_t wrap(const T &thing) noexcept
|
|
|
|
{
|
|
|
|
static_assert(sizeof(T) <= 8, "T is too big for FFI");
|
|
|
|
uint64_t b = 0;
|
|
|
|
memcpy(&b, &thing, sizeof(T));
|
|
|
|
return b;
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
template <typename T> static inline T unwrap(const std::array<uint8_t, 8> &value) noexcept
|
|
|
|
{
|
|
|
|
static_assert(sizeof(T) <= 8, "T is too big for FFI");
|
|
|
|
T result{};
|
|
|
|
memcpy(&result, value.data(), sizeof(result));
|
|
|
|
return result;
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
template <typename T> static inline T unwrap(const uint64_t value) noexcept
|
|
|
|
{
|
|
|
|
std::array<uint8_t, 8> data{};
|
|
|
|
static_assert(sizeof(value) >= data.size(), "uint64_t is not an appropriate size");
|
|
|
|
memcpy(data.data(), &value, data.size());
|
|
|
|
return unwrap<T>(data);
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
static inline BelId unwrap_bel(const uint64_t bel) noexcept { return unwrap<BelId>(bel); }
|
2024-01-03 23:07:22 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
static inline PipId unwrap_pip(const uint64_t pip) noexcept { return unwrap<PipId>(pip); }
|
2024-01-03 23:07:22 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
static inline WireId unwrap_wire(const uint64_t wire) noexcept { return unwrap<WireId>(wire); }
|
|
|
|
} // namespace
|
2023-12-09 01:36:48 +08:00
|
|
|
|
|
|
|
using DownhillIter = decltype(Context(ArchArgs()).getPipsDownhill(WireId()).begin());
|
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
struct DownhillIterWrapper
|
|
|
|
{
|
2023-12-09 01:36:48 +08:00
|
|
|
DownhillIter current;
|
|
|
|
DownhillIter end;
|
|
|
|
|
|
|
|
DownhillIterWrapper(DownhillIter begin, DownhillIter end) : current(begin), end(end) {}
|
|
|
|
};
|
|
|
|
using UphillIter = decltype(Context(ArchArgs()).getPipsUphill(WireId()).begin());
|
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
struct UphillIterWrapper
|
|
|
|
{
|
2023-12-09 01:36:48 +08:00
|
|
|
UphillIter current;
|
|
|
|
UphillIter end;
|
|
|
|
|
|
|
|
UphillIterWrapper(UphillIter begin, UphillIter end) : current(begin), end(end) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
extern "C" {
|
2024-01-12 17:09:28 +08:00
|
|
|
USING_NEXTPNR_NAMESPACE;
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
void npnr_log_info(const char *string) { log_info("%s", string); }
|
|
|
|
void npnr_log_error(const char *string) { log_error("%s", string); }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
uint64_t npnr_belid_null() { return wrap(BelId()); }
|
|
|
|
uint64_t npnr_wireid_null() { return wrap(WireId()); }
|
|
|
|
uint64_t npnr_pipid_null() { return wrap(PipId()); }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
int npnr_context_get_grid_dim_x(const Context *ctx) { return ctx->getGridDimX(); }
|
|
|
|
int npnr_context_get_grid_dim_y(const Context *ctx) { return ctx->getGridDimY(); }
|
|
|
|
void npnr_context_bind_bel(Context *ctx, uint64_t bel, CellInfo *cell, PlaceStrength strength)
|
|
|
|
{
|
|
|
|
return ctx->bindBel(unwrap_bel(bel), cell, strength);
|
|
|
|
}
|
|
|
|
void npnr_context_unbind_bel(Context *ctx, uint64_t bel) { return ctx->unbindBel(unwrap_bel(bel)); }
|
|
|
|
bool npnr_context_check_bel_avail(Context *ctx, uint64_t bel) { return ctx->checkBelAvail(unwrap_bel(bel)); }
|
|
|
|
void npnr_context_bind_wire(Context *ctx, uint64_t wire, NetInfo *net, PlaceStrength strength)
|
|
|
|
{
|
|
|
|
ctx->bindWire(unwrap_wire(wire), net, strength);
|
|
|
|
}
|
|
|
|
void npnr_context_unbind_wire(Context *ctx, uint64_t wire) { ctx->unbindWire(unwrap_wire(wire)); }
|
|
|
|
void npnr_context_bind_pip(Context *ctx, uint64_t pip, NetInfo *net, PlaceStrength strength)
|
|
|
|
{
|
|
|
|
ctx->bindPip(unwrap_pip(pip), net, strength);
|
|
|
|
}
|
|
|
|
void npnr_context_unbind_pip(Context *ctx, uint64_t pip) { ctx->unbindPip(unwrap_pip(pip)); }
|
|
|
|
uint64_t npnr_context_get_pip_src_wire(const Context *ctx, uint64_t pip)
|
|
|
|
{
|
|
|
|
return wrap(ctx->getPipSrcWire(unwrap_pip(pip)));
|
|
|
|
}
|
|
|
|
uint64_t npnr_context_get_pip_dst_wire(const Context *ctx, uint64_t pip)
|
|
|
|
{
|
|
|
|
return wrap(ctx->getPipDstWire(unwrap_pip(pip)));
|
|
|
|
}
|
|
|
|
float npnr_context_estimate_delay(const Context *ctx, uint64_t src, uint64_t dst)
|
|
|
|
{
|
|
|
|
return ctx->getDelayNS(ctx->estimateDelay(unwrap_wire(src), unwrap_wire(dst)));
|
|
|
|
}
|
|
|
|
float npnr_context_get_pip_delay(const Context *ctx, uint64_t pip)
|
|
|
|
{
|
|
|
|
return ctx->getDelayNS(ctx->getPipDelay(unwrap_pip(pip)).maxDelay());
|
|
|
|
}
|
|
|
|
float npnr_context_get_wire_delay(const Context *ctx, uint64_t wire)
|
|
|
|
{
|
|
|
|
return ctx->getDelayNS(ctx->getWireDelay(unwrap_wire(wire)).maxDelay());
|
|
|
|
}
|
|
|
|
float npnr_context_delay_epsilon(const Context *ctx) { return ctx->getDelayNS(ctx->getDelayEpsilon()); }
|
|
|
|
Loc npnr_context_get_pip_location(const Context *ctx, uint64_t pip) { return ctx->getPipLocation(unwrap_pip(pip)); }
|
|
|
|
bool npnr_context_check_pip_avail_for_net(const Context *ctx, uint64_t pip, NetInfo *net)
|
|
|
|
{
|
|
|
|
return ctx->checkPipAvailForNet(unwrap_pip(pip), net);
|
|
|
|
}
|
|
|
|
|
2024-01-16 09:52:29 +08:00
|
|
|
uint64_t npnr_context_get_pips_leak(const Context *ctx, uint64_t **const pips)
|
2024-01-12 17:09:28 +08:00
|
|
|
{
|
|
|
|
const auto ctx_pips{ctx->getPips()};
|
|
|
|
const auto size{std::accumulate(ctx_pips.begin(), ctx_pips.end(), /*initial value*/ size_t{},
|
|
|
|
[](size_t value, const auto & /*pip*/) { return value + 1U; })};
|
|
|
|
*pips = new uint64_t[size];
|
|
|
|
auto idx = 0;
|
|
|
|
for (const auto &pip : ctx_pips) {
|
|
|
|
(*pips)[idx] = wrap(pip);
|
|
|
|
idx++;
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
2024-01-12 17:09:28 +08:00
|
|
|
// Yes, by never deleting pip_vec, we leak memory.
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2024-01-16 09:52:29 +08:00
|
|
|
uint64_t npnr_context_get_wires_leak(const Context *ctx, uint64_t **const wires)
|
2024-01-12 17:09:28 +08:00
|
|
|
{
|
|
|
|
const auto ctx_wires{ctx->getWires()};
|
|
|
|
const auto size{std::accumulate(ctx_wires.begin(), ctx_wires.end(), /*initial value*/ size_t{},
|
|
|
|
[](size_t value, const auto & /*wire*/) { return value + 1U; })};
|
|
|
|
*wires = new uint64_t[size];
|
|
|
|
auto idx = 0;
|
|
|
|
for (const auto &wire : ctx_wires) {
|
|
|
|
(*wires)[idx] = wrap(wire);
|
|
|
|
idx++;
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
2024-01-12 17:09:28 +08:00
|
|
|
// Yes, by never deleting wires, we leak memory.
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void npnr_context_check(const Context *ctx) { ctx->check(); }
|
|
|
|
bool npnr_context_debug(const Context *ctx) { return ctx->debug; }
|
|
|
|
int npnr_context_id(const Context *ctx, const char *str) { return ctx->id(str).hash(); }
|
|
|
|
const char *npnr_context_name_of(const Context *ctx, IdString str) { return ctx->nameOf(str); }
|
|
|
|
const char *npnr_context_name_of_pip(const Context *ctx, uint64_t pip) { return ctx->nameOfPip(unwrap_pip(pip)); }
|
|
|
|
const char *npnr_context_name_of_wire(const Context *ctx, uint64_t wire) { return ctx->nameOfWire(unwrap_wire(wire)); }
|
|
|
|
bool npnr_context_verbose(const Context *ctx) { return ctx->verbose; }
|
|
|
|
|
|
|
|
uint64_t npnr_context_get_netinfo_source_wire(const Context *ctx, const NetInfo *net)
|
|
|
|
{
|
|
|
|
return wrap(ctx->getNetinfoSourceWire(net));
|
|
|
|
}
|
|
|
|
uint64_t npnr_context_get_netinfo_sink_wire(const Context *ctx, const NetInfo *net, const PortRef *sink, uint32_t n)
|
|
|
|
{
|
|
|
|
return wrap(ctx->getNetinfoSinkWire(net, *sink, n));
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t npnr_context_nets_leak(const Context *ctx, int **names, NetInfo ***nets)
|
|
|
|
{
|
|
|
|
auto size = ctx->nets.size();
|
|
|
|
*names = new int[size];
|
|
|
|
*nets = new NetInfo *[size];
|
|
|
|
auto idx = 0;
|
|
|
|
for (auto &item : ctx->nets) {
|
|
|
|
(*names)[idx] = item.first.index;
|
|
|
|
(*nets)[idx] = item.second.get();
|
|
|
|
idx++;
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
2024-01-12 17:09:28 +08:00
|
|
|
// Yes, by never deleting `names` and `nets` we leak memory.
|
|
|
|
return size;
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
DownhillIterWrapper *npnr_context_get_pips_downhill(Context *ctx, uint64_t wire_id)
|
|
|
|
{
|
|
|
|
auto wire = unwrap_wire(wire_id);
|
|
|
|
auto range = ctx->getPipsDownhill(wire);
|
|
|
|
return new DownhillIterWrapper(range.begin(), range.end());
|
|
|
|
}
|
|
|
|
void npnr_delete_downhill_iter(DownhillIterWrapper *iter) { delete iter; }
|
|
|
|
UphillIterWrapper *npnr_context_get_pips_uphill(Context *ctx, uint64_t wire_id)
|
|
|
|
{
|
|
|
|
auto wire = unwrap_wire(wire_id);
|
|
|
|
auto range = ctx->getPipsUphill(wire);
|
|
|
|
return new UphillIterWrapper(range.begin(), range.end());
|
|
|
|
}
|
|
|
|
void npnr_delete_uphill_iter(UphillIterWrapper *iter) { delete iter; }
|
|
|
|
|
|
|
|
PortRef *npnr_netinfo_driver(NetInfo *net)
|
|
|
|
{
|
|
|
|
if (net == nullptr) {
|
|
|
|
return nullptr;
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
2024-01-12 17:09:28 +08:00
|
|
|
return &net->driver;
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-16 09:55:50 +08:00
|
|
|
uint32_t npnr_netinfo_users_leak(const NetInfo *net, const PortRef ***users)
|
2024-01-12 17:09:28 +08:00
|
|
|
{
|
|
|
|
auto size = net->users.entries();
|
2024-01-16 10:01:04 +08:00
|
|
|
*users = new const PortRef *[size];
|
2024-01-12 17:09:28 +08:00
|
|
|
auto idx = 0;
|
|
|
|
for (auto &item : net->users) {
|
|
|
|
(*users)[idx] = &item;
|
|
|
|
idx++;
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
2024-01-12 17:09:28 +08:00
|
|
|
// Yes, by not freeing `users`, we leak memory.
|
|
|
|
return size;
|
|
|
|
}
|
2023-12-09 01:36:48 +08:00
|
|
|
|
|
|
|
#ifdef ARCH_ECP5
|
2024-01-12 17:09:28 +08:00
|
|
|
bool npnr_netinfo_is_global(NetInfo *net) { return net->is_global; }
|
2023-12-09 01:36:48 +08:00
|
|
|
#else
|
2024-01-12 17:09:28 +08:00
|
|
|
bool npnr_netinfo_is_global(NetInfo * /*net*/) { return false; }
|
2023-12-09 01:36:48 +08:00
|
|
|
#endif
|
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
int32_t npnr_netinfo_udata(NetInfo *net) { return net->udata; }
|
|
|
|
void npnr_netinfo_udata_set(NetInfo *net, int32_t value) { net->udata = value; }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
CellInfo *npnr_portref_cell(const PortRef *port) { return port->cell; }
|
|
|
|
Loc npnr_cellinfo_get_location(const CellInfo *info) { return info->getLocation(); }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
void npnr_inc_downhill_iter(DownhillIterWrapper *iter) { ++iter->current; }
|
|
|
|
uint64_t npnr_deref_downhill_iter(DownhillIterWrapper *iter) { return wrap(*iter->current); }
|
|
|
|
bool npnr_is_downhill_iter_done(DownhillIterWrapper *iter) { return !(iter->current != iter->end); }
|
|
|
|
void npnr_inc_uphill_iter(UphillIterWrapper *iter) { ++iter->current; }
|
|
|
|
uint64_t npnr_deref_uphill_iter(UphillIterWrapper *iter) { return wrap(*iter->current); }
|
|
|
|
bool npnr_is_uphill_iter_done(UphillIterWrapper *iter) { return !(iter->current != iter->end); }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
void rust_example_printnets(Context *ctx);
|
2023-12-09 01:36:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
2024-01-12 17:09:28 +08:00
|
|
|
void example_printnets(Context *ctx) { rust_example_printnets(ctx); }
|
2023-12-09 01:36:48 +08:00
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|