gowin: Himbaechel. Allow to combine IOLOGIC.
Corrects the situation when it is impossible to use IOBUF with two IOLOGIC elements at the same time - input and output. Addresses https://github.com/YosysHQ/nextpnr/issues/1275 This is done by dividing one IOLOGIC Bel into two - input IOLOGIC and output IOLOGIC plus checking for compatibility of the cells located there. At the moment, this check is simple and allows only the combination of DDR and DDRC primitives. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
4981ebb698
commit
4e8436a1fc
@ -797,7 +797,8 @@ X(IDES8)
|
|||||||
X(IDES10)
|
X(IDES10)
|
||||||
X(IVIDEO)
|
X(IVIDEO)
|
||||||
X(IDES16)
|
X(IDES16)
|
||||||
X(IOLOGIC)
|
X(IOLOGICI)
|
||||||
|
X(IOLOGICO)
|
||||||
X(IOLOGICA)
|
X(IOLOGICA)
|
||||||
X(IOLOGICB)
|
X(IOLOGICB)
|
||||||
X(IOLOGIC_TYPE)
|
X(IOLOGIC_TYPE)
|
||||||
|
@ -200,7 +200,8 @@ void GowinImpl::postRoute()
|
|||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
auto ci = cell.second.get();
|
auto ci = cell.second.get();
|
||||||
if (ci->type == id_IOLOGIC || (is_iologic(ci) && !ci->type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC))) {
|
if (ci->type.in(id_IOLOGICI, id_IOLOGICO) ||
|
||||||
|
((is_iologici(ci) || is_iologico(ci)) && !ci->type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC))) {
|
||||||
if (visited_hclk_users.find(ci->name) == visited_hclk_users.end()) {
|
if (visited_hclk_users.find(ci->name) == visited_hclk_users.end()) {
|
||||||
// mark FCLK<-HCLK connections
|
// mark FCLK<-HCLK connections
|
||||||
const NetInfo *h_net = ci->getPort(id_FCLK);
|
const NetInfo *h_net = ci->getPort(id_FCLK);
|
||||||
@ -269,8 +270,11 @@ IdString GowinImpl::getBelBucketForCellType(IdString cell_type) const
|
|||||||
if (type_is_ssram(cell_type)) {
|
if (type_is_ssram(cell_type)) {
|
||||||
return id_RAM16SDP4;
|
return id_RAM16SDP4;
|
||||||
}
|
}
|
||||||
if (type_is_iologic(cell_type)) {
|
if (type_is_iologici(cell_type)) {
|
||||||
return id_IOLOGIC;
|
return id_IOLOGICI;
|
||||||
|
}
|
||||||
|
if (type_is_iologico(cell_type)) {
|
||||||
|
return id_IOLOGICO;
|
||||||
}
|
}
|
||||||
if (type_is_bsram(cell_type)) {
|
if (type_is_bsram(cell_type)) {
|
||||||
return id_BSRAM;
|
return id_BSRAM;
|
||||||
@ -299,8 +303,11 @@ bool GowinImpl::isValidBelForCellType(IdString cell_type, BelId bel) const
|
|||||||
if (bel_type == id_RAM16SDP4) {
|
if (bel_type == id_RAM16SDP4) {
|
||||||
return type_is_ssram(cell_type);
|
return type_is_ssram(cell_type);
|
||||||
}
|
}
|
||||||
if (bel_type == id_IOLOGIC) {
|
if (bel_type == id_IOLOGICI) {
|
||||||
return type_is_iologic(cell_type);
|
return type_is_iologici(cell_type);
|
||||||
|
}
|
||||||
|
if (bel_type == id_IOLOGICO) {
|
||||||
|
return type_is_iologico(cell_type);
|
||||||
}
|
}
|
||||||
if (bel_type == id_BSRAM) {
|
if (bel_type == id_BSRAM) {
|
||||||
return type_is_bsram(cell_type);
|
return type_is_bsram(cell_type);
|
||||||
|
@ -28,12 +28,19 @@ inline bool type_is_diffio(IdString cell_type)
|
|||||||
}
|
}
|
||||||
inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type); }
|
inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type); }
|
||||||
|
|
||||||
inline bool type_is_iologic(IdString cell_type)
|
// IOLOGIC input and output separately
|
||||||
|
|
||||||
|
inline bool type_is_iologico(IdString cell_type)
|
||||||
{
|
{
|
||||||
return cell_type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8, id_OSER10, id_OVIDEO, id_IDDR, id_IDDRC, id_IDES4,
|
return cell_type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8, id_OSER10, id_OVIDEO);
|
||||||
id_IDES8, id_IDES10, id_IVIDEO);
|
|
||||||
}
|
}
|
||||||
inline bool is_iologic(const CellInfo *cell) { return type_is_iologic(cell->type); }
|
inline bool is_iologico(const CellInfo *cell) { return type_is_iologico(cell->type); }
|
||||||
|
|
||||||
|
inline bool type_is_iologici(IdString cell_type)
|
||||||
|
{
|
||||||
|
return cell_type.in(id_IDDR, id_IDDRC, id_IDES4, id_IDES8, id_IDES10, id_IVIDEO);
|
||||||
|
}
|
||||||
|
inline bool is_iologici(const CellInfo *cell) { return type_is_iologici(cell->type); }
|
||||||
|
|
||||||
// Return true if a cell is a SSRAM
|
// Return true if a cell is a SSRAM
|
||||||
inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); }
|
inline bool type_is_ssram(IdString cell_type) { return cell_type.in(id_RAM16SDP1, id_RAM16SDP2, id_RAM16SDP4); }
|
||||||
@ -96,10 +103,10 @@ enum
|
|||||||
IOBB_Z = 51, // +IOBC...IOBL
|
IOBB_Z = 51, // +IOBC...IOBL
|
||||||
|
|
||||||
IOLOGICA_Z = 70,
|
IOLOGICA_Z = 70,
|
||||||
IDES16_Z = 72,
|
IDES16_Z = 74,
|
||||||
OSER16_Z = 73,
|
OSER16_Z = 75,
|
||||||
|
|
||||||
BUFG_Z = 74, // : 81 reserve just in case
|
BUFG_Z = 76, // : 81 reserve just in case
|
||||||
BSRAM_Z = 100,
|
BSRAM_Z = 100,
|
||||||
|
|
||||||
OSC_Z = 274,
|
OSC_Z = 274,
|
||||||
|
@ -32,10 +32,10 @@ IOBA_Z = 50
|
|||||||
IOBB_Z = 51
|
IOBB_Z = 51
|
||||||
|
|
||||||
IOLOGICA_Z = 70
|
IOLOGICA_Z = 70
|
||||||
IDES16_Z = 72
|
IDES16_Z = 74
|
||||||
OSER16_Z = 73
|
OSER16_Z = 75
|
||||||
|
|
||||||
BUFG_Z = 74 # : 81 reserve just in case
|
BUFG_Z = 76 # : 81 reserve just in case
|
||||||
BSRAM_Z = 100
|
BSRAM_Z = 100
|
||||||
|
|
||||||
OSC_Z = 274
|
OSC_Z = 274
|
||||||
@ -438,19 +438,20 @@ def create_io_tiletype(chip: Chip, db: chipdb, x: int, y: int, ttyp: int, tdesc:
|
|||||||
for idx, name in {(IOLOGICA_Z, 'IOLOGICA'), (IOLOGICA_Z + 1, 'IOLOGICB')}:
|
for idx, name in {(IOLOGICA_Z, 'IOLOGICA'), (IOLOGICA_Z + 1, 'IOLOGICB')}:
|
||||||
if name not in db.grid[y][x].bels:
|
if name not in db.grid[y][x].bels:
|
||||||
continue
|
continue
|
||||||
iol = tt.create_bel(name, "IOLOGIC", z = idx)
|
for off, io_type in {(0, 'O'), (2, 'I')}:
|
||||||
for port, wire in db.grid[y][x].bels[name].portmap.items():
|
iol = tt.create_bel(f"{name}{io_type}", f"IOLOGIC{io_type}", z = idx + off)
|
||||||
if port == 'FCLK': # XXX compatibility
|
for port, wire in db.grid[y][x].bels[name].portmap.items():
|
||||||
wire = f'FCLK{name[-1]}'
|
if port == 'FCLK': # XXX compatibility
|
||||||
if not tt.has_wire(wire):
|
wire = f'FCLK{name[-1]}'
|
||||||
if port in {'CLK', 'PCLK'}:
|
if not tt.has_wire(wire):
|
||||||
tt.create_wire(wire, "TILE_CLK")
|
if port in {'CLK', 'PCLK'}:
|
||||||
|
tt.create_wire(wire, "TILE_CLK")
|
||||||
|
else:
|
||||||
|
tt.create_wire(wire, "IOL_PORT")
|
||||||
|
if port in {'Q', 'Q0', 'Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6', 'Q7', 'Q8', 'Q9', 'DF', 'LAG', 'LEAD'}:
|
||||||
|
tt.add_bel_pin(iol, port, wire, PinType.OUTPUT)
|
||||||
else:
|
else:
|
||||||
tt.create_wire(wire, "IOL_PORT")
|
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
|
||||||
if port in {'Q', 'Q0', 'Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6', 'Q7', 'Q8', 'Q9', 'DF', 'LAG', 'LEAD'}:
|
|
||||||
tt.add_bel_pin(iol, port, wire, PinType.OUTPUT)
|
|
||||||
else:
|
|
||||||
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
|
|
||||||
tdesc.tiletype = tiletype
|
tdesc.tiletype = tiletype
|
||||||
return tt
|
return tt
|
||||||
|
|
||||||
|
@ -52,14 +52,15 @@ bool GowinUtils::is_simple_io_bel(BelId bel)
|
|||||||
|
|
||||||
Loc GowinUtils::get_pair_iologic_bel(Loc loc)
|
Loc GowinUtils::get_pair_iologic_bel(Loc loc)
|
||||||
{
|
{
|
||||||
loc.z = BelZ::IOLOGICA_Z + (1 - (loc.z - BelZ::IOLOGICA_Z));
|
int const z[] = {1, 0, 3, 2};
|
||||||
|
loc.z = BelZ::IOLOGICA_Z + z[(loc.z - BelZ::IOLOGICA_Z)];
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
BelId GowinUtils::get_io_bel_from_iologic(BelId bel)
|
BelId GowinUtils::get_io_bel_from_iologic(BelId bel)
|
||||||
{
|
{
|
||||||
Loc loc = ctx->getBelLocation(bel);
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
loc.z = BelZ::IOBA_Z + loc.z - BelZ::IOLOGICA_Z;
|
loc.z = BelZ::IOBA_Z + ((loc.z - BelZ::IOLOGICA_Z) & 1);
|
||||||
return ctx->getBelByLocation(loc);
|
return ctx->getBelByLocation(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,7 +347,7 @@ struct GowinPacker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BelId get_iologic_bel(CellInfo *iob)
|
BelId get_iologico_bel(CellInfo *iob)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(iob->bel != BelId());
|
NPNR_ASSERT(iob->bel != BelId());
|
||||||
Loc loc = ctx->getBelLocation(iob->bel);
|
Loc loc = ctx->getBelLocation(iob->bel);
|
||||||
@ -355,6 +355,14 @@ struct GowinPacker
|
|||||||
return ctx->getBelByLocation(loc);
|
return ctx->getBelByLocation(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BelId get_iologici_bel(CellInfo *iob)
|
||||||
|
{
|
||||||
|
NPNR_ASSERT(iob->bel != BelId());
|
||||||
|
Loc loc = ctx->getBelLocation(iob->bel);
|
||||||
|
loc.z = loc.z - BelZ::IOBA_Z + BelZ::IOLOGICA_Z + 2;
|
||||||
|
return ctx->getBelByLocation(loc);
|
||||||
|
}
|
||||||
|
|
||||||
void check_iologic_placement(CellInfo &ci, Loc iob_loc, int diff /* 1 - diff */)
|
void check_iologic_placement(CellInfo &ci, Loc iob_loc, int diff /* 1 - diff */)
|
||||||
{
|
{
|
||||||
if (ci.type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC, id_OSER4) || diff) {
|
if (ci.type.in(id_ODDR, id_ODDRC, id_IDDR, id_IDDRC, id_OSER4) || diff) {
|
||||||
@ -367,6 +375,26 @@ struct GowinPacker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// While we require an exact match of the type, in the future the criteria
|
||||||
|
// may be relaxed and there will be a comparison of the control networks
|
||||||
|
// used.
|
||||||
|
bool are_iologic_compatible(CellInfo *ci_0, CellInfo *ci_1)
|
||||||
|
{
|
||||||
|
switch (ci_0->type.hash()) {
|
||||||
|
case ID_ODDR:
|
||||||
|
return ci_1->type == id_IDDR;
|
||||||
|
case ID_ODDRC:
|
||||||
|
return ci_1->type == id_IDDRC;
|
||||||
|
case ID_IDDR:
|
||||||
|
return ci_1->type == id_ODDR;
|
||||||
|
case ID_IDDRC:
|
||||||
|
return ci_1->type == id_ODDRC;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void pack_bi_output_iol(CellInfo &ci, std::vector<IdString> &nets_to_remove)
|
void pack_bi_output_iol(CellInfo &ci, std::vector<IdString> &nets_to_remove)
|
||||||
{
|
{
|
||||||
// These primitives have an additional pin to control the tri-state iob - Q1.
|
// These primitives have an additional pin to control the tri-state iob - Q1.
|
||||||
@ -377,7 +405,16 @@ struct GowinPacker
|
|||||||
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
|
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
|
||||||
BelId iob_bel = out_iob->bel;
|
BelId iob_bel = out_iob->bel;
|
||||||
|
|
||||||
BelId l_bel = get_iologic_bel(out_iob);
|
BelId l_bel = get_iologico_bel(out_iob);
|
||||||
|
// check compatible Input and Output iologic if any
|
||||||
|
BelId in_l_bel = get_iologici_bel(out_iob);
|
||||||
|
if (in_l_bel != BelId() && !ctx->checkBelAvail(in_l_bel)) {
|
||||||
|
CellInfo *in_iologic_ci = ctx->getBoundBelCell(in_l_bel);
|
||||||
|
if (!are_iologic_compatible(&ci, in_iologic_ci)) {
|
||||||
|
log_error("IOLOGIC %s at %s cannot coexist with %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel),
|
||||||
|
ctx->nameOf(in_iologic_ci));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (l_bel == BelId()) {
|
if (l_bel == BelId()) {
|
||||||
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
||||||
}
|
}
|
||||||
@ -434,7 +471,7 @@ struct GowinPacker
|
|||||||
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
|
NPNR_ASSERT(out_iob != nullptr && out_iob->bel != BelId());
|
||||||
BelId iob_bel = out_iob->bel;
|
BelId iob_bel = out_iob->bel;
|
||||||
|
|
||||||
BelId l_bel = get_iologic_bel(out_iob);
|
BelId l_bel = get_iologico_bel(out_iob);
|
||||||
if (l_bel == BelId()) {
|
if (l_bel == BelId()) {
|
||||||
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
||||||
}
|
}
|
||||||
@ -554,7 +591,7 @@ struct GowinPacker
|
|||||||
NPNR_ASSERT(in_iob != nullptr && in_iob->bel != BelId());
|
NPNR_ASSERT(in_iob != nullptr && in_iob->bel != BelId());
|
||||||
BelId iob_bel = in_iob->bel;
|
BelId iob_bel = in_iob->bel;
|
||||||
|
|
||||||
BelId l_bel = get_iologic_bel(in_iob);
|
BelId l_bel = get_iologici_bel(in_iob);
|
||||||
if (l_bel == BelId()) {
|
if (l_bel == BelId()) {
|
||||||
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
log_error("Can't place IOLOGIC %s at %s\n", ctx->nameOf(&ci), ctx->nameOfBel(iob_bel));
|
||||||
}
|
}
|
||||||
@ -605,7 +642,7 @@ struct GowinPacker
|
|||||||
|
|
||||||
for (auto &cell : ctx->cells) {
|
for (auto &cell : ctx->cells) {
|
||||||
CellInfo &ci = *cell.second;
|
CellInfo &ci = *cell.second;
|
||||||
if (!is_iologic(&ci)) {
|
if (!(is_iologici(&ci) || is_iologico(&ci))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ctx->debug) {
|
if (ctx->debug) {
|
||||||
@ -704,7 +741,7 @@ struct GowinPacker
|
|||||||
aux->setParam(ctx->id("UPDATE"), Property("SAME"));
|
aux->setParam(ctx->id("UPDATE"), Property("SAME"));
|
||||||
|
|
||||||
// make cell in the next location
|
// make cell in the next location
|
||||||
ctx->createCell(main_name, id_IOLOGIC);
|
ctx->createCell(main_name, id_IOLOGICO);
|
||||||
aux = ctx->cells.at(main_name).get();
|
aux = ctx->cells.at(main_name).get();
|
||||||
|
|
||||||
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
||||||
@ -777,7 +814,7 @@ struct GowinPacker
|
|||||||
ci.copyPortTo(id_CALIB, aux, id_CALIB);
|
ci.copyPortTo(id_CALIB, aux, id_CALIB);
|
||||||
|
|
||||||
// make cell in the next location
|
// make cell in the next location
|
||||||
ctx->createCell(main_name, id_IOLOGIC);
|
ctx->createCell(main_name, id_IOLOGICI);
|
||||||
aux = ctx->cells.at(main_name).get();
|
aux = ctx->cells.at(main_name).get();
|
||||||
|
|
||||||
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
aux->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
||||||
|
Loading…
Reference in New Issue
Block a user