From eb15463406c5784f7c3599163ba40571188d57c7 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 9 Jan 2020 19:02:01 +0000 Subject: [PATCH] nexus: Add routing FASM export Signed-off-by: David Shah --- nexus/arch.h | 21 ++++++- nexus/bba_version.inc | 2 +- nexus/fasm.cc | 143 ++++++++++++++++++++++++++++++++++++++++++ nexus/main.cc | 13 +++- 4 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 nexus/fasm.cc diff --git a/nexus/arch.h b/nexus/arch.h index 2f6c5f7e..f46f51c7 100644 --- a/nexus/arch.h +++ b/nexus/arch.h @@ -100,8 +100,15 @@ NPNR_PACKED_STRUCT(struct LocWireInfoPOD { RelPtr bel_pins; }); +enum PipFlags +{ + PIP_FIXED_CONN = 0x8000, +}; + NPNR_PACKED_STRUCT(struct PipInfoPOD { uint16_t from_wire, to_wire; + uint16_t flags; + uint16_t padding; int32_t tile_type; }); @@ -1115,7 +1122,16 @@ struct Arch : BaseCtx { return chip_canonical_wire(db, chip_info, tile, index); } - + IdString pip_src_wire_name(PipId pip) const + { + int wire = pip_data(pip).from_wire; + return db->loctypes[chip_info->grid[pip.tile].loc_type].wires[wire].name; + } + IdString pip_dst_wire_name(PipId pip) const + { + int wire = pip_data(pip).to_wire; + return db->loctypes[chip_info->grid[pip.tile].loc_type].wires[wire].name; + } // ------------------------------------------------- NeighWireRange neigh_wire_range(WireId wire) const @@ -1136,6 +1152,9 @@ struct Arch : BaseCtx // ------------------------------------------------- bool nexus_logic_tile_valid(LogicTileStatus <s) const; + + // ------------------------------------------------- + void write_fasm(std::ostream &out) const; }; NEXTPNR_NAMESPACE_END diff --git a/nexus/bba_version.inc b/nexus/bba_version.inc index 0cfbf088..00750edc 100644 --- a/nexus/bba_version.inc +++ b/nexus/bba_version.inc @@ -1 +1 @@ -2 +3 diff --git a/nexus/fasm.cc b/nexus/fasm.cc new file mode 100644 index 00000000..36656ec4 --- /dev/null +++ b/nexus/fasm.cc @@ -0,0 +1,143 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2020 David Shah + * + * + * 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" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN +namespace { +struct NexusFasmWriter +{ + const Context *ctx; + std::ostream &out; + std::vector fasm_ctx; + + void push(const std::string &x) { fasm_ctx.push_back(x); } + + void pop() { fasm_ctx.pop_back(); } + + void pop(int N) + { + for (int i = 0; i < N; i++) + fasm_ctx.pop_back(); + } + bool last_was_blank = true; + void blank() + { + if (!last_was_blank) + out << std::endl; + last_was_blank = true; + } + + void write_prefix() + { + for (auto &x : fasm_ctx) + out << x << "."; + last_was_blank = false; + } + + void write_bit(const std::string &name, bool value = true) + { + if (value) { + write_prefix(); + out << name << std::endl; + } + } + void write_comment(const std::string &cmt) { out << "# " << cmt << std::endl; } + + void write_vector(const std::string &name, const std::vector &value, bool invert = false) + { + write_prefix(); + out << name << " = " << int(value.size()) << "'b"; + for (auto bit : boost::adaptors::reverse(value)) + out << ((bit ^ invert) ? '1' : '0'); + out << std::endl; + } + + void write_int_vector(const std::string &name, uint64_t value, int width, bool invert = false) + { + std::vector bits(width, false); + for (int i = 0; i < width; i++) + bits[i] = (value & (1ULL << i)) != 0; + write_vector(name, bits, invert); + } + + NexusFasmWriter(const Context *ctx, std::ostream &out) : ctx(ctx), out(out) {} + std::string tile_name(int loc, const PhysicalTileInfoPOD &tile) + { + int r = loc / ctx->chip_info->width; + int c = loc % ctx->chip_info->width; + return stringf("%sR%dC%d__%s", ctx->nameOf(tile.prefix), r, c, ctx->nameOf(tile.tiletype)); + } + const PhysicalTileInfoPOD &tile_by_type_and_loc(int loc, IdString type) + { + auto &ploc = ctx->chip_info->grid[loc]; + for (int i = 0; i < ploc.num_phys_tiles; i++) { + if (ploc.phys_tiles[i].tiletype == type.index) + return ploc.phys_tiles[i]; + } + log_error("No tile of type %s found at location R%dC%d", ctx->nameOf(type), loc / ctx->chip_info->width, + loc % ctx->chip_info->width); + } + std::string escape_name(const std::string &name) + { + std::string escaped; + for (char c : name) { + if (c == ':') + escaped += "__"; + else + escaped += c; + } + return escaped; + } + void write_pip(PipId pip) + { + auto &pd = ctx->pip_data(pip); + if (pd.flags & PIP_FIXED_CONN) + return; + std::string tile = tile_name(pip.tile, tile_by_type_and_loc(pip.tile, pd.tile_type)); + std::string source_wire = escape_name(ctx->pip_src_wire_name(pip).str(ctx)); + std::string dest_wire = escape_name(ctx->pip_src_wire_name(pip).str(ctx)); + write_bit(stringf("%s.PIP.%s.%s", tile.c_str(), dest_wire.c_str(), source_wire.c_str())); + } + void write_net(const NetInfo *net) + { + write_comment(stringf("Net %s", ctx->nameOf(net))); + std::set sorted_pips; + for (auto &w : net->wires) + sorted_pips.insert(w.second.pip); + for (auto p : sorted_pips) + write_pip(p); + blank(); + } + void operator()() + { + // Write routing + for (auto n : sorted(ctx->nets)) { + write_net(n.second); + } + } +}; +} // namespace + +void Arch::write_fasm(std::ostream &out) const { NexusFasmWriter(getCtx(), out)(); } + +NEXTPNR_NAMESPACE_END diff --git a/nexus/main.cc b/nexus/main.cc index 77f739a8..9549a573 100644 --- a/nexus/main.cc +++ b/nexus/main.cc @@ -49,11 +49,20 @@ po::options_description NexusCommandHandler::getArchOptions() po::options_description specific("Architecture specific options"); specific.add_options()("chipdb", po::value(), "name of chip database binary"); specific.add_options()("device", po::value(), "device name"); - + specific.add_options()("fasm", po::value(), "fasm file to write"); return specific; } -void NexusCommandHandler::customBitstream(Context *ctx) {} +void NexusCommandHandler::customBitstream(Context *ctx) +{ + if (vm.count("fasm")) { + std::string filename = vm["fasm"].as(); + std::ofstream out(filename); + if (!out) + log_error("Failed to open output FASM file %s.\n", filename.c_str()); + ctx->write_fasm(out); + } +} std::unique_ptr NexusCommandHandler::createContext(std::unordered_map &values) {