Add Context::archcheck() and "nextpnr-ice40 --test"
Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
parent
90fe002a36
commit
e647604e2a
146
common/archcheck.cc
Normal file
146
common/archcheck.cc
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Clifford Wolf <clifford@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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define dbg(...) log(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dbg(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USING_NEXTPNR_NAMESPACE
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void archcheck_names(const Context *ctx)
|
||||||
|
{
|
||||||
|
log_info("Checking entity names.\n");
|
||||||
|
|
||||||
|
log_info("Checking bel names..\n");
|
||||||
|
for (BelId bel : ctx->getBels()) {
|
||||||
|
IdString name = ctx->getBelName(bel);
|
||||||
|
BelId bel2 = ctx->getBelByName(name);
|
||||||
|
log_assert(bel == bel2);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Checking wire names..\n");
|
||||||
|
for (WireId wire : ctx->getWires()) {
|
||||||
|
IdString name = ctx->getWireName(wire);
|
||||||
|
WireId wire2 = ctx->getWireByName(name);
|
||||||
|
log_assert(wire == wire2);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Checking pip names..\n");
|
||||||
|
for (PipId pip : ctx->getPips()) {
|
||||||
|
IdString name = ctx->getPipName(pip);
|
||||||
|
PipId pip2 = ctx->getPipByName(name);
|
||||||
|
log_assert(pip == pip2);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_break();
|
||||||
|
}
|
||||||
|
|
||||||
|
void archcheck_locs(const Context *ctx)
|
||||||
|
{
|
||||||
|
log_info("Checking location data.\n");
|
||||||
|
|
||||||
|
log_info("Checking all bels..\n");
|
||||||
|
for (BelId bel : ctx->getBels()) {
|
||||||
|
log_assert(bel != BelId());
|
||||||
|
dbg("> %s\n", ctx->getBelName(bel).c_str(ctx));
|
||||||
|
|
||||||
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
|
dbg(" ... %d %d %d\n", loc.x, loc.y, loc.z);
|
||||||
|
|
||||||
|
log_assert(0 <= loc.x);
|
||||||
|
log_assert(0 <= loc.y);
|
||||||
|
log_assert(0 <= loc.z);
|
||||||
|
log_assert(loc.x < ctx->getGridDimX());
|
||||||
|
log_assert(loc.y < ctx->getGridDimY());
|
||||||
|
log_assert(loc.z < ctx->getTileDimZ(loc.x, loc.y));
|
||||||
|
|
||||||
|
BelId bel2 = ctx->getBelByLocation(loc);
|
||||||
|
dbg(" ... %s\n", ctx->getBelName(bel2).c_str(ctx));
|
||||||
|
log_assert(bel == bel2);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Checking all locations..\n");
|
||||||
|
for (int x = 0; x < ctx->getGridDimX(); x++)
|
||||||
|
for (int y = 0; y < ctx->getGridDimY(); y++)
|
||||||
|
{
|
||||||
|
dbg("> %d %d\n", x, y);
|
||||||
|
std::unordered_set<int> usedz;
|
||||||
|
|
||||||
|
for (int z = 0; z < ctx->getTileDimZ(x, y); z++) {
|
||||||
|
BelId bel = ctx->getBelByLocation(Loc(x, y, z));
|
||||||
|
if (bel == BelId())
|
||||||
|
continue;
|
||||||
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
|
dbg(" + %d %s\n", z, ctx->getBelName(bel).c_str(ctx));
|
||||||
|
log_assert(x == loc.x);
|
||||||
|
log_assert(y == loc.y);
|
||||||
|
log_assert(z == loc.z);
|
||||||
|
usedz.insert(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BelId bel : ctx->getBelsByTile(x, y)) {
|
||||||
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
|
dbg(" - %d %s\n", loc.z, ctx->getBelName(bel).c_str(ctx));
|
||||||
|
log_assert(x == loc.x);
|
||||||
|
log_assert(y == loc.y);
|
||||||
|
log_assert(usedz.count(loc.z));
|
||||||
|
usedz.erase(loc.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert(usedz.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
log_break();
|
||||||
|
}
|
||||||
|
|
||||||
|
void archcheck_conn(const Context *ctx)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
log_info("Checking connectivity data.\n");
|
||||||
|
|
||||||
|
log_info("Checking all wires..\n");
|
||||||
|
for (WireId wire : ctx->getWires())
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void Context::archcheck() const
|
||||||
|
{
|
||||||
|
log_info("Running architecture database integrity check.\n");
|
||||||
|
log_break();
|
||||||
|
|
||||||
|
archcheck_names(this);
|
||||||
|
archcheck_locs(this);
|
||||||
|
archcheck_conn(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
@ -69,17 +69,13 @@ NPNR_NORETURN void log_cmd_error(const char *format, ...) NPNR_ATTRIBUTE(format(
|
|||||||
void log_break();
|
void log_break();
|
||||||
void log_flush();
|
void log_flush();
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line)
|
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line)
|
||||||
{
|
{
|
||||||
if (!cond)
|
if (!cond)
|
||||||
log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
|
log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
|
||||||
}
|
}
|
||||||
#define log_assert(_assert_expr_) \
|
#define log_assert(_assert_expr_) \
|
||||||
YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
|
NEXTPNR_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
|
||||||
#else
|
|
||||||
#define log_assert(_assert_expr_)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
|
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
|
||||||
#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
@ -472,6 +472,7 @@ struct Context : Arch, DeterministicRNG
|
|||||||
uint32_t checksum() const;
|
uint32_t checksum() const;
|
||||||
|
|
||||||
void check() const;
|
void check() const;
|
||||||
|
void archcheck() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -373,8 +373,12 @@ with open(args.filename, "r") as f:
|
|||||||
if line[0] == ".extra_cell":
|
if line[0] == ".extra_cell":
|
||||||
if len(line) >= 5:
|
if len(line) >= 5:
|
||||||
mode = ("extra_cell", (line[4], int(line[1]), int(line[2]), int(line[3])))
|
mode = ("extra_cell", (line[4], int(line[1]), int(line[2]), int(line[3])))
|
||||||
else:
|
elif line[3] == "WARMBOOT":
|
||||||
|
mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 0))
|
||||||
|
elif line[3] == "PLL":
|
||||||
mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 3))
|
mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 3))
|
||||||
|
else:
|
||||||
|
assert 0
|
||||||
extra_cells[mode[1]] = []
|
extra_cells[mode[1]] = []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -564,11 +568,14 @@ def add_bel_ram(x, y):
|
|||||||
add_bel_input(bel, wire_names[(x, y1, "ram/RCLKE")], "RCLKE")
|
add_bel_input(bel, wire_names[(x, y1, "ram/RCLKE")], "RCLKE")
|
||||||
add_bel_input(bel, wire_names[(x, y1, "ram/RE")], "RE")
|
add_bel_input(bel, wire_names[(x, y1, "ram/RE")], "RE")
|
||||||
|
|
||||||
def add_bel_gb(x, y, g):
|
def add_bel_gb(xy, x, y, g):
|
||||||
|
if xy[0] != x or xy[1] != y:
|
||||||
|
return
|
||||||
|
|
||||||
bel = len(bel_name)
|
bel = len(bel_name)
|
||||||
bel_name.append("X%d/Y%d/gb" % (x, y))
|
bel_name.append("X%d/Y%d/gb" % (x, y))
|
||||||
bel_type.append("SB_GB")
|
bel_type.append("SB_GB")
|
||||||
bel_pos.append((x, y, 0))
|
bel_pos.append((x, y, 2))
|
||||||
bel_wires.append(list())
|
bel_wires.append(list())
|
||||||
|
|
||||||
add_bel_input(bel, wire_names[(x, y, "fabout")], "USER_SIGNAL_TO_GLOBAL_BUFFER")
|
add_bel_input(bel, wire_names[(x, y, "fabout")], "USER_SIGNAL_TO_GLOBAL_BUFFER")
|
||||||
@ -605,50 +612,57 @@ for tile_xy, tile_type in sorted(tiles.items()):
|
|||||||
if tile_type == "logic":
|
if tile_type == "logic":
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
add_bel_lc(tile_xy[0], tile_xy[1], i)
|
add_bel_lc(tile_xy[0], tile_xy[1], i)
|
||||||
|
|
||||||
if tile_type == "io":
|
if tile_type == "io":
|
||||||
for i in range(2):
|
for i in range(2):
|
||||||
add_bel_io(tile_xy[0], tile_xy[1], i)
|
add_bel_io(tile_xy[0], tile_xy[1], i)
|
||||||
|
|
||||||
|
if dev_name == "1k":
|
||||||
|
add_bel_gb(tile_xy, 7, 0, 0)
|
||||||
|
add_bel_gb(tile_xy, 7, 17, 1)
|
||||||
|
add_bel_gb(tile_xy, 13, 9, 2)
|
||||||
|
add_bel_gb(tile_xy, 0, 9, 3)
|
||||||
|
add_bel_gb(tile_xy, 6, 17, 4)
|
||||||
|
add_bel_gb(tile_xy, 6, 0, 5)
|
||||||
|
add_bel_gb(tile_xy, 0, 8, 6)
|
||||||
|
add_bel_gb(tile_xy, 13, 8, 7)
|
||||||
|
elif dev_name == "5k":
|
||||||
|
add_bel_gb(tile_xy, 13, 0, 0)
|
||||||
|
add_bel_gb(tile_xy, 13, 31, 1)
|
||||||
|
add_bel_gb(tile_xy, 19, 31, 2)
|
||||||
|
add_bel_gb(tile_xy, 6, 31, 3)
|
||||||
|
add_bel_gb(tile_xy, 12, 31, 4)
|
||||||
|
add_bel_gb(tile_xy, 12, 0, 5)
|
||||||
|
add_bel_gb(tile_xy, 6, 0, 6)
|
||||||
|
add_bel_gb(tile_xy, 19, 0, 7)
|
||||||
|
elif dev_name == "8k":
|
||||||
|
add_bel_gb(tile_xy, 33, 16, 7)
|
||||||
|
add_bel_gb(tile_xy, 0, 16, 6)
|
||||||
|
add_bel_gb(tile_xy, 17, 33, 1)
|
||||||
|
add_bel_gb(tile_xy, 17, 0, 0)
|
||||||
|
add_bel_gb(tile_xy, 0, 17, 3)
|
||||||
|
add_bel_gb(tile_xy, 33, 17, 2)
|
||||||
|
add_bel_gb(tile_xy, 16, 0, 5)
|
||||||
|
add_bel_gb(tile_xy, 16, 33, 4)
|
||||||
|
elif dev_name == "384":
|
||||||
|
add_bel_gb(tile_xy, 7, 4, 7)
|
||||||
|
add_bel_gb(tile_xy, 0, 4, 6)
|
||||||
|
add_bel_gb(tile_xy, 4, 9, 1)
|
||||||
|
add_bel_gb(tile_xy, 4, 0, 0)
|
||||||
|
add_bel_gb(tile_xy, 0, 5, 3)
|
||||||
|
add_bel_gb(tile_xy, 7, 5, 2)
|
||||||
|
add_bel_gb(tile_xy, 3, 0, 5)
|
||||||
|
add_bel_gb(tile_xy, 3, 9, 4)
|
||||||
|
|
||||||
if tile_type == "ramb":
|
if tile_type == "ramb":
|
||||||
add_bel_ram(tile_xy[0], tile_xy[1])
|
add_bel_ram(tile_xy[0], tile_xy[1])
|
||||||
|
|
||||||
if dev_name == "1k":
|
for ec in sorted(extra_cells.keys()):
|
||||||
add_bel_gb( 7, 0, 0)
|
if ec[1] == tile_xy[0] and ec[2] == tile_xy[1]:
|
||||||
add_bel_gb( 7, 17, 1)
|
add_bel_ec(ec)
|
||||||
add_bel_gb(13, 9, 2)
|
|
||||||
add_bel_gb( 0, 9, 3)
|
|
||||||
add_bel_gb( 6, 17, 4)
|
|
||||||
add_bel_gb( 6, 0, 5)
|
|
||||||
add_bel_gb( 0, 8, 6)
|
|
||||||
add_bel_gb(13, 8, 7)
|
|
||||||
elif dev_name == "5k":
|
|
||||||
add_bel_gb(13, 0, 0)
|
|
||||||
add_bel_gb(13, 31, 1)
|
|
||||||
add_bel_gb(19, 31, 2)
|
|
||||||
add_bel_gb( 6, 31, 3)
|
|
||||||
add_bel_gb(12, 31, 4)
|
|
||||||
add_bel_gb(12, 0, 5)
|
|
||||||
add_bel_gb( 6, 0, 6)
|
|
||||||
add_bel_gb(19, 0, 7)
|
|
||||||
elif dev_name == "8k":
|
|
||||||
add_bel_gb(33, 16, 7)
|
|
||||||
add_bel_gb( 0, 16, 6)
|
|
||||||
add_bel_gb(17, 33, 1)
|
|
||||||
add_bel_gb(17, 0, 0)
|
|
||||||
add_bel_gb( 0, 17, 3)
|
|
||||||
add_bel_gb(33, 17, 2)
|
|
||||||
add_bel_gb(16, 0, 5)
|
|
||||||
add_bel_gb(16, 33, 4)
|
|
||||||
elif dev_name == "384":
|
|
||||||
add_bel_gb( 7, 4, 7)
|
|
||||||
add_bel_gb( 0, 4, 6)
|
|
||||||
add_bel_gb( 4, 9, 1)
|
|
||||||
add_bel_gb( 4, 0, 0)
|
|
||||||
add_bel_gb( 0, 5, 3)
|
|
||||||
add_bel_gb( 7, 5, 2)
|
|
||||||
add_bel_gb( 3, 0, 5)
|
|
||||||
add_bel_gb( 3, 9, 4)
|
|
||||||
|
|
||||||
for ec in sorted(extra_cells.keys()):
|
for ec in sorted(extra_cells.keys()):
|
||||||
|
if ec[1] == 0 and ec[2] == 0:
|
||||||
add_bel_ec(ec)
|
add_bel_ec(ec)
|
||||||
|
|
||||||
class BinaryBlobAssembler:
|
class BinaryBlobAssembler:
|
||||||
|
@ -107,6 +107,7 @@ int main(int argc, char *argv[])
|
|||||||
options.add_options()("seed", po::value<int>(), "seed value for random number generator");
|
options.add_options()("seed", po::value<int>(), "seed value for random number generator");
|
||||||
options.add_options()("version,V", "show version");
|
options.add_options()("version,V", "show version");
|
||||||
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||||
|
options.add_options()("test", "check architecture database integrity");
|
||||||
#ifdef ICE40_HX1K_ONLY
|
#ifdef ICE40_HX1K_ONLY
|
||||||
options.add_options()("hx1k", "set device type to iCE40HX1K");
|
options.add_options()("hx1k", "set device type to iCE40HX1K");
|
||||||
#else
|
#else
|
||||||
@ -315,6 +316,9 @@ int main(int argc, char *argv[])
|
|||||||
std::cout << "</svg>\n";
|
std::cout << "</svg>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vm.count("test"))
|
||||||
|
ctx->archcheck();
|
||||||
|
|
||||||
if (vm.count("tmfuzz")) {
|
if (vm.count("tmfuzz")) {
|
||||||
std::vector<WireId> src_wires, dst_wires;
|
std::vector<WireId> src_wires, dst_wires;
|
||||||
|
|
||||||
@ -360,8 +364,10 @@ int main(int argc, char *argv[])
|
|||||||
ctx->chip_info->wire_data[dst.index].type);
|
ctx->chip_info->wire_data[dst.index].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm.count("freq"))
|
if (vm.count("freq"))
|
||||||
ctx->target_freq = vm["freq"].as<double>() * 1e6;
|
ctx->target_freq = vm["freq"].as<double>() * 1e6;
|
||||||
|
|
||||||
ctx->timing_driven = true;
|
ctx->timing_driven = true;
|
||||||
if (vm.count("no-tmdriv"))
|
if (vm.count("no-tmdriv"))
|
||||||
ctx->timing_driven = false;
|
ctx->timing_driven = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user