nextpnr/himbaechel/uarch/xilinx/pack.h
gatecat 24fc33c014 xilinx: Basic I/ODDR support
Signed-off-by: gatecat <gatecat@ds0.me>
2024-09-27 17:09:15 +02:00

219 lines
7.4 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019-23 Myrtle Shah <gatecat@ds0.me>
*
* 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 <algorithm>
#include <boost/optional.hpp>
#include <iterator>
#include <queue>
#include <unordered_set>
#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<IdString, IdString> port_xform;
dict<IdString, std::vector<IdString>> port_multixform;
dict<IdString, IdString> param_xform;
std::vector<std::pair<IdString, std::string>> set_attrs;
std::vector<std::pair<IdString, Property>> set_params;
};
// Distributed RAM control set
struct DRAMControlSet
{
std::vector<NetInfo *> 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<CellInfo *> muxcys;
std::vector<CellInfo *> xorcys;
};
pool<IdString> packed_cells;
// General helper functions
void flush_cells();
void xform_cell(const dict<IdString, XFormRule> &rules, CellInfo *ci);
void generic_xform(const dict<IdString, XFormRule> &rules, bool print_summary = false);
CellInfo *feed_through_lut(NetInfo *net, const std::vector<PortRef> &feed_users);
CellInfo *feed_through_muxf(NetInfo *net, IdString type, const std::vector<PortRef> &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<CellInfo *> &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<NetInfo *> &data,
const std::vector<NetInfo *> &select, NetInfo *out, int zoffset);
void pack_srls();
void split_carry4s();
// DistRAM
dict<IdString, XFormRule> dram_rules, dram32_6_rules, dram32_5_rules;
CellInfo *create_dram_lut(const std::string &name, CellInfo *base, const DRAMControlSet &ctrlset,
std::vector<NetInfo *> address, NetInfo *di, NetInfo *dout, int z);
CellInfo *create_dram32_lut(const std::string &name, CellInfo *base, const DRAMControlSet &ctrlset,
std::vector<NetInfo *> address, NetInfo *di, NetInfo *dout, bool o5, int z);
void pack_dram();
// Constant pins
dict<IdString, dict<IdString, bool>> tied_pins;
dict<IdString, pool<IdString>> invertible_pins;
void pack_constants();
// IO
dict<IdString, pool<IdString>> 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<CellInfo *, PortRef> 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<NetInfo *> &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<NetInfo *, 2> &i, NetInfo *o);
void decompose_iob(CellInfo *xil_iob, bool is_hr, const std::string &iostandard);
void pack_io();
// IOLOGIC
dict<IdString, XFormRule> 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