diff --git a/cyclonev/arch.cc b/cyclonev/arch.cc index 98a09d3b..62acf9e2 100644 --- a/cyclonev/arch.cc +++ b/cyclonev/arch.cc @@ -210,6 +210,23 @@ std::vector Arch::getBelPins(BelId bel) const return pins; } +bool Arch::isValidBelForCellType(IdString cell_type, BelId bel) const { + // Any combinational cell type can - theoretically - be placed at a combinational ALM bel + // The precise legality mechanics will be dealt with in isBelLocationValid. + IdString bel_type = getBelType(bel); + if (bel_type == id_MISTRAL_COMB) + return is_comb_cell(cell_type); + else + return bel_type == cell_type; +} + +BelBucketId Arch::getBelBucketForCellType(IdString cell_type) const { + if (is_comb_cell(cell_type)) + return id_MISTRAL_COMB; + else + return cell_type; +} + bool Arch::pack() { return true; } bool Arch::place() { return true; } bool Arch::route() { return true; } diff --git a/cyclonev/arch.h b/cyclonev/arch.h index 53fa4174..34d90a04 100644 --- a/cyclonev/arch.h +++ b/cyclonev/arch.h @@ -44,6 +44,8 @@ struct ALMInfo std::array lut_bels; std::array ff_bels; // TODO: ALM configuration (L5/L6 mode, LUT input permutation, etc) + // So we only validity-check changed parts + bool valid = false, dirty = false; }; struct LABInfo @@ -54,6 +56,9 @@ struct LABInfo std::array aclr_wires; WireId sclr_wire, sload_wire; // TODO: LAB configuration (control set etc) + + // These apply to the validity-checking status of the shared FF control sets + bool ctrl_valid = false, ctrl_dirty = false; }; struct PinInfo @@ -313,6 +318,11 @@ struct Arch : BaseArch // ------------------------------------------------- + bool isValidBelForCellType(IdString cell_type, BelId bel) const override; + BelBucketId getBelBucketForCellType(IdString cell_type) const override; + + // ------------------------------------------------- + bool pack() override; bool place() override; bool route() override; @@ -331,14 +341,17 @@ struct Arch : BaseArch return WireId(cyclonev->pnode_to_rnode(CycloneV::pnode(bt, x, y, port, bi, pi))); } - void create_lab(int x, int y); + void create_lab(int x, int y); // lab.cc void create_gpio(int x, int y); // ------------------------------------------------- - bool is_comb_cell(IdString cell_type) const; - bool is_alm_legal(uint32_t lab, uint8_t alm) const; - bool is_lab_ctrlset_legal(uint32_t lab) const; + bool is_comb_cell(IdString cell_type) const; // lab.cc + bool is_alm_legal(uint32_t lab, uint8_t alm) const; // lab.cc + bool is_lab_ctrlset_legal(uint32_t lab) const; // lab.cc + + void assign_comb_info(CellInfo *cell) const; // lab.cc + void assign_ff_info(CellInfo *cell) const; // lab.cc // ------------------------------------------------- diff --git a/cyclonev/archdefs.h b/cyclonev/archdefs.h index d6555887..5afdd783 100644 --- a/cyclonev/archdefs.h +++ b/cyclonev/archdefs.h @@ -134,6 +134,28 @@ struct ArchPinInfo struct NetInfo; +// Structures for representing how FF control sets are stored and validity-checked +struct ControlSig +{ + const NetInfo *net; + bool inverted; + + bool connected() const { return net != nullptr; } + bool operator==(const ControlSig &other) const { return net == other.net && inverted == other.inverted; } + bool operator!=(const ControlSig &other) const { return net == other.net && inverted == other.inverted; } +}; + +struct FFControlSet +{ + ControlSig clk, ena, aclr, sclr, sload; + + bool operator==(const FFControlSet &other) const + { + return clk == other.clk && ena == other.ena && aclr == other.aclr && sclr == other.sclr && sload == other.sload; + } + bool operator!=(const FFControlSet &other) const { return !(*this == other); } +}; + struct ArchCellInfo { union @@ -141,7 +163,7 @@ struct ArchCellInfo struct { // Store the nets here for fast validity checking (avoids too many map lookups in a hot path) - std::array input_sigs; + std::array lut_in; const NetInfo *comb_out; int lut_input_count; @@ -151,8 +173,8 @@ struct ArchCellInfo } combInfo; struct { - const NetInfo *clk, *ena, *aclr, *sclr, *sload, *sdata, *datain; - bool clk_inv, ena_inv, aclr_inv, sclr_inv, sload_inv; + FFControlSet ctrlset; + const NetInfo *sdata, *datain; } ffInfo; }; diff --git a/cyclonev/constids.inc b/cyclonev/constids.inc index a22bda47..90d5e753 100644 --- a/cyclonev/constids.inc +++ b/cyclonev/constids.inc @@ -47,6 +47,7 @@ X(MISTRAL_ALUT4) X(MISTRAL_ALUT3) X(MISTRAL_ALUT2) X(MISTRAL_NOT) +X(MISTRAL_CONST) X(MISTRAL_ALUT_ARITH) X(D0) diff --git a/cyclonev/lab.cc b/cyclonev/lab.cc index a4619a8c..2c2c619a 100644 --- a/cyclonev/lab.cc +++ b/cyclonev/lab.cc @@ -19,11 +19,14 @@ #include "log.h" #include "nextpnr.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN // This file contains functions related to our custom LAB structure, including creating the LAB bels; checking the // legality of LABs; and manipulating LUT inputs and equations + +// LAB/ALM structure creation functions namespace { static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx) { @@ -185,4 +188,100 @@ void Arch::create_lab(int x, int y) } } +// Cell handling and annotation functions +namespace { + ControlSig get_ctrlsig(const CellInfo *cell, IdString port) { + ControlSig result; + result.net = get_net_or_empty(cell, port); + if (cell->pin_data.count(port)) + result.inverted = cell->pin_data.at(port).inverted; + else + result.inverted = false; + return result; + } +} + +bool Arch::is_comb_cell(IdString cell_type) const +{ + // Return true if a cell is a combinational cell type, to be a placed at a MISTRAL_COMB location + switch (cell_type.index) { + case ID_MISTRAL_ALUT6: + case ID_MISTRAL_ALUT5: + case ID_MISTRAL_ALUT4: + case ID_MISTRAL_ALUT3: + case ID_MISTRAL_ALUT2: + case ID_MISTRAL_NOT: + case ID_MISTRAL_CONST: + case ID_MISTRAL_ALUT_ARITH: + return true; + default: + return false; + } +} + +void Arch::assign_comb_info(CellInfo *cell) const +{ + cell->combInfo.is_carry = false; + cell->combInfo.is_shared = false; + cell->combInfo.is_extended = false; + + if (cell->type == id_MISTRAL_ALUT_ARITH) { + cell->combInfo.is_carry = true; + cell->combInfo.lut_input_count = 5; + cell->combInfo.lut_bits_count = 32; + // This is a special case in terms of naming + int i = 0; + for (auto pin : {id_A, id_B, id_C, id_D0, id_D1}) { + cell->combInfo.lut_in[i++] = get_net_or_empty(cell, pin); + } + cell->combInfo.comb_out = get_net_or_empty(cell, id_SO); + } else { + cell->combInfo.lut_input_count = 0; + switch (cell->type.index) { + case ID_MISTRAL_ALUT6: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[5] = get_net_or_empty(cell, id_F); + [[fallthrough]]; + case ID_MISTRAL_ALUT5: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[4] = get_net_or_empty(cell, id_E); + [[fallthrough]]; + case ID_MISTRAL_ALUT4: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[3] = get_net_or_empty(cell, id_D); + [[fallthrough]]; + case ID_MISTRAL_ALUT3: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[2] = get_net_or_empty(cell, id_C); + [[fallthrough]]; + case ID_MISTRAL_ALUT2: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[1] = get_net_or_empty(cell, id_B); + [[fallthrough]]; + case ID_MISTRAL_NOT: + ++cell->combInfo.lut_input_count; + cell->combInfo.lut_in[0] = get_net_or_empty(cell, id_A); + [[fallthrough]]; + case ID_MISTRAL_CONST: + // MISTRAL_CONST is a nextpnr-inserted cell type for 0-input, constant-generating LUTs + break; + default: + log_error("unexpected combinational cell type %s\n", getCtx()->nameOf(cell->type)); + } + // Note that this relationship won't hold for extended mode, when that is supported + cell->combInfo.lut_bits_count = (1 << cell->combInfo.lut_input_count); + } +} + +void Arch::assign_ff_info(CellInfo *cell) const +{ + cell->ffInfo.ctrlset.clk = get_ctrlsig(cell, id_CLK); + cell->ffInfo.ctrlset.ena = get_ctrlsig(cell, id_ENA); + cell->ffInfo.ctrlset.aclr = get_ctrlsig(cell, id_ACLR); + cell->ffInfo.ctrlset.sclr = get_ctrlsig(cell, id_SCLR); + cell->ffInfo.ctrlset.sload = get_ctrlsig(cell, id_SLOAD); + cell->ffInfo.sdata = get_net_or_empty(cell, id_SDATA); + cell->ffInfo.datain = get_net_or_empty(cell, id_DATAIN); +} + NEXTPNR_NAMESPACE_END \ No newline at end of file