diff options
author | gatecat <gatecat@ds0.me> | 2021-05-09 16:27:57 +0100 |
---|---|---|
committer | gatecat <gatecat@ds0.me> | 2021-05-15 14:54:33 +0100 |
commit | c5d983066df541ad93a13904e96e0298489e2fcd (patch) | |
tree | f0acc0724f6152fd14610bcbe5e812397177bb0d | |
parent | 2612853238af4c84fa38c1c5e349fa19c5c51ebe (diff) | |
download | nextpnr-c5d983066df541ad93a13904e96e0298489e2fcd.tar.gz nextpnr-c5d983066df541ad93a13904e96e0298489e2fcd.tar.bz2 nextpnr-c5d983066df541ad93a13904e96e0298489e2fcd.zip |
mistral: Some preps for generating bitstreams
Signed-off-by: gatecat <gatecat@ds0.me>
-rw-r--r-- | mistral/arch.cc | 6 | ||||
-rw-r--r-- | mistral/arch.h | 12 | ||||
-rw-r--r-- | mistral/base_bitstream.cc | 86 | ||||
-rw-r--r-- | mistral/lab.cc | 55 |
4 files changed, 131 insertions, 28 deletions
diff --git a/mistral/arch.cc b/mistral/arch.cc index 592eddff..632fb0b2 100644 --- a/mistral/arch.cc +++ b/mistral/arch.cc @@ -303,6 +303,12 @@ WireId Arch::add_wire(int x, int y, IdString name, uint64_t flags) } } +bool Arch::wires_connected(WireId src, WireId dst) const +{ + PipId pip(src.node, dst.node); + return getBoundPipNet(pip) != nullptr; +} + PipId Arch::add_pip(WireId src, WireId dst) { wires[src].wires_downhill.push_back(dst); diff --git a/mistral/arch.h b/mistral/arch.h index 868d8650..860b3327 100644 --- a/mistral/arch.h +++ b/mistral/arch.h @@ -40,6 +40,10 @@ struct ArchArgs // These structures are used for fast ALM validity checking struct ALMInfo { + // Wires, so bitstream gen can determine connectivity + std::array<WireId, 2> comb_out; + std::array<WireId, 2> sel_clk, sel_ena, sel_aclr, sel_ef; + std::array<WireId, 4> ff_in, ff_out; // Pointers to bels std::array<BelId, 2> lut_bels; std::array<BelId, 4> ff_bels; @@ -326,6 +330,8 @@ struct Arch : BaseArch<ArchRanges> const std::vector<BelPin> &getWireBelPins(WireId wire) const override { return wires.at(wire).bel_pins; } AllWireRange getWires() const override { return AllWireRange(wires); } + bool wires_connected(WireId src, WireId dst) const; + // ------------------------------------------------- PipId getPipByName(IdStringList name) const override; @@ -461,9 +467,15 @@ struct Arch : BaseArch<ArchRanges> static const std::unordered_map<IdString, CellPinsData> cell_pins_db; // pins.cc CellPinStyle get_cell_pin_style(const CellInfo *cell, IdString port) const; // pins.cc + // ------------------------------------------------- + // List of IO constraints, used by QSF parser std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr; void read_qsf(std::istream &in); // qsf.cc + + // ------------------------------------------------- + + void init_base_bitstream(); // base_bitstream.cc }; NEXTPNR_NAMESPACE_END diff --git a/mistral/base_bitstream.cc b/mistral/base_bitstream.cc new file mode 100644 index 00000000..95199b18 --- /dev/null +++ b/mistral/base_bitstream.cc @@ -0,0 +1,86 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2021 gatecat <gatecat@ds0.me> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "log.h" +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace { +// Device-specific default config for the sx120f die +void default_sx120f(CycloneV *cv) +{ + // Default PMA config? + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 11), CycloneV::FFPLL_IQCLK_DIRECTION, 0, CycloneV::TRISTATE); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 11), CycloneV::FFPLL_IQCLK_DIRECTION, 1, CycloneV::TRISTATE); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 23), CycloneV::FFPLL_IQCLK_DIRECTION, 0, CycloneV::DOWN); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 23), CycloneV::FFPLL_IQCLK_DIRECTION, 1, CycloneV::UP); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 35), CycloneV::FFPLL_IQCLK_DIRECTION, 0, CycloneV::UP); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 35), CycloneV::FFPLL_IQCLK_DIRECTION, 1, CycloneV::UP); + cv->bmux_b_set(CycloneV::PMA3, CycloneV::xy2pos(0, 35), CycloneV::FPLL_DRV_EN, -1, false); + cv->bmux_m_set(CycloneV::PMA3, CycloneV::xy2pos(0, 35), CycloneV::HCLK_TOP_OUT_DRIVER, -1, CycloneV::TRISTATE); + // Default PLL config + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_ATB_EN0, -1, true); + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_ATB_EN0_PRECOMP, -1, true); + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_ATB_EN1, -1, true); + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_ATB_EN1_PRECOMP, -1, true); + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_BG_KICKSTART, -1, true); + cv->bmux_b_set(CycloneV::FPLL, CycloneV::xy2pos(0, 73), CycloneV::PL_AUX_VBGMON_POWERDOWN, -1, true); + + // 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); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 13), 4), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 34), 69), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(0, 35), 4), true); + 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, 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); + + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 18), 66), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 20), 8), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 27), 69), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 28), 43), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 59), 66), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 61), 8), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 68), 69), true); + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(9, 69), 43), true); + + for (int z = 10; z <= 45; z++) + cv->inv_set(CycloneV::rnode(CycloneV::GOUT, CycloneV::xy2pos(51, 80), z), true); +} +} // namespace + +void Arch::init_base_bitstream() +{ + switch (cyclonev->current_model()->variant.die.type) { + case CycloneV::SX120F: + default_sx120f(cyclonev); + break; + default: + log_error("FIXME: die type %s currently unsupported for bitgen.\n", + cyclonev->current_model()->variant.die.name); + } +} + +NEXTPNR_NAMESPACE_END
\ No newline at end of file diff --git a/mistral/lab.cc b/mistral/lab.cc index da50fe33..663b86e2 100644 --- a/mistral/lab.cc +++ b/mistral/lab.cc @@ -32,6 +32,7 @@ namespace { static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx) { auto &lab = arch->labs.at(lab_idx); + auto &alm = lab.alms.at(z); // Create the combinational part of ALMs. // There are two of these, for the two LUT outputs, and these also contain the carry chain and associated logic // Each one has all 8 ALM inputs as input pins. In many cases only a subset of these are used; depending on mode; @@ -79,33 +80,32 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx) arch->add_bel_pin(bel, id_COUT, PORT_OUT, carry_out); arch->add_bel_pin(bel, id_SHAREOUT, PORT_OUT, share_out); // Combinational output - WireId comb_out = arch->add_wire(x, y, arch->id(stringf("COMBOUT[%d]", z * 2 + i))); - arch->add_bel_pin(bel, id_COMBOUT, PORT_OUT, comb_out); + alm.comb_out[i] = arch->add_wire(x, y, arch->id(stringf("COMBOUT[%d]", z * 2 + i))); + arch->add_bel_pin(bel, id_COMBOUT, PORT_OUT, alm.comb_out[i]); // Assign indexing - lab.alms.at(z).lut_bels.at(i) = bel; + alm.lut_bels.at(i) = bel; auto &b = arch->bel_data(bel); b.lab_data.lab = lab_idx; b.lab_data.alm = z; b.lab_data.idx = i; } // Create the control set and E/F selection - which is per pair of FF - std::array<WireId, 2> sel_clk, sel_ena, sel_aclr, sel_ef; for (int i = 0; i < 2; i++) { // Wires - sel_clk[i] = arch->add_wire(x, y, arch->id(stringf("CLK%c[%d]", i ? 'B' : 'T', z))); - sel_ena[i] = arch->add_wire(x, y, arch->id(stringf("ENA%c[%d]", i ? 'B' : 'T', z))); - sel_aclr[i] = arch->add_wire(x, y, arch->id(stringf("ACLR%c[%d]", i ? 'B' : 'T', z))); - sel_ef[i] = arch->add_wire(x, y, arch->id(stringf("%cEF[%d]", i ? 'B' : 'T', z))); + alm.sel_clk[i] = arch->add_wire(x, y, arch->id(stringf("CLK%c[%d]", i ? 'B' : 'T', z))); + alm.sel_ena[i] = arch->add_wire(x, y, arch->id(stringf("ENA%c[%d]", i ? 'B' : 'T', z))); + alm.sel_aclr[i] = arch->add_wire(x, y, arch->id(stringf("ACLR%c[%d]", i ? 'B' : 'T', z))); + alm.sel_ef[i] = arch->add_wire(x, y, arch->id(stringf("%cEF[%d]", i ? 'B' : 'T', z))); // Muxes - three CLK/ENA per LAB, two ACLR for (int j = 0; j < 3; j++) { - arch->add_pip(lab.clk_wires[j], sel_clk[i]); - arch->add_pip(lab.ena_wires[j], sel_ena[i]); + arch->add_pip(lab.clk_wires[j], alm.sel_clk[i]); + arch->add_pip(lab.ena_wires[j], alm.sel_ena[i]); if (j < 2) - arch->add_pip(lab.aclr_wires[j], sel_aclr[i]); + arch->add_pip(lab.aclr_wires[j], alm.sel_aclr[i]); } // E/F pips - arch->add_pip(arch->get_port(CycloneV::LAB, x, y, z, i ? CycloneV::E1 : CycloneV::E0), sel_ef[i]); - arch->add_pip(arch->get_port(CycloneV::LAB, x, y, z, i ? CycloneV::F1 : CycloneV::F0), sel_ef[i]); + arch->add_pip(arch->get_port(CycloneV::LAB, x, y, z, i ? CycloneV::E1 : CycloneV::E0), alm.sel_ef[i]); + arch->add_pip(arch->get_port(CycloneV::LAB, x, y, z, i ? CycloneV::F1 : CycloneV::F0), alm.sel_ef[i]); } // Create the flipflops and associated routing @@ -114,32 +114,31 @@ static void create_alm(Arch *arch, int x, int y, int z, uint32_t lab_idx) for (int i = 0; i < 4; i++) { // FF input, selected by *PKREG* - WireId comb_out = arch->add_wire(x, y, arch->id(stringf("COMBOUT[%d]", (z * 2) + (i / 2)))); - WireId ff_in = arch->add_wire(x, y, arch->id(stringf("FFIN[%d]", (z * 4) + i))); - arch->add_pip(comb_out, ff_in); - arch->add_pip(sel_ef[i / 2], ff_in); + alm.ff_in[i] = arch->add_wire(x, y, arch->id(stringf("FFIN[%d]", (z * 4) + i))); + arch->add_pip(alm.comb_out[i / 2], alm.ff_in[i]); + arch->add_pip(alm.sel_ef[i / 2], alm.ff_in[i]); // FF bel BelId bel = arch->add_bel(x, y, arch->id(stringf("ALM%d_FF%d", z, i)), id_MISTRAL_FF); - arch->add_bel_pin(bel, id_CLK, PORT_IN, sel_clk[i / 2]); - arch->add_bel_pin(bel, id_ENA, PORT_IN, sel_ena[i / 2]); - arch->add_bel_pin(bel, id_ACLR, PORT_IN, sel_aclr[i / 2]); + arch->add_bel_pin(bel, id_CLK, PORT_IN, alm.sel_clk[i / 2]); + arch->add_bel_pin(bel, id_ENA, PORT_IN, alm.sel_ena[i / 2]); + arch->add_bel_pin(bel, id_ACLR, PORT_IN, alm.sel_aclr[i / 2]); arch->add_bel_pin(bel, id_SCLR, PORT_IN, lab.sclr_wire); arch->add_bel_pin(bel, id_SLOAD, PORT_IN, lab.sload_wire); - arch->add_bel_pin(bel, id_DATAIN, PORT_IN, ff_in); - arch->add_bel_pin(bel, id_SDATA, PORT_IN, sel_ef[i / 2]); + arch->add_bel_pin(bel, id_DATAIN, PORT_IN, alm.ff_in[i]); + arch->add_bel_pin(bel, id_SDATA, PORT_IN, alm.sel_ef[i / 2]); // FF output - WireId ff_out = arch->add_wire(x, y, arch->id(stringf("FFOUT[%d]", (z * 4) + i))); - arch->add_bel_pin(bel, id_Q, PORT_OUT, ff_out); + alm.ff_out[i] = arch->add_wire(x, y, arch->id(stringf("FFOUT[%d]", (z * 4) + i))); + arch->add_bel_pin(bel, id_Q, PORT_OUT, alm.ff_out[i]); // Output mux (*DFF*) WireId out = arch->get_port(CycloneV::LAB, x, y, z, outputs[i]); - arch->add_pip(ff_out, out); - arch->add_pip(comb_out, out); + arch->add_pip(alm.ff_out[i], out); + arch->add_pip(alm.comb_out[i / 2], out); // 'L' output mux where applicable if (i == 1 || i == 3) { WireId l_out = arch->get_port(CycloneV::LAB, x, y, z, l_outputs[i / 2]); - arch->add_pip(ff_out, l_out); - arch->add_pip(comb_out, l_out); + arch->add_pip(alm.ff_out[i], l_out); + arch->add_pip(alm.comb_out[i / 2], l_out); } lab.alms.at(z).ff_bels.at(i) = bel; |