Merge pull request #998 from yrabbit/clock-wip

gowin: add a separate router for the clocks
This commit is contained in:
myrtle 2022-07-18 08:39:05 +01:00 committed by GitHub
commit 5667113f8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 479 additions and 1 deletions

View File

@ -256,6 +256,8 @@ bool Arch::allocate_longwire(NetInfo *ni, int lw_idx)
return true; return true;
} }
void Arch::auto_longwires() {}
void Arch::fix_longwire_bels() void Arch::fix_longwire_bels()
{ {
// After routing, it is clear which wires and in which bus SS00 and SS40 are used and // After routing, it is clear which wires and in which bus SS00 and SS40 are used and
@ -341,6 +343,14 @@ BelInfo &Arch::bel_info(IdString bel)
return b->second; return b->second;
} }
NetInfo &Arch::net_info(IdString net)
{
auto b = nets.find(net);
if (b == nets.end())
NPNR_ASSERT_FALSE_STR("no net named " + net.str(this));
return *b->second;
}
void Arch::addWire(IdString name, IdString type, int x, int y) void Arch::addWire(IdString name, IdString type, int x, int y)
{ {
NPNR_ASSERT(wires.count(name) == 0); NPNR_ASSERT(wires.count(name) == 0);
@ -543,6 +553,8 @@ void Arch::setDelayScaling(double scale, double offset)
args.delayOffset = offset; args.delayOffset = offset;
} }
void Arch::addCellTimingClass(IdString cell, IdString port, TimingPortClass cls) {cellTiming[cell].portClasses[port] = cls;}
void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; } void Arch::addCellTimingClock(IdString cell, IdString port) { cellTiming[cell].portClasses[port] = TMG_CLOCK_INPUT; }
void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay) void Arch::addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay)
@ -657,6 +669,7 @@ bool aliasCompare(GlobalAliasPOD i, GlobalAliasPOD j)
return (i.dest_row < j.dest_row) || (i.dest_row == j.dest_row && i.dest_col < j.dest_col) || return (i.dest_row < j.dest_row) || (i.dest_row == j.dest_row && i.dest_col < j.dest_col) ||
(i.dest_row == j.dest_row && i.dest_col == j.dest_col && i.dest_id < j.dest_id); (i.dest_row == j.dest_row && i.dest_col == j.dest_col && i.dest_id < j.dest_id);
} }
bool timingCompare(TimingPOD i, TimingPOD j) { return i.name_id < j.name_id; } bool timingCompare(TimingPOD i, TimingPOD j) { return i.name_id < j.name_id; }
template <class T, class C> const T *genericLookup(const T *first, int len, const T val, C compare) template <class T, class C> const T *genericLookup(const T *first, int len, const T val, C compare)
@ -1895,6 +1908,11 @@ bool Arch::place()
bool Arch::route() bool Arch::route()
{ {
std::string router = str_or_default(settings, id_router, defaultRouter); std::string router = str_or_default(settings, id_router, defaultRouter);
if (bool_or_default(settings, id("arch.enable-globals"))) {
route_gowin_globals(getCtx());
}
bool result; bool result;
if (router == "router1") { if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx())); result = router1(getCtx(), Router1Cfg(getCtx()));
@ -2004,6 +2022,8 @@ void Arch::assignArchInfo()
// add timing paths // add timing paths
addCellTimingClock(cname, id_CLK); addCellTimingClock(cname, id_CLK);
addCellTimingClass(cname, id_CE, TMG_REGISTER_INPUT);
addCellTimingClass(cname, id_LSR, TMG_REGISTER_INPUT);
IdString ports[4] = {id_A, id_B, id_C, id_D}; IdString ports[4] = {id_A, id_B, id_C, id_D};
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
DelayPair setup = DelayPair setup =
@ -2034,7 +2054,19 @@ void Arch::assignArchInfo()
delay = delay + delayLookup(speed->lut.timings.get(), speed->lut.num_timings, id_fx_ofx1); delay = delay + delayLookup(speed->lut.timings.get(), speed->lut.num_timings, id_fx_ofx1);
addCellTimingDelay(cname, id_I0, id_OF, delay); addCellTimingDelay(cname, id_I0, id_OF, delay);
addCellTimingDelay(cname, id_I1, id_OF, delay); addCellTimingDelay(cname, id_I1, id_OF, delay);
addCellTimingClass(cname, id_SEL, TMG_COMB_INPUT);
break;
} }
case ID_IOB:
/* FALLTHRU */
case ID_IOBS:
addCellTimingClass(cname, id_I, TMG_ENDPOINT);
addCellTimingClass(cname, id_O, TMG_STARTPOINT);
break;
case ID_BUFS:
addCellTimingClass(cname, id_I, TMG_ENDPOINT);
addCellTimingClass(cname, id_O, TMG_STARTPOINT);
break;
default: default:
break; break;
} }
@ -2078,4 +2110,22 @@ bool Arch::cellsCompatible(const CellInfo **cells, int count) const
return true; return true;
} }
void Arch::route_gowin_globals(Context *ctx) { globals_router.route_globals(ctx); }
void Arch::mark_gowin_globals(Context *ctx) { globals_router.mark_globals(ctx); }
// ---------------------------------------------------------------
void Arch::pre_pack(Context *ctx)
{
if (bool_or_default(settings, id("arch.enable-auto-longwires"))) {
auto_longwires();
}
}
void Arch::post_pack(Context *ctx)
{
if (bool_or_default(settings, id("arch.enable-globals"))) {
mark_gowin_globals(ctx);
}
}
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

