diff --git a/himbaechel/uarch/gatemate/CMakeLists.txt b/himbaechel/uarch/gatemate/CMakeLists.txt index 6977ce9b..6040d498 100644 --- a/himbaechel/uarch/gatemate/CMakeLists.txt +++ b/himbaechel/uarch/gatemate/CMakeLists.txt @@ -38,17 +38,17 @@ if (NOT HIMBAECHEL_PEPPERCORN_PATH AND NOT IMPORT_BBA_FILES) message(FATAL_ERROR "HIMBAECHEL_PEPPERCORN_PATH must be set to a Project Peppercorn checkout") endif() -#set(ALL_HIMBAECHE_GATEMATE_DEVICES CCGM1A1 CCGM1A2 CCGM1A4 CCGM1A9 CCGM1A16 CCGM1A25) -set(ALL_HIMBAECHE_GATEMATE_DEVICES CCGM1A1) -set(HIMBAECHEL_GATEMATE_DEVICES ${ALL_HIMBAECHE_GATEMATE_DEVICES} CACHE STRING - "Include support for these GateMate devices (available: ${ALL_HIMBAECHE_GATEMATE_DEVICES})") +#set(ALL_HIMBAECHEL_GATEMATE_DEVICES CCGM1A1 CCGM1A2 CCGM1A4 CCGM1A9 CCGM1A16 CCGM1A25) +set(ALL_HIMBAECHEL_GATEMATE_DEVICES CCGM1A1 CCGM1A2) +set(HIMBAECHEL_GATEMATE_DEVICES ${ALL_HIMBAECHEL_GATEMATE_DEVICES} CACHE STRING + "Include support for these GateMate devices (available: ${ALL_HIMBAECHEL_GATEMATE_DEVICES})") if (HIMBAECHEL_GATEMATE_DEVICES STREQUAL "all") - set(HIMBAECHEL_GATEMATE_DEVICES ${ALL_HIMBAECHE_GATEMATE_DEVICES}) + set(HIMBAECHEL_GATEMATE_DEVICES ${ALL_HIMBAECHEL_GATEMATE_DEVICES}) endif() message(STATUS "Enabled Himbaechel-GateMate devices: ${HIMBAECHEL_GATEMATE_DEVICES}") foreach (device ${HIMBAECHEL_GATEMATE_DEVICES}) - if (NOT device IN_LIST ALL_HIMBAECHE_GATEMATE_DEVICES) + if (NOT device IN_LIST ALL_HIMBAECHEL_GATEMATE_DEVICES) message(FATAL_ERROR "Device ${device} is not a supported GateMate device") endif() diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 3f00f2c8..d258ae90 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -46,6 +46,77 @@ struct BitstreamBackend return reinterpret_cast(ctx->chip_info->tile_insts[tile].extra_data.get()); } + bool need_inversion(CellInfo *cell, IdString port) + { + PortRef sink; + sink.cell = cell; + sink.port = port; + + NetInfo *net_info = cell->getPort(port); + if (!net_info) + return false; + + WireId src_wire = ctx->getNetinfoSourceWire(net_info); + WireId dst_wire = ctx->getNetinfoSinkWire(net_info, sink, 0); + + if (src_wire == WireId()) + return false; + + WireId cursor = dst_wire; + bool invert = false; + while (cursor != WireId() && cursor != src_wire) { + auto it = net_info->wires.find(cursor); + + if (it == net_info->wires.end()) + break; + + PipId pip = it->second.pip; + if (pip == PipId()) + break; + + invert ^= ctx->isPipInverting(pip); + cursor = ctx->getPipSrcWire(pip); + } + + return invert; + } + + void update_cpe_lt(CellInfo *cell, IdString port, IdString init, dict ¶ms) + { + unsigned init_val = int_or_default(params, init); + bool invert = need_inversion(cell, port); + if (invert) { + if (port.in(id_IN1, id_IN3)) + init_val = (init_val & 0b1010) >> 1 | (init_val & 0b0101) << 1; + else + init_val = (init_val & 0b0011) << 2 | (init_val & 0b1100) >> 2; + params[init] = Property(init_val, 4); + } + } + + void update_cpe_inv(CellInfo *cell, IdString port, IdString param, dict ¶ms) + { + unsigned init_val = int_or_default(params, param); + bool invert = need_inversion(cell, port); + if (invert) { + params[param] = Property(3 - init_val, 2); + } + } + + void update_cpe_mux(CellInfo *cell, IdString port, IdString param, int bit, dict ¶ms) + { + // Mux inversion data is contained in other CPE half + Loc l = ctx->getBelLocation(cell->bel); + CellInfo *cell_u = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(l.x, l.y, 0))); + unsigned init_val = int_or_default(params, param); + bool invert = need_inversion(cell_u, port); + if (invert) { + int old = (init_val >> bit) & 1; + int val = (init_val & (~(1 << bit) & 0xf)) | ((!old) << bit); + params[param] = Property(val, 4); + } + } + std::vector int_to_bitvector(int val, int size) { std::vector bv; @@ -105,36 +176,34 @@ struct BitstreamBackend boost::replace_all(word, "TES.", stringf("TES%d.", id)); if (boost::starts_with(word, "SB_DRIVE.")) { Loc l; + auto ti = *tile_extra_data(pip.tile); tile_xy(ctx->chip_info, pip.tile, l.x, l.y); l.z = 0; BelId cpe_bel = ctx->getBelByLocation(l); // Only if switchbox is inside core (same as sharing location with CPE) if (cpe_bel != BelId() && ctx->getBelType(cpe_bel).in(id_CPE_HALF_L, id_CPE_HALF_U)) { - // Convert coordinates into in-tile coordinates - int xt = ((l.x - 2 - 1) + 16) % 8; - int yt = ((l.y - 2 - 1) + 16) % 8; // Bitstream data for certain SB_DRIVES is located in other tiles switch (word[14]) { case '3': - if (xt >= 4) { + if (ti.tile_x >= 4) { loc.x -= 2; word[14] = '1'; }; break; case '4': - if (yt >= 4) { + if (ti.tile_y >= 4) { loc.y -= 2; word[14] = '2'; }; break; case '1': - if (xt <= 3) { + if (ti.tile_x <= 3) { loc.x += 2; word[14] = '3'; }; break; case '2': - if (yt <= 3) { + if (ti.tile_y <= 3) { loc.y += 2; word[14] = '4'; }; @@ -154,39 +223,75 @@ struct BitstreamBackend { ChipConfig cc; cc.chip_name = device; - int bank[9] = {0}; + int bank[uarch->dies][9] = {0}; for (auto &cell : ctx->cells) { CfgLoc loc = get_config_loc(cell.second.get()->bel.tile); auto ¶ms = cell.second.get()->params; switch (cell.second->type.index) { - case id_CC_IBUF.index: - case id_CC_TOBUF.index: - case id_CC_OBUF.index: - case id_CC_IOBUF.index: - case id_CC_LVDS_IBUF.index: - case id_CC_LVDS_TOBUF.index: - case id_CC_LVDS_OBUF.index: - case id_CC_LVDS_IOBUF.index: + case id_CPE_IBUF.index: + case id_CPE_TOBUF.index: + case id_CPE_OBUF.index: + case id_CPE_IOBUF.index: + case id_CPE_LVDS_IBUF.index: + case id_CPE_LVDS_TOBUF.index: + case id_CPE_LVDS_OBUF.index: + case id_CPE_LVDS_IOBUF.index: for (auto &p : params) { - bank[ctx->get_bel_package_pin(cell.second.get()->bel)->pad_bank] = 1; + 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()); } break; case id_CPE_HALF_U.index: case id_CPE_HALF_L.index: { + // Update configuration bits based on signal inversion + dict params = cell.second->params; + uint8_t func = int_or_default(cell.second->params, id_C_FUNCTION, 0); + if (cell.second->type.in(id_CPE_HALF_U) && func != C_MX4) { + update_cpe_lt(cell.second.get(), id_IN1, id_INIT_L00, params); + update_cpe_lt(cell.second.get(), id_IN2, id_INIT_L00, params); + update_cpe_lt(cell.second.get(), id_IN3, id_INIT_L01, params); + update_cpe_lt(cell.second.get(), id_IN4, id_INIT_L01, params); + } + if (cell.second->type.in(id_CPE_HALF_L)) { + update_cpe_lt(cell.second.get(), id_IN1, id_INIT_L02, params); + update_cpe_lt(cell.second.get(), id_IN2, id_INIT_L02, params); + update_cpe_lt(cell.second.get(), id_IN3, id_INIT_L03, params); + update_cpe_lt(cell.second.get(), id_IN4, id_INIT_L03, params); + if (func == C_MX4) { + update_cpe_mux(cell.second.get(), id_IN1, id_INIT_L11, 0, params); + update_cpe_mux(cell.second.get(), id_IN2, id_INIT_L11, 1, params); + update_cpe_mux(cell.second.get(), id_IN3, id_INIT_L11, 2, params); + update_cpe_mux(cell.second.get(), id_IN4, id_INIT_L11, 3, params); + } + } + if (cell.second->type.in(id_CPE_HALF_U, id_CPE_HALF_L)) { + update_cpe_inv(cell.second.get(), id_CLK, id_C_CPE_CLK, params); + update_cpe_inv(cell.second.get(), id_EN, id_C_CPE_EN, params); + bool set = int_or_default(params, id_C_EN_SR, 0) == 1; + if (set) + update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_SET, params); + else + update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_RES, params); + } int id = tile_extra_data(cell.second.get()->bel.tile)->prim_id; for (auto &p : params) { cc.tiles[loc].add_word(stringf("CPE%d.%s", id, p.first.c_str(ctx)), p.second.as_bits()); } } break; - case id_BUFG.index: { - Loc l = ctx->getBelLocation(cell.second->bel); - cc.configs[0].add_word(stringf("GLBOUT.GLB%d_EN", l.z), int_to_bitvector(1, 1)); + case id_CLKIN.index: { + for (auto &p : params) { + cc.configs[loc.die].add_word(stringf("CLKIN.%s", p.first.c_str(ctx)), p.second.as_bits()); + } + } break; + case id_GLBOUT.index: { + for (auto &p : params) { + cc.configs[loc.die].add_word(stringf("GLBOUT.%s", p.first.c_str(ctx)), p.second.as_bits()); + } } break; case id_PLL.index: { Loc l = ctx->getBelLocation(cell.second->bel); for (auto &p : params) { - cc.configs[0].add_word(stringf("PLL%d.%s", l.z - 4, p.first.c_str(ctx)), p.second.as_bits()); + cc.configs[loc.die].add_word(stringf("PLL%d.%s", l.z - 2, p.first.c_str(ctx)), p.second.as_bits()); } } break; case id_RAM.index: { @@ -224,15 +329,21 @@ struct BitstreamBackend } } - cc.configs[0].add_word("GPIO.BANK_N1", int_to_bitvector(bank[0], 1)); - cc.configs[0].add_word("GPIO.BANK_N2", int_to_bitvector(bank[1], 1)); - cc.configs[0].add_word("GPIO.BANK_E1", int_to_bitvector(bank[2], 1)); - cc.configs[0].add_word("GPIO.BANK_E2", int_to_bitvector(bank[3], 1)); - cc.configs[0].add_word("GPIO.BANK_W1", int_to_bitvector(bank[4], 1)); - cc.configs[0].add_word("GPIO.BANK_W2", int_to_bitvector(bank[5], 1)); - cc.configs[0].add_word("GPIO.BANK_S1", int_to_bitvector(bank[6], 1)); - cc.configs[0].add_word("GPIO.BANK_S2", int_to_bitvector(bank[7], 1)); - cc.configs[0].add_word("GPIO.BANK_CFG", int_to_bitvector(bank[8], 1)); + for (int i = 0; i < uarch->dies; i++) { + cc.configs[i].add_word("GPIO.BANK_N1", int_to_bitvector(bank[i][0], 1)); + cc.configs[i].add_word("GPIO.BANK_N2", int_to_bitvector(bank[i][1], 1)); + cc.configs[i].add_word("GPIO.BANK_E1", int_to_bitvector(bank[i][2], 1)); + cc.configs[i].add_word("GPIO.BANK_E2", int_to_bitvector(bank[i][3], 1)); + cc.configs[i].add_word("GPIO.BANK_W1", int_to_bitvector(bank[i][4], 1)); + cc.configs[i].add_word("GPIO.BANK_W2", int_to_bitvector(bank[i][5], 1)); + cc.configs[i].add_word("GPIO.BANK_S1", int_to_bitvector(bank[i][6], 1)); + cc.configs[i].add_word("GPIO.BANK_S2", int_to_bitvector(bank[i][7], 1)); + cc.configs[i].add_word("GPIO.BANK_CFG", int_to_bitvector(bank[i][8], 1)); + } + if (uarch->dies == 2) { + cc.configs[0].add_word("D2D.N", int_to_bitvector(1, 1)); + cc.configs[1].add_word("D2D.S", int_to_bitvector(1, 1)); + } for (auto &net : ctx->nets) { NetInfo *ni = net.second.get(); diff --git a/himbaechel/uarch/gatemate/ccf.cc b/himbaechel/uarch/gatemate/ccf.cc index 0f91a76c..0913a6c4 100644 --- a/himbaechel/uarch/gatemate/ccf.cc +++ b/himbaechel/uarch/gatemate/ccf.cc @@ -43,6 +43,7 @@ struct GateMateCCFReader std::istream ∈ int lineno; dict defaults; + std::vector count; GateMateCCFReader(Context *ctx, GateMateImpl *uarch, std::istream &in) : ctx(ctx), uarch(uarch), in(in){}; @@ -81,11 +82,17 @@ struct GateMateCCFReader if (name == "LOC") { if (is_default) log_error("Value '%s' can not be defined for default GPIO in line %d.\n", name.c_str(), lineno); - if (ctx->get_package_pin_bel(ctx->id(value)) == BelId()) + if (ctx->get_package_pin_bel(ctx->id(value)) == BelId() && value != "SER_CLK" && value != "SER_CLK_N") log_error("Unknown location '%s' used in line %d.\n", value.c_str(), lineno); if (!uarch->available_pads.count(ctx->id(value))) log_error("Pad '%s' used in line %d not available.\n", value.c_str(), lineno); props->emplace(id_LOC, Property(value)); + for (int i = 0; i < uarch->dies; i++) { + if (uarch->locations.count(std::make_pair(ctx->id(value), i))) + count[i]++; + else + count[i]--; + } uarch->available_pads.erase(ctx->id(value)); } else if (name == "SCHMITT_TRIGGER" || name == "PULLUP" || name == "PULLDOWN" || name == "KEEPER" || name == "FF_IBF" || name == "FF_OBF" || name == "LVDS_BOOST" || name == "LVDS_RTERM") { @@ -148,6 +155,7 @@ struct GateMateCCFReader return std::all_of(str.begin(), str.end(), [](char c) { return isblank(c) || c == '\r' || c == '\n'; }); }; lineno = 0; + count = std::vector(uarch->dies, 0); while (std::getline(in, line)) { ++lineno; // Both // and # are considered start of comment @@ -213,6 +221,14 @@ struct GateMateCCFReader } if (!isempty(linebuf)) log_error("unexpected end of CCF file\n"); + int max_num = 0; + uarch->preferred_die = 0; + for (int i = 0; i < uarch->dies; i++) { + if (count[i] > max_num) { + max_num = count[i]; + uarch->preferred_die = i; + } + } } }; diff --git a/himbaechel/uarch/gatemate/cells.cc b/himbaechel/uarch/gatemate/cells.cc index c473d040..9be8ea67 100644 --- a/himbaechel/uarch/gatemate/cells.cc +++ b/himbaechel/uarch/gatemate/cells.cc @@ -47,6 +47,24 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name) if (type == id_CPE_HALF_L) { add_port(id_COUTY1, PORT_OUT); } + } else if (type.in(id_CLKIN)) { + for (int i = 0; i < 4; i++) { + add_port(ctx->idf("CLK%d", i), PORT_IN); + add_port(ctx->idf("CLK_REF%d", i), PORT_OUT); + } + add_port(id_SER_CLK, PORT_IN); + } else if (type.in(id_GLBOUT)) { + for (int i = 0; i < 4; i++) { + add_port(ctx->idf("CLK0_%d", i), PORT_IN); + add_port(ctx->idf("CLK90_%d", i), PORT_IN); + add_port(ctx->idf("CLK180_%d", i), PORT_IN); + add_port(ctx->idf("CLK270_%d", i), PORT_IN); + add_port(ctx->idf("CLK_REF_OUT%d", i), PORT_IN); + add_port(ctx->idf("USR_GLB%d", i), PORT_IN); + add_port(ctx->idf("USR_FB%d", i), PORT_IN); + add_port(ctx->idf("CLK_FB%d", i), PORT_OUT); + add_port(ctx->idf("GLB%d", i), PORT_OUT); + } } else if (type.in(id_CC_BUFG)) { add_port(id_I, PORT_IN); add_port(id_O, PORT_OUT); diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index 91fd3ab3..9e5ba03f 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -957,12 +957,68 @@ X(CLOCK1) X(CLOCK2) X(CLOCK3) X(CLOCK4) - -// hardware primitive BUFG -X(BUFG) -// BUFG pins //X(I) //X(O) +//X(IO) +//X(I_P) +//X(I_N) +//X(O_P) +//X(O_N) +//X(IO_P) +//X(IO_N) + +// hardware primitive CLKIN +X(CLKIN) +// CLKIN pins +//X(CLK0) +X(CLK1) +X(CLK2) +X(CLK3) +X(SER_CLK) +X(CLK_REF0) +X(CLK_REF1) +X(CLK_REF2) +X(CLK_REF3) + +// hardware primitive GLBOUT +X(GLBOUT) +// GLBOUT pins +X(CLK0_0) +X(CLK90_0) +X(CLK180_0) +X(CLK270_0) +X(CLK_REF_OUT0) +X(USR_GLB0) +X(USR_FB0) +X(CLK_FB0) +X(GLB0) +X(CLK0_1) +X(CLK90_1) +X(CLK180_1) +X(CLK270_1) +X(CLK_REF_OUT1) +X(USR_GLB1) +X(USR_FB1) +X(CLK_FB1) +X(GLB1) +X(CLK0_2) +X(CLK90_2) +X(CLK180_2) +X(CLK270_2) +X(CLK_REF_OUT2) +X(USR_GLB2) +X(USR_FB2) +X(CLK_FB2) +X(GLB2) +X(CLK0_3) +X(CLK90_3) +X(CLK180_3) +X(CLK270_3) +X(CLK_REF_OUT3) +X(USR_GLB3) +X(USR_FB3) +X(CLK_FB3) +X(GLB3) // hardware primitive PLL X(PLL) @@ -1593,6 +1649,10 @@ X(F_RSTN) //X(FRD_ADDRX[14]) //X(FRD_ADDR[15]) //X(FRD_ADDRX[15]) +//X(CLOCK1) +//X(CLOCK2) +//X(CLOCK3) +//X(CLOCK4) // hardware primitive SERDES X(SERDES) @@ -1995,9 +2055,6 @@ X(LVDS_EN) X(LVDS_IE) //X(LVDS_RTERM) -// GPIO virtual pin -X(DI) - X(CPE_HALF) X(RAM_I1) X(RAM_I2) @@ -2104,3 +2161,12 @@ X(PLL_BISC_CO) X(CC_ADDF2) X(A2) X(B2) + +X(CPE_IBUF) +X(CPE_OBUF) +X(CPE_TOBUF) +X(CPE_IOBUF) +X(CPE_LVDS_IBUF) +X(CPE_LVDS_OBUF) +X(CPE_LVDS_TOBUF) +X(CPE_LVDS_IOBUF) diff --git a/himbaechel/uarch/gatemate/extra_data.h b/himbaechel/uarch/gatemate/extra_data.h index 8342ef5c..163fe805 100644 --- a/himbaechel/uarch/gatemate/extra_data.h +++ b/himbaechel/uarch/gatemate/extra_data.h @@ -28,7 +28,10 @@ NPNR_PACKED_STRUCT(struct GateMateTileExtraDataPOD { uint8_t die; uint8_t bit_x; uint8_t bit_y; + uint8_t tile_x; + uint8_t tile_y; uint8_t prim_id; + uint16_t dummy; }); NPNR_PACKED_STRUCT(struct GateMatePipExtraDataPOD { @@ -52,6 +55,13 @@ NPNR_PACKED_STRUCT(struct GateMateBelPinConstraintPOD { NPNR_PACKED_STRUCT(struct GateMateBelExtraDataPOD { RelSlice constraints; }); +NPNR_PACKED_STRUCT(struct GateMatePadExtraDataPOD { + uint16_t x; + uint16_t y; + uint16_t z; + uint16_t dummy; +}); + enum MuxFlags { MUX_INVERT = 1, diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 9ff7c299..963995f0 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -38,6 +38,12 @@ void GateMateImpl::init_database(Arch *arch) arch->load_chipdb(stringf("gatemate/chipdb-%s.bin", args.device.c_str())); arch->set_package("FBGA324"); arch->set_speed_grade("DEFAULT"); + dies = std::stoi(args.device.substr(6)); +} + +const GateMateTileExtraDataPOD *GateMateImpl::tile_extra_data(int tile) const +{ + return reinterpret_cast(ctx->chip_info->tile_insts[tile].extra_data.get()); } void GateMateImpl::init(Context *ctx) @@ -45,8 +51,12 @@ void GateMateImpl::init(Context *ctx) HimbaechelAPI::init(ctx); for (const auto &pad : ctx->package_info->pads) { available_pads.emplace(IdString(pad.package_pin)); + available_pads.emplace(ctx->id("SER_CLK")); + available_pads.emplace(ctx->id("SER_CLK_N")); BelId bel = ctx->getBelByName(IdStringList::concat(IdString(pad.tile), IdString(pad.bel))); bel_to_pad.emplace(bel, &pad); + locations.emplace(std::make_pair(IdString(pad.package_pin), tile_extra_data(bel.tile)->die), + ctx->getBelLocation(bel)); } for (auto bel : ctx->getBels()) { auto *ptr = bel_extra_data(bel); @@ -54,6 +64,10 @@ void GateMateImpl::init(Context *ctx) for (const auto &p : ptr->constraints) pins.emplace(IdString(p.name), &p); pin_to_constr.emplace(bel, pins); + if (ctx->getBelType(bel).in(id_CLKIN, id_GLBOUT, id_PLL, id_USR_RSTN, id_CFG_CTRL, id_SERDES)) { + locations.emplace(std::make_pair(ctx->getBelName(bel)[1], tile_extra_data(bel.tile)->die), + ctx->getBelLocation(bel)); + } } } @@ -72,6 +86,11 @@ bool GateMateImpl::isBelLocationValid(BelId bel, bool explain_invalid) const if (cell == nullptr) { return true; } + + // TODO: remove when placemente per die is better handled + if (cell->belStrength != PlaceStrength::STRENGTH_FIXED && tile_extra_data(bel.tile)->die != preferred_die) + return false; + if (ctx->getBelType(bel).in(id_CPE_HALF, id_CPE_HALF_L, id_CPE_HALF_U)) { Loc loc = ctx->getBelLocation(bel); const CellInfo *adj_half = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.y, loc.z == 1 ? 0 : 1))); @@ -160,77 +179,6 @@ bool GateMateImpl::getClusterPlacement(ClusterId cluster, BelId root_bel, return getChildPlacement(root_cell, root_loc, placement); } -bool GateMateImpl::need_inversion(CellInfo *cell, IdString port) -{ - PortRef sink; - sink.cell = cell; - sink.port = port; - - NetInfo *net_info = cell->getPort(port); - if (!net_info) - return false; - - WireId src_wire = ctx->getNetinfoSourceWire(net_info); - WireId dst_wire = ctx->getNetinfoSinkWire(net_info, sink, 0); - - if (src_wire == WireId()) - return false; - - WireId cursor = dst_wire; - bool invert = false; - while (cursor != WireId() && cursor != src_wire) { - auto it = net_info->wires.find(cursor); - - if (it == net_info->wires.end()) - break; - - PipId pip = it->second.pip; - if (pip == PipId()) - break; - - invert ^= ctx->isPipInverting(pip); - cursor = ctx->getPipSrcWire(pip); - } - - return invert; -} - -void GateMateImpl::update_cpe_lt(CellInfo *cell, IdString port, IdString init) -{ - unsigned init_val = int_or_default(cell->params, init); - bool invert = need_inversion(cell, port); - if (invert) { - if (port.in(id_IN1, id_IN3)) - init_val = (init_val & 0b1010) >> 1 | (init_val & 0b0101) << 1; - else - init_val = (init_val & 0b0011) << 2 | (init_val & 0b1100) >> 2; - cell->params[init] = Property(init_val, 4); - } -} - -void GateMateImpl::update_cpe_inv(CellInfo *cell, IdString port, IdString param) -{ - unsigned init_val = int_or_default(cell->params, param); - bool invert = need_inversion(cell, port); - if (invert) { - cell->params[param] = Property(3 - init_val, 2); - } -} - -void GateMateImpl::update_cpe_mux(CellInfo *cell, IdString port, IdString param, int bit) -{ - // Mux inversion data is contained in other CPE half - Loc l = ctx->getBelLocation(cell->bel); - CellInfo *cell_l = ctx->getBoundBelCell(ctx->getBelByLocation(Loc(l.x, l.y, 1))); - unsigned init_val = int_or_default(cell_l->params, param); - bool invert = need_inversion(cell, port); - if (invert) { - int old = (init_val >> bit) & 1; - int val = (init_val & (~(1 << bit) & 0xf)) | ((!old) << bit); - cell_l->params[param] = Property(val, 4); - } -} - void GateMateImpl::rename_param(CellInfo *cell, IdString name, IdString new_name, int width) { if (cell->params.count(name)) { @@ -274,50 +222,6 @@ void GateMateImpl::preRoute() { route_clock(); } void GateMateImpl::postRoute() { ctx->assignArchInfo(); - // Update configuration bits based on signal inversion - for (auto &cell : ctx->cells) { - if (cell.second->type.in(id_CPE_HALF_U)) { - uint8_t func = int_or_default(cell.second->params, id_C_FUNCTION, 0); - if (func != C_MX4) { - update_cpe_lt(cell.second.get(), id_IN1, id_INIT_L00); - update_cpe_lt(cell.second.get(), id_IN2, id_INIT_L00); - update_cpe_lt(cell.second.get(), id_IN3, id_INIT_L01); - update_cpe_lt(cell.second.get(), id_IN4, id_INIT_L01); - } else { - update_cpe_mux(cell.second.get(), id_IN1, id_INIT_L11, 0); - update_cpe_mux(cell.second.get(), id_IN2, id_INIT_L11, 1); - update_cpe_mux(cell.second.get(), id_IN3, id_INIT_L11, 2); - update_cpe_mux(cell.second.get(), id_IN4, id_INIT_L11, 3); - } - } - if (cell.second->type.in(id_CPE_HALF_L)) { - update_cpe_lt(cell.second.get(), id_IN1, id_INIT_L02); - update_cpe_lt(cell.second.get(), id_IN2, id_INIT_L02); - update_cpe_lt(cell.second.get(), id_IN3, id_INIT_L03); - update_cpe_lt(cell.second.get(), id_IN4, id_INIT_L03); - } - if (cell.second->type.in(id_CPE_HALF_U, id_CPE_HALF_L)) { - update_cpe_inv(cell.second.get(), id_CLK, id_C_CPE_CLK); - update_cpe_inv(cell.second.get(), id_EN, id_C_CPE_EN); - bool set = int_or_default(cell.second->params, id_C_EN_SR, 0) == 1; - if (set) - update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_SET); - else - update_cpe_inv(cell.second.get(), id_SR, id_C_CPE_RES); - } - } - // Sanity check - for (auto &c : ctx->cells) { - CellInfo *cell = c.second.get(); - if (!cell->type.in(id_CPE_HALF_U, id_CPE_HALF_L)) { - for (auto port : cell->ports) { - if (need_inversion(cell, port.first)) { - log_error("Unhandled cell '%s' of type '%s' port '%s'\n", cell->name.c_str(ctx), - cell->type.c_str(ctx), port.first.c_str(ctx)); - } - } - } - } print_utilisation(ctx); const ArchArgs &args = ctx->args; @@ -367,8 +271,8 @@ void GateMateImpl::assign_cell_info() // Bel bucket functions IdString GateMateImpl::getBelBucketForCellType(IdString cell_type) const { - if (cell_type.in(id_CC_IBUF, id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF, id_CC_LVDS_IBUF, id_CC_LVDS_TOBUF, - id_CC_LVDS_OBUF, id_CC_LVDS_IOBUF)) + if (cell_type.in(id_CPE_IBUF, id_CPE_OBUF, id_CPE_TOBUF, id_CPE_IOBUF, id_CPE_LVDS_IBUF, id_CPE_LVDS_TOBUF, + id_CPE_LVDS_OBUF, id_CPE_LVDS_IOBUF)) return id_GPIO; else if (cell_type.in(id_CPE_HALF_U, id_CPE_HALF_L, id_CPE_HALF)) return id_CPE_HALF; @@ -388,8 +292,8 @@ bool GateMateImpl::isValidBelForCellType(IdString cell_type, BelId bel) const { IdString bel_type = ctx->getBelType(bel); if (bel_type == id_GPIO) - return cell_type.in(id_CC_IBUF, id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF, id_CC_LVDS_IBUF, id_CC_LVDS_TOBUF, - id_CC_LVDS_OBUF, id_CC_LVDS_IOBUF); + return cell_type.in(id_CPE_IBUF, id_CPE_OBUF, id_CPE_TOBUF, id_CPE_IOBUF, id_CPE_LVDS_IBUF, id_CPE_LVDS_TOBUF, + id_CPE_LVDS_OBUF, id_CPE_LVDS_IOBUF); else if (bel_type == id_CPE_HALF_U) return cell_type.in(id_CPE_HALF_U, id_CPE_HALF); else if (bel_type == id_CPE_HALF_L) diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index e34f186b..e4f23e24 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -62,9 +62,14 @@ struct GateMateImpl : HimbaechelAPI bool isPipInverting(PipId pip) const override; + const GateMateTileExtraDataPOD *tile_extra_data(int tile) const; + std::set available_pads; std::map bel_to_pad; pool ddr_nets; + dict, Loc> locations; + int dies; + int preferred_die; private: bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc, @@ -75,10 +80,6 @@ struct GateMateImpl : HimbaechelAPI void parse_ccf(const std::string &filename); void assign_cell_info(); - bool need_inversion(CellInfo *cell, IdString port); - void update_cpe_lt(CellInfo *cell, IdString port, IdString init); - void update_cpe_inv(CellInfo *cell, IdString port, IdString param); - void update_cpe_mux(CellInfo *cell, IdString port, IdString param, int bit); void rename_param(CellInfo *cell, IdString name, IdString new_name, int width); void route_clock(); diff --git a/himbaechel/uarch/gatemate/gen/arch_gen.py b/himbaechel/uarch/gatemate/gen/arch_gen.py index c5b98d2c..8e3cf04d 100644 --- a/himbaechel/uarch/gatemate/gen/arch_gen.py +++ b/himbaechel/uarch/gatemate/gen/arch_gen.py @@ -46,6 +46,8 @@ class TileExtraData(BBAStruct): die : int = 0 bit_x: int = 0 bit_y: int = 0 + tile_x: int = 0 + tile_y: int = 0 prim_id : int = 0 def serialise_lists(self, context: str, bba: BBAWriter): @@ -54,7 +56,10 @@ class TileExtraData(BBAStruct): bba.u8(self.die) bba.u8(self.bit_x) bba.u8(self.bit_y) + bba.u8(self.tile_x) + bba.u8(self.tile_y) bba.u8(self.prim_id) + bba.u16(0) @dataclass class PipExtraData(BBAStruct): @@ -111,6 +116,20 @@ class BelExtraData(BBAStruct): def serialise(self, context: str, bba: BBAWriter): bba.slice(f"{context}_constraints", len(self.constraints)) +@dataclass +class PadExtraData(BBAStruct): + x: int = 0 + y: int = 0 + z: int = 0 + + def serialise_lists(self, context: str, bba: BBAWriter): + pass + def serialise(self, context: str, bba: BBAWriter): + bba.u16(self.x) + bba.u16(self.y) + bba.u16(self.z) + bba.u16(0) + def set_timings(ch): speed = "DEFAULT" tmg = ch.set_speed_grades([speed]) @@ -140,7 +159,7 @@ def set_timings(ch): dff.add_setup_hold("CLK", "IN4", ClockEdge.RISING, TimingValue(60), TimingValue(50)) dff.add_clock_out("CLK", "OUT", ClockEdge.RISING, TimingValue(60)) -EXPECTED_VERSION = 1.1 +EXPECTED_VERSION = 1.2 def main(): # Range needs to be +1, but we are adding +2 more to coordinates, since @@ -178,16 +197,12 @@ def main(): tt.create_group(group.name, group.type) for wire in sorted(die.get_endpoints_for_type(type_name)): tt.create_wire(wire.name, wire.type) - if "GPIO" in type_name: - tt.create_wire("GPIO.DI", "CPE_VIRTUAL_WIRE") for prim in sorted(die.get_primitives_for_type(type_name)): bel = tt.create_bel(prim.name, prim.type, prim.z) extra = BelExtraData() for constr in sorted(die.get_pins_constraint(type_name, prim.name, prim.type)): extra.add_constraints(ch.strs.id(constr.name),constr.rel_x,constr.rel_y,0 if constr.pin_num==2 else 1) bel.extra_data = extra - if prim.name == "GPIO": - tt.add_bel_pin(bel, "DI", "GPIO.DI", PinType.INPUT) for pin in sorted(die.get_primitive_pins(prim.type)): tt.add_bel_pin(bel, pin.name, die.get_pin_connection_name(prim,pin), pin.dir) for mux in sorted(die.get_mux_connections_for_type(type_name)): @@ -204,16 +219,13 @@ def main(): if mux.name.startswith("SB_DRIVE"): plane = int(mux.name[10:12]) pp.extra_data = PipExtraData(PIP_EXTRA_MUX, ch.strs.id(mux.name), mux.bits, mux.value, mux_flags, plane) - if "GPIO" in type_name: - tt.create_pip("GPIO.DI", "GPIO.IN1") - tt.create_pip("GPIO.DI", "GPIO.IN2") # Setup tile grid for x in range(dev.max_col() + 3): for y in range(dev.max_row() + 3): ti = ch.set_tile_type(x, y, dev.get_tile_type(x - 2,y - 2)) tileinfo = dev.get_tile_info(x - 2,y - 2) - ti.extra_data = TileExtraData(tileinfo.die, tileinfo.bit_x, tileinfo.bit_y, tileinfo.prim_index) + ti.extra_data = TileExtraData(tileinfo.die, tileinfo.bit_x, tileinfo.bit_y, tileinfo.tile_x, tileinfo.tile_y, tileinfo.prim_index) # Create nodes between tiles for _,nodes in dev.get_connections(): @@ -226,7 +238,8 @@ def main(): for package in dev.get_packages(): pkg = ch.create_package(package) for pad in sorted(dev.get_package_pads(package)): - pkg.create_pad(pad.name, f"X{pad.x+2}Y{pad.y+2}", pad.bel, pad.function, pad.bank, pad.flags) + pp = pkg.create_pad(pad.name, f"X{pad.x+2}Y{pad.y+2}", pad.bel, pad.function, pad.bank, pad.flags) + pp.extra_data = PadExtraData(pad.ddr.x+2, pad.ddr.y+2, pad.ddr.z) ch.write_bba(args.bba) diff --git a/himbaechel/uarch/gatemate/gfx.cc b/himbaechel/uarch/gatemate/gfx.cc index 334b0650..bdd5e068 100644 --- a/himbaechel/uarch/gatemate/gfx.cc +++ b/himbaechel/uarch/gatemate/gfx.cc @@ -62,7 +62,8 @@ void GateMateImpl::drawBel(std::vector &g, GraphicElement::style el.y2 = el.y1 + 0.60; g.push_back(el); break; - case id_BUFG.index: + case id_CLKIN.index: + case id_GLBOUT.index: el.x1 = loc.x + 0.15 + loc.z * 0.20; el.x2 = el.x1 + 0.15; el.y1 = loc.y + 0.10; @@ -70,7 +71,7 @@ void GateMateImpl::drawBel(std::vector &g, GraphicElement::style g.push_back(el); break; case id_PLL.index: - el.x1 = loc.x + 0.15 + (loc.z - 4) * 0.20; + el.x1 = loc.x + 0.15 + (loc.z - 2) * 0.20; el.x2 = el.x1 + 0.15; el.y1 = loc.y + 0.60; el.y2 = el.y1 + 0.30; diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index a0ed44e5..053bf3a7 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -178,7 +178,7 @@ void GateMatePacker::pack_misc() continue; ci.type = id_USR_RSTN; ci.cluster = ci.name; - Loc fixed_loc(0, 0, 3); // USR_RSTN + Loc fixed_loc = uarch->locations[std::make_pair(id_USR_RSTN, uarch->preferred_die)]; ctx->bindBel(ctx->getBelByLocation(fixed_loc), &ci, PlaceStrength::STRENGTH_FIXED); move_ram_i_fixed(&ci, id_USR_RSTN, fixed_loc); @@ -189,7 +189,7 @@ void GateMatePacker::pack_misc() continue; ci.type = id_CFG_CTRL; ci.cluster = ci.name; - Loc fixed_loc(0, 0, 2); // CFG_CTRL + Loc fixed_loc = uarch->locations[std::make_pair(id_CFG_CTRL, uarch->preferred_die)]; ctx->bindBel(ctx->getBelByLocation(fixed_loc), &ci, PlaceStrength::STRENGTH_FIXED); move_ram_o_fixed(&ci, id_CLK, fixed_loc); @@ -261,6 +261,7 @@ void GateMateImpl::pack() packer.pack_addf(); packer.pack_cpe(); packer.remove_constants(); + packer.remove_clocking(); } NEXTPNR_NAMESPACE_END diff --git a/himbaechel/uarch/gatemate/pack.h b/himbaechel/uarch/gatemate/pack.h index 5f16c245..85098568 100644 --- a/himbaechel/uarch/gatemate/pack.h +++ b/himbaechel/uarch/gatemate/pack.h @@ -42,6 +42,7 @@ struct GateMatePacker void pack_serdes(); void remove_constants(); + void remove_clocking(); void remove_not_used(); private: @@ -60,7 +61,6 @@ struct GateMatePacker uint8_t ram_ctrl_signal(CellInfo *cell, IdString port, bool alt); uint8_t ram_clk_signal(CellInfo *cell, IdString port); bool is_gpio_valid_dff(CellInfo *dff); - BelId get_bank_cpe(int bank); // Cell creating CellInfo *create_cell_ptr(IdString type, IdString name); void flush_cells(); @@ -69,6 +69,8 @@ struct GateMatePacker pool packed_cells; std::map global_signals; + std::vector clkin; + std::vector glbout; Context *ctx; GateMateImpl *uarch; diff --git a/himbaechel/uarch/gatemate/pack_clocking.cc b/himbaechel/uarch/gatemate/pack_clocking.cc index 7ca9b0c2..7d840b3f 100644 --- a/himbaechel/uarch/gatemate/pack_clocking.cc +++ b/himbaechel/uarch/gatemate/pack_clocking.cc @@ -78,17 +78,22 @@ void GateMatePacker::sort_bufg() flush_cells(); } +static int glb_mux_mapping[] = { + // CLK0_0 CLK90_0 CLK180_0 CLK270_0 CLK0_1 CLK0_2 CLK0_3 + 4, 5, 6, 7, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, // GLBOUT 0 + // CLK90_0 CLK0_1 CLK90_1 CLK180_1 CLK270_1 CLK90_2 CLK90_3 + 0, 1, 0, 0, 4, 5, 6, 7, 0, 2, 0, 0, 0, 3, 0, 0, // GLBOUT 1 + // CLK180_0 CLK180_1 CLK0_2 CLK90_2 CLK180_2 CLK270_2 CLK180_3 + 0, 0, 1, 0, 0, 0, 2, 0, 4, 5, 6, 7, 0, 0, 3, 0, // GLBOUT 2 + // CLK270_0 CLK270_1 CLK270_2 CLK0_3 CLK90_3 CLK180_3 CLK270_3 + 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 4, 5, 6, 7, // GLBOUT 3 +}; + void GateMatePacker::pack_bufg() { log_info("Packing BUFGs..\n"); CellInfo *bufg[4] = {nullptr}; CellInfo *pll[4] = {nullptr}; - for (auto &cell : ctx->cells) { - CellInfo &ci = *cell.second; - if (!ci.type.in(id_PLL)) - continue; - pll[ci.constr_z - 4] = &ci; - } auto update_bufg_port = [&](CellInfo *cell, int port_num, int pll_num) { CellInfo *b = net_only_drives(ctx, cell->getPort(ctx->idf("CLK%d", 90 * port_num)), is_bufg, id_I, false); @@ -105,11 +110,14 @@ void GateMatePacker::pack_bufg() } }; - for (int i = 0; i < 4; i++) { - if (pll[i]) { - for (int j = 0; j < 4; j++) - update_bufg_port(pll[i], j, i); - } + for (auto &cell : ctx->cells) { + CellInfo &ci = *cell.second; + if (!ci.type.in(id_PLL)) + continue; + int index = ci.constr_z - 2; + pll[index] = &ci; + for (int j = 0; j < 4; j++) + update_bufg_port(pll[index], j, index); } for (auto &cell : ctx->cells) { @@ -118,34 +126,32 @@ void GateMatePacker::pack_bufg() continue; NetInfo *in_net = ci.getPort(id_I); + int die = uarch->preferred_die; if (in_net) { - bool is_cpe_source = true; - if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_GPIO) { - auto pad_info = uarch->bel_to_pad[in_net->driver.cell->bel]; - if (pad_info->flags) - is_cpe_source = false; + if (in_net->driver.cell) { + if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_GPIO) { + 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)); + } + } + } else { + // SER_CLK + clkin[die]->connectPort(id_SER_CLK, in_net); } - if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_PLL) { - is_cpe_source = false; - } - if (is_cpe_source) { - ci.cluster = ci.name; - } - copy_constraint(in_net, ci.getPort(id_O)); - } - ci.type = id_BUFG; - } - for (auto &cell : ctx->cells) { - CellInfo &ci = *cell.second; - if (!ci.type.in(id_BUFG)) - continue; - NetInfo *in_net = ci.getPort(id_I); - if (in_net && ctx->getBelBucketForCellType(in_net->driver.cell->type) != id_PLL) { - for (int i = 0; i < 4; i++) { - if (bufg[i] == nullptr) { - bufg[i] = &ci; - break; + copy_constraint(in_net, ci.getPort(id_O)); + + if ((in_net->driver.cell && ctx->getBelBucketForCellType(in_net->driver.cell->type) != id_PLL) || + !in_net->driver.cell) { + for (int i = 0; i < 4; i++) { + if (bufg[i] == nullptr) { + bufg[i] = &ci; + break; + } } } } @@ -155,13 +161,82 @@ void GateMatePacker::pack_bufg() if (bufg[i]) { CellInfo &ci = *bufg[i]; global_signals.emplace(ci.getPort(id_O), i); - Loc fixed_loc(33 + 2, 131 + 2, i); // BUFG - BelId bufg_bel = ctx->getBelByLocation(fixed_loc); - ctx->bindBel(bufg_bel, &ci, PlaceStrength::STRENGTH_FIXED); - if (ci.cluster != ClusterId()) - move_ram_o_fixed(&ci, id_I, fixed_loc); + int glb_mux = 0; + NetInfo *in_net = ci.getPort(id_I); + int die = uarch->preferred_die; + if (in_net->driver.cell) { + bool user_glb = true; + if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_GPIO) { + 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; + clkin[die]->params[ctx->idf("REF%d", i)] = Property(pad_info->flags - 1, 3); + clkin[die]->params[ctx->idf("REF%d_INV", i)] = Property(Property::State::S0); + NetInfo *conn = ctx->createNet(ci.name); + clkin[die]->connectPort(ctx->idf("CLK_REF%d", i), conn); + glbout[die]->connectPort(ctx->idf("CLK_REF_OUT%d", i), conn); + user_glb = false; + } + } + if (ctx->getBelBucketForCellType(in_net->driver.cell->type) == id_PLL) { + CellInfo *pll = in_net->driver.cell; + int pll_index = ctx->getBelLocation(pll->bel).z - 2; + int pll_out = 0; + if (pll->getPort(id_CLK0) == in_net) + pll_out = 0; + else if (pll->getPort(id_CLK90) == in_net) + pll_out = 1; + else if (pll->getPort(id_CLK180) == in_net) + pll_out = 2; + else if (pll->getPort(id_CLK270) == in_net) + pll_out = 3; + else + log_error("Uknown connecton on BUFG to PLL.\n"); + glb_mux = glb_mux_mapping[i * 16 + pll_index * 4 + pll_out]; + ci.movePortTo(id_I, glbout[die], ctx->idf("%s_%d", in_net->driver.port.c_str(ctx), pll_index)); + user_glb = false; + } + if (user_glb) { + ci.movePortTo(id_I, glbout[die], ctx->idf("USR_GLB%d", i)); + move_ram_o_fixed(glbout[die], ctx->idf("USR_GLB%d", i), ctx->getBelLocation(glbout[die]->bel)); + glbout[die]->params[ctx->idf("USR_GLB%d", i)] = Property(Property::State::S1); + } + } else { + // SER_CLK + clkin[die]->params[ctx->idf("REF%d", i)] = Property(0b100, 3); + clkin[die]->params[ctx->idf("REF%d_INV", i)] = Property(Property::State::S0); + } + + ci.movePortTo(id_O, glbout[die], ctx->idf("GLB%d", i)); + glbout[die]->params[ctx->idf("GLB%d_EN", i)] = Property(Property::State::S1); + glbout[die]->params[ctx->idf("GLB%d", i)] = Property(glb_mux, 3); + packed_cells.emplace(ci.name); } } + + for (int i = 0; i < 4; i++) { + if (pll[i]) { + NetInfo *feedback_net = pll[i]->getPort(id_CLK_FEEDBACK); + int die = uarch->tile_extra_data(pll[i]->bel.tile)->die; + if (feedback_net) { + if (!global_signals.count(feedback_net)) { + pll[i]->movePortTo(id_CLK_FEEDBACK, glbout[die], ctx->idf("USR_FB%d", i)); + move_ram_o_fixed(glbout[die], ctx->idf("USR_FB%d", i), ctx->getBelLocation(glbout[die]->bel)); + glbout[die]->params[ctx->idf("USR_FB%d", i)] = Property(Property::State::S1); + } else { + int index = global_signals[feedback_net]; + glbout[die]->params[ctx->idf("FB%d", i)] = Property(index, 2); + pll[i]->disconnectPort(id_CLK_FEEDBACK); + } + NetInfo *conn = + ctx->createNet(ctx->idf("%s_%s", glbout[die]->name.c_str(ctx), feedback_net->name.c_str(ctx))); + pll[i]->connectPort(id_CLK_FEEDBACK, conn); + glbout[die]->connectPort(ctx->idf("CLK_FB%d", i), conn); + } + } + } + + flush_cells(); } void GateMatePacker::pll_out(CellInfo *cell, IdString origPort, Loc fixed) @@ -203,6 +278,16 @@ void GateMatePacker::insert_bufg(CellInfo *cell, IdString port) void GateMatePacker::insert_pll_bufg() { + for (int i = 0; i < uarch->dies; i++) { + Loc fixed_loc = uarch->locations[std::make_pair(id_CLKIN, i)]; + clkin.push_back(create_cell_ptr(id_CLKIN, ctx->idf("CLKIN%d", i))); + BelId clkin_bel = ctx->getBelByLocation(fixed_loc); + ctx->bindBel(clkin_bel, clkin.back(), PlaceStrength::STRENGTH_FIXED); + glbout.push_back(create_cell_ptr(id_GLBOUT, ctx->idf("GLBOUT%d", i))); + fixed_loc = uarch->locations[std::make_pair(id_GLBOUT, i)]; + BelId glbout_bel = ctx->getBelByLocation(fixed_loc); + ctx->bindBel(glbout_bel, glbout.back(), PlaceStrength::STRENGTH_FIXED); + } std::vector cells; for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -218,9 +303,33 @@ void GateMatePacker::insert_pll_bufg() } } +void GateMatePacker::remove_clocking() +{ + auto remove_unused_cells = [&](std::vector &cells, const char *type) { + for (auto cell : cells) { + bool used = false; + for (auto port : cell->ports) { + if (cell->getPort(port.first)) { + used = true; + break; + } + } + if (!used) { + BelId bel = cell->bel; + if (bel != BelId()) + ctx->unbindBel(bel); + packed_cells.emplace(cell->name); + } + } + }; + remove_unused_cells(clkin, "CLKIN"); + remove_unused_cells(glbout, "GLBOUT"); + flush_cells(); +} + void GateMatePacker::pack_pll() { - int pll_index = 0; + int pll_index[uarch->dies] = {0}; log_info("Packing PLLss..\n"); for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; @@ -232,15 +341,30 @@ void GateMatePacker::pack_pll() disconnect_if_gnd(&ci, id_CLK_FEEDBACK); disconnect_if_gnd(&ci, id_USR_LOCKED_STDY_RST); + int die = uarch->preferred_die; + + NetInfo *clk = ci.getPort(id_CLK_REF); + if (clk) { + 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) { + 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; + } + } + } + ci.cluster = ci.name; ci.constr_abs_z = true; - ci.constr_z = 4 + pll_index; // Position to a proper Z location + ci.constr_z = 2 + pll_index[die]; // Position to a proper Z location - Loc fixed_loc(33 + 2, 131 + 2, 4 + pll_index); // PLL + Loc fixed_loc = uarch->locations[std::make_pair(ctx->idf("PLL%d", pll_index[die]), die)]; BelId pll_bel = ctx->getBelByLocation(fixed_loc); ctx->bindBel(pll_bel, &ci, PlaceStrength::STRENGTH_FIXED); - if (pll_index > 4) + if (pll_index[die] > 4) log_error("Used more than available PLLs.\n"); if (ci.getPort(id_CLK_REF) == nullptr && ci.getPort(id_USR_CLK_REF) == nullptr) @@ -249,7 +373,7 @@ void GateMatePacker::pack_pll() if (ci.getPort(id_CLK_REF) != nullptr && ci.getPort(id_USR_CLK_REF) != nullptr) log_error("CLK_REF and USR_CLK_REF are not allowed to be set in same time.\n"); - NetInfo *clk = ci.getPort(id_CLK_REF); + clk = ci.getPort(id_CLK_REF); delay_t period = ctx->getDelayFromNS(1.0e9 / ctx->setting("target_freq")); if (clk) { if (ctx->getBelBucketForCellType(clk->driver.cell->type) == id_CC_BUFG) { @@ -261,10 +385,16 @@ void GateMatePacker::pack_pll() if (ctx->getBelBucketForCellType(clk->driver.cell->type) != id_GPIO) 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 & 1)) + if (pad_info->flags == 0) log_error("CLK_REF must be driven with CLK dedicated pin.\n"); if (clk->clkconstr) period = clk->clkconstr->period.minDelay(); + + ci.movePortTo(id_CLK_REF, clkin[die], ctx->idf("CLK%d", pad_info->flags - 1)); + + NetInfo *conn = ctx->createNet(ctx->idf("%s_CLK_REF", ci.name.c_str(ctx))); + clkin[die]->connectPort(ctx->idf("CLK_REF%d", pll_index[die]), conn); + ci.connectPort(id_CLK_REF, conn); } clk = ci.getPort(id_USR_CLK_REF); @@ -275,10 +405,6 @@ void GateMatePacker::pack_pll() period = clk->clkconstr->period.minDelay(); } - NetInfo *fbk = ci.getPort(id_CLK_FEEDBACK); - if (fbk && !fbk->driver.cell->type.in(id_CC_BUFG)) - move_ram_o_fixed(&ci, id_CLK_FEEDBACK, fixed_loc); - if (ci.getPort(id_CLK_REF_OUT)) log_error("Output CLK_REF_OUT cannot be used if PLL is used.\n"); @@ -342,28 +468,28 @@ void GateMatePacker::pack_pll() // PLL_cfg_val_800_1400 PLL values from 11.08.2021 bool feedback = false; if (ci.getPort(id_CLK_FEEDBACK)) { - ci.params[ctx->id("CFG_A.FB_PATH")] = Property(0b1, 1); + ci.params[ctx->id("CFG_A_FB_PATH")] = Property(0b1, 1); feedback = true; } - ci.params[ctx->id("CFG_A.FINE_TUNE")] = Property(0b00011001000, 11); - ci.params[ctx->id("CFG_A.COARSE_TUNE")] = Property(0b100, 3); - ci.params[ctx->id("CFG_A.AO_SW")] = Property(0b01000, 5); - ci.params[ctx->id("CFG_A.OPEN_LOOP")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.ENFORCE_LOCK")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.PFD_SEL")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.LOCK_DETECT_WIN")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.SYNC_BYPASS")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.FILTER_SHIFT")] = Property(0b10, 2); - ci.params[ctx->id("CFG_A.FAST_LOCK")] = Property(0b1, 1); - ci.params[ctx->id("CFG_A.SAR_LIMIT")] = Property(0b010, 3); - ci.params[ctx->id("CFG_A.OP_LOCK")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.PDIV0_MUX")] = Property(0b1, 1); - ci.params[ctx->id("CFG_A.EN_COARSE_TUNE")] = Property(0b1, 1); - ci.params[ctx->id("CFG_A.EN_USR_CFG")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.PLL_EN_SEL")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_FINE_TUNE")] = Property(0b00011001000, 11); + ci.params[ctx->id("CFG_A_COARSE_TUNE")] = Property(0b100, 3); + ci.params[ctx->id("CFG_A_AO_SW")] = Property(0b01000, 5); + ci.params[ctx->id("CFG_A_OPEN_LOOP")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_ENFORCE_LOCK")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_PFD_SEL")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_LOCK_DETECT_WIN")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_SYNC_BYPASS")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_FILTER_SHIFT")] = Property(0b10, 2); + ci.params[ctx->id("CFG_A_FAST_LOCK")] = Property(0b1, 1); + ci.params[ctx->id("CFG_A_SAR_LIMIT")] = Property(0b010, 3); + ci.params[ctx->id("CFG_A_OP_LOCK")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_PDIV0_MUX")] = Property(0b1, 1); + ci.params[ctx->id("CFG_A_EN_COARSE_TUNE")] = Property(0b1, 1); + ci.params[ctx->id("CFG_A_EN_USR_CFG")] = Property(0b0, 1); + ci.params[ctx->id("CFG_A_PLL_EN_SEL")] = Property(0b0, 1); - ci.params[ctx->id("CFG_A.CI_FILTER_CONST")] = Property(ci_const, 5); - ci.params[ctx->id("CFG_A.CP_FILTER_CONST")] = Property(cp_const, 5); + ci.params[ctx->id("CFG_A_CI_FILTER_CONST")] = Property(ci_const, 5); + ci.params[ctx->id("CFG_A_CP_FILTER_CONST")] = Property(cp_const, 5); /* clock path selection 0-0 PDIV0_MUX = 0, FB_PATH = 0 // DCO clock with intern feedback @@ -375,12 +501,12 @@ void GateMatePacker::pack_pll() bool pdiv0_mux = true; PllCfgRecord val = get_pll_settings(ref_clk, out_clk, perf_md, low_jitter, pdiv0_mux, feedback); if (val.f_core > 0) { // cfg exists - ci.params[ctx->id("CFG_A.K")] = Property(val.K, 12); - ci.params[ctx->id("CFG_A.N1")] = Property(val.N1, 6); - ci.params[ctx->id("CFG_A.N2")] = Property(val.N2, 10); - ci.params[ctx->id("CFG_A.M1")] = Property(val.M1, 6); - ci.params[ctx->id("CFG_A.M2")] = Property(val.M2, 10); - ci.params[ctx->id("CFG_A.PDIV1_SEL")] = Property(val.PDIV1 == 2 ? 1 : 0, 1); + ci.params[ctx->id("CFG_A_K")] = Property(val.K, 12); + ci.params[ctx->id("CFG_A_N1")] = Property(val.N1, 6); + ci.params[ctx->id("CFG_A_N2")] = Property(val.N2, 10); + ci.params[ctx->id("CFG_A_M1")] = Property(val.M1, 6); + ci.params[ctx->id("CFG_A_M2")] = Property(val.M2, 10); + ci.params[ctx->id("CFG_A_PDIV1_SEL")] = Property(val.PDIV1 == 2 ? 1 : 0, 1); } else { log_error("Unable to configure PLL %s\n", ci.name.c_str(ctx)); } @@ -397,41 +523,41 @@ void GateMatePacker::pack_pll() for (int i = 0; i < 2; i++) { char cfg = 'A' + i; IdString id = i == 0 ? id_PLL_CFG_A : id_PLL_CFG_B; - ci.params[ctx->idf("CFG_%c.CI_FILTER_CONST", cfg)] = Property(extract_bits(ci.params, id, 0, 5), 5); - ci.params[ctx->idf("CFG_%c.CP_FILTER_CONST", cfg)] = Property(extract_bits(ci.params, id, 5, 5), 5); - ci.params[ctx->idf("CFG_%c.N1", cfg)] = Property(extract_bits(ci.params, id, 10, 6), 6); - ci.params[ctx->idf("CFG_%c.N2", cfg)] = Property(extract_bits(ci.params, id, 16, 10), 10); - ci.params[ctx->idf("CFG_%c.M1", cfg)] = Property(extract_bits(ci.params, id, 26, 6), 6); - ci.params[ctx->idf("CFG_%c.M2", cfg)] = Property(extract_bits(ci.params, id, 32, 10), 10); - ci.params[ctx->idf("CFG_%c.K", cfg)] = Property(extract_bits(ci.params, id, 42, 12), 12); - ci.params[ctx->idf("CFG_%c.FB_PATH", cfg)] = Property(extract_bits(ci.params, id, 54, 1), 1); - ci.params[ctx->idf("CFG_%c.FINE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 55, 11), 11); - ci.params[ctx->idf("CFG_%c.COARSE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 66, 3), 3); - ci.params[ctx->idf("CFG_%c.AO_SW", cfg)] = Property(extract_bits(ci.params, id, 69, 5), 5); - ci.params[ctx->idf("CFG_%c.OPEN_LOOP", cfg)] = Property(extract_bits(ci.params, id, 74, 1), 1); - ci.params[ctx->idf("CFG_%c.ENFORCE_LOCK", cfg)] = Property(extract_bits(ci.params, id, 75, 1), 1); - ci.params[ctx->idf("CFG_%c.PFD_SEL", cfg)] = Property(extract_bits(ci.params, id, 76, 1), 1); - ci.params[ctx->idf("CFG_%c.LOCK_DETECT_WIN", cfg)] = Property(extract_bits(ci.params, id, 77, 1), 1); - ci.params[ctx->idf("CFG_%c.SYNC_BYPASS", cfg)] = Property(extract_bits(ci.params, id, 78, 1), 1); - ci.params[ctx->idf("CFG_%c.FILTER_SHIFT", cfg)] = Property(extract_bits(ci.params, id, 79, 2), 2); - ci.params[ctx->idf("CFG_%c.FAST_LOCK", cfg)] = Property(extract_bits(ci.params, id, 81, 1), 1); - ci.params[ctx->idf("CFG_%c.SAR_LIMIT", cfg)] = Property(extract_bits(ci.params, id, 82, 3), 3); - ci.params[ctx->idf("CFG_%c.OP_LOCK", cfg)] = Property(extract_bits(ci.params, id, 85, 1), 1); - ci.params[ctx->idf("CFG_%c.PDIV1_SEL", cfg)] = Property(extract_bits(ci.params, id, 86, 1), 1); - ci.params[ctx->idf("CFG_%c.PDIV0_MUX", cfg)] = Property(extract_bits(ci.params, id, 87, 1), 1); - ci.params[ctx->idf("CFG_%c.EN_COARSE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 88, 1), 1); - ci.params[ctx->idf("CFG_%c.EN_USR_CFG", cfg)] = Property(extract_bits(ci.params, id, 89, 1), 1); - ci.params[ctx->idf("CFG_%c.PLL_EN_SEL", cfg)] = Property(extract_bits(ci.params, id, 90, 1), 1); - int N1 = int_or_default(ci.params, ctx->idf("CFG_%c.N1", cfg)); - int N2 = int_or_default(ci.params, ctx->idf("CFG_%c.N2", cfg)); - int M1 = int_or_default(ci.params, ctx->idf("CFG_%c.M1", cfg)); - int M2 = int_or_default(ci.params, ctx->idf("CFG_%c.M2", cfg)); - int K = int_or_default(ci.params, ctx->idf("CFG_%c.K", cfg)); - int PDIV1 = bool_or_default(ci.params, ctx->idf("CFG_%c.PDIV1_SEL", cfg)) ? 2 : 0; + ci.params[ctx->idf("CFG_%c_CI_FILTER_CONST", cfg)] = Property(extract_bits(ci.params, id, 0, 5), 5); + ci.params[ctx->idf("CFG_%c_CP_FILTER_CONST", cfg)] = Property(extract_bits(ci.params, id, 5, 5), 5); + ci.params[ctx->idf("CFG_%c_N1", cfg)] = Property(extract_bits(ci.params, id, 10, 6), 6); + ci.params[ctx->idf("CFG_%c_N2", cfg)] = Property(extract_bits(ci.params, id, 16, 10), 10); + ci.params[ctx->idf("CFG_%c_M1", cfg)] = Property(extract_bits(ci.params, id, 26, 6), 6); + ci.params[ctx->idf("CFG_%c_M2", cfg)] = Property(extract_bits(ci.params, id, 32, 10), 10); + ci.params[ctx->idf("CFG_%c_K", cfg)] = Property(extract_bits(ci.params, id, 42, 12), 12); + ci.params[ctx->idf("CFG_%c_FB_PATH", cfg)] = Property(extract_bits(ci.params, id, 54, 1), 1); + ci.params[ctx->idf("CFG_%c_FINE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 55, 11), 11); + ci.params[ctx->idf("CFG_%c_COARSE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 66, 3), 3); + ci.params[ctx->idf("CFG_%c_AO_SW", cfg)] = Property(extract_bits(ci.params, id, 69, 5), 5); + ci.params[ctx->idf("CFG_%c_OPEN_LOOP", cfg)] = Property(extract_bits(ci.params, id, 74, 1), 1); + ci.params[ctx->idf("CFG_%c_ENFORCE_LOCK", cfg)] = Property(extract_bits(ci.params, id, 75, 1), 1); + ci.params[ctx->idf("CFG_%c_PFD_SEL", cfg)] = Property(extract_bits(ci.params, id, 76, 1), 1); + ci.params[ctx->idf("CFG_%c_LOCK_DETECT_WIN", cfg)] = Property(extract_bits(ci.params, id, 77, 1), 1); + ci.params[ctx->idf("CFG_%c_SYNC_BYPASS", cfg)] = Property(extract_bits(ci.params, id, 78, 1), 1); + ci.params[ctx->idf("CFG_%c_FILTER_SHIFT", cfg)] = Property(extract_bits(ci.params, id, 79, 2), 2); + ci.params[ctx->idf("CFG_%c_FAST_LOCK", cfg)] = Property(extract_bits(ci.params, id, 81, 1), 1); + ci.params[ctx->idf("CFG_%c_SAR_LIMIT", cfg)] = Property(extract_bits(ci.params, id, 82, 3), 3); + ci.params[ctx->idf("CFG_%c_OP_LOCK", cfg)] = Property(extract_bits(ci.params, id, 85, 1), 1); + ci.params[ctx->idf("CFG_%c_PDIV1_SEL", cfg)] = Property(extract_bits(ci.params, id, 86, 1), 1); + ci.params[ctx->idf("CFG_%c_PDIV0_MUX", cfg)] = Property(extract_bits(ci.params, id, 87, 1), 1); + ci.params[ctx->idf("CFG_%c_EN_COARSE_TUNE", cfg)] = Property(extract_bits(ci.params, id, 88, 1), 1); + ci.params[ctx->idf("CFG_%c_EN_USR_CFG", cfg)] = Property(extract_bits(ci.params, id, 89, 1), 1); + ci.params[ctx->idf("CFG_%c_PLL_EN_SEL", cfg)] = Property(extract_bits(ci.params, id, 90, 1), 1); + int N1 = int_or_default(ci.params, ctx->idf("CFG_%c_N1", cfg)); + int N2 = int_or_default(ci.params, ctx->idf("CFG_%c_N2", cfg)); + int M1 = int_or_default(ci.params, ctx->idf("CFG_%c_M1", cfg)); + int M2 = int_or_default(ci.params, ctx->idf("CFG_%c_M2", cfg)); + int K = int_or_default(ci.params, ctx->idf("CFG_%c_K", cfg)); + int PDIV1 = bool_or_default(ci.params, ctx->idf("CFG_%c_PDIV1_SEL", cfg)) ? 2 : 0; double out_clk; double ref_clk = 1000.0f / ctx->getDelayNS(period); - if (!bool_or_default(ci.params, ctx->idf("CFG_%c.FB_PATH", cfg))) { - if (bool_or_default(ci.params, ctx->idf("CFG_%c.PDIV0_MUX", cfg))) { + if (!bool_or_default(ci.params, ctx->idf("CFG_%c_FB_PATH", cfg))) { + if (bool_or_default(ci.params, ctx->idf("CFG_%c_PDIV0_MUX", cfg))) { out_clk = (ref_clk * N1 * N2) / (K * 2 * M1 * M2); } else { out_clk = (ref_clk / K) * N1 * N2 * PDIV1; @@ -490,7 +616,7 @@ void GateMatePacker::pack_pll() ci.type = id_PLL; - pll_index++; + pll_index[die]++; } } diff --git a/himbaechel/uarch/gatemate/pack_io.cc b/himbaechel/uarch/gatemate/pack_io.cc index acfdb30d..bd56cdc3 100644 --- a/himbaechel/uarch/gatemate/pack_io.cc +++ b/himbaechel/uarch/gatemate/pack_io.cc @@ -24,30 +24,11 @@ NEXTPNR_NAMESPACE_BEGIN -BelId GateMatePacker::get_bank_cpe(int bank) +std::string get_die_name(int total_dies, int die) { - switch (bank) { - case 0: - return ctx->getBelByLocation(Loc(97 + 2, 128 + 2, 1)); // N1, RAM_O1 - case 1: - return ctx->getBelByLocation(Loc(97 + 2, 128 + 2, 0)); // N2, RAM_O2 - case 2: - return ctx->getBelByLocation(Loc(160 + 2, 65 + 2, 1)); // E1, RAM_O1 - case 3: - return ctx->getBelByLocation(Loc(160 + 2, 65 + 2, 0)); // E2, RAM_O2 - case 4: - return ctx->getBelByLocation(Loc(1 + 2, 65 + 2, 1)); // W1, RAM_O1 - case 5: - return ctx->getBelByLocation(Loc(1 + 2, 65 + 2, 0)); // W2, RAM_O2 - case 6: - return ctx->getBelByLocation(Loc(97 + 2, 1 + 2, 1)); // S1, RAM_O1 - case 7: - return ctx->getBelByLocation(Loc(97 + 2, 1 + 2, 0)); // S2, RAM_O2 - case 8: - return ctx->getBelByLocation(Loc(49 + 2, 1 + 2, 1)); // S3, RAM_O1 - default: - log_error("Unkown bank\n"); - } + if (total_dies == 1) + return ""; + return stringf("on die '%d%c'", int(die / total_dies) + 1, 'A' + int(die % total_dies)); } void GateMatePacker::pack_io() @@ -152,6 +133,21 @@ void GateMatePacker::pack_io() loc = new_loc; } + if (loc == "SER_CLK" || loc == "SER_CLK_N") { + if (ci.type.in(id_CC_IBUF)) { + log_info(" Constraining '%s' to pad '%s'\n", ci.name.c_str(ctx), loc.c_str()); + NetInfo *ser_clk = ci.getPort(id_I); + for (auto s : ci.getPort(id_Y)->users) { + s.cell->disconnectPort(s.port); + s.cell->connectPort(s.port, ser_clk); + } + ci.disconnectPort(id_I); + packed_cells.emplace(ci.name); + continue; + } else { + log_error("SER_CLK and SER_CLK_N pins can only be used on input port.\n"); + } + } if (loc == "UNPLACED") { const ArchArgs &args = ctx->args; if (args.options.count("allow-unconstrained")) @@ -271,16 +267,13 @@ void GateMatePacker::pack_io() } } - // Disconnect PADs - ci.disconnectPort(id_IO); - ci.disconnectPort(id_I); - ci.disconnectPort(id_O); - ci.disconnectPort(id_IO_P); - ci.disconnectPort(id_IO_N); - ci.disconnectPort(id_I_P); - ci.disconnectPort(id_I_N); - ci.disconnectPort(id_O_P); - ci.disconnectPort(id_O_N); + static dict map_types = { + {id_CC_IBUF, id_CPE_IBUF}, {id_CC_OBUF, id_CPE_OBUF}, + {id_CC_TOBUF, id_CPE_TOBUF}, {id_CC_IOBUF, id_CPE_IOBUF}, + {id_CC_LVDS_IBUF, id_CPE_LVDS_IBUF}, {id_CC_LVDS_TOBUF, id_CPE_LVDS_TOBUF}, + {id_CC_LVDS_OBUF, id_CPE_LVDS_OBUF}, {id_CC_LVDS_IOBUF, id_CPE_LVDS_IOBUF}, + }; + ci.type = map_types[ci.type]; if (loc.empty() || loc == "UNPLACED") { if (uarch->available_pads.empty()) @@ -291,17 +284,23 @@ void GateMatePacker::pack_io() } ci.params[id_LOC] = Property(loc); - BelId bel = ctx->get_package_pin_bel(ctx->id(loc)); + BelId bel; + if (uarch->locations.count(std::make_pair(ctx->id(loc), uarch->preferred_die))) + bel = ctx->getBelByLocation(uarch->locations[std::make_pair(ctx->id(loc), uarch->preferred_die)]); + else + bel = ctx->get_package_pin_bel(ctx->id(loc)); if (bel == BelId()) log_error("Unable to constrain IO '%s', device does not have a pin named '%s'\n", ci.name.c_str(ctx), loc.c_str()); - log_info(" Constraining '%s' to pad '%s'\n", ci.name.c_str(ctx), loc.c_str()); + log_info(" Constraining '%s' to pad '%s'%s.\n", ci.name.c_str(ctx), loc.c_str(), + get_die_name(uarch->dies, uarch->tile_extra_data(bel.tile)->die).c_str()); if (!ctx->checkBelAvail(bel)) { 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))); } ctx->bindBel(bel, &ci, PlaceStrength::STRENGTH_FIXED); } + flush_cells(); } void GateMatePacker::pack_io_sel() @@ -309,14 +308,13 @@ void GateMatePacker::pack_io_sel() std::vector cells; for (auto &cell : ctx->cells) { CellInfo &ci = *cell.second; - if (!ci.type.in(id_CC_IBUF, id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF, id_CC_LVDS_IBUF, id_CC_LVDS_OBUF, - id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF)) + if (!uarch->getBelBucketForCellType(ci.type).in(id_GPIO)) continue; cells.push_back(&ci); } - CellInfo *ddr[9] = {nullptr}; // for each bank + CellInfo *ddr[uarch->dies][9] = {nullptr}; // for each bank auto set_out_clk = [&](CellInfo *cell, CellInfo *target) -> bool { NetInfo *clk_net = cell->getPort(id_CLK); @@ -371,7 +369,7 @@ void GateMatePacker::pack_io_sel() ci.params[id_IN2_FF] = Property(Property::State::S1); packed_cells.emplace(dff->name); ci.disconnectPort(id_Y); - dff->movePortTo(id_Q, &ci, id_DI); + dff->movePortTo(id_Q, &ci, id_IN1); set_in_clk(dff, &ci); bool invert = bool_or_default(dff->params, id_CLK_INV, 0); if (invert) { @@ -407,7 +405,7 @@ void GateMatePacker::pack_io_sel() } else { ci.params[id_INV_IN2_CLOCK] = Property(Property::State::S1); } - return false; + return true; }; for (auto &cell : cells) { @@ -466,7 +464,8 @@ void GateMatePacker::pack_io_sel() oddr->movePortTo(id_D0, &ci, id_OUT2); oddr->movePortTo(id_D1, &ci, id_OUT1); const auto &pad = ctx->get_package_pin(ctx->id(loc)); - CellInfo *cpe_half = ddr[pad->pad_bank]; + int die = uarch->tile_extra_data(ci.bel.tile)->die; + CellInfo *cpe_half = ddr[die][pad->pad_bank]; if (cpe_half) { if (cpe_half->getPort(id_IN1) != oddr->getPort(id_DDR)) log_error("DDR port use signal different than already occupied DDR source.\n"); @@ -477,8 +476,10 @@ void GateMatePacker::pack_io_sel() oddr->movePortTo(id_DDR, &ci, id_DDR); cpe_half = move_ram_o(&ci, id_DDR, false); uarch->ddr_nets.insert(cpe_half->getPort(id_IN1)->name); - ctx->bindBel(get_bank_cpe(pad->pad_bank), cpe_half, PlaceStrength::STRENGTH_FIXED); - ddr[pad->pad_bank] = cpe_half; + auto l = reinterpret_cast(pad->extra_data.get()); + ctx->bindBel(ctx->getBelByLocation(Loc(l->x, l->y, l->z)), cpe_half, + PlaceStrength::STRENGTH_FIXED); + ddr[die][pad->pad_bank] = cpe_half; } use_custom_clock = set_out_clk(oddr, &ci); bool invert = bool_or_default(oddr->params, id_CLK_INV, 0); @@ -505,7 +506,7 @@ void GateMatePacker::pack_io_sel() } if (!ff_ibf_merged && !iddr_merged) - ci.renamePort(id_Y, id_DI); + ci.renamePort(id_Y, id_IN1); } Loc root_loc = ctx->getBelLocation(ci.bel); diff --git a/himbaechel/uarch/gatemate/route_clock.cc b/himbaechel/uarch/gatemate/route_clock.cc index 7f96b0ba..52668592 100644 --- a/himbaechel/uarch/gatemate/route_clock.cc +++ b/himbaechel/uarch/gatemate/route_clock.cc @@ -111,8 +111,21 @@ void GateMateImpl::route_clock() log_info(" routing net '%s'\n", clk_net->name.c_str(ctx)); ctx->bindWire(ctx->getNetinfoSourceWire(clk_net), clk_net, STRENGTH_LOCKED); - auto bufg_idx = ctx->getBelLocation(clk_net->driver.cell->bel).z; - auto clk_plane = 9 + bufg_idx; + auto clk_plane = 0; + switch (clk_net->driver.port.index) { + case id_GLB0.index: + clk_plane = 9; + break; + case id_GLB1.index: + clk_plane = 10; + break; + case id_GLB2.index: + clk_plane = 11; + break; + case id_GLB3.index: + clk_plane = 12; + break; + } for (auto &usr : clk_net->users) { std::priority_queue, std::greater> visit; @@ -123,7 +136,7 @@ void GateMateImpl::route_clock() continue; auto cpe_loc = ctx->getBelLocation(usr.cell->bel); - auto is_glb_clk = clk_net->driver.cell->type == id_BUFG; + auto is_glb_clk = clk_net->driver.cell->type == id_GLBOUT; auto sink_wire = ctx->getNetinfoSinkWire(clk_net, usr, 0); if (ctx->debug) {