2023-07-20 10:09:14 +08:00
|
|
|
#ifndef GOWIN_UTILS_H
|
|
|
|
#define GOWIN_UTILS_H
|
|
|
|
|
|
|
|
#include "idstringlist.h"
|
|
|
|
#include "nextpnr_namespaces.h"
|
|
|
|
#include "nextpnr_types.h"
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_BEGIN
|
|
|
|
|
2023-08-08 08:57:45 +08:00
|
|
|
namespace BelFlags {
|
|
|
|
static constexpr uint32_t FLAG_SIMPLE_IO = 0x100;
|
|
|
|
}
|
|
|
|
|
2023-07-20 10:09:14 +08:00
|
|
|
struct GowinUtils
|
|
|
|
{
|
|
|
|
Context *ctx;
|
|
|
|
|
|
|
|
GowinUtils() {}
|
|
|
|
|
|
|
|
void init(Context *ctx) { this->ctx = ctx; }
|
|
|
|
|
2023-08-13 20:05:18 +08:00
|
|
|
// tile
|
|
|
|
IdString get_tile_class(int x, int y);
|
|
|
|
Loc get_tile_io16_offs(int x, int y);
|
|
|
|
|
2023-07-20 10:09:14 +08:00
|
|
|
// pin functions: GCLKT_4, SSPI_CS, READY etc
|
2024-04-07 19:47:23 +08:00
|
|
|
IdStringList get_pin_funcs(BelId io_bel);
|
|
|
|
|
|
|
|
// PLL pads (type - CLKIN, FeedBack, etc)
|
|
|
|
BelId get_pll_bel(BelId io_bel, IdString type);
|
2023-08-08 08:57:45 +08:00
|
|
|
|
|
|
|
// Bels and pips
|
|
|
|
bool is_simple_io_bel(BelId bel);
|
|
|
|
Loc get_pair_iologic_bel(Loc loc);
|
|
|
|
BelId get_io_bel_from_iologic(BelId bel);
|
2024-07-14 14:53:26 +08:00
|
|
|
BelId get_dqce_bel(IdString spine_name);
|
|
|
|
BelId get_dcs_bel(IdString spine_name);
|
2023-08-08 08:57:45 +08:00
|
|
|
|
2024-06-23 18:26:50 +08:00
|
|
|
// BSRAM
|
2024-07-06 17:14:43 +08:00
|
|
|
bool has_SP32(void);
|
2024-06-23 18:26:50 +08:00
|
|
|
bool need_SP_fix(void);
|
2024-06-25 16:27:00 +08:00
|
|
|
bool need_BSRAM_OUTREG_fix(void);
|
2024-06-28 06:15:50 +08:00
|
|
|
bool need_BLKSEL_fix(void);
|
2024-06-23 18:26:50 +08:00
|
|
|
|
2024-07-06 17:14:43 +08:00
|
|
|
// Power saving
|
|
|
|
bool has_BANDGAP(void);
|
|
|
|
|
2024-03-18 20:08:52 +08:00
|
|
|
// DSP
|
|
|
|
inline int get_dsp_18_z(int z) const { return z & (~3); }
|
|
|
|
inline int get_dsp_9_idx(int z) const { return z & 3; }
|
|
|
|
inline int get_dsp_18_idx(int z) const { return z & 4; }
|
|
|
|
inline int get_dsp_paired_9(int z) const { return (3 - get_dsp_9_idx(z)) | (z & (~3)); }
|
|
|
|
inline int get_dsp_mult_from_padd(int padd_z) const { return padd_z + 8; }
|
|
|
|
inline int get_dsp_padd_from_mult(int mult_z) const { return mult_z - 8; }
|
|
|
|
inline int get_dsp_next_macro(int z) const { return z + 32; }
|
|
|
|
inline int get_dsp(int z) const { return BelZ::DSP_Z; }
|
|
|
|
inline int get_dsp_macro(int z) const { return (z & 0x20) + BelZ::DSP_0_Z; }
|
|
|
|
inline int get_dsp_macro_num(int z) const { return (z & 0x20) >> 5; }
|
|
|
|
Loc get_dsp_next_9_in_chain(Loc from) const;
|
|
|
|
Loc get_dsp_next_macro_in_chain(Loc from) const;
|
|
|
|
Loc get_dsp_next_in_chain(Loc from, IdString dsp_type) const;
|
|
|
|
|
|
|
|
// check bus.
|
|
|
|
// This is necessary to find the head in the DSP chain - these buses are
|
|
|
|
// not switched in the hardware, but in software you can leave them
|
|
|
|
// unconnected or connect them to VCC or VSS, which is the same - as I
|
|
|
|
// already said, they are hard-wired and we are only discovering the fact
|
|
|
|
// that they are not connected to another DSP in the chain.
|
|
|
|
CellInfo *dsp_bus_src(const CellInfo *ci, const char *bus_prefix, int wire_num) const;
|
|
|
|
CellInfo *dsp_bus_dst(const CellInfo *ci, const char *bus_prefix, int wire_num) const;
|
|
|
|
|
2023-08-08 08:57:45 +08:00
|
|
|
bool is_diff_io_supported(IdString type);
|
2024-07-06 17:14:43 +08:00
|
|
|
bool has_bottom_io_cnds(void);
|
2023-08-08 08:57:45 +08:00
|
|
|
IdString get_bottom_io_wire_a_net(int8_t condition);
|
|
|
|
IdString get_bottom_io_wire_b_net(int8_t condition);
|
gowin: Himbaechel. Add GW1NZ-1 BSRAM.
The following primitives are implemented for the GW1NZ-1 chip:
* pROM - read only memory - (bitwidth: 1, 2, 4, 8, 16, 32).
* pROMX9 - read only memory - (bitwidth: 9, 18, 36).
* SDPB - semidual port - (bitwidth: 1, 2, 4, 8, 16, 32).
* SDPX9B - semidual port - (bitwidth: 9, 18, 36).
* DPB - dual port - (bitwidth: 16).
* DPX9B - dual port - (bitwidth: 18).
* SP - single port - (bitwidth: 1, 2, 4, 8, 16, 32).
* SPX9 - single port - (bitwidth: 9, 18, 36).
Also:
- The creation of databases for GW1NS-2 has been removed - this was not
planned to be supported in Himbaechel from the very beginning and
even examples were not created in apicula for this chip due to the
lack of boards with it on sale.
- It is temporarily prohibited to connect DFFs and LUTs into clusters
because for some reason this prevents the creation of images on lower
chips (placer cannot find the placement), although without these
clusters the images are quite working. Requires further research.
- Added creation of ALU with mode 0 - addition. Such an element is not
generated by Yosys, but it is a favorite vendor element and its
support here greatly simplifies the compilation of vendor netlists.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
2023-11-20 10:27:56 +08:00
|
|
|
|
|
|
|
// wires
|
|
|
|
inline bool is_wire_type_default(IdString wire_type) { return wire_type == IdString(); }
|
2024-01-23 12:50:36 +08:00
|
|
|
// If wire is an important part of the global network (like SPINExx)
|
|
|
|
inline bool is_global_wire(WireId wire) const
|
|
|
|
{
|
|
|
|
return ctx->getWireName(wire)[1].in(
|
|
|
|
id_SPINE0, id_SPINE1, id_SPINE2, id_SPINE3, id_SPINE4, id_SPINE5, id_SPINE6, id_SPINE7, id_SPINE8,
|
|
|
|
id_SPINE9, id_SPINE10, id_SPINE11, id_SPINE12, id_SPINE13, id_SPINE14, id_SPINE15, id_SPINE16,
|
|
|
|
id_SPINE17, id_SPINE18, id_SPINE19, id_SPINE20, id_SPINE21, id_SPINE22, id_SPINE23, id_SPINE24,
|
|
|
|
id_SPINE25, id_SPINE26, id_SPINE27, id_SPINE28, id_SPINE29, id_SPINE30, id_SPINE31);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pips
|
|
|
|
inline bool is_global_pip(PipId pip) const
|
|
|
|
{
|
|
|
|
return is_global_wire(ctx->getPipSrcWire(pip)) || is_global_wire(ctx->getPipDstWire(pip));
|
|
|
|
}
|
gowin: Himbaechel. Add BSRAM for all chips.
The following primitives are implemented for the GW1N-1, GW2A-18,
GW2AR-18C, GW1NSR-4C, GW1NR-9C, GW1NR-9 and GW1N-4 chips:
* pROM - read only memory - (bitwidth: 1, 2, 4, 8, 16, 32).
* pROMX9 - read only memory - (bitwidth: 9, 18, 36).
* SDPB - semidual port - (bitwidth: 1, 2, 4, 8, 16, 32).
* SDPX9B - semidual port - (bitwidth: 9, 18, 36).
* DPB - dual port - (bitwidth: 16).
* DPX9B - dual port - (bitwidth: 18).
* SP - single port - (bitwidth: 1, 2, 4, 8, 16, 32).
* SPX9 - single port - (bitwidth: 9, 18, 36).
For GW1NSR-4C and GW1NR-9 chips, SP/SPX9 primitives with data widths
of 32/36 bits are implemented using a pair of 16-bit wide
primitives.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
2023-11-26 18:51:16 +08:00
|
|
|
|
|
|
|
// make cell but do not include it in the list of chip cells.
|
|
|
|
std::unique_ptr<CellInfo> create_cell(IdString name, IdString type);
|
2024-08-03 21:57:22 +08:00
|
|
|
|
|
|
|
// HCLK
|
|
|
|
BelId get_clkdiv_for_clkdiv2(BelId clkdiv2_bel) const;
|
|
|
|
BelId get_other_hclk_clkdiv2(BelId clkdiv2_bel) const;
|
|
|
|
BelId get_other_hclk_clkdiv(BelId clkdiv_bel) const;
|
|
|
|
BelId get_clkdiv2_for_clkdiv(BelId clkdiv_bel) const;
|
|
|
|
IdStringList get_hclk_id(BelId hclk_bel) const; // use the upper CLKDIV2 (CLKDIV2_0 orCLKDIV2_2) as an id
|
|
|
|
|
|
|
|
// Find Bels connected to a bound cell
|
|
|
|
void find_connected_bels(const CellInfo *cell, IdString port, IdString dest_type, IdString dest_pin, int iter_limit,
|
|
|
|
std::vector<BelId> &candidates);
|
|
|
|
|
|
|
|
// Find a maximum bipartite matching
|
|
|
|
template <typename T1, typename T2> std::map<T1, T2> find_maximum_bipartite_matching(std::map<T1, std::set<T2>> &G)
|
|
|
|
{
|
|
|
|
std::map<int, T1> U;
|
|
|
|
std::map<int, T2> V;
|
|
|
|
std::map<T2, int> V_IDX;
|
|
|
|
std::vector<std::vector<int>> int_graph(G.size());
|
|
|
|
|
|
|
|
int u_idx = 0;
|
|
|
|
int v_idx = 0;
|
|
|
|
|
|
|
|
// Translate the input graph to an integer graph
|
|
|
|
for (auto row : G) {
|
|
|
|
U.insert(std::pair(u_idx, row.first));
|
|
|
|
for (auto v : row.second) {
|
|
|
|
if (V_IDX.find(v) == V_IDX.end()) {
|
|
|
|
V_IDX[v] = v_idx;
|
|
|
|
V[v_idx] = v;
|
|
|
|
v_idx++;
|
|
|
|
}
|
|
|
|
int_graph[u_idx].push_back(V_IDX[v]);
|
|
|
|
}
|
|
|
|
u_idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> int_matching = kuhn_find_maximum_bipartite_matching(u_idx, v_idx, int_graph);
|
|
|
|
std::map<T1, T2> ret_matching;
|
|
|
|
|
|
|
|
int m_idx = 0;
|
|
|
|
for (auto val : int_matching) {
|
|
|
|
if (val >= 0) { // elements that are not matched have a value of -1
|
|
|
|
ret_matching[U[val]] = V[m_idx];
|
|
|
|
}
|
|
|
|
m_idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret_matching;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a maximum matching in a bipartite graph, g
|
|
|
|
std::vector<int> kuhn_find_maximum_bipartite_matching(int n, int k, std::vector<std::vector<int>> &g);
|
2023-07-20 10:09:14 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
NEXTPNR_NAMESPACE_END
|
|
|
|
|
|
|
|
#endif
|