so, I spent all night on this bug, and fedi thinks that a write-up of that might be useful for other people.
the symptoms
going into this, all I really knew was that the reporter said it was correlated to usage of the M10Ks in nextpnr-mistral. let's run it and see.
$ ~/nextpnr/build-mistral/nextpnr-mistral --device ms --json blink_rgb.json --rbf blink_rgb.rbf --freq 50 --qsf io.qsf
Info: Initialising bels...
Info: Initialising routing graph...
Info: imported 2739969 wires and 25465239 pips
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_2' to pin PIN_W15 (bel MISTRAL_IO.89.8.1)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_1' to pin PIN_AA24 (bel MISTRAL_IO.89.9.2)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD' to pin PIN_V16 (bel MISTRAL_IO.89.9.0)
Info: Constraining IO 'blink_rgb_0.i_reset_n_MISTRAL_IB_O' to pin PIN_AH17 (bel MISTRAL_IO.64.0.2)
Info: Constraining IO 'i_clock_MISTRAL_IB_PAD' to pin PIN_V11 (bel MISTRAL_IO.32.0.0)
Info: Annotating ports with timing budgets for target frequency 50.00 MHz
Info: Checksum: 0x12b4a4b4
Info: Device utilisation:
Info: MISTRAL_COMB: 253/83820 0%
Info: MISTRAL_FF: 103/167640 0%
Info: MISTRAL_IO: 5/ 472 1%
Info: MISTRAL_CLKENA: 1/ 2 50%
Info: cyclonev_oscillator: 0/ 1 0%
Info: cyclonev_hps_interface_mpu_general_purpose: 0/ 1 0%
Info: MISTRAL_M10K: 16/ 553 2%
Info: Placed 0 cells based on constraints.
Info: Creating initial analytic placement for 226 cells, random placement wirelen = 33762.
Info: at initial placer iter 0, wirelen = 167
Info: at initial placer iter 1, wirelen = 159
Info: at initial placer iter 2, wirelen = 139
Info: at initial placer iter 3, wirelen = 139
Info: Running main analytical placer, max placement attempts per cell = 17860.
Info: at iteration #1, type MISTRAL_FF: wirelen solved = 756, spread = 1355, legal = 1526; time = 0.01s
Info: at iteration #1, type MISTRAL_COMB: wirelen solved = 963, spread = 2087, legal = 2091; time = 0.01s
Info: at iteration #1, type MISTRAL_M10K: wirelen solved = 1966, spread = 3097, legal = 3098; time = 0.01s
Info: at iteration #1, type MISTRAL_CLKENA: wirelen solved = 3098, spread = 3098, legal = 3260; time = 0.00s
Info: at iteration #1, type ALL: wirelen solved = 151, spread = 2739, legal = 3071; time = 0.01s
terminate called after throwing an instance of 'std::out_of_range'
what(): dict::at()
Aborted (core dumped)
hmm, a crash in the analytical placer. odd.
dict is nextpnr's implementation of std::unordered_map if people were wondering; we use our own implementation to have identical behaviour across platforms.
the stack trace
#0 0x00007ffff73aa26c in ?? () from /usr/lib/libc.so.6
#1 0x00007ffff735aa08 in raise () from /usr/lib/libc.so.6
#2 0x00007ffff7343538 in abort () from /usr/lib/libc.so.6
#3 0x00007ffff76bba6f in __gnu_cxx::__verbose_terminate_handler ()
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/vterminate.cc:95
#4 0x00007ffff76cf11c in __cxxabiv1::__terminate (handler=<optimized out>)
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:48
#5 0x00007ffff76cf189 in std::terminate () at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:58
#6 0x00007ffff76cf3ed in __cxxabiv1::__cxa_throw (obj=<optimized out>,
tinfo=0x7ffff788b0e8 <typeinfo for std::out_of_range>, dest=0x7ffff76e75c0 <std::out_of_range::~out_of_range()>)
at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_throw.cc:98
#7 0x000055555564396e in nextpnr_mistral::dict<nextpnr_mistral::IdString, nextpnr_mistral::ArchPinInfo, nextpnr_mistral::hash_ops<nextpnr_mistral::IdString> >::at (this=<optimized out>, key=...)
at /home/lofty/nextpnr/common/kernel/hashlib.h:597
#8 0x0000555555695e69 in nextpnr_mistral::Arch::getBelPinsForCellPin (this=0x555566b67a20, pin=...,
cell_info=<optimized out>) at /home/lofty/nextpnr/mistral/arch.h:446
#9 nextpnr_mistral::Context::predictArcDelay (this=0x555566b67a20, net_info=0x55558bfcf000, sink=...)
at /home/lofty/nextpnr/common/kernel/context.cc:104
#10 0x00005555556ce13d in nextpnr_mistral::TimingAnalyser::get_route_delays (this=0x7fffffffb780)
at /home/lofty/nextpnr/common/kernel/timing.cc:145
#11 nextpnr_mistral::TimingAnalyser::run (this=0x7fffffffb780, update_route_delays=<optimized out>)
at /home/lofty/nextpnr/common/kernel/timing.cc:50
#12 0x000055555573b1bc in nextpnr_mistral::HeAPPlacer::place (this=0x7fffffffb600)
at /home/lofty/nextpnr/common/place/placer_heap.cc:281
#13 nextpnr_mistral::placer_heap (cfg=..., ctx=<optimized out>) at /home/lofty/nextpnr/common/place/placer_heap.cc:1812
#14 nextpnr_mistral::Arch::place (this=0x555566b67a20) at /home/lofty/nextpnr/mistral/arch.cc:471
#15 0x000055555579f1e4 in nextpnr_mistral::CommandHandler::executeMain(std::unique_ptr<nextpnr_mistral::Context, std::default_delete<nextpnr_mistral::Context> >) [clone .constprop.0] (this=this@entry=0x7fffffffc640,
ctx=std::unique_ptr<nextpnr_mistral::Context> = {...}) at /home/lofty/nextpnr/common/kernel/command.cc:469
the relevant frame here is #8: there's a crash in getBelPinsForCellPin. that function looks like this:
there's not much to go wrong here; the only call to at is the pin_data.at(pin), which suggests that pin doesn't exist, even though it should.
what ispin, anyway?
(gdb) p pin
$1 = {index = 82}
oh, right. nextpnr uses string interning to reduce memory usage, especially for repetitive sequences, and an interned string is called an IdString. so, we need to turn this IdString into an actual string.
one does this by calling the .str method of the IdString, passing it the Arch (...more specifically, the Context, of which Arch is a derived class) which contains the string pool. this gets one a std::string, so now one calls .c_str() on that to get a C string.
(can gdb print std::strings? probably, but .str(this).c_str() is so ingrained in my muscle memory that I pretty much always use it.)
(gdb) p pin.str(this).c_str()
$3 = 0x555566b6a828 "B1DATA"
B1DATA, hm.
some background
let's step back a little: what's a "bel"? what's a "bel pin"? what's a "cell" (in this context)?
nextpnr differentiates between abstract models of how the hardware can be configured - cells - from the concrete model of how the hardware actually is - bels.
for example, a cell might be a LUT generated by Yosys, but the corresponding bel would be an ALM, which is a bit more complicated.
as one might see from the diagram, there needs to be a mapping from the inputs and outputs of an abstract cell to the concrete bel that will implement it: those bel inputs and outputs are "bel pins".
now, for some bels, you can use a static template, but the M10Ks need to have different cell-pin-to-bel-pin mappings depending on the configuration.
the M10K 10-kilobit memory block
before I go into the code, I think it's worth describing why the code is what it is.
internally, the M10K is 40 sub-blocks of 8-bit address by 1-bit data; this gives a range of 8-bit address by 40-bit data, 9-bit address by 20-bit data, 10-bit address by 10-bit data, 11-bit address by 5-bit data, 12-bit address by 2-bit data, and 13-bit address by 1-bit data.
it has two ports, each port containing a 12-bit address, a 20-bit data input and a 20-bit data output, plus read/write enables.
there is an internal data read multiplexer, but no corresponding data write demultiplexer, so one must manually wire up the write port.
40-bit data mode...might be the subject of another post.
for 20-bit data mode, this is easy enough: data bit N goes to DATAAIN[N].
for 10-bit data mode, data bit N goes to the above and DATAAIN[N+10].
for 5-bit data mode, data bit N goes to the above, DATAAIN[N+5], and DATAAIN[N+15].
for 2-bit data mode, data bit N goes to the above, DATAAIN[N+2], DATAAIN[N+7], DATAAIN[N+12], DATAAIN[N+17].
for 1-bit data mode, data bit N goes in every bit except DATAAIN[4], DATAAIN[9], DATAAIN[14], and DATAAIN[19].
now, one may ask where the 13th address bit for 13x1-bit mode comes from; "obviously", it comes from DATAAIN[4].
it's an annoying exception to the rule, and printf debugging showed that this is where the problem lies.
the code
(this code has been lightly edited for clarity, but the bug(s) remains)
void setup_m10ks()
{
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
if (ci->type != id_MISTRAL_M10K)
continue;
auto abits = ci->params.at(id_CFG_ABITS).as_int64();
auto dbits = ci->params.at(id_CFG_DBITS).as_int64();
NPNR_ASSERT(abits >= 7 && abits <= 13);
NPNR_ASSERT(dbits == 1 || dbits == 2 || dbits == 5 || dbits == 10 || dbits == 20);
// Quartus doesn't seem to generate ADDRSTALL[AB], BYTEENABLE[AB][01].
// It *does* generate ACLR[01] but leaves them unconnected if unused.
// Enables.
// RDEN[1] and WREN[0] are left unconnected.
ci->pin_data[ctx->id("A1EN")].bel_pins = {ctx->id("WREN[1]")};
ci->pin_data[ctx->id("B1EN")].bel_pins = {ctx->id("RDEN[0]")};
// Clocks.
ci->pin_data[ctx->id("CLK1")].bel_pins = {ctx->id("CLKIN[0]")};
// Clock enables left unconnected.
// Address lines.
int addr_offset = std::max(12 - std::max(abits, 9L), 0L);
int bit_offset = (abits == 13);
if (abits == 13) {
ci->pin_data[ctx->id("A1ADDR[0]")].bel_pins = {ctx->id("DATAAIN[4]")};
ci->pin_data[ctx->id("B1ADDR[0]")].bel_pins = {ctx->id("DATABIN[19]")};
}
for (int bit = bit_offset; bit < abits; bit++) {
ci->pin_data[ctx->idf("A1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRA[%d]", bit + addr_offset)};
ci->pin_data[ctx->idf("B1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRB[%d]", bit + addr_offset)};
}
// Data lines
std::vector<int> offsets;
offsets.push_back(0);
if (abits >= 10 && dbits <= 10) {
offsets.push_back(10);
}
if (abits >= 11 && dbits <= 5) {
offsets.push_back(5);
offsets.push_back(15);
}
if (abits >= 12 && dbits <= 2) {
offsets.push_back(2);
offsets.push_back(7);
offsets.push_back(12);
offsets.push_back(17);
}
if (abits == 13 && dbits == 1) {
offsets.push_back(1);
offsets.push_back(3);
offsets.push_back(6);
offsets.push_back(8);
offsets.push_back(11);
offsets.push_back(13);
offsets.push_back(16);
offsets.push_back(18);
}
for (int bit = 0; bit < dbits; bit++)
for (int offset : offsets)
ci->pin_data[ctx->idf("A1DATA[%d]", bit)].bel_pins.push_back(ctx->idf("DATAAIN[%d]", bit + offset));
for (int bit = 0; bit < dbits; bit++)
ci->pin_data[ctx->idf("B1DATA[%d]", bit)].bel_pins = {ctx->idf("DATABOUT[%d]", bit)};
}
}
bug the first
if you remember from earlier, the missing entry is B1DATA. at the very bottom of the function is this:
for (int bit = 0; bit < dbits; bit++)
ci->pin_data[ctx->idf("B1DATA[%d]", bit)].bel_pins = {ctx->idf("DATABOUT[%d]", bit)};
where dbits is the data width in bits. in 13x1 mode, this is 1, so, this loop assigns the IdString for DATABOUT[0] to ci->pin_data["B1DATA[0]"].bel_pins.
but it's not looking for the cell pin B1DATA[0], it's looking for the cell pin B1DATA. so, we can special-case dbits == 1, and assign to the correct cell pin names.
// snipped code as above.
// In this corner case the pin name does not have indexing
// because it's a single bit wide...
if (abits == 13 && dbits == 1) {
for (int offset : offsets)
ci->pin_data[ctx->idf("A1DATA")].bel_pins.push_back(ctx->idf("DATAAIN[%d]", offset));
ci->pin_data[ctx->idf("B1DATA")].bel_pins = {ctx->idf("DATABOUT[0]")};
continue;
}
for (int bit = 0; bit < dbits; bit++)
for (int offset : offsets)
ci->pin_data[ctx->idf("A1DATA[%d]", bit)].bel_pins.push_back(ctx->idf("DATAAIN[%d]", bit + offset));
for (int bit = 0; bit < dbits; bit++)
ci->pin_data[ctx->idf("B1DATA[%d]", bit)].bel_pins = {ctx->idf("DATABOUT[%d]", bit)};
}
}
let's compile it and run it again!
bug the second
$ ~/nextpnr/build-mistral/nextpnr-mistral --device ms --json blink_rgb.json --rbf blink_rgb.rbf --freq 50 --qsf io.qsf
Info: Initialising bels...
Info: Initialising routing graph...
Info: imported 2739969 wires and 25465239 pips
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_2' to pin PIN_W15 (bel MISTRAL_IO.89.8.1)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_1' to pin PIN_AA24 (bel MISTRAL_IO.89.9.2)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD' to pin PIN_V16 (bel MISTRAL_IO.89.9.0)
Info: Constraining IO 'blink_rgb_0.i_reset_n_MISTRAL_IB_O' to pin PIN_AH17 (bel MISTRAL_IO.64.0.2)
Info: Constraining IO 'i_clock_MISTRAL_IB_PAD' to pin PIN_V11 (bel MISTRAL_IO.32.0.0)
Info: Annotating ports with timing budgets for target frequency 50.00 MHz
Info: Checksum: 0x12b4a4b4
Info: Device utilisation:
Info: MISTRAL_COMB: 253/83820 0%
Info: MISTRAL_FF: 103/167640 0%
Info: MISTRAL_IO: 5/ 472 1%
Info: MISTRAL_CLKENA: 1/ 2 50%
Info: cyclonev_oscillator: 0/ 1 0%
Info: cyclonev_hps_interface_mpu_general_purpose: 0/ 1 0%
Info: MISTRAL_M10K: 16/ 553 2%
Info: Placed 0 cells based on constraints.
Info: Creating initial analytic placement for 226 cells, random placement wirelen = 33762.
Info: at initial placer iter 0, wirelen = 167
Info: at initial placer iter 1, wirelen = 159
Info: at initial placer iter 2, wirelen = 139
Info: at initial placer iter 3, wirelen = 139
Info: Running main analytical placer, max placement attempts per cell = 17860.
Info: at iteration #1, type MISTRAL_FF: wirelen solved = 756, spread = 1355, legal = 1526; time = 0.07s
Info: at iteration #1, type MISTRAL_COMB: wirelen solved = 963, spread = 2087, legal = 2091; time = 0.03s
Info: at iteration #1, type MISTRAL_M10K: wirelen solved = 1966, spread = 3097, legal = 3098; time = 0.03s
Info: at iteration #1, type MISTRAL_CLKENA: wirelen solved = 3098, spread = 3098, legal = 3260; time = 0.02s
Info: at iteration #1, type ALL: wirelen solved = 151, spread = 2739, legal = 3071; time = 0.11s
Info: at iteration #2, type MISTRAL_FF: wirelen solved = 2954, spread = 2954, legal = 2954; time = 0.02s
Info: at iteration #2, type MISTRAL_COMB: wirelen solved = 2533, spread = 2663, legal = 2816; time = 0.03s
Info: at iteration #2, type MISTRAL_M10K: wirelen solved = 1444, spread = 2545, legal = 2540; time = 0.03s
Info: at iteration #2, type MISTRAL_CLKENA: wirelen solved = 2380, spread = 2380, legal = 2540; time = 0.02s
Info: at iteration #2, type ALL: wirelen solved = 241, spread = 2288, legal = 2525; time = 0.09s
Info: at iteration #3, type MISTRAL_FF: wirelen solved = 2535, spread = 2535, legal = 2558; time = 0.05s
Info: at iteration #3, type MISTRAL_COMB: wirelen solved = 2209, spread = 2589, legal = 2627; time = 0.03s
Info: at iteration #3, type MISTRAL_M10K: wirelen solved = 1379, spread = 2346, legal = 2393; time = 0.03s
Info: at iteration #3, type MISTRAL_CLKENA: wirelen solved = 2272, spread = 2272, legal = 2436; time = 0.02s
Info: at iteration #3, type ALL: wirelen solved = 277, spread = 2239, legal = 2676; time = 0.09s
Info: at iteration #4, type MISTRAL_FF: wirelen solved = 2453, spread = 2485, legal = 2578; time = 0.04s
Info: at iteration #4, type MISTRAL_COMB: wirelen solved = 2335, spread = 2563, legal = 2434; time = 0.03s
Info: at iteration #4, type MISTRAL_M10K: wirelen solved = 1301, spread = 2169, legal = 2168; time = 0.03s
Info: at iteration #4, type MISTRAL_CLKENA: wirelen solved = 1998, spread = 1998, legal = 2168; time = 0.02s
Info: at iteration #4, type ALL: wirelen solved = 284, spread = 1991, legal = 2312; time = 0.09s
Info: at iteration #5, type MISTRAL_FF: wirelen solved = 2125, spread = 2097, legal = 2135; time = 0.03s
Info: at iteration #5, type MISTRAL_COMB: wirelen solved = 1741, spread = 2248, legal = 2357; time = 0.03s
Info: at iteration #5, type MISTRAL_M10K: wirelen solved = 1501, spread = 2288, legal = 2319; time = 0.03s
Info: at iteration #5, type MISTRAL_CLKENA: wirelen solved = 2151, spread = 2151, legal = 2319; time = 0.02s
Info: at iteration #5, type ALL: wirelen solved = 271, spread = 1924, legal = 2230; time = 0.09s
Info: at iteration #6, type MISTRAL_FF: wirelen solved = 1975, spread = 1925, legal = 1930; time = 0.03s
Info: at iteration #6, type MISTRAL_COMB: wirelen solved = 1783, spread = 2011, legal = 2047; time = 0.03s
Info: at iteration #6, type MISTRAL_M10K: wirelen solved = 1268, spread = 2026, legal = 2029; time = 0.03s
Info: at iteration #6, type MISTRAL_CLKENA: wirelen solved = 1897, spread = 1897, legal = 2067; time = 0.02s
Info: at iteration #6, type ALL: wirelen solved = 375, spread = 1844, legal = 2087; time = 0.09s
Info: at iteration #7, type MISTRAL_FF: wirelen solved = 2004, spread = 1974, legal = 2001; time = 0.03s
Info: at iteration #7, type MISTRAL_COMB: wirelen solved = 1738, spread = 2205, legal = 2299; time = 0.03s
Info: at iteration #7, type MISTRAL_M10K: wirelen solved = 1562, spread = 2258, legal = 2253; time = 0.03s
Info: at iteration #7, type MISTRAL_CLKENA: wirelen solved = 2083, spread = 2083, legal = 2216; time = 0.02s
Info: at iteration #7, type ALL: wirelen solved = 387, spread = 1759, legal = 2042; time = 0.08s
Info: at iteration #8, type MISTRAL_FF: wirelen solved = 1975, spread = 1905, legal = 1945; time = 0.03s
Info: at iteration #8, type MISTRAL_COMB: wirelen solved = 1720, spread = 2004, legal = 2044; time = 0.03s
Info: at iteration #8, type MISTRAL_M10K: wirelen solved = 1350, spread = 2044, legal = 2042; time = 0.03s
Info: at iteration #8, type MISTRAL_CLKENA: wirelen solved = 1911, spread = 1911, legal = 2079; time = 0.03s
Info: at iteration #8, type ALL: wirelen solved = 489, spread = 1724, legal = 1902; time = 0.08s
Info: at iteration #9, type MISTRAL_FF: wirelen solved = 1851, spread = 1832, legal = 2005; time = 0.05s
Info: at iteration #9, type MISTRAL_COMB: wirelen solved = 1750, spread = 2052, legal = 2111; time = 0.03s
Info: at iteration #9, type MISTRAL_M10K: wirelen solved = 1395, spread = 2109, legal = 2117; time = 0.03s
Info: at iteration #9, type MISTRAL_CLKENA: wirelen solved = 1951, spread = 1951, legal = 2117; time = 0.02s
Info: at iteration #9, type ALL: wirelen solved = 370, spread = 1731, legal = 1995; time = 0.08s
Info: at iteration #10, type MISTRAL_FF: wirelen solved = 1960, spread = 2107, legal = 2141; time = 0.03s
Info: at iteration #10, type MISTRAL_COMB: wirelen solved = 1812, spread = 2145, legal = 2226; time = 0.03s
Info: at iteration #10, type MISTRAL_M10K: wirelen solved = 1509, spread = 2192, legal = 2202; time = 0.03s
Info: at iteration #10, type MISTRAL_CLKENA: wirelen solved = 2042, spread = 2042, legal = 2168; time = 0.02s
Info: at iteration #10, type ALL: wirelen solved = 423, spread = 1718, legal = 1892; time = 0.08s
Info: at iteration #11, type MISTRAL_FF: wirelen solved = 1798, spread = 1757, legal = 1788; time = 0.03s
Info: at iteration #11, type MISTRAL_COMB: wirelen solved = 1536, spread = 1738, legal = 1842; time = 0.03s
Info: at iteration #11, type MISTRAL_M10K: wirelen solved = 1209, spread = 2137, legal = 2026; time = 0.03s
Info: at iteration #11, type MISTRAL_CLKENA: wirelen solved = 1888, spread = 1888, legal = 2048; time = 0.03s
Info: at iteration #11, type ALL: wirelen solved = 477, spread = 1786, legal = 2097; time = 0.09s
Info: at iteration #12, type MISTRAL_FF: wirelen solved = 1943, spread = 1904, legal = 1919; time = 0.03s
Info: at iteration #12, type MISTRAL_COMB: wirelen solved = 1751, spread = 2170, legal = 2291; time = 0.03s
Info: at iteration #12, type MISTRAL_M10K: wirelen solved = 1580, spread = 2517, legal = 2390; time = 0.03s
Info: at iteration #12, type MISTRAL_CLKENA: wirelen solved = 2242, spread = 2242, legal = 2390; time = 0.02s
Info: at iteration #12, type ALL: wirelen solved = 544, spread = 2184, legal = 2221; time = 0.08s
Info: at iteration #13, type MISTRAL_FF: wirelen solved = 2149, spread = 2152, legal = 2248; time = 0.04s
Info: at iteration #13, type MISTRAL_COMB: wirelen solved = 1967, spread = 2696, legal = 2708; time = 0.03s
Info: at iteration #13, type MISTRAL_M10K: wirelen solved = 1965, spread = 2734, legal = 2669; time = 0.03s
Info: at iteration #13, type MISTRAL_CLKENA: wirelen solved = 2531, spread = 2531, legal = 2669; time = 0.02s
Info: at iteration #13, type ALL: wirelen solved = 599, spread = 2158, legal = 2218; time = 0.08s
Info: at iteration #14, type MISTRAL_FF: wirelen solved = 2099, spread = 2144, legal = 2143; time = 0.03s
Info: at iteration #14, type MISTRAL_COMB: wirelen solved = 1890, spread = 2381, legal = 2397; time = 0.03s
Info: at iteration #14, type MISTRAL_M10K: wirelen solved = 1613, spread = 2314, legal = 2283; time = 0.03s
Info: at iteration #14, type MISTRAL_CLKENA: wirelen solved = 2151, spread = 2151, legal = 2283; time = 0.03s
Info: at iteration #14, type ALL: wirelen solved = 673, spread = 1916, legal = 2049; time = 0.08s
Info: at iteration #15, type MISTRAL_FF: wirelen solved = 2085, spread = 2077, legal = 2095; time = 0.04s
Info: at iteration #15, type MISTRAL_COMB: wirelen solved = 1821, spread = 2250, legal = 2257; time = 0.03s
Info: at iteration #15, type MISTRAL_M10K: wirelen solved = 1471, spread = 2170, legal = 2170; time = 0.03s
Info: at iteration #15, type MISTRAL_CLKENA: wirelen solved = 2042, spread = 2042, legal = 2150; time = 0.03s
Info: at iteration #15, type ALL: wirelen solved = 593, spread = 1840, legal = 1942; time = 0.08s
Info: HeAP Placer Time: 4.88s
Info: of which solving equations: 1.94s
Info: of which spreading cells: 0.63s
Info: of which strict legalisation: 0.45s
Info: Running simulated annealing placer for refinement.
Info: at iteration #1: temp = 0.000000, timing cost = 14, wirelen = 1892
Info: at iteration #5: temp = 0.000000, timing cost = 4, wirelen = 1435
Info: at iteration #10: temp = 0.000000, timing cost = 5, wirelen = 1359
Info: at iteration #14: temp = 0.000000, timing cost = 4, wirelen = 1341
Info: SA placement time 0.81s
Info: Max frequency for clock 'blink_rgb_0.i_clock': 324.68 MHz (PASS at 50.00 MHz)
Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 16920, 17043) |****
Info: [ 17043, 17166) |****
Info: [ 17166, 17289) |*******************
Info: [ 17289, 17412) |*************************
Info: [ 17412, 17535) |*********************
Info: [ 17535, 17658) |*************
Info: [ 17658, 17781) |**********************
Info: [ 17781, 17904) |*******************
Info: [ 17904, 18027) |*****************************
Info: [ 18027, 18150) |*****************
Info: [ 18150, 18273) |***************
Info: [ 18273, 18396) |***********
Info: [ 18396, 18519) |
Info: [ 18519, 18642) |
Info: [ 18642, 18765) |
Info: [ 18765, 18888) |
Info: [ 18888, 19011) |
Info: [ 19011, 19134) |*
Info: [ 19134, 19257) |***
Info: [ 19257, 19380) |***
Info: Checksum: 0xd45ef47f
Info: Preparing LABs for routing...
Info: Routing globals...
Info: routed net 'blink_rgb_0.i_clock' using global resources
Info: Running router2...
Info: Setting up routing resources...
ERROR: No wire found for port B1ADDR[12] on destination cell blink_rgb_0.rom_0.123.0.0.0.
0 warnings, 1 error
we made it through the analytical placer at least?
I mentioned before that the M10K has 12-bit address inputs, but B1ADDR[12] (0-indexed) would refer to the 13th bit of this address input, which...doesn't exist.
// Address lines.
int addr_offset = std::max(12 - std::max(abits, 9L), 0L);
int bit_offset = (abits == 13);
if (abits == 13) {
ci->pin_data[ctx->id("A1ADDR[0]")].bel_pins = {ctx->id("DATAAIN[4]")};
ci->pin_data[ctx->id("B1ADDR[0]")].bel_pins = {ctx->id("DATABIN[19]")};
}
for (int bit = bit_offset; bit < abits; bit++) {
ci->pin_data[ctx->idf("A1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRA[%d]", bit + addr_offset)};
ci->pin_data[ctx->idf("B1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRB[%d]", bit + addr_offset)};
}
the cause of that is bit_offset. when we're in the 13x1-bit mode, the least significant bit gets stuffed in DATAAIN[4], so the least-significant bit is skipped, and the remaining bits go through the loop of being assigned. however, this leads to ADDR{A,B} starting at one instead of zero.
so, to fix this we need to subtract bit_offset to make ADDR{A,B} zero-indexed again.
there is another trick available here, but I chose not to use it due to it being a bit more surprising: if addr_offset did not have the std::max to keep it non-negative, then in 13x1 mode, addr_offset would be -1, which would correct for the one-indexing.
// Address lines.
int addr_offset = std::max(12 - std::max(abits, 9L), 0L);
int bit_offset = (abits == 13);
if (abits == 13) {
ci->pin_data[ctx->id("A1ADDR[0]")].bel_pins = {ctx->id("DATAAIN[4]")};
ci->pin_data[ctx->id("B1ADDR[0]")].bel_pins = {ctx->id("DATABIN[19]")};
}
for (int bit = bit_offset; bit < abits; bit++) {
ci->pin_data[ctx->idf("A1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRA[%d]", bit + addr_offset - bit_offset)};
ci->pin_data[ctx->idf("B1ADDR[%d]", bit)].bel_pins = {ctx->idf("ADDRB[%d]", bit + addr_offset - bit_offset)};
}
let's compile it and run it again!
[final fantasy victory sound]
$ ~/nextpnr/build-mistral/nextpnr-mistral --device ms --json blink_rgb.json --rbf blink_rgb.rbf --freq 50 --qsf io.qsf
Info: Initialising bels...
Info: Initialising routing graph...
Info: imported 2739969 wires and 25465239 pips
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_2' to pin PIN_W15 (bel MISTRAL_IO.89.8.1)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD_1' to pin PIN_AA24 (bel MISTRAL_IO.89.9.2)
Info: Constraining IO 'o_rgb_MISTRAL_OB_PAD' to pin PIN_V16 (bel MISTRAL_IO.89.9.0)
Info: Constraining IO 'blink_rgb_0.i_reset_n_MISTRAL_IB_O' to pin PIN_AH17 (bel MISTRAL_IO.64.0.2)
Info: Constraining IO 'i_clock_MISTRAL_IB_PAD' to pin PIN_V11 (bel MISTRAL_IO.32.0.0)
Info: Annotating ports with timing budgets for target frequency 50.00 MHz
Info: Checksum: 0x12b4a4b4
Info: Device utilisation:
Info: MISTRAL_COMB: 253/83820 0%
Info: MISTRAL_FF: 103/167640 0%
Info: MISTRAL_IO: 5/ 472 1%
Info: MISTRAL_CLKENA: 1/ 2 50%
Info: cyclonev_oscillator: 0/ 1 0%
Info: cyclonev_hps_interface_mpu_general_purpose: 0/ 1 0%
Info: MISTRAL_M10K: 16/ 553 2%
Info: Placed 0 cells based on constraints.
Info: Creating initial analytic placement for 226 cells, random placement wirelen = 33762.
Info: at initial placer iter 0, wirelen = 167
Info: at initial placer iter 1, wirelen = 159
Info: at initial placer iter 2, wirelen = 139
Info: at initial placer iter 3, wirelen = 139
Info: Running main analytical placer, max placement attempts per cell = 17860.
Info: at iteration #1, type MISTRAL_FF: wirelen solved = 756, spread = 1355, legal = 1526; time = 0.06s
Info: at iteration #1, type MISTRAL_COMB: wirelen solved = 963, spread = 2087, legal = 2091; time = 0.03s
Info: at iteration #1, type MISTRAL_M10K: wirelen solved = 1966, spread = 3097, legal = 3098; time = 0.03s
Info: at iteration #1, type MISTRAL_CLKENA: wirelen solved = 3098, spread = 3098, legal = 3260; time = 0.02s
Info: at iteration #1, type ALL: wirelen solved = 151, spread = 2739, legal = 3071; time = 0.11s
Info: at iteration #2, type MISTRAL_FF: wirelen solved = 2954, spread = 2954, legal = 2954; time = 0.02s
Info: at iteration #2, type MISTRAL_COMB: wirelen solved = 2533, spread = 2663, legal = 2816; time = 0.03s
Info: at iteration #2, type MISTRAL_M10K: wirelen solved = 1444, spread = 2545, legal = 2540; time = 0.03s
Info: at iteration #2, type MISTRAL_CLKENA: wirelen solved = 2380, spread = 2380, legal = 2540; time = 0.02s
Info: at iteration #2, type ALL: wirelen solved = 241, spread = 2288, legal = 2525; time = 0.09s
Info: at iteration #3, type MISTRAL_FF: wirelen solved = 2535, spread = 2535, legal = 2558; time = 0.05s
Info: at iteration #3, type MISTRAL_COMB: wirelen solved = 2209, spread = 2589, legal = 2627; time = 0.03s
Info: at iteration #3, type MISTRAL_M10K: wirelen solved = 1379, spread = 2346, legal = 2393; time = 0.03s
Info: at iteration #3, type MISTRAL_CLKENA: wirelen solved = 2272, spread = 2272, legal = 2436; time = 0.02s
Info: at iteration #3, type ALL: wirelen solved = 277, spread = 2239, legal = 2676; time = 0.09s
Info: at iteration #4, type MISTRAL_FF: wirelen solved = 2453, spread = 2485, legal = 2578; time = 0.04s
Info: at iteration #4, type MISTRAL_COMB: wirelen solved = 2335, spread = 2563, legal = 2434; time = 0.03s
Info: at iteration #4, type MISTRAL_M10K: wirelen solved = 1301, spread = 2169, legal = 2168; time = 0.03s
Info: at iteration #4, type MISTRAL_CLKENA: wirelen solved = 1998, spread = 1998, legal = 2168; time = 0.02s
Info: at iteration #4, type ALL: wirelen solved = 284, spread = 1991, legal = 2312; time = 0.10s
Info: at iteration #5, type MISTRAL_FF: wirelen solved = 2125, spread = 2097, legal = 2135; time = 0.03s
Info: at iteration #5, type MISTRAL_COMB: wirelen solved = 1741, spread = 2248, legal = 2357; time = 0.03s
Info: at iteration #5, type MISTRAL_M10K: wirelen solved = 1501, spread = 2288, legal = 2319; time = 0.03s
Info: at iteration #5, type MISTRAL_CLKENA: wirelen solved = 2151, spread = 2151, legal = 2319; time = 0.02s
Info: at iteration #5, type ALL: wirelen solved = 271, spread = 1924, legal = 2230; time = 0.09s
Info: at iteration #6, type MISTRAL_FF: wirelen solved = 1975, spread = 1925, legal = 1930; time = 0.03s
Info: at iteration #6, type MISTRAL_COMB: wirelen solved = 1783, spread = 2011, legal = 2047; time = 0.03s
Info: at iteration #6, type MISTRAL_M10K: wirelen solved = 1268, spread = 2026, legal = 2029; time = 0.03s
Info: at iteration #6, type MISTRAL_CLKENA: wirelen solved = 1897, spread = 1897, legal = 2067; time = 0.02s
Info: at iteration #6, type ALL: wirelen solved = 375, spread = 1844, legal = 2087; time = 0.09s
Info: at iteration #7, type MISTRAL_FF: wirelen solved = 2004, spread = 1974, legal = 2001; time = 0.03s
Info: at iteration #7, type MISTRAL_COMB: wirelen solved = 1738, spread = 2205, legal = 2299; time = 0.03s
Info: at iteration #7, type MISTRAL_M10K: wirelen solved = 1562, spread = 2258, legal = 2253; time = 0.03s
Info: at iteration #7, type MISTRAL_CLKENA: wirelen solved = 2083, spread = 2083, legal = 2216; time = 0.02s
Info: at iteration #7, type ALL: wirelen solved = 387, spread = 1759, legal = 2042; time = 0.08s
Info: at iteration #8, type MISTRAL_FF: wirelen solved = 1975, spread = 1905, legal = 1945; time = 0.03s
Info: at iteration #8, type MISTRAL_COMB: wirelen solved = 1720, spread = 2004, legal = 2044; time = 0.03s
Info: at iteration #8, type MISTRAL_M10K: wirelen solved = 1350, spread = 2044, legal = 2042; time = 0.03s
Info: at iteration #8, type MISTRAL_CLKENA: wirelen solved = 1911, spread = 1911, legal = 2079; time = 0.03s
Info: at iteration #8, type ALL: wirelen solved = 489, spread = 1724, legal = 1902; time = 0.08s
Info: at iteration #9, type MISTRAL_FF: wirelen solved = 1851, spread = 1832, legal = 2005; time = 0.05s
Info: at iteration #9, type MISTRAL_COMB: wirelen solved = 1750, spread = 2052, legal = 2111; time = 0.03s
Info: at iteration #9, type MISTRAL_M10K: wirelen solved = 1395, spread = 2109, legal = 2117; time = 0.03s
Info: at iteration #9, type MISTRAL_CLKENA: wirelen solved = 1951, spread = 1951, legal = 2117; time = 0.02s
Info: at iteration #9, type ALL: wirelen solved = 370, spread = 1731, legal = 1995; time = 0.08s
Info: at iteration #10, type MISTRAL_FF: wirelen solved = 1960, spread = 2107, legal = 2141; time = 0.04s
Info: at iteration #10, type MISTRAL_COMB: wirelen solved = 1812, spread = 2145, legal = 2226; time = 0.03s
Info: at iteration #10, type MISTRAL_M10K: wirelen solved = 1509, spread = 2192, legal = 2202; time = 0.03s
Info: at iteration #10, type MISTRAL_CLKENA: wirelen solved = 2042, spread = 2042, legal = 2168; time = 0.03s
Info: at iteration #10, type ALL: wirelen solved = 423, spread = 1718, legal = 1892; time = 0.08s
Info: at iteration #11, type MISTRAL_FF: wirelen solved = 1798, spread = 1757, legal = 1788; time = 0.03s
Info: at iteration #11, type MISTRAL_COMB: wirelen solved = 1536, spread = 1738, legal = 1842; time = 0.03s
Info: at iteration #11, type MISTRAL_M10K: wirelen solved = 1209, spread = 2137, legal = 2026; time = 0.03s
Info: at iteration #11, type MISTRAL_CLKENA: wirelen solved = 1888, spread = 1888, legal = 2048; time = 0.03s
Info: at iteration #11, type ALL: wirelen solved = 477, spread = 1786, legal = 2097; time = 0.09s
Info: at iteration #12, type MISTRAL_FF: wirelen solved = 1943, spread = 1904, legal = 1919; time = 0.03s
Info: at iteration #12, type MISTRAL_COMB: wirelen solved = 1751, spread = 2170, legal = 2291; time = 0.03s
Info: at iteration #12, type MISTRAL_M10K: wirelen solved = 1580, spread = 2517, legal = 2390; time = 0.03s
Info: at iteration #12, type MISTRAL_CLKENA: wirelen solved = 2242, spread = 2242, legal = 2390; time = 0.02s
Info: at iteration #12, type ALL: wirelen solved = 544, spread = 2184, legal = 2221; time = 0.08s
Info: at iteration #13, type MISTRAL_FF: wirelen solved = 2149, spread = 2152, legal = 2248; time = 0.04s
Info: at iteration #13, type MISTRAL_COMB: wirelen solved = 1967, spread = 2696, legal = 2708; time = 0.03s
Info: at iteration #13, type MISTRAL_M10K: wirelen solved = 1965, spread = 2734, legal = 2669; time = 0.03s
Info: at iteration #13, type MISTRAL_CLKENA: wirelen solved = 2531, spread = 2531, legal = 2669; time = 0.02s
Info: at iteration #13, type ALL: wirelen solved = 599, spread = 2158, legal = 2218; time = 0.08s
Info: at iteration #14, type MISTRAL_FF: wirelen solved = 2099, spread = 2144, legal = 2143; time = 0.03s
Info: at iteration #14, type MISTRAL_COMB: wirelen solved = 1890, spread = 2381, legal = 2397; time = 0.03s
Info: at iteration #14, type MISTRAL_M10K: wirelen solved = 1613, spread = 2314, legal = 2283; time = 0.03s
Info: at iteration #14, type MISTRAL_CLKENA: wirelen solved = 2151, spread = 2151, legal = 2283; time = 0.02s
Info: at iteration #14, type ALL: wirelen solved = 673, spread = 1916, legal = 2049; time = 0.08s
Info: at iteration #15, type MISTRAL_FF: wirelen solved = 2085, spread = 2077, legal = 2095; time = 0.04s
Info: at iteration #15, type MISTRAL_COMB: wirelen solved = 1821, spread = 2250, legal = 2257; time = 0.03s
Info: at iteration #15, type MISTRAL_M10K: wirelen solved = 1471, spread = 2170, legal = 2170; time = 0.03s
Info: at iteration #15, type MISTRAL_CLKENA: wirelen solved = 2042, spread = 2042, legal = 2150; time = 0.03s
Info: at iteration #15, type ALL: wirelen solved = 593, spread = 1840, legal = 1942; time = 0.08s
Info: HeAP Placer Time: 4.84s
Info: of which solving equations: 1.93s
Info: of which spreading cells: 0.63s
Info: of which strict legalisation: 0.45s
Info: Running simulated annealing placer for refinement.
Info: at iteration #1: temp = 0.000000, timing cost = 14, wirelen = 1892
Info: at iteration #5: temp = 0.000000, timing cost = 4, wirelen = 1435
Info: at iteration #10: temp = 0.000000, timing cost = 5, wirelen = 1359
Info: at iteration #14: temp = 0.000000, timing cost = 4, wirelen = 1341
Info: SA placement time 0.81s
Info: Max frequency for clock 'blink_rgb_0.i_clock': 324.68 MHz (PASS at 50.00 MHz)
Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 16920, 17043) |****
Info: [ 17043, 17166) |****
Info: [ 17166, 17289) |*******************
Info: [ 17289, 17412) |*************************
Info: [ 17412, 17535) |*********************
Info: [ 17535, 17658) |*************
Info: [ 17658, 17781) |**********************
Info: [ 17781, 17904) |*******************
Info: [ 17904, 18027) |*****************************
Info: [ 18027, 18150) |*****************
Info: [ 18150, 18273) |***************
Info: [ 18273, 18396) |***********
Info: [ 18396, 18519) |
Info: [ 18519, 18642) |
Info: [ 18642, 18765) |
Info: [ 18765, 18888) |
Info: [ 18888, 19011) |
Info: [ 19011, 19134) |*
Info: [ 19134, 19257) |***
Info: [ 19257, 19380) |***
Info: Checksum: 0xd45ef47f
Info: Preparing LABs for routing...
Info: Routing globals...
Info: routed net 'blink_rgb_0.i_clock' using global resources
Info: Running router2...
Info: Setting up routing resources...
Info: Running main router loop...
Info: iter=1 wires=4063 overused=146 overuse=156 archfail=NA
Info: iter=2 wires=4139 overused=53 overuse=53 archfail=NA
Info: iter=3 wires=4199 overused=18 overuse=18 archfail=NA
Info: iter=4 wires=4210 overused=11 overuse=11 archfail=NA
Info: iter=5 wires=4215 overused=4 overuse=4 archfail=NA
Info: iter=6 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=7 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=8 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=9 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=10 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=11 wires=4224 overused=1 overuse=1 archfail=NA
Info: iter=12 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=13 wires=4223 overused=1 overuse=1 archfail=NA
Info: iter=14 wires=4228 overused=0 overuse=0 archfail=0
Info: Router2 time 2.51s
Info: Running router1 to check that route is legal...
Info: Routing..
Info: Setting up routing queue.
Info: Routing 0 arcs.
Info: | (re-)routed arcs | delta | remaining| time spent |
Info: IterCnt | w/ripup wo/ripup | w/r wo/r | arcs| batch(sec) total(sec)|
Info: 0 | 0 0 | 0 0 | 0| 0.07 0.07|
Info: Routing complete.
Info: Router1 time 0.07s
Info: Checksum: 0x19b2a390
Info: Critical path report for clock 'blink_rgb_0.i_clock' (posedge -> posedge):
Info: curr total
Info: 0.7 0.7 Source blink_rgb_0.counter_MISTRAL_FF_Q_6.Q
Info: 1.6 2.3 Net blink_rgb_0.counter[19] budget 4.587000 ns (71,1) -> (71,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E_MISTRAL_ALUT4_Q.C
Info: 0.4 2.7 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E_MISTRAL_ALUT4_Q.Q
Info: 1.4 4.1 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E[4] budget 4.587000 ns (71,1) -> (72,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1.E
Info: Defined in:
Info: /usr/local/bin/../share/yosys/intel_alm/common/alm_map.v:7.19-7.20
Info: 0.1 4.2 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1.Q
Info: 0.6 4.8 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B[4] budget 4.587000 ns (72,1) -> (72,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A.E
Info: Defined in:
Info: /usr/local/bin/../share/yosys/intel_alm/common/alm_map.v:7.19-7.20
Info: 0.1 4.9 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A.Q
Info: 0.8 5.8 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_Q budget 4.587000 ns (72,1) -> (72,2)
Info: Sink blink_rgb_0.counter_MISTRAL_FF_Q_10.SCLR
Info: -0.2 5.6 Setup blink_rgb_0.counter_MISTRAL_FF_Q_10.SCLR
Info: 1.1 ns logic, 4.4 ns routing
Info: Max frequency for clock 'blink_rgb_0.i_clock': 180.02 MHz (PASS at 50.00 MHz)
Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 14445, 14668) |*************
Info: [ 14668, 14891) |****
Info: [ 14891, 15114) |************************************
Info: [ 15114, 15337) |*****
Info: [ 15337, 15560) |************************************
Info: [ 15560, 15783) |**************
Info: [ 15783, 16006) |**********
Info: [ 16006, 16229) |************************
Info: [ 16229, 16452) |***********
Info: [ 16452, 16675) |*********************
Info: [ 16675, 16898) |*************
Info: [ 16898, 17121) |***
Info: [ 17121, 17344) |*****
Info: [ 17344, 17567) |*****
Info: [ 17567, 17790) |*
Info: [ 17790, 18013) |
Info: [ 18013, 18236) |
Info: [ 18236, 18459) |**
Info: [ 18459, 18682) |**
Info: [ 18682, 18905) |*
Info: Running signoff timing analysis...
Info: Critical path report for clock 'blink_rgb_0.i_clock' (posedge -> posedge):
Info: curr total
Info: 0.7 0.7 Source blink_rgb_0.counter_MISTRAL_FF_Q_6.Q
Info: 1.5 2.3 Net blink_rgb_0.counter[19] budget 4.587000 ns (71,1) -> (71,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E_MISTRAL_ALUT4_Q.C
Info: 0.4 2.7 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E_MISTRAL_ALUT4_Q.Q
Info: 1.7 4.4 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1_E[4] budget 4.587000 ns (71,1) -> (72,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1.E
Info: Defined in:
Info: /usr/local/bin/../share/yosys/intel_alm/common/alm_map.v:7.19-7.20
Info: 0.1 4.5 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B_MISTRAL_ALUT5_Q_1.Q
Info: 0.5 4.9 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_B[4] budget 4.587000 ns (72,1) -> (72,1)
Info: Sink blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A.E
Info: Defined in:
Info: /usr/local/bin/../share/yosys/intel_alm/common/alm_map.v:7.19-7.20
Info: 0.1 5.0 Source blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A.Q
Info: 0.9 5.9 Net blink_rgb_0.i_reset_n_MISTRAL_ALUT5_A_Q budget 4.587000 ns (72,1) -> (72,2)
Info: Sink blink_rgb_0.counter_MISTRAL_FF_Q_10.SCLR
Info: -0.2 5.7 Setup blink_rgb_0.counter_MISTRAL_FF_Q_10.SCLR
Info: 1.1 ns logic, 4.6 ns routing
Info: Max frequency for clock 'blink_rgb_0.i_clock': 174.64 MHz (PASS at 50.00 MHz)
Info: Slack histogram:
Info: legend: * represents 1 endpoint(s)
Info: + represents [1,1) endpoint(s)
Info: [ 14274, 14507) |****************
Info: [ 14507, 14740) |
Info: [ 14740, 14973) |**************
Info: [ 14973, 15206) |
Info: [ 15206, 15439) |***********************
Info: [ 15439, 15672) |*******************
Info: [ 15672, 15905) |***********************************
Info: [ 15905, 16138) |************************
Info: [ 16138, 16371) |********************
Info: [ 16371, 16604) |*********************
Info: [ 16604, 16837) |*******
Info: [ 16837, 17070) |*********
Info: [ 17070, 17303) |*******
Info: [ 17303, 17536) |*****
Info: [ 17536, 17769) |*
Info: [ 17769, 18002) |
Info: [ 18002, 18235) |
Info: [ 18235, 18468) |*
Info: [ 18468, 18701) |*
Info: [ 18701, 18934) |***
Info: Program finished normally.
so, I spent all night on this bug, and fedi thinks that a write-up of that might be useful for other people.
the symptoms
going into this, all I really knew was that the reporter said it was correlated to usage of the M10Ks in nextpnr-mistral. let's run it and see.
hmm, a crash in the analytical placer. odd.
dict
is nextpnr's implementation ofstd::unordered_map
if people were wondering; we use our own implementation to have identical behaviour across platforms.the stack trace
the relevant frame here is #8: there's a crash in
getBelPinsForCellPin
. that function looks like this:there's not much to go wrong here; the only call to
at
is thepin_data.at(pin)
, which suggests thatpin
doesn't exist, even though it should.what is
pin
, anyway?oh, right. nextpnr uses string interning to reduce memory usage, especially for repetitive sequences, and an interned string is called an
IdString
. so, we need to turn thisIdString
into an actual string.one does this by calling the
.str
method of theIdString
, passing it theArch
(...more specifically, theContext
, of whichArch
is a derived class) which contains the string pool. this gets one astd::string
, so now one calls.c_str()
on that to get a C string.(can
gdb
printstd::string
s? probably, but.str(this).c_str()
is so ingrained in my muscle memory that I pretty much always use it.)B1DATA
, hm.some background
let's step back a little: what's a "bel"? what's a "bel pin"? what's a "cell" (in this context)?
nextpnr differentiates between abstract models of how the hardware can be configured - cells - from the concrete model of how the hardware actually is - bels.
for example, a cell might be a LUT generated by Yosys, but the corresponding bel would be an ALM, which is a bit more complicated.
as one might see from the diagram, there needs to be a mapping from the inputs and outputs of an abstract cell to the concrete bel that will implement it: those bel inputs and outputs are "bel pins".
now, for some bels, you can use a static template, but the M10Ks need to have different cell-pin-to-bel-pin mappings depending on the configuration.
the M10K 10-kilobit memory block
before I go into the code, I think it's worth describing why the code is what it is.
internally, the M10K is 40 sub-blocks of 8-bit address by 1-bit data; this gives a range of 8-bit address by 40-bit data, 9-bit address by 20-bit data, 10-bit address by 10-bit data, 11-bit address by 5-bit data, 12-bit address by 2-bit data, and 13-bit address by 1-bit data.
it has two ports, each port containing a 12-bit address, a 20-bit data input and a 20-bit data output, plus read/write enables.
there is an internal data read multiplexer, but no corresponding data write demultiplexer, so one must manually wire up the write port.
DATAAIN[N]
.N
goes to the above andDATAAIN[N+10]
.N
goes to the above,DATAAIN[N+5]
, andDATAAIN[N+15]
.N
goes to the above,DATAAIN[N+2]
,DATAAIN[N+7]
,DATAAIN[N+12]
,DATAAIN[N+17]
.N
goes in every bit exceptDATAAIN[4]
,DATAAIN[9]
,DATAAIN[14]
, andDATAAIN[19]
.now, one may ask where the 13th address bit for 13x1-bit mode comes from; "obviously", it comes from
DATAAIN[4]
.it's an annoying exception to the rule, and
printf
debugging showed that this is where the problem lies.the code
(this code has been lightly edited for clarity, but the bug(s) remains)
bug the first
if you remember from earlier, the missing entry is
B1DATA
. at the very bottom of the function is this:where
dbits
is the data width in bits. in 13x1 mode, this is1
, so, this loop assigns theIdString
forDATABOUT[0]
toci->pin_data["B1DATA[0]"].bel_pins
.but it's not looking for the cell pin
B1DATA[0]
, it's looking for the cell pinB1DATA
. so, we can special-casedbits == 1
, and assign to the correct cell pin names.let's compile it and run it again!
bug the second
we made it through the analytical placer at least?
I mentioned before that the M10K has 12-bit address inputs, but
B1ADDR[12]
(0-indexed) would refer to the 13th bit of this address input, which...doesn't exist.the cause of that is
bit_offset
. when we're in the 13x1-bit mode, the least significant bit gets stuffed inDATAAIN[4]
, so the least-significant bit is skipped, and the remaining bits go through the loop of being assigned. however, this leads toADDR{A,B}
starting at one instead of zero.so, to fix this we need to subtract
bit_offset
to makeADDR{A,B}
zero-indexed again.there is another trick available here, but I chose not to use it due to it being a bit more surprising: if
addr_offset
did not have thestd::max
to keep it non-negative, then in 13x1 mode,addr_offset
would be-1
, which would correct for the one-indexing.let's compile it and run it again!
[final fantasy victory sound]