diff --git a/cyclonev/arch.cc b/cyclonev/arch.cc index 10b7a71b..64444695 100644 --- a/cyclonev/arch.cc +++ b/cyclonev/arch.cc @@ -261,6 +261,66 @@ 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, IdString bucket) +{ + // 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]; + bel.name = name; + bel.type = type; + bel.bucket = bucket; + return id; +} + +WireId Arch::add_wire(int x, int y, IdString name, uint64_t flags) +{ + std::array 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; + 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) +{ + bels[bel].pins[pin].dir = dir; + bels[bel].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 diff --git a/cyclonev/arch.h b/cyclonev/arch.h index ce21a63c..1f545134 100644 --- a/cyclonev/arch.h +++ b/cyclonev/arch.h @@ -37,16 +37,45 @@ struct ArchArgs std::string mistral_root; }; +// These structures are used for fast ALM validity checking +struct ALMInfo +{ + // Pointers to bels + std::array lut_bels; + std::array ff_bels; + // TODO: ALM configuration (L5/L6 mode, LUT input permutation, etc) +}; + +struct LABInfo +{ + std::array alms; + // TODO: LAB configuration (control set etc) +}; + struct PinInfo { - IdString name; WireId wire; - PortType type; + PortType dir; }; struct BelInfo { - // TODO + IdString name; + IdString type; + IdString bucket; + int z; + std::unordered_map pins; + // Info for different kinds of bels + union + { + // This enables fast lookup of the associated ALM, etc + struct + { + uint32_t lab; // index into the list of LABs + uint8_t alm; // ALM index inside LAB + uint8_t idx; // LUT or FF index inside ALM + } labData; + }; }; // We maintain our own wire data based on mistral's. This gets us the bidirectional linking that nextpnr needs, @@ -272,6 +301,18 @@ struct Arch : BaseArch bool place() override; bool route() override; + // ------------------------------------------------- + // Functions for device setup + + BelId add_bel(int x, int y, IdString name, IdString type, IdString bucket); + WireId add_wire(int x, int y, IdString name, uint64_t flags = 0); + PipId add_pip(WireId src, WireId dst); + + void add_bel_pin(BelId bel, IdString pin, PortType dir, WireId wire); + + void create_lab(int x, int y); + void create_gpio(int x, int y); + // ------------------------------------------------- static const std::string defaultPlacer;