View File

@ -31,6 +31,8 @@
#include "nextpnr_namespaces.h" #include "nextpnr_namespaces.h"
#include "nextpnr_types.h" #include "nextpnr_types.h"
#include "globals.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
template <typename T> struct RelPtr template <typename T> struct RelPtr
@ -289,6 +291,7 @@ struct Arch : BaseArch<ArchRanges>
WireInfo &wire_info(IdString wire); WireInfo &wire_info(IdString wire);
PipInfo &pip_info(IdString pip); PipInfo &pip_info(IdString pip);
BelInfo &bel_info(IdString bel); BelInfo &bel_info(IdString bel);
NetInfo &net_info(IdString net);
std::vector<IdString> bel_ids, wire_ids, pip_ids; std::vector<IdString> bel_ids, wire_ids, pip_ids;
@ -336,6 +339,7 @@ struct Arch : BaseArch<ArchRanges>
void setDelayScaling(double scale, double offset); void setDelayScaling(double scale, double offset);
void addCellTimingClock(IdString cell, IdString port); void addCellTimingClock(IdString cell, IdString port);
void addCellTimingClass(IdString cell, IdString port, TimingPortClass cls);
void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay); void addCellTimingDelay(IdString cell, IdString fromPort, IdString toPort, DelayQuad delay);
void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold); void addCellTimingSetupHold(IdString cell, IdString port, IdString clock, DelayPair setup, DelayPair hold);
void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq); void addCellTimingClockToOut(IdString cell, IdString port, IdString clock, DelayQuad clktoq);
@ -461,6 +465,13 @@ struct Arch : BaseArch<ArchRanges>
bool haveBelType(int x, int y, IdString bel_type); bool haveBelType(int x, int y, IdString bel_type);
bool allocate_longwire(NetInfo *ni, int lw_idx = -1); bool allocate_longwire(NetInfo *ni, int lw_idx = -1);
void fix_longwire_bels(); void fix_longwire_bels();
void pre_pack(Context *ctx);
void post_pack(Context *ctx);
void auto_longwires();
GowinGlobalRouter globals_router;
void mark_gowin_globals(Context *ctx);
void route_gowin_globals(Context *ctx);
// chip db version // chip db version
unsigned int const chipdb_version = 1; unsigned int const chipdb_version = 1;

308
gowin/globals.cc Normal file
View File

