cyclonev: Rework bels
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
86ce6abf6a
commit
431c4cec9f
109
cyclonev/arch.cc
109
cyclonev/arch.cc
@ -56,6 +56,7 @@ Arch::Arch(ArchArgs args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_info("Initialising bels...\n");
|
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 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);
|
||||||
@ -63,22 +64,11 @@ Arch::Arch(ArchArgs args)
|
|||||||
for (CycloneV::block_type_t bel : cyclonev->pos_get_bels(pos)) {
|
for (CycloneV::block_type_t bel : cyclonev->pos_get_bels(pos)) {
|
||||||
switch (bel) {
|
switch (bel) {
|
||||||
case CycloneV::block_type_t::LAB:
|
case CycloneV::block_type_t::LAB:
|
||||||
/*
|
create_lab(x, y);
|
||||||
* 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))];
|
|
||||||
}
|
|
||||||
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++) {
|
// TODO
|
||||||
bels[BelId(pos, (bel << 8 | z))];
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
@ -111,21 +101,22 @@ Arch::Arch(ArchArgs args)
|
|||||||
|
|
||||||
int Arch::getTileBelDimZ(int x, int y) const
|
int Arch::getTileBelDimZ(int x, int y) const
|
||||||
{
|
{
|
||||||
// FIXME: currently encoding type in z (this will be fixed soon when site contents are implemented)
|
// This seems like a reasonable upper bound
|
||||||
return 16384;
|
return 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
BelId Arch::getBelByName(IdStringList name) const
|
BelId Arch::getBelByName(IdStringList name) const
|
||||||
{
|
{
|
||||||
BelId bel;
|
BelId bel;
|
||||||
NPNR_ASSERT(name.size() == 4);
|
NPNR_ASSERT(name.size() == 4);
|
||||||
auto bel_type = cyclonev->block_type_lookup(name[0].str(this));
|
|
||||||
int x = id2int.at(name[1]);
|
int x = id2int.at(name[1]);
|
||||||
int y = id2int.at(name[2]);
|
int y = id2int.at(name[2]);
|
||||||
int z = id2int.at(name[3]);
|
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 = z;
|
||||||
|
|
||||||
|
NPNR_ASSERT(name[0] == getBelType(bel));
|
||||||
|
|
||||||
return bel;
|
return bel;
|
||||||
}
|
}
|
||||||
@ -135,10 +126,9 @@ IdStringList Arch::getBelName(BelId bel) const
|
|||||||
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;
|
|
||||||
|
|
||||||
std::array<IdString, 4> ids{
|
std::array<IdString, 4> ids{
|
||||||
id(cyclonev->block_type_names[bel_type]),
|
getBelType(bel),
|
||||||
int2id.at(x),
|
int2id.at(x),
|
||||||
int2id.at(y),
|
int2id.at(y),
|
||||||
int2id.at(z),
|
int2id.at(z),
|
||||||
@ -201,60 +191,23 @@ IdStringList Arch::getPipName(PipId pip) const
|
|||||||
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
|
std::vector<BelId> Arch::getBelsByTile(int x, int y) const
|
||||||
{
|
{
|
||||||
// This should probably be redesigned, but it's a hack.
|
// This should probably be redesigned, but it's a hack.
|
||||||
std::vector<BelId> bels{};
|
std::vector<BelId> bels;
|
||||||
|
if (x >= 0 && x < cyclonev->get_tile_sx() && y >= 0 && y < cyclonev->get_tile_sy()) {
|
||||||
CycloneV::pos_t pos = cyclonev->xy2pos(x, y);
|
for (size_t i = 0; i < bels_by_tile.at(pos2idx(x, y)).size(); i++)
|
||||||
|
bels.push_back(BelId(CycloneV::xy2pos(x, y), i));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bels;
|
return bels;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString Arch::getBelType(BelId bel) const
|
IdString Arch::getBelType(BelId bel) const { return bel_data(bel).type; }
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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; }
|
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)
|
BelId Arch::add_bel(int x, int y, IdString name, IdString type)
|
||||||
{
|
{
|
||||||
// TODO: nothing else is using this BelId system yet...
|
auto &bels = bels_by_tile.at(pos2idx(x, y));
|
||||||
// TODO (tomorrow?): we probably want a belsByTile type arrangement, similar for wires and pips, for better spacial
|
BelId id = BelId(CycloneV::xy2pos(x, y), bels.size());
|
||||||
// locality
|
all_bels.push_back(id);
|
||||||
int z = 0;
|
bels.emplace_back();
|
||||||
BelId id;
|
auto &bel = bels.back();
|
||||||
// Determine a unique z-coordinate
|
|
||||||
while (bels.count(id = BelId(CycloneV::xy2pos(x, y), z)))
|
|
||||||
z++;
|
|
||||||
auto &bel = bels[id];
|
|
||||||
bel.name = name;
|
bel.name = name;
|
||||||
bel.type = type;
|
bel.type = type;
|
||||||
|
// TODO: buckets (for example LABs and MLABs in the same bucket)
|
||||||
bel.bucket = type;
|
bel.bucket = type;
|
||||||
return id;
|
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)
|
void Arch::add_bel_pin(BelId bel, IdString pin, PortType dir, WireId wire)
|
||||||
{
|
{
|
||||||
bels[bel].pins[pin].dir = dir;
|
auto &b = bel_data(bel);
|
||||||
bels[bel].pins[pin].wire = wire;
|
b.pins[pin].dir = dir;
|
||||||
|
b.pins[pin].wire = wire;
|
||||||
|
|
||||||
BelPin bel_pin;
|
BelPin bel_pin;
|
||||||
bel_pin.bel = bel;
|
bel_pin.bel = bel;
|
||||||
|
@ -67,7 +67,9 @@ struct BelInfo
|
|||||||
IdString name;
|
IdString name;
|
||||||
IdString type;
|
IdString type;
|
||||||
IdString bucket;
|
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;
|
std::unordered_map<IdString, PinInfo> pins;
|
||||||
// Info for different kinds of bels
|
// Info for different kinds of bels
|
||||||
union
|
union
|
||||||
@ -204,13 +206,12 @@ 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 = AllBelRange;
|
using AllBelsRangeT = const std::vector<BelId> &;
|
||||||
using TileBelsRangeT = std::vector<BelId>;
|
using TileBelsRangeT = std::vector<BelId>;
|
||||||
using BelPinsRangeT = std::vector<IdString>;
|
using BelPinsRangeT = std::vector<IdString>;
|
||||||
// Wires
|
// Wires
|
||||||
@ -242,7 +243,7 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
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
|
||||||
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;
|
std::vector<BelId> getBelsByTile(int x, int y) const override;
|
||||||
Loc getBelLocation(BelId bel) const override
|
Loc getBelLocation(BelId bel) const override
|
||||||
{
|
{
|
||||||
@ -250,16 +251,27 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
}
|
}
|
||||||
BelId getBelByLocation(Loc loc) const override
|
BelId getBelByLocation(Loc loc) const override
|
||||||
{
|
{
|
||||||
BelId id = BelId(CycloneV::xy2pos(loc.x, loc.y), loc.z);
|
if (loc.x < 0 || loc.x >= cyclonev->get_tile_sx())
|
||||||
if (bels.count(id))
|
|
||||||
return id;
|
|
||||||
else
|
|
||||||
return BelId();
|
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
|
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
|
||||||
PortType getBelPinType(BelId bel, IdString pin) const override { return PORT_IN; }
|
{
|
||||||
std::vector<IdString> getBelPins(BelId bel) const override { return {}; }
|
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;
|
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;
|
|
||||||
|
|
||||||
// List of LABs
|
// List of LABs
|
||||||
std::vector<LABInfo> labs;
|
std::vector<LABInfo> labs;
|
||||||
@ -347,6 +358,21 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// This structure is only used for nextpnr-created wires
|
// This structure is only used for nextpnr-created wires
|
||||||
std::unordered_map<IdStringList, WireId> npnr_wirebyname;
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -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);
|
arch->add_bel_pin(bel, id_COMBOUT, PORT_OUT, comb_out);
|
||||||
// Assign indexing
|
// Assign indexing
|
||||||
lab.alms.at(z).lut_bels.at(i) = bel;
|
lab.alms.at(z).lut_bels.at(i) = bel;
|
||||||
arch->bels.at(bel).lab_data.lab = lab_idx;
|
auto &b = arch->bel_data(bel);
|
||||||
arch->bels.at(bel).lab_data.alm = z;
|
b.lab_data.lab = lab_idx;
|
||||||
arch->bels.at(bel).lab_data.idx = i;
|
b.lab_data.alm = z;
|
||||||
|
b.lab_data.idx = i;
|
||||||
}
|
}
|
||||||
// Create the control set and E/F selection - which is per pair of FF
|
// 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;
|
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;
|
lab.alms.at(z).ff_bels.at(i) = bel;
|
||||||
arch->bels.at(bel).lab_data.lab = lab_idx;
|
auto &b = arch->bel_data(bel);
|
||||||
arch->bels.at(bel).lab_data.alm = z;
|
b.lab_data.lab = lab_idx;
|
||||||
arch->bels.at(bel).lab_data.idx = i;
|
b.lab_data.alm = z;
|
||||||
|
b.lab_data.idx = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Loading…
Reference in New Issue
Block a user