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:
Clifford Wolf 2018-06-18 17:08:35 +02:00
parent 58dfdfa9c8
commit 79d1075345
9 changed files with 191 additions and 151 deletions

View File

@ -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 // true, then this cell must be the only load. If ignore_cell is set, that cell
// is not considered // is not considered
template <typename F1> template <typename F1>
CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port, CellInfo *net_only_drives(const Context *ctx, NetInfo *net, F1 cell_pred,
bool exclusive = false, CellInfo *exclude = nullptr) IdString port, bool exclusive = false,
CellInfo *exclude = nullptr)
{ {
if (net == nullptr) if (net == nullptr)
return nullptr; return nullptr;
@ -63,7 +64,8 @@ CellInfo *net_only_drives(NetInfo *net, F1 cell_pred, IdString port,
} }
} }
for (const auto &load : net->users) { 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; 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 // If a net is driven by a given port of a cell matching a predicate, return
// that cell, otherwise nullptr // that cell, otherwise nullptr
template <typename F1> 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) if (net == nullptr)
return 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; return net->driver.cell;
} else { } else {
return nullptr; return nullptr;

View File

@ -108,7 +108,7 @@ static void place_initial(Context *ctx, CellInfo *cell, rnd_state &rnd)
if (best_bel == BelId()) { if (best_bel == BelId()) {
if (iters == 0 || ripup_bel == BelId()) if (iters == 0 || ripup_bel == BelId())
log_error("failed to place cell '%s' of type '%s'\n", 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; --iters;
ctx->unbindBel(ripup_target->bel); ctx->unbindBel(ripup_target->bel);
ripup_target->bel = BelId(); 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); ctx->bindBel(cell->bel, cell->name);
// Back annotate location // 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; cell = ripup_target;
} }
} }
@ -294,22 +294,23 @@ void place_design_sa(Context *ctx, int seed)
// Initial constraints placer // Initial constraints placer
for (auto cell_entry : ctx->cells) { for (auto cell_entry : ctx->cells) {
CellInfo *cell = cell_entry.second; CellInfo *cell = cell_entry.second;
auto loc = cell->attrs.find("BEL"); auto loc = cell->attrs.find(ctx->id("BEL"));
if (loc != cell->attrs.end()) { if (loc != cell->attrs.end()) {
std::string loc_name = loc->second; std::string loc_name = loc->second;
BelId bel = ctx->getBelByName(IdString(loc_name)); BelId bel = ctx->getBelByName(ctx->id(loc_name));
if (bel == BelId()) { if (bel == BelId()) {
log_error("No Bel named \'%s\' located for " log_error("No Bel named \'%s\' located for "
"this chip (processing BEL attribute on \'%s\')\n", "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); BelType bel_type = ctx->getBelType(bel);
if (bel_type != ctx->belTypeFromId(cell->type)) { if (bel_type != ctx->belTypeFromId(cell->type)) {
log_error("Bel \'%s\' of type \'%s\' does not match cell " log_error("Bel \'%s\' of type \'%s\' does not match cell "
"\'%s\' of type \'%s\'", "\'%s\' of type \'%s\'",
loc_name.c_str(), ctx->belTypeToId(bel_type).c_str(), loc_name.c_str(),
cell->name.c_str(), cell->type.c_str()); ctx->belTypeToId(bel_type).c_str(ctx),
cell->name.c_str(ctx), cell->type.c_str(ctx));
} }
cell->bel = bel; cell->bel = bel;
@ -436,9 +437,9 @@ void place_design_sa(Context *ctx, int seed)
std::string cell_text = "no cell"; std::string cell_text = "no cell";
IdString cell = ctx->getBelCell(bel, false); IdString cell = ctx->getBelCell(bel, false);
if (cell != IdString()) 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)", 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());
} }
} }
} }

View File

@ -16,27 +16,27 @@ bool check_all_nets_driven(Context *ctx)
if (debug) if (debug)
log_info(" Examining cell \'%s\', of type \'%s\'\n", 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) { for (auto port_entry : cell->ports) {
PortInfo &port = port_entry.second; PortInfo &port = port_entry.second;
if (debug) if (debug)
log_info(" Checking name of port \'%s\' " log_info(" Checking name of port \'%s\' "
"against \'%s\'\n", "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 == port_entry.first);
assert(port.name.size() > 0); assert(!port.name.empty());
if (port.net == NULL) { if (port.net == NULL) {
if (debug) if (debug)
log_warning( log_warning(
" Port \'%s\' in cell \'%s\' is unconnected\n", " 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 { } else {
assert(port.net); assert(port.net);
if (debug) if (debug)
log_info(" Checking for a net named \'%s\'\n", 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); assert(ctx->nets.count(port.net->name) > 0);
} }
} }
@ -46,22 +46,23 @@ bool check_all_nets_driven(Context *ctx)
NetInfo *net = net_entry.second; NetInfo *net = net_entry.second;
assert(net->name == net_entry.first); assert(net->name == net_entry.first);
if ((net->driver.cell != NULL) && (net->driver.cell->type != "GND") && if ((net->driver.cell != NULL) &&
(net->driver.cell->type != "VCC")) { (net->driver.cell->type != ctx->id("GND")) &&
(net->driver.cell->type != ctx->id("VCC"))) {
if (debug) if (debug)
log_info(" Checking for a driver cell named \'%s\'\n", 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); assert(ctx->cells.count(net->driver.cell->name) > 0);
} }
for (auto user : net->users) { for (auto user : net->users) {
if ((user.cell != NULL) && (user.cell->type != "GND") && if ((user.cell != NULL) && (user.cell->type != ctx->id("GND")) &&
(user.cell->type != "VCC")) { (user.cell->type != ctx->id("VCC"))) {
if (debug) if (debug)
log_info(" Checking for a user cell named \'%s\'\n", 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); assert(ctx->cells.count(user.cell->name) > 0);
} }
} }

View File

@ -34,7 +34,8 @@ static const NetInfo *get_net_or_empty(const CellInfo *cell,
return nullptr; 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; bool dffs_exist = false, dffs_neg = false;
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; 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"); clk = get_net_or_empty(cell, "CLK");
sr = get_net_or_empty(cell, "SR"); 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); locals.insert(cen->name);
if (!is_global_net(clk) && clk != nullptr) if (!is_global_net(ctx, clk) && clk != nullptr)
locals.insert(clk->name); locals.insert(clk->name);
if (!is_global_net(sr) && sr != nullptr) if (!is_global_net(ctx, sr) && sr != nullptr)
locals.insert(sr->name); locals.insert(sr->name);
if (bool_or_default(cell->params, "NEG_CLK")) { if (bool_or_default(cell->params, "NEG_CLK")) {
@ -99,7 +100,7 @@ bool isBelLocationValid(Context *ctx, BelId bel)
cells.push_back(ci_other); cells.push_back(ci_other);
} }
} }
return logicCellsCompatible(cells); return logicCellsCompatible(ctx, cells);
} else { } else {
IdString cellId = ctx->getBelCell(bel, false); IdString cellId = ctx->getBelCell(bel, false);
if (cellId == IdString()) if (cellId == IdString())
@ -125,16 +126,16 @@ bool isValidBelForCell(Context *ctx, CellInfo *cell, BelId bel)
} }
cells.push_back(cell); cells.push_back(cell);
return logicCellsCompatible(cells); return logicCellsCompatible(ctx, cells);
} else if (cell->type == "SB_IO") { } else if (cell->type == "SB_IO") {
return ctx->getBelPackagePin(bel) != ""; return ctx->getBelPackagePin(bel) != "";
} else if (cell->type == "SB_GB") { } else if (cell->type == "SB_GB") {
bool is_reset = false, is_cen = false; bool is_reset = false, is_cen = false;
assert(cell->ports.at("GLOBAL_BUFFER_OUTPUT").net != nullptr); assert(cell->ports.at("GLOBAL_BUFFER_OUTPUT").net != nullptr);
for (auto user : cell->ports.at("GLOBAL_BUFFER_OUTPUT").net->users) { 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; is_reset = true;
if (is_enable_port(user)) if (is_enable_port(ctx, user))
is_cen = true; is_cen = true;
} }
IdString glb_net = ctx->getWireName( IdString glb_net = ctx->getWireName(

View File

@ -73,8 +73,7 @@ void set_config(const TileInfoPOD &ti,
} }
} }
int get_param_or_def(const CellInfo *cell, const std::string &param, int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0)
int defval = 0)
{ {
auto found = cell->params.find(param); auto found = cell->params.find(param);
if (found != cell->params.end()) if (found != cell->params.end())
@ -83,7 +82,7 @@ int get_param_or_def(const CellInfo *cell, const std::string &param,
return defval; return defval;
} }
std::string get_param_str_or_def(const CellInfo *cell, const std::string &param, std::string get_param_str_or_def(const CellInfo *cell, const IdString param,
std::string defval = "") std::string defval = "")
{ {
auto found = cell->params.find(param); auto found = cell->params.find(param);
@ -153,20 +152,24 @@ void write_asc(const Context *ctx, std::ostream &out)
for (auto cell : ctx->cells) { for (auto cell : ctx->cells) {
BelId bel = cell.second->bel; BelId bel = cell.second->bel;
if (bel == BelId()) { if (bel == BelId()) {
std::cout << "Found unplaced cell " << cell.first std::cout << "Found unplaced cell " << cell.first.str(ctx)
<< " while generating bitstream!" << std::endl; << " while generating bitstream!" << std::endl;
continue; continue;
} }
const BelInfoPOD &beli = ci.bel_data[bel.index]; const BelInfoPOD &beli = ci.bel_data[bel.index];
int x = beli.x, y = beli.y, z = beli.z; 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]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC];
unsigned lut_init = get_param_or_def(cell.second, "LUT_INIT"); unsigned lut_init =
bool neg_clk = get_param_or_def(cell.second, "NEG_CLK"); get_param_or_def(cell.second, ctx->id("LUT_INIT"));
bool dff_enable = get_param_or_def(cell.second, "DFF_ENABLE"); bool neg_clk = get_param_or_def(cell.second, ctx->id("NEG_CLK"));
bool async_sr = get_param_or_def(cell.second, "ASYNC_SR"); bool dff_enable =
bool set_noreset = get_param_or_def(cell.second, "SET_NORESET"); get_param_or_def(cell.second, ctx->id("DFF_ENABLE"));
bool carry_enable = get_param_or_def(cell.second, "CARRY_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); std::vector<bool> lc(20, false);
// From arachne-pnr // From arachne-pnr
static std::vector<int> lut_perm = { static std::vector<int> lut_perm = {
@ -186,11 +189,13 @@ void write_asc(const Context *ctx, std::ostream &out)
lc.at(i), i); lc.at(i), i);
if (dff_enable) if (dff_enable)
set_config(ti, config.at(y).at(x), "NegClk", neg_clk); 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]; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
unsigned pin_type = get_param_or_def(cell.second, "PIN_TYPE"); unsigned pin_type =
bool neg_trigger = get_param_or_def(cell.second, "NEG_TRIGGER"); get_param_or_def(cell.second, ctx->id("PIN_TYPE"));
bool pullup = get_param_or_def(cell.second, "PULLUP"); 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++) { for (int i = 0; i < 6; i++) {
bool val = (pin_type >> i) & 0x01; bool val = (pin_type >> i) & 0x01;
set_config(ti, config.at(y).at(x), 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), set_config(ti, config.at(iey).at(iex),
"IoCtrl.REN_" + std::to_string(iez), !pullup); "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 // 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]; const BelInfoPOD &beli = ci.bel_data[bel.index];
int x = beli.x, y = beli.y; int x = beli.x, y = beli.y;
const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT]; 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", set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp",
true); true);
} }
bool negclk_r = get_param_or_def(cell.second, "NEG_CLK_R"); bool negclk_r = get_param_or_def(cell.second, ctx->id("NEG_CLK_R"));
bool negclk_w = get_param_or_def(cell.second, "NEG_CLK_W"); bool negclk_w = get_param_or_def(cell.second, ctx->id("NEG_CLK_W"));
int write_mode = get_param_or_def(cell.second, "WRITE_MODE"); int write_mode =
int read_mode = get_param_or_def(cell.second, "READ_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_ramb, config.at(y).at(x), "NegClk", negclk_w);
set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r); 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 // Write RAM init data
for (auto cell : ctx->cells) { for (auto cell : ctx->cells) {
if (cell.second->bel != BelId()) { 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]; const BelInfoPOD &beli = ci.bel_data[cell.second->bel.index];
int x = beli.x, y = beli.y; int x = beli.x, y = beli.y;
out << ".ram_data " << x << " " << y << std::endl; 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::vector<bool> bits(256);
std::string init = get_param_str_or_def( std::string init = get_param_str_or_def(
cell.second, cell.second,
std::string("INIT_") + get_hexdigit(w)); ctx->id(std::string("INIT_") + get_hexdigit(w)));
assert(init != ""); assert(init != "");
for (int i = 0; i < init.size(); i++) { for (int i = 0; i < init.size(); i++) {
bool val = (init.at((init.size() - 1) - i) == '1'); 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()) { for (auto wire : ctx->getWires()) {
IdString net = ctx->getWireNet(wire, false); IdString net = ctx->getWireNet(wire, false);
if (net != IdString()) if (net != IdString())
out << ".sym " << wire.index << " " << net << std::endl; out << ".sym " << wire.index << " " << net.str(ctx) << std::endl;
} }
} }

View File

@ -24,7 +24,8 @@
NEXTPNR_NAMESPACE_BEGIN 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}; 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["SET_NORESET"] = "0";
new_cell->params["ASYNC_SR"] = "0"; new_cell->params["ASYNC_SR"] = "0";
add_port(new_cell, "I0", PORT_IN); add_port(ctx, new_cell, "I0", PORT_IN);
add_port(new_cell, "I1", PORT_IN); add_port(ctx, new_cell, "I1", PORT_IN);
add_port(new_cell, "I2", PORT_IN); add_port(ctx, new_cell, "I2", PORT_IN);
add_port(new_cell, "I3", PORT_IN); add_port(ctx, new_cell, "I3", PORT_IN);
add_port(new_cell, "CIN", PORT_IN); add_port(ctx, new_cell, "CIN", PORT_IN);
add_port(new_cell, "CLK", PORT_IN); add_port(ctx, new_cell, "CLK", PORT_IN);
add_port(new_cell, "CEN", PORT_IN); add_port(ctx, new_cell, "CEN", PORT_IN);
add_port(new_cell, "SR", PORT_IN); add_port(ctx, new_cell, "SR", PORT_IN);
add_port(new_cell, "LO", PORT_OUT); add_port(ctx, new_cell, "LO", PORT_OUT);
add_port(new_cell, "O", PORT_OUT); add_port(ctx, new_cell, "O", PORT_OUT);
add_port(new_cell, "OUT", PORT_OUT); add_port(ctx, new_cell, "OUT", PORT_OUT);
} else if (type == "SB_IO") { } else if (type == "SB_IO") {
new_cell->params["PIN_TYPE"] = "0"; new_cell->params["PIN_TYPE"] = "0";
new_cell->params["PULLUP"] = "0"; new_cell->params["PULLUP"] = "0";
new_cell->params["NEG_TRIGGER"] = "0"; new_cell->params["NEG_TRIGGER"] = "0";
new_cell->params["IOSTANDARD"] = "SB_LVCMOS"; 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(ctx, new_cell, "LATCH_INPUT_VALUE", PORT_IN);
add_port(new_cell, "CLOCK_ENABLE", PORT_IN); add_port(ctx, new_cell, "CLOCK_ENABLE", PORT_IN);
add_port(new_cell, "INPUT_CLK", PORT_IN); add_port(ctx, new_cell, "INPUT_CLK", PORT_IN);
add_port(new_cell, "OUTPUT_CLK", PORT_IN); add_port(ctx, new_cell, "OUTPUT_CLK", PORT_IN);
add_port(new_cell, "OUTPUT_ENABLE", PORT_IN); add_port(ctx, new_cell, "OUTPUT_ENABLE", PORT_IN);
add_port(new_cell, "D_OUT_0", PORT_IN); add_port(ctx, new_cell, "D_OUT_0", PORT_IN);
add_port(new_cell, "D_OUT_1", PORT_IN); add_port(ctx, new_cell, "D_OUT_1", PORT_IN);
add_port(new_cell, "D_IN_0", PORT_OUT); add_port(ctx, new_cell, "D_IN_0", PORT_OUT);
add_port(new_cell, "D_IN_1", PORT_OUT); add_port(ctx, new_cell, "D_IN_1", PORT_OUT);
} else if (type == "ICESTORM_RAM") { } else if (type == "ICESTORM_RAM") {
new_cell->params["NEG_CLK_W"] = "0"; new_cell->params["NEG_CLK_W"] = "0";
new_cell->params["NEG_CLK_R"] = "0"; new_cell->params["NEG_CLK_R"] = "0";
new_cell->params["WRITE_MODE"] = "0"; new_cell->params["WRITE_MODE"] = "0";
new_cell->params["READ_MODE"] = "0"; new_cell->params["READ_MODE"] = "0";
add_port(new_cell, "RCLK", PORT_IN); add_port(ctx, new_cell, "RCLK", PORT_IN);
add_port(new_cell, "RCLKE", PORT_IN); add_port(ctx, new_cell, "RCLKE", PORT_IN);
add_port(new_cell, "RE", PORT_IN); add_port(ctx, new_cell, "RE", PORT_IN);
add_port(new_cell, "WCLK", PORT_IN); add_port(ctx, new_cell, "WCLK", PORT_IN);
add_port(new_cell, "WCLKE", PORT_IN); add_port(ctx, new_cell, "WCLKE", PORT_IN);
add_port(new_cell, "WE", PORT_IN); add_port(ctx, new_cell, "WE", PORT_IN);
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
add_port(new_cell, "WDATA_" + std::to_string(i), PORT_IN); add_port(ctx, new_cell, "WDATA_" + std::to_string(i), PORT_IN);
add_port(new_cell, "MASK_" + std::to_string(i), PORT_IN); add_port(ctx, 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, "RDATA_" + std::to_string(i), PORT_OUT);
} }
for (int i = 0; i < 11; i++) { for (int i = 0; i < 11; i++) {
add_port(new_cell, "RADDR_" + std::to_string(i), PORT_IN); add_port(ctx, 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, "WADDR_" + std::to_string(i), PORT_IN);
} }
} else if (type == "SB_GB") { } else if (type == "SB_GB") {
add_port(new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN); add_port(ctx, new_cell, "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN);
add_port(new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT); add_port(ctx, new_cell, "GLOBAL_BUFFER_OUTPUT", PORT_OUT);
} else { } else {
log_error("unable to create iCE40 cell of type %s", type.c_str()); log_error("unable to create iCE40 cell of type %s", type.c_str());
} }
return new_cell; 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"]; lc->params["LUT_INIT"] = lut->params["LUT_INIT"];
replace_port(lut, "I0", lc, "I0"); 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"; lc->params["DFF_ENABLE"] = "1";
std::string config = dff->type.str().substr(6); 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"); 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") { if (nxio->type == "$nextpnr_ibuf") {
sbio->params["PIN_TYPE"] = "1"; 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) if (port.cell == nullptr)
return false; return false;
if (is_ff(port.cell)) if (is_ff(ctx, port.cell))
return port.port == "C"; return port.port == "C";
if (port.cell->type == "ICESTORM_LC") if (port.cell->type == "ICESTORM_LC")
return port.port == "CLK"; 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 port.port == "RCLK" || port.port == "WCLK";
return false; return false;
} }
bool is_reset_port(const PortRef &port) bool is_reset_port(const Context *ctx, const PortRef &port)
{ {
if (port.cell == nullptr) if (port.cell == nullptr)
return false; return false;
if (is_ff(port.cell)) if (is_ff(ctx, port.cell))
return port.port == "R" || port.port == "S"; return port.port == "R" || port.port == "S";
if (port.cell->type == "ICESTORM_LC") if (port.cell->type == "ICESTORM_LC")
return port.port == "SR"; return port.port == "SR";
return false; return false;
} }
bool is_enable_port(const PortRef &port) bool is_enable_port(const Context *ctx, const PortRef &port)
{ {
if (port.cell == nullptr) if (port.cell == nullptr)
return false; return false;
if (is_ff(port.cell)) if (is_ff(ctx, port.cell))
return port.port == "E"; return port.port == "E";
if (port.cell->type == "ICESTORM_LC") if (port.cell->type == "ICESTORM_LC")
return port.port == "CEN"; return port.port == "CEN";
return false; 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 NEXTPNR_NAMESPACE_END

View File

@ -31,61 +31,84 @@ CellInfo *create_ice_cell(Context *ctx, IdString type,
IdString name = IdString()); IdString name = IdString());
// Return true if a cell is a LUT // 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 // 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" || return cell->type == ctx->id("SB_DFF") ||
cell->type == "SB_DFFSR" || cell->type == "SB_DFFR" || cell->type == ctx->id("SB_DFFE") ||
cell->type == "SB_DFFSS" || cell->type == "SB_DFFS" || cell->type == ctx->id("SB_DFFSR") ||
cell->type == "SB_DFFESR" || cell->type == "SB_DFFER" || cell->type == ctx->id("SB_DFFR") ||
cell->type == "SB_DFFESS" || cell->type == "SB_DFFES" || cell->type == ctx->id("SB_DFFSS") ||
cell->type == "SB_DFFN" || cell->type == "SB_DFFNE" || cell->type == ctx->id("SB_DFFS") ||
cell->type == "SB_DFFNSR" || cell->type == "SB_DFFNR" || cell->type == ctx->id("SB_DFFESR") ||
cell->type == "SB_DFFNSS" || cell->type == "SB_DFFNS" || cell->type == ctx->id("SB_DFFER") ||
cell->type == "SB_DFFNESR" || cell->type == "SB_DFFNER" || cell->type == ctx->id("SB_DFFESS") ||
cell->type == "SB_DFFNESS" || cell->type == "SB_DFFNES"; 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 // 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 // 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 // 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" || return cell->type == ctx->id("SB_RAM40_4K") ||
cell->type == "SB_RAM40_4KNW" || cell->type == "SB_RAM40_4KNRNW"; 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 // 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 // as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected // 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 // 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 // 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 // be configured as pass through and D connected to I0, otherwise D will be
// ignored // 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 // 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 // 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 // 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 // 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 // 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 NEXTPNR_NAMESPACE_END

View File

@ -201,7 +201,7 @@ int main(int argc, char *argv[])
std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" " std::cout << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
"xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"; "xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
for (auto bel : ctx.getBels()) { 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)) for (auto &el : ctx.getBelGraphics(bel))
svg_dump_el(el); svg_dump_el(el);
} }

