Merge pull request #858 from cr1901/machxo2

MachXO2 Checkpoint 2
This commit is contained in:
gatecat 2021-12-17 07:11:31 +00:00 committed by GitHub
commit a120577773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 18 deletions

View File

@ -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!

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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