diff --git a/himbaechel/uarch/gatemate/bitstream.cc b/himbaechel/uarch/gatemate/bitstream.cc index 73574554..d36c6345 100644 --- a/himbaechel/uarch/gatemate/bitstream.cc +++ b/himbaechel/uarch/gatemate/bitstream.cc @@ -118,6 +118,10 @@ struct BitstreamBackend 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: for (auto &p : params) { cc.tiles[loc].add_word(stringf("GPIO.%s", p.first.c_str(ctx)), p.second.as_bits()); } diff --git a/himbaechel/uarch/gatemate/ccf.cc b/himbaechel/uarch/gatemate/ccf.cc index f29d7e2b..b601ea8b 100644 --- a/himbaechel/uarch/gatemate/ccf.cc +++ b/himbaechel/uarch/gatemate/ccf.cc @@ -77,7 +77,7 @@ struct GateMateCCFReader 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()) log_error("Unknown location '%s' used in line %d.\n", value.c_str(), lineno); - props->emplace(ctx->id("PIN_NAME"), Property(value)); + props->emplace(id_LOC, Property(value)); } else if (name == "SCHMITT_TRIGGER" || name == "PULLUP" || name == "PULLDOWN" || name == "KEEPER" || name == "FF_IBF" || name == "FF_OBF" || name == "LVDS_BOOST" || name == "LVDS_RTERM") { if (value == "TRUE") { diff --git a/himbaechel/uarch/gatemate/constids.inc b/himbaechel/uarch/gatemate/constids.inc index 4f3e0d5b..1ac219f1 100644 --- a/himbaechel/uarch/gatemate/constids.inc +++ b/himbaechel/uarch/gatemate/constids.inc @@ -63,6 +63,7 @@ X(IO_N) X(OUT3) X(OUT4) +X(LOC) X(PIN_NAME) X(PIN_NAME_P) X(PIN_NAME_N) @@ -84,7 +85,8 @@ X(OE_ENABLE) X(OUT_SIGNAL) X(INPUT_ENABLE) X(OUT23_14_SEL) - +X(LVDS_EN) +X(LVDS_IE) X(INIT_L00) X(INIT_L01) X(INIT_L02) diff --git a/himbaechel/uarch/gatemate/pack.cc b/himbaechel/uarch/gatemate/pack.cc index 6145751c..e6b5aa48 100644 --- a/himbaechel/uarch/gatemate/pack.cc +++ b/himbaechel/uarch/gatemate/pack.cc @@ -90,15 +90,22 @@ void GateMatePacker::pack_io() for (auto &attrs : ci->attrs) top_port.cell->attrs[attrs.first] = attrs.second; for (auto ¶ms : ci->params) { - if (top_port.cell->params.count(params.first)) { - if (top_port.cell->params[params.first] != params.second) { + IdString key = params.first; + if (top_port.cell->type.in(id_CC_LVDS_IBUF, id_CC_LVDS_OBUF, id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF)) { + if (top_port.port.in(id_I_P, id_O_P, id_IO_P)) + key = id_PIN_NAME_P; + if (top_port.port.in(id_I_N, id_O_N, id_IO_N)) + key = id_PIN_NAME_N; + } + if (top_port.cell->params.count(key)) { + if (top_port.cell->params[key] != params.second) { std::string val = params.second.is_string ? params.second.as_string() : std::to_string(params.second.as_int64()); - log_warning("Overriding parameter '%s' with value '%s' for cell '%s'.\n", - params.first.c_str(ctx), val.c_str(), ctx->nameOf(top_port.cell)); + log_warning("Overriding parameter '%s' with value '%s' for cell '%s'.\n", key.c_str(ctx), + val.c_str(), ctx->nameOf(top_port.cell)); } } - top_port.cell->params[params.first] = params.second; + top_port.cell->params[key] = params.second; } // Make sure that top level net is set correctly @@ -112,19 +119,41 @@ void GateMatePacker::pack_io() 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)) + 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)) continue; - std::string loc = str_or_default(ci.params, id_PIN_NAME, "UNPLACED"); + + bool is_lvds = ci.type.in(id_CC_LVDS_IBUF, id_CC_LVDS_OBUF, id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF); + + std::string loc = str_or_default(ci.params, is_lvds ? id_PIN_NAME_P : id_PIN_NAME, "UNPLACED"); + if (ci.params.count(id_LOC)) { + std::string new_loc = str_or_default(ci.params, id_LOC, "UNPLACED"); + if (loc != "UNPLACED" && loc != new_loc) + log_warning("Overriding location of cell '%s' from '%s' with '%s'\n", ctx->nameOf(&ci), loc.c_str(), + new_loc.c_str()); + loc = new_loc; + } + if (loc == "UNPLACED") log_warning("IO signal name '%s' is not defined in CCF file and will be auto-placed.\n", ctx->nameOf(&ci)); disconnect_if_gnd(&ci, id_T); if (ci.type == id_CC_TOBUF && !ci.getPort(id_T)) ci.type = id_CC_OBUF; + if (ci.type == id_CC_LVDS_TOBUF && !ci.getPort(id_T)) + ci.type = id_CC_LVDS_OBUF; std::vector keys; for (auto &p : ci.params) { - if (p.first.in(id_PIN_NAME, id_V_IO)) { + + if (p.first.in(id_PIN_NAME, id_PIN_NAME_P, id_PIN_NAME_N)) { + if (ctx->get_package_pin_bel(ctx->id(p.second.as_string())) == BelId()) + log_error("Unknown %s '%s' for cell '%s'.\n", p.first.c_str(ctx), p.second.as_string().c_str(), + ci.name.c_str(ctx)); + keys.push_back(p.first); + continue; + } + if (p.first.in(id_V_IO, id_LOC)) { keys.push_back(p.first); continue; } @@ -136,6 +165,11 @@ void GateMatePacker::pack_io() if (ci.type.in(id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF) && p.first.in(id_DRIVE, id_SLEW, id_DELAY_OBF, id_FF_OBF)) continue; + if (ci.type.in(id_CC_LVDS_IBUF, id_CC_LVDS_IOBUF) && p.first.in(id_LVDS_RTERM, id_DELAY_IBF, id_FF_IBF)) + continue; + if (ci.type.in(id_CC_LVDS_OBUF, id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF) && + p.first.in(id_LVDS_BOOST, id_DELAY_OBF, id_FF_OBF)) + continue; log_warning("Removing unsupported parameter '%s' for type '%s'.\n", p.first.c_str(ctx), ci.type.c_str(ctx)); keys.push_back(p.first); } @@ -150,19 +184,37 @@ void GateMatePacker::pack_io() else log_error("Unknown value '%s' for SLEW parameter of '%s' cell.\n", val.c_str(), ci.name.c_str(ctx)); } + if (is_lvds) { + std::string p_pin = str_or_default(ci.params, id_PIN_NAME_P, "UNPLACED"); + std::string n_pin = str_or_default(ci.params, id_PIN_NAME_N, "UNPLACED"); + if (p_pin == "UNPLACED" || n_pin == "UNPLACED") + log_error("Both LVDS pins must be set to a valid locations.\n"); + if (p_pin.substr(0, 6) != n_pin.substr(0, 6) || p_pin[7] != n_pin[7]) + log_error("Both LVDS pads '%s' and '%s' do not match.\n", p_pin.c_str(), n_pin.c_str()); + if (p_pin[6] != 'A') + log_error("Both LVDS positive pad must be from type A.\n"); + if (n_pin[6] != 'B') + log_error("Both LVDS negative pad must be from type B.\n"); + } for (auto key : keys) ci.params.erase(key); if ((ci.params.count(id_KEEPER) + ci.params.count(id_PULLUP) + ci.params.count(id_PULLDOWN)) > 1) log_error("PULLUP, PULLDOWN and KEEPER are mutually exclusive parameters.\n"); + if (is_lvds) + ci.params[id_LVDS_EN] = Property(Property::State::S1); + // DELAY_IBF and DELAY_OBF must be set depending of type // Also we need to enable input/output - if (ci.type.in(id_CC_IBUF, id_CC_IOBUF)) { + if (ci.type.in(id_CC_IBUF, id_CC_IOBUF, id_CC_LVDS_IBUF, id_CC_LVDS_IOBUF)) { ci.params[id_DELAY_IBF] = Property(1 << int_or_default(ci.params, id_DELAY_IBF, 0), 16); - ci.params[id_INPUT_ENABLE] = Property(Property::State::S1); + if (is_lvds) + ci.params[id_LVDS_IE] = Property(Property::State::S1); + else + ci.params[id_INPUT_ENABLE] = Property(Property::State::S1); } - if (ci.type.in(id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF)) { + if (ci.type.in(id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF, id_CC_LVDS_OBUF, id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF)) { ci.params[id_DELAY_OBF] = Property(1 << int_or_default(ci.params, id_DELAY_OBF, 0), 16); ci.params[id_OE_ENABLE] = Property(Property::State::S1); } @@ -173,7 +225,8 @@ void GateMatePacker::pack_io() ci.params[id_DRIVE] = Property((val - 3) / 3, 2); } for (auto &p : ci.params) { - if (p.first.in(id_PULLUP, id_PULLDOWN, id_KEEPER, id_SCHMITT_TRIGGER, id_FF_OBF, id_FF_IBF)) { + if (p.first.in(id_PULLUP, id_PULLDOWN, id_KEEPER, id_SCHMITT_TRIGGER, id_FF_OBF, id_FF_IBF, id_LVDS_RTERM, + id_LVDS_BOOST)) { int val = int_or_default(ci.params, p.first, 0); if (val != 0 && val != 1) log_error("Unsupported value '%d' for %s parameter of '%s' cell.\n", val, p.first.c_str(ctx), @@ -186,6 +239,12 @@ void GateMatePacker::pack_io() 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); // Remap ports to GPIO bel ci.renamePort(id_A, id_DO); @@ -208,7 +267,10 @@ void GateMatePacker::pack_io() 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()); - + 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); } }