mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-05-04 07:08:26 +00:00
Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into q3k/gl
This commit is contained in:
10
ice40/arch.h
10
ice40/arch.h
@@ -515,6 +515,8 @@ struct Arch : BaseCtx
|
||||
return id(chip_info->bel_data[bel.index].name.get());
|
||||
}
|
||||
|
||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||
|
||||
void bindBel(BelId bel, IdString cell)
|
||||
{
|
||||
assert(bel != BelId());
|
||||
@@ -607,6 +609,8 @@ struct Arch : BaseCtx
|
||||
return id(chip_info->wire_data[wire.index].name.get());
|
||||
}
|
||||
|
||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||
|
||||
void bindWire(WireId wire, IdString net)
|
||||
{
|
||||
assert(wire != WireId());
|
||||
@@ -646,6 +650,8 @@ struct Arch : BaseCtx
|
||||
PipId getPipByName(IdString name) const;
|
||||
IdString getPipName(PipId pip) const;
|
||||
|
||||
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
|
||||
|
||||
void bindPip(PipId pip, IdString net)
|
||||
{
|
||||
assert(pip != PipId());
|
||||
@@ -755,8 +761,10 @@ struct Arch : BaseCtx
|
||||
|
||||
void estimatePosition(BelId bel, int &x, int &y, bool &gb) const;
|
||||
delay_t estimateDelay(WireId src, WireId dst) const;
|
||||
delay_t getDelayEpsilon() const { return 10; }
|
||||
delay_t getDelayEpsilon() const { return 20; }
|
||||
delay_t getRipupDelayPenalty() const { return 200; }
|
||||
float getDelayNS(delay_t v) const { return v * 0.001; }
|
||||
uint32_t getDelayChecksum(delay_t v) const { return v; }
|
||||
|
||||
// -------------------------------------------------
|
||||
|
||||
|
||||
@@ -229,6 +229,16 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
set_config(ti, config.at(iey).at(iex),
|
||||
"IoCtrl.REN_" + std::to_string(iez), !pullup);
|
||||
}
|
||||
|
||||
if (ctx->args.type == ArchArgs::UP5K) {
|
||||
if (iez == 0) {
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39",
|
||||
!pullup);
|
||||
} else if (iez == 1) {
|
||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35",
|
||||
!pullup);
|
||||
}
|
||||
}
|
||||
} else if (cell.second->type == ctx->id("SB_GB")) {
|
||||
// no cell config bits
|
||||
} else if (cell.second->type == ctx->id("ICESTORM_RAM")) {
|
||||
@@ -312,7 +322,8 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
ctx->args.type == ArchArgs::HX8K) {
|
||||
setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25);
|
||||
} else if (ctx->args.type == ArchArgs::UP5K) {
|
||||
if (tile == TILE_LOGIC) {
|
||||
if (tile == TILE_LOGIC || tile == TILE_RAMB ||
|
||||
tile == TILE_RAMT) {
|
||||
setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 ||
|
||||
y == 26 || y == 27);
|
||||
} else {
|
||||
|
||||
469
ice40/main.cc
469
ice40/main.cc
@@ -39,6 +39,8 @@
|
||||
#include "timing.h"
|
||||
#include "version.h"
|
||||
|
||||
USING_NEXTPNR_NAMESPACE
|
||||
|
||||
void svg_dump_el(const GraphicElement &el)
|
||||
{
|
||||
float scale = 10.0, offset = 10.0;
|
||||
@@ -61,268 +63,291 @@ void svg_dump_el(const GraphicElement &el)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
int rc = 0;
|
||||
std::string str;
|
||||
|
||||
log_files.push_back(stdout);
|
||||
|
||||
po::options_description options("Allowed options");
|
||||
options.add_options()("help,h", "show help");
|
||||
options.add_options()("verbose,v", "verbose output");
|
||||
options.add_options()("force,f", "keep running after errors");
|
||||
options.add_options()("gui", "start gui");
|
||||
options.add_options()("svg", "dump SVG file");
|
||||
options.add_options()("pack-only",
|
||||
"pack design only without placement or routing");
|
||||
|
||||
options.add_options()("run", po::value<std::vector<std::string>>(),
|
||||
"python file to execute");
|
||||
options.add_options()("json", po::value<std::string>(),
|
||||
"JSON design file to ingest");
|
||||
options.add_options()("pcf", po::value<std::string>(),
|
||||
"PCF constraints file to ingest");
|
||||
options.add_options()("asc", po::value<std::string>(),
|
||||
"asc bitstream file to write");
|
||||
options.add_options()("seed", po::value<int>(),
|
||||
"seed value for random number generator");
|
||||
options.add_options()("version,V", "show version");
|
||||
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||
options.add_options()("lp384", "set device type to iCE40LP384");
|
||||
options.add_options()("lp1k", "set device type to iCE40LP1K");
|
||||
options.add_options()("lp8k", "set device type to iCE40LP8K");
|
||||
options.add_options()("hx1k", "set device type to iCE40HX1K");
|
||||
options.add_options()("hx8k", "set device type to iCE40HX8K");
|
||||
options.add_options()("up5k", "set device type to iCE40UP5K");
|
||||
options.add_options()("package", po::value<std::string>(),
|
||||
"set device package");
|
||||
po::positional_options_description pos;
|
||||
pos.add("run", -1);
|
||||
|
||||
po::variables_map vm;
|
||||
try {
|
||||
po::parsed_options parsed = po::command_line_parser(argc, argv)
|
||||
.options(options)
|
||||
.positional(pos)
|
||||
.run();
|
||||
namespace po = boost::program_options;
|
||||
int rc = 0;
|
||||
std::string str;
|
||||
|
||||
po::store(parsed, vm);
|
||||
log_files.push_back(stdout);
|
||||
|
||||
po::notify(vm);
|
||||
}
|
||||
po::options_description options("Allowed options");
|
||||
options.add_options()("help,h", "show help");
|
||||
options.add_options()("verbose,v", "verbose output");
|
||||
options.add_options()("debug", "debug output");
|
||||
options.add_options()("force,f", "keep running after errors");
|
||||
options.add_options()("gui", "start gui");
|
||||
options.add_options()("svg", "dump SVG file");
|
||||
options.add_options()("pack-only",
|
||||
"pack design only without placement or routing");
|
||||
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
options.add_options()("run", po::value<std::vector<std::string>>(),
|
||||
"python file to execute");
|
||||
options.add_options()("json", po::value<std::string>(),
|
||||
"JSON design file to ingest");
|
||||
options.add_options()("pcf", po::value<std::string>(),
|
||||
"PCF constraints file to ingest");
|
||||
options.add_options()("asc", po::value<std::string>(),
|
||||
"asc bitstream file to write");
|
||||
options.add_options()("seed", po::value<int>(),
|
||||
"seed value for random number generator");
|
||||
options.add_options()("version,V", "show version");
|
||||
options.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||
options.add_options()("lp384", "set device type to iCE40LP384");
|
||||
options.add_options()("lp1k", "set device type to iCE40LP1K");
|
||||
options.add_options()("lp8k", "set device type to iCE40LP8K");
|
||||
options.add_options()("hx1k", "set device type to iCE40HX1K");
|
||||
options.add_options()("hx8k", "set device type to iCE40HX8K");
|
||||
options.add_options()("up5k", "set device type to iCE40UP5K");
|
||||
options.add_options()("freq", po::value<double>(),
|
||||
"set target frequency for design in MHz");
|
||||
options.add_options()("package", po::value<std::string>(),
|
||||
"set device package");
|
||||
po::positional_options_description pos;
|
||||
pos.add("run", -1);
|
||||
|
||||
if (vm.count("help") || argc == 1) {
|
||||
help:
|
||||
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;
|
||||
}
|
||||
po::variables_map vm;
|
||||
try {
|
||||
po::parsed_options parsed = po::command_line_parser(argc, argv)
|
||||
.options(options)
|
||||
.positional(pos)
|
||||
.run();
|
||||
|
||||
if (vm.count("version")) {
|
||||
std::cout << boost::filesystem::basename(argv[0])
|
||||
<< " -- Next Generation Place and Route (git "
|
||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||
return 1;
|
||||
}
|
||||
po::store(parsed, vm);
|
||||
|
||||
ArchArgs chipArgs;
|
||||
po::notify(vm);
|
||||
}
|
||||
|
||||
if (vm.count("lp384")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP384;
|
||||
chipArgs.package = "qn32";
|
||||
}
|
||||
catch (std::exception &e) {
|
||||
std::cout << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count("lp1k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
if (vm.count("help") || argc == 1) {
|
||||
help:
|
||||
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("lp8k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP8K;
|
||||
chipArgs.package = "ct256";
|
||||
}
|
||||
if (vm.count("version")) {
|
||||
std::cout << boost::filesystem::basename(argv[0])
|
||||
<< " -- Next Generation Place and Route (git "
|
||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (vm.count("hx1k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::HX1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
ArchArgs chipArgs;
|
||||
|
||||
if (vm.count("hx8k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::HX8K;
|
||||
chipArgs.package = "ct256";
|
||||
}
|
||||
if (vm.count("lp384")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP384;
|
||||
chipArgs.package = "qn32";
|
||||
}
|
||||
|
||||
if (vm.count("up5k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::UP5K;
|
||||
chipArgs.package = "sg48";
|
||||
}
|
||||
if (vm.count("lp1k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
|
||||
if (chipArgs.type == ArchArgs::NONE) {
|
||||
chipArgs.type = ArchArgs::HX1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
if (vm.count("lp8k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::LP8K;
|
||||
chipArgs.package = "ct256";
|
||||
}
|
||||
|
||||
if (vm.count("hx1k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::HX1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
|
||||
if (vm.count("hx8k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::HX8K;
|
||||
chipArgs.package = "ct256";
|
||||
}
|
||||
|
||||
if (vm.count("up5k")) {
|
||||
if (chipArgs.type != ArchArgs::NONE)
|
||||
goto help;
|
||||
chipArgs.type = ArchArgs::UP5K;
|
||||
chipArgs.package = "sg48";
|
||||
}
|
||||
|
||||
if (chipArgs.type == ArchArgs::NONE) {
|
||||
chipArgs.type = ArchArgs::HX1K;
|
||||
chipArgs.package = "tq144";
|
||||
}
|
||||
#ifdef ICE40_HX1K_ONLY
|
||||
if (chipArgs.type != ArchArgs::HX1K) {
|
||||
std::cout << "This version of nextpnr-ice40 is built with HX1K-support "
|
||||
"only.\n";
|
||||
return 1;
|
||||
}
|
||||
if (chipArgs.type != ArchArgs::HX1K) {
|
||||
std::cout << "This version of nextpnr-ice40 is built with "
|
||||
"HX1K-support "
|
||||
"only.\n";
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vm.count("package"))
|
||||
chipArgs.package = vm["package"].as<std::string>();
|
||||
if (vm.count("package"))
|
||||
chipArgs.package = vm["package"].as<std::string>();
|
||||
|
||||
Context ctx(chipArgs);
|
||||
init_python(argv[0]);
|
||||
python_export_global("ctx", ctx);
|
||||
Context ctx(chipArgs);
|
||||
init_python(argv[0]);
|
||||
python_export_global("ctx", ctx);
|
||||
|
||||
if (vm.count("verbose")) {
|
||||
ctx.verbose = true;
|
||||
}
|
||||
if (vm.count("verbose")) {
|
||||
ctx.verbose = true;
|
||||
}
|
||||
|
||||
if (vm.count("force")) {
|
||||
ctx.force = true;
|
||||
}
|
||||
if (vm.count("debug")) {
|
||||
ctx.verbose = true;
|
||||
ctx.debug = true;
|
||||
}
|
||||
|
||||
if (vm.count("seed")) {
|
||||
ctx.rngseed(vm["seed"].as<int>());
|
||||
}
|
||||
if (vm.count("force")) {
|
||||
ctx.force = true;
|
||||
}
|
||||
|
||||
if (vm.count("svg")) {
|
||||
std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
|
||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
for (auto bel : ctx.getBels()) {
|
||||
std::cout << "<!-- " << ctx.getBelName(bel).str(&ctx) << " -->\n";
|
||||
for (auto &el : ctx.getBelGraphics(bel))
|
||||
if (vm.count("seed")) {
|
||||
ctx.rngseed(vm["seed"].as<int>());
|
||||
}
|
||||
|
||||
if (vm.count("svg")) {
|
||||
std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
|
||||
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
for (auto bel : ctx.getBels()) {
|
||||
std::cout << "<!-- " << ctx.getBelName(bel).str(&ctx)
|
||||
<< " -->\n";
|
||||
for (auto &el : ctx.getBelGraphics(bel))
|
||||
svg_dump_el(el);
|
||||
}
|
||||
std::cout << "<!-- Frame -->\n";
|
||||
for (auto &el : ctx.getFrameGraphics())
|
||||
svg_dump_el(el);
|
||||
std::cout << "</svg>\n";
|
||||
}
|
||||
std::cout << "<!-- Frame -->\n";
|
||||
for (auto &el : ctx.getFrameGraphics())
|
||||
svg_dump_el(el);
|
||||
std::cout << "</svg>\n";
|
||||
}
|
||||
|
||||
if (vm.count("tmfuzz")) {
|
||||
std::vector<WireId> src_wires, dst_wires;
|
||||
if (vm.count("tmfuzz")) {
|
||||
std::vector<WireId> src_wires, dst_wires;
|
||||
|
||||
/*for (auto w : ctx.getWires())
|
||||
src_wires.push_back(w);*/
|
||||
for (auto b : ctx.getBels()) {
|
||||
if (ctx.getBelType(b) == TYPE_ICESTORM_LC) {
|
||||
src_wires.push_back(ctx.getWireBelPin(b, PIN_O));
|
||||
/*for (auto w : ctx.getWires())
|
||||
src_wires.push_back(w);*/
|
||||
for (auto b : ctx.getBels()) {
|
||||
if (ctx.getBelType(b) == TYPE_ICESTORM_LC) {
|
||||
src_wires.push_back(ctx.getWireBelPin(b, PIN_O));
|
||||
}
|
||||
if (ctx.getBelType(b) == TYPE_SB_IO) {
|
||||
src_wires.push_back(ctx.getWireBelPin(b, PIN_D_IN_0));
|
||||
}
|
||||
}
|
||||
if (ctx.getBelType(b) == TYPE_SB_IO) {
|
||||
src_wires.push_back(ctx.getWireBelPin(b, PIN_D_IN_0));
|
||||
|
||||
for (auto b : ctx.getBels()) {
|
||||
if (ctx.getBelType(b) == TYPE_ICESTORM_LC) {
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I0));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I1));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I2));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I3));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_CEN));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_CIN));
|
||||
}
|
||||
if (ctx.getBelType(b) == TYPE_SB_IO) {
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_D_OUT_0));
|
||||
dst_wires.push_back(
|
||||
ctx.getWireBelPin(b, PIN_OUTPUT_ENABLE));
|
||||
}
|
||||
}
|
||||
|
||||
ctx.shuffle(src_wires);
|
||||
ctx.shuffle(dst_wires);
|
||||
|
||||
for (int i = 0;
|
||||
i < int(src_wires.size()) && i < int(dst_wires.size()); i++) {
|
||||
delay_t actual_delay;
|
||||
WireId src = src_wires[i], dst = dst_wires[i];
|
||||
if (!get_actual_route_delay(&ctx, src, dst, actual_delay))
|
||||
continue;
|
||||
printf("%s %s %.3f %.3f %d %d %d %d %d %d\n",
|
||||
ctx.getWireName(src).c_str(&ctx),
|
||||
ctx.getWireName(dst).c_str(&ctx),
|
||||
ctx.getDelayNS(actual_delay),
|
||||
ctx.getDelayNS(ctx.estimateDelay(src, dst)),
|
||||
ctx.chip_info->wire_data[src.index].x,
|
||||
ctx.chip_info->wire_data[src.index].y,
|
||||
ctx.chip_info->wire_data[src.index].type,
|
||||
ctx.chip_info->wire_data[dst.index].x,
|
||||
ctx.chip_info->wire_data[dst.index].y,
|
||||
ctx.chip_info->wire_data[dst.index].type);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto b : ctx.getBels()) {
|
||||
if (ctx.getBelType(b) == TYPE_ICESTORM_LC) {
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I0));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I1));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I2));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_I3));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_CEN));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_CIN));
|
||||
if (vm.count("json")) {
|
||||
std::string filename = vm["json"].as<std::string>();
|
||||
std::ifstream f(filename);
|
||||
if (!parse_json_file(f, filename, &ctx))
|
||||
log_error("Loading design failed.\n");
|
||||
|
||||
if (vm.count("pcf")) {
|
||||
std::ifstream pcf(vm["pcf"].as<std::string>());
|
||||
if (!apply_pcf(&ctx, pcf))
|
||||
log_error("Loading PCF failed.\n");
|
||||
}
|
||||
if (ctx.getBelType(b) == TYPE_SB_IO) {
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_D_OUT_0));
|
||||
dst_wires.push_back(ctx.getWireBelPin(b, PIN_OUTPUT_ENABLE));
|
||||
|
||||
if (!pack_design(&ctx) && !ctx.force)
|
||||
log_error("Packing design failed.\n");
|
||||
double freq = 50e6;
|
||||
if (vm.count("freq"))
|
||||
freq = vm["freq"].as<double>() * 1e6;
|
||||
assign_budget(&ctx, freq);
|
||||
print_utilisation(&ctx);
|
||||
|
||||
if (!vm.count("pack-only")) {
|
||||
if (!place_design_sa(&ctx) && !ctx.force)
|
||||
log_error("Placing design failed.\n");
|
||||
if (!route_design(&ctx) && !ctx.force)
|
||||
log_error("Routing design failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
ctx.shuffle(src_wires);
|
||||
ctx.shuffle(dst_wires);
|
||||
|
||||
for (int i = 0; i < int(src_wires.size()) && i < int(dst_wires.size());
|
||||
i++) {
|
||||
delay_t actual_delay;
|
||||
WireId src = src_wires[i], dst = dst_wires[i];
|
||||
if (!get_actual_route_delay(&ctx, src, dst, actual_delay))
|
||||
continue;
|
||||
printf("%s %s %.3f %.3f %d %d %d %d %d %d\n",
|
||||
ctx.getWireName(src).c_str(&ctx),
|
||||
ctx.getWireName(dst).c_str(&ctx),
|
||||
ctx.getDelayNS(actual_delay),
|
||||
ctx.getDelayNS(ctx.estimateDelay(src, dst)),
|
||||
ctx.chip_info->wire_data[src.index].x,
|
||||
ctx.chip_info->wire_data[src.index].y,
|
||||
ctx.chip_info->wire_data[src.index].type,
|
||||
ctx.chip_info->wire_data[dst.index].x,
|
||||
ctx.chip_info->wire_data[dst.index].y,
|
||||
ctx.chip_info->wire_data[dst.index].type);
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.count("json")) {
|
||||
std::string filename = vm["json"].as<std::string>();
|
||||
std::istream *f = new std::ifstream(filename);
|
||||
|
||||
parse_json_file(f, filename, &ctx);
|
||||
|
||||
if (vm.count("pcf")) {
|
||||
std::ifstream pcf(vm["pcf"].as<std::string>());
|
||||
apply_pcf(&ctx, pcf);
|
||||
if (vm.count("asc")) {
|
||||
std::string filename = vm["asc"].as<std::string>();
|
||||
std::ofstream f(filename);
|
||||
write_asc(&ctx, f);
|
||||
}
|
||||
|
||||
if (!pack_design(&ctx) && !ctx.force)
|
||||
log_error("Packing design failed.\n");
|
||||
assign_budget(&ctx, 50e6);
|
||||
print_utilisation(&ctx);
|
||||
|
||||
if (!vm.count("pack-only")) {
|
||||
if (!place_design_sa(&ctx) && !ctx.force)
|
||||
log_error("Placing design failed.\n");
|
||||
if (!route_design(&ctx) && !ctx.force)
|
||||
log_error("Routing design failed.\n");
|
||||
if (vm.count("run")) {
|
||||
std::vector<std::string> files =
|
||||
vm["run"].as<std::vector<std::string>>();
|
||||
for (auto filename : files)
|
||||
execute_python_file(filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (vm.count("asc")) {
|
||||
std::string filename = vm["asc"].as<std::string>();
|
||||
std::ofstream f(filename);
|
||||
write_asc(&ctx, f);
|
||||
}
|
||||
if (vm.count("gui")) {
|
||||
QApplication a(argc, argv);
|
||||
QSurfaceFormat fmt;
|
||||
fmt.setSamples(10);
|
||||
QSurfaceFormat::setDefaultFormat(fmt);
|
||||
MainWindow w(&ctx);
|
||||
w.show();
|
||||
|
||||
if (vm.count("run")) {
|
||||
std::vector<std::string> files =
|
||||
vm["run"].as<std::vector<std::string>>();
|
||||
for (auto filename : files)
|
||||
execute_python_file(filename.c_str());
|
||||
rc = a.exec();
|
||||
}
|
||||
deinit_python();
|
||||
return rc;
|
||||
} catch (log_execution_error_exception) {
|
||||
#if defined(_MSC_VER)
|
||||
_exit(EXIT_FAILURE);
|
||||
#else
|
||||
_Exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vm.count("gui")) {
|
||||
QApplication a(argc, argv);
|
||||
QSurfaceFormat fmt;
|
||||
fmt.setSamples(10);
|
||||
QSurfaceFormat::setDefaultFormat(fmt);
|
||||
MainWindow w(&ctx);
|
||||
w.show();
|
||||
|
||||
rc = a.exec();
|
||||
}
|
||||
deinit_python();
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "cells.h"
|
||||
#include "design_utils.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
@@ -34,10 +35,11 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
|
||||
std::unordered_set<IdString> packed_cells;
|
||||
std::vector<CellInfo *> new_cells;
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx),
|
||||
ci->type.c_str(ctx));
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx),
|
||||
ci->type.c_str(ctx));
|
||||
if (is_lut(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
|
||||
ci->name.str(ctx) + "_LC");
|
||||
@@ -45,8 +47,9 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
// See if we can pack into a DFF
|
||||
// TODO: LUT cascade
|
||||
NetInfo *o = ci->ports.at(ctx->id("O")).net;
|
||||
@@ -54,7 +57,8 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
auto lut_bel = ci->attrs.find(ctx->id("BEL"));
|
||||
bool packed_dff = false;
|
||||
if (dff) {
|
||||
log_info("found attached dff %s\n", dff->name.c_str(ctx));
|
||||
if (ctx->verbose)
|
||||
log_info("found attached dff %s\n", dff->name.c_str(ctx));
|
||||
auto dff_bel = dff->attrs.find(ctx->id("BEL"));
|
||||
if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() &&
|
||||
lut_bel->second != dff_bel->second) {
|
||||
@@ -66,8 +70,9 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
if (dff_bel != dff->attrs.end())
|
||||
packed->attrs[ctx->id("BEL")] = dff_bel->second;
|
||||
packed_cells.insert(dff->name);
|
||||
log_info("packed cell %s into %s\n", dff->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n",
|
||||
dff->name.c_str(ctx), packed->name.c_str(ctx));
|
||||
packed_dff = true;
|
||||
}
|
||||
}
|
||||
@@ -92,15 +97,16 @@ static void pack_nonlut_ffs(Context *ctx)
|
||||
std::unordered_set<IdString> packed_cells;
|
||||
std::vector<CellInfo *> new_cells;
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ff(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
|
||||
ci->name.str(ctx) + "_DFFLC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
std::inserter(packed->attrs, packed->attrs.begin()));
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
if (ctx->verbose)
|
||||
log_info("packed cell %s into %s\n", ci->name.c_str(ctx),
|
||||
packed->name.c_str(ctx));
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
dff_to_lc(ctx, ci, packed, true);
|
||||
@@ -121,7 +127,7 @@ static void pack_carries(Context *ctx)
|
||||
|
||||
std::unordered_set<IdString> packed_cells;
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_carry(ctx, ci)) {
|
||||
packed_cells.insert(cell.first);
|
||||
@@ -196,7 +202,7 @@ static void pack_ram(Context *ctx)
|
||||
std::unordered_set<IdString> packed_cells;
|
||||
std::vector<CellInfo *> new_cells;
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ram(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM",
|
||||
@@ -242,10 +248,11 @@ static void set_net_constant(const Context *ctx, NetInfo *orig,
|
||||
for (auto user : orig->users) {
|
||||
if (user.cell != nullptr) {
|
||||
CellInfo *uc = user.cell;
|
||||
log_info("%s user %s\n", orig->name.c_str(ctx),
|
||||
uc->name.c_str(ctx));
|
||||
if (is_lut(ctx, uc) && (user.port.str(ctx).at(0) == 'I') &&
|
||||
!constval) {
|
||||
if (ctx->verbose)
|
||||
log_info("%s user %s\n", orig->name.c_str(ctx),
|
||||
uc->name.c_str(ctx));
|
||||
if ((is_lut(ctx, uc) || is_lc(ctx, uc)) &&
|
||||
(user.port.str(ctx).at(0) == 'I') && !constval) {
|
||||
uc->ports[user.port].net = nullptr;
|
||||
} else {
|
||||
uc->ports[user.port].net = constnet;
|
||||
@@ -279,7 +286,7 @@ static void pack_constants(Context *ctx)
|
||||
|
||||
bool gnd_used = false, vcc_used = false;
|
||||
|
||||
for (auto net : ctx->nets) {
|
||||
for (auto net : sorted(ctx->nets)) {
|
||||
NetInfo *ni = net.second;
|
||||
if (ni->driver.cell != nullptr &&
|
||||
ni->driver.cell->type == ctx->id("GND")) {
|
||||
@@ -323,7 +330,7 @@ static void pack_io(Context *ctx)
|
||||
|
||||
log_info("Packing IOs..\n");
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_nextpnr_iob(ctx, ci)) {
|
||||
CellInfo *sb = nullptr;
|
||||
@@ -406,8 +413,8 @@ static void promote_globals(Context *ctx)
|
||||
{
|
||||
log_info("Promoting globals..\n");
|
||||
|
||||
std::unordered_map<IdString, int> clock_count, reset_count, cen_count;
|
||||
for (auto net : ctx->nets) {
|
||||
std::map<IdString, int> clock_count, reset_count, cen_count;
|
||||
for (auto net : sorted(ctx->nets)) {
|
||||
NetInfo *ni = net.second;
|
||||
if (ni->driver.cell != nullptr && !is_global_net(ctx, ni)) {
|
||||
clock_count[net.first] = 0;
|
||||
@@ -481,13 +488,19 @@ static void promote_globals(Context *ctx)
|
||||
// Main pack function
|
||||
bool pack_design(Context *ctx)
|
||||
{
|
||||
pack_constants(ctx);
|
||||
promote_globals(ctx);
|
||||
pack_io(ctx);
|
||||
pack_lut_lutffs(ctx);
|
||||
pack_nonlut_ffs(ctx);
|
||||
pack_ram(ctx);
|
||||
return true;
|
||||
try {
|
||||
log_break();
|
||||
pack_constants(ctx);
|
||||
promote_globals(ctx);
|
||||
pack_io(ctx);
|
||||
pack_lut_lutffs(ctx);
|
||||
pack_nonlut_ffs(ctx);
|
||||
pack_ram(ctx);
|
||||
log_info("Checksum: 0x%08x\n", ctx->checksum());
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
75
ice40/pcf.cc
75
ice40/pcf.cc
@@ -27,44 +27,51 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
// Read a w
|
||||
|
||||
// Apply PCF constraints to a pre-packing design
|
||||
void apply_pcf(Context *ctx, std::istream &in)
|
||||
bool apply_pcf(Context *ctx, std::istream &in)
|
||||
{
|
||||
if (!in)
|
||||
log_error("failed to open PCF file");
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
size_t cstart = line.find("#");
|
||||
if (cstart != std::string::npos)
|
||||
line = line.substr(0, cstart);
|
||||
std::stringstream ss(line);
|
||||
std::vector<std::string> words;
|
||||
std::string tmp;
|
||||
while (ss >> tmp)
|
||||
words.push_back(tmp);
|
||||
if (words.size() == 0)
|
||||
continue;
|
||||
std::string cmd = words.at(0);
|
||||
if (cmd == "set_io") {
|
||||
size_t args_end = 1;
|
||||
while (args_end < words.size() && words.at(args_end).at(0) == '-')
|
||||
args_end++;
|
||||
std::string cell = words.at(args_end);
|
||||
std::string pin = words.at(args_end + 1);
|
||||
auto fnd_cell = ctx->cells.find(cell);
|
||||
if (fnd_cell == ctx->cells.end()) {
|
||||
log_warning("unmatched pcf constraint %s\n", cell.c_str());
|
||||
try {
|
||||
if (!in)
|
||||
log_error("failed to open PCF file");
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
size_t cstart = line.find("#");
|
||||
if (cstart != std::string::npos)
|
||||
line = line.substr(0, cstart);
|
||||
std::stringstream ss(line);
|
||||
std::vector<std::string> words;
|
||||
std::string tmp;
|
||||
while (ss >> tmp)
|
||||
words.push_back(tmp);
|
||||
if (words.size() == 0)
|
||||
continue;
|
||||
std::string cmd = words.at(0);
|
||||
if (cmd == "set_io") {
|
||||
size_t args_end = 1;
|
||||
while (args_end < words.size() &&
|
||||
words.at(args_end).at(0) == '-')
|
||||
args_end++;
|
||||
std::string cell = words.at(args_end);
|
||||
std::string pin = words.at(args_end + 1);
|
||||
auto fnd_cell = ctx->cells.find(cell);
|
||||
if (fnd_cell == ctx->cells.end()) {
|
||||
log_warning("unmatched pcf constraint %s\n", cell.c_str());
|
||||
} else {
|
||||
BelId pin_bel = ctx->getPackagePinBel(pin);
|
||||
if (pin_bel == BelId())
|
||||
log_error("package does not have a pin named %s\n",
|
||||
pin.c_str());
|
||||
fnd_cell->second->attrs["BEL"] =
|
||||
ctx->getBelName(pin_bel).str();
|
||||
log_info("constrained '%s' to bel '%s'\n", cell.c_str(),
|
||||
fnd_cell->second->attrs["BEL"].c_str());
|
||||
}
|
||||
} else {
|
||||
BelId pin_bel = ctx->getPackagePinBel(pin);
|
||||
if (pin_bel == BelId())
|
||||
log_error("package does not have a pin named %s\n",
|
||||
pin.c_str());
|
||||
fnd_cell->second->attrs["BEL"] = ctx->getBelName(pin_bel).str();
|
||||
log_info("constrained '%s' to bel '%s'\n", cell.c_str(),
|
||||
fnd_cell->second->attrs["BEL"].c_str());
|
||||
log_error("unsupported pcf command '%s'\n", cmd.c_str());
|
||||
}
|
||||
} else {
|
||||
log_error("unsupported pcf command '%s'\n", cmd.c_str());
|
||||
}
|
||||
return true;
|
||||
} catch (log_execution_error_exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Apply PCF constraints to a pre-packing design
|
||||
void apply_pcf(Context *ctx, std::istream &in);
|
||||
bool apply_pcf(Context *ctx, std::istream &in);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ set -ex
|
||||
rm -f picorv32.v
|
||||
wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v
|
||||
yosys -p 'synth_ice40 -nocarry -blif picorv32.blif -top top' picorv32.v picorv32_top.v
|
||||
arachne-pnr -d 8k --post-place-blif picorv32_place.blif picorv32.blif
|
||||
arachne-pnr -d 8k --post-place-blif picorv32_place.blif picorv32.blif -o picorv32_arachne_all.asc
|
||||
yosys -p "read_blif -wideports picorv32_place.blif; read_verilog -lib +/ice40/cells_sim.v; write_json picorv32_place.json"
|
||||
./transform_arachne_loc.py picorv32_place.json > picorv32_place_nx.json
|
||||
../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32_place_nx.json
|
||||
../nextpnr-ice40 --hx8k --asc picorv32_ar_placed.asc --json picorv32_place_nx.json --force
|
||||
|
||||
Reference in New Issue
Block a user