aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-05-03 15:12:24 +0100
committergatecat <gatecat@ds0.me>2021-05-15 14:54:33 +0100
commit431c4cec9ff9652ddafabac7244f19f425ff3e06 (patch)
tree590d4ede9c0970e132d9864d70f8c419742b88c7
parent86ce6abf6a47f0f452dfe0045cec762d986e7ada (diff)
downloadnextpnr-431c4cec9ff9652ddafabac7244f19f425ff3e06.tar.gz
nextpnr-431c4cec9ff9652ddafabac7244f19f425ff3e06.tar.bz2
nextpnr-431c4cec9ff9652ddafabac7244f19f425ff3e06.zip
cyclonev: Rework bels
Signed-off-by: gatecat <gatecat@ds0.me>
-rw-r--r--cyclonev/arch.cc109
-rw-r--r--cyclonev/arch.h50
-rw-r--r--cyclonev/lab.cc14
3 files changed, 76 insertions, 97 deletions
diff --git a/cyclonev/arch.cc b/cyclonev/arch.cc
index f41eb10e..d8464ca2 100644
--- a/cyclonev/arch.cc
+++ b/cyclonev/arch.cc
@@ -56,6 +56,7 @@ Arch::Arch(ArchArgs args)
}
log_info("Initialising bels...\n");
+ bels_by_tile.resize(cyclonev->get_tile_sx() * cyclonev->get_tile_sy());
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);
@@ -63,22 +64,11 @@ Arch::Arch(ArchArgs args)
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.
- */
- for (int z = 0; z < 60; z++) {
- bels[BelId(pos, (bel << 8 | z))];
- }
+ create_lab(x, y);
break;
case CycloneV::block_type_t::GPIO:
- // GPIO tiles contain 4 pins.
- for (int z = 0; z < 4; z++) {
- bels[BelId(pos, (bel << 8 | z))];
- }
+ // GPIO tiles contain 4 pins
+ // TODO
break;
default:
continue;
@@ -111,21 +101,22 @@ Arch::Arch(ArchArgs args)
int Arch::getTileBelDimZ(int x, int y) const
{
- // FIXME: currently encoding type in z (this will be fixed soon when site contents are implemented)
- return 16384;
+ // This seems like a reasonable upper bound
+ return 256;
}
BelId Arch::getBelByName(IdStringList name) const
{
BelId bel;
NPNR_ASSERT(name.size() == 4);
- auto bel_type = cyclonev->block_type_lookup(name[0].str(this));
int x = id2int.at(name[1]);
int y = id2int.at(name[2]);
int z = id2int.at(name[3]);
bel.pos = CycloneV::xy2pos(x, y);
- bel.z = (bel_type << 8) | z;
+ bel.z = z;
+
+ NPNR_ASSERT(name[0] == getBelType(bel));
return bel;
}
@@ -135,10 +126,9 @@ IdStringList Arch::getBelName(BelId bel) const
int x = CycloneV::pos2x(bel.pos);
int y = CycloneV::pos2y(bel.pos);
int z = bel.z & 0xFF;
- int bel_type = bel.z >> 8;
std::array<IdString, 4> ids{
- id(cyclonev->block_type_names[bel_type]),
+ getBelType(bel),
int2id.at(x),
int2id.at(y),
int2id.at(z),
@@ -201,60 +191,23 @@ IdStringList Arch::getPipName(PipId pip) const
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
{
// This should probably be redesigned, but it's a hack.
- std::vector<BelId> bels{};
-
- CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
-
- for (CycloneV::block_type_t cvbel : cyclonev->pos_get_bels(pos)) {
- switch (cvbel) {
- 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.
- */
- for (int z = 0; z < 60; z++) {
- bels.push_back(BelId(pos, (cvbel << 8 | z)));
- }
- break;
- case CycloneV::block_type_t::GPIO:
- // GPIO tiles contain 4 pins.
- for (int z = 0; z < 4; z++) {
- bels.push_back(BelId(pos, (cvbel << 8 | z)));
- }
- break;
- default:
- continue;
- }
+ 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));
}
return bels;
}
-IdString Arch::getBelType(BelId bel) const
-{
- for (CycloneV::block_type_t cvbel : cyclonev->pos_get_bels(bel.pos)) {
- switch (cvbel) {
- 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 IdString(this, "LAB");
- case CycloneV::block_type_t::GPIO:
- // GPIO tiles contain 4 pins.
- return IdString(this, "GPIO");
- default:
- continue;
- }
- }
+IdString Arch::getBelType(BelId bel) const { return bel_data(bel).type; }
- return IdString();
+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;
}
bool Arch::pack() { return true; }
@@ -263,17 +216,14 @@ bool Arch::route() { return true; }
BelId Arch::add_bel(int x, int y, IdString name, IdString type)
{
- // TODO: nothing else is using this BelId system yet...
- // TODO (tomorrow?): we probably want a belsByTile type arrangement, similar for wires and pips, for better spacial
- // locality
- int z = 0;
- BelId id;
- // Determine a unique z-coordinate
- while (bels.count(id = BelId(CycloneV::xy2pos(x, y), z)))
- z++;
- auto &bel = bels[id];
+ 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;
}
@@ -312,8 +262,9 @@ PipId Arch::add_pip(WireId src, WireId dst)
void Arch::add_bel_pin(BelId bel, IdString pin, PortType dir, WireId wire)
{
- bels[bel].pins[pin].dir = dir;
- bels[bel].pins[pin].wire = wire;
+ auto &b = bel_data(bel);
+ b.pins[pin].dir = dir;
+ b.pins[pin].wire = wire;
BelPin bel_pin;
bel_pin.bel = bel;
diff --git a/cyclonev/arch.h b/cyclonev/arch.h
index 0614860d..5ecba367 100644
--- a/cyclonev/arch.h
+++ b/cyclonev/arch.h
@@ -67,7 +67,9 @@ struct BelInfo
IdString name;
IdString type;
IdString bucket;
- int z;
+ // For cases where we need to determine an original block index, due to multiple bels at the same tile this might
+ // not be the same as the nextpnr z-coordinate
+ int block_index;
std::unordered_map<IdString, PinInfo> pins;
// Info for different kinds of bels
union
@@ -204,13 +206,12 @@ template <typename T> struct key_range
};
using AllWireRange = key_range<std::unordered_map<WireId, WireInfo>>;
-using AllBelRange = key_range<std::unordered_map<BelId, BelInfo>>;
struct ArchRanges : BaseArchRanges
{
using ArchArgsT = ArchArgs;
// Bels
- using AllBelsRangeT = AllBelRange;
+ using AllBelsRangeT = const std::vector<BelId> &;
using TileBelsRangeT = std::vector<BelId>;
using BelPinsRangeT = std::vector<IdString>;
// Wires
@@ -242,7 +243,7 @@ struct Arch : BaseArch<ArchRanges>
BelId getBelByName(IdStringList name) const override; // arch.cc
IdStringList getBelName(BelId bel) const override; // arch.cc
- AllBelRange getBels() const override { return AllBelRange(bels); }
+ const std::vector<BelId> &getBels() const override { return all_bels; }
std::vector<BelId> getBelsByTile(int x, int y) const override;
Loc getBelLocation(BelId bel) const override
{
@@ -250,16 +251,27 @@ struct Arch : BaseArch<ArchRanges>
}
BelId getBelByLocation(Loc loc) const override
{
- BelId id = BelId(CycloneV::xy2pos(loc.x, loc.y), loc.z);
- if (bels.count(id))
- return id;
- else
+ if (loc.x < 0 || loc.x >= cyclonev->get_tile_sx())
+ return BelId();
+ if (loc.y < 0 || loc.y >= cyclonev->get_tile_sy())
+ return BelId();
+ auto &bels = bels_by_tile.at(pos2idx(loc.x, loc.y));
+ if (loc.z < 0 || loc.z >= int(bels.size()))
return BelId();
+ return BelId(CycloneV::xy2pos(loc.x, loc.y), loc.z);
}
IdString getBelType(BelId bel) const override; // arch.cc
- WireId getBelPinWire(BelId bel, IdString pin) const override { return WireId(); }
- PortType getBelPinType(BelId bel, IdString pin) const override { return PORT_IN; }
- std::vector<IdString> getBelPins(BelId bel) const override { return {}; }
+ WireId getBelPinWire(BelId bel, IdString pin) const override
+ {
+ auto &pins = bel_data(bel).pins;
+ auto found = pins.find(pin);
+ if (found == pins.end())
+ return WireId();
+ else
+ return found->second.wire;
+ }
+ PortType getBelPinType(BelId bel, IdString pin) const override { return bel_data(bel).pins.at(pin).dir; }
+ std::vector<IdString> getBelPins(BelId bel) const override;
// -------------------------------------------------
@@ -330,7 +342,6 @@ struct Arch : BaseArch<ArchRanges>
static const std::vector<std::string> availableRouters;
std::unordered_map<WireId, WireInfo> wires;
- std::unordered_map<BelId, BelInfo> bels;
// List of LABs
std::vector<LABInfo> labs;
@@ -347,6 +358,21 @@ struct Arch : BaseArch<ArchRanges>
// This structure is only used for nextpnr-created wires
std::unordered_map<IdStringList, WireId> npnr_wirebyname;
+
+ std::vector<std::vector<BelInfo>> bels_by_tile;
+ std::vector<BelId> all_bels;
+
+ size_t pos2idx(int x, int y) const
+ {
+ NPNR_ASSERT(x >= 0 && x < int(cyclonev->get_tile_sx()));
+ NPNR_ASSERT(y >= 0 && y < int(cyclonev->get_tile_sy()));
+ return y * cyclonev->get_tile_sx() + x;
+ }
+
+ size_t pos2idx(CycloneV::pos_t pos) const { return pos2idx(CycloneV::pos2x(pos), CycloneV::pos2y(pos)); }
+
+ BelInfo &bel_data(BelId bel) { return bels_by_tile.at(pos2idx(bel.pos)).at(bel.z); }
+ const BelInfo &bel_data(BelId bel) const { return bels_by_tile.at(pos2idx(bel.pos)).at(bel.z); }
};
NEXTPNR_NAMESPACE_END
diff --git a/cyclonev/lab.cc b/cyclonev/lab.cc
index b464b88a..55602da4 100644
--- a/cyclonev/lab.cc
+++ b/cyclonev/lab.cc
@@ -79,9 +79,10 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
arch->add_bel_pin(bel, id_COMBOUT, PORT_OUT, comb_out);
// Assign indexing
lab.alms.at(z).lut_bels.at(i) = bel;
- arch->bels.at(bel).lab_data.lab = lab_idx;
- arch->bels.at(bel).lab_data.alm = z;
- arch->bels.at(bel).lab_data.idx = i;
+ auto &b = arch->bel_data(bel);
+ b.lab_data.lab = lab_idx;
+ b.lab_data.alm = z;
+ b.lab_data.idx = i;
}
// Create the control set and E/F selection - which is per pair of FF
std::array<WireId, 2> sel_clk, sel_ena, sel_aclr, sel_ef;
@@ -138,9 +139,10 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
}
lab.alms.at(z).ff_bels.at(i) = bel;
- arch->bels.at(bel).lab_data.lab = lab_idx;
- arch->bels.at(bel).lab_data.alm = z;
- arch->bels.at(bel).lab_data.idx = i;
+ auto &b = arch->bel_data(bel);
+ b.lab_data.lab = lab_idx;
+ b.lab_data.alm = z;
+ b.lab_data.idx = i;
}
}
} // namespace