cyclonev: More preparations for validity checking
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
9bd7ef5f5f
commit
1cd22b81da
@ -210,6 +210,23 @@ std::vector<IdString> Arch::getBelPins(BelId bel) const
|
|||||||
return pins;
|
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::pack() { return true; }
|
||||||
bool Arch::place() { return true; }
|
bool Arch::place() { return true; }
|
||||||
bool Arch::route() { return true; }
|
bool Arch::route() { return true; }
|
||||||
|
@ -44,6 +44,8 @@ struct ALMInfo
|
|||||||
std::array<BelId, 2> lut_bels;
|
std::array<BelId, 2> lut_bels;
|
||||||
std::array<BelId, 4> ff_bels;
|
std::array<BelId, 4> ff_bels;
|
||||||
// TODO: ALM configuration (L5/L6 mode, LUT input permutation, etc)
|
// TODO: ALM configuration (L5/L6 mode, LUT input permutation, etc)
|
||||||
|
// So we only validity-check changed parts
|
||||||
|
bool valid = false, dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LABInfo
|
struct LABInfo
|
||||||
@ -54,6 +56,9 @@ struct LABInfo
|
|||||||
std::array<WireId, 2> aclr_wires;
|
std::array<WireId, 2> aclr_wires;
|
||||||
WireId sclr_wire, sload_wire;
|
WireId sclr_wire, sload_wire;
|
||||||
// TODO: LAB configuration (control set etc)
|
// 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
|
struct PinInfo
|
||||||
@ -313,6 +318,11 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
bool isValidBelForCellType(IdString cell_type, BelId bel) const override;
|
||||||
|
BelBucketId getBelBucketForCellType(IdString cell_type) const override;
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
|
||||||
bool pack() override;
|
bool pack() override;
|
||||||
bool place() override;
|
bool place() override;
|
||||||
bool route() override;
|
bool route() override;
|
||||||
@ -331,14 +341,17 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
return WireId(cyclonev->pnode_to_rnode(CycloneV::pnode(bt, x, y, port, bi, pi)));
|
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);
|
void create_gpio(int x, int y);
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
bool is_comb_cell(IdString cell_type) const;
|
bool is_comb_cell(IdString cell_type) const; // lab.cc
|
||||||
bool is_alm_legal(uint32_t lab, uint8_t alm) const;
|
bool is_alm_legal(uint32_t lab, uint8_t alm) const; // lab.cc
|
||||||
bool is_lab_ctrlset_legal(uint32_t lab) const;
|
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
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
@ -134,6 +134,28 @@ struct ArchPinInfo
|
|||||||
|
|
||||||
struct NetInfo;
|
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
|
struct ArchCellInfo
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
@ -141,7 +163,7 @@ struct ArchCellInfo
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
// Store the nets here for fast validity checking (avoids too many map lookups in a hot path)
|
// Store the nets here for fast validity checking (avoids too many map lookups in a hot path)
|
||||||
std::array<const NetInfo *, 7> input_sigs;
|
std::array<const NetInfo *, 7> lut_in;
|
||||||
const NetInfo *comb_out;
|
const NetInfo *comb_out;
|
||||||
|
|
||||||
int lut_input_count;
|
int lut_input_count;
|
||||||
@ -151,8 +173,8 @@ struct ArchCellInfo
|
|||||||
} combInfo;
|
} combInfo;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
const NetInfo *clk, *ena, *aclr, *sclr, *sload, *sdata, *datain;
|
FFControlSet ctrlset;
|
||||||
bool clk_inv, ena_inv, aclr_inv, sclr_inv, sload_inv;
|
const NetInfo *sdata, *datain;
|
||||||
} ffInfo;
|
} ffInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ X(MISTRAL_ALUT4)
|
|||||||
X(MISTRAL_ALUT3)
|
X(MISTRAL_ALUT3)
|
||||||
X(MISTRAL_ALUT2)
|
X(MISTRAL_ALUT2)
|
||||||
X(MISTRAL_NOT)
|
X(MISTRAL_NOT)
|
||||||
|
X(MISTRAL_CONST)
|
||||||
X(MISTRAL_ALUT_ARITH)
|
X(MISTRAL_ALUT_ARITH)
|
||||||
|
|
||||||
X(D0)
|
X(D0)
|
||||||
|
@ -19,11 +19,14 @@
|
|||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// This file contains functions related to our custom LAB structure, including creating the LAB bels; checking the
|
// 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
|
// legality of LABs; and manipulating LUT inputs and equations
|
||||||
|
|
||||||
|
// LAB/ALM structure creation functions
|
||||||
namespace {
|
namespace {
|
||||||
static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx)
|
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
|
NEXTPNR_NAMESPACE_END
|
Loading…
Reference in New Issue
Block a user