@ -0,0 +1,308 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
* Copyright (C) 2022 YRabbit <rabbit@yrabbit.cyou>
*
* 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 <algorithm>
#include <iomanip>
#include <iostream>
#include <queue>
#include "cells.h"
#include "log.h"
#include "nextpnr.h"
#include "place_common.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
bool GowinGlobalRouter::is_clock_port(PortRef const &user)
{
if ((user.cell->type == id_SLICE || user.cell->type == id_ODDR || user.cell->type == id_ODDRC) &&
user.port == id_CLK) {
return true;
}
return false;
}
std::pair<WireId, BelId> GowinGlobalRouter::clock_io(Context *ctx, PortRef const &driver)
{
// XXX normally all alternative functions of the pins should be passed
// in the chip database, but at the moment we find them from aliases/pips
// XXX check diff inputs too
if (driver.cell == nullptr || driver.cell->type != id_IOB || !driver.cell->attrs.count(id_BEL)) {
return std::make_pair(WireId(), BelId());
}
// clock IOs have pips output->SPINExx
BelInfo &bel = ctx->bel_info(ctx->id(driver.cell->attrs[id_BEL].as_string()));
WireId wire = bel.pins[id_O].wire;
for (auto const pip : ctx->getPipsDownhill(wire)) {
if (ctx->wire_info(ctx->getPipDstWire(pip)).type.str(ctx).rfind("SPINE", 0) == 0) {
return std::make_pair(wire, bel.name);
}
}
return std::make_pair(WireId(), BelId());
}
// gather the clock nets
void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t> &clock_nets)
{
for (auto const &net : ctx->nets) {
NetInfo const *ni = net.second.get();
auto new_clock = clock_nets.end();
auto clock_wire_bel = clock_io(ctx, ni->driver);
if (clock_wire_bel.first != WireId()) {
clock_nets.emplace_back(net.first);
new_clock = --clock_nets.end();
new_clock->clock_io_wire = clock_wire_bel.first;
new_clock->clock_io_bel = clock_wire_bel.second;
}
for (auto const &user : ni->users) {
if (is_clock_port(user)) {
if (new_clock == clock_nets.end()) {
clock_nets.emplace_back(net.first);
new_clock = --clock_nets.end();
}
++(new_clock->clock_ports);
}
}
}
// need to prioritize the nets
std::sort(clock_nets.begin(), clock_nets.end());
if (ctx->verbose) {
for (auto const &net : clock_nets) {
log_info(" Net:%s, ports:%d, io:%s\n", net.name.c_str(ctx), net.clock_ports,
net.clock_io_wire == WireId() ? "No" : net.clock_io_wire.c_str(ctx));
}
}
}
// non clock port
// returns GB pip
IdString GowinGlobalRouter::route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock,
pool<IdString> &used_pips, pool<IdString> &undo_wires)
{
static std::vector<IdString> one_hop = {id_S111, id_S121, id_N111, id_N121, id_W111, id_W121, id_E111, id_E121};
char buf[40];
// uphill pips
for (auto const uphill : ctx->getPipsUphill(dstWire)) {
WireId srcWire = ctx->getPipSrcWire(uphill);
if (find(one_hop.begin(), one_hop.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) != one_hop.end()) {
// found one hop pip
if (used_wires.count(srcWire)) {
if (used_wires[srcWire] != clock) {
continue;
}
}
WireInfo wi = ctx->wire_info(srcWire);
std::string wire_alias = srcWire.str(ctx).substr(srcWire.str(ctx).rfind("_") + 1);
snprintf(buf, sizeof(buf), "R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, clock, wire_alias.c_str());
IdString gb = ctx->id(buf);
auto up_pips = ctx->getPipsUphill(srcWire);
if (find(up_pips.begin(), up_pips.end(), gb) != up_pips.end()) {
if (!used_wires.count(srcWire)) {
used_wires.insert(std::make_pair(srcWire, clock));
undo_wires.insert(srcWire);
}
used_pips.insert(uphill);
if (ctx->verbose) {
log_info(" 1-hop Pip:%s\n", uphill.c_str(ctx));
}
return gb;
}
}
}
return IdString();
}
// route one net
void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net)
{
// For failed routing undo
pool<IdString> used_pips;
pool<IdString> undo_wires;
log_info(" Route net %s, use clock #%d.\n", net.name.c_str(ctx), net.clock);
for (auto const &user : ctx->net_info(net.name).users) {
// >>> port <- GB<clock>0
WireId dstWire = ctx->getNetinfoSinkWire(&ctx->net_info(net.name), user, 0);
if (ctx->verbose) {
log_info(" Cell:%s, port:%s, wire:%s\n", user.cell->name.c_str(ctx), user.port.c_str(ctx),
dstWire.c_str(ctx));
}
char buf[30];
PipId gb_pip_id;
if (user.port == id_CLK) {
WireInfo const wi = ctx->wire_info(dstWire);
snprintf(buf, sizeof(buf), "R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, net.clock,
ctx->wire_info(dstWire).type.c_str(ctx));
gb_pip_id = ctx->id(buf);
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gb_pip_id) !=
ctx->getPipsUphill(dstWire).end());
} else {
// Non clock port
gb_pip_id = route_to_non_clock_port(ctx, dstWire, net.clock, used_pips, undo_wires);
if (gb_pip_id == IdString()) {
if (ctx->verbose) {
log_info(" Can't find route to %s, net %s will be routed in a standard way.\n", dstWire.c_str(ctx),
net.name.c_str(ctx));
}
for (IdString const undo : undo_wires) {
used_wires.erase(undo);
}
return;
}
}
if (ctx->verbose) {
log_info(" GB Pip:%s\n", gb_pip_id.c_str(ctx));
}
if (used_pips.count(gb_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(gb_pip_id);
// >>> GBOx <- GTx0
dstWire = ctx->getPipSrcWire(gb_pip_id);
WireInfo dstWireInfo = ctx->wire_info(dstWire);
int branch_tap_idx = net.clock > 3 ? 1 : 0;
snprintf(buf, sizeof(buf), "R%dC%d_GT%d0_GBO%d", dstWireInfo.y + 1, dstWireInfo.x + 1, branch_tap_idx,
branch_tap_idx);
PipId gt_pip_id = ctx->id(buf);
if (ctx->verbose) {
log_info(" GT Pip:%s\n", buf);
}
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gt_pip_id) !=
ctx->getPipsUphill(dstWire).end());
// if already routed
if (used_pips.count(gt_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(gt_pip_id);
// >>> GTx0 <- SPINExx
// XXX no optimization here, we need to store
// the SPINE <-> clock# correspondence in the database. In the
// meantime, we define in run-time in a completely suboptimal way.
std::vector<std::string> clock_spine;
dstWire = ctx->getPipSrcWire(gt_pip_id);
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
std::string name = ctx->wire_info(ctx->getPipSrcWire(uphill_pip)).type.str(ctx);
if (name.rfind("SPINE", 0) == 0) {
clock_spine.push_back(name);
}
}
sort(clock_spine.begin(), clock_spine.end(), [](const std::string &a, const std::string &b) -> bool {
return (a.size() < b.size()) || (a.size() == b.size() && a < b);
});
dstWireInfo = ctx->wire_info(dstWire);
snprintf(buf, sizeof(buf), "R%dC%d_%s_GT%d0", dstWireInfo.y + 1, dstWireInfo.x + 1,
clock_spine[net.clock - branch_tap_idx * 4].c_str(), branch_tap_idx);
PipId spine_pip_id = ctx->id(buf);
if (ctx->verbose) {
log_info(" Spine Pip:%s\n", buf);
}
// sanity
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), spine_pip_id) !=
ctx->getPipsUphill(dstWire).end());
// if already routed
if (used_pips.count(spine_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(spine_pip_id);
// >>> SPINExx <- IO
dstWire = ctx->getPipSrcWire(spine_pip_id);
dstWireInfo = ctx->wire_info(dstWire);
PipId io_pip_id = PipId();
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
if (ctx->getPipSrcWire(uphill_pip) == net.clock_io_wire) {
io_pip_id = uphill_pip;
}
}
NPNR_ASSERT(io_pip_id != PipId());
if (ctx->verbose) {
log_info(" IO Pip:%s\n", io_pip_id.c_str(ctx));
}
// if already routed
if (used_pips.count(io_pip_id)) {
if (ctx->verbose) {
log_info(" ^routed already^\n");
}
continue;
}
used_pips.insert(io_pip_id);
}
log_info(" Net %s is routed.\n", net.name.c_str(ctx));
for (auto const pip : used_pips) {
ctx->bindPip(pip, &ctx->net_info(net.name), STRENGTH_LOCKED);
}
ctx->bindWire(net.clock_io_wire, &ctx->net_info(net.name), STRENGTH_LOCKED);
}
void GowinGlobalRouter::route_globals(Context *ctx)
{
log_info("Routing globals...\n");
for (auto const &net : nets) {
route_net(ctx, net);
}
}
// Allocate networks that will be routed through the global system.
// Mark their driver cells as global buffers to exclude them from the analysis.
void GowinGlobalRouter::mark_globals(Context *ctx)
{
log_info("Find global nets...\n");
std::vector<globalnet_t> clock_nets;
gather_clock_nets(ctx, clock_nets);
// XXX we need to use the list of indexes of clocks from the database
// use 6 clocks (XXX 3 for GW1NZ-1)
int max_clock = 3, cur_clock = -1;
for (auto &net : clock_nets) {
// XXX only IO clock for now
if (net.clock_io_wire == WireId()) {
log_info(" Non IO clock, skip %s.\n", net.name.c_str(ctx));
continue;
}
if (++cur_clock >= max_clock) {
log_info(" No more clock wires left, skip the remaining nets.\n");
break;
}
net.clock = cur_clock;
BelInfo &bi = ctx->bel_info(net.clock_io_bel);
bi.gb = true;
nets.emplace_back(net);
}
}
NEXTPNR_NAMESPACE_END

