Getting rid of old IdString API users, Add ctx to many internal APIs
Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
parent
58dfdfa9c8
commit
79d1075345
@ -41,8 +41,9 @@ void replace_port(CellInfo *old_cell, IdString old_name, CellInfo *rep_cell,
|
||||
// true, then this cell must be the only load. If ignore_cell is set, that cell
|
||||
// is not considered
|
||||
template <typename F1>
|
||||
CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
|
||||
bool exclusive = false, CellInfo *exclude = nullptr)
|
||||
CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
|
||||
IdString port, bool exclusive = false,
|
||||
CellInfo *exclude = nullptr)
|
||||
{
|
||||
if (net == nullptr)
|
||||
return nullptr;
|
||||
@ -63,7 +64,8 @@ CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
|
||||
}
|
||||
}
|
||||
for (const auto &load : net->users) {
|
||||
if (load.cell != exclude && cell_pred(load.cell) && load.port == port) {
|
||||
if (load.cell != exclude && cell_pred(ctx, load.cell) &&
|
||||
load.port == port) {
|
||||
return load.cell;
|
||||
}
|
||||
}
|
||||
@ -73,11 +75,12 @@ CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
|
||||
// If a net is driven by a given port of a cell matching a predicate, return
|
||||
// that cell, otherwise nullptr
|
||||
template <typename F1>
|
||||
CellInfo *net_driven_by(const NetInfo *net, F1 cell_pred, IdString port)
|
||||
CellInfo *net_driven_by(const Context *ctx, const NetInfo *net, F1 cell_pred,
|
||||
IdString port)
|
||||
{
|
||||
if (net == nullptr)
|
||||
return nullptr;
|
||||
if (cell_pred(net->driver.cell) && net->driver.port == port) {
|
||||
if (cell_pred(ctx, net->driver.cell) && net->driver.port == port) {
|
||||
return net->driver.cell;
|
||||
} else {
|
||||
return nullptr;
|
||||
|
@ -108,7 +108,7 @@ static void place_initial(Context *ctx, CellInfo *cell, rnd_state &rnd)
|
||||
if (best_bel == BelId()) {
|
||||
if (iters == 0 || ripup_bel == BelId())
|
||||
log_error("failed to place cell '%s' of type '%s'\n",
|
||||
cell->name.c_str(), cell->type.c_str());
|
||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
--iters;
|
||||
ctx->unbindBel(ripup_target->bel);
|
||||
ripup_target->bel = BelId();
|
||||
@ -120,7 +120,7 @@ static void place_initial(Context *ctx, CellInfo *cell, rnd_state &rnd)
|
||||
ctx->bindBel(cell->bel, cell->name);
|
||||
|
||||
// Back annotate location
|
||||
cell->attrs["BEL"] = ctx->getBelName(cell->bel).str();
|
||||
cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx);
|
||||
cell = ripup_target;
|
||||
}
|
||||
}
|
||||
@ -294,22 +294,23 @@ void place_design_sa(Context *ctx, int seed)
|
||||
// Initial constraints placer
|
||||
for (auto cell_entry : ctx->cells) {
|
||||
CellInfo *cell = cell_entry.second;
|
||||
auto loc = cell->attrs.find("BEL");
|
||||
auto loc = cell->attrs.find(ctx->id("BEL"));
|
||||
if (loc != cell->attrs.end()) {
|
||||
std::string loc_name = loc->second;
|
||||
BelId bel = ctx->getBelByName(IdString(loc_name));
|
||||
BelId bel = ctx->getBelByName(ctx->id(loc_name));
|
||||
if (bel == BelId()) {
|
||||
log_error("No Bel named \'%s\' located for "
|
||||
"this chip (processing BEL attribute on \'%s\')\n",
|
||||
loc_name.c_str(), cell->name.c_str());
|
||||
loc_name.c_str(), cell->name.c_str(ctx));
|
||||
}
|
||||
|
||||
BelType bel_type = ctx->getBelType(bel);
|
||||
if (bel_type != ctx->belTypeFromId(cell->type)) {
|
||||
log_error("Bel \'%s\' of type \'%s\' does not match cell "
|
||||
"\'%s\' of type \'%s\'",
|
||||
loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(),
|
||||
cell->name.c_str(), cell->type.c_str());
|
||||
loc_name.c_str(),
|
||||
ctx->belTypeToId(bel_type).c_str(ctx),
|
||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
}
|
||||
|
||||
cell->bel = bel;
|
||||
@ -436,9 +437,9 @@ void place_design_sa(Context *ctx, int seed)
|
||||
std::string cell_text = "no cell";
|
||||
IdString cell = ctx->getBelCell(bel, false);
|
||||
if (cell != IdString())
|
||||
cell_text = std::string("cell '") + cell.str() + "'";
|
||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
||||
log_error("post-placement validity check failed for Bel '%s' (%s)",
|
||||
ctx->getBelName(bel).c_str(), cell_text.c_str());
|
||||
ctx->getBelName(bel).c_str(ctx), cell_text.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,27 +16,27 @@ bool check_all_nets_driven(Context *ctx)
|
||||
|
||||
if (debug)
|
||||
log_info(" Examining cell \'%s\', of type \'%s\'\n",
|
||||
cell->name.c_str(), cell->type.c_str());
|
||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||
for (auto port_entry : cell->ports) {
|
||||
PortInfo &port = port_entry.second;
|
||||
|
||||
if (debug)
|
||||
log_info(" Checking name of port \'%s\' "
|
||||
"against \'%s\'\n",
|
||||
port_entry.first.c_str(), port.name.c_str());
|
||||
port_entry.first.c_str(ctx), port.name.c_str(ctx));
|
||||
assert(port.name == port_entry.first);
|
||||
assert(port.name.size() > 0);
|
||||
assert(!port.name.empty());
|
||||
|
||||
if (port.net == NULL) {
|
||||
if (debug)
|
||||
log_warning(
|
||||
" Port \'%s\' in cell \'%s\' is unconnected\n",
|
||||
port.name.c_str(), cell->name.c_str());
|
||||
port.name.c_str(ctx), cell->name.c_str(ctx));
|
||||
} else {
|
||||
assert(port.net);
|
||||
if (debug)
|
||||
log_info(" Checking for a net named \'%s\'\n",
|
||||
port.net->name.c_str());
|
||||
port.net->name.c_str(ctx));
|
||||
assert(ctx->nets.count(port.net->name) > 0);
|
||||
}
|
||||
}
|
||||
@ -46,22 +46,23 @@ bool check_all_nets_driven(Context *ctx)
|
||||
NetInfo *net = net_entry.second;
|
||||
|
||||
assert(net->name == net_entry.first);
|
||||
if ((net->driver.cell != NULL) && (net->driver.cell->type != "GND") &&
|
||||
(net->driver.cell->type != "VCC")) {
|
||||
if ((net->driver.cell != NULL) &&
|
||||
(net->driver.cell->type != ctx->id("GND")) &&
|
||||
(net->driver.cell->type != ctx->id("VCC"))) {
|
||||
|
||||
if (debug)
|
||||
log_info(" Checking for a driver cell named \'%s\'\n",
|
||||
net->driver.cell->name.c_str());
|
||||
net->driver.cell->name.c_str(ctx));
|
||||
assert(ctx->cells.count(net->driver.cell->name) > 0);
|
||||
}
|
||||
|
||||
for (auto user : net->users) {
|
||||
if ((user.cell != NULL) && (user.cell->type != "GND") &&
|
||||
(user.cell->type != "VCC")) {
|
||||
if ((user.cell != NULL) && (user.cell->type != ctx->id("GND")) &&
|
||||
(user.cell->type != ctx->id("VCC"))) {
|
||||
|
||||
if (debug)
|
||||
log_info(" Checking for a user cell named \'%s\'\n",
|
||||
user.cell->name.c_str());
|
||||
user.cell->name.c_str(ctx));
|
||||
assert(ctx->cells.count(user.cell->name) > 0);
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,8 @@ static const NetInfo *get_net_or_empty(const CellInfo *cell,
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
||||
static bool logicCellsCompatible(const Context *ctx,
|
||||
const std::vector<const CellInfo *> &cells)
|
||||
{
|
||||
bool dffs_exist = false, dffs_neg = false;
|
||||
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
||||
@ -49,11 +50,11 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
||||
clk = get_net_or_empty(cell, "CLK");
|
||||
sr = get_net_or_empty(cell, "SR");
|
||||
|
||||
if (!is_global_net(cen) && cen != nullptr)
|
||||
if (!is_global_net(ctx, cen) && cen != nullptr)
|
||||
locals.insert(cen->name);
|
||||
if (!is_global_net(clk) && clk != nullptr)
|
||||
if (!is_global_net(ctx, clk) && clk != nullptr)
|
||||
locals.insert(clk->name);
|
||||
if (!is_global_net(sr) && sr != nullptr)
|
||||
if (!is_global_net(ctx, sr) && sr != nullptr)
|
||||
locals.insert(sr->name);
|
||||
|
||||
if (bool_or_default(cell->params, "NEG_CLK")) {
|
||||
@ -99,7 +100,7 @@ bool isBelLocationValid(Context *ctx, BelId bel)
|
||||
cells.push_back(ci_other);
|
||||
}
|
||||
}
|
||||
return logicCellsCompatible(cells);
|
||||
return logicCellsCompatible(ctx, cells);
|
||||
} else {
|
||||
IdString cellId = ctx->getBelCell(bel, false);
|
||||
if (cellId == IdString())
|
||||
@ -125,16 +126,16 @@ bool isValidBelForCell(Context *ctx, CellInfo *cell, BelId bel)
|
||||
}
|
||||
|
||||
cells.push_back(cell);
|
||||
return logicCellsCompatible(cells);
|
||||
return logicCellsCompatible(ctx, cells);
|
||||
} else if (cell->type == "SB_IO") {
|
||||
return ctx->getBelPackagePin(bel) != "";
|
||||
} else if (cell->type == "SB_GB") {
|
||||
bool is_reset = false, is_cen = false;
|
||||
assert(cell->ports.at("GLOBAL_BUFFER_OUTPUT").net != nullptr);
|
||||
for (auto user : cell->ports.at("GLOBAL_BUFFER_OUTPUT").net->users) {
|
||||
if (is_reset_port(user))
|
||||
if (is_reset_port(ctx, user))
|
||||
is_reset = true;
|
||||
if (is_enable_port(user))
|
||||
if (is_enable_port(ctx, user))
|
||||
is_cen = true;
|
||||
}
|
||||
IdString glb_net = ctx->getWireName(
|
||||
|
@ -73,8 +73,7 @@ void set_config(const TileInfoPOD &ti,
|
||||
}
|
||||
}
|
||||
|
||||
int get_param_or_def(const CellInfo *cell, const std::string ¶m,
|
||||
int defval = 0)
|
||||
int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0)
|
||||
{
|
||||
auto found = cell->params.find(param);
|
||||
if (found != cell->params.end())
|
||||
@ -83,7 +82,7 @@ int get_param_or_def(const CellInfo *cell, const std::string ¶m,
|
||||
return defval;
|
||||
}
|
||||
|
||||
std::string get_param_str_or_def(const CellInfo *cell, const std::string ¶m,
|
||||
std::string get_param_str_or_def(const CellInfo *cell, const IdString param,
|
||||
std::string defval = "")
|
||||
{
|
||||
auto found = cell->params.find(param);
|
||||
@ -153,20 +152,24 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
for (auto cell : ctx->cells) {
|
||||
BelId bel = cell.second->bel;
|
||||
if (bel == BelId()) {
|
||||
std::cout << "Found unplaced cell " << cell.first
|
||||
std::cout << "Found unplaced cell " << cell.first.str(ctx)
|
||||
<< " while generating bitstream!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
int x = beli.x, y = beli.y, z = beli.z;
|
||||
if (cell.second->type == "ICESTORM_LC") {
|
||||
if (cell.second->type == ctx->id("ICESTORM_LC")) {
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
|
||||
unsigned lut_init = get_param_or_def(cell.second, "LUT_INIT");
|
||||
bool neg_clk = get_param_or_def(cell.second, "NEG_CLK");
|
||||
bool dff_enable = get_param_or_def(cell.second, "DFF_ENABLE");
|
||||
bool async_sr = get_param_or_def(cell.second, "ASYNC_SR");
|
||||
bool set_noreset = get_param_or_def(cell.second, "SET_NORESET");
|
||||
bool carry_enable = get_param_or_def(cell.second, "CARRY_ENABLE");
|
||||
unsigned lut_init =
|
||||
get_param_or_def(cell.second, ctx->id("LUT_INIT"));
|
||||
bool neg_clk = get_param_or_def(cell.second, ctx->id("NEG_CLK"));
|
||||
bool dff_enable =
|
||||
get_param_or_def(cell.second, ctx->id("DFF_ENABLE"));
|
||||
bool async_sr = get_param_or_def(cell.second, ctx->id("ASYNC_SR"));
|
||||
bool set_noreset =
|
||||
get_param_or_def(cell.second, ctx->id("SET_NORESET"));
|
||||
bool carry_enable =
|
||||
get_param_or_def(cell.second, ctx->id("CARRY_ENABLE"));
|
||||
std::vector<bool> lc(20, false);
|
||||
// From arachne-pnr
|
||||
static std::vector<int> lut_perm = {
|
||||
@ -186,11 +189,13 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
lc.at(i), i);
|
||||
if (dff_enable)
|
||||
set_config(ti, config.at(y).at(x), "NegClk", neg_clk);
|
||||
} else if (cell.second->type == "SB_IO") {
|
||||
} else if (cell.second->type == ctx->id("SB_IO")) {
|
||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||
unsigned pin_type = get_param_or_def(cell.second, "PIN_TYPE");
|
||||
bool neg_trigger = get_param_or_def(cell.second, "NEG_TRIGGER");
|
||||
bool pullup = get_param_or_def(cell.second, "PULLUP");
|
||||
unsigned pin_type =
|
||||
get_param_or_def(cell.second, ctx->id("PIN_TYPE"));
|
||||
bool neg_trigger =
|
||||
get_param_or_def(cell.second, ctx->id("NEG_TRIGGER"));
|
||||
bool pullup = get_param_or_def(cell.second, ctx->id("PULLUP"));
|
||||
for (int i = 0; i < 6; i++) {
|
||||
bool val = (pin_type >> i) & 0x01;
|
||||
set_config(ti, config.at(y).at(x),
|
||||
@ -224,9 +229,9 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
set_config(ti, config.at(iey).at(iex),
|
||||
"IoCtrl.REN_" + std::to_string(iez), !pullup);
|
||||
}
|
||||
} else if (cell.second->type == "SB_GB") {
|
||||
} else if (cell.second->type == ctx->id("SB_GB")) {
|
||||
// no cell config bits
|
||||
} else if (cell.second->type == "ICESTORM_RAM") {
|
||||
} else if (cell.second->type == ctx->id("ICESTORM_RAM")) {
|
||||
const BelInfoPOD &beli = ci.bel_data[bel.index];
|
||||
int x = beli.x, y = beli.y;
|
||||
const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT];
|
||||
@ -236,10 +241,11 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp",
|
||||
true);
|
||||
}
|
||||
bool negclk_r = get_param_or_def(cell.second, "NEG_CLK_R");
|
||||
bool negclk_w = get_param_or_def(cell.second, "NEG_CLK_W");
|
||||
int write_mode = get_param_or_def(cell.second, "WRITE_MODE");
|
||||
int read_mode = get_param_or_def(cell.second, "READ_MODE");
|
||||
bool negclk_r = get_param_or_def(cell.second, ctx->id("NEG_CLK_R"));
|
||||
bool negclk_w = get_param_or_def(cell.second, ctx->id("NEG_CLK_W"));
|
||||
int write_mode =
|
||||
get_param_or_def(cell.second, ctx->id("WRITE_MODE"));
|
||||
int read_mode = get_param_or_def(cell.second, ctx->id("READ_MODE"));
|
||||
set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w);
|
||||
set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r);
|
||||
|
||||
@ -373,7 +379,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
// Write RAM init data
|
||||
for (auto cell : ctx->cells) {
|
||||
if (cell.second->bel != BelId()) {
|
||||
if (cell.second->type == "ICESTORM_RAM") {
|
||||
if (cell.second->type == ctx->id("ICESTORM_RAM")) {
|
||||
const BelInfoPOD &beli = ci.bel_data[cell.second->bel.index];
|
||||
int x = beli.x, y = beli.y;
|
||||
out << ".ram_data " << x << " " << y << std::endl;
|
||||
@ -381,7 +387,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
std::vector<bool> bits(256);
|
||||
std::string init = get_param_str_or_def(
|
||||
cell.second,
|
||||
std::string("INIT_") + get_hexdigit(w));
|
||||
ctx->id(std::string("INIT_") + get_hexdigit(w)));
|
||||
assert(init != "");
|
||||
for (int i = 0; i < init.size(); i++) {
|
||||
bool val = (init.at((init.size() - 1) - i) == '1');
|
||||
@ -404,7 +410,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
||||
for (auto wire : ctx->getWires()) {
|
||||
IdString net = ctx->getWireNet(wire, false);
|
||||
if (net != IdString())
|
||||
out << ".sym " << wire.index << " " << net << std::endl;
|
||||
out << ".sym " << wire.index << " " << net.str(ctx) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
static void add_port(CellInfo *cell, IdString name, PortType dir)
|
||||
static void add_port(const Context *ctx, CellInfo *cell, IdString name,
|
||||
PortType dir)
|
||||
{
|
||||
cell->ports[name] = PortInfo{name, nullptr, dir};
|
||||
}
|
||||
@ -48,72 +49,72 @@ CellInfo *create_ice_cell(Context *ctx, IdString type, IdString name)
|
||||
new_cell->params["SET_NORESET"] = "0";
|
||||
new_cell->params["ASYNC_SR"] = "0";
|
||||
|
||||
add_port(new_cell, "I0", PORT_IN);
|
||||
add_port(new_cell, "I1", PORT_IN);
|
||||
add_port(new_cell, "I2", PORT_IN);
|
||||
add_port(new_cell, "I3", PORT_IN);
|
||||
add_port(new_cell, "CIN", PORT_IN);
|
||||
add_port(ctx, new_cell, "I0", PORT_IN);
|
||||
add_port(ctx, new_cell, "I1", PORT_IN);
|
||||
add_port(ctx, new_cell, "I2", PORT_IN);
|
||||
add_port(ctx, new_cell, "I3", PORT_IN);
|
||||
add_port(ctx, new_cell, "CIN", PORT_IN);
|
||||
|
||||
add_port(new_cell, "CLK", PORT_IN);
|
||||
add_port(new_cell, "CEN", PORT_IN);
|
||||
add_port(new_cell, "SR", PORT_IN);
|
||||
add_port(ctx, new_cell, "CLK", PORT_IN);
|
||||
add_port(ctx, new_cell, "CEN", PORT_IN);
|
||||
add_port(ctx, new_cell, "SR", PORT_IN);
|
||||
|
||||
add_port(new_cell, "LO", PORT_OUT);
|
||||
add_port(new_cell, "O", PORT_OUT);
|
||||
add_port(new_cell, "OUT", PORT_OUT);
|
||||
add_port(ctx, new_cell, "LO", PORT_OUT);
|
||||
add_port(ctx, new_cell, "O", PORT_OUT);
|
||||
add_port(ctx, new_cell, "OUT", PORT_OUT);
|
||||
} else if (type == "SB_IO") {
|
||||
new_cell->params["PIN_TYPE"] = "0";
|
||||
new_cell->params["PULLUP"] = "0";
|
||||
new_cell->params["NEG_TRIGGER"] = "0";
|
||||
new_cell->params["IOSTANDARD"] = "SB_LVCMOS";
|
||||
|
||||
add_port(new_cell, "PACKAGE_PIN", PORT_INOUT);
|
||||
add_port(ctx, new_cell, "PACKAGE_PIN", PORT_INOUT);
|
||||
|
||||
add_port(new_cell, "LATCH_INPUT_VALUE", PORT_IN);
|
||||
add_port(new_cell, "CLOCK_ENABLE", PORT_IN);
|
||||
add_port(new_cell, "INPUT_CLK", PORT_IN);
|
||||
add_port(new_cell, "OUTPUT_CLK", PORT_IN);
|
||||
add_port(ctx, new_cell, "LATCH_INPUT_VALUE", PORT_IN);
|
||||
add_port(ctx, new_cell, "CLOCK_ENABLE", PORT_IN);
|
||||
add_port(ctx, new_cell, "INPUT_CLK", PORT_IN);
|
||||
add_port(ctx, new_cell, "OUTPUT_CLK", PORT_IN);
|
||||
|
||||
add_port(new_cell, "OUTPUT_ENABLE", PORT_IN);
|
||||
add_port(new_cell, "D_OUT_0", PORT_IN);
|
||||
add_port(new_cell, "D_OUT_1", PORT_IN);
|
||||
add_port(ctx, new_cell, "OUTPUT_ENABLE", PORT_IN);
|
||||
add_port(ctx, new_cell, "D_OUT_0", PORT_IN);
|
||||
add_port(ctx, new_cell, "D_OUT_1", PORT_IN);
|
||||
|
||||
add_port(new_cell, "D_IN_0", PORT_OUT);
|
||||
add_port(new_cell, "D_IN_1", PORT_OUT);
|
||||
add_port(ctx, new_cell, "D_IN_0", PORT_OUT);
|
||||
add_port(ctx, new_cell, "D_IN_1", PORT_OUT);
|
||||
} else if (type == "ICESTORM_RAM") {
|
||||
new_cell->params["NEG_CLK_W"] = "0";
|
||||
new_cell->params["NEG_CLK_R"] = "0";
|
||||
new_cell->params["WRITE_MODE"] = "0";
|
||||
new_cell->params["READ_MODE"] = "0";
|
||||
|
||||
add_port(new_cell, "RCLK", PORT_IN);
|
||||
add_port(new_cell, "RCLKE", PORT_IN);
|
||||
add_port(new_cell, "RE", PORT_IN);
|
||||
add_port(ctx, new_cell, "RCLK", PORT_IN);
|
||||
add_port(ctx, new_cell, "RCLKE", PORT_IN);
|
||||
add_port(ctx, new_cell, "RE", PORT_IN);
|
||||
|
||||
add_port(new_cell, "WCLK", PORT_IN);
|
||||
add_port(new_cell, "WCLKE", PORT_IN);
|
||||
add_port(new_cell, "WE", PORT_IN);
|
||||
add_port(ctx, new_cell, "WCLK", PORT_IN);
|
||||
add_port(ctx, new_cell, "WCLKE", PORT_IN);
|
||||
add_port(ctx, new_cell, "WE", PORT_IN);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
add_port(new_cell, "WDATA_" + std::to_string(i), PORT_IN);
|
||||
add_port(new_cell, "MASK_" + std::to_string(i), PORT_IN);
|
||||
add_port(new_cell, "RDATA_" + std::to_string(i), PORT_OUT);
|
||||
add_port(ctx, new_cell, "WDATA_" + std::to_string(i), PORT_IN);
|
||||
add_port(ctx, new_cell, "MASK_" + std::to_string(i), PORT_IN);
|
||||
add_port(ctx, new_cell, "RDATA_" + std::to_string(i), PORT_OUT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
add_port(new_cell, "RADDR_" + std::to_string(i), PORT_IN);
|
||||
add_port(new_cell, "WADDR_" + std::to_string(i), PORT_IN);
|
||||
add_port(ctx, new_cell, "RADDR_" + std::to_string(i), PORT_IN);
|
||||
add_port(ctx, new_cell, "WADDR_" + std::to_string(i), PORT_IN);
|
||||
}
|
||||
} else if (type == "SB_GB") {
|
||||
add_port(new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN);
|
||||
add_port(new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT);
|
||||
add_port(ctx, new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN);
|
||||
add_port(ctx, new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT);
|
||||
} else {
|
||||
log_error("unable to create iCE40 cell of type %s", type.c_str());
|
||||
}
|
||||
return new_cell;
|
||||
}
|
||||
|
||||
void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||
{
|
||||
lc->params["LUT_INIT"] = lut->params["LUT_INIT"];
|
||||
replace_port(lut, "I0", lc, "I0");
|
||||
@ -126,7 +127,8 @@ void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff)
|
||||
}
|
||||
}
|
||||
|
||||
void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc,
|
||||
bool pass_thru_lut)
|
||||
{
|
||||
lc->params["DFF_ENABLE"] = "1";
|
||||
std::string config = dff->type.str().substr(6);
|
||||
@ -176,7 +178,7 @@ void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut)
|
||||
replace_port(dff, "Q", lc, "O");
|
||||
}
|
||||
|
||||
void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
|
||||
void nxio_to_sb(const Context *ctx, CellInfo *nxio, CellInfo *sbio)
|
||||
{
|
||||
if (nxio->type == "$nextpnr_ibuf") {
|
||||
sbio->params["PIN_TYPE"] = "1";
|
||||
@ -192,44 +194,44 @@ void nxio_to_sb(CellInfo *nxio, CellInfo *sbio)
|
||||
}
|
||||
}
|
||||
|
||||
bool is_clock_port(const PortRef &port)
|
||||
bool is_clock_port(const Context *ctx, const PortRef &port)
|
||||
{
|
||||
if (port.cell == nullptr)
|
||||
return false;
|
||||
if (is_ff(port.cell))
|
||||
if (is_ff(ctx, port.cell))
|
||||
return port.port == "C";
|
||||
if (port.cell->type == "ICESTORM_LC")
|
||||
return port.port == "CLK";
|
||||
if (is_ram(port.cell) || port.cell->type == "ICESTORM_RAM")
|
||||
if (is_ram(ctx, port.cell) || port.cell->type == "ICESTORM_RAM")
|
||||
return port.port == "RCLK" || port.port == "WCLK";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_reset_port(const PortRef &port)
|
||||
bool is_reset_port(const Context *ctx, const PortRef &port)
|
||||
{
|
||||
if (port.cell == nullptr)
|
||||
return false;
|
||||
if (is_ff(port.cell))
|
||||
if (is_ff(ctx, port.cell))
|
||||
return port.port == "R" || port.port == "S";
|
||||
if (port.cell->type == "ICESTORM_LC")
|
||||
return port.port == "SR";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_enable_port(const PortRef &port)
|
||||
bool is_enable_port(const Context *ctx, const PortRef &port)
|
||||
{
|
||||
if (port.cell == nullptr)
|
||||
return false;
|
||||
if (is_ff(port.cell))
|
||||
if (is_ff(ctx, port.cell))
|
||||
return port.port == "E";
|
||||
if (port.cell->type == "ICESTORM_LC")
|
||||
return port.port == "CEN";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_global_net(const NetInfo *net)
|
||||
bool is_global_net(const Context *ctx, const NetInfo *net)
|
||||
{
|
||||
return bool(net_driven_by(net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
||||
return bool(net_driven_by(ctx, net, is_gbuf, "GLOBAL_BUFFER_OUTPUT"));
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
@ -31,61 +31,84 @@ CellInfo *create_ice_cell(Context *ctx, IdString type,
|
||||
IdString name = IdString());
|
||||
|
||||
// Return true if a cell is a LUT
|
||||
inline bool is_lut(const CellInfo *cell) { return cell->type == "SB_LUT4"; }
|
||||
inline bool is_lut(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_LUT4");
|
||||
}
|
||||
|
||||
// Return true if a cell is a flipflop
|
||||
inline bool is_ff(const CellInfo *cell)
|
||||
inline bool is_ff(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == "SB_DFF" || cell->type == "SB_DFFE" ||
|
||||
cell->type == "SB_DFFSR" || cell->type == "SB_DFFR" ||
|
||||
cell->type == "SB_DFFSS" || cell->type == "SB_DFFS" ||
|
||||
cell->type == "SB_DFFESR" || cell->type == "SB_DFFER" ||
|
||||
cell->type == "SB_DFFESS" || cell->type == "SB_DFFES" ||
|
||||
cell->type == "SB_DFFN" || cell->type == "SB_DFFNE" ||
|
||||
cell->type == "SB_DFFNSR" || cell->type == "SB_DFFNR" ||
|
||||
cell->type == "SB_DFFNSS" || cell->type == "SB_DFFNS" ||
|
||||
cell->type == "SB_DFFNESR" || cell->type == "SB_DFFNER" ||
|
||||
cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES";
|
||||
return cell->type == ctx->id("SB_DFF") ||
|
||||
cell->type == ctx->id("SB_DFFE") ||
|
||||
cell->type == ctx->id("SB_DFFSR") ||
|
||||
cell->type == ctx->id("SB_DFFR") ||
|
||||
cell->type == ctx->id("SB_DFFSS") ||
|
||||
cell->type == ctx->id("SB_DFFS") ||
|
||||
cell->type == ctx->id("SB_DFFESR") ||
|
||||
cell->type == ctx->id("SB_DFFER") ||
|
||||
cell->type == ctx->id("SB_DFFESS") ||
|
||||
cell->type == ctx->id("SB_DFFES") ||
|
||||
cell->type == ctx->id("SB_DFFN") ||
|
||||
cell->type == ctx->id("SB_DFFNE") ||
|
||||
cell->type == ctx->id("SB_DFFNSR") ||
|
||||
cell->type == ctx->id("SB_DFFNR") ||
|
||||
cell->type == ctx->id("SB_DFFNSS") ||
|
||||
cell->type == ctx->id("SB_DFFNS") ||
|
||||
cell->type == ctx->id("SB_DFFNESR") ||
|
||||
cell->type == ctx->id("SB_DFFNER") ||
|
||||
cell->type == ctx->id("SB_DFFNESS") ||
|
||||
cell->type == ctx->id("SB_DFFNES");
|
||||
}
|
||||
|
||||
// Return true if a cell is a SB_IO
|
||||
inline bool is_sb_io(const CellInfo *cell) { return cell->type == "SB_IO"; }
|
||||
inline bool is_sb_io(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_IO");
|
||||
}
|
||||
|
||||
// Return true if a cell is a global buffer
|
||||
inline bool is_gbuf(const CellInfo *cell) { return cell->type == "SB_GB"; }
|
||||
inline bool is_gbuf(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == ctx->id("SB_GB");
|
||||
}
|
||||
|
||||
// Return true if a cell is a RAM
|
||||
inline bool is_ram(const CellInfo *cell)
|
||||
inline bool is_ram(const Context *ctx, const CellInfo *cell)
|
||||
{
|
||||
return cell->type == "SB_RAM40_4K" || cell->type == "SB_RAM40_4KNR" ||
|
||||
cell->type == "SB_RAM40_4KNW" || cell->type == "SB_RAM40_4KNRNW";
|
||||
return cell->type == ctx->id("SB_RAM40_4K") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNR") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNW") ||
|
||||
cell->type == ctx->id("SB_RAM40_4KNRNW");
|
||||
}
|
||||
|
||||
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
|
||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||
// can be reconnected
|
||||
void lut_to_lc(CellInfo *lut, CellInfo *lc, bool no_dff = true);
|
||||
void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc,
|
||||
bool no_dff = true);
|
||||
|
||||
// Convert a SB_DFFx primitive to (part of) an ICESTORM_LC, setting parameters
|
||||
// and reconnecting signals as necessary. If pass_thru_lut is True, the LUT will
|
||||
// be configured as pass through and D connected to I0, otherwise D will be
|
||||
// ignored
|
||||
void dff_to_lc(CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false);
|
||||
void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc,
|
||||
bool pass_thru_lut = false);
|
||||
|
||||
// Convert a nextpnr IO buffer to a SB_IO
|
||||
void nxio_to_sb(CellInfo *nxio, CellInfo *sbio);
|
||||
void nxio_to_sb(const Context *ctx, CellInfo *nxio, CellInfo *sbio);
|
||||
|
||||
// Return true if a net is a global net
|
||||
bool is_global_net(const NetInfo *net);
|
||||
bool is_global_net(const Context *ctx, const NetInfo *net);
|
||||
|
||||
// Return true if a port is a clock port
|
||||
bool is_clock_port(const PortRef &port);
|
||||
bool is_clock_port(const Context *ctx, const PortRef &port);
|
||||
|
||||
// Return true if a port is a reset port
|
||||
bool is_reset_port(const PortRef &port);
|
||||
bool is_reset_port(const Context *ctx, const PortRef &port);
|
||||
|
||||
// Return true if a port is a clock enable port
|
||||
bool is_enable_port(const PortRef &port);
|
||||
bool is_enable_port(const Context *ctx, const PortRef &port);
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
|
@ -201,7 +201,7 @@ int main(int argc, char *argv[])
|
||||
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) << " -->\n";
|
||||
std::cout << "<!-- " << ctx.getBelName(bel).str(&ctx) << " -->\n";
|
||||
for (auto &el : ctx.getBelGraphics(bel))
|
||||
svg_dump_el(el);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
CellInfo *ci = cell.second;
|
||||
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(),
|
||||
ci->type.c_str());
|
||||
if (is_lut(ci)) {
|
||||
if (is_lut(ctx, ci)) {
|
||||
CellInfo *packed =
|
||||
create_ice_cell(ctx, "ICESTORM_LC", ci->name.str() + "_LC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
@ -50,7 +50,7 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
// See if we can pack into a DFF
|
||||
// TODO: LUT cascade
|
||||
NetInfo *o = ci->ports.at("O").net;
|
||||
CellInfo *dff = net_only_drives(o, is_ff, "D", true);
|
||||
CellInfo *dff = net_only_drives(ctx, o, is_ff, "D", true);
|
||||
auto lut_bel = ci->attrs.find("BEL");
|
||||
bool packed_dff = false;
|
||||
if (dff) {
|
||||
@ -60,8 +60,8 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
lut_bel->second != dff_bel->second) {
|
||||
// Locations don't match, can't pack
|
||||
} else {
|
||||
lut_to_lc(ci, packed, false);
|
||||
dff_to_lc(dff, packed, false);
|
||||
lut_to_lc(ctx, ci, packed, false);
|
||||
dff_to_lc(ctx, dff, packed, false);
|
||||
ctx->nets.erase(o->name);
|
||||
if (dff_bel != dff->attrs.end())
|
||||
packed->attrs["BEL"] = dff_bel->second;
|
||||
@ -72,7 +72,7 @@ static void pack_lut_lutffs(Context *ctx)
|
||||
}
|
||||
}
|
||||
if (!packed_dff) {
|
||||
lut_to_lc(ci, packed, true);
|
||||
lut_to_lc(ctx, ci, packed, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ static void pack_nonlut_ffs(Context *ctx)
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ff(ci)) {
|
||||
if (is_ff(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
|
||||
ci->name.str() + "_DFFLC");
|
||||
std::copy(ci->attrs.begin(), ci->attrs.end(),
|
||||
@ -103,7 +103,7 @@ static void pack_nonlut_ffs(Context *ctx)
|
||||
packed->name.c_str());
|
||||
packed_cells.insert(ci->name);
|
||||
new_cells.push_back(packed);
|
||||
dff_to_lc(ci, packed, true);
|
||||
dff_to_lc(ctx, ci, packed, true);
|
||||
}
|
||||
}
|
||||
for (auto pcell : packed_cells) {
|
||||
@ -124,7 +124,7 @@ static void pack_ram(Context *ctx)
|
||||
|
||||
for (auto cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (is_ram(ci)) {
|
||||
if (is_ram(ctx, ci)) {
|
||||
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM",
|
||||
ci->name.str() + "_RAM");
|
||||
packed_cells.insert(ci->name);
|
||||
@ -161,14 +161,16 @@ static void pack_ram(Context *ctx)
|
||||
}
|
||||
|
||||
// Merge a net into a constant net
|
||||
static void set_net_constant(NetInfo *orig, NetInfo *constnet, bool constval)
|
||||
static void set_net_constant(const Context *ctx, NetInfo *orig,
|
||||
NetInfo *constnet, bool constval)
|
||||
{
|
||||
orig->driver.cell = nullptr;
|
||||
for (auto user : orig->users) {
|
||||
if (user.cell != nullptr) {
|
||||
CellInfo *uc = user.cell;
|
||||
log_info("%s user %s\n", orig->name.c_str(), uc->name.c_str());
|
||||
if (is_lut(uc) && (user.port.str().at(0) == 'I') && !constval) {
|
||||
if (is_lut(ctx, uc) && (user.port.str().at(0) == 'I') &&
|
||||
!constval) {
|
||||
uc->ports[user.port].net = nullptr;
|
||||
} else {
|
||||
uc->ports[user.port].net = constnet;
|
||||
@ -203,13 +205,13 @@ static void pack_constants(Context *ctx)
|
||||
for (auto net : ctx->nets) {
|
||||
NetInfo *ni = net.second;
|
||||
if (ni->driver.cell != nullptr && ni->driver.cell->type == "GND") {
|
||||
set_net_constant(ni, gnd_net, false);
|
||||
set_net_constant(ctx, ni, gnd_net, false);
|
||||
ctx->cells[gnd_cell->name] = gnd_cell;
|
||||
ctx->nets[gnd_net->name] = gnd_net;
|
||||
dead_nets.push_back(net.first);
|
||||
} else if (ni->driver.cell != nullptr &&
|
||||
ni->driver.cell->type == "VCC") {
|
||||
set_net_constant(ni, vcc_net, true);
|
||||
set_net_constant(ctx, ni, vcc_net, true);
|
||||
ctx->cells[vcc_cell->name] = vcc_cell;
|
||||
ctx->nets[vcc_net->name] = vcc_net;
|
||||
dead_nets.push_back(net.first);
|
||||
@ -239,11 +241,11 @@ static void pack_io(Context *ctx)
|
||||
if (is_nextpnr_iob(ci)) {
|
||||
CellInfo *sb = nullptr;
|
||||
if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") {
|
||||
sb = net_only_drives(ci->ports.at("O").net, is_sb_io,
|
||||
sb = net_only_drives(ctx, ci->ports.at("O").net, is_sb_io,
|
||||
"PACKAGE_PIN", true, ci);
|
||||
|
||||
} else if (ci->type == "$nextpnr_obuf") {
|
||||
sb = net_only_drives(ci->ports.at("I").net, is_sb_io,
|
||||
sb = net_only_drives(ctx, ci->ports.at("I").net, is_sb_io,
|
||||
"PACKAGE_PIN", true, ci);
|
||||
}
|
||||
if (sb != nullptr) {
|
||||
@ -260,7 +262,7 @@ static void pack_io(Context *ctx)
|
||||
} else {
|
||||
// Create a SB_IO buffer
|
||||
sb = create_ice_cell(ctx, "SB_IO");
|
||||
nxio_to_sb(ci, sb);
|
||||
nxio_to_sb(ctx, ci, sb);
|
||||
new_cells.push_back(sb);
|
||||
}
|
||||
packed_cells.insert(ci->name);
|
||||
@ -297,8 +299,9 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset,
|
||||
gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
|
||||
std::vector<PortRef> keep_users;
|
||||
for (auto user : net->users) {
|
||||
if (is_clock_port(user) || (is_reset && is_reset_port(user)) ||
|
||||
(is_cen && is_enable_port(user))) {
|
||||
if (is_clock_port(ctx, user) ||
|
||||
(is_reset && is_reset_port(ctx, user)) ||
|
||||
(is_cen && is_enable_port(ctx, user))) {
|
||||
user.cell->ports[user.port].net = glbnet;
|
||||
glbnet->users.push_back(user);
|
||||
} else {
|
||||
@ -317,17 +320,17 @@ static void promote_globals(Context *ctx)
|
||||
std::unordered_map<IdString, int> clock_count, reset_count, cen_count;
|
||||
for (auto net : ctx->nets) {
|
||||
NetInfo *ni = net.second;
|
||||
if (ni->driver.cell != nullptr && !is_global_net(ni)) {
|
||||
if (ni->driver.cell != nullptr && !is_global_net(ctx, ni)) {
|
||||
clock_count[net.first] = 0;
|
||||
reset_count[net.first] = 0;
|
||||
cen_count[net.first] = 0;
|
||||
|
||||
for (auto user : ni->users) {
|
||||
if (is_clock_port(user))
|
||||
if (is_clock_port(ctx, user))
|
||||
clock_count[net.first]++;
|
||||
if (is_reset_port(user))
|
||||
if (is_reset_port(ctx, user))
|
||||
reset_count[net.first]++;
|
||||
if (is_enable_port(user))
|
||||
if (is_enable_port(ctx, user))
|
||||
cen_count[net.first]++;
|
||||
}
|
||||
}
|
||||
@ -335,7 +338,7 @@ static void promote_globals(Context *ctx)
|
||||
int prom_globals = 0, prom_resets = 0, prom_cens = 0;
|
||||
int gbs_available = 8;
|
||||
for (auto cell : ctx->cells)
|
||||
if (is_gbuf(cell.second))
|
||||
if (is_gbuf(ctx, cell.second))
|
||||
--gbs_available;
|
||||
while (prom_globals < gbs_available) {
|
||||
auto global_clock =
|
||||
|
Loading…
Reference in New Issue
Block a user