Merge branch 'redist_slack' of gitlab.com:SymbioticEDA/nextpnr into redist_slack
This commit is contained in:
commit
5d58d6ad1b
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
60
ecp5/arch.cc
60
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 {}; }
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
35
ecp5/gfx.h
Normal file
35
ecp5/gfx.h
Normal file
@ -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
|
10
ecp5/main.cc
10
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;
|
||||
}
|
||||
|
||||
|
@ -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"); }
|
||||
|
@ -40,6 +40,8 @@ void MainWindow::createMenu()
|
||||
{
|
||||
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
|
||||
menuBar->addAction(menu_Custom->menuAction());
|
||||
|
||||
createGraphicsBar();
|
||||
}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
@ -40,6 +40,8 @@ void MainWindow::createMenu()
|
||||
{
|
||||
QMenu *menu_Custom = new QMenu("&Generic", menuBar);
|
||||
menuBar->addAction(menu_Custom->menuAction());
|
||||
|
||||
createGraphicsBar();
|
||||
}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
@ -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
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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("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 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 dst[2] in ("fabout", "clk"):
|
||||
return 0 # FIXME?
|
||||
|
||||
if src[2].startswith("glb_netwk_") and dst[2].startswith("glb2local_"):
|
||||
return 0 # FIXME?
|
||||
|
||||
if dst[2] == "carry_in_mux":
|
||||
return db["ICE_CARRY_IN_MUX.carryinitin.carryinitout"]
|
||||
|
||||
if dst[2] in ("lutff_global/clk", "io_global/inclk", "io_global/outclk", "ram/RCLK", "ram/WCLK"):
|
||||
return db["ClkMux.I.O"]
|
||||
|
||||
if dst[2] in ("lutff_global/s_r", "io_global/latch", "ram/RE", "ram/WE"):
|
||||
return db["SRMux.I.O"]
|
||||
|
||||
if dst[2] in ("lutff_global/cen", "io_global/cen", "ram/RCLKE", "ram/WCLKE"):
|
||||
return db["CEMux.I.O"]
|
||||
|
||||
if dst[2].startswith("local_"):
|
||||
return db["LocalMux.I.O"]
|
||||
|
||||
if src_type == "LOCAL" and dst_type == "LOCAL":
|
||||
return 250
|
||||
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 == "GLOBAL" and dst_type == "LOCAL":
|
||||
return 400
|
||||
if re.match(r"lutff_\d+/in_\d+", dst[2]):
|
||||
return db["InMux.I.O"]
|
||||
|
||||
# Local -> Span
|
||||
if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]):
|
||||
return db["InMux.I.O"]
|
||||
|
||||
if src_type == "LOCAL" and dst_type in ("SP4_HORZ", "SP4_VERT"):
|
||||
return 350
|
||||
|
||||
if src_type == "LOCAL" and dst_type in ("SP12_HORZ", "SP12_VERT"):
|
||||
return 500
|
||||
|
||||
# Span -> Local
|
||||
|
||||
if src_type in ("SP4_HORZ", "SP4_VERT", "SP12_HORZ", "SP12_VERT") and dst_type == "LOCAL":
|
||||
return 300
|
||||
|
||||
# Span -> Span
|
||||
|
||||
if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP12_HORZ", "SP12_VERT"):
|
||||
return 450
|
||||
|
||||
if src_type in ("SP4_HORZ", "SP4_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"):
|
||||
return 300
|
||||
|
||||
if src_type in ("SP12_HORZ", "SP12_VERT") and dst_type in ("SP4_HORZ", "SP4_VERT"):
|
||||
return 380
|
||||
|
||||
# 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)):
|
||||
|
Loading…
Reference in New Issue
Block a user