mirror of https://github.com/YosysHQ/nextpnr.git
Gowin. Implement ALU for the GW5A series. (#1541)
The ALUs in the GW5A series have undergone changes compared to previous
chips.
The most significant change is the appearance of an input MUX for
carry — it is now possible to switch between VCC, GND, and COUT of the
previous ALU, as well as generate carry in logic.
The granularity of resource allocation for ALUs has also changed — it is
now possible to use each half of a slice independently for ALUs.
Not all new features are reflected in this commit:
- since there is one CIN MUX for every six ALUs and it only works for
ALUs with index 0, the new granularity is not very useful: the head of
the chain can only be placed in the zero ALU. It is possible to gain one
LUT by allocating ALUs in odd numbers, but we will leave that for the
future.
- using CIN MUX to generate carry in logic is interesting, but we have
not yet been able to get the vendor IDE to generate such a
configuration to figure out which wires are used, so for now we are
leaving the old behavior in logic with the allocation of a specialized
head ALU.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
0a7cbe1cd7
commit
d966fc5dcb
|
|
@ -1368,4 +1368,5 @@ X(SEG_WIRES_TO_ISOLATE)
|
|||
// routing params
|
||||
X(NO_GP_CLOCK_ROUTING)
|
||||
|
||||
|
||||
// gw5a alu
|
||||
X(CIN_NETTYPE)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ NPNR_PACKED_STRUCT(struct Extra_chip_data_POD {
|
|||
static constexpr int32_t HAS_CLKDIV_HCLK = 64;
|
||||
static constexpr int32_t HAS_PINCFG = 128;
|
||||
static constexpr int32_t HAS_DFF67 = 256;
|
||||
static constexpr int32_t HAS_CIN_MUX = 512;
|
||||
});
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ CHIP_HAS_PLL_HCLK = 0x20
|
|||
CHIP_HAS_CLKDIV_HCLK = 0x40
|
||||
CHIP_HAS_PINCFG = 0x80
|
||||
CHIP_HAS_DFF67 = 0x100
|
||||
CHIP_HAS_CIN_MUX = 0x200
|
||||
|
||||
# Tile flags
|
||||
TILE_I3C_CAPABLE_IO = 0x1
|
||||
|
|
@ -1590,6 +1591,8 @@ def main():
|
|||
chip_flags |= CHIP_HAS_PINCFG;
|
||||
if "HAS_DFF67" in db.chip_flags:
|
||||
chip_flags |= CHIP_HAS_DFF67;
|
||||
if "HAS_CIN_MUX" in db.chip_flags:
|
||||
chip_flags |= CHIP_HAS_CIN_MUX;
|
||||
|
||||
X = db.cols;
|
||||
Y = db.rows;
|
||||
|
|
|
|||
|
|
@ -342,6 +342,12 @@ bool GowinUtils::has_DFF67(void) const
|
|||
return extra->chip_flags & Extra_chip_data_POD::HAS_DFF67;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_CIN_MUX(void) const
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
return extra->chip_flags & Extra_chip_data_POD::HAS_CIN_MUX;
|
||||
}
|
||||
|
||||
bool GowinUtils::has_SP32(void)
|
||||
{
|
||||
const Extra_chip_data_POD *extra = reinterpret_cast<const Extra_chip_data_POD *>(ctx->chip_info->extra_data.get());
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ struct GowinUtils
|
|||
// Logic cell structure
|
||||
bool has_DFF67(void) const;
|
||||
|
||||
// ALU
|
||||
bool has_CIN_MUX(void) const;
|
||||
|
||||
// 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; }
|
||||
|
|
|
|||
|
|
@ -1867,7 +1867,8 @@ struct GowinPacker
|
|||
// ALU
|
||||
// ===================================
|
||||
// create ALU CIN block
|
||||
std::unique_ptr<CellInfo> alu_add_cin_block(Context *ctx, CellInfo *head, NetInfo *cin_net)
|
||||
std::unique_ptr<CellInfo> alu_add_cin_block(Context *ctx, CellInfo *head, NetInfo *cin_net, bool cin_is_vcc,
|
||||
bool cin_is_gnd)
|
||||
{
|
||||
std::string name = head->name.str(ctx) + "_HEAD_ALULC";
|
||||
IdString name_id = ctx->id(name);
|
||||
|
|
@ -1880,13 +1881,13 @@ struct GowinPacker
|
|||
cin_ci->addOutput(id_COUT);
|
||||
cin_ci->connectPort(id_COUT, cout_net);
|
||||
|
||||
if (cin_net->name == ctx->id("$PACKER_GND")) {
|
||||
if (cin_is_gnd) {
|
||||
cin_ci->setParam(id_ALU_MODE, std::string("C2L"));
|
||||
cin_ci->addInput(id_I2);
|
||||
cin_ci->connectPort(id_I2, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
return cin_ci;
|
||||
}
|
||||
if (cin_net->name == ctx->id("$PACKER_VCC")) {
|
||||
if (cin_is_vcc) {
|
||||
cin_ci->setParam(id_ALU_MODE, std::string("ONE2C"));
|
||||
cin_ci->addInput(id_I2);
|
||||
cin_ci->connectPort(id_I2, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
|
|
@ -1902,6 +1903,7 @@ struct GowinPacker
|
|||
cin_ci->addInput(id_I2);
|
||||
cin_ci->connectPort(id_I2, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
|
||||
cin_ci->setParam(id_ALU_MODE, std::string("0")); // ADD
|
||||
cin_ci->setParam(id_CIN_NETTYPE, Property("LOGIC"));
|
||||
return cin_ci;
|
||||
}
|
||||
|
||||
|
|
@ -1962,29 +1964,52 @@ struct GowinPacker
|
|||
if (ctx->debug) {
|
||||
log_info("ALU head found %s. CIN net is %s\n", ctx->nameOf(ci), ctx->nameOf(cin_net));
|
||||
}
|
||||
// always prepend first ALU with carry generator block
|
||||
// three cases: CIN == 0, CIN == 1 and CIN == ?
|
||||
new_cells.push_back(alu_add_cin_block(ctx, ci, cin_net));
|
||||
CellInfo *cin_block_ci = new_cells.back().get();
|
||||
// CIN block is the cluster root and is always placed in ALU0
|
||||
// This is a possible place for further optimization
|
||||
|
||||
bool cin_is_vcc = cin_net->name == ctx->id("$PACKER_VCC");
|
||||
bool cin_is_gnd = cin_net->name == ctx->id("$PACKER_GND");
|
||||
bool cin_is_logic = !cin_is_vcc && !cin_is_gnd;
|
||||
CellInfo *cin_block_ci;
|
||||
int alu_chain_len;
|
||||
|
||||
// According to the documentation, GW5A can use CIN from
|
||||
// logic using the input MUX, but in practice this has not
|
||||
// yet been achieved. We are leaving the old mechanism in
|
||||
// place for this case.
|
||||
if ((!gwu.has_CIN_MUX()) || cin_is_logic) {
|
||||
// prepend first ALU with carry generator block
|
||||
// three cases: CIN == 0, CIN == 1 and CIN == ?
|
||||
new_cells.push_back(alu_add_cin_block(ctx, ci, cin_net, cin_is_vcc, cin_is_gnd));
|
||||
cin_block_ci = new_cells.back().get();
|
||||
// CIN block is the cluster root and is always placed in ALU0
|
||||
alu_chain_len = 1;
|
||||
} else {
|
||||
cin_block_ci = ci;
|
||||
ci->disconnectPort(id_CIN);
|
||||
if (cin_is_vcc) {
|
||||
ci->setParam(id_CIN_NETTYPE, Property("VCC"));
|
||||
} else {
|
||||
ci->setParam(id_CIN_NETTYPE, Property("GND"));
|
||||
}
|
||||
alu_chain_len = 0;
|
||||
}
|
||||
cin_block_ci->cluster = cin_block_ci->name;
|
||||
cin_block_ci->constr_z = BelZ::ALU0_Z;
|
||||
cin_block_ci->constr_abs_z = true;
|
||||
|
||||
int alu_chain_len = 1;
|
||||
while (true) {
|
||||
// add to cluster
|
||||
if (ctx->debug) {
|
||||
log_info("Add ALU to the chain (len:%d): %s\n", alu_chain_len, ctx->nameOf(ci));
|
||||
if (ci != cin_block_ci) {
|
||||
// add to cluster
|
||||
if (ctx->debug) {
|
||||
log_info("Add ALU to the chain (len:%d): %s\n", alu_chain_len, ctx->nameOf(ci));
|
||||
}
|
||||
cin_block_ci->constr_children.push_back(ci);
|
||||
NPNR_ASSERT(ci->cluster == ClusterId());
|
||||
ci->cluster = cin_block_ci->name;
|
||||
ci->constr_abs_z = false;
|
||||
ci->constr_x = alu_chain_len / 6;
|
||||
ci->constr_y = 0;
|
||||
ci->constr_z = alu_chain_len % 6;
|
||||
}
|
||||
cin_block_ci->constr_children.push_back(ci);
|
||||
NPNR_ASSERT(ci->cluster == ClusterId());
|
||||
ci->cluster = cin_block_ci->name;
|
||||
ci->constr_abs_z = false;
|
||||
ci->constr_x = alu_chain_len / 6;
|
||||
ci->constr_y = 0;
|
||||
ci->constr_z = alu_chain_len % 6;
|
||||
// XXX mode 0 - ADD
|
||||
if (ci->params.at(id_ALU_MODE).as_int64() == 0) {
|
||||
ci->renamePort(id_I3, id_I2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue