From 91a0eb93672e9c764f03fd1b0a7d22595a61c516 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Tue, 18 Jan 2022 22:37:35 +0100 Subject: Mistral: fix gpio OE, add hmc bypass support --- .github/workflows/mistral_ci.yml | 2 +- mistral/arch.h | 34 +++++++++++++++++++++- mistral/bitstream.cc | 62 ++++++++++++++++++++++++---------------- mistral/io.cc | 10 ++++--- 4 files changed, 78 insertions(+), 30 deletions(-) diff --git a/.github/workflows/mistral_ci.yml b/.github/workflows/mistral_ci.yml index 0da633e6..a02026cf 100644 --- a/.github/workflows/mistral_ci.yml +++ b/.github/workflows/mistral_ci.yml @@ -21,7 +21,7 @@ jobs: - name: Execute build nextpnr env: MISTRAL_PATH: ${{ github.workspace }}/deps/mistral - MISTRAL_REVISION: db29e403bede4d514fcf83948db9d4c05df07e96 + MISTRAL_REVISION: 0c2ab2b2c6af33fea1c20349be2e0068366ed615 run: | source ./.github/ci/build_mistral.sh get_dependencies diff --git a/mistral/arch.h b/mistral/arch.h index 9c38d5d2..98340d4e 100644 --- a/mistral/arch.h +++ b/mistral/arch.h @@ -461,9 +461,41 @@ struct Arch : BaseArch void add_bel_pin(BelId bel, IdString pin, PortType dir, WireId wire); + CycloneV::rnode_t find_rnode(CycloneV::block_type_t bt, int x, int y, CycloneV::port_type_t port, int bi = -1, int pi = -1) const + { + auto pn1 = CycloneV::pnode(bt, x, y, port, bi, pi); + auto rn1 = cyclonev->pnode_to_rnode(pn1); + if(rn1) + return rn1; + + if(bt == CycloneV::GPIO) { + auto pn2 = cyclonev->p2p_to(pn1); + if(!pn2) { + auto pnv = cyclonev->p2p_from(pn1); + if(!pnv.empty()) + pn2 = pnv[0]; + } + auto pn3 = cyclonev->hmc_get_bypass(pn2); + auto rn2 = cyclonev->pnode_to_rnode(pn3); + return rn2; + } + + return 0; + } + WireId get_port(CycloneV::block_type_t bt, int x, int y, int bi, CycloneV::port_type_t port, int pi = -1) const { - return WireId(cyclonev->pnode_to_rnode(CycloneV::pnode(bt, x, y, port, bi, pi))); + auto rn = find_rnode(bt, x, y, port, bi, pi); + if(rn) + return WireId(rn); + + fprintf(stderr, "Trying to connect unknown node %s\n", CycloneV::pn2s(CycloneV::pnode(bt, x, y, port, bi, pi)).c_str()); + exit(1); + } + + bool has_port(CycloneV::block_type_t bt, int x, int y, int bi, CycloneV::port_type_t port, int pi = -1) const + { + return find_rnode(bt, x, y, port, bi, pi) != 0; } void create_lab(int x, int y, bool is_mlab); // lab.cc diff --git a/mistral/bitstream.cc b/mistral/bitstream.cc index b432be03..33079727 100644 --- a/mistral/bitstream.cc +++ b/mistral/bitstream.cc @@ -29,6 +29,34 @@ struct MistralBitgen Context *ctx; CycloneV *cv; + using rnode_t = CycloneV::rnode_t; + using pnode_t = CycloneV::pnode_t; + using pos_t = CycloneV::pos_t; + using block_type_t = CycloneV::block_type_t; + using port_type_t = CycloneV::port_type_t; + + rnode_t find_rnode(block_type_t bt, pos_t pos, port_type_t port, int bi = -1, int pi = -1) const + { + auto pn1 = CycloneV::pnode(bt, pos, port, bi, pi); + auto rn1 = cv->pnode_to_rnode(pn1); + if(rn1) + return rn1; + + if(bt == CycloneV::GPIO) { + auto pn2 = cv->p2p_to(pn1); + if(!pn2) { + auto pnv = cv->p2p_from(pn1); + if(!pnv.empty()) + pn2 = pnv[0]; + } + auto pn3 = cv->hmc_get_bypass(pn2); + auto rn2 = cv->pnode_to_rnode(pn3); + return rn2; + } + + return 0; + } + void options() { if (!ctx->setting("compress_rbf", false)) { @@ -38,27 +66,6 @@ struct MistralBitgen cv->opt_r_set(CycloneV::OPT_B, 0xffffff402dffffffULL); } - 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() { for (auto &net : ctx->nets) { @@ -87,12 +94,20 @@ struct MistralBitgen if (is_output) { cv->bmux_m_set(CycloneV::GPIO, pos, CycloneV::DRIVE_STRENGTH, bi, CycloneV::V3P3_LVTTL_16MA_LVCMOS_2MA); cv->bmux_m_set(CycloneV::GPIO, pos, CycloneV::IOCSR_STD, bi, CycloneV::DIS); + + // Output gpios must also bypass things in the associated dqs + auto dqs = cv->p2p_to(CycloneV::pnode(CycloneV::GPIO, pos, CycloneV::PNONE, bi, -1)); + printf("%s -> %s\n", CycloneV::pn2s(CycloneV::pnode(CycloneV::GPIO, pos, CycloneV::PNONE, bi, -1)).c_str(), CycloneV::pn2s(dqs).c_str()); + if(dqs) { + cv->bmux_m_set(CycloneV::DQS16, CycloneV::pn2p(dqs), CycloneV::INPUT_REG4_SEL, CycloneV::pn2bi(dqs), CycloneV::SEL_LOCKED_DPA); + cv->bmux_r_set(CycloneV::DQS16, CycloneV::pn2p(dqs), CycloneV::RB_T9_SEL_EREG_CFF_DELAY, CycloneV::pn2bi(dqs), 0x1f); + } } // There seem to be two mirrored OEIN inversion bits for constant OE for inputs/outputs. This might be to // prevent a single bitflip from turning inputs to outputs and messing up other devices on the boards, notably // ECP5 does similar. OEIN.0 inverted for outputs; OEIN.1 for inputs - cv->inv_set(cv->pnode_to_rnode(CycloneV::pnode(CycloneV::GPIO, pos, CycloneV::OEIN, bi, is_output ? 0 : 1)), - true); + cv->inv_set(find_rnode(CycloneV::GPIO, pos, CycloneV::OEIN, bi, 0), is_output); + cv->inv_set(find_rnode(CycloneV::GPIO, pos, CycloneV::OEIN, bi, 1), !is_output); } void write_clkbuf_cell(CellInfo *ci, int x, int y, int bi) @@ -299,7 +314,6 @@ struct MistralBitgen cv->clear(); options(); write_routing(); - write_dqs(); write_cells(); write_labs(); } diff --git a/mistral/io.cc b/mistral/io.cc index dab3672e..a0a01af3 100644 --- a/mistral/io.cc +++ b/mistral/io.cc @@ -30,10 +30,12 @@ void Arch::create_gpio(int x, int y) WireId pad = add_wire(x, y, id(stringf("PAD[%d]", z))); BelId bel = add_bel(x, y, id(stringf("IO[%d]", z)), id_MISTRAL_IO); add_bel_pin(bel, id_PAD, PORT_INOUT, pad); - // FIXME: is the port index of zero always correct? - add_bel_pin(bel, id_I, PORT_IN, get_port(CycloneV::GPIO, x, y, z, CycloneV::DATAOUT, 0)); - add_bel_pin(bel, id_OE, PORT_IN, get_port(CycloneV::GPIO, x, y, z, CycloneV::OEIN, 0)); - add_bel_pin(bel, id_O, PORT_OUT, get_port(CycloneV::GPIO, x, y, z, CycloneV::DATAIN, 0)); + if(has_port(CycloneV::GPIO, x, y, z, CycloneV::DATAOUT, 0)) { + // FIXME: is the port index of zero always correct? + add_bel_pin(bel, id_I, PORT_IN, get_port(CycloneV::GPIO, x, y, z, CycloneV::DATAOUT, 0)); + add_bel_pin(bel, id_OE, PORT_IN, get_port(CycloneV::GPIO, x, y, z, CycloneV::OEIN, 0)); + add_bel_pin(bel, id_O, PORT_OUT, get_port(CycloneV::GPIO, x, y, z, CycloneV::DATAIN, 0)); + } bel_data(bel).block_index = z; } } -- cgit v1.2.3