aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie Hung <eddieh@ece.ubc.ca>2018-07-31 18:26:39 -0700
committerEddie Hung <eddieh@ece.ubc.ca>2018-07-31 18:26:39 -0700
commit5d58d6ad1b473ed7e3eb59a393a685b7ef219621 (patch)
tree7ea550e34111502879c803f2107bd8a4ecb211bc
parent87438542e51c91fd6bf838d4f2aceb3c79303a72 (diff)
parent8131921e998eda144c85984710ec421f67f18658 (diff)
downloadnextpnr-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.md5
-rw-r--r--common/place_common.cc6
-rw-r--r--ecp5/arch.cc60
-rw-r--r--ecp5/arch.h2
-rw-r--r--ecp5/archdefs.h13
-rw-r--r--ecp5/gfx.h35
-rw-r--r--ecp5/main.cc10
-rw-r--r--generic/arch.h2
-rw-r--r--gui/ecp5/mainwindow.cc2
-rw-r--r--gui/generic/mainwindow.cc2
-rw-r--r--gui/treemodel.cc4
-rw-r--r--ice40/arch.cc50
-rw-r--r--ice40/arch.h4
-rw-r--r--ice40/chipdb.py83
14 files changed, 214 insertions, 64 deletions
diff --git a/README.md b/README.md
index 51141b09..c22579ba 100644
--- a/README.md
+++ b/README.md
@@ -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)):