aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/arch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/arch.cc')
-rw-r--r--ecp5/arch.cc70
1 files changed, 70 insertions, 0 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 23cdea3b..7de5c7aa 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -746,6 +746,29 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return TMG_GEN_CLOCK;
else
NPNR_ASSERT_FALSE("bad clkdiv port");
+ } else if (cell->type == id_DQSBUFM) {
+ if (port == id_READ0 || port == id_READ1) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_INPUT;
+ } else if (port == id_DATAVALID) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_OUTPUT;
+ } else if (port == id_SCLK || port == id_ECLK || port == id_DQSI) {
+ return TMG_CLOCK_INPUT;
+ } else if (port == id_DQSR90 || port == id_DQSW || port == id_DQSW270) {
+ return TMG_GEN_CLOCK;
+ }
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_STARTPOINT : TMG_ENDPOINT;
+ } else if (cell->type == id_DDRDLL) {
+ if (port == id_CLK)
+ return TMG_CLOCK_INPUT;
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_STARTPOINT : TMG_ENDPOINT;
+ } else if (cell->type == id_TRELLIS_ECLKBUF) {
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_COMB_OUTPUT : TMG_COMB_INPUT;
+ } else if (cell->type == id_ECLKSYNCB) {
+ if (cell->ports.at(port).name == id_STOP)
+ return TMG_ENDPOINT;
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_COMB_OUTPUT : TMG_COMB_INPUT;
} else {
log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this),
cell->name.c_str(this));
@@ -829,6 +852,16 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
info.setup = getDelayFromNS(0.1);
info.hold = getDelayFromNS(0);
}
+ } else if (cell->type == id_DQSBUFM) {
+ info.clock_port = id_SCLK;
+ if (port == id_DATAVALID) {
+ info.clockToQ = getDelayFromNS(0.2);
+ } else if (port == id_READ0 || port == id_READ1) {
+ info.setup = getDelayFromNS(0.5);
+ info.hold = getDelayFromNS(-0.4);
+ } else {
+ NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
+ }
}
return info;
}
@@ -850,4 +883,41 @@ GlobalInfoPOD Arch::globalInfoAtLoc(Location loc)
return chip_info->location_glbinfo[locidx];
}
+bool Arch::getPIODQSGroup(BelId pio, bool &dqsright, int &dqsrow)
+{
+ for (int i = 0; i < chip_info->num_pios; i++) {
+ if (Location(chip_info->pio_info[i].abs_loc) == pio.location && chip_info->pio_info[i].bel_index == pio.index) {
+ int dqs = chip_info->pio_info[i].dqsgroup;
+ if (dqs == -1)
+ return false;
+ else {
+ dqsright = (dqs & 2048) != 0;
+ dqsrow = dqs & 0x1FF;
+ return true;
+ }
+ }
+ }
+ NPNR_ASSERT_FALSE("failed to find PIO");
+}
+
+BelId Arch::getDQSBUF(bool dqsright, int dqsrow)
+{
+ BelId bel;
+ bel.location.y = dqsrow;
+ bel.location.x = (dqsright ? (chip_info->width - 1) : 0);
+ for (int i = 0; i < locInfo(bel)->num_bels; i++) {
+ auto &bd = locInfo(bel)->bel_data[i];
+ if (bd.type == id_DQSBUFM.index) {
+ bel.index = i;
+ return bel;
+ }
+ }
+ NPNR_ASSERT_FALSE("failed to find DQSBUF");
+}
+
+WireId Arch::getBankECLK(int bank, int eclk)
+{
+ return getWireByLocAndBasename(Location(0, 0), "G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(eclk));
+}
+
NEXTPNR_NAMESPACE_END