aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt9
-rw-r--r--README.md7
-rw-r--r--common/log.cc12
-rw-r--r--common/log.h3
-rw-r--r--common/placer1.cc65
-rw-r--r--docs/archapi.md15
-rw-r--r--ecp5/arch.cc4
-rw-r--r--ecp5/arch.h18
-rw-r--r--generic/arch.cc21
-rw-r--r--generic/arch.h10
-rw-r--r--gui/designwidget.cc15
-rw-r--r--ice40/arch.cc41
-rw-r--r--ice40/arch.h11
-rw-r--r--ice40/arch_place.cc29
-rw-r--r--ice40/bitstream.cc10
-rw-r--r--ice40/chains.cc2
-rw-r--r--ice40/chipdb.py214
-rw-r--r--ice40/family.cmake4
-rw-r--r--ice40/gfx.cc153
-rw-r--r--ice40/gfx.h155
-rw-r--r--json/jsonparse.cc32
21 files changed, 756 insertions, 74 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4c222d71..0cf55eb8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,6 +5,13 @@ project(nextpnr)
option(BUILD_GUI "Build GUI" ON)
option(BUILD_PYTHON "Build Python Integration" ON)
option(BUILD_TESTS "Build GUI" OFF)
+option(STATIC_BUILD "Create static build" OFF)
+
+set(link_param "")
+if (STATIC_BUILD)
+ set(Boost_USE_STATIC_LIBS ON)
+ set(link_param "-static")
+endif()
# List of families to build
set(FAMILIES generic ice40 ecp5)
@@ -211,7 +218,7 @@ foreach (family ${ARCH})
# Include family-specific source files to all family targets and set defines appropriately
target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/)
target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family})
- target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES})
+ target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} ${link_param})
if (NOT MSVC)
target_link_libraries(${target} LINK_PUBLIC pthread)
endif()
diff --git a/README.md b/README.md
index e9f197cd..a47a06a7 100644
--- a/README.md
+++ b/README.md
@@ -127,6 +127,13 @@ cmake -DARCH=ice40 -DCMAKE_BUILD_TYPE=Debug -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -
make -j$(nproc)
```
+To make static build relase for iCE40 architecture use the following:
+
+```
+cmake -DARCH=ice40 -DBUILD_PYTHON=OFF -DBUILD_GUI=OFF -DSTATIC_BUILD=ON .
+make -j$(nproc)
+```
+
Notes for developers
--------------------
diff --git a/common/log.cc b/common/log.cc
index df5430bb..e30449ad 100644
--- a/common/log.cc
+++ b/common/log.cc
@@ -46,6 +46,18 @@ void (*log_error_atexit)() = NULL;
// static bool next_print_log = false;
static int log_newline_count = 0;
+std::string stringf(const char *fmt, ...)
+{
+ std::string string;
+ va_list ap;
+
+ va_start(ap, fmt);
+ string = vstringf(fmt, ap);
+ va_end(ap);
+
+ return string;
+}
+
std::string vstringf(const char *fmt, va_list ap)
{
std::string string;
diff --git a/common/log.h b/common/log.h
index 74b9f0f5..b5fddf53 100644
--- a/common/log.h
+++ b/common/log.h
@@ -51,6 +51,9 @@ extern bool log_quiet_warnings;
extern std::string log_last_error;
extern void (*log_error_atexit)();
+std::string stringf(const char *fmt, ...);
+std::string vstringf(const char *fmt, va_list ap);
+
extern std::ostream clog;
void log(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
void log_always(const char *format, ...) NPNR_ATTRIBUTE(format(printf, 1, 2));
diff --git a/common/placer1.cc b/common/placer1.cc
index 4171e21b..363b4d58 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -71,6 +71,19 @@ class SAPlacer
fast_bels.at(type_idx).at(loc.x).at(loc.y).push_back(bel);
}
diameter = std::max(max_x, max_y) + 1;
+
+ costs.resize(ctx->nets.size());
+ old_udata.reserve(ctx->nets.size());
+ decltype(NetInfo::udata) n = 0;
+ for (auto &net : ctx->nets) {
+ old_udata.emplace_back(net.second->udata);
+ net.second->udata = n++;
+ }
+ }
+
+ ~SAPlacer() {
+ for (auto &net : ctx->nets)
+ net.second->udata = old_udata[net.second->udata];
}
bool place()
@@ -148,7 +161,7 @@ class SAPlacer
curr_tns = 0;
for (auto &net : ctx->nets) {
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
- metrics[net.first] = wl;
+ costs[net.second->udata] = CostChange{wl, -1};
curr_metric += wl;
}
@@ -249,7 +262,7 @@ class SAPlacer
curr_tns = 0;
for (auto &net : ctx->nets) {
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
- metrics[net.first] = wl;
+ costs[net.second->udata] = CostChange{wl, -1};
curr_metric += wl;
}
@@ -338,10 +351,8 @@ class SAPlacer
// Attempt a SA position swap, return true on success or false on failure
bool try_swap_position(CellInfo *cell, BelId newBel)
{
- static std::unordered_set<NetInfo *> update;
- static std::vector<std::pair<IdString, wirelen_t>> new_lengths;
- new_lengths.clear();
- update.clear();
+ static std::vector<NetInfo*> updates;
+ updates.clear();
BelId oldBel = cell->bel;
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
if (other_cell != nullptr && other_cell->belStrength > STRENGTH_WEAK) {
@@ -357,14 +368,23 @@ class SAPlacer
ctx->unbindBel(newBel);
}
- for (const auto &port : cell->ports)
- if (port.second.net != nullptr)
- update.insert(port.second.net);
+ for (const auto &port : cell->ports) {
+ if (port.second.net != nullptr) {
+ auto &cost = costs[port.second.net->udata];
+ if (cost.new_cost == 0) continue;
+ cost.new_cost = 0;
+ updates.emplace_back(port.second.net);
+ }
+ }
if (other_cell != nullptr) {
for (const auto &port : other_cell->ports)
- if (port.second.net != nullptr)
- update.insert(port.second.net);
+ if (port.second.net != nullptr) {
+ auto &cost = costs[port.second.net->udata];
+ if (cost.new_cost == 0) continue;
+ cost.new_cost = 0;
+ updates.emplace_back(port.second.net);
+ }
}
ctx->bindBel(newBel, cell, STRENGTH_WEAK);
@@ -382,12 +402,13 @@ class SAPlacer
new_metric = curr_metric;
// Recalculate metrics for all nets touched by the peturbation
- for (auto net : update) {
- new_metric -= metrics.at(net->name);
+ for (const auto &net : updates) {
+ auto &c = costs[net->udata];
+ new_metric -= c.curr_cost;
float temp_tns = 0;
wirelen_t net_new_wl = get_net_metric(ctx, net, MetricType::COST, temp_tns);
new_metric += net_new_wl;
- new_lengths.push_back(std::make_pair(net->name, net_new_wl));
+ c.new_cost = net_new_wl;
}
new_dist = get_constraints_distance(ctx, cell);
@@ -406,8 +427,10 @@ class SAPlacer
goto swap_fail;
}
curr_metric = new_metric;
- for (auto new_wl : new_lengths)
- metrics.at(new_wl.first) = new_wl.second;
+ for (const auto &net : updates) {
+ auto &c = costs[net->udata];
+ c = CostChange{c.new_cost, -1};
+ }
return true;
swap_fail:
@@ -415,6 +438,8 @@ class SAPlacer
if (other_cell != nullptr) {
ctx->bindBel(newBel, other_cell, STRENGTH_WEAK);
}
+ for (const auto &net : updates)
+ costs[net->udata].new_cost = -1;
return false;
}
@@ -443,7 +468,6 @@ class SAPlacer
}
Context *ctx;
- std::unordered_map<IdString, wirelen_t> metrics;
wirelen_t curr_metric = std::numeric_limits<wirelen_t>::max();
float curr_tns = 0;
float temp = 1000;
@@ -458,6 +482,13 @@ class SAPlacer
const float post_legalise_temp = 10;
const float post_legalise_dia_scale = 1.5;
Placer1Cfg cfg;
+
+ struct CostChange {
+ wirelen_t curr_cost;
+ wirelen_t new_cost;
+ };
+ std::vector<CostChange> costs;
+ std::vector<decltype(NetInfo::udata)> old_udata;
};
Placer1Cfg::Placer1Cfg(Context *ctx) : Settings(ctx) { constraintWeight = get<float>("placer1/constraintWeight", 10); }
diff --git a/docs/archapi.md b/docs/archapi.md
index 473cdd2e..73443c15 100644
--- a/docs/archapi.md
+++ b/docs/archapi.md
@@ -151,6 +151,11 @@ Return a list of all bels on the device.
Return the type of a given bel.
+### const\_range\<std\:\:pair\<IdString, std::string\>\> getBelAttrs(BelId bel) const
+
+Return the attributes for that bel. Bel attributes are only informal. They are displayed by the GUI but are otherwise
+unused. An implementation may simply return an empty range.
+
### WireId getBelPinWire(BelId bel, IdString pin) const
Return the wire connected to the given bel pin.
@@ -180,6 +185,11 @@ Get the type of a wire. The wire type is purely informal and
isn't used by any of the core algorithms. Implementations may
simply return `IdString()`.
+### const\_range\<std\:\:pair\<IdString, std::string\>\> getWireAttrs(WireId wire) const
+
+Return the attributes for that wire. Wire attributes are only informal. They are displayed by the GUI but are otherwise
+unused. An implementation may simply return an empty range.
+
### uint32\_t getWireChecksum(WireId wire) const
Return a (preferably unique) number that represents this wire. This is used in design state checksum calculations.
@@ -242,6 +252,11 @@ Get the name for a pip. (Pip names must be unique.)
Get the type of a pip. Pip types are purely informal and
implementations may simply return `IdString()`.
+### const\_range\<std\:\:pair\<IdString, std::string\>\> getPipAttrs(PipId pip) const
+
+Return the attributes for that pip. Pip attributes are only informal. They are displayed by the GUI but are otherwise
+unused. An implementation may simply return an empty range.
+
### Loc getPipLocation(PipId pip) const
Get the X/Y/Z location of a given pip. Pip locations do not need to be unique, and in most cases they aren't. So
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 047f5518..acf1b42e 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -367,7 +367,7 @@ BelId Arch::getBelByLocation(Loc loc) const
delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
- return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
+ return 50 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y));
}
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
@@ -376,7 +376,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
auto driver_loc = getBelLocation(driver.cell->bel);
auto sink_loc = getBelLocation(sink.cell->bel);
- return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
+ return 50 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y));
}
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 36792625..f5336e55 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -522,6 +522,12 @@ struct Arch : BaseCtx
return id;
}
+ std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId) const
+ {
+ std::vector<std::pair<IdString, std::string>> ret;
+ return ret;
+ }
+
WireId getBelPinWire(BelId bel, IdString pin) const;
BelPinRange getWireBelPins(WireId wire) const
@@ -553,6 +559,12 @@ struct Arch : BaseCtx
IdString getWireType(WireId wire) const { return IdString(); }
+ std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId) const
+ {
+ std::vector<std::pair<IdString, std::string>> ret;
+ return ret;
+ }
+
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
@@ -633,6 +645,12 @@ struct Arch : BaseCtx
IdString getPipType(PipId pip) const { return IdString(); }
+ std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId) const
+ {
+ std::vector<std::pair<IdString, std::string>> ret;
+ return ret;
+ }
+
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
diff --git a/generic/arch.cc b/generic/arch.cc
index b37f53b8..583c74d8 100644
--- a/generic/arch.cc
+++ b/generic/arch.cc
@@ -184,6 +184,21 @@ void Arch::setGroupDecal(GroupId group, DecalXY decalxy)
refreshUiGroup(group);
}
+void Arch::setWireAttr(IdString wire, IdString key, const std::string &value)
+{
+ wires.at(wire).attrs[key] = value;
+}
+
+void Arch::setPipAttr(IdString pip, IdString key, const std::string &value)
+{
+ pips.at(pip).attrs[key] = value;
+}
+
+void Arch::setBelAttr(IdString bel, IdString key, const std::string &value)
+{
+ bels.at(bel).attrs[key] = value;
+}
+
// ---------------------------------------------------------------
Arch::Arch(ArchArgs args) : chipName("generic"), args(args) {}
@@ -251,6 +266,8 @@ const std::vector<BelId> &Arch::getBels() const { return bel_ids; }
IdString Arch::getBelType(BelId bel) const { return bels.at(bel).type; }
+const std::map<IdString, std::string> &Arch::getBelAttrs(BelId bel) const { return bels.at(bel).attrs; }
+
WireId Arch::getBelPinWire(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).wire; }
PortType Arch::getBelPinType(BelId bel, IdString pin) const { return bels.at(bel).pins.at(pin).type; }
@@ -276,6 +293,8 @@ IdString Arch::getWireName(WireId wire) const { return wire; }
IdString Arch::getWireType(WireId wire) const { return wires.at(wire).type; }
+const std::map<IdString, std::string> &Arch::getWireAttrs(WireId wire) const { return wires.at(wire).attrs; }
+
uint32_t Arch::getWireChecksum(WireId wire) const
{
// FIXME
@@ -328,6 +347,8 @@ IdString Arch::getPipName(PipId pip) const { return pip; }
IdString Arch::getPipType(PipId pip) const { return pips.at(pip).type; }
+const std::map<IdString, std::string> &Arch::getPipAttrs(PipId pip) const { return pips.at(pip).attrs; }
+
uint32_t Arch::getPipChecksum(PipId wire) const
{
// FIXME
diff --git a/generic/arch.h b/generic/arch.h
index 7549a75b..22966e2a 100644
--- a/generic/arch.h
+++ b/generic/arch.h
@@ -32,6 +32,7 @@ struct WireInfo;
struct PipInfo
{
IdString name, type;
+ std::map<IdString, std::string> attrs;
NetInfo *bound_net;
WireId srcWire, dstWire;
DelayInfo delay;
@@ -42,6 +43,7 @@ struct PipInfo
struct WireInfo
{
IdString name, type;
+ std::map<IdString, std::string> attrs;
NetInfo *bound_net;
std::vector<PipId> downhill, uphill, aliases;
BelPin uphill_bel_pin;
@@ -61,6 +63,7 @@ struct PinInfo
struct BelInfo
{
IdString name, type;
+ std::map<IdString, std::string> attrs;
CellInfo *bound_cell;
std::unordered_map<IdString, PinInfo> pins;
DecalXY decalxy;
@@ -120,6 +123,10 @@ struct Arch : BaseCtx
void setBelDecal(BelId bel, DecalXY decalxy);
void setGroupDecal(GroupId group, DecalXY decalxy);
+ void setWireAttr(IdString wire, IdString key, const std::string &value);
+ void setPipAttr(IdString pip, IdString key, const std::string &value);
+ void setBelAttr(IdString bel, IdString key, const std::string &value);
+
// ---------------------------------------------------------------
// Common Arch API. Every arch must provide the following methods.
@@ -151,6 +158,7 @@ struct Arch : BaseCtx
CellInfo *getConflictingBelCell(BelId bel) const;
const std::vector<BelId> &getBels() const;
IdString getBelType(BelId bel) const;
+ const std::map<IdString, std::string> &getBelAttrs(BelId bel) const;
WireId getBelPinWire(BelId bel, IdString pin) const;
PortType getBelPinType(BelId bel, IdString pin) const;
std::vector<IdString> getBelPins(BelId bel) const;
@@ -158,6 +166,7 @@ struct Arch : BaseCtx
WireId getWireByName(IdString name) const;
IdString getWireName(WireId wire) const;
IdString getWireType(WireId wire) const;
+ const std::map<IdString, std::string> &getWireAttrs(WireId wire) const;
uint32_t getWireChecksum(WireId wire) const;
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength);
void unbindWire(WireId wire);
@@ -171,6 +180,7 @@ struct Arch : BaseCtx
PipId getPipByName(IdString name) const;
IdString getPipName(PipId pip) const;
IdString getPipType(PipId pip) const;
+ const std::map<IdString, std::string> &getPipAttrs(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const;
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength);
void unbindPip(PipId pip);
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index 896ef071..1b0e617e 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -411,6 +411,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Conflicting Cell", ctx->nameOf(ctx->getConflictingBelCell(bel)),
ElementType::CELL);
+ QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
+ for (auto &item : ctx->getBelAttrs(bel)) {
+ addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
+ }
+
QtProperty *belpinsItem = addSubGroup(topItem, "Ports");
for (const auto &item : ctx->getBelPins(bel)) {
QtProperty *portInfoItem = addSubGroup(belpinsItem, item.c_str(ctx));
@@ -433,6 +438,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingWireNet(wire)),
ElementType::NET);
+ QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
+ for (auto &item : ctx->getWireAttrs(wire)) {
+ addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
+ }
+
DelayInfo delay = ctx->getWireDelay(wire);
QtProperty *delayItem = addSubGroup(topItem, "Delay");
@@ -492,6 +502,11 @@ void DesignWidget::onSelectionChanged(const QItemSelection &, const QItemSelecti
addProperty(topItem, QVariant::String, "Dest Wire", ctx->getWireName(ctx->getPipDstWire(pip)).c_str(ctx),
ElementType::WIRE);
+ QtProperty *attrsItem = addSubGroup(topItem, "Attributes");
+ for (auto &item : ctx->getPipAttrs(pip)) {
+ addProperty(attrsItem, QVariant::String, item.first.c_str(ctx), item.second.c_str());
+ }
+
DelayInfo delay = ctx->getPipDelay(pip);
QtProperty *delayItem = addSubGroup(topItem, "Delay");
diff --git a/ice40/arch.cc b/ice40/arch.cc
index 357b3018..91dc5d66 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -226,6 +226,12 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const
return PORT_INOUT;
}
+std::vector<std::pair<IdString, std::string>> Arch::getBelAttrs(BelId) const
+{
+ std::vector<std::pair<IdString, std::string>> ret;
+ return ret;
+}
+
WireId Arch::getBelPinWire(BelId bel, IdString pin) const
{
WireId ret;
@@ -331,6 +337,28 @@ IdString Arch::getWireType(WireId wire) const
return IdString();
}
+std::vector<std::pair<IdString, std::string>> Arch::getWireAttrs(WireId wire) const
+{
+ std::vector<std::pair<IdString, std::string>> ret;
+ auto &wi = chip_info->wire_data[wire.index];
+
+ ret.push_back(std::make_pair(id("INDEX"), stringf("%d", wi.netidx)));
+
+ ret.push_back(std::make_pair(id("GRID_X"), stringf("%d", wi.x)));
+ ret.push_back(std::make_pair(id("GRID_Y"), stringf("%d", wi.y)));
+ ret.push_back(std::make_pair(id("GRID_Z"), stringf("%d", wi.z)));
+
+#if 0
+ for (int i = 0; i < wi.num_segments; i++) {
+ auto &si = wi.segments[i];
+ ret.push_back(std::make_pair(id(stringf("segment[%d]", i)),
+ stringf("X%d/Y%d/%s", si.x, si.y, chip_info->tile_wire_names[si.index].get())));
+ }
+#endif
+
+ return ret;
+}
+
// -----------------------------------------------------------------------
PipId Arch::getPipByName(IdString name) const
@@ -372,6 +400,15 @@ IdString Arch::getPipName(PipId pip) const
#endif
}
+IdString Arch::getPipType(PipId pip) const { return IdString(); }
+
+std::vector<std::pair<IdString, std::string>> Arch::getPipAttrs(PipId) const
+{
+ std::vector<std::pair<IdString, std::string>> ret;
+ return ret;
+}
+
+
// -----------------------------------------------------------------------
BelId Arch::getPackagePinBel(const std::string &pin) const
@@ -718,7 +755,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
- el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1;
+ el.x1 = chip_info->bel_data[bel.index].x + lut_swbox_x1;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2;
el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 +
(4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch;
@@ -732,7 +769,7 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
GraphicElement el;
el.type = GraphicElement::TYPE_BOX;
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
- el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1;
+ el.x1 = chip_info->bel_data[bel.index].x + lut_swbox_x1;
el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2;
el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i;
el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch;
diff --git a/ice40/arch.h b/ice40/arch.h
index 2f2a0f30..871b25fb 100644
--- a/ice40/arch.h
+++ b/ice40/arch.h
@@ -108,6 +108,8 @@ NPNR_PACKED_STRUCT(struct WireInfoPOD {
};
RelPtr<char> name;
+ int32_t netidx;
+
int32_t num_uphill, num_downhill;
RelPtr<int32_t> pips_uphill, pips_downhill;
@@ -225,6 +227,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
RelPtr<BelConfigPOD> bel_config;
RelPtr<PackageInfoPOD> packages_data;
RelPtr<CellTimingPOD> cell_timing;
+ RelPtr<RelPtr<char>> tile_wire_names;
});
#if defined(_MSC_VER)
@@ -502,6 +505,8 @@ struct Arch : BaseCtx
return IdString(chip_info->bel_data[bel.index].type);
}
+ std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId bel) const;
+
WireId getBelPinWire(BelId bel, IdString pin) const;
PortType getBelPinType(BelId bel, IdString pin) const;
std::vector<IdString> getBelPins(BelId bel) const;
@@ -517,6 +522,7 @@ struct Arch : BaseCtx
}
IdString getWireType(WireId wire) const;
+ std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const;
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
@@ -692,7 +698,8 @@ struct Arch : BaseCtx
IdString getPipName(PipId pip) const;
- IdString getPipType(PipId pip) const { return IdString(); }
+ IdString getPipType(PipId pip) const;
+ std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
@@ -812,7 +819,7 @@ struct Arch : BaseCtx
bool isBelLocationValid(BelId bel) const;
// Helper function for above
- bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const;
+ bool logicCellsCompatible(const CellInfo** it, const size_t size) const;
// -------------------------------------------------
// Assign architecure-specific arguments to nets and cells, which must be
diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc
index bbddb7ee..c69fd34f 100644
--- a/ice40/arch_place.cc
+++ b/ice40/arch_place.cc
@@ -23,15 +23,17 @@
#include "nextpnr.h"
#include "util.h"
+#include <boost/range/iterator_range.hpp>
+
NEXTPNR_NAMESPACE_BEGIN
-bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
+bool Arch::logicCellsCompatible(const CellInfo** it, const size_t size) const
{
bool dffs_exist = false, dffs_neg = false;
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
int locals_count = 0;
- for (auto cell : cells) {
+ for (auto cell : boost::make_iterator_range(it, it+size)) {
NPNR_ASSERT(cell->belType == id_ICESTORM_LC);
if (cell->lcInfo.dffEnable) {
if (!dffs_exist) {
@@ -71,15 +73,15 @@ bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) cons
bool Arch::isBelLocationValid(BelId bel) const
{
if (getBelType(bel) == id_ICESTORM_LC) {
- std::vector<const CellInfo *> bel_cells;
+ std::array<const CellInfo *, 8> bel_cells;
+ size_t num_cells = 0;
Loc bel_loc = getBelLocation(bel);
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
CellInfo *ci_other = getBoundBelCell(bel_other);
- if (ci_other != nullptr) {
- bel_cells.push_back(ci_other);
- }
+ if (ci_other != nullptr)
+ bel_cells[num_cells++] = ci_other;
}
- return logicCellsCompatible(bel_cells);
+ return logicCellsCompatible(bel_cells.data(), num_cells);
} else {
CellInfo *ci = getBoundBelCell(bel);
if (ci == nullptr)
@@ -94,17 +96,18 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
if (cell->type == id_ICESTORM_LC) {
NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC);
- std::vector<const CellInfo *> bel_cells;
+ std::array<const CellInfo *, 8> bel_cells;
+ size_t num_cells = 0;
+
Loc bel_loc = getBelLocation(bel);
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
CellInfo *ci_other = getBoundBelCell(bel_other);
- if (ci_other != nullptr && bel_other != bel) {
- bel_cells.push_back(ci_other);
- }
+ if (ci_other != nullptr && bel_other != bel)
+ bel_cells[num_cells++] = ci_other;
}
- bel_cells.push_back(cell);
- return logicCellsCompatible(bel_cells);
+ bel_cells[num_cells++] = cell;
+ return logicCellsCompatible(bel_cells.data(), num_cells);
} else if (cell->type == id_SB_IO) {
// Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc
index ee276e49..4ea91011 100644
--- a/ice40/bitstream.cc
+++ b/ice40/bitstream.cc
@@ -870,10 +870,12 @@ bool read_asc(Context *ctx, std::istream &in)
}
if (isUsed) {
NetInfo *net = ctx->wire_to_net[pi.dst];
- WireId wire;
- wire.index = pi.dst;
- ctx->unbindWire(wire);
- ctx->bindPip(pip, net, STRENGTH_WEAK);
+ if (net!=nullptr) {
+ WireId wire;
+ wire.index = pi.dst;
+ ctx->unbindWire(wire);
+ ctx->bindPip(pip, net, STRENGTH_WEAK);
+ }
}
}
for (auto bel : ctx->getBels()) {
diff --git a/ice40/chains.cc b/ice40/chains.cc
index 8638a96c..bb20b60b 100644
--- a/ice40/chains.cc
+++ b/ice40/chains.cc
@@ -97,7 +97,7 @@ class ChainConstrainer
}
tile.push_back(cell);
chains.back().cells.push_back(cell);
- bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
+ bool split_chain = (!ctx->logicCellsCompatible(tile.data(), tile.size())) || (int(chains.back().cells.size()) > max_length);
if (split_chain) {
CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT")));
tile.pop_back();
diff --git a/ice40/chipdb.py b/ice40/chipdb.py
index 7bdf82f0..a28cba4a 100644
--- a/ice40/chipdb.py
+++ b/ice40/chipdb.py
@@ -50,6 +50,7 @@ tiletypes = dict()
wiretypes = dict()
gfx_wire_ids = dict()
+gfx_wire_names = list()
wire_segments = dict()
fast_timings = None
@@ -93,6 +94,136 @@ with open(args.gfxh) as f:
idx = len(gfx_wire_ids)
name = line.strip().rstrip(",")
gfx_wire_ids[name] = idx
+ gfx_wire_names.append(name)
+
+def gfx_wire_alias(old, new):
+ assert old in gfx_wire_ids
+ assert new not in gfx_wire_ids
+ gfx_wire_ids[new] = gfx_wire_ids[old]
+
+# GFX aliases for RAM tiles
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_RAM_RADDR_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_RAM_RADDR_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_2", "TILE_WIRE_RAM_RADDR_2")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_RAM_RADDR_3")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_0", "TILE_WIRE_RAM_RADDR_4")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_1", "TILE_WIRE_RAM_RADDR_5")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_2", "TILE_WIRE_RAM_RADDR_6")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_3", "TILE_WIRE_RAM_RADDR_7")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_0", "TILE_WIRE_RAM_RADDR_8")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_1", "TILE_WIRE_RAM_RADDR_9")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_2", "TILE_WIRE_RAM_RADDR_10")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_RAM_WADDR_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_RAM_WADDR_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_2", "TILE_WIRE_RAM_WADDR_2")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_RAM_WADDR_3")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_0", "TILE_WIRE_RAM_WADDR_4")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_1", "TILE_WIRE_RAM_WADDR_5")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_2", "TILE_WIRE_RAM_WADDR_6")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_IN_3", "TILE_WIRE_RAM_WADDR_7")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_0", "TILE_WIRE_RAM_WADDR_8")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_1", "TILE_WIRE_RAM_WADDR_9")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_IN_2", "TILE_WIRE_RAM_WADDR_10")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_0", "TILE_WIRE_RAM_MASK_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_1", "TILE_WIRE_RAM_MASK_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_2", "TILE_WIRE_RAM_MASK_2")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_3", "TILE_WIRE_RAM_MASK_3")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_RAM_MASK_4")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_RAM_MASK_5")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_2", "TILE_WIRE_RAM_MASK_6")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_RAM_MASK_7")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_0", "TILE_WIRE_RAM_MASK_8")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_1", "TILE_WIRE_RAM_MASK_9")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_2", "TILE_WIRE_RAM_MASK_10")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_IN_3", "TILE_WIRE_RAM_MASK_11")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_RAM_MASK_12")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_RAM_MASK_13")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_2", "TILE_WIRE_RAM_MASK_14")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_RAM_MASK_15")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_0", "TILE_WIRE_RAM_WDATA_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_1", "TILE_WIRE_RAM_WDATA_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_2", "TILE_WIRE_RAM_WDATA_2")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_3", "TILE_WIRE_RAM_WDATA_3")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_0", "TILE_WIRE_RAM_WDATA_4")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_1", "TILE_WIRE_RAM_WDATA_5")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_2", "TILE_WIRE_RAM_WDATA_6")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_3", "TILE_WIRE_RAM_WDATA_7")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_0", "TILE_WIRE_RAM_WDATA_8")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_1", "TILE_WIRE_RAM_WDATA_9")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_2", "TILE_WIRE_RAM_WDATA_10")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_IN_3", "TILE_WIRE_RAM_WDATA_11")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_0", "TILE_WIRE_RAM_WDATA_12")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_1", "TILE_WIRE_RAM_WDATA_13")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_2", "TILE_WIRE_RAM_WDATA_14")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_IN_3", "TILE_WIRE_RAM_WDATA_15")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_RAM_RDATA_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_RAM_RDATA_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_OUT", "TILE_WIRE_RAM_RDATA_2")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_OUT", "TILE_WIRE_RAM_RDATA_3")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_RAM_RDATA_4")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_RAM_RDATA_5")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_OUT", "TILE_WIRE_RAM_RDATA_6")
+gfx_wire_alias("TILE_WIRE_LUTFF_7_OUT", "TILE_WIRE_RAM_RDATA_7")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_RAM_RDATA_8")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_RAM_RDATA_9")
+gfx_wire_alias("TILE_WIRE_LUTFF_2_OUT", "TILE_WIRE_RAM_RDATA_10")
+gfx_wire_alias("TILE_WIRE_LUTFF_3_OUT", "TILE_WIRE_RAM_RDATA_11")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_RAM_RDATA_12")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_RAM_RDATA_13")
+gfx_wire_alias("TILE_WIRE_LUTFF_6_OUT", "TILE_WIRE_RAM_RDATA_14")
+gfx_wire_alias("TILE_WIRE_LUTFF_7_OUT", "TILE_WIRE_RAM_RDATA_15")
+
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_RAM_RCLKE")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_RAM_WCLKE")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_RAM_RCLK")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_RAM_WCLK")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_RAM_RE")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_RAM_WE")
+
+# GFX aliases for IO tiles
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_0", "TILE_WIRE_IO_0_D_OUT_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_1", "TILE_WIRE_IO_0_D_OUT_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_0_IN_3", "TILE_WIRE_IO_0_OUT_ENB")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_0_OUT", "TILE_WIRE_IO_0_D_IN_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_1_OUT", "TILE_WIRE_IO_0_D_IN_1")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_0", "TILE_WIRE_IO_1_D_OUT_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_1", "TILE_WIRE_IO_1_D_OUT_1")
+gfx_wire_alias("TILE_WIRE_LUTFF_4_IN_3", "TILE_WIRE_IO_1_OUT_ENB")
+
+gfx_wire_alias("TILE_WIRE_LUTFF_4_OUT", "TILE_WIRE_IO_1_D_IN_0")
+gfx_wire_alias("TILE_WIRE_LUTFF_5_OUT", "TILE_WIRE_IO_1_D_IN_1")
+
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CEN", "TILE_WIRE_IO_GLOBAL_CEN")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_CLK", "TILE_WIRE_IO_GLOBAL_INCLK")
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_S_R", "TILE_WIRE_IO_GLOBAL_OUTCLK")
+
+gfx_wire_alias("TILE_WIRE_FUNC_GLOBAL_G0", "TILE_WIRE_IO_GLOBAL_LATCH")
+
+for neigh in "BNL BNR BOT LFT RGT TNL TNR TOP".split():
+ for i in range(8):
+ gfx_wire_alias("TILE_WIRE_NEIGH_OP_%s_%d" % (neigh, i), "TILE_WIRE_LOGIC_OP_%s_%d" % (neigh, i))
+
+# End of GFX aliases
+
def read_timings(filename):
db = dict()
@@ -165,6 +296,18 @@ def maj_wire_name(name):
return name[2] in ("sp12_v_b_0", "sp12_v_b_1")
return False
+def norm_wire_xy(x, y, name):
+ if name.startswith("glb_netwk_"):
+ return None
+ if name.startswith("neigh_op_"):
+ return None
+ if name.startswith("logic_op_"):
+ return None
+ if name.startswith("io_global/latch"):
+ return None
+ return None # FIXME
+ return (x, y)
+
def cmp_wire_names(newname, oldname):
if maj_wire_name(newname):
return True
@@ -508,11 +651,13 @@ with open(args.filename, "r") as f:
wire_names_r[mode[1]] = wname
if mode[1] not in wire_xy:
wire_xy[mode[1]] = list()
- wire_xy[mode[1]].append((int(line[0]), int(line[1])))
+ wire_xy[mode[1]].append(wname)
if mode[1] not in wire_segments:
wire_segments[mode[1]] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
- wire_segments[mode[1]][(wname[0], wname[1])] = wname[2]
+ if (wname[0], wname[1]) not in wire_segments[mode[1]]:
+ wire_segments[mode[1]][(wname[0], wname[1])] = list()
+ wire_segments[mode[1]][(wname[0], wname[1])].append(wname[2])
continue
if mode[0] in ("buffer", "routing"):
@@ -561,7 +706,9 @@ def add_wire(x, y, name):
wire_names_r[wire_idx] = wname
wire_segments[wire_idx] = dict()
if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids:
- wire_segments[wire_idx][(wname[0], wname[1])] = wname[2]
+ if (wname[0], wname[1]) not in wire_segments[wire_idx]:
+ wire_segments[wire_idx][(wname[0], wname[1])] = list()
+ wire_segments[wire_idx][(wname[0], wname[1])].append(wname[2])
return wire_idx
def add_switch(x, y, bel=-1):
@@ -932,6 +1079,10 @@ bba.post('NEXTPNR_NAMESPACE_END')
bba.push("chipdb_blob_%s" % dev_name)
bba.r("chip_info_%s" % dev_name, "chip_info")
+bba.l("tile_wire_names")
+for name in gfx_wire_names:
+ bba.s(name, name)
+
for bel in range(len(bel_name)):
bba.l("bel_wires_%d" % bel, "BelWirePOD")
for data in sorted(bel_wires[bel]):
@@ -1028,20 +1179,32 @@ for wire in range(num_wires):
info["num_bel_pins"] = num_bel_pins
info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None
- if wire in wire_xy:
- avg_x, avg_y = 0, 0
+ pos_xy = None
+ first = None
- for x, y in wire_xy[wire]:
- avg_x += x
- avg_y += y
- avg_x /= len(wire_xy[wire])
- avg_y /= len(wire_xy[wire])
+ if wire in wire_xy:
+ for x, y, n in wire_xy[wire]:
+ norm_xy = norm_wire_xy(x, y, n)
+ if norm_xy is None:
+ continue
+ if pos_xy is None:
+ pos_xy = norm_xy
+ first = (x, y, n)
+ elif pos_xy != norm_xy:
+ print("Conflicting positions for wire %s: (%d, %d, %s) -> (%d, %d), (%d, %d, %s) -> (%d, %d)" % \
+ ((info["name"],) + first + pos_xy + (x, y, n) + norm_xy), file=sys.stderr)
+ assert 0
+ if (pos_xy is None) and (len(wire_xy[wire]) > 1):
+ # print("Only 'None' positions for wire %s." % info["name"], file=sys.stderr)
+ # assert 0
+ pass
- info["x"] = int(round(avg_x))
- info["y"] = int(round(avg_y))
- else:
+ if pos_xy is None:
info["x"] = wire_names_r[wire][0]
info["y"] = wire_names_r[wire][1]
+ else:
+ info["x"] = pos_xy[0]
+ info["y"] = pos_xy[1]
wireinfo.append(info)
@@ -1102,14 +1265,21 @@ for t in range(num_tile_types):
bba.l("wire_data_%s" % dev_name, "WireInfoPOD")
for wire, info in enumerate(wireinfo):
bba.s(info["name"], "name")
+ bba.u32(wire, "netidx")
+
bba.u32(info["num_uphill"], "num_uphill")
bba.u32(info["num_downhill"], "num_downhill")
bba.r(info["list_uphill"], "pips_uphill")
bba.r(info["list_downhill"], "pips_downhill")
bba.u32(info["num_bel_pins"], "num_bel_pins")
bba.r(info["list_bel_pins"], "bel_pins")
- bba.u32(len(wire_segments[wire]), "num_segments")
- if len(wire_segments[wire]):
+
+ num_segments = 0
+ for segs in wire_segments[wire].values():
+ num_segments += len(segs)
+ bba.u32(num_segments, "num_segments")
+
+ if num_segments:
bba.r("wire_segments_%d" % wire, "segments")
else:
bba.u32(0, "segments")
@@ -1125,24 +1295,25 @@ for wire, info in enumerate(wireinfo):
for wire in range(num_wires):
if len(wire_segments[wire]):
bba.l("wire_segments_%d" % wire, "WireSegmentPOD")
- for xy, seg in sorted(wire_segments[wire].items()):
- bba.u8(xy[0], "x")
- bba.u8(xy[1], "y")
- bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
+ for xy, segs in sorted(wire_segments[wire].items()):
+ for seg in segs:
+ bba.u8(xy[0], "x")
+ bba.u8(xy[1], "y")
+ bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index")
bba.l("pip_data_%s" % dev_name, "PipInfoPOD")
for info in pipinfo:
src_seg = -1
src_segname = wire_names_r[info["src"]]
if (info["x"], info["y"]) in wire_segments[info["src"]]:
- src_segname = wire_segments[info["src"]][(info["x"], info["y"])]
+ src_segname = wire_segments[info["src"]][(info["x"], info["y"])][0]
src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")]
src_segname = src_segname.replace("/", ".")
dst_seg = -1
dst_segname = wire_names_r[info["dst"]]
if (info["x"], info["y"]) in wire_segments[info["dst"]]:
- dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])]
+ dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])][0]
dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")]
dst_segname = dst_segname.replace("/", ".")
@@ -1276,5 +1447,6 @@ bba.r("bits_info_%s" % dev_name, "bits_info")
bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config")
bba.r("package_info_%s" % dev_name, "packages_data")
bba.r("cell_timings_%s" % dev_name, "cell_timing")
+bba.r("tile_wire_names", "tile_wire_names")
bba.pop()
diff --git a/ice40/family.cmake b/ice40/family.cmake
index f558a14d..0e1d36e6 100644
--- a/ice40/family.cmake
+++ b/ice40/family.cmake
@@ -36,7 +36,7 @@ if (MSVC)
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h)
add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}
- DEPENDS ${DEV_TXT_DB} ${DB_PY}
+ DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
)
add_custom_command(OUTPUT ${DEV_CC_DB}
COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB}
@@ -69,7 +69,7 @@ else()
add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new
COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
- DEPENDS ${DEV_TXT_DB} ${DB_PY}
+ DEPENDS ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${DEV_TXT_DB} ${DB_PY}
)
add_custom_command(OUTPUT ${DEV_CC_DB}
COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
diff --git a/ice40/gfx.cc b/ice40/gfx.cc
index 1ab2fb3c..79350ad0 100644
--- a/ice40/gfx.cc
+++ b/ice40/gfx.cc
@@ -339,6 +339,78 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
g.push_back(el);
}
+ // IO Span-4 Wires connecting to fabric
+
+ if (id >= TILE_WIRE_SPAN4_HORZ_0 && id <= TILE_WIRE_SPAN4_HORZ_47) {
+ int idx = id - TILE_WIRE_SPAN4_HORZ_0;
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (48 - (idx ^ 1)));
+
+ el.x1 = x;
+ el.x2 = x + 1.0;
+ el.y1 = y1;
+ el.y2 = y1;
+ g.push_back(el);
+
+ el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
+ el.x2 = el.x1;
+ el.y1 = y1;
+ el.y2 = y + main_swbox_y2;
+ g.push_back(el);
+ }
+
+ if (id >= TILE_WIRE_SPAN4_VERT_0 && id <= TILE_WIRE_SPAN4_VERT_47) {
+ int idx = id - TILE_WIRE_SPAN4_VERT_0;
+ float x1 = x + 0.03 + 0.0025 * (48 - (idx ^ 1));
+
+ el.x1 = x1;
+ el.x2 = x1;
+ el.y1 = y;
+ el.y2 = y + 1.0;
+ g.push_back(el);
+
+ el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
+ el.y2 = el.y1;
+ el.x1 = x1;
+ el.x2 = x + main_swbox_x1;
+ g.push_back(el);
+ }
+
+ // IO Span-12 Wires connecting to fabric
+
+ if (id >= TILE_WIRE_SPAN12_HORZ_0 && id <= TILE_WIRE_SPAN12_HORZ_23) {
+ int idx = id - TILE_WIRE_SPAN12_HORZ_0;
+ float y1 = y + 1.0 - (0.03 + 0.0025 * (88 - (idx ^ 1)));
+
+ el.x1 = x;
+ el.x2 = x + 1.0;
+ el.y1 = y1;
+ el.y2 = y1;
+ g.push_back(el);
+
+ el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
+ el.x2 = el.x1;
+ el.y1 = y1;
+ el.y2 = y + main_swbox_y2;
+ g.push_back(el);
+ }
+
+ if (id >= TILE_WIRE_SPAN12_VERT_0 && id <= TILE_WIRE_SPAN12_VERT_23) {
+ int idx = id - TILE_WIRE_SPAN12_VERT_0;
+ float x1 = x + 0.03 + 0.0025 * (88 - (idx ^ 1));
+
+ el.x1 = x1;
+ el.x2 = x1;
+ el.y1 = y;
+ el.y2 = y + 1.0;
+ g.push_back(el);
+
+ el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
+ el.y2 = el.y1;
+ el.x1 = x1;
+ el.x2 = x + main_swbox_x1;
+ g.push_back(el);
+ }
+
// Global2Local
if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
@@ -457,6 +529,42 @@ void gfxTileWire(std::vector<GraphicElement> &g, int x, int y, GfxTileWireId id,
}
}
+ // LC Control for IO and BRAM
+
+ if (id >= TILE_WIRE_FUNC_GLOBAL_CEN && id <= TILE_WIRE_FUNC_GLOBAL_S_R) {
+ int idx = id - TILE_WIRE_FUNC_GLOBAL_CEN;
+
+ el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5);
+ el.x2 = el.x1;
+ el.y1 = y + main_swbox_y1;
+ el.y2 = el.y1 - 0.005 * (idx + 2);
+ g.push_back(el);
+
+ el.y1 = el.y2;
+ el.x2 = x + logic_cell_x2 - 0.005 * (2 - idx + 5);
+ g.push_back(el);
+
+ el.y2 = y + logic_cell_y1;
+ el.x1 = el.x2;
+ g.push_back(el);
+ }
+
+ if (id == TILE_WIRE_FABOUT) {
+ el.y1 = y + main_swbox_y1;
+ el.y2 = el.y1 - 0.005 * 4;
+ el.x1 = x + main_swbox_x2 - 0.005 * 9;
+ el.x2 = el.x1;
+ g.push_back(el);
+ }
+
+ if (id == TILE_WIRE_FUNC_GLOBAL_G0) {
+ el.y1 = y + logic_cell_y1;
+ el.y2 = el.y1 - 0.005 * 4;
+ el.x1 = x + logic_cell_x2 - 0.005 * 3;
+ el.x2 = el.x1;
+ g.push_back(el);
+ }
+
// LC Cascade
if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) {
@@ -571,6 +679,38 @@ static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
return true;
}
+ // IO Span-4 Wires connecting to fabric
+
+ if (id >= TILE_WIRE_SPAN4_HORZ_0 && id <= TILE_WIRE_SPAN4_HORZ_47) {
+ int idx = id - TILE_WIRE_SPAN4_HORZ_0;
+ x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SPAN4_VERT_0 && id <= TILE_WIRE_SPAN4_VERT_47) {
+ int idx = id - TILE_WIRE_SPAN4_VERT_0;
+ y = 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1)));
+ x = main_swbox_x1;
+ return true;
+ }
+
+ // IO Span-12 Wires connecting to fabric
+
+ if (id >= TILE_WIRE_SPAN12_HORZ_0 && id <= TILE_WIRE_SPAN12_HORZ_23) {
+ int idx = id - TILE_WIRE_SPAN12_HORZ_0;
+ x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5);
+ y = main_swbox_y2;
+ return true;
+ }
+
+ if (id >= TILE_WIRE_SPAN12_VERT_0 && id <= TILE_WIRE_SPAN12_VERT_23) {
+ int idx = id - TILE_WIRE_SPAN12_VERT_0;
+ y = 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1)));
+ x = main_swbox_x1;
+ return true;
+ }
+
// Global2Local
if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) {
@@ -626,6 +766,19 @@ static bool getWireXY_main(GfxTileWireId id, float &x, float &y)
return true;
}
+ if (id >= TILE_WIRE_FUNC_GLOBAL_CEN && id <= TILE_WIRE_FUNC_GLOBAL_S_R) {
+ int idx = id - TILE_WIRE_FUNC_GLOBAL_CEN;
+ x = main_swbox_x2 - 0.005 * (idx + 5);
+ y = main_swbox_y1;
+ return true;
+ }
+
+ if (id == TILE_WIRE_FABOUT) {
+ x = main_swbox_x2 - 0.005 * 9;
+ y = main_swbox_y1;
+ return true;
+ }
+
return false;
}
diff --git a/ice40/gfx.h b/ice40/gfx.h
index 8ee7b0b6..5401a410 100644
--- a/ice40/gfx.h
+++ b/ice40/gfx.h
@@ -205,6 +205,13 @@ enum GfxTileWireId
TILE_WIRE_LUTFF_GLOBAL_CLK,
TILE_WIRE_LUTFF_GLOBAL_S_R,
+ TILE_WIRE_FUNC_GLOBAL_CEN,
+ TILE_WIRE_FUNC_GLOBAL_CLK,
+ TILE_WIRE_FUNC_GLOBAL_S_R,
+
+ TILE_WIRE_FUNC_GLOBAL_G0,
+ TILE_WIRE_FABOUT,
+
TILE_WIRE_CARRY_IN,
TILE_WIRE_CARRY_IN_MUX,
@@ -509,6 +516,154 @@ enum GfxTileWireId
TILE_WIRE_SP12_H_L_22,
TILE_WIRE_SP12_H_L_23,
+ TILE_WIRE_SPAN4_VERT_0,
+ TILE_WIRE_SPAN4_VERT_1,
+ TILE_WIRE_SPAN4_VERT_2,
+ TILE_WIRE_SPAN4_VERT_3,
+ TILE_WIRE_SPAN4_VERT_4,
+ TILE_WIRE_SPAN4_VERT_5,
+ TILE_WIRE_SPAN4_VERT_6,
+ TILE_WIRE_SPAN4_VERT_7,
+ TILE_WIRE_SPAN4_VERT_8,
+ TILE_WIRE_SPAN4_VERT_9,
+ TILE_WIRE_SPAN4_VERT_10,
+ TILE_WIRE_SPAN4_VERT_11,
+ TILE_WIRE_SPAN4_VERT_12,
+ TILE_WIRE_SPAN4_VERT_13,
+ TILE_WIRE_SPAN4_VERT_14,
+ TILE_WIRE_SPAN4_VERT_15,
+ TILE_WIRE_SPAN4_VERT_16,
+ TILE_WIRE_SPAN4_VERT_17,
+ TILE_WIRE_SPAN4_VERT_18,
+ TILE_WIRE_SPAN4_VERT_19,
+ TILE_WIRE_SPAN4_VERT_20,
+ TILE_WIRE_SPAN4_VERT_21,
+ TILE_WIRE_SPAN4_VERT_22,
+ TILE_WIRE_SPAN4_VERT_23,
+ TILE_WIRE_SPAN4_VERT_24,
+ TILE_WIRE_SPAN4_VERT_25,
+ TILE_WIRE_SPAN4_VERT_26,
+ TILE_WIRE_SPAN4_VERT_27,
+ TILE_WIRE_SPAN4_VERT_28,
+ TILE_WIRE_SPAN4_VERT_29,
+ TILE_WIRE_SPAN4_VERT_30,
+ TILE_WIRE_SPAN4_VERT_31,
+ TILE_WIRE_SPAN4_VERT_32,
+ TILE_WIRE_SPAN4_VERT_33,
+ TILE_WIRE_SPAN4_VERT_34,
+ TILE_WIRE_SPAN4_VERT_35,
+ TILE_WIRE_SPAN4_VERT_36,
+ TILE_WIRE_SPAN4_VERT_37,
+ TILE_WIRE_SPAN4_VERT_38,
+ TILE_WIRE_SPAN4_VERT_39,
+ TILE_WIRE_SPAN4_VERT_40,
+ TILE_WIRE_SPAN4_VERT_41,
+ TILE_WIRE_SPAN4_VERT_42,
+ TILE_WIRE_SPAN4_VERT_43,
+ TILE_WIRE_SPAN4_VERT_44,
+ TILE_WIRE_SPAN4_VERT_45,
+ TILE_WIRE_SPAN4_VERT_46,
+ TILE_WIRE_SPAN4_VERT_47,
+
+ TILE_WIRE_SPAN4_HORZ_0,
+ TILE_WIRE_SPAN4_HORZ_1,
+ TILE_WIRE_SPAN4_HORZ_2,
+ TILE_WIRE_SPAN4_HORZ_3,
+ TILE_WIRE_SPAN4_HORZ_4,
+ TILE_WIRE_SPAN4_HORZ_5,
+ TILE_WIRE_SPAN4_HORZ_6,
+ TILE_WIRE_SPAN4_HORZ_7,
+ TILE_WIRE_SPAN4_HORZ_8,
+ TILE_WIRE_SPAN4_HORZ_9,
+ TILE_WIRE_SPAN4_HORZ_10,
+ TILE_WIRE_SPAN4_HORZ_11,
+ TILE_WIRE_SPAN4_HORZ_12,
+ TILE_WIRE_SPAN4_HORZ_13,
+ TILE_WIRE_SPAN4_HORZ_14,
+ TILE_WIRE_SPAN4_HORZ_15,
+ TILE_WIRE_SPAN4_HORZ_16,
+ TILE_WIRE_SPAN4_HORZ_17,
+ TILE_WIRE_SPAN4_HORZ_18,
+ TILE_WIRE_SPAN4_HORZ_19,
+ TILE_WIRE_SPAN4_HORZ_20,
+ TILE_WIRE_SPAN4_HORZ_21,
+ TILE_WIRE_SPAN4_HORZ_22,
+ TILE_WIRE_SPAN4_HORZ_23,
+ TILE_WIRE_SPAN4_HORZ_24,
+ TILE_WIRE_SPAN4_HORZ_25,
+ TILE_WIRE_SPAN4_HORZ_26,
+ TILE_WIRE_SPAN4_HORZ_27,
+ TILE_WIRE_SPAN4_HORZ_28,
+ TILE_WIRE_SPAN4_HORZ_29,
+ TILE_WIRE_SPAN4_HORZ_30,
+ TILE_WIRE_SPAN4_HORZ_31,
+ TILE_WIRE_SPAN4_HORZ_32,
+ TILE_WIRE_SPAN4_HORZ_33,
+ TILE_WIRE_SPAN4_HORZ_34,
+ TILE_WIRE_SPAN4_HORZ_35,
+ TILE_WIRE_SPAN4_HORZ_36,
+ TILE_WIRE_SPAN4_HORZ_37,
+ TILE_WIRE_SPAN4_HORZ_38,
+ TILE_WIRE_SPAN4_HORZ_39,
+ TILE_WIRE_SPAN4_HORZ_40,
+ TILE_WIRE_SPAN4_HORZ_41,
+ TILE_WIRE_SPAN4_HORZ_42,
+ TILE_WIRE_SPAN4_HORZ_43,
+ TILE_WIRE_SPAN4_HORZ_44,
+ TILE_WIRE_SPAN4_HORZ_45,
+ TILE_WIRE_SPAN4_HORZ_46,
+ TILE_WIRE_SPAN4_HORZ_47,
+
+ TILE_WIRE_SPAN12_VERT_0,
+ TILE_WIRE_SPAN12_VERT_1,
+ TILE_WIRE_SPAN12_VERT_2,
+ TILE_WIRE_SPAN12_VERT_3,
+ TILE_WIRE_SPAN12_VERT_4,
+ TILE_WIRE_SPAN12_VERT_5,
+ TILE_WIRE_SPAN12_VERT_6,
+ TILE_WIRE_SPAN12_VERT_7,
+ TILE_WIRE_SPAN12_VERT_8,
+ TILE_WIRE_SPAN12_VERT_9,
+ TILE_WIRE_SPAN12_VERT_10,
+ TILE_WIRE_SPAN12_VERT_11,
+ TILE_WIRE_SPAN12_VERT_12,
+ TILE_WIRE_SPAN12_VERT_13,
+ TILE_WIRE_SPAN12_VERT_14,
+ TILE_WIRE_SPAN12_VERT_15,
+ TILE_WIRE_SPAN12_VERT_16,
+ TILE_WIRE_SPAN12_VERT_17,
+ TILE_WIRE_SPAN12_VERT_18,
+ TILE_WIRE_SPAN12_VERT_19,
+ TILE_WIRE_SPAN12_VERT_20,
+ TILE_WIRE_SPAN12_VERT_21,
+ TILE_WIRE_SPAN12_VERT_22,
+ TILE_WIRE_SPAN12_VERT_23,
+
+ TILE_WIRE_SPAN12_HORZ_0,
+ TILE_WIRE_SPAN12_HORZ_1,
+ TILE_WIRE_SPAN12_HORZ_2,
+ TILE_WIRE_SPAN12_HORZ_3,
+ TILE_WIRE_SPAN12_HORZ_4,
+ TILE_WIRE_SPAN12_HORZ_5,
+ TILE_WIRE_SPAN12_HORZ_6,
+ TILE_WIRE_SPAN12_HORZ_7,
+ TILE_WIRE_SPAN12_HORZ_8,
+ TILE_WIRE_SPAN12_HORZ_9,
+ TILE_WIRE_SPAN12_HORZ_10,
+ TILE_WIRE_SPAN12_HORZ_11,
+ TILE_WIRE_SPAN12_HORZ_12,
+ TILE_WIRE_SPAN12_HORZ_13,
+ TILE_WIRE_SPAN12_HORZ_14,
+ TILE_WIRE_SPAN12_HORZ_15,
+ TILE_WIRE_SPAN12_HORZ_16,
+ TILE_WIRE_SPAN12_HORZ_17,
+ TILE_WIRE_SPAN12_HORZ_18,
+ TILE_WIRE_SPAN12_HORZ_19,
+ TILE_WIRE_SPAN12_HORZ_20,
+ TILE_WIRE_SPAN12_HORZ_21,
+ TILE_WIRE_SPAN12_HORZ_22,
+ TILE_WIRE_SPAN12_HORZ_23,
+
TILE_WIRE_PLLIN,
TILE_WIRE_PLLOUT_A,
TILE_WIRE_PLLOUT_B
diff --git a/json/jsonparse.cc b/json/jsonparse.cc
index d73525bc..a690bf18 100644
--- a/json/jsonparse.cc
+++ b/json/jsonparse.cc
@@ -52,7 +52,7 @@ struct JsonNode
std::map<string, JsonNode *> data_dict;
std::vector<string> data_dict_keys;
- JsonNode(std::istream &f)
+ JsonNode(std::istream &f, int &lineno)
{
type = 0;
data_number = 0;
@@ -63,6 +63,8 @@ struct JsonNode
if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n");
+ if (ch == '\n')
+ lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
continue;
@@ -91,9 +93,12 @@ struct JsonNode
break;
}
- if ('0' <= ch && ch <= '9') {
+ if (('0' <= ch && ch <= '9') || ('-' == ch)) {
type = 'N';
- data_number = ch - '0';
+ if (ch == '-')
+ data_number = 0;
+ else
+ data_number = ch - '0';
data_string += ch;
while (1) {
@@ -114,6 +119,8 @@ struct JsonNode
data_string += ch;
}
+ if (data_string[0] == '-')
+ data_number = -data_number;
data_string = "";
break;
@@ -148,6 +155,8 @@ struct JsonNode
if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n");
+ if (ch == '\n')
+ lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
continue;
@@ -155,7 +164,7 @@ struct JsonNode
break;
f.unget();
- data_array.push_back(new JsonNode(f));
+ data_array.push_back(new JsonNode(f, lineno));
}
break;
@@ -170,6 +179,8 @@ struct JsonNode
if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n");
+ if (ch == '\n')
+ lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ',')
continue;
@@ -177,7 +188,7 @@ struct JsonNode
break;
f.unget();
- JsonNode key(f);
+ JsonNode key(f, lineno);
while (1) {
ch = f.get();
@@ -185,6 +196,8 @@ struct JsonNode
if (ch == EOF)
log_error("Unexpected EOF in JSON file.\n");
+ if (ch == '\n')
+ lineno++;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == ':')
continue;
@@ -192,10 +205,10 @@ struct JsonNode
break;
}
- JsonNode *value = new JsonNode(f);
+ JsonNode *value = new JsonNode(f, lineno);
if (key.type != 'S')
- log_error("Unexpected non-string key in JSON dict.\n");
+ log_error("Unexpected non-string key in JSON dict, line %d.\n", lineno);
data_dict[key.data_string] = value;
data_dict_keys.push_back(key.data_string);
@@ -204,7 +217,7 @@ struct JsonNode
break;
}
- log_error("Unexpected character in JSON file: '%c'\n", ch);
+ log_error("Unexpected character in JSON file, line %d: '%c'\n", lineno, ch);
}
}
@@ -736,8 +749,9 @@ bool parse_json_file(std::istream &f, std::string &filename, Context *ctx)
{
try {
using namespace JsonParser;
+ int lineno = 1;
- JsonNode root(f);
+ JsonNode root(f, lineno);
if (root.type != 'D')
log_error("JSON root node is not a dictionary.\n");