aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYRabbit <rabbit@yrabbit.cyou>2023-04-05 20:32:44 +1000
committermyrtle <gatecat@ds0.me>2023-04-06 08:41:54 +0200
commit9bcefe46a89a1fb55ab86f2e0a3319baf1b92807 (patch)
tree94f3987f583a68b83d3fcb48e225121d44ed51b2
parent23f2877ddee51e7e69fdf2b1caaa0337e2459ce9 (diff)
downloadnextpnr-9bcefe46a89a1fb55ab86f2e0a3319baf1b92807.tar.gz
nextpnr-9bcefe46a89a1fb55ab86f2e0a3319baf1b92807.tar.bz2
nextpnr-9bcefe46a89a1fb55ab86f2e0a3319baf1b92807.zip
gowin: Add implementation of IDDR and IDDRC primitives
Simple deserialization primitives are implemented for all supported boards. Compatible with older apicula bases. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
-rw-r--r--gowin/arch.cc6
-rw-r--r--gowin/pack.cc41
2 files changed, 30 insertions, 17 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 8292e322..ce893f1b 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -1696,9 +1696,9 @@ Arch::Arch(ArchArgs args) : args(args)
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};
+ 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};
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)));
diff --git a/gowin/pack.cc b/gowin/pack.cc
index c7da985f..d40913b6 100644
--- a/gowin/pack.cc
+++ b/gowin/pack.cc
@@ -834,6 +834,11 @@ static bool is_gowin_iologic(const Context *ctx, const CellInfo *cell)
static void reconnect_ides_outs(CellInfo *ci)
{
switch (ci->type.hash()) {
+ case ID_IDDR: /* fall-through*/
+ case ID_IDDRC:
+ ci->renamePort(id_Q1, id_Q9);
+ ci->renamePort(id_Q0, id_Q8);
+ break;
case ID_IDES4:
ci->renamePort(id_Q3, id_Q9);
ci->renamePort(id_Q2, id_Q8);
@@ -1036,7 +1041,6 @@ static void pack_iologic(Context *ctx)
ci->setAttr(id_IOLOGIC_TYPE, ci->type.str(ctx));
if (ci->type == id_OSER4) {
- ci->type = id_IOLOGIC;
// two OSER4 share FCLK, check it
Loc other_loc = loc;
other_loc.z = 1 - loc.z + 2 * BelZ::iologic_z;
@@ -1061,6 +1065,7 @@ static void pack_iologic(Context *ctx)
std::unique_ptr<CellInfo> aux_cell =
create_generic_cell(ctx, id_IOLOGIC, ci->name.str(ctx) + "_AUX");
ci->setAttr(ctx->id("IOLOGIC_AUX_CELL"), ci->name.str(ctx) + "_AUX");
+ aux_cell->setAttr(id_IOLOGIC_TYPE, std::string("DUMMY"));
aux_cell->setParam(ctx->id("OUTMODE"), std::string("DDRENABLE"));
aux_cell->setAttr(ctx->id("IOLOGIC_MASTER_CELL"), ci->name.str(ctx));
aux_cell->setAttr(id_BEL, ctx->getBelName(ctx->getBelByLocation(loc)).str(ctx));
@@ -1071,10 +1076,11 @@ static void pack_iologic(Context *ctx)
aux_cell->connectPort(id_PCLK, ci->ports.at(id_PCLK).net);
}
new_cells.push_back(std::move(aux_cell));
- ci->type = id_IOLOGIC;
}
+ ci->type = id_IOLOGIC;
} break;
case ID_IDDR: /* fall-through */
+ case ID_IDDRC: /* fall-through */
case ID_IDES4: /* fall-through */
case ID_IDES8: /* fall-through */
case ID_IDES10: /* fall-through */
@@ -1098,6 +1104,10 @@ static void pack_iologic(Context *ctx)
}
std::string in_mode;
switch (ci->type.hash()) {
+ case ID_IDDR: /* fall-through */
+ case ID_IDDRC:
+ in_mode = "IDDRX1";
+ break;
case ID_IDES4:
in_mode = "IDDRX2";
break;
@@ -1131,17 +1141,19 @@ static void pack_iologic(Context *ctx)
reconnect_ides_outs(ci);
// common clock inputs
- if (ci->type == id_IDES4) {
- ci->type = id_IOLOGIC;
- // two IDER4 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_IDES4);
- 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_IDES4 || ci->type == id_IDDR || ci->type == id_IDDRC) {
+ if (ci->type == id_IDES4) {
+ // two IDER4 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_IDES4);
+ 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 {
@@ -1157,6 +1169,7 @@ static void pack_iologic(Context *ctx)
std::unique_ptr<CellInfo> aux_cell =
create_generic_cell(ctx, id_IOLOGIC, ci->name.str(ctx) + "_AUX");
ci->setAttr(ctx->id("IOLOGIC_AUX_CELL"), ci->name.str(ctx) + "_AUX");
+ aux_cell->setAttr(id_IOLOGIC_TYPE, std::string("DUMMY"));
aux_cell->setParam(ctx->id("INMODE"), std::string("DDRENABLE"));
aux_cell->setAttr(ctx->id("IOLOGIC_MASTER_CELL"), ci->name.str(ctx));
aux_cell->setAttr(id_BEL, ctx->getBelName(ctx->getBelByLocation(loc)).str(ctx));
@@ -1167,8 +1180,8 @@ static void pack_iologic(Context *ctx)
aux_cell->connectPort(id_PCLK, ci->ports.at(id_PCLK).net);
}
new_cells.push_back(std::move(aux_cell));
- ci->type = id_IOLOGIC;
}
+ ci->type = id_IOLOGIC;
} break;
default:
break;