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(IVIDEO)
|
||||
X(IDES16)
|
||||
X(IOLOGIC)
|
||||
X(IOLOGICI)
|
||||
X(IOLOGICO)
|
||||
X(IOLOGICA)
|
||||
X(IOLOGICB)
|
||||
X(IOLOGIC_TYPE)
|
||||
|
@ -200,7 +200,8 @@ void GowinImpl::postRoute()
|
||||
|
||||
for (auto &cell : ctx->cells) {
|
||||
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()) {
|
||||
// mark FCLK<-HCLK connections
|
||||
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)) {
|
||||
return id_RAM16SDP4;
|
||||
}
|
||||
if (type_is_iologic(cell_type)) {
|
||||
return id_IOLOGIC;
|
||||
if (type_is_iologici(cell_type)) {
|
||||
return id_IOLOGICI;
|
||||
}
|
||||
if (type_is_iologico(cell_type)) {
|
||||
return id_IOLOGICO;
|
||||
}
|
||||
if (type_is_bsram(cell_type)) {
|
||||
return id_BSRAM;
|
||||
@ -299,8 +303,11 @@ bool GowinImpl::isValidBelForCellType(IdString cell_type, BelId bel) const
|
||||
if (bel_type == id_RAM16SDP4) {
|
||||
return type_is_ssram(cell_type);
|
||||
}
|
||||
if (bel_type == id_IOLOGIC) {
|
||||
return type_is_iologic(cell_type);
|
||||
if (bel_type == id_IOLOGICI) {
|
||||
return type_is_iologici(cell_type);
|
||||
}
|
||||
if (bel_type == id_IOLOGICO) {
|
||||
return type_is_iologico(cell_type);
|
||||
}
|
||||
if (bel_type == id_BSRAM) {
|
||||
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 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,
|
||||
id_IDES8, id_IDES10, id_IVIDEO);
|
||||
return cell_type.in(id_ODDR, id_ODDRC, id_OSER4, id_OSER8, id_OSER10, id_OVIDEO);
|
||||
}
|
||||
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
|
||||
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
|
||||
|
||||
IOLOGICA_Z = 70,
|
||||
IDES16_Z = 72,
|
||||
OSER16_Z = 73,
|
||||
IDES16_Z = 74,
|
||||
OSER16_Z = 75,
|
||||
|
||||
BUFG_Z = 74, // : 81 reserve just in case
|
||||
BUFG_Z = 76, // : 81 reserve just in case
|
||||
BSRAM_Z = 100,
|
||||
|
||||
OSC_Z = 274,
|
||||
|
@ -32,10 +32,10 @@ IOBA_Z = 50
|
||||
IOBB_Z = 51
|
||||
|
||||
IOLOGICA_Z = 70
|
||||
IDES16_Z = 72
|
||||
OSER16_Z = 73
|
||||
IDES16_Z = 74
|
||||
OSER16_Z = 75
|
||||
|
||||
BUFG_Z = 74 # : 81 reserve just in case
|
||||
BUFG_Z = 76 # : 81 reserve just in case
|
||||
BSRAM_Z = 100
|
||||
|
||||
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')}:
|
||||
if name not in db.grid[y][x].bels:
|
||||
continue
|
||||
iol = tt.create_bel(name, "IOLOGIC", z = idx)
|
||||
for port, wire in db.grid[y][x].bels[name].portmap.items():
|
||||
if port == 'FCLK': # XXX compatibility
|
||||
wire = f'FCLK{name[-1]}'
|
||||
if not tt.has_wire(wire):
|
||||
if port in {'CLK', 'PCLK'}:
|
||||
tt.create_wire(wire, "TILE_CLK")
|
||||
for off, io_type in {(0, 'O'), (2, 'I')}:
|
||||
iol = tt.create_bel(f"{name}{io_type}", f"IOLOGIC{io_type}", z = idx + off)
|
||||
for port, wire in db.grid[y][x].bels[name].portmap.items():
|
||||
if port == 'FCLK': # XXX compatibility
|
||||
wire = f'FCLK{name[-1]}'
|
||||
if not tt.has_wire(wire):
|
||||
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:
|
||||
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:
|
||||
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
|
||||
tt.add_bel_pin(iol, port, wire, PinType.INPUT)
|
||||
tdesc.tiletype = tiletype
|
||||
return tt
|
||||
|
||||
|
@ -52,14 +52,15 @@ bool GowinUtils::is_simple_io_bel(BelId bel)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
BelId GowinUtils::get_io_bel_from_iologic(BelId 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);
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ struct GowinPacker
|
||||
}
|
||||
}
|
||||
|
||||
BelId get_iologic_bel(CellInfo *iob)
|
||||
BelId get_iologico_bel(CellInfo *iob)
|
||||
{
|
||||
NPNR_ASSERT(iob->bel != BelId());
|
||||
Loc loc = ctx->getBelLocation(iob->bel);
|
||||
@ -355,6 +355,14 @@ struct GowinPacker
|
||||
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 */)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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());
|
||||
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()) {
|
||||
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());
|
||||
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()) {
|
||||
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());
|
||||
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()) {
|
||||
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) {
|
||||
CellInfo &ci = *cell.second;
|
||||
if (!is_iologic(&ci)) {
|
||||
if (!(is_iologici(&ci) || is_iologico(&ci))) {
|
||||
continue;
|
||||
}
|
||||
if (ctx->debug) {
|
||||
@ -704,7 +741,7 @@ struct GowinPacker
|
||||
aux->setParam(ctx->id("UPDATE"), Property("SAME"));
|
||||
|
||||
// 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->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
||||
@ -777,7 +814,7 @@ struct GowinPacker
|
||||
ci.copyPortTo(id_CALIB, aux, id_CALIB);
|
||||
|
||||
// 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->setAttr(ctx->id("MAIN_CELL"), Property(main_name.str(ctx)));
|
||||
|
Loading…
Reference in New Issue
Block a user