/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2019-23 Myrtle Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include #include #include #include #include #include "chain_utils.h" #include "design_utils.h" #include "log.h" #include "nextpnr.h" #include "pins.h" #include "xilinx.h" #ifndef HB_XILINX_PACK_H #define HB_XILINX_PACK_H NEXTPNR_NAMESPACE_BEGIN struct XilinxPacker { Context *ctx; XilinxImpl *uarch; XilinxPacker(Context *ctx, XilinxImpl *uarch) : ctx(ctx), uarch(uarch) {}; // Generic cell transformation // Given cell name map and port map // If port name is not found in port map; it will be copied as-is but stripping [] struct XFormRule { IdString new_type; dict port_xform; dict> port_multixform; dict param_xform; std::vector> set_attrs; std::vector> set_params; }; // Distributed RAM control set struct DRAMControlSet { std::vector wa; NetInfo *wclk, *we; bool wclk_inv; IdString memtype; bool operator==(const DRAMControlSet &other) const { return wa == other.wa && wclk == other.wclk && we == other.we && wclk_inv == other.wclk_inv && memtype == other.memtype; } bool operator!=(const DRAMControlSet &other) const { return wa != other.wa || wclk != other.wclk || we != other.we || wclk_inv != other.wclk_inv || memtype != other.memtype; } unsigned int hash() const { unsigned seed = 0; seed = mkhash(seed, wa.size()); for (auto abit : wa) seed = mkhash(seed, (abit == nullptr ? IdString() : abit->name).hash()); seed = mkhash(seed, (wclk == nullptr ? IdString() : wclk->name).hash()); seed = mkhash(seed, (we == nullptr ? IdString() : we->name).hash()); seed = mkhash(seed, wclk_inv); seed = mkhash(seed, memtype.hash()); return seed; } }; struct DRAMType { int abits; int dbits; int rports; }; struct CarryGroup { std::vector muxcys; std::vector xorcys; }; pool packed_cells; // General helper functions void flush_cells(); void xform_cell(const dict &rules, CellInfo *ci); void generic_xform(const dict &rules, bool print_summary = false); CellInfo *feed_through_lut(NetInfo *net, const std::vector &feed_users); CellInfo *feed_through_muxf(NetInfo *net, IdString type, const std::vector &feed_users); IdString int_name(IdString base, const std::string &postfix, bool is_hierarchy = true); NetInfo *create_internal_net(IdString base, const std::string &postfix, bool is_hierarchy = true); void rename_net(IdString old, IdString newname); void tie_port(CellInfo *ci, const std::string &port, bool value, bool inv = false); // LUTs & FFs void pack_inverters(); void pack_luts(); void pack_ffs(); void pack_lutffs(); bool is_constrained(const CellInfo *cell); void pack_muxfs(); void finalise_muxfs(); void legalise_muxf_tree(CellInfo *curr, std::vector &mux_roots); void constrain_muxf_tree(CellInfo *curr, CellInfo *base, int zoffset); void create_muxf_tree(CellInfo *base, const std::string &name_base, const std::vector &data, const std::vector &select, NetInfo *out, int zoffset); void pack_srls(); void split_carry4s(); // DistRAM dict dram_rules, dram32_6_rules, dram32_5_rules; CellInfo *create_dram_lut(const std::string &name, CellInfo *base, const DRAMControlSet &ctrlset, std::vector address, NetInfo *di, NetInfo *dout, int z); CellInfo *create_dram32_lut(const std::string &name, CellInfo *base, const DRAMControlSet &ctrlset, std::vector address, NetInfo *di, NetInfo *dout, bool o5, int z); void pack_dram(); // Constant pins dict> tied_pins; dict> invertible_pins; void pack_constants(); // IO dict> toplevel_ports; NetInfo *invert_net(NetInfo *toinv); CellInfo *insert_obuf(IdString name, IdString type, NetInfo *i, NetInfo *o, NetInfo *tri = nullptr); CellInfo *insert_outinv(IdString name, NetInfo *i, NetInfo *o); std::pair insert_pad_and_buf(CellInfo *npnr_io); CellInfo *create_iobuf(CellInfo *npnr_io, IdString &top_port); // Clocking BelId find_bel_with_short_route(WireId source, IdString beltype, IdString belpin); void try_preplace(CellInfo *cell, IdString port); void preplace_unique(CellInfo *cell); // Cell creating CellInfo *create_cell(IdString type, IdString name); CellInfo *create_lut(const std::string &name, const std::vector &inputs, NetInfo *output, const Property &init); int autoidx = 0; }; struct XC7Packer : public XilinxPacker { XC7Packer(Context *ctx, XilinxImpl *uarch) : XilinxPacker(ctx, uarch) {}; // Carries bool has_illegal_fanout(NetInfo *carry); void pack_carries(); // IO CellInfo *insert_ibuf(IdString name, IdString type, NetInfo *i, NetInfo *o); CellInfo *insert_diffibuf(IdString name, IdString type, const std::array &i, NetInfo *o); void decompose_iob(CellInfo *xil_iob, bool is_hr, const std::string &iostandard); void pack_io(); // IOLOGIC dict hp_iol_rules, hd_iol_rules, ioctrl_rules; void fold_inverter(CellInfo *cell, std::string port); SiteIndex get_ologic_site(BelId io_bel); SiteIndex get_ilogic_site(BelId io_bel); SiteIndex get_ioctrl_site(BelId io_bel); SiteIndex get_odelay_site(BelId io_bel); SiteIndex get_idelay_site(BelId io_bel); // Call before packing constants void prepare_iologic(); void pack_iologic(); void pack_idelayctrl(); // Clocking void prepare_clocking(); void pack_plls(); void pack_gbs(); void pack_clocking(); // BRAM void pack_bram(); // DSP void pack_dsps(); private: unsigned walk_dsp(CellInfo *root, CellInfo *ci, int constr_z); void check_valid_pad(CellInfo *ci, std::string type); }; NEXTPNR_NAMESPACE_END #endif