aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/arch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'ecp5/arch.cc')
-rw-r--r--ecp5/arch.cc69
1 files changed, 64 insertions, 5 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index ab24842e..db043f35 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -852,10 +852,12 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
} else if (cell->type == id_DP16KD) {
return false;
} else if (cell->type == id_MULT18X18D) {
+ if (cell->multInfo.is_clocked)
+ return false;
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,
+ return getDelayFromTimingDatabase(cell->multInfo.timing_id, id(std::string("") + fn.front()), id_P,
delay);
}
return false;
@@ -938,12 +940,33 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
} else if (cell->type == id_MULT18X18D) {
if (port == id_CLK0 || port == id_CLK1 || port == id_CLK2 || port == id_CLK3)
return TMG_CLOCK_INPUT;
+ if (port == id_CE0 || port == id_CE1 || port == id_CE2 || port == id_CE3 || port == id_RST0 ||
+ port == id_RST1 || port == id_RST2 || port == id_RST3 || port == id_SIGNEDA || port == id_SIGNEDB) {
+ if (cell->multInfo.is_clocked) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_INPUT;
+ } else {
+ return TMG_COMB_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;
+ if ((pname.front() == 'A' || pname.front() == 'B') && std::isdigit(pname.at(1))) {
+ if (cell->multInfo.is_clocked) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_INPUT;
+ } else {
+ return TMG_COMB_INPUT;
+ }
+ }
+ if ((pname.front() == 'P') && std::isdigit(pname.at(1))) {
+ if (cell->multInfo.is_clocked) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_OUTPUT;
+ } else {
+ return TMG_COMB_OUTPUT;
+ }
+ }
}
return TMG_IGNORE;
} else if (cell->type == id_ALU54B) {
@@ -1117,6 +1140,42 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
} else {
NPNR_ASSERT_FALSE("unknown DQSBUFM register port");
}
+ } else if (cell->type == id_MULT18X18D) {
+ std::string port_name = port.str(this);
+ // To keep the timing DB small, like signals (e.g. P[35:0] have been
+ // grouped. To look up the timing, we therefore need to map this port
+ // to the enclosing port group.
+ auto has_prefix = [](std::string base, std::string prefix) {
+ return base.compare(0, prefix.size(), prefix) == 0;
+ };
+ IdString port_group;
+ if (has_prefix(port_name, "A")) {
+ port_group = id_A;
+ } else if (has_prefix(port_name, "B")) {
+ port_group = id_B;
+ } else if (has_prefix(port_name, "P")) {
+ port_group = id_P;
+ } else if (has_prefix(port_name, "CE")) {
+ port_group = id_CE0;
+ } else if (has_prefix(port_name, "RST")) {
+ port_group = id_RST0;
+ } else if (has_prefix(port_name, "SIGNED")) {
+ // Both SIGNEDA and SIGNEDB exist in the DB, so can directly use these here
+ port_group = port;
+ } else {
+ NPNR_ASSERT_FALSE("Unknown MULT18X18D register port");
+ }
+
+ // If this port is clocked at all, it must be clocked from CLK0
+ IdString clock_id = id_CLK0;
+ info.clock_port = clock_id;
+ info.edge = RISING_EDGE;
+ if (cell->ports.at(port).type == PORT_OUT) {
+ bool is_path = getDelayFromTimingDatabase(cell->multInfo.timing_id, clock_id, port_group, info.clockToQ);
+ NPNR_ASSERT(is_path);
+ } else {
+ getSetupHoldFromTimingDatabase(cell->multInfo.timing_id, clock_id, port_group, info.setup, info.hold);
+ }
}
return info;
}