From 119b47acf3be0c7bd5b75f736ac07fdc81f74c2a Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 29 May 2023 05:39:28 +0100 Subject: [PATCH] mistral: add 8x40-bit M10K addressing mode --- mistral/bitstream.cc | 18 ++++++++++-------- mistral/pack.cc | 31 +++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/mistral/bitstream.cc b/mistral/bitstream.cc index c7fe7ccb..e3268810 100644 --- a/mistral/bitstream.cc +++ b/mistral/bitstream.cc @@ -126,9 +126,11 @@ struct MistralBitgen // Notes: // DATA_FLOW_THRU is probably transparent reads. + auto dbits = ci->params.at(id_CFG_DBITS).as_int64(); + cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::A_DATA_FLOW_THRU, bi, 1); - cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::A_DATA_WIDTH, bi, ci->params.at(id_CFG_DBITS).as_int64()); - cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::A_FAST_WRITE, bi, CycloneV::FAST); + cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::A_DATA_WIDTH, bi, dbits); + cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::A_FAST_WRITE, bi, dbits == 40 ? CycloneV::SLOW : CycloneV::FAST); cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::A_OUTPUT_SEL, bi, CycloneV::ASYNC); cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::A_SA_WREN_DELAY, bi, 1); cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::A_SAEN_DELAY, bi, 2); @@ -136,8 +138,8 @@ struct MistralBitgen cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::A_WR_TIMER_PULSE, bi, 0x0b); cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::B_DATA_FLOW_THRU, bi, 1); - cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::B_DATA_WIDTH, bi, ci->params.at(id_CFG_DBITS).as_int64()); - cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::B_FAST_WRITE, bi, CycloneV::FAST); + cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::B_DATA_WIDTH, bi, dbits); + cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::B_FAST_WRITE, bi, dbits == 40 ? CycloneV::SLOW : CycloneV::FAST); cv->bmux_m_set(CycloneV::M10K, pos, CycloneV::B_OUTPUT_SEL, bi, CycloneV::ASYNC); cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::B_SA_WREN_DELAY, bi, 1); cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::B_SAEN_DELAY, bi, 2); @@ -145,10 +147,10 @@ struct MistralBitgen cv->bmux_r_set(CycloneV::M10K, pos, CycloneV::B_WR_TIMER_PULSE, bi, 0x0b); cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::TOP_CLK_SEL, bi, 1); - cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::TOP_W_INV, bi, 1); - cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::TOP_W_SEL, bi, 1); - cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::BOT_CLK_INV, bi, 1); - cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::BOT_W_SEL, bi, 1); + cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::TOP_W_INV, bi, dbits != 40); + cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::TOP_W_SEL, bi, dbits != 40); + cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::BOT_CLK_INV, bi, dbits != 40); + cv->bmux_n_set(CycloneV::M10K, pos, CycloneV::BOT_W_SEL, bi, dbits != 40); cv->bmux_b_set(CycloneV::M10K, pos, CycloneV::TRUE_DUAL_PORT, bi, 0); diff --git a/mistral/pack.cc b/mistral/pack.cc index 51ad0aeb..c0a71e33 100644 --- a/mistral/pack.cc +++ b/mistral/pack.cc @@ -392,7 +392,7 @@ struct MistralPacker 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); + NPNR_ASSERT(dbits == 1 || dbits == 2 || dbits == 5 || dbits == 10 || dbits == 20 || dbits == 40); NPNR_ASSERT((1 << abits) * dbits <= 10240); log_info("Setting up %ld-bit address, %ld-bit data M10K for %s.\n", abits, dbits, ci->name.str(ctx).c_str()); @@ -402,8 +402,11 @@ struct MistralPacker // 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]")}; + // RDEN[1] is left unconnected. + if (dbits == 40) + ci->pin_data[ctx->id("A1EN")].bel_pins = {ctx->id("WREN[0]")}; + else + 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. @@ -415,7 +418,7 @@ struct MistralPacker // One could remove the std::max here and the `- bit_offset`s here, // because they would cancel out, but I think this way is less confusing. - int addr_offset = std::max(12 - std::max(abits, 9L), 0L); + int addr_offset = std::max(12 - std::max(abits, dbits == 40 ? 8L : 9L), 0L); int bit_offset = (abits == 13); if (abits == 13) { ci->pin_data[ctx->id("A1ADDR[0]")].bel_pins = {ctx->id("DATAAIN[4]")}; @@ -462,13 +465,25 @@ struct MistralPacker continue; } - for (int bit = 0; bit < dbits; bit++) { + // 40-bit data mode causes some headaches... + bit_offset = dbits == 40 ? 20 : 0; + + // Write port + for (int bit = 0; bit < std::min(dbits, 20L); 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)}; + if (dbits == 40) + for (int bit = bit_offset; bit < dbits; bit++) + ci->pin_data[ctx->idf("A1DATA[%d]", bit)].bel_pins.push_back(ctx->idf("DATABIN[%d]", bit - bit_offset)); + + // Read port + if (dbits == 40) + for (int bit = 0; bit < 20; bit++) + ci->pin_data[ctx->idf("B1DATA[%d]", bit)].bel_pins = {ctx->idf("DATAAOUT[%d]", bit)}; + + for (int bit = bit_offset; bit < dbits; bit++) + ci->pin_data[ctx->idf("B1DATA[%d]", bit)].bel_pins = {ctx->idf("DATABOUT[%d]", bit - bit_offset)}; } }