mirror of
https://github.com/YosysHQ/nextpnr.git
synced 2026-01-11 23:53:21 +00:00
gatemate: support multiple clock distribution strategies (#1574)
* gatemate: support multiple clock distribution strategies * error out on non supported cases * Implement full use strategy * Address review comments
This commit is contained in:
parent
17d42e41db
commit
36045543c7
@ -921,8 +921,10 @@ class HeAPPlacer
|
|||||||
y0 = std::max(y0, r.y0);
|
y0 = std::max(y0, r.y0);
|
||||||
x1 = std::min(x1, r.x1);
|
x1 = std::min(x1, r.x1);
|
||||||
y1 = std::min(y1, r.y1);
|
y1 = std::min(y1, r.y1);
|
||||||
if (x0 > x1) std::swap(x0, x1);
|
if (x0 > x1)
|
||||||
if (y0 > y1) std::swap(y0, y1);
|
std::swap(x0, x1);
|
||||||
|
if (y0 > y1)
|
||||||
|
std::swap(y0, y1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick a random X and Y location within our search radius / search box
|
// Pick a random X and Y location within our search radius / search box
|
||||||
|
|||||||
@ -125,6 +125,11 @@ CellInfo *GateMatePacker::create_cell_ptr(IdString type, IdString name)
|
|||||||
} else if (type.in(id_CPE_IBUF)) {
|
} else if (type.in(id_CPE_IBUF)) {
|
||||||
add_port(id_Y, PORT_OUT);
|
add_port(id_Y, PORT_OUT);
|
||||||
add_port(id_I, PORT_IN);
|
add_port(id_I, PORT_IN);
|
||||||
|
} else if (type.in(id_CPE_IOBUF)) {
|
||||||
|
add_port(id_Y, PORT_OUT);
|
||||||
|
add_port(id_T, PORT_IN);
|
||||||
|
add_port(id_A, PORT_IN);
|
||||||
|
add_port(id_IO, PORT_INOUT);
|
||||||
} else if (type.in(id_PLL)) {
|
} else if (type.in(id_PLL)) {
|
||||||
add_port(id_CLK_REF, PORT_IN);
|
add_port(id_CLK_REF, PORT_IN);
|
||||||
add_port(id_USR_CLK_REF, PORT_IN);
|
add_port(id_USR_CLK_REF, PORT_IN);
|
||||||
|
|||||||
@ -162,6 +162,7 @@ void GateMateImpl::init(Context *ctx)
|
|||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto &die : extra->dies) {
|
for (auto &die : extra->dies) {
|
||||||
IdString name(die.name);
|
IdString name(die.name);
|
||||||
|
index_to_die[index] = name;
|
||||||
die_to_index[name] = index++;
|
die_to_index[name] = index++;
|
||||||
ctx->createRectangularRegion(name, die.x1, die.y1, die.x2, die.y2);
|
ctx->createRectangularRegion(name, die.x1, die.y1, die.x2, die.y2);
|
||||||
if (die_name == name.c_str(ctx)) {
|
if (die_name == name.c_str(ctx)) {
|
||||||
|
|||||||
@ -30,6 +30,13 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
enum MultiDieStrategy
|
||||||
|
{
|
||||||
|
CLOCK_MIRROR,
|
||||||
|
REUSE_CLK1,
|
||||||
|
FULL_USE,
|
||||||
|
};
|
||||||
|
|
||||||
struct GateMateImpl : HimbaechelAPI
|
struct GateMateImpl : HimbaechelAPI
|
||||||
{
|
{
|
||||||
~GateMateImpl();
|
~GateMateImpl();
|
||||||
@ -91,9 +98,14 @@ struct GateMateImpl : HimbaechelAPI
|
|||||||
int fpga_mode;
|
int fpga_mode;
|
||||||
int timing_mode;
|
int timing_mode;
|
||||||
std::map<const NetInfo *, int> global_signals;
|
std::map<const NetInfo *, int> global_signals;
|
||||||
|
dict<std::pair<IdString, int>, NetInfo *> global_mapping;
|
||||||
|
dict<std::pair<IdString, int>, IdString> global_clk_mapping;
|
||||||
std::vector<CellInfo *> clkin;
|
std::vector<CellInfo *> clkin;
|
||||||
std::vector<CellInfo *> glbout;
|
std::vector<CellInfo *> glbout;
|
||||||
std::vector<CellInfo *> pll;
|
std::vector<CellInfo *> pll;
|
||||||
|
pool<IdString> ignore;
|
||||||
|
MultiDieStrategy strategy;
|
||||||
|
dict<int, IdString> index_to_die;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
||||||
|
|||||||
@ -397,6 +397,37 @@ void GateMatePacker::remove_double_constrained()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GateMatePacker::recursiveAddToRegion(CellInfo *root, IdString die)
|
||||||
|
{
|
||||||
|
if (root->region && root->region->name != die)
|
||||||
|
log_error("Trying to assign cell '%s' to multiple regions.\n", root->name.c_str(ctx));
|
||||||
|
ctx->constrainCellToRegion(root->name, die);
|
||||||
|
for (auto cell : root->constr_children) {
|
||||||
|
if (cell->region && cell->region->name != die)
|
||||||
|
log_error("Trying to assign cell '%s' to multiple regions.\n", cell->name.c_str(ctx));
|
||||||
|
ctx->constrainCellToRegion(cell->name, die);
|
||||||
|
recursiveAddToRegion(cell, die);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GateMatePacker::assign_clocks()
|
||||||
|
{
|
||||||
|
log_info("Assign cells based on clock..\n");
|
||||||
|
for (auto &glob : uarch->global_signals) {
|
||||||
|
const NetInfo *net = glob.first;
|
||||||
|
for (auto &user : net->users) {
|
||||||
|
IdString die = uarch->index_to_die[uarch->tile_extra_data(net->driver.cell->bel.tile)->die];
|
||||||
|
if (user.cell->region && user.cell->region->name != die)
|
||||||
|
log_error("Trying to assign cell '%s' to multiple regions.\n", user.cell->name.c_str(ctx));
|
||||||
|
ctx->constrainCellToRegion(user.cell->name, die);
|
||||||
|
if (user.cell->cluster != ClusterId()) {
|
||||||
|
CellInfo *root = ctx->getClusterRootCell(user.cell->cluster);
|
||||||
|
recursiveAddToRegion(root, die);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GateMateImpl::pack()
|
void GateMateImpl::pack()
|
||||||
{
|
{
|
||||||
const ArchArgs &args = ctx->args;
|
const ArchArgs &args = ctx->args;
|
||||||
@ -404,8 +435,34 @@ void GateMateImpl::pack()
|
|||||||
parse_ccf(args.options.at("ccf"));
|
parse_ccf(args.options.at("ccf"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forced_die != IdString())
|
if (args.options.count("multi")) {
|
||||||
|
std::string val = args.options.at("multi");
|
||||||
|
if (val == "mirror") {
|
||||||
|
strategy = MultiDieStrategy::CLOCK_MIRROR;
|
||||||
|
log_info("Multidie mode: CLOCK MIRROR\n");
|
||||||
|
} else if (val == "clk1") {
|
||||||
|
strategy = MultiDieStrategy::REUSE_CLK1;
|
||||||
|
log_info("Multidie mode: REUSE CLK1\n");
|
||||||
|
} else if (val == "full") {
|
||||||
|
strategy = MultiDieStrategy::FULL_USE;
|
||||||
|
log_info("Multidie mode: FULL USE\n");
|
||||||
|
} else {
|
||||||
|
log_error("Unknown value for 'multi' option. Allowed values are 'mirror', 'full' and 'clk1'.\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strategy = MultiDieStrategy::CLOCK_MIRROR;
|
||||||
|
if (dies != 1)
|
||||||
|
log_warning("Multi die clock placement strategy set to 'mirror'.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forced_die != IdString()) {
|
||||||
preferred_die = die_to_index[forced_die];
|
preferred_die = die_to_index[forced_die];
|
||||||
|
if (strategy == MultiDieStrategy::FULL_USE)
|
||||||
|
log_error("Not allowed to use forced die in FULL USE mode.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strategy == MultiDieStrategy::REUSE_CLK1 || strategy == MultiDieStrategy::FULL_USE)
|
||||||
|
preferred_die = 0;
|
||||||
|
|
||||||
GateMatePacker packer(ctx, this);
|
GateMatePacker packer(ctx, this);
|
||||||
packer.pack_constants();
|
packer.pack_constants();
|
||||||
@ -431,6 +488,9 @@ void GateMateImpl::pack()
|
|||||||
ctx->constrainCellToRegion(cell.second->name, forced_die);
|
ctx->constrainCellToRegion(cell.second->name, forced_die);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strategy == MultiDieStrategy::FULL_USE)
|
||||||
|
packer.assign_clocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GateMateImpl::repack()
|
void GateMateImpl::repack()
|
||||||
@ -438,7 +498,8 @@ void GateMateImpl::repack()
|
|||||||
GateMatePacker packer(ctx, this);
|
GateMatePacker packer(ctx, this);
|
||||||
packer.repack_ram();
|
packer.repack_ram();
|
||||||
packer.repack_cpe();
|
packer.repack_cpe();
|
||||||
packer.reassign_clocks();
|
if (strategy != MultiDieStrategy::FULL_USE)
|
||||||
|
packer.reassign_clocks();
|
||||||
packer.remove_clocking();
|
packer.remove_clocking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ struct GateMatePacker
|
|||||||
void pack_cpe();
|
void pack_cpe();
|
||||||
void pack_addf();
|
void pack_addf();
|
||||||
void pack_bufg();
|
void pack_bufg();
|
||||||
void sort_bufg();
|
void sort_bufg(unsigned max_num);
|
||||||
void insert_clocking();
|
void insert_clocking();
|
||||||
void pack_pll();
|
void pack_pll();
|
||||||
void pack_misc();
|
void pack_misc();
|
||||||
@ -71,6 +71,7 @@ struct GateMatePacker
|
|||||||
void repack_ram();
|
void repack_ram();
|
||||||
void reassign_clocks();
|
void reassign_clocks();
|
||||||
void copy_clocks();
|
void copy_clocks();
|
||||||
|
void assign_clocks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void rename_param(CellInfo *cell, IdString name, IdString new_name, int width);
|
void rename_param(CellInfo *cell, IdString name, IdString new_name, int width);
|
||||||
@ -88,6 +89,12 @@ struct GateMatePacker
|
|||||||
void move_connections(NetInfo *from_net, NetInfo *to_net);
|
void move_connections(NetInfo *from_net, NetInfo *to_net);
|
||||||
void remap_ram_half(CellInfo *half, CellInfo *cell, int num);
|
void remap_ram_half(CellInfo *half, CellInfo *cell, int num);
|
||||||
|
|
||||||
|
void strategy_mirror();
|
||||||
|
void strategy_clk1();
|
||||||
|
void strategy_full();
|
||||||
|
|
||||||
|
void recursiveAddToRegion(CellInfo *root, IdString die);
|
||||||
|
|
||||||
PllCfgRecord get_pll_settings(double f_ref, double f_core, int mode, int low_jitter, bool pdiv0_mux, bool feedback);
|
PllCfgRecord get_pll_settings(double f_ref, double f_core, int mode, int low_jitter, bool pdiv0_mux, bool feedback);
|
||||||
|
|
||||||
std::pair<CellInfo *, CellInfo *> move_ram_i(CellInfo *cell, IdString origPort, bool place = true,
|
std::pair<CellInfo *, CellInfo *> move_ram_i(CellInfo *cell, IdString origPort, bool place = true,
|
||||||
|
|||||||
@ -30,7 +30,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
|
|
||||||
inline bool is_bufg(const BaseCtx *ctx, const CellInfo *cell) { return cell->type.in(id_CC_BUFG); }
|
inline bool is_bufg(const BaseCtx *ctx, const CellInfo *cell) { return cell->type.in(id_CC_BUFG); }
|
||||||
|
|
||||||
void GateMatePacker::sort_bufg()
|
void GateMatePacker::sort_bufg(unsigned max_num)
|
||||||
{
|
{
|
||||||
struct ItemBufG
|
struct ItemBufG
|
||||||
{
|
{
|
||||||
@ -61,8 +61,8 @@ void GateMatePacker::sort_bufg()
|
|||||||
bufg.push_back(ItemBufG(&ci, o_net->users.entries()));
|
bufg.push_back(ItemBufG(&ci, o_net->users.entries()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufg.size() > 4) {
|
if (bufg.size() > max_num) {
|
||||||
log_warning("More than 4 BUFG used. Those with highest fan-out will be used.\n");
|
log_warning("More than %d BUFG used. Those with highest fan-out will be used.\n", max_num);
|
||||||
std::sort(bufg.begin(), bufg.end(), [](const ItemBufG &a, const ItemBufG &b) { return a.fan_out > b.fan_out; });
|
std::sort(bufg.begin(), bufg.end(), [](const ItemBufG &a, const ItemBufG &b) { return a.fan_out > b.fan_out; });
|
||||||
for (size_t i = 4; i < bufg.size(); i++) {
|
for (size_t i = 4; i < bufg.size(); i++) {
|
||||||
log_warning("Removing BUFG cell %s.\n", bufg.at(i).cell->name.c_str(ctx));
|
log_warning("Removing BUFG cell %s.\n", bufg.at(i).cell->name.c_str(ctx));
|
||||||
@ -92,7 +92,7 @@ static int glb_mux_mapping[] = {
|
|||||||
|
|
||||||
void GateMatePacker::pack_bufg()
|
void GateMatePacker::pack_bufg()
|
||||||
{
|
{
|
||||||
sort_bufg();
|
sort_bufg(uarch->strategy == MultiDieStrategy::FULL_USE ? 4 * uarch->dies : 4);
|
||||||
|
|
||||||
log_info("Packing BUFGs..\n");
|
log_info("Packing BUFGs..\n");
|
||||||
auto update_bufg_port = [&](std::vector<CellInfo *> &bufg, CellInfo *cell, int port_num, int pll_num) {
|
auto update_bufg_port = [&](std::vector<CellInfo *> &bufg, CellInfo *cell, int port_num, int pll_num) {
|
||||||
@ -113,7 +113,7 @@ void GateMatePacker::pack_bufg()
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned max_plls = 4; // * uarch->dies;
|
unsigned max_plls = 4 * uarch->dies;
|
||||||
// Index vector for permutation
|
// Index vector for permutation
|
||||||
std::vector<unsigned> indexes(max_plls);
|
std::vector<unsigned> indexes(max_plls);
|
||||||
for (unsigned i = 0; i < max_plls; ++i)
|
for (unsigned i = 0; i < max_plls; ++i)
|
||||||
@ -682,7 +682,117 @@ void GateMatePacker::copy_clocks()
|
|||||||
{
|
{
|
||||||
if (uarch->dies == 1)
|
if (uarch->dies == 1)
|
||||||
return;
|
return;
|
||||||
log_info("Copy clocks..\n");
|
switch (uarch->strategy) {
|
||||||
|
case MultiDieStrategy::REUSE_CLK1:
|
||||||
|
if (uarch->global_signals.size() > 1 || uarch->pll.size() > 1)
|
||||||
|
log_error("Unable to use REUSE CLK1 strategy when there is more than one clock/PLL.\n");
|
||||||
|
strategy_clk1();
|
||||||
|
break;
|
||||||
|
case MultiDieStrategy::CLOCK_MIRROR:
|
||||||
|
if (uarch->global_signals.size() > 4 || uarch->pll.size() > 4)
|
||||||
|
log_error("Unable to use MIRROR CLOCK strategy when there is more than 4 clocks/PLLs.\n");
|
||||||
|
strategy_mirror();
|
||||||
|
break;
|
||||||
|
case MultiDieStrategy::FULL_USE:
|
||||||
|
strategy_full();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GateMatePacker::strategy_full()
|
||||||
|
{
|
||||||
|
log_info("All resources for clock distribution..\n");
|
||||||
|
|
||||||
|
for (int new_die = 1; new_die < uarch->dies; new_die++) {
|
||||||
|
// Create appropriate GPIO and IOSEL cells
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
NetInfo *in_net = uarch->clkin[new_die]->getPort(ctx->idf("CLK%d", i));
|
||||||
|
if (in_net && in_net->driver.cell) {
|
||||||
|
CellInfo *iosel = in_net->driver.cell;
|
||||||
|
auto pad_info = uarch->bel_to_pad[iosel->bel];
|
||||||
|
Loc l = uarch->locations[std::make_pair(IdString(pad_info->package_pin), new_die)];
|
||||||
|
CellInfo *iosel_new = ctx->getBoundBelCell(ctx->getBelByLocation(l));
|
||||||
|
if (!iosel_new) {
|
||||||
|
iosel_new = create_cell_ptr(iosel->type, ctx->idf("%s$die%d", iosel->name.c_str(ctx), new_die));
|
||||||
|
iosel_new->params = iosel->params;
|
||||||
|
ctx->bindBel(ctx->getBelByLocation(l), iosel_new, PlaceStrength::STRENGTH_FIXED);
|
||||||
|
|
||||||
|
CellInfo *gpio = iosel->getPort(id_GPIO_IN)->driver.cell;
|
||||||
|
CellInfo *gpio_new =
|
||||||
|
create_cell_ptr(gpio->type, ctx->idf("%s$die%d", gpio->name.c_str(ctx), new_die));
|
||||||
|
gpio_new->params = gpio->params;
|
||||||
|
ctx->bindBel(ctx->getBelByLocation({l.x, l.y, 0}), gpio_new, PlaceStrength::STRENGTH_FIXED);
|
||||||
|
|
||||||
|
// Duplicate input connection
|
||||||
|
gpio_new->connectPort(id_I, gpio->getPort(id_I));
|
||||||
|
// Connect IOSEL and CPE_IBUF
|
||||||
|
gpio_new->connectPorts(id_Y, iosel_new, id_GPIO_IN);
|
||||||
|
}
|
||||||
|
uarch->clkin[new_die]->disconnectPort(ctx->idf("CLK%d", i));
|
||||||
|
if (iosel_new->getPort(id_IN1))
|
||||||
|
uarch->clkin[new_die]->connectPort(ctx->idf("CLK%d", i), iosel_new->getPort(id_IN1));
|
||||||
|
else
|
||||||
|
iosel_new->connectPorts(id_IN1, uarch->clkin[new_die], ctx->idf("CLK%d", i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GateMatePacker::strategy_clk1()
|
||||||
|
{
|
||||||
|
log_info("Reuse CLK1 for clock distribution..\n");
|
||||||
|
NetInfo *net = uarch->glbout[0]->getPort(id_GLB0);
|
||||||
|
NetInfo *new_clk1 = ctx->createNet(ctx->id("$clk1$pin"));
|
||||||
|
for (int new_die = 0; new_die < uarch->dies; new_die++) {
|
||||||
|
CellInfo *iosel = create_cell_ptr(id_IOSEL, ctx->idf("$iosel_clk1$die%d", new_die));
|
||||||
|
iosel->setParam(id_DELAY_IBF, Property(1, 16));
|
||||||
|
iosel->setParam(id_INPUT_ENABLE, Property(1, 1));
|
||||||
|
if (new_die == 0) {
|
||||||
|
// On die 0 it should be output as well
|
||||||
|
iosel->setParam(id_DELAY_OBF, Property(1, 16));
|
||||||
|
iosel->setParam(id_OE_ENABLE, Property(1, 1));
|
||||||
|
iosel->setParam(id_OUT_SIGNAL, Property(1, 1));
|
||||||
|
iosel->setParam(id_SLEW, Property(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
BelId bel = ctx->getBelByLocation(uarch->locations[std::make_pair(ctx->id("IO_SB_A7"), new_die)]);
|
||||||
|
ctx->bindBel(bel, iosel, PlaceStrength::STRENGTH_FIXED);
|
||||||
|
|
||||||
|
CellInfo *gpio = create_cell_ptr((new_die ? id_CPE_IBUF : id_CPE_IOBUF), ctx->idf("$clk1$die%d", new_die));
|
||||||
|
Loc loc = ctx->getBelLocation(bel);
|
||||||
|
ctx->bindBel(ctx->getBelByLocation({loc.x, loc.y, 0}), gpio, PlaceStrength::STRENGTH_FIXED);
|
||||||
|
|
||||||
|
uarch->clkin[new_die]->connectPort(id_CLK1, new_clk1);
|
||||||
|
uarch->clkin[new_die]->params[ctx->id("REF1")] = Property(1, 3);
|
||||||
|
uarch->glbout[new_die]->params[ctx->id("GLB1_EN")] = Property(Property::State::S1);
|
||||||
|
uarch->glbout[new_die]->params[ctx->id("GLB1_CFG")] = Property(0, 3);
|
||||||
|
uarch->clkin[new_die]->connectPorts(ctx->id("CLK_REF1"), uarch->glbout[new_die], ctx->id("CLK_REF_OUT1"));
|
||||||
|
|
||||||
|
gpio->connectPorts(id_Y, iosel, id_GPIO_IN);
|
||||||
|
|
||||||
|
if (new_die == 0) {
|
||||||
|
iosel->connectPort(id_OUT1, ctx->getNetByAlias(uarch->global_signals.begin()->first->name));
|
||||||
|
CellInfo *cpe = move_ram_o_fixed(iosel, id_OUT1, loc).first;
|
||||||
|
uarch->ignore.emplace(cpe->name);
|
||||||
|
|
||||||
|
iosel->connectPorts(id_GPIO_OUT, gpio, id_A);
|
||||||
|
iosel->connectPorts(id_GPIO_EN, gpio, id_T);
|
||||||
|
gpio->connectPort(id_IO, new_clk1);
|
||||||
|
} else {
|
||||||
|
gpio->connectPort(id_I, new_clk1);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetInfo *new_signal = ctx->createNet(ctx->idf("%s$die%d", net->name.c_str(ctx), new_die));
|
||||||
|
uarch->glbout[new_die]->connectPort(ctx->id("GLB1"), new_signal);
|
||||||
|
copy_constraint(net, new_signal);
|
||||||
|
uarch->global_mapping.emplace(std::make_pair(net->name, new_die), new_signal);
|
||||||
|
uarch->global_clk_mapping.emplace(std::make_pair(id_CLOCK1, new_die), id_CLOCK2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GateMatePacker::strategy_mirror()
|
||||||
|
{
|
||||||
|
log_info("Mirror clocks..\n");
|
||||||
|
|
||||||
// Save first CLKIN inputs
|
// Save first CLKIN inputs
|
||||||
std::vector<CellInfo *> clk_iosel(4, nullptr);
|
std::vector<CellInfo *> clk_iosel(4, nullptr);
|
||||||
@ -793,8 +903,52 @@ void GateMatePacker::copy_clocks()
|
|||||||
ctx->idf("CLK_REF_OUT%d", i));
|
ctx->idf("CLK_REF_OUT%d", i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
NetInfo *net = uarch->glbout[0]->getPort(ctx->idf("GLB%d", i));
|
||||||
|
if (net) {
|
||||||
|
if (new_die != 0) {
|
||||||
|
NetInfo *new_signal = ctx->createNet(ctx->idf("%s$die%d", net->name.c_str(ctx), new_die));
|
||||||
|
uarch->glbout[new_die]->connectPort(ctx->idf("GLB%d", i), new_signal);
|
||||||
|
copy_constraint(net, new_signal);
|
||||||
|
uarch->global_mapping.emplace(std::make_pair(net->name, new_die), new_signal);
|
||||||
|
} else {
|
||||||
|
uarch->global_mapping.emplace(std::make_pair(net->name, new_die), net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int clk_config_val(IdString name)
|
||||||
|
{
|
||||||
|
switch (name.index) {
|
||||||
|
case id_CLOCK1.index:
|
||||||
|
return 0b00100011;
|
||||||
|
case id_CLOCK2.index:
|
||||||
|
return 0b00110011;
|
||||||
|
case id_CLOCK3.index:
|
||||||
|
return 0b00000011;
|
||||||
|
case id_CLOCK4.index:
|
||||||
|
return 0b00010011;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioclk_config_val(IdString name)
|
||||||
|
{
|
||||||
|
switch (name.index) {
|
||||||
|
case id_CLOCK1.index:
|
||||||
|
return 0;
|
||||||
|
case id_CLOCK2.index:
|
||||||
|
return 1;
|
||||||
|
case id_CLOCK3.index:
|
||||||
|
return 2;
|
||||||
|
case id_CLOCK4.index:
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void GateMatePacker::reassign_clocks()
|
void GateMatePacker::reassign_clocks()
|
||||||
{
|
{
|
||||||
if (uarch->dies == 1)
|
if (uarch->dies == 1)
|
||||||
@ -805,22 +959,55 @@ void GateMatePacker::reassign_clocks()
|
|||||||
|
|
||||||
for (auto &glob : uarch->global_signals) {
|
for (auto &glob : uarch->global_signals) {
|
||||||
const NetInfo *net = glob.first;
|
const NetInfo *net = glob.first;
|
||||||
int index = glob.second;
|
|
||||||
int drv_die = uarch->tile_extra_data(net->driver.cell->bel.tile)->die;
|
|
||||||
auto users = net->users; // make a copy
|
auto users = net->users; // make a copy
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (auto &user : users) {
|
for (auto &user : users) {
|
||||||
int cell_die = uarch->tile_extra_data(user.cell->bel.tile)->die;
|
int cell_die = uarch->tile_extra_data(user.cell->bel.tile)->die;
|
||||||
if (cell_die != drv_die) {
|
if (uarch->global_mapping.count(std::make_pair(net->name, cell_die))) {
|
||||||
if (!new_bufg[cell_die][index]) {
|
NetInfo *new_net = uarch->global_mapping.at(std::make_pair(net->name, cell_die));
|
||||||
NetInfo *new_signal = ctx->createNet(ctx->idf("%s$die%d", net->name.c_str(ctx), cell_die));
|
if (uarch->ignore.count(user.cell->name))
|
||||||
new_bufg[cell_die][index] = new_signal;
|
continue;
|
||||||
uarch->glbout[cell_die]->connectPort(ctx->idf("GLB%d", index), new_signal);
|
|
||||||
copy_constraint(net, new_signal);
|
if (new_net == net)
|
||||||
}
|
continue;
|
||||||
|
|
||||||
user.cell->disconnectPort(user.port);
|
user.cell->disconnectPort(user.port);
|
||||||
user.cell->connectPort(user.port, new_bufg[cell_die][index]);
|
|
||||||
|
if (user.port.in(id_CLOCK1, id_CLOCK2, id_CLOCK3, id_CLOCK4) &&
|
||||||
|
uarch->global_clk_mapping.count(std::make_pair(user.port, cell_die))) {
|
||||||
|
IdString newPort = uarch->global_clk_mapping.at(std::make_pair(user.port, cell_die));
|
||||||
|
if (!user.cell->ports.count(newPort))
|
||||||
|
user.cell->addInput(newPort);
|
||||||
|
user.cell->connectPort(newPort, new_net);
|
||||||
|
|
||||||
|
if (user.cell->type == id_RAM) {
|
||||||
|
int a0_clk = int_or_default(user.cell->params, id_RAM_cfg_forward_a0_clk, 0);
|
||||||
|
int a1_clk = int_or_default(user.cell->params, id_RAM_cfg_forward_a1_clk, 0);
|
||||||
|
int b0_clk = int_or_default(user.cell->params, id_RAM_cfg_forward_b0_clk, 0);
|
||||||
|
int b1_clk = int_or_default(user.cell->params, id_RAM_cfg_forward_b1_clk, 0);
|
||||||
|
|
||||||
|
if (a0_clk == clk_config_val(user.port))
|
||||||
|
user.cell->params[id_RAM_cfg_forward_a0_clk] = Property(clk_config_val(newPort), 8);
|
||||||
|
if (a1_clk == clk_config_val(user.port))
|
||||||
|
user.cell->params[id_RAM_cfg_forward_a1_clk] = Property(clk_config_val(newPort), 8);
|
||||||
|
if (b0_clk == clk_config_val(user.port))
|
||||||
|
user.cell->params[id_RAM_cfg_forward_b0_clk] = Property(clk_config_val(newPort), 8);
|
||||||
|
if (b1_clk == clk_config_val(user.port))
|
||||||
|
user.cell->params[id_RAM_cfg_forward_b1_clk] = Property(clk_config_val(newPort), 8);
|
||||||
|
}
|
||||||
|
if (user.cell->type == id_IOSEL) {
|
||||||
|
int in_clk = int_or_default(user.cell->params, id_IN_CLOCK, 0);
|
||||||
|
int out_clk = int_or_default(user.cell->params, id_OUT_CLOCK, 0);
|
||||||
|
if (in_clk == ioclk_config_val(user.port))
|
||||||
|
user.cell->params[id_IN_CLOCK] = Property(ioclk_config_val(newPort), 2);
|
||||||
|
if (out_clk == ioclk_config_val(user.port))
|
||||||
|
user.cell->params[id_OUT_CLOCK] = Property(ioclk_config_val(newPort), 2);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
user.cell->connectPort(user.port, new_net);
|
||||||
count++;
|
count++;
|
||||||
|
} else {
|
||||||
|
log_error("Global signal '%s' is not available in die %d.\n", net->name.c_str(ctx), cell_die);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count)
|
if (count)
|
||||||
|
|||||||
@ -376,7 +376,14 @@ void GateMatePacker::pack_io_sel()
|
|||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
int index = uarch->global_signals[clk_net];
|
int index = uarch->global_signals[clk_net];
|
||||||
cell->movePortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
NetInfo *net = target->getPort(ctx->idf("CLOCK%d", index + 1));
|
||||||
|
if (net) {
|
||||||
|
if (net != clk_net)
|
||||||
|
log_error("Not able to connected different CLK signal to cell '%s'.\n",
|
||||||
|
cell->name.c_str(ctx));
|
||||||
|
} else {
|
||||||
|
cell->movePortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
||||||
|
}
|
||||||
target->params[id_OUT_CLOCK] = Property(index, 2);
|
target->params[id_OUT_CLOCK] = Property(index, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,7 +403,14 @@ void GateMatePacker::pack_io_sel()
|
|||||||
target->params[id_SEL_IN_CLOCK] = Property(Property::State::S1);
|
target->params[id_SEL_IN_CLOCK] = Property(Property::State::S1);
|
||||||
} else {
|
} else {
|
||||||
int index = uarch->global_signals[clk_net];
|
int index = uarch->global_signals[clk_net];
|
||||||
cell->movePortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
NetInfo *net = target->getPort(ctx->idf("CLOCK%d", index + 1));
|
||||||
|
if (net) {
|
||||||
|
if (net != clk_net)
|
||||||
|
log_error("Not able to connected different CLK signal to cell '%s'.\n",
|
||||||
|
cell->name.c_str(ctx));
|
||||||
|
} else {
|
||||||
|
cell->movePortTo(id_CLK, target, ctx->idf("CLOCK%d", index + 1));
|
||||||
|
}
|
||||||
target->params[id_IN_CLOCK] = Property(index, 2);
|
target->params[id_IN_CLOCK] = Property(index, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user