aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-05-10 21:23:47 +0100
committergatecat <gatecat@ds0.me>2021-05-15 14:54:33 +0100
commitdea4c6f53f23aa228ced3016903c62bdc3745e34 (patch)
treec52dce6451122dda180a5f03821964ce117be06e
parent27eb3be7dae5038099aab8299e0f1d9d675fd855 (diff)
downloadnextpnr-dea4c6f53f23aa228ced3016903c62bdc3745e34.tar.gz
nextpnr-dea4c6f53f23aa228ced3016903c62bdc3745e34.tar.bz2
nextpnr-dea4c6f53f23aa228ced3016903c62bdc3745e34.zip
mistral: Setting some more boilerplate bits
Signed-off-by: gatecat <gatecat@ds0.me>
-rw-r--r--mistral/base_bitstream.cc14
-rw-r--r--mistral/bitstream.cc102
-rw-r--r--mistral/family.cmake3
3 files changed, 118 insertions, 1 deletions
diff --git a/mistral/base_bitstream.cc b/mistral/base_bitstream.cc
index bf85c6b9..759cdfeb 100644
--- a/mistral/base_bitstream.cc
+++ b/mistral/base_bitstream.cc
@@ -45,6 +45,18 @@ void default_sx120f(CycloneV *cv)
// Default TERM config
cv->bmux_b_set(CycloneV::TERM, CycloneV::xy2pos(89, 34), CycloneV::INTOSC_2_EN, 0, 0);
+ // TODO: what if these pins are used? where do these come from
+ for (int z = 0; z < 4; z++) {
+ cv->bmux_m_set(CycloneV::GPIO, CycloneV::xy2pos(89, 43), CycloneV::IOCSR_STD, z, CycloneV::NVR_LOW);
+ cv->bmux_m_set(CycloneV::GPIO, CycloneV::xy2pos(89, 66), CycloneV::IOCSR_STD, z, CycloneV::NVR_LOW);
+ }
+ for (int y : {38, 44, 51, 58, 65, 73, 79}) {
+ // TODO: Why only these upper DQS? is there a pattern?
+ cv->bmux_b_set(CycloneV::DQS16, CycloneV::xy2pos(89, y), CycloneV::RB_2X_CLK_DQS_INV, 0, 1);
+ cv->bmux_b_set(CycloneV::DQS16, CycloneV::xy2pos(89, y), CycloneV::RB_ACLR_LFIFO_EN, 0, 1);
+ cv->bmux_b_set(CycloneV::DQS16, CycloneV::xy2pos(89, y), CycloneV::RB_LFIFO_BYPASS, 0, 0);
+ }
+
// Discover these mux values using
// grep 'i [_A-Z0-9.]* 1' empty.bt
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 12), 69), true);
@@ -54,7 +66,7 @@ void default_sx120f(CycloneV *cv)
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 37), 31), true);
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 40), 43), true);
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 46), 69), true);
- cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 47), 53), true);
+ cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 47), 43), true);
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 53), 69), true);
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 54), 4), true);
cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 73), 68), true);
diff --git a/mistral/bitstream.cc b/mistral/bitstream.cc
index 9ed3a161..2c612a73 100644
--- a/mistral/bitstream.cc
+++ b/mistral/bitstream.cc
@@ -46,6 +46,107 @@ struct MistralBitgen
cv->opt_b_set(CycloneV::RELEASE_CLEARS_BEFORE_TRISTATES_DIS, true);
cv->opt_b_set(CycloneV::RETRY_CONFIG_ON_ERROR_EN, true);
cv->opt_r_set(CycloneV::START_UP_CLOCK, 0x3F);
+ // Default inversion
+ write_default_inv();
+ }
+
+ void write_default_inv()
+ {
+ // Some PNODEs are inverted by default. Set them up here.
+ for (const auto &pn2r : cv->get_all_p2r()) {
+ const auto &pn = pn2r.first;
+ auto pt = CycloneV::pn2pt(pn);
+ auto pi = CycloneV::pn2pi(pn);
+
+ switch (CycloneV::pn2bt(pn)) {
+ case CycloneV::HMC: {
+ // HMC OE are inverted to set OE=0, i.e. unused pins floating
+ // TODO: handle the case when we are using the HMC or HMC bypass
+ std::string name(CycloneV::port_type_names[pt]);
+ if (name.compare(0, 5, "IOINT") != 0 || name.compare(name.size() - 2, 2, "OE") != 0)
+ continue;
+ cv->inv_set(pn2r.second, true);
+ break;
+ };
+ // HPS IO - TODO: what about when we actually support the HPS primitives?
+ case CycloneV::HPS_BOOT: {
+ switch (pt) {
+ case CycloneV::CSEL_EN:
+ case CycloneV::BSEL_EN:
+ case CycloneV::BOOT_FROM_FPGA_READY:
+ case CycloneV::BOOT_FROM_FPGA_ON_FAILURE:
+ cv->inv_set(pn2r.second, true);
+ break;
+ case CycloneV::CSEL:
+ if (pi < 2)
+ cv->inv_set(pn2r.second, true);
+ break;
+ case CycloneV::BSEL:
+ if (pi < 3)
+ cv->inv_set(pn2r.second, true);
+ break;
+ default:
+ break;
+ };
+ break;
+ };
+ case CycloneV::HPS_CROSS_TRIGGER: {
+ if (pt == CycloneV::CLK_EN)
+ cv->inv_set(pn2r.second, true);
+ break;
+ };
+ case CycloneV::HPS_TEST: {
+ if (pt == CycloneV::CFG_DFX_BYPASS_ENABLE)
+ cv->inv_set(pn2r.second, true);
+ break;
+ };
+ case CycloneV::GPIO: {
+ // Ignore GPIO used by the design
+ BelId bel = ctx->bel_by_block_idx(CycloneV::pn2x(pn), CycloneV::pn2y(pn), id_MISTRAL_IO,
+ CycloneV::pn2bi(pn));
+ if (bel != BelId() && ctx->getBoundBelCell(bel) != nullptr)
+ continue;
+ // Bonded IO invert OEIN.1 which disables the output buffer and floats the IO
+ // Unbonded IO invert OEIN.0 which enables the output buffer, and {DATAIN.[0123]} to drive a constant
+ // GND, presumably for power/EMI reasons
+ bool is_bonded = cv->pin_find_pnode(pn) != nullptr;
+ if (is_bonded && (pt != CycloneV::OEIN || pi != 1))
+ continue;
+ if (!is_bonded && (pt != CycloneV::DATAIN) && (pt != CycloneV::OEIN || pi != 0))
+ continue;
+ cv->inv_set(pn2r.second, true);
+ break;
+ };
+ case CycloneV::FPLL: {
+ if (pt == CycloneV::EXTSWITCH || (pt == CycloneV::CLKEN && pi < 2))
+ cv->inv_set(pn2r.second, true);
+ break;
+ };
+ default:
+ break;
+ }
+ }
+ }
+
+ void write_dqs()
+ {
+ for (auto pos : cv->dqs16_get_pos()) {
+ int x = CycloneV::pos2x(pos), y = CycloneV::pos2y(pos);
+ // DQS bypass for used output pins
+ for (int z = 0; z < 16; z++) {
+ int ioy = y + (z / 4) - 2;
+ if (ioy < 0 || ioy >= int(cv->get_tile_sy()))
+ continue;
+ BelId bel = ctx->bel_by_block_idx(x, ioy, id_MISTRAL_IO, z % 4);
+ if (bel == BelId())
+ continue;
+ CellInfo *ci = ctx->getBoundBelCell(bel);
+ if (ci == nullptr || (ci->type != id_MISTRAL_IO && ci->type != id_MISTRAL_OB))
+ continue; // not an output
+ cv->bmux_m_set(CycloneV::DQS16, pos, CycloneV::INPUT_REG4_SEL, z, CycloneV::SEL_LOCKED_DPA);
+ cv->bmux_r_set(CycloneV::DQS16, pos, CycloneV::RB_T9_SEL_EREG_CFF_DELAY, z, 0x1f);
+ }
+ }
}
void write_routing()
@@ -71,6 +172,7 @@ struct MistralBitgen
cv->clear();
init();
write_routing();
+ write_dqs();
}
};
} // namespace
diff --git a/mistral/family.cmake b/mistral/family.cmake
index 441d81db..79681ba8 100644
--- a/mistral/family.cmake
+++ b/mistral/family.cmake
@@ -2,10 +2,13 @@ set(MISTRAL_ROOT "" CACHE STRING "Mistral install path")
aux_source_directory(${MISTRAL_ROOT}/lib MISTRAL_LIB_FILES)
add_library(mistral STATIC ${MISTRAL_LIB_FILES})
+target_compile_options(mistral PRIVATE -Wno-maybe-uninitialized)
find_package(LibLZMA REQUIRED)
foreach(family_target ${family_targets})
target_include_directories(${family_target} PRIVATE ${MISTRAL_ROOT}/lib ${LIBLZMA_INCLUDE_DIRS})
target_link_libraries(${family_target} PRIVATE mistral ${LIBLZMA_LIBRARIES})
+ # Currently required to avoid issues with mistral (LTO means the warnings can end up in nextpnr)
+ target_link_options(${family_target} PRIVATE -Wno-maybe-uninitialized)
endforeach()