91
gowin/globals.h Normal file
View File

@ -0,0 +1,91 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 gatecat <gatecat@ds0.me>
* Copyright (C) 2022 YRabbit <rabbit@yrabbit.cyou>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef GOWIN_GLOBALS_H
#define GOWIN_GLOBALS_H
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
class GowinGlobalRouter
{
public:
GowinGlobalRouter() {}
private:
// wire -> clock#
dict<WireId, int> used_wires;
// ordered nets
struct globalnet_t
{
IdString name;
int clock_ports;
BelId clock_io_bel;
WireId clock_io_wire; // IO wire if there is one
int clock; // clock #
globalnet_t()
{
name = IdString();
clock_ports = 0;
clock_io_bel = BelId();
clock_io_wire = WireId();
clock = -1;
}
globalnet_t(IdString _name)
{
name = _name;
clock_ports = 0;
clock_io_bel = BelId();
clock_io_wire = WireId();
clock = -1;
}
// sort
bool operator<(const globalnet_t &other) const
{
if ((clock_io_wire != WireId()) ^ (other.clock_io_wire != WireId())) {
return !(clock_io_wire != WireId());
}
return clock_ports < other.clock_ports;
}
// search
bool operator==(const globalnet_t &other) const { return name == other.name; }
};
// discovered nets
std::vector<globalnet_t> nets;
bool is_clock_port(PortRef const &user);
std::pair<WireId, BelId> clock_io(Context *ctx, PortRef const &driver);
void gather_clock_nets(Context *ctx, std::vector<globalnet_t> &clock_nets);
IdString route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock, pool<IdString> &used_pips,
pool<IdString> &undo_wires);
void route_net(Context *ctx, globalnet_t const &net);
public:
void mark_globals(Context *ctx);
void route_globals(Context *ctx);
};
NEXTPNR_NAMESPACE_END
#endif // GOWIN_GLOBALS_H