View File

@ -38,7 +38,7 @@ static void pack_lut_lutffs(Context *ctx)
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
log_info("cell '%s' is of type '%s'\n", ci->name.c_str(), log_info("cell '%s' is of type '%s'\n", ci->name.c_str(),
ci->type.c_str()); ci->type.c_str());
if (is_lut(ci)) { if (is_lut(ctx, ci)) {
CellInfo *packed = CellInfo *packed =
create_ice_cell(ctx, "ICESTORM_LC", ci->name.str() + "_LC"); create_ice_cell(ctx, "ICESTORM_LC", ci->name.str() + "_LC");
std::copy(ci->attrs.begin(), ci->attrs.end(), 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 // See if we can pack into a DFF
// TODO: LUT cascade // TODO: LUT cascade
NetInfo *o = ci->ports.at("O").net; 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"); auto lut_bel = ci->attrs.find("BEL");
bool packed_dff = false; bool packed_dff = false;
if (dff) { if (dff) {
@ -60,8 +60,8 @@ static void pack_lut_lutffs(Context *ctx)
lut_bel->second != dff_bel->second) { lut_bel->second != dff_bel->second) {
// Locations don't match, can't pack // Locations don't match, can't pack
} else { } else {
lut_to_lc(ci, packed, false); lut_to_lc(ctx, ci, packed, false);
dff_to_lc(dff, packed, false); dff_to_lc(ctx, dff, packed, false);
ctx->nets.erase(o->name); ctx->nets.erase(o->name);
if (dff_bel != dff->attrs.end()) if (dff_bel != dff->attrs.end())
packed->attrs["BEL"] = dff_bel->second; packed->attrs["BEL"] = dff_bel->second;
@ -72,7 +72,7 @@ static void pack_lut_lutffs(Context *ctx)
} }
} }
if (!packed_dff) { 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) { for (auto cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_ff(ci)) { if (is_ff(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC", CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC",
ci->name.str() + "_DFFLC"); ci->name.str() + "_DFFLC");
std::copy(ci->attrs.begin(), ci->attrs.end(), std::copy(ci->attrs.begin(), ci->attrs.end(),
@ -103,7 +103,7 @@ static void pack_nonlut_ffs(Context *ctx)
packed->name.c_str()); packed->name.c_str());
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
new_cells.push_back(packed); new_cells.push_back(packed);
dff_to_lc(ci, packed, true); dff_to_lc(ctx, ci, packed, true);
} }
} }
for (auto pcell : packed_cells) { for (auto pcell : packed_cells) {
@ -124,7 +124,7 @@ static void pack_ram(Context *ctx)
for (auto cell : ctx->cells) { for (auto cell : ctx->cells) {
CellInfo *ci = cell.second; CellInfo *ci = cell.second;
if (is_ram(ci)) { if (is_ram(ctx, ci)) {
CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM", CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM",
ci->name.str() + "_RAM"); ci->name.str() + "_RAM");
packed_cells.insert(ci->name); packed_cells.insert(ci->name);
@ -161,14 +161,16 @@ static void pack_ram(Context *ctx)
} }
// Merge a net into a constant net // 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; orig->driver.cell = nullptr;
for (auto user : orig->users) { for (auto user : orig->users) {
if (user.cell != nullptr) { if (user.cell != nullptr) {
CellInfo *uc = user.cell; CellInfo *uc = user.cell;
log_info("%s user %s\n", orig->name.c_str(), uc->name.c_str()); 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; uc->ports[user.port].net = nullptr;
} else { } else {
uc->ports[user.port].net = constnet; uc->ports[user.port].net = constnet;
@ -203,13 +205,13 @@ static void pack_constants(Context *ctx)
for (auto net : ctx->nets) { for (auto net : ctx->nets) {
NetInfo *ni = net.second; NetInfo *ni = net.second;
if (ni->driver.cell != nullptr && ni->driver.cell->type == "GND") { 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->cells[gnd_cell->name] = gnd_cell;
ctx->nets[gnd_net->name] = gnd_net; ctx->nets[gnd_net->name] = gnd_net;
dead_nets.push_back(net.first); dead_nets.push_back(net.first);
} else if (ni->driver.cell != nullptr && } else if (ni->driver.cell != nullptr &&
ni->driver.cell->type == "VCC") { 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->cells[vcc_cell->name] = vcc_cell;
ctx->nets[vcc_net->name] = vcc_net; ctx->nets[vcc_net->name] = vcc_net;
dead_nets.push_back(net.first); dead_nets.push_back(net.first);
@ -239,11 +241,11 @@ static void pack_io(Context *ctx)
if (is_nextpnr_iob(ci)) { if (is_nextpnr_iob(ci)) {
CellInfo *sb = nullptr; CellInfo *sb = nullptr;
if (ci->type == "$nextpnr_ibuf" || ci->type == "$nextpnr_iobuf") { 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); "PACKAGE_PIN", true, ci);
} else if (ci->type == "$nextpnr_obuf") { } 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); "PACKAGE_PIN", true, ci);
} }
if (sb != nullptr) { if (sb != nullptr) {
@ -260,7 +262,7 @@ static void pack_io(Context *ctx)
} else { } else {
// Create a SB_IO buffer // Create a SB_IO buffer
sb = create_ice_cell(ctx, "SB_IO"); sb = create_ice_cell(ctx, "SB_IO");
nxio_to_sb(ci, sb); nxio_to_sb(ctx, ci, sb);
new_cells.push_back(sb); new_cells.push_back(sb);
} }
packed_cells.insert(ci->name); 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; gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
std::vector<PortRef> keep_users; std::vector<PortRef> keep_users;
for (auto user : net->users) { for (auto user : net->users) {
if (is_clock_port(user) || (is_reset && is_reset_port(user)) || if (is_clock_port(ctx, user) ||
(is_cen && is_enable_port(user))) { (is_reset && is_reset_port(ctx, user)) ||
(is_cen && is_enable_port(ctx, user))) {
user.cell->ports[user.port].net = glbnet; user.cell->ports[user.port].net = glbnet;
glbnet->users.push_back(user); glbnet->users.push_back(user);
} else { } else {
@ -317,17 +320,17 @@ static void promote_globals(Context *ctx)
std::unordered_map<IdString, int> clock_count, reset_count, cen_count; std::unordered_map<IdString, int> clock_count, reset_count, cen_count;
for (auto net : ctx->nets) { for (auto net : ctx->nets) {
NetInfo *ni = net.second; 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; clock_count[net.first] = 0;
reset_count[net.first] = 0; reset_count[net.first] = 0;
cen_count[net.first] = 0; cen_count[net.first] = 0;
for (auto user : ni->users) { for (auto user : ni->users) {
if (is_clock_port(user)) if (is_clock_port(ctx, user))
clock_count[net.first]++; clock_count[net.first]++;
if (is_reset_port(user)) if (is_reset_port(ctx, user))
reset_count[net.first]++; reset_count[net.first]++;
if (is_enable_port(user)) if (is_enable_port(ctx, user))
cen_count[net.first]++; 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 prom_globals = 0, prom_resets = 0, prom_cens = 0;
int gbs_available = 8; int gbs_available = 8;
for (auto cell : ctx->cells) for (auto cell : ctx->cells)
if (is_gbuf(cell.second)) if (is_gbuf(ctx, cell.second))
--gbs_available; --gbs_available;
while (prom_globals < gbs_available) { while (prom_globals < gbs_available) {
auto global_clock = auto global_clock =