cyclonev: Add names and archcheck fixes
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
af0bffbae9
commit
5d1b8bf744
@ -58,4 +58,23 @@ std::string IdStringList::str(const Context *ctx) const
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdStringList IdStringList::concat(IdStringList a, IdStringList b)
|
||||||
|
{
|
||||||
|
IdStringList result(a.size() + b.size());
|
||||||
|
for (size_t i = 0; i < a.size(); i++)
|
||||||
|
result.ids[i] = a[i];
|
||||||
|
for (size_t i = 0; i < b.size(); i++)
|
||||||
|
result.ids[a.size() + i] = b[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdStringList IdStringList::slice(size_t s, size_t e) const
|
||||||
|
{
|
||||||
|
NPNR_ASSERT(e >= s);
|
||||||
|
IdStringList result(e - s);
|
||||||
|
for (size_t i = 0; i < result.size(); i++)
|
||||||
|
result.ids[i] = ids[s + i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -64,6 +64,9 @@ struct IdStringList
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static IdStringList concat(IdStringList a, IdStringList b);
|
||||||
|
IdStringList slice(size_t s, size_t e) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
123
cyclonev/arch.cc
123
cyclonev/arch.cc
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
|
|
||||||
#include "cyclonev.h"
|
#include "cyclonev.h"
|
||||||
@ -41,6 +42,19 @@ Arch::Arch(ArchArgs args)
|
|||||||
this->cyclonev = mistral::CycloneV::get_model(args.device, args.mistral_root);
|
this->cyclonev = mistral::CycloneV::get_model(args.device, args.mistral_root);
|
||||||
NPNR_ASSERT(this->cyclonev != nullptr);
|
NPNR_ASSERT(this->cyclonev != nullptr);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = 0; x < cyclonev->get_tile_sx(); x++) {
|
for (int x = 0; x < cyclonev->get_tile_sx(); x++) {
|
||||||
for (int y = 0; y < cyclonev->get_tile_sy(); y++) {
|
for (int y = 0; y < cyclonev->get_tile_sy(); y++) {
|
||||||
CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
|
CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
|
||||||
@ -56,13 +70,13 @@ Arch::Arch(ArchArgs args)
|
|||||||
* One ALM contains 2 LUT outputs and 4 flop outputs.
|
* One ALM contains 2 LUT outputs and 4 flop outputs.
|
||||||
*/
|
*/
|
||||||
for (int z = 0; z < 60; z++) {
|
for (int z = 0; z < 60; z++) {
|
||||||
this->bel_list.push_back(BelId(pos, z));
|
bels[BelId(pos, (bel << 8 | z))];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CycloneV::block_type_t::GPIO:
|
case CycloneV::block_type_t::GPIO:
|
||||||
// GPIO tiles contain 4 pins.
|
// GPIO tiles contain 4 pins.
|
||||||
for (int z = 0; z < 4; z++) {
|
for (int z = 0; z < 4; z++) {
|
||||||
this->bel_list.push_back(BelId(pos, z));
|
bels[BelId(pos, (bel << 8 | z))];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -71,44 +85,25 @@ Arch::Arch(ArchArgs args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseArch::init_cell_types();
|
||||||
|
BaseArch::init_bel_buckets();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Arch::getTileBelDimZ(int x, int y) const
|
int Arch::getTileBelDimZ(int x, int y) const
|
||||||
{
|
{
|
||||||
CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
|
// FIXME: currently encoding type in z (this will be fixed soon when site contents are implemented)
|
||||||
|
return 16384;
|
||||||
for (CycloneV::block_type_t bel : cyclonev->pos_get_bels(pos)) {
|
|
||||||
switch (bel) {
|
|
||||||
case CycloneV::block_type_t::LAB:
|
|
||||||
/*
|
|
||||||
* nextpnr and mistral disagree on what a BEL is: mistral thinks an entire LAB
|
|
||||||
* is one BEL, but nextpnr wants something with more precision.
|
|
||||||
*
|
|
||||||
* One LAB contains 10 ALMs.
|
|
||||||
* One ALM contains 2 LUT outputs and 4 flop outputs.
|
|
||||||
*/
|
|
||||||
return 60;
|
|
||||||
case CycloneV::block_type_t::GPIO:
|
|
||||||
// GPIO tiles contain 4 pins.
|
|
||||||
return 4;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// As a temporary hack, only LABs and IO are allowed to be placed, so every other tile type has zero BELs.
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BelId Arch::getBelByName(IdStringList name) const
|
BelId Arch::getBelByName(IdStringList name) const
|
||||||
{
|
{
|
||||||
char bel_type_str[80] = {0};
|
|
||||||
int x = 0, y = 0, z = 0;
|
|
||||||
BelId bel;
|
BelId bel;
|
||||||
|
NPNR_ASSERT(name.size() == 4);
|
||||||
sscanf(name[0].c_str(this), "%25s.%d.%d.%d", bel_type_str, &x, &y, &z);
|
auto bel_type = cyclonev->block_type_lookup(name[0].str(this));
|
||||||
|
int x = id2int.at(name[1]);
|
||||||
auto bel_type = cyclonev->block_type_lookup(std::string{bel_type_str});
|
int y = id2int.at(name[2]);
|
||||||
|
int z = id2int.at(name[3]);
|
||||||
|
|
||||||
bel.pos = CycloneV::xy2pos(x, y);
|
bel.pos = CycloneV::xy2pos(x, y);
|
||||||
bel.z = (bel_type << 8) | z;
|
bel.z = (bel_type << 8) | z;
|
||||||
@ -118,16 +113,70 @@ BelId Arch::getBelByName(IdStringList name) const
|
|||||||
|
|
||||||
IdStringList Arch::getBelName(BelId bel) const
|
IdStringList Arch::getBelName(BelId bel) const
|
||||||
{
|
{
|
||||||
char bel_str[80] = {0};
|
|
||||||
|
|
||||||
int x = CycloneV::pos2x(bel.pos);
|
int x = CycloneV::pos2x(bel.pos);
|
||||||
int y = CycloneV::pos2y(bel.pos);
|
int y = CycloneV::pos2y(bel.pos);
|
||||||
int z = bel.z & 0xFF;
|
int z = bel.z & 0xFF;
|
||||||
int bel_type = bel.z >> 8;
|
int bel_type = bel.z >> 8;
|
||||||
|
|
||||||
snprintf(bel_str, 80, "%s.%03d.%03d.%03d", cyclonev->block_type_names[bel_type], x, y, z);
|
std::array<IdString, 4> ids{
|
||||||
|
id(cyclonev->block_type_names[bel_type]),
|
||||||
|
int2id.at(x),
|
||||||
|
int2id.at(y),
|
||||||
|
int2id.at(z),
|
||||||
|
};
|
||||||
|
|
||||||
return IdStringList(id(bel_str));
|
return IdStringList(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
|
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
|
||||||
@ -148,13 +197,13 @@ std::vector<BelId> Arch::getBelsByTile(int x, int y) const
|
|||||||
* One ALM contains 2 LUT outputs and 4 flop outputs.
|
* One ALM contains 2 LUT outputs and 4 flop outputs.
|
||||||
*/
|
*/
|
||||||
for (int z = 0; z < 60; z++) {
|
for (int z = 0; z < 60; z++) {
|
||||||
bels.push_back(BelId(pos, z));
|
bels.push_back(BelId(pos, (cvbel << 8 | z)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CycloneV::block_type_t::GPIO:
|
case CycloneV::block_type_t::GPIO:
|
||||||
// GPIO tiles contain 4 pins.
|
// GPIO tiles contain 4 pins.
|
||||||
for (int z = 0; z < 4; z++) {
|
for (int z = 0; z < 4; z++) {
|
||||||
bels.push_back(BelId(pos, z));
|
bels.push_back(BelId(pos, (cvbel << 8 | z)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -46,13 +46,7 @@ struct PinInfo
|
|||||||
|
|
||||||
struct BelInfo
|
struct BelInfo
|
||||||
{
|
{
|
||||||
IdString name, type;
|
// TODO
|
||||||
std::map<IdString, std::string> attrs;
|
|
||||||
CellInfo *bound_cell;
|
|
||||||
std::unordered_map<IdString, PinInfo> pins;
|
|
||||||
DecalXY decalxy;
|
|
||||||
int x, y, z;
|
|
||||||
bool gb;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WireInfo
|
struct WireInfo
|
||||||
@ -125,12 +119,13 @@ template <typename T> struct key_range
|
|||||||
};
|
};
|
||||||
|
|
||||||
using AllWireRange = key_range<std::unordered_map<WireId, WireInfo>>;
|
using AllWireRange = key_range<std::unordered_map<WireId, WireInfo>>;
|
||||||
|
using AllBelRange = key_range<std::unordered_map<BelId, BelInfo>>;
|
||||||
|
|
||||||
struct ArchRanges : BaseArchRanges
|
struct ArchRanges : BaseArchRanges
|
||||||
{
|
{
|
||||||
using ArchArgsT = ArchArgs;
|
using ArchArgsT = ArchArgs;
|
||||||
// Bels
|
// Bels
|
||||||
using AllBelsRangeT = const std::vector<BelId> &;
|
using AllBelsRangeT = AllBelRange;
|
||||||
using TileBelsRangeT = std::vector<BelId>;
|
using TileBelsRangeT = std::vector<BelId>;
|
||||||
using BelPinsRangeT = std::vector<IdString>;
|
using BelPinsRangeT = std::vector<IdString>;
|
||||||
// Wires
|
// Wires
|
||||||
@ -147,9 +142,6 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
mistral::CycloneV *cyclonev;
|
mistral::CycloneV *cyclonev;
|
||||||
|
|
||||||
std::unordered_map<BelId, BelInfo> bels;
|
|
||||||
std::vector<BelId> bel_list;
|
|
||||||
|
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
ArchArgs archArgs() const { return args; }
|
ArchArgs archArgs() const { return args; }
|
||||||
|
|
||||||
@ -159,18 +151,26 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
int getGridDimX() const override { return cyclonev->get_tile_sx(); }
|
int getGridDimX() const override { return cyclonev->get_tile_sx(); }
|
||||||
int getGridDimY() const override { return cyclonev->get_tile_sy(); }
|
int getGridDimY() const override { return cyclonev->get_tile_sy(); }
|
||||||
int getTileBelDimZ(int x, int y) const override; // arch.cc
|
int getTileBelDimZ(int x, int y) const override; // arch.cc
|
||||||
|
char getNameDelimiter() const override { return '.'; }
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
BelId getBelByName(IdStringList name) const override; // arch.cc
|
BelId getBelByName(IdStringList name) const override; // arch.cc
|
||||||
IdStringList getBelName(BelId bel) const override; // arch.cc
|
IdStringList getBelName(BelId bel) const override; // arch.cc
|
||||||
const std::vector<BelId> &getBels() const override { return bel_list; }
|
AllBelRange getBels() const override { return AllBelRange(bels); }
|
||||||
std::vector<BelId> getBelsByTile(int x, int y) const override;
|
std::vector<BelId> getBelsByTile(int x, int y) const override;
|
||||||
Loc getBelLocation(BelId bel) const override
|
Loc getBelLocation(BelId bel) const override
|
||||||
{
|
{
|
||||||
return Loc(CycloneV::pos2x(bel.pos), CycloneV::pos2y(bel.pos), bel.z);
|
return Loc(CycloneV::pos2x(bel.pos), CycloneV::pos2y(bel.pos), bel.z);
|
||||||
}
|
}
|
||||||
BelId getBelByLocation(Loc loc) const override { return BelId(CycloneV::xy2pos(loc.x, loc.y), loc.z); }
|
BelId getBelByLocation(Loc loc) const override
|
||||||
|
{
|
||||||
|
BelId id = BelId(CycloneV::xy2pos(loc.x, loc.y), loc.z);
|
||||||
|
if (bels.count(id))
|
||||||
|
return id;
|
||||||
|
else
|
||||||
|
return BelId();
|
||||||
|
}
|
||||||
IdString getBelType(BelId bel) const override; // arch.cc
|
IdString getBelType(BelId bel) const override; // arch.cc
|
||||||
WireId getBelPinWire(BelId bel, IdString pin) const override { return WireId(); }
|
WireId getBelPinWire(BelId bel, IdString pin) const override { return WireId(); }
|
||||||
PortType getBelPinType(BelId bel, IdString pin) const override { return PORT_IN; }
|
PortType getBelPinType(BelId bel, IdString pin) const override { return PORT_IN; }
|
||||||
@ -178,18 +178,18 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
WireId getWireByName(IdStringList name) const override { return WireId(); }
|
WireId getWireByName(IdStringList name) const override;
|
||||||
IdStringList getWireName(WireId wire) const override { return IdStringList(); }
|
IdStringList getWireName(WireId wire) const override;
|
||||||
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
DelayQuad getWireDelay(WireId wire) const override { return DelayQuad(0); }
|
||||||
const std::vector<BelPin> &getWireBelPins(WireId wire) const override { return empty_belpin_list; }
|
const std::vector<BelPin> &getWireBelPins(WireId wire) const override { return empty_belpin_list; }
|
||||||
AllWireRange getWires() const override { return AllWireRange(wires); }
|
AllWireRange getWires() const override { return AllWireRange(wires); }
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
PipId getPipByName(IdStringList name) const override { return PipId(); }
|
PipId getPipByName(IdStringList name) const override;
|
||||||
const std::unordered_set<PipId> &getPips() const override { return all_pips; }
|
const std::unordered_set<PipId> &getPips() const override { return all_pips; }
|
||||||
Loc getPipLocation(PipId pip) const override { return Loc(0, 0, 0); }
|
Loc getPipLocation(PipId pip) const override { return Loc(0, 0, 0); }
|
||||||
IdStringList getPipName(PipId pip) const override { return IdStringList(); }
|
IdStringList getPipName(PipId pip) const override;
|
||||||
WireId getPipSrcWire(PipId pip) const override { return WireId(pip.src); };
|
WireId getPipSrcWire(PipId pip) const override { return WireId(pip.src); };
|
||||||
WireId getPipDstWire(PipId pip) const override { return WireId(pip.dst); };
|
WireId getPipDstWire(PipId pip) const override { return WireId(pip.dst); };
|
||||||
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
DelayQuad getPipDelay(PipId pip) const override { return DelayQuad(0); }
|
||||||
@ -228,11 +228,22 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
static const std::vector<std::string> availableRouters;
|
static const std::vector<std::string> availableRouters;
|
||||||
|
|
||||||
std::unordered_map<WireId, WireInfo> wires;
|
std::unordered_map<WireId, WireInfo> wires;
|
||||||
|
std::unordered_map<BelId, BelInfo> bels;
|
||||||
|
|
||||||
// WIP to link without failure
|
// WIP to link without failure
|
||||||
std::unordered_set<PipId> all_pips;
|
std::unordered_set<PipId> all_pips;
|
||||||
std::vector<PipId> empty_pip_list;
|
std::vector<PipId> empty_pip_list;
|
||||||
std::vector<BelPin> empty_belpin_list;
|
std::vector<BelPin> empty_belpin_list;
|
||||||
|
|
||||||
|
// Conversion between numbers and rnode types and IdString, for fast wire name implementation
|
||||||
|
std::vector<IdString> int2id;
|
||||||
|
std::unordered_map<IdString, int> id2int;
|
||||||
|
|
||||||
|
std::vector<IdString> rn_t2id;
|
||||||
|
std::unordered_map<IdString, CycloneV::rnode_type_t> id2rn_t;
|
||||||
|
|
||||||
|
// This structure is only used for nextpnr-created wires
|
||||||
|
std::unordered_map<IdStringList, WireId> npnr_wirebyname;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -49,3 +49,5 @@ X(D1)
|
|||||||
X(CI)
|
X(CI)
|
||||||
X(CO)
|
X(CO)
|
||||||
X(SO)
|
X(SO)
|
||||||
|
|
||||||
|
X(WIRE)
|
Loading…
Reference in New Issue
Block a user