diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 388216a1..f8560834 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -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()); diff --git a/himbaechel/uarch/gatemate/cells.cc b/himbaechel/uarch/gatemate/cells.cc index 67288382..4f2cac56 100644 --- a/himbaechel/uarch/gatemate/cells.cc +++ b/himbaechel/uarch/gatemate/cells.cc @@ -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)); } diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index 11140382..960965fa 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -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) diff --git a/himbaechel/uarch/gatemate/gen/arch_gen.py b/himbaechel/uarch/gatemate/gen/arch_gen.py index 5949610e..6c70cf03 100644 --- a/himbaechel/uarch/gatemate/gen/arch_gen.py +++ b/himbaechel/uarch/gatemate/gen/arch_gen.py @@ -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 diff --git a/himbaechel/uarch/gatemate/pack_clocking.cc b/himbaechel/uarch/gatemate/pack_clocking.cc index a4814428..1a39c261 100644 --- a/himbaechel/uarch/gatemate/pack_clocking.cc +++ b/himbaechel/uarch/gatemate/pack_clocking.cc @@ -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) diff --git a/himbaechel/uarch/gatemate/pack_io.cc b/himbaechel/uarch/gatemate/pack_io.cc index 3a5ac1f9..111b7e3e 100644 --- a/himbaechel/uarch/gatemate/pack_io.cc +++ b/himbaechel/uarch/gatemate/pack_io.cc @@ -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 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); }