ecp5: Conservative analysis of comb DSP timing Signed-off-by: David Shah <dave@ds0.me>
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 5b3cc66..cb1a3cc 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc
@@ -701,6 +701,13 @@ return false; } else if (cell->type == id_DP16KD) { return false; + } else if (cell->type == id_MULT18X18D) { + std::string fn = fromPort.str(this), tn = toPort.str(this); + if (fn.size() > 1 && (fn.front() == 'A' || fn.front() == 'B') && std::isdigit(fn.at(1))) { + if (tn.size() > 1 && tn.front() == 'P' && std::isdigit(tn.at(1))) + return getDelayFromTimingDatabase(id_MULT18X18D_REGS_NONE, id(std::string("") + fn.front()), id_P, delay); + } + return false; } else if (cell->type == id_IOLOGIC || cell->type == id_SIOLOGIC) { return false; } else { @@ -778,7 +785,16 @@ } NPNR_ASSERT_FALSE_STR("no timing type for RAM port '" + port.str(this) + "'"); } else if (cell->type == id_MULT18X18D) { - return TMG_IGNORE; // FIXME + if (port == id_CLK0 || port == id_CLK1 || port == id_CLK2 || port == id_CLK3) + return TMG_CLOCK_INPUT; + std::string pname = port.str(this); + if (pname.size() > 1) { + if ((pname.front() == 'A' || pname.front() == 'B') && std::isdigit(pname.at(1))) + return TMG_COMB_INPUT; + if (pname.front() == 'P' && std::isdigit(pname.at(1))) + return TMG_COMB_OUTPUT; + } + return TMG_IGNORE; } else if (cell->type == id_ALU54B) { return TMG_IGNORE; // FIXME } else if (cell->type == id_EHXPLLL) {
diff --git a/ecp5/constids.inc b/ecp5/constids.inc index 8a3179b..007e952 100644 --- a/ecp5/constids.inc +++ b/ecp5/constids.inc
@@ -1281,4 +1281,11 @@ X(WRCFLAG) X(SCLK) -X(TRELLIS_ECLKBUF) \ No newline at end of file +X(TRELLIS_ECLKBUF) + +X(MULT18X18D_REGS_ALL) +X(MULT18X18D_REGS_INPUT) +X(MULT18X18D_REGS_NONE) +X(MULT18X18D_REGS_OUTPUT) +X(MULT18X18D_REGS_PIPELINE) +X(P) \ No newline at end of file