View File

@ -51,6 +51,8 @@ po::options_description GowinCommandHandler::getArchOptions()
specific.add_options()("device", po::value<std::string>(), "device name"); specific.add_options()("device", po::value<std::string>(), "device name");
specific.add_options()("family", po::value<std::string>(), "family name"); specific.add_options()("family", po::value<std::string>(), "family name");
specific.add_options()("cst", po::value<std::string>(), "physical constraints file"); specific.add_options()("cst", po::value<std::string>(), "physical constraints file");
specific.add_options()("enable-globals", "separate routing of the clocks");
specific.add_options()("enable-auto-longwires", "automatic detection and routing of long wires");
return specific; return specific;
} }
@ -79,7 +81,19 @@ std::unique_ptr<Context> GowinCommandHandler::createContext(dict<std::string, Pr
chipArgs.family = buf; chipArgs.family = buf;
} }
chipArgs.partnumber = match[0]; chipArgs.partnumber = match[0];
return std::unique_ptr<Context>(new Context(chipArgs));
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
// routing options
// the default values will change in the future
ctx->settings[ctx->id("arch.enable-globals")] = 0;
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0;
if (vm.count("enable-globals")) {
ctx->settings[ctx->id("arch.enable-globals")] = 1;
}
if (vm.count("enable-auto-longwires")) {
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 1;
}
return ctx;
} }
void GowinCommandHandler::customAfterLoad(Context *ctx) void GowinCommandHandler::customAfterLoad(Context *ctx)

View File

@ -26,6 +26,8 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#include "globals.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
static void make_dummy_alu(Context *ctx, int alu_idx, CellInfo *ci, CellInfo *packed_head, static void make_dummy_alu(Context *ctx, int alu_idx, CellInfo *ci, CellInfo *packed_head,
@ -1098,6 +1100,7 @@ bool Arch::pack()
Context *ctx = getCtx(); Context *ctx = getCtx();
try { try {
log_break(); log_break();
pre_pack(ctx);
pack_constants(ctx); pack_constants(ctx);
pack_sram(ctx); pack_sram(ctx);
pack_gsr(ctx); pack_gsr(ctx);
@ -1108,6 +1111,7 @@ bool Arch::pack()
pack_alus(ctx); pack_alus(ctx);
pack_lut_lutffs(ctx); pack_lut_lutffs(ctx);
pack_nonlut_ffs(ctx); pack_nonlut_ffs(ctx);
post_pack(ctx);
ctx->settings[id_pack] = 1; ctx->settings[id_pack] = 1;
ctx->assignArchInfo(); ctx->assignArchInfo();
log_info("Checksum: 0x%08x\n", ctx->checksum()); log_info("Checksum: 0x%08x\n", ctx->checksum());