mistral: add 8x40-bit M10K addressing mode

This commit is contained in:
Lofty 2023-05-29 05:39:28 +01:00
parent c5666c47fe
commit 119b47acf3
2 changed files with 33 additions and 16 deletions

View File

@ -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);

View File

@ -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)};
}
}