gatemate: add IOSEL as separate primitive (#1533)

This commit is contained in:
Miodrag Milanović 2025-08-14 12:20:24 +02:00 committed by GitHub
parent b0626280e9
commit 95ab16f380
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 71 additions and 14 deletions

View File

@ -289,6 +289,8 @@ struct BitstreamBackend
case id_CPE_LVDS_TOBUF.index:
case id_CPE_LVDS_OBUF.index:
case id_CPE_LVDS_IOBUF.index:
break;
case id_IOSEL.index:
for (auto &p : params) {
bank[loc.die][ctx->get_bel_package_pin(cell.second.get()->bel)->pad_bank] = 1;
cc.tiles[loc].add_word(stringf("GPIO.%s", p.first.c_str(ctx)), p.second.as_bits());

View File

@ -106,6 +106,22 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name)
add_port(id_POUTY1, PORT_OUT);
add_port(id_COUTY2, PORT_OUT);
add_port(id_POUTY2, PORT_OUT);
} else if (type.in(id_IOSEL)) {
add_port(id_GPIO_OUT, PORT_OUT);
add_port(id_GPIO_EN, PORT_OUT);
add_port(id_GPIO_IN, PORT_IN);
add_port(id_IN1, PORT_OUT);
add_port(id_IN2, PORT_OUT);
add_port(id_OUT1, PORT_IN);
add_port(id_OUT2, PORT_IN);
add_port(id_OUT3, PORT_IN);
add_port(id_OUT4, PORT_IN);
add_port(id_DDR, PORT_IN);
add_port(id_CLOCK1, PORT_IN);
add_port(id_CLOCK2, PORT_IN);
add_port(id_CLOCK3, PORT_IN);
add_port(id_CLOCK4, PORT_IN);
} else {
log_error("Trying to create unknown cell type %s\n", type.c_str(ctx));
}

View File

@ -1030,9 +1030,12 @@ X(CPE_CPLINES)
//X(COUTY2)
//X(POUTY2)
// hardware primitive GPIO
X(GPIO)
// GPIO pins
// hardware primitive IOSEL
X(IOSEL)
// IOSEL pins
X(GPIO_OUT)
X(GPIO_EN)
X(GPIO_IN)
//X(IN1)
//X(IN2)
//X(OUT1)
@ -1044,6 +1047,13 @@ X(CLOCK1)
X(CLOCK2)
X(CLOCK3)
X(CLOCK4)
// hardware primitive GPIO
X(GPIO)
// GPIO pins
//X(Y)
//X(T)
//X(A)
//X(I)
//X(O)
//X(IO)

View File

@ -228,7 +228,7 @@ def set_timings(ch):
lut.add_comb_arc("I", "RAM_O", TimingValue(0, 0))
lut.add_comb_arc("RAM_I", "OUT", TimingValue(0, 0))
EXPECTED_VERSION = 1.3
EXPECTED_VERSION = 1.4
def main():
# Range needs to be +1, but we are adding +2 more to coordinates, since

View File

@ -130,13 +130,15 @@ void GateMatePacker::pack_bufg()
int die = uarch->preferred_die;
if (in_net) {
if (in_net->driver.cell) {
if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_GPIO) {
if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_IOSEL) {
auto pad_info = uarch->bel_to_pad[in_net->driver.cell->bel];
if (pad_info->flags) {
int index = pad_info->flags - 1;
die = uarch->tile_extra_data(in_net->driver.cell->bel.tile)->die;
if (!clkin[die]->getPort(ctx->idf("CLK%d", index)))
clkin[die]->connectPort(ctx->idf("CLK%d", index), in_net->driver.cell->getPort(id_I));
if (!clkin[die]->getPort(ctx->idf("CLK%d", index))) {
CellInfo *gpio = in_net->driver.cell->getPort(id_GPIO_IN)->driver.cell;
clkin[die]->connectPort(ctx->idf("CLK%d", index), gpio->getPort(id_I));
}
}
}
} else {
@ -167,7 +169,7 @@ void GateMatePacker::pack_bufg()
int die = uarch->preferred_die;
if (in_net->driver.cell) {
bool user_glb = true;
if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_GPIO) {
if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_IOSEL) {
auto pad_info = uarch->bel_to_pad[in_net->driver.cell->bel];
if (pad_info->flags) {
die = uarch->tile_extra_data(in_net->driver.cell->bel.tile)->die;
@ -355,7 +357,7 @@ void GateMatePacker::pack_pll()
if (ctx->getBelBucketForCellType(clk->driver.cell->type) == id_CC_BUFG) {
clk = clk->driver.cell->getPort(id_I);
}
if (ctx->getBelBucketForCellType(clk->driver.cell->type) == id_GPIO) {
if (ctx->getBelBucketForCellType(clk->driver.cell->type) == id_IOSEL) {
auto pad_info = uarch->bel_to_pad[clk->driver.cell->bel];
if (pad_info->flags != 0) {
die = uarch->tile_extra_data(clk->driver.cell->bel.tile)->die;
@ -390,7 +392,7 @@ void GateMatePacker::pack_pll()
ci.connectPort(id_CLK_REF, in);
clk = in;
}
if (ctx->getBelBucketForCellType(clk->driver.cell->type) != id_GPIO)
if (ctx->getBelBucketForCellType(clk->driver.cell->type) != id_IOSEL)
log_error("CLK_REF must be driven with GPIO pin.\n");
auto pad_info = uarch->bel_to_pad[clk->driver.cell->bel];
if (pad_info->flags == 0)

View File

@ -318,7 +318,32 @@ void GateMatePacker::pack_io()
log_error("Can't place %s at %s because it's already taken by %s\n", ctx->nameOf(&ci), ctx->nameOfBel(bel),
ctx->nameOf(ctx->getBoundBelCell(bel)));
}
// Place IOSEL
CellInfo *iosel = create_cell_ptr(id_IOSEL, ctx->idf("%s$iosel", ci.name.c_str(ctx)));
iosel->params = ci.params;
ctx->bindBel(bel, iosel, PlaceStrength::STRENGTH_FIXED);
// Rewire
ci.movePortTo(id_A, iosel, id_A);
ci.movePortTo(id_T, iosel, id_T);
ci.movePortTo(id_Y, iosel, id_Y);
// Place GPIO
Loc l = ctx->getBelLocation(bel);
bel = ctx->getBelByLocation({l.x, l.y, 0});
ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_FIXED);
// Remove not needed params
ci.params.clear();
// Add connections between GPIO and IOSEL
if (iosel->getPort(id_A))
ci.connectPorts(id_A, iosel, id_GPIO_OUT);
if (iosel->getPort(id_Y))
ci.connectPorts(id_Y, iosel, id_GPIO_IN);
if (iosel->getPort(id_T))
ci.connectPorts(id_T, iosel, id_GPIO_EN);
}
flush_cells();
}
@ -329,7 +354,7 @@ void GateMatePacker::pack_io_sel()
std::vector<CellInfo *> cells;
for (auto &cell : ctx->cells) {
CellInfo &ci = *cell.second;
if (!uarch->getBelBucketForCellType(ci.type).in(id_GPIO))
if (!uarch->getBelBucketForCellType(ci.type).in(id_IOSEL))
continue;
cells.push_back(&ci);
@ -457,7 +482,8 @@ void GateMatePacker::pack_io_sel()
} else {
ci.params[id_OUT_SIGNAL] = Property(Property::State::S1);
bool ff_obf_merged = false;
if (ff_obf && do_net->driver.cell->type == id_CC_DFF && do_net->users.entries() == 1) {
if (ff_obf && do_net->driver.cell && do_net->driver.cell->type == id_CC_DFF &&
do_net->users.entries() == 1) {
CellInfo *dff = do_net->driver.cell;
if (is_gpio_valid_dff(dff)) {
ci.params[id_OUT1_FF] = Property(Property::State::S1);
@ -477,7 +503,7 @@ void GateMatePacker::pack_io_sel()
}
}
bool oddr_merged = false;
if (do_net->driver.cell->type == id_CC_ODDR && do_net->users.entries() == 1) {
if (do_net->driver.cell && do_net->driver.cell->type == id_CC_ODDR && do_net->users.entries() == 1) {
CellInfo *oddr = do_net->driver.cell;
ci.params[id_OUT1_FF] = Property(Property::State::S1);
ci.params[id_OUT2_FF] = Property(Property::State::S1);
@ -521,7 +547,8 @@ void GateMatePacker::pack_io_sel()
ff_ibf_merged = merge_ibf(di_net, ci, use_custom_clock);
}
bool iddr_merged = false;
if (di_net->users.entries() == 1 && (*di_net->users.begin()).cell->type == id_CC_IDDR) {
if (di_net->users.entries() == 1 && (*di_net->users.begin()).cell->type == id_CC_IDDR &&
(*di_net->users.begin()).port == id_D) {
iddr_merged = merge_iddr(di_net, ci, use_custom_clock);
}