diff options
author | Ross Schlaikjer <ross@schlaikjer.net> | 2020-04-29 14:39:52 -0400 |
---|---|---|
committer | Ross Schlaikjer <ross@schlaikjer.net> | 2020-04-29 14:39:52 -0400 |
commit | 0043ae0807affd77749b162199cd4da3b37d994c (patch) | |
tree | 8e8bf6c08a8af5990688f4306ab7d537f8f274aa /ecp5 | |
parent | 66252849506738f16c70bc8d78486500aaccd84c (diff) | |
download | nextpnr-0043ae0807affd77749b162199cd4da3b37d994c.tar.gz nextpnr-0043ae0807affd77749b162199cd4da3b37d994c.tar.bz2 nextpnr-0043ae0807affd77749b162199cd4da3b37d994c.zip |
Issue warning for mixed-mode inputs
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/arch.cc | 35 | ||||
-rw-r--r-- | ecp5/archdefs.h | 4 | ||||
-rw-r--r-- | ecp5/pack.cc | 47 |
3 files changed, 46 insertions, 40 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 7dd85b70..4e149806 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -938,29 +938,19 @@ 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) + return cell->multInfo.is_clocked ? TMG_REGISTER_INPUT : TMG_COMB_INPUT; + if (port == id_RST0 || port == id_RST1 || port == id_RST2 || port == id_RST3) + return cell->multInfo.is_clocked ? TMG_REGISTER_INPUT : TMG_COMB_INPUT; + if (port == id_SIGNEDA || port == id_SIGNEDB) + return cell->multInfo.is_clocked ? TMG_REGISTER_INPUT : TMG_COMB_INPUT; std::string pname = port.str(this); if (pname.size() > 1) { - if (pname.front() == 'A' && std::isdigit(pname.at(1))) { - if (cell->multInfo.is_in_a_registered) { - clockInfoCount = 1; + if ((pname.front() == 'A' || pname.front() == 'B' || pname.front() == 'P') && std::isdigit(pname.at(1))) + if (cell->multInfo.is_clocked) return TMG_REGISTER_INPUT; - } - return TMG_COMB_INPUT; - } - if (pname.front() == 'B' && std::isdigit(pname.at(1))) { - if (cell->multInfo.is_in_b_registered) { - clockInfoCount = 1; - return TMG_REGISTER_INPUT; - } - return TMG_COMB_INPUT; - } - if (pname.front() == 'P' && std::isdigit(pname.at(1))) { - if (cell->multInfo.is_output_registered) { - clockInfoCount = 1; - return TMG_REGISTER_OUTPUT; - } - return TMG_COMB_OUTPUT; - } + + return TMG_COMB_INPUT; } return TMG_IGNORE; } else if (cell->type == id_ALU54B) { @@ -1143,16 +1133,12 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port return base.compare(0, prefix.size(), prefix) == 0; }; IdString port_group; - IdString clock_id = id_CLK0; 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; - // If the output is registered, we care about propagation delay from CLK. - // If it is not registered, our propagation delay is from A/B - clock_id = cell->multInfo.is_output_registered ? id_CLK0 : id_A; } else if (has_prefix(port_name, "CE")) { port_group = id_CE0; } else if (has_prefix(port_name, "RST")) { @@ -1165,6 +1151,7 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port } // If this port is clocked at all, it must be clocked from CLK0 + IdString clock_id = id_CLK0; 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); diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index d32e4a23..586c385f 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -190,9 +190,7 @@ struct ArchCellInfo } ramInfo; struct { - bool is_in_a_registered; - bool is_in_b_registered; - bool is_output_registered; + bool is_clocked; nextpnr_ecp5::IdString timing_id; } multInfo; }; diff --git a/ecp5/pack.cc b/ecp5/pack.cc index b92a2dfd..1c1df2ee 100644 --- a/ecp5/pack.cc +++ b/ecp5/pack.cc @@ -3052,26 +3052,47 @@ void Arch::assignArchInfo() log_error("MULT18X18D %s has invalid REG_INPUTB_CLK configuration '%s'\n", ci->name.c_str(this), reg_inputb_clk.c_str()); // Inputs are registered IFF the REG_INPUT value is not NONE - ci->multInfo.is_in_a_registered = reg_inputa_clk != "NONE"; - ci->multInfo.is_in_b_registered = reg_inputb_clk != "NONE"; + const bool is_in_a_registered = reg_inputa_clk != "NONE"; + const bool is_in_b_registered = reg_inputb_clk != "NONE"; // Similarly, get the output register clock std::string reg_output_clk = str_or_default(ci->params, id("REG_OUTPUT_CLK"), "NONE"); if (reg_output_clk != "NONE" && reg_output_clk != "CLK0" && reg_output_clk != "CLK1" && reg_output_clk != "CLK2" && reg_output_clk != "CLK3") log_error("MULT18X18D %s has invalid REG_OUTPUT_CLK configuration '%s'\n", ci->name.c_str(this), reg_output_clk.c_str()); - ci->multInfo.is_output_registered = reg_output_clk != "NONE"; - // Based on our register settings, pick the timing data to use for this cell - const bool both_inputs_registered = ci->multInfo.is_in_a_registered && ci->multInfo.is_in_b_registered; - if (!both_inputs_registered && !ci->multInfo.is_output_registered) { - ci->multInfo.timing_id = id_MULT18X18D_REGS_NONE; - } else if (both_inputs_registered && !ci->multInfo.is_output_registered) { - ci->multInfo.timing_id = id_MULT18X18D_REGS_INPUT; - } else if (!both_inputs_registered && ci->multInfo.is_output_registered) { - ci->multInfo.timing_id = id_MULT18X18D_REGS_OUTPUT; - } else if (both_inputs_registered && ci->multInfo.is_output_registered) { - ci->multInfo.timing_id = id_MULT18X18D_REGS_ALL; + const bool is_output_registered = reg_output_clk != "NONE"; + + // If only one of the inputs is registered, we are going to treat that as + // neither input registered so that we don't have to deal with mixed timing. + // Emit a warning to that effect. + const bool any_input_registered = is_in_a_registered || is_in_b_registered; + const bool both_inputs_registered = is_in_a_registered && is_in_b_registered; + const bool input_registers_mismatched = any_input_registered && !both_inputs_registered; + if (input_registers_mismatched) { + log_warning("MULT18X18D %s has unsupported mixed input register modes (reg_inputa_clk=%s, " + "reg_inputb_clk=%s)\n", + ci->name.c_str(this), reg_inputa_clk.c_str(), reg_inputb_clk.c_str()); + log_warning("Timings for MULT18X18D %s will be calculated as though neither input were registered\n", + ci->name.c_str(this)); + + // Act as though the inputs are unregistered, so select timing DB based only on the + // output register mode + ci->multInfo.timing_id = is_output_registered ? id_MULT18X18D_REGS_OUTPUT : id_MULT18X18D_REGS_NONE; + } else { + // Based on our register settings, pick the timing data to use for this cell + if (!both_inputs_registered && !is_output_registered) { + ci->multInfo.timing_id = id_MULT18X18D_REGS_NONE; + } else if (both_inputs_registered && !is_output_registered) { + ci->multInfo.timing_id = id_MULT18X18D_REGS_INPUT; + } else if (!both_inputs_registered && is_output_registered) { + ci->multInfo.timing_id = id_MULT18X18D_REGS_OUTPUT; + } else if (both_inputs_registered && is_output_registered) { + ci->multInfo.timing_id = id_MULT18X18D_REGS_ALL; + } } + // If we aren't a pure combinatorial multiplier, then our timings are + // calculated with respect to CLK0 + ci->multInfo.is_clocked = ci->multInfo.timing_id != id_MULT18X18D_REGS_NONE; } } for (auto net : sorted(nets)) { |