From 71192dc7a3b8dfae1f76f48412dd906bfb0783e7 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Fri, 14 Apr 2023 16:54:08 +1000 Subject: gowin: Remove inherited code for ODDR(c) Implement ODDR(c) as part of IOLOGIC and remove all old code associated with those primitives. Signed-off-by: YRabbit --- gowin/arch.cc | 79 +++++--------------------------------- gowin/arch.h | 1 - gowin/constids.inc | 4 +- gowin/pack.cc | 109 ++++++++++++++--------------------------------------- 4 files changed, 40 insertions(+), 153 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index 0278cd8f..6756bf9f 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -1416,7 +1416,6 @@ Arch::Arch(ArchArgs args) : args(args) IdString portname; int z = 0; bool dff = true; - bool oddrc = false; switch (static_cast(bel->type_id)) { case ID_PLLVR: belname = idf("R%dC%d_PLLVR", row + 1, col + 1); @@ -1690,82 +1689,22 @@ Arch::Arch(ArchArgs args) : args(args) break; // IO logic - case ID_ODDRCB: - z++; /* fall-through*/ - case ID_ODDRCA: - oddrc = true; - z++; /* fall-through*/ - case ID_ODDRB: - z++; /* fall-through*/ - case ID_ODDRA: { - snprintf(buf, 32, "R%dC%d_ODDR%s%c", row + 1, col + 1, oddrc ? "C" : "", 'A' + z - (oddrc ? 2 : 0)); - belname = id(buf); - addBel(belname, id_ODDR, Loc(col, row, BelZ::oddr_0_z + z), false); - - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_D0)->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_D0, id(buf)); - - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_D1)->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_D1, id(buf)); - - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_TX)->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_TX, id(buf)); - - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_CLK)->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_CLK, id(buf)); - - const PairPOD *quirk_port = pairLookup(bel->ports.get(), bel->num_ports, ID_ODDR_ALWAYS_LOW); - if (quirk_port != nullptr) { - ddr_has_extra_inputs = true; - portname = IdString(quirk_port->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_ODDR_ALWAYS_LOW, id(buf)); - } - quirk_port = pairLookup(bel->ports.get(), bel->num_ports, ID_ODDR_ALWAYS_HIGH); - if (quirk_port != nullptr) { - ddr_has_extra_inputs = true; - portname = IdString(quirk_port->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_ODDR_ALWAYS_HIGH, id(buf)); - } - - if (oddrc) { - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_CE)->src_id); - snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); - addBelInput(belname, id_CE, id(buf)); - } - - // dummy wires - snprintf(buf, 32, "ODDR%s%c_Q0", oddrc ? "C" : "", 'A' + z - (oddrc ? 2 : 0)); - IdString id_q0 = id(buf); - IdString q0_name = wireToGlobal(row, col, db, id_q0); - if (wires.count(q0_name) == 0) - addWire(q0_name, id_q0, row, col); - addBelOutput(belname, id_Q0, q0_name); - - snprintf(buf, 32, "ODDR%s%c_Q1", oddrc ? "C" : "", 'A' + z - (oddrc ? 2 : 0)); - IdString id_q1 = id(buf); - IdString q1_name = wireToGlobal(row, col, db, id_q1); - if (wires.count(q1_name) == 0) - addWire(q1_name, id_q1, row, col); - addBelOutput(belname, id_Q1, q1_name); - } break; case ID_IOLOGICB: z++; /* fall-through*/ case ID_IOLOGICA: { belname = idf("R%dC%d_IOLOGIC%c", row + 1, col + 1, 'A' + z); addBel(belname, id_IOLOGIC, Loc(col, row, BelZ::iologic_z + z), false); - IdString const iologic_in_ports[] = {id_TX0, id_TX1, id_TX2, id_TX3, id_RESET, id_CALIB, id_PCLK, - id_D, id_D0, id_D1, id_D2, id_D3, id_D4, id_D5, - id_D6, id_D7, id_D8, id_D9, id_CLK, id_CLEAR}; + IdString const iologic_in_ports[] = {id_TX, id_TX0, id_TX1, id_TX2, id_TX3, id_RESET, + id_CALIB, id_PCLK, id_D, id_D0, id_D1, id_D2, + id_D3, id_D4, id_D5, id_D6, id_D7, id_D8, + id_D9, id_CLK, id_CLEAR, id_DAADJ0, id_DAADJ1}; for (IdString port : iologic_in_ports) { - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, port.hash())->src_id); - addBelInput(belname, port, idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this))); + const PairPOD *portid = pairLookup(bel->ports.get(), bel->num_ports, port.hash()); + if (portid != nullptr) { + portname = IdString(portid->src_id); + addBelInput(belname, port, idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this))); + } } IdString const iologic_out_ports[] = {id_Q, id_Q0, id_Q1, id_Q2, id_Q3, id_Q4, id_Q5, id_Q6, id_Q7, id_Q8, id_Q9}; diff --git a/gowin/arch.h b/gowin/arch.h index 23da3661..c3e1e7dd 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -535,7 +535,6 @@ enum ioba_z = 0, // IOBA iobb_z = 1, // IOBB mux_0_z = 10, // start Z for the MUX2LUT5 bels - oddr_0_z = 20, // XXX start Z for the ODDR bels lutram_0_z = 30, // start Z for the LUTRAM bels vcc_0_z = 277, // virtual VCC bel Z gnd_0_z = 278, // virtual VSS bel Z diff --git a/gowin/constids.inc b/gowin/constids.inc index daedb8a6..3a4b0dd2 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -767,8 +767,8 @@ X(TX3) X(FCLK) X(PCLK) X(CALIB) -X(ODDR_ALWAYS_LOW) -X(ODDR_ALWAYS_HIGH) +X(DAADJ0) +X(DAADJ1) X(GW9_ALWAYS_LOW0) X(GW9_ALWAYS_LOW1) X(GW9C_ALWAYS_LOW0) diff --git a/gowin/pack.cc b/gowin/pack.cc index 2ff42e55..c9ca635b 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -903,79 +903,15 @@ static void pack_iologic(Context *ctx) CellInfo *q0_dst = nullptr; CellInfo *q1_dst = nullptr; switch (ci->type.hash()) { - case ID_ODDRC: /* fall-through*/ - case ID_ODDR: { - q0_dst = net_only_drives(ctx, ci->ports.at(id_Q0).net, is_iob, id_I); - NPNR_ASSERT(q0_dst != nullptr); - - auto iob_bel = q0_dst->attrs.find(id_BEL); - if (q0_dst->attrs.count(id_DIFF_TYPE)) { - ci->attrs[id_OBUF_TYPE] = std::string("DBUF"); - } else { - ci->attrs[id_OBUF_TYPE] = std::string("SBUF"); - } - if (iob_bel != q0_dst->attrs.end()) { - // already know there to place, no need of any cluster stuff - Loc loc = ctx->getBelLocation(ctx->getBelByNameStr(iob_bel->second.as_string())); - loc.z += BelZ::oddr_0_z; - ci->attrs[id_BEL] = ctx->getBelName(ctx->getBelByLocation(loc)).str(ctx); - } else { - // make cluster from ODDR and OBUF - ci->cluster = ci->name; - ci->constr_x = 0; - ci->constr_y = 0; - ci->constr_z = 0; - ci->constr_abs_z = false; - ci->constr_children.push_back(q0_dst); - q0_dst->cluster = ci->name; - q0_dst->constr_x = 0; - q0_dst->constr_y = 0; - q0_dst->constr_z = -BelZ::oddr_0_z; - q0_dst->constr_abs_z = false; - } - - // disconnect Q0 output: it is wired internally - delete_nets.insert(ci->ports.at(id_Q0).net->name); - q0_dst->disconnectPort(id_I); - ci->disconnectPort(id_Q0); - - ci->attrs[id_IOBUF] = 0; - // if Q1 is conected then disconnet it too - if (port_used(ci, id_Q1)) { - q1_dst = net_only_drives(ctx, ci->ports.at(id_Q1).net, is_iob, id_OEN); - if (q1_dst != nullptr) { - delete_nets.insert(ci->ports.at(id_Q1).net->name); - q0_dst->disconnectPort(id_OEN); - ci->disconnectPort(id_Q1); - ci->attrs[id_IOBUF] = 1; - } - } - // if have XXX_ inputs connect them - if (ctx->ddr_has_extra_inputs) { - ci->addInput(id_ODDR_ALWAYS_LOW); - ci->connectPort(id_ODDR_ALWAYS_LOW, ctx->nets[ctx->id("$PACKER_GND_NET")].get()); - ci->addInput(id_ODDR_ALWAYS_HIGH); - ci->connectPort(id_ODDR_ALWAYS_HIGH, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); - } - if (iob_bel != q0_dst->attrs.end()) { - IdString io_bel_name = ctx->getBelByNameStr(iob_bel->second.as_string()); - if (ctx->gw1n9_quirk && ctx->bels.at(io_bel_name).pins.count(id_GW9_ALWAYS_LOW0)) { - q0_dst->disconnectPort(id_GW9_ALWAYS_LOW0); - q0_dst->connectPort(id_GW9_ALWAYS_LOW0, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); - } - if (ctx->bels.at(io_bel_name).pins.count(id_GW9C_ALWAYS_LOW1)) { - q0_dst->disconnectPort(id_GW9C_ALWAYS_LOW1); - q0_dst->connectPort(id_GW9C_ALWAYS_LOW1, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); - } - } - } break; + case ID_ODDR: /* fall-through */ + case ID_ODDRC: /* fall-through */ case ID_OSER4: /* fall-through */ case ID_OSER8: /* fall-through */ case ID_OSER10: /* fall-through */ case ID_OVIDEO: { IdString output = id_Q; IdString output_1 = IdString(); - if (ci->type == id_OSER4 || ci->type == id_OSER8) { + if (ci->type == id_ODDR || ci->type == id_ODDRC || ci->type == id_OSER4 || ci->type == id_OSER8) { output = id_Q0; output_1 = id_Q1; } @@ -999,6 +935,10 @@ static void pack_iologic(Context *ctx) std::string out_mode; switch (ci->type.hash()) { + case ID_ODDR: + case ID_ODDRC: + out_mode = "ODDRX1"; + break; case ID_OSER4: out_mode = "ODDRX2"; break; @@ -1025,12 +965,18 @@ static void pack_iologic(Context *ctx) delete_nets.insert(ci->ports.at(output).net->name); q0_dst->disconnectPort(id_I); ci->disconnectPort(output); - bool have_XXX = - ctx->bels.at(ctx->getBelByNameStr(iob_bel->second.as_string())).pins.count(id_GW9C_ALWAYS_LOW1); - if (have_XXX) { + if (ctx->bels.at(ctx->getBelByNameStr(iob_bel->second.as_string())).pins.count(id_GW9C_ALWAYS_LOW1)) { q0_dst->disconnectPort(id_GW9C_ALWAYS_LOW1); q0_dst->connectPort(id_GW9C_ALWAYS_LOW1, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); } + if (ctx->bels.at(ctx->getBelByLocation(loc)).pins.count(id_DAADJ0)) { + ci->addInput(id_DAADJ0); + ci->connectPort(id_DAADJ0, ctx->nets[ctx->id("$PACKER_GND_NET")].get()); + } + if (ctx->bels.at(ctx->getBelByLocation(loc)).pins.count(id_DAADJ1)) { + ci->addInput(id_DAADJ1); + ci->connectPort(id_DAADJ1, ctx->nets[ctx->id("$PACKER_VCC_NET")].get()); + } // if Q1 is connected then disconnet it too if (output_1 != IdString() && port_used(ci, output_1)) { @@ -1057,16 +1003,19 @@ static void pack_iologic(Context *ctx) ci->setAttr(id_IOBUF, 0); ci->setAttr(id_IOLOGIC_TYPE, ci->type.str(ctx)); - if (ci->type == id_OSER4) { - // two OSER4 share FCLK, check it - Loc other_loc = loc; - other_loc.z = 1 - loc.z + 2 * BelZ::iologic_z; - BelId other_bel = ctx->getBelByLocation(other_loc); - CellInfo *other_cell = ctx->getBoundBelCell(other_bel); - if (other_cell != nullptr) { - NPNR_ASSERT(other_cell->type == id_OSER4); - if (ci->ports.at(id_FCLK).net != other_cell->ports.at(id_FCLK).net) { - log_error("%s and %s have differnet FCLK nets\n", ctx->nameOf(ci), ctx->nameOf(other_cell)); + if (ci->type == id_OSER4 || ci->type == id_ODDR || ci->type == id_ODDRC) { + if (ci->type == id_OSER4) { + // two OSER4 share FCLK, check it + Loc other_loc = loc; + other_loc.z = 1 - loc.z + 2 * BelZ::iologic_z; + BelId other_bel = ctx->getBelByLocation(other_loc); + CellInfo *other_cell = ctx->getBoundBelCell(other_bel); + if (other_cell != nullptr) { + NPNR_ASSERT(other_cell->type == id_OSER4); + if (ci->ports.at(id_FCLK).net != other_cell->ports.at(id_FCLK).net) { + log_error("%s and %s have differnet FCLK nets\n", ctx->nameOf(ci), + ctx->nameOf(other_cell)); + } } } } else { -- cgit v1.2.3