diff options
author | gatecat <gatecat@ds0.me> | 2021-05-03 15:12:24 +0100 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2021-05-15 14:54:33 +0100 |
commit | 431c4cec9ff9652ddafabac7244f19f425ff3e06 (patch) | |
tree | 590d4ede9c0970e132d9864d70f8c419742b88c7 | |
parent | 86ce6abf6a47f0f452dfe0045cec762d986e7ada (diff) | |
download | nextpnr-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.cc | 109 | ||||
-rw-r--r-- | cyclonev/arch.h | 50 | ||||
-rw-r--r-- | cyclonev/lab.cc | 14 |
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 |