diff options
author | Eddie Hung <eddieh@ece.ubc.ca> | 2018-07-31 18:26:39 -0700 |
---|---|---|
committer | Eddie Hung <eddieh@ece.ubc.ca> | 2018-07-31 18:26:39 -0700 |
commit | 5d58d6ad1b473ed7e3eb59a393a685b7ef219621 (patch) | |
tree | 7ea550e34111502879c803f2107bd8a4ecb211bc | |
parent | 87438542e51c91fd6bf838d4f2aceb3c79303a72 (diff) | |
parent | 8131921e998eda144c85984710ec421f67f18658 (diff) | |
download | nextpnr-5d58d6ad1b473ed7e3eb59a393a685b7ef219621.tar.gz nextpnr-5d58d6ad1b473ed7e3eb59a393a685b7ef219621.tar.bz2 nextpnr-5d58d6ad1b473ed7e3eb59a393a685b7ef219621.zip |
Merge branch 'redist_slack' of gitlab.com:SymbioticEDA/nextpnr into redist_slack
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | common/place_common.cc | 6 | ||||
-rw-r--r-- | ecp5/arch.cc | 60 | ||||
-rw-r--r-- | ecp5/arch.h | 2 | ||||
-rw-r--r-- | ecp5/archdefs.h | 13 | ||||
-rw-r--r-- | ecp5/gfx.h | 35 | ||||
-rw-r--r-- | ecp5/main.cc | 10 | ||||
-rw-r--r-- | generic/arch.h | 2 | ||||
-rw-r--r-- | gui/ecp5/mainwindow.cc | 2 | ||||
-rw-r--r-- | gui/generic/mainwindow.cc | 2 | ||||
-rw-r--r-- | gui/treemodel.cc | 4 | ||||
-rw-r--r-- | ice40/arch.cc | 50 | ||||
-rw-r--r-- | ice40/arch.h | 4 | ||||
-rw-r--r-- | ice40/chipdb.py | 83 |
14 files changed, 214 insertions, 64 deletions
@@ -162,3 +162,8 @@ Links and references - [SymbiFlow](https://github.com/SymbiFlow/symbiflow-arch-defs) - [Gaffe](https://github.com/kc8apf/gaffe) - [KinglerPAR](https://github.com/rqou/KinglerPAR) + +> SymbiFlow is working with the Verilog to Routing tool to extend the current +research tool to support real architectures. VtR is strongly focused on +architecture research but having support for real architectures might enable +research nextpnr zu providing documentation and explanation. diff --git a/common/place_common.cc b/common/place_common.cc index d9d40714..9bc24303 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -39,6 +39,8 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type driver_loc = ctx->getBelLocation(driver_cell->bel); if (driver_gb) return 0; + + delay_t negative_slack = 0; delay_t worst_slack = std::numeric_limits<delay_t>::max(); int xmin = driver_loc.x, xmax = driver_loc.x, ymin = driver_loc.y, ymax = driver_loc.y; for (auto load : net->users) { @@ -51,7 +53,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type delay_t net_delay = ctx->predictDelay(net, load); auto slack = load.budget - net_delay; if (slack < 0) - tns += slack; + negative_slack += slack; worst_slack = std::min(slack, worst_slack); } @@ -70,7 +72,7 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type wirelength = wirelen_t((ymax - ymin) + (xmax - xmin)); } - tns = ctx->getDelayNS(tns); + tns += ctx->getDelayNS(negative_slack); return wirelength; } diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 6fa26e1a..14b5b8f2 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -21,6 +21,7 @@ #include <algorithm> #include <cmath> #include <cstring> +#include "gfx.h" #include "log.h" #include "nextpnr.h" #include "placer1.h" @@ -140,9 +141,8 @@ Arch::Arch(ArchArgs args) : args(args) // ----------------------------------------------------------------------- -std::string Arch::getChipName() +std::string Arch::getChipName() const { - if (args.type == ArchArgs::LFE5U_25F) { return "LFE5U-25F"; } else if (args.type == ArchArgs::LFE5U_45F) { @@ -432,16 +432,64 @@ bool Arch::route() { return router1(getCtx()); } // ----------------------------------------------------------------------- -std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decalId) const +std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const { std::vector<GraphicElement> ret; - // FIXME + + if (decal.type == DecalId::TYPE_FRAME) { + /* nothing */ + } + + if (decal.type == DecalId::TYPE_BEL) { + BelId bel; + bel.index = decal.z; + bel.location = decal.location; + int z = locInfo(bel)->bel_data[bel.index].z; + auto bel_type = getBelType(bel); + + if (bel_type == TYPE_TRELLIS_SLICE) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = bel.location.x + logic_cell_x1; + el.x2 = bel.location.x + logic_cell_x2; + el.y1 = bel.location.y + logic_cell_y1 + (z)*logic_cell_pitch; + el.y2 = bel.location.y + logic_cell_y2 + (z)*logic_cell_pitch; + ret.push_back(el); + } + + if (bel_type == TYPE_TRELLIS_IO) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = bel.location.x + logic_cell_x1; + el.x2 = bel.location.x + logic_cell_x2; + el.y1 = bel.location.y + logic_cell_y1 + (2 * z) * logic_cell_pitch; + el.y2 = bel.location.y + logic_cell_y2 + (2 * z + 1) * logic_cell_pitch; + ret.push_back(el); + } + } + return ret; } -DecalXY Arch::getFrameDecal() const { return {}; } +DecalXY Arch::getFrameDecal() const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_FRAME; + decalxy.decal.active = true; + return decalxy; +} -DecalXY Arch::getBelDecal(BelId bel) const { return {}; } +DecalXY Arch::getBelDecal(BelId bel) const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_BEL; + decalxy.decal.location = bel.location; + decalxy.decal.z = bel.index; + decalxy.decal.active = bel_to_cell.count(bel) && (bel_to_cell.at(bel) != IdString()); + return decalxy; +} DecalXY Arch::getWireDecal(WireId wire) const { return {}; } diff --git a/ecp5/arch.h b/ecp5/arch.h index 62a035aa..255bafc7 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -399,7 +399,7 @@ struct Arch : BaseCtx ArchArgs args; Arch(ArchArgs args); - std::string getChipName(); + std::string getChipName() const; IdString archId() const { return id("ecp5"); } IdString archArgsToId(ArchArgs args) const; diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index 40442e1b..829db683 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -120,17 +120,21 @@ struct GroupId struct DecalId { - char type = 0; // Bel/Wire/Pip/Frame (b/w/p/f) + enum + { + TYPE_FRAME, + TYPE_BEL + } type; Location location; uint32_t z = 0; - + bool active = false; bool operator==(const DecalId &other) const { - return type == other.type && location == other.location && z == other.z; + return type == other.type && location == other.location && z == other.z && active == other.active; } bool operator!=(const DecalId &other) const { - return type != other.type || location != other.location || z != other.z; + return type != other.type || location != other.location || z != other.z || active != other.active; } }; @@ -200,6 +204,7 @@ template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId> boost::hash_combine(seed, hash<int>()(decal.type)); boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location)); boost::hash_combine(seed, hash<int>()(decal.z)); + boost::hash_combine(seed, hash<bool>()(decal.active)); return seed; } }; diff --git a/ecp5/gfx.h b/ecp5/gfx.h new file mode 100644 index 00000000..0290d2f6 --- /dev/null +++ b/ecp5/gfx.h @@ -0,0 +1,35 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 David Shah <david@symbioticeda.com> + * + * 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. + * + */ + +#ifndef ECP5_GFX_H +#define ECP5_GFX_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +const float logic_cell_x1 = 0.76; +const float logic_cell_x2 = 0.95; +const float logic_cell_y1 = 0.05; +const float logic_cell_y2 = 0.15; +const float logic_cell_pitch = 0.125; + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/ecp5/main.cc b/ecp5/main.cc index 9f683a7b..68660ced 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -100,16 +100,18 @@ int main(int argc, char *argv[]) } if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; std::cout << "\n"; std::cout << options << "\n"; return argc != 1; } if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; return 1; } diff --git a/generic/arch.h b/generic/arch.h index 0c831004..154a2352 100644 --- a/generic/arch.h +++ b/generic/arch.h @@ -122,7 +122,7 @@ struct Arch : BaseCtx Arch(ArchArgs args); - std::string getChipName() { return chipName; } + std::string getChipName() const { return chipName; } IdString archId() const { return id("generic"); } IdString archArgsToId(ArchArgs args) const { return id("none"); } diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index 1168a55c..4b1c7e3b 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -40,6 +40,8 @@ void MainWindow::createMenu() {
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction());
+
+ createGraphicsBar();
}
void MainWindow::new_proj() {}
diff --git a/gui/generic/mainwindow.cc b/gui/generic/mainwindow.cc index 88e291e6..1efc73bb 100644 --- a/gui/generic/mainwindow.cc +++ b/gui/generic/mainwindow.cc @@ -40,6 +40,8 @@ void MainWindow::createMenu() {
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
menuBar->addAction(menu_Custom->menuAction());
+
+ createGraphicsBar();
}
void MainWindow::new_proj() {}
diff --git a/gui/treemodel.cc b/gui/treemodel.cc index d79e38de..d42dc401 100644 --- a/gui/treemodel.cc +++ b/gui/treemodel.cc @@ -141,6 +141,7 @@ void ContextTreeModel::loadData(Context *ctx) QMap<QString, ContextTreeItem *> pip_items; // Add pips to tree +#ifndef ARCH_ECP5 for (auto pip : ctx->getPips()) { auto id = ctx->getPipName(pip); QStringList items = QString(id.c_str(ctx)).split("/"); @@ -164,6 +165,7 @@ void ContextTreeModel::loadData(Context *ctx) parent = pip_items[name]; } } +#endif pip_root->sort(); nets_root = new ContextTreeItem("Nets"); @@ -341,4 +343,4 @@ QList<QModelIndex> ContextTreeModel::search(QString text) } return list; } -NEXTPNR_NAMESPACE_END
\ No newline at end of file +NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.cc b/ice40/arch.cc index 76ce6a39..bdfb13fe 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -204,7 +204,7 @@ Arch::Arch(ArchArgs args) : args(args) // ----------------------------------------------------------------------- -std::string Arch::getChipName() +std::string Arch::getChipName() const { #ifdef ICE40_HX1K_ONLY if (args.type == ArchArgs::HX1K) { @@ -311,9 +311,23 @@ PortType Arch::getBelPinType(BelId bel, PortPin pin) const int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - for (int i = 0; i < num_bel_wires; i++) - if (bel_wires[i].port == pin) - return PortType(bel_wires[i].type); + if (num_bel_wires < 7) { + for (int i = 0; i < num_bel_wires; i++) { + if (bel_wires[i].port == pin) + return PortType(bel_wires[i].type); + } + } else { + int b = 0, e = num_bel_wires-1; + while (b <= e) { + int i = (b+e) / 2; + if (bel_wires[i].port == pin) + return PortType(bel_wires[i].type); + if (bel_wires[i].port > pin) + e = i-1; + else + b = i+1; + } + } return PORT_INOUT; } @@ -327,10 +341,25 @@ WireId Arch::getBelPinWire(BelId bel, PortPin pin) const int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - for (int i = 0; i < num_bel_wires; i++) { - if (bel_wires[i].port == pin) { - ret.index = bel_wires[i].wire_index; - break; + if (num_bel_wires < 7) { + for (int i = 0; i < num_bel_wires; i++) { + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + } + } else { + int b = 0, e = num_bel_wires-1; + while (b <= e) { + int i = (b+e) / 2; + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + if (bel_wires[i].port > pin) + e = i-1; + else + b = i+1; } } @@ -602,6 +631,11 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const int xd = sink_loc.x - driver_loc.x, yd = sink_loc.y - driver_loc.y; int xscale = 120, yscale = 120, offset = 0; + // if (chip_info->wire_data[src.index].type == WIRE_TYPE_SP4_VERT) { + // yd = yd < -4 ? yd + 4 : (yd < 0 ? 0 : yd); + // offset = 500; + // } + if (driver.port == id_o) offset += 330; if (sink.port == id_i0 || sink.port == id_i1 || sink.port == id_i2 || sink.port == id_i3) offset += 260; diff --git a/ice40/arch.h b/ice40/arch.h index a4d148e5..92698b4d 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -44,9 +44,9 @@ template <typename T> struct RelPtr }; NPNR_PACKED_STRUCT(struct BelWirePOD { - int32_t wire_index; PortPin port; int32_t type; + int32_t wire_index; }); NPNR_PACKED_STRUCT(struct BelInfoPOD { @@ -365,7 +365,7 @@ struct Arch : BaseCtx ArchArgs args; Arch(ArchArgs args); - std::string getChipName(); + std::string getChipName() const; IdString archId() const { return id("ice40"); } IdString archArgsToId(ArchArgs args) const; diff --git a/ice40/chipdb.py b/ice40/chipdb.py index 3ef58185..97ccbe48 100644 --- a/ice40/chipdb.py +++ b/ice40/chipdb.py @@ -214,56 +214,71 @@ def wire_type(name): assert 0 return wt -def pipdelay(src, dst, db): +def pipdelay(src_idx, dst_idx, db): if db is None: return 0 - src = wire_names_r[src] - dst = wire_names_r[dst] + src = wire_names_r[src_idx] + dst = wire_names_r[dst_idx] src_type = wire_type(src[2]) dst_type = wire_type(dst[2]) - if dst[2].startswith("local_"): - return db["LocalMux.I.O"] + if dst[2].startswith("sp4_") or dst[2].startswith("span4_"): + if src[2].startswith("sp12_") or src[2].startswith("span12_"): + return db["Sp12to4.I.O"] + + if src[2].startswith("span4_"): + return db["IoSpan4Mux.I.O"] + + if dst[2].startswith("sp4_h_"): + return db["Span4Mux_h4.I.O"] + else: + return db["Span4Mux_v4.I.O"] - if src_type == "LOCAL" and dst_type == "LOCAL": - return 250 + if dst[2].startswith("sp12_") or dst[2].startswith("span12_"): + if dst[2].startswith("sp12_h_"): + return db["Span12Mux_h12.I.O"] + else: + return db["Span12Mux_v12.I.O"] - if src_type == "GLOBAL" and dst_type == "LOCAL": - return 400 + if dst[2] in ("fabout", "clk"): + return 0 # FIXME? - # Local -> Span + if src[2].startswith("glb_netwk_") and dst[2].startswith("glb2local_"): + return 0 # FIXME? - if src_type == "LOCAL" and dst_type in ("SP4_HORZ", "SP4_VERT"): - return 350 + if dst[2] == "carry_in_mux": + return db["ICE_CARRY_IN_MUX.carryinitin.carryinitout"] - if src_type == "LOCAL" and dst_type in ("SP12_HORZ", "SP12_VERT"): - return 500 + if dst[2] in ("lutff_global/clk", "io_global/inclk", "io_global/outclk", "ram/RCLK", "ram/WCLK"): + return db["ClkMux.I.O"] - # Span -> Local + if dst[2] in ("lutff_global/s_r", "io_global/latch", "ram/RE", "ram/WE"): + return db["SRMux.I.O"] - if src_type in ("SP4_HORZ", "SP4_VERT", "SP12_HORZ", "SP12_VERT") and dst_type == "LOCAL": - return 300 + if dst[2] in ("lutff_global/cen", "io_global/cen", "ram/RCLKE", "ram/WCLKE"): + return db["CEMux.I.O"] - # Span -> Span + if dst[2].startswith("local_"): + return db["LocalMux.I.O"] - if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP12_HORZ", "SP12_VERT"): - return 450 + if src[2].startswith("local_") and dst[2] in ("io_0/D_OUT_0", "io_0/D_OUT_1", "io_0/OUT_ENB", "io_1/D_OUT_0", "io_1/D_OUT_1", "io_1/OUT_ENB"): + return db["IoInMux.I.O"] - if src_type in ("SP4_HORZ", "SP4_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"): - return 300 + if re.match(r"lutff_\d+/in_\d+", dst[2]): + return db["InMux.I.O"] - if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"): - return 380 + if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]): + return db["InMux.I.O"] - # print(src, dst, src_type, dst_type, file=sys.stderr) + print(src, dst, src_idx, dst_idx, src_type, dst_type, file=sys.stderr) assert 0 -def wiredelay(wire, db): +def wiredelay(wire_idx, db): if db is None: return 0 - wire = wire_names_r[wire] + wire = wire_names_r[wire_idx] wtype = wire_type(wire[2]) # FIXME @@ -492,13 +507,13 @@ def add_bel_input(bel, wire, port): if wire not in wire_belports: wire_belports[wire] = set() wire_belports[wire].add((bel, port)) - bel_wires[bel].append((wire, port, 0)) + bel_wires[bel].append((portpins[port], 0, wire)) def add_bel_output(bel, wire, port): if wire not in wire_belports: wire_belports[wire] = set() wire_belports[wire].add((bel, port)) - bel_wires[bel].append((wire, port, 1)) + bel_wires[bel].append((portpins[port], 1, wire)) def add_bel_lc(x, y, z): bel = len(bel_name) @@ -759,14 +774,12 @@ bba.post('NEXTPNR_NAMESPACE_END') bba.push("chipdb_blob_%s" % dev_name) bba.r("chip_info_%s" % dev_name, "chip_info") -index = 0 for bel in range(len(bel_name)): bba.l("bel_wires_%d" % bel, "BelWirePOD") - for i in range(len(bel_wires[bel])): - bba.u32(bel_wires[bel][i][0], "wire_index") - bba.u32(portpins[bel_wires[bel][i][1]], "port") - bba.u32(bel_wires[bel][i][2], "type") - index += 1 + for data in sorted(bel_wires[bel]): + bba.u32(data[0], "port") + bba.u32(data[1], "type") + bba.u32(data[2], "wire_index") bba.l("bel_data_%s" % dev_name, "BelInfoPOD") for bel in range(len(bel_name)): |