nextpnr/cyclonev/arch.cc

292 lines
8.3 KiB
C++
Raw Normal View History

2020-06-13 05:09:46 +08:00
/*
* nextpnr -- Next Generation Place and Route
*
2021-01-07 00:22:17 +08:00
* Copyright (C) 2021 Lofty <dan.ravensloft@gmail.com>
2020-06-13 05:09:46 +08:00
*
* 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.
*/
2021-01-07 00:22:17 +08:00
#include <algorithm>
#include "log.h"
2021-01-07 00:22:17 +08:00
#include "nextpnr.h"
#include "cyclonev.h"
2021-01-07 00:22:17 +08:00
NEXTPNR_NAMESPACE_BEGIN
2021-01-07 02:07:59 +08:00
using namespace mistral;
2021-01-07 00:22:17 +08:00
void IdString::initialize_arch(const BaseCtx *ctx)
{
#define X(t) initialize_add(ctx, #t, ID_##t);
#include "constids.inc"
#undef X
}
2021-01-07 00:22:17 +08:00
Arch::Arch(ArchArgs args)
{
this->args = args;
this->cyclonev = mistral::CycloneV::get_model(args.device, args.mistral_root);
2021-01-07 00:22:17 +08:00
NPNR_ASSERT(this->cyclonev != nullptr);
2021-02-04 22:28:39 +08:00
// Setup fast identifier maps
for (int i = 0; i < 1024; i++) {
IdString int_id = id(stringf("%d", i));
int2id.push_back(int_id);
id2int[int_id] = i;
}
for (int t = int(CycloneV::NONE); t <= int(CycloneV::DCMUX); t++) {
IdString rnode_id = id(CycloneV::rnode_type_names[t]);
rn_t2id.push_back(rnode_id);
id2rn_t[rnode_id] = CycloneV::rnode_type_t(t);
}
log_info("Initialising bels...\n");
bels_by_tile.resize(cyclonev->get_tile_sx() * cyclonev->get_tile_sy());
2021-02-04 22:28:39 +08:00
for (int x = 0; x < cyclonev->get_tile_sx(); x++) {
for (int y = 0; y < cyclonev->get_tile_sy(); y++) {
CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
for (CycloneV::block_type_t bel : cyclonev->pos_get_bels(pos)) {
switch (bel) {
case CycloneV::block_type_t::LAB:
create_lab(x, y);
break;
2021-02-04 22:28:39 +08:00
case CycloneV::block_type_t::GPIO:
// GPIO tiles contain 4 pins
// TODO
break;
2021-02-04 22:28:39 +08:00
default:
continue;
}
}
}
}
// This import takes about 5s, perhaps long term we can speed it up, e.g. defer to Mistral more...
log_info("Initialising routing graph...\n");
int pip_count = 0;
for (const auto &mux : cyclonev->dest_node_to_rmux) {
const auto &rmux = cyclonev->rmux_info[mux.second];
WireId dst_wire(mux.first);
for (const auto &src : rmux.sources) {
if (CycloneV::rn2t(src) == CycloneV::NONE)
continue;
WireId src_wire(src);
wires[dst_wire].wires_uphill.push_back(src_wire);
wires[src_wire].wires_downhill.push_back(dst_wire);
++pip_count;
}
}
log_info(" imported %d wires and %d pips\n", int(wires.size()), pip_count);
BaseArch::init_cell_types();
BaseArch::init_bel_buckets();
2021-01-07 00:22:17 +08:00
}
int Arch::getTileBelDimZ(int x, int y) const
{
// This seems like a reasonable upper bound
return 256;
2021-01-07 00:22:17 +08:00
}
BelId Arch::getBelByName(IdStringList name) const
2021-01-07 00:22:17 +08:00
{
BelId bel;
NPNR_ASSERT(name.size() == 4);
int x = id2int.at(name[1]);
int y = id2int.at(name[2]);
int z = id2int.at(name[3]);
2021-01-07 00:22:17 +08:00
bel.pos = CycloneV::xy2pos(x, y);
bel.z = z;
NPNR_ASSERT(name[0] == getBelType(bel));
2021-01-07 00:22:17 +08:00
return bel;
}
IdStringList Arch::getBelName(BelId bel) const
2021-01-07 00:22:17 +08:00
{
int x = CycloneV::pos2x(bel.pos);
int y = CycloneV::pos2y(bel.pos);
2021-01-07 02:07:59 +08:00
int z = bel.z & 0xFF;
2021-01-07 00:22:17 +08:00
std::array<IdString, 4> ids{
getBelType(bel),
int2id.at(x),
int2id.at(y),
int2id.at(z),
};
return IdStringList(ids);
}
2021-01-07 00:22:17 +08:00
WireId Arch::getWireByName(IdStringList name) const
{
// non-mistral wires
auto found_npnr = npnr_wirebyname.find(name);
if (found_npnr != npnr_wirebyname.end())
return found_npnr->second;
// mistral wires
NPNR_ASSERT(name.size() == 4);
CycloneV::rnode_type_t ty = id2rn_t.at(name[0]);
int x = id2int.at(name[1]);
int y = id2int.at(name[2]);
int z = id2int.at(name[3]);
return WireId(CycloneV::rnode(ty, x, y, z));
}
IdStringList Arch::getWireName(WireId wire) const
{
if (wire.is_nextpnr_created()) {
// non-mistral wires
std::array<IdString, 4> ids{
id_WIRE,
int2id.at(CycloneV::rn2x(wire.node)),
int2id.at(CycloneV::rn2y(wire.node)),
wires.at(wire).name_override,
};
return IdStringList(ids);
} else {
std::array<IdString, 4> ids{
rn_t2id.at(CycloneV::rn2t(wire.node)),
int2id.at(CycloneV::rn2x(wire.node)),
int2id.at(CycloneV::rn2y(wire.node)),
int2id.at(CycloneV::rn2z(wire.node)),
};
return IdStringList(ids);
}
}
PipId Arch::getPipByName(IdStringList name) const
{
WireId src = getWireByName(name.slice(0, 4));
WireId dst = getWireByName(name.slice(4, 8));
NPNR_ASSERT(src != WireId());
NPNR_ASSERT(dst != WireId());
return PipId(src.node, dst.node);
}
IdStringList Arch::getPipName(PipId pip) const
{
return IdStringList::concat(getWireName(getPipSrcWire(pip)), getWireName(getPipDstWire(pip)));
2021-02-03 08:12:14 +08:00
}
2021-01-07 00:22:17 +08:00
2021-02-04 10:29:59 +08:00
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
{
// This should probably be redesigned, but it's a hack.
std::vector<BelId> bels;
if (x >= 0 && x < cyclonev->get_tile_sx() && y >= 0 && y < cyclonev->get_tile_sy()) {
for (size_t i = 0; i < bels_by_tile.at(pos2idx(x, y)).size(); i++)
bels.push_back(BelId(CycloneV::xy2pos(x, y), i));
2021-02-04 10:29:59 +08:00
}
return bels;
}
IdString Arch::getBelType(BelId bel) const { return bel_data(bel).type; }
2021-02-04 10:29:59 +08:00
std::vector<IdString> Arch::getBelPins(BelId bel) const
{
std::vector<IdString> pins;
for (auto &p : bel_data(bel).pins)
pins.push_back(p.first);
return pins;
2021-02-04 10:29:59 +08:00
}
2021-01-07 00:22:17 +08:00
bool Arch::pack() { return true; }
bool Arch::place() { return true; }
bool Arch::route() { return true; }
BelId Arch::add_bel(int x, int y, IdString name, IdString type)
{
auto &bels = bels_by_tile.at(pos2idx(x, y));
BelId id = BelId(CycloneV::xy2pos(x, y), bels.size());
all_bels.push_back(id);
bels.emplace_back();
auto &bel = bels.back();
bel.name = name;
bel.type = type;
// TODO: buckets (for example LABs and MLABs in the same bucket)
bel.bucket = type;
return id;
}
WireId Arch::add_wire(int x, int y, IdString name, uint64_t flags)
{
std::array<IdString, 4> ids{
id_WIRE,
int2id.at(x),
int2id.at(y),
name,
};
IdStringList full_name(ids);
auto existing = npnr_wirebyname.find(full_name);
if (existing != npnr_wirebyname.end()) {
// Already exists, don't create anything
return existing->second;
} else {
// Determine a unique ID for the wire
int z = 0;
WireId id;
while (wires.count(id = WireId(CycloneV::rnode(CycloneV::rnode_type_t((z >> 10) + 128), x, y, (z & 0x3FF)))))
z++;
wires[id].name_override = name;
wires[id].flags = flags;
npnr_wirebyname[full_name] = id;
return id;
}
}
PipId Arch::add_pip(WireId src, WireId dst)
{
wires[src].wires_downhill.push_back(dst);
wires[dst].wires_uphill.push_back(src);
return PipId(src.node, dst.node);
}
void Arch::add_bel_pin(BelId bel, IdString pin, PortType dir, WireId wire)
{
auto &b = bel_data(bel);
NPNR_ASSERT(!b.pins.count(pin));
b.pins[pin].dir = dir;
b.pins[pin].wire = wire;
BelPin bel_pin;
bel_pin.bel = bel;
bel_pin.pin = pin;
wires[wire].bel_pins.push_back(bel_pin);
}
#ifdef WITH_HEAP
const std::string Arch::defaultPlacer = "heap";
#else
const std::string Arch::defaultPlacer = "sa";
#endif
const std::vector<std::string> Arch::availablePlacers = {"sa",
#ifdef WITH_HEAP
"heap"
#endif
};
const std::string Arch::defaultRouter = "router1";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
2021-01-07 00:22:17 +08:00
NEXTPNR_NAMESPACE_END