commit
a120577773
@ -10,6 +10,7 @@ Currently nextpnr supports:
|
||||
* Lattice Nexus devices supported by [Project Oxide](https://github.com/gatecat/prjoxide)
|
||||
* Gowin LittleBee devices supported by [Project Apicula](https://github.com/YosysHQ/apicula)
|
||||
* *(experimental)* Cyclone V devices supported by [Mistral](https://github.com/Ravenslofty/mistral)
|
||||
* *(experimental)* Lattice MachXO2 devices supported by [Project Trellis](https://github.com/YosysHQ/prjtrellis)
|
||||
* *(experimental)* a "generic" back-end for user-defined architectures
|
||||
|
||||
There is some work in progress towards [support for Xilinx devices](https://github.com/gatecat/nextpnr-xilinx/) but it is not upstream and not intended for end users at the present time. We hope to see more FPGA families supported in the future. We would love your help in developing this awesome new project!
|
||||
|
@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "bitstream.h"
|
||||
#include "config.h"
|
||||
@ -59,16 +60,25 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire)
|
||||
|
||||
// Handle MachXO2's wonderful naming quirks for wires in left/right tiles, whose
|
||||
// relative coords push them outside the bounds of the chip.
|
||||
// Indents are based on wires proximity/purpose.
|
||||
auto is_pio_wire = [](std::string name) {
|
||||
// clang-format off
|
||||
return (name.find("DI") != std::string::npos || name.find("JDI") != std::string::npos ||
|
||||
name.find("PADD") != std::string::npos || name.find("INDD") != std::string::npos ||
|
||||
name.find("IOLDO") != std::string::npos || name.find("IOLTO") != std::string::npos ||
|
||||
name.find("JCE") != std::string::npos || name.find("JCLK") != std::string::npos ||
|
||||
name.find("JLSR") != std::string::npos || name.find("JONEG") != std::string::npos ||
|
||||
name.find("JOPOS") != std::string::npos || name.find("JTS") != std::string::npos ||
|
||||
name.find("PADD") != std::string::npos || name.find("INDD") != std::string::npos ||
|
||||
name.find("IOLDO") != std::string::npos || name.find("IOLTO") != std::string::npos ||
|
||||
// JCE0-3, JCLK0-3, JLSR0-3 connect to PIO wires named JCEA-D, JCLKA-D, JLSRA-D.
|
||||
name.find("JCEA") != std::string::npos || name.find("JCEB") != std::string::npos ||
|
||||
name.find("JCEC") != std::string::npos || name.find("JCED") != std::string::npos ||
|
||||
name.find("JCLKA") != std::string::npos || name.find("JCLKB") != std::string::npos ||
|
||||
name.find("JCLKC") != std::string::npos || name.find("JCLKD") != std::string::npos ||
|
||||
name.find("JLSRA") != std::string::npos || name.find("JLSRB") != std::string::npos ||
|
||||
name.find("JLSRC") != std::string::npos || name.find("JLSRD") != std::string::npos ||
|
||||
name.find("JONEG") != std::string::npos || name.find("JOPOS") != std::string::npos ||
|
||||
name.find("JTS") != std::string::npos ||
|
||||
name.find("JIN") != std::string::npos || name.find("JIP") != std::string::npos ||
|
||||
// Connections to global mux
|
||||
name.find("JINCK") != std::string::npos);
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix7 == "BRANCH_")
|
||||
@ -92,10 +102,19 @@ static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire)
|
||||
if (loc == wire.location) {
|
||||
// TODO: JINCK is not currently handled by this.
|
||||
if (is_pio_wire(basename)) {
|
||||
if (wire.location.x == 0)
|
||||
return "W1_" + basename;
|
||||
else if (wire.location.x == max_col)
|
||||
return "E1_" + basename;
|
||||
if (wire.location.x == 0) {
|
||||
std::string pio_name = "W1_" + basename;
|
||||
if (ctx->verbose)
|
||||
log_info("PIO wire %s was adjusted by W1 to form Trellis name %s.\n", ctx->nameOfWire(wire),
|
||||
pio_name.c_str());
|
||||
return pio_name;
|
||||
} else if (wire.location.x == max_col) {
|
||||
std::string pio_name = "E1_" + basename;
|
||||
if (ctx->verbose)
|
||||
log_info("PIO wire %s was adjusted by E1 to form Trellis name %s.\n", ctx->nameOfWire(wire),
|
||||
pio_name.c_str());
|
||||
return pio_name;
|
||||
}
|
||||
}
|
||||
return basename;
|
||||
}
|
||||
|
@ -19,6 +19,6 @@ set -ex
|
||||
${YOSYS:-yosys} -p "ghdl --std=08 prims.vhd ${1}.vhd -e;
|
||||
attrmap -tocase LOC
|
||||
synth_machxo2 -json ${1}-vhdl.json"
|
||||
${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json $1-vhdl.json --textcfg $1-vhdl.txt
|
||||
${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --json $1-vhdl.json --textcfg $1-vhdl.txt
|
||||
ecppack --compress $DB_ARG $1-vhdl.txt $1-vhdl.bit
|
||||
tinyproga -b $1-vhdl.bit
|
||||
|
@ -17,6 +17,6 @@ fi
|
||||
set -ex
|
||||
|
||||
${YOSYS:-yosys} -p "synth_machxo2 -json $1.json" $1.v
|
||||
${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --no-iobs --json $1.json --textcfg $1.txt
|
||||
${NEXTPNR:-../../nextpnr-machxo2} --1200 --package QFN32 --json $1.json --textcfg $1.txt
|
||||
ecppack --compress $DB_ARG $1.txt $1.bit
|
||||
tinyproga -b $1.bit
|
||||
|
@ -61,6 +61,7 @@ do_smt() {
|
||||
miter -equiv -make_assert gold gate ${2}${1}_miter
|
||||
hierarchy -top ${2}${1}_miter; proc;
|
||||
opt_clean
|
||||
flatten t:*FACADE_IO*
|
||||
write_verilog ${2}${1}_miter.v
|
||||
write_smt2 ${2}${1}_miter.smt2"
|
||||
|
||||
@ -71,8 +72,8 @@ do_smt() {
|
||||
set -ex
|
||||
|
||||
${YOSYS:-yosys} -p "read_verilog ${1}.v
|
||||
synth_machxo2 -noiopad -json ${1}.json"
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json
|
||||
synth_machxo2 -json ${1}.json"
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --json ${1}.json --write ${2}${1}.json
|
||||
${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v
|
||||
read_json ${2}${1}.json
|
||||
clean -purge
|
||||
|
@ -26,7 +26,7 @@ set -ex
|
||||
${YOSYS:-yosys} -p "read_verilog ${1}.v
|
||||
synth_machxo2 -json ${1}.json
|
||||
show -format png -prefix ${1}"
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --json ${1}.json --write ${2}${1}.json
|
||||
${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v
|
||||
read_json ${2}${1}.json
|
||||
clean -purge
|
||||
|
@ -30,7 +30,7 @@ set -ex
|
||||
|
||||
${YOSYS:-yosys} -p "read_verilog ${1}.v
|
||||
synth_machxo2 -json ${1}.json"
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --no-iobs --json ${1}.json --write ${2}${1}.json
|
||||
${NEXTPNR:-../../nextpnr-machxo2} $NEXTPNR_MODE --1200 --package QFN32 --json ${1}.json --write ${2}${1}.json
|
||||
${YOSYS:-yosys} -p "read_verilog -lib +/machxo2/cells_sim.v
|
||||
read_json ${2}${1}.json
|
||||
clean -purge
|
||||
|
@ -69,7 +69,6 @@ po::options_description MachXO2CommandHandler::getArchOptions()
|
||||
|
||||
// specific.add_options()("lpf", po::value<std::vector<std::string>>(), "LPF pin constraint file(s)");
|
||||
|
||||
specific.add_options()("no-iobs", "disable automatic IO buffer insertion (unimplemented- always enabled)");
|
||||
return specific;
|
||||
}
|
||||
|
||||
@ -108,8 +107,6 @@ std::unique_ptr<Context> MachXO2CommandHandler::createContext(dict<std::string,
|
||||
}
|
||||
|
||||
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||
if (vm.count("no-iobs"))
|
||||
ctx->settings[ctx->id("disable_iobs")] = Property::State::S1;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,45 @@ static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
|
||||
|
||||
static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; }
|
||||
|
||||
static bool nextpnr_iob_connects_only_facade_iob(Context *ctx, CellInfo *iob, NetInfo *&top)
|
||||
{
|
||||
NPNR_ASSERT(is_nextpnr_iob(ctx, iob));
|
||||
|
||||
if (iob->type == ctx->id("$nextpnr_ibuf")) {
|
||||
NetInfo *o = iob->ports.at(id_O).net;
|
||||
top = o;
|
||||
|
||||
CellInfo *fio = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
|
||||
return fio != nullptr;
|
||||
} else if (iob->type == ctx->id("$nextpnr_obuf")) {
|
||||
NetInfo *i = iob->ports.at(id_I).net;
|
||||
top = i;
|
||||
|
||||
// If connected to a FACADE_IO PAD, the net attached to an I port of an
|
||||
// $nextpnr_obuf will not have a driver, only users; an inout port
|
||||
// like PAD cannot be a driver in nextpnr. So net_driven_by won't
|
||||
// return anything. We exclude the IOB as one of the two users because
|
||||
// we already know that the net drives the $nextpnr_obuf.
|
||||
CellInfo *fio = net_only_drives(ctx, i, is_facade_iob, id_PAD, true, iob);
|
||||
return fio != nullptr;
|
||||
} else if (iob->type == ctx->id("$nextpnr_iobuf")) {
|
||||
NetInfo *o = iob->ports.at(id_O).net;
|
||||
top = o;
|
||||
|
||||
// When split_io is enabled in a frontend (it is for JSON), the I and O
|
||||
// ports of a $nextpnr_iobuf are split; the I port connects to the
|
||||
// driver of the original net before IOB insertion, and the O port
|
||||
// connects everything else. Because FACADE_IO PADs cannot be a driver
|
||||
// in nextpnr, the we can safely ignore the I port of an $nextpnr_iobuf
|
||||
// for any JSON input we're interested in accepting.
|
||||
CellInfo *fio_o = net_only_drives(ctx, o, is_facade_iob, id_PAD, true);
|
||||
return fio_o != nullptr;
|
||||
}
|
||||
|
||||
// Unreachable!
|
||||
NPNR_ASSERT(false);
|
||||
}
|
||||
|
||||
// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
|
||||
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
|
||||
// attributes.
|
||||
@ -241,6 +280,14 @@ static void pack_io(Context *ctx)
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second.get();
|
||||
if (is_nextpnr_iob(ctx, ci)) {
|
||||
NetInfo *top;
|
||||
|
||||
if (!nextpnr_iob_connects_only_facade_iob(ctx, ci, top))
|
||||
log_error("Top level net '%s' is not connected to a FACADE_IO PAD port.\n", top->name.c_str(ctx));
|
||||
|
||||
if (ctx->verbose)
|
||||
log_info("Removing top-level IOBUF '%s' of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
|
||||
|
||||
for (auto &p : ci->ports)
|
||||
disconnect_port(ctx, ci, p.first);
|
||||
packed_cells.insert(ci->name);
|
||||
|
Loading…
Reference in New Issue
Block a user