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 <rabbit@yrabbit.cyou>
This commit is contained in:
parent
b0a78de78f
commit
71192dc7a3
@ -1416,7 +1416,6 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
IdString portname;
|
IdString portname;
|
||||||
int z = 0;
|
int z = 0;
|
||||||
bool dff = true;
|
bool dff = true;
|
||||||
bool oddrc = false;
|
|
||||||
switch (static_cast<ConstIds>(bel->type_id)) {
|
switch (static_cast<ConstIds>(bel->type_id)) {
|
||||||
case ID_PLLVR:
|
case ID_PLLVR:
|
||||||
belname = idf("R%dC%d_PLLVR", row + 1, col + 1);
|
belname = idf("R%dC%d_PLLVR", row + 1, col + 1);
|
||||||
@ -1690,83 +1689,23 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// IO logic
|
// 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:
|
case ID_IOLOGICB:
|
||||||
z++; /* fall-through*/
|
z++; /* fall-through*/
|
||||||
case ID_IOLOGICA: {
|
case ID_IOLOGICA: {
|
||||||
belname = idf("R%dC%d_IOLOGIC%c", row + 1, col + 1, 'A' + z);
|
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);
|
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,
|
IdString const iologic_in_ports[] = {id_TX, id_TX0, id_TX1, id_TX2, id_TX3, id_RESET,
|
||||||
id_D, id_D0, id_D1, id_D2, id_D3, id_D4, id_D5,
|
id_CALIB, id_PCLK, id_D, id_D0, id_D1, id_D2,
|
||||||
id_D6, id_D7, id_D8, id_D9, id_CLK, id_CLEAR};
|
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) {
|
for (IdString port : iologic_in_ports) {
|
||||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, port.hash())->src_id);
|
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)));
|
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,
|
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};
|
id_Q5, id_Q6, id_Q7, id_Q8, id_Q9};
|
||||||
for (IdString port : iologic_out_ports) {
|
for (IdString port : iologic_out_ports) {
|
||||||
|
@ -535,7 +535,6 @@ enum
|
|||||||
ioba_z = 0, // IOBA
|
ioba_z = 0, // IOBA
|
||||||
iobb_z = 1, // IOBB
|
iobb_z = 1, // IOBB
|
||||||
mux_0_z = 10, // start Z for the MUX2LUT5 bels
|
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
|
lutram_0_z = 30, // start Z for the LUTRAM bels
|
||||||
vcc_0_z = 277, // virtual VCC bel Z
|
vcc_0_z = 277, // virtual VCC bel Z
|
||||||
gnd_0_z = 278, // virtual VSS bel Z
|
gnd_0_z = 278, // virtual VSS bel Z
|
||||||
|
@ -767,8 +767,8 @@ X(TX3)
|
|||||||
X(FCLK)
|
X(FCLK)
|
||||||
X(PCLK)
|
X(PCLK)
|
||||||
X(CALIB)
|
X(CALIB)
|
||||||
X(ODDR_ALWAYS_LOW)
|
X(DAADJ0)
|
||||||
X(ODDR_ALWAYS_HIGH)
|
X(DAADJ1)
|
||||||
X(GW9_ALWAYS_LOW0)
|
X(GW9_ALWAYS_LOW0)
|
||||||
X(GW9_ALWAYS_LOW1)
|
X(GW9_ALWAYS_LOW1)
|
||||||
X(GW9C_ALWAYS_LOW0)
|
X(GW9C_ALWAYS_LOW0)
|
||||||
|
@ -903,79 +903,15 @@ static void pack_iologic(Context *ctx)
|
|||||||
CellInfo *q0_dst = nullptr;
|
CellInfo *q0_dst = nullptr;
|
||||||
CellInfo *q1_dst = nullptr;
|
CellInfo *q1_dst = nullptr;
|
||||||
switch (ci->type.hash()) {
|
switch (ci->type.hash()) {
|
||||||
|
case ID_ODDR: /* fall-through */
|
||||||
case ID_ODDRC: /* fall-through */
|
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_OSER4: /* fall-through */
|
case ID_OSER4: /* fall-through */
|
||||||
case ID_OSER8: /* fall-through */
|
case ID_OSER8: /* fall-through */
|
||||||
case ID_OSER10: /* fall-through */
|
case ID_OSER10: /* fall-through */
|
||||||
case ID_OVIDEO: {
|
case ID_OVIDEO: {
|
||||||
IdString output = id_Q;
|
IdString output = id_Q;
|
||||||
IdString output_1 = IdString();
|
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 = id_Q0;
|
||||||
output_1 = id_Q1;
|
output_1 = id_Q1;
|
||||||
}
|
}
|
||||||
@ -999,6 +935,10 @@ static void pack_iologic(Context *ctx)
|
|||||||
|
|
||||||
std::string out_mode;
|
std::string out_mode;
|
||||||
switch (ci->type.hash()) {
|
switch (ci->type.hash()) {
|
||||||
|
case ID_ODDR:
|
||||||
|
case ID_ODDRC:
|
||||||
|
out_mode = "ODDRX1";
|
||||||
|
break;
|
||||||
case ID_OSER4:
|
case ID_OSER4:
|
||||||
out_mode = "ODDRX2";
|
out_mode = "ODDRX2";
|
||||||
break;
|
break;
|
||||||
@ -1025,12 +965,18 @@ static void pack_iologic(Context *ctx)
|
|||||||
delete_nets.insert(ci->ports.at(output).net->name);
|
delete_nets.insert(ci->ports.at(output).net->name);
|
||||||
q0_dst->disconnectPort(id_I);
|
q0_dst->disconnectPort(id_I);
|
||||||
ci->disconnectPort(output);
|
ci->disconnectPort(output);
|
||||||
bool have_XXX =
|
if (ctx->bels.at(ctx->getBelByNameStr(iob_bel->second.as_string())).pins.count(id_GW9C_ALWAYS_LOW1)) {
|
||||||
ctx->bels.at(ctx->getBelByNameStr(iob_bel->second.as_string())).pins.count(id_GW9C_ALWAYS_LOW1);
|
|
||||||
if (have_XXX) {
|
|
||||||
q0_dst->disconnectPort(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());
|
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 Q1 is connected then disconnet it too
|
||||||
if (output_1 != IdString() && port_used(ci, output_1)) {
|
if (output_1 != IdString() && port_used(ci, output_1)) {
|
||||||
@ -1057,6 +1003,7 @@ static void pack_iologic(Context *ctx)
|
|||||||
ci->setAttr(id_IOBUF, 0);
|
ci->setAttr(id_IOBUF, 0);
|
||||||
ci->setAttr(id_IOLOGIC_TYPE, ci->type.str(ctx));
|
ci->setAttr(id_IOLOGIC_TYPE, ci->type.str(ctx));
|
||||||
|
|
||||||
|
if (ci->type == id_OSER4 || ci->type == id_ODDR || ci->type == id_ODDRC) {
|
||||||
if (ci->type == id_OSER4) {
|
if (ci->type == id_OSER4) {
|
||||||
// two OSER4 share FCLK, check it
|
// two OSER4 share FCLK, check it
|
||||||
Loc other_loc = loc;
|
Loc other_loc = loc;
|
||||||
@ -1066,7 +1013,9 @@ static void pack_iologic(Context *ctx)
|
|||||||
if (other_cell != nullptr) {
|
if (other_cell != nullptr) {
|
||||||
NPNR_ASSERT(other_cell->type == id_OSER4);
|
NPNR_ASSERT(other_cell->type == id_OSER4);
|
||||||
if (ci->ports.at(id_FCLK).net != other_cell->ports.at(id_FCLK).net) {
|
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));
|
log_error("%s and %s have differnet FCLK nets\n", ctx->nameOf(ci),
|
||||||
|
ctx->nameOf(other_cell));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user