Make ice40::Arch thread-safe
We move all non-chip data to be private and guard them with an R/W mutex. We then modify all calls that access these fields to lock/shared_lock the mutex as required. Profiling the code before and after is an exercise left to the reader :).
This commit is contained in:
parent
309a533b7c
commit
0816f447b7
@ -241,6 +241,7 @@ IdString Arch::archArgsToId(ArchArgs args) const
|
|||||||
|
|
||||||
BelId Arch::getBelByName(IdString name) const
|
BelId Arch::getBelByName(IdString name) const
|
||||||
{
|
{
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
BelId ret;
|
BelId ret;
|
||||||
|
|
||||||
if (bel_by_name.empty()) {
|
if (bel_by_name.empty()) {
|
||||||
@ -276,6 +277,7 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const
|
|||||||
WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
||||||
{
|
{
|
||||||
WireId ret;
|
WireId ret;
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
|
||||||
@ -296,6 +298,7 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
|||||||
WireId Arch::getWireByName(IdString name) const
|
WireId Arch::getWireByName(IdString name) const
|
||||||
{
|
{
|
||||||
WireId ret;
|
WireId ret;
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
if (wire_by_name.empty()) {
|
if (wire_by_name.empty()) {
|
||||||
for (int i = 0; i < chip_info->num_wires; i++)
|
for (int i = 0; i < chip_info->num_wires; i++)
|
||||||
@ -314,6 +317,7 @@ WireId Arch::getWireByName(IdString name) const
|
|||||||
PipId Arch::getPipByName(IdString name) const
|
PipId Arch::getPipByName(IdString name) const
|
||||||
{
|
{
|
||||||
PipId ret;
|
PipId ret;
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
if (pip_by_name.empty()) {
|
if (pip_by_name.empty()) {
|
||||||
for (int i = 0; i < chip_info->num_pips; i++) {
|
for (int i = 0; i < chip_info->num_pips; i++) {
|
||||||
@ -372,6 +376,8 @@ std::string Arch::getBelPackagePin(BelId bel) const
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// TODO(cliffordvienna): lock all of this
|
||||||
|
|
||||||
GroupId Arch::getGroupByName(IdString name) const
|
GroupId Arch::getGroupByName(IdString name) const
|
||||||
{
|
{
|
||||||
for (auto g : getGroups())
|
for (auto g : getGroups())
|
||||||
@ -488,6 +494,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const
|
|||||||
|
|
||||||
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
||||||
{
|
{
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
std::vector<GraphicElement> ret;
|
std::vector<GraphicElement> ret;
|
||||||
|
|
||||||
if (decal.type == DecalId::TYPE_FRAME) {
|
if (decal.type == DecalId::TYPE_FRAME) {
|
||||||
|
38
ice40/arch.h
38
ice40/arch.h
@ -21,6 +21,9 @@
|
|||||||
#error Include "arch.h" via "nextpnr.h" only.
|
#error Include "arch.h" via "nextpnr.h" only.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/thread/shared_lock_guard.hpp>
|
||||||
|
#include <boost/thread/shared_mutex.hpp>
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**** Everything in this section must be kept in sync with chipdb.py ****/
|
/**** Everything in this section must be kept in sync with chipdb.py ****/
|
||||||
@ -324,8 +327,17 @@ struct ArchArgs
|
|||||||
std::string package;
|
std::string package;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arch : BaseCtx
|
class Arch : public BaseCtx
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
// All of the following...
|
||||||
|
std::vector<IdString> bel_to_cell;
|
||||||
|
std::vector<IdString> wire_to_net;
|
||||||
|
std::vector<IdString> pip_to_net;
|
||||||
|
std::vector<IdString> switches_locked;
|
||||||
|
// ... are guarded by the following lock:
|
||||||
|
mutable boost::shared_mutex mtx_;
|
||||||
|
public:
|
||||||
const ChipInfoPOD *chip_info;
|
const ChipInfoPOD *chip_info;
|
||||||
const PackageInfoPOD *package_info;
|
const PackageInfoPOD *package_info;
|
||||||
|
|
||||||
@ -333,11 +345,6 @@ struct Arch : BaseCtx
|
|||||||
mutable std::unordered_map<IdString, int> wire_by_name;
|
mutable std::unordered_map<IdString, int> wire_by_name;
|
||||||
mutable std::unordered_map<IdString, int> pip_by_name;
|
mutable std::unordered_map<IdString, int> pip_by_name;
|
||||||
|
|
||||||
std::vector<IdString> bel_to_cell;
|
|
||||||
std::vector<IdString> wire_to_net;
|
|
||||||
std::vector<IdString> pip_to_net;
|
|
||||||
std::vector<IdString> switches_locked;
|
|
||||||
|
|
||||||
ArchArgs args;
|
ArchArgs args;
|
||||||
Arch(ArchArgs args);
|
Arch(ArchArgs args);
|
||||||
|
|
||||||
@ -368,6 +375,7 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
|
NPNR_ASSERT(bel_to_cell[bel.index] == IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
bel_to_cell[bel.index] = cell;
|
bel_to_cell[bel.index] = cell;
|
||||||
cells[cell]->bel = bel;
|
cells[cell]->bel = bel;
|
||||||
cells[cell]->belStrength = strength;
|
cells[cell]->belStrength = strength;
|
||||||
@ -377,6 +385,7 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
|
NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
cells[bel_to_cell[bel.index]]->bel = BelId();
|
cells[bel_to_cell[bel.index]]->bel = BelId();
|
||||||
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
||||||
bel_to_cell[bel.index] = IdString();
|
bel_to_cell[bel.index] = IdString();
|
||||||
@ -385,18 +394,21 @@ struct Arch : BaseCtx
|
|||||||
bool checkBelAvail(BelId bel) const
|
bool checkBelAvail(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return bel_to_cell[bel.index] == IdString();
|
return bel_to_cell[bel.index] == IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundBelCell(BelId bel) const
|
IdString getBoundBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return bel_to_cell[bel.index];
|
return bel_to_cell[bel.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingBelCell(BelId bel) const
|
IdString getConflictingBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return bel_to_cell[bel.index];
|
return bel_to_cell[bel.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,6 +482,8 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire.index] == IdString());
|
NPNR_ASSERT(wire_to_net[wire.index] == IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
wire_to_net[wire.index] = net;
|
wire_to_net[wire.index] = net;
|
||||||
nets[net]->wires[wire].pip = PipId();
|
nets[net]->wires[wire].pip = PipId();
|
||||||
nets[net]->wires[wire].strength = strength;
|
nets[net]->wires[wire].strength = strength;
|
||||||
@ -479,6 +493,7 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire.index] != IdString());
|
NPNR_ASSERT(wire_to_net[wire.index] != IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
auto &net_wires = nets[wire_to_net[wire.index]]->wires;
|
auto &net_wires = nets[wire_to_net[wire.index]]->wires;
|
||||||
auto it = net_wires.find(wire);
|
auto it = net_wires.find(wire);
|
||||||
@ -497,18 +512,24 @@ struct Arch : BaseCtx
|
|||||||
bool checkWireAvail(WireId wire) const
|
bool checkWireAvail(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
return wire_to_net[wire.index] == IdString();
|
return wire_to_net[wire.index] == IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundWireNet(WireId wire) const
|
IdString getBoundWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
return wire_to_net[wire.index];
|
return wire_to_net[wire.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingWireNet(WireId wire) const
|
IdString getConflictingWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
return wire_to_net[wire.index];
|
return wire_to_net[wire.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,6 +553,7 @@ struct Arch : BaseCtx
|
|||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] == IdString());
|
NPNR_ASSERT(pip_to_net[pip.index] == IdString());
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
|
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
pip_to_net[pip.index] = net;
|
pip_to_net[pip.index] = net;
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
||||||
@ -549,6 +571,7 @@ struct Arch : BaseCtx
|
|||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] != IdString());
|
NPNR_ASSERT(pip_to_net[pip.index] != IdString());
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
|
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
|
||||||
|
boost::lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = chip_info->pip_data[pip.index].dst;
|
dst.index = chip_info->pip_data[pip.index].dst;
|
||||||
@ -563,18 +586,21 @@ struct Arch : BaseCtx
|
|||||||
bool checkPipAvail(PipId pip) const
|
bool checkPipAvail(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
|
return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getBoundPipNet(PipId pip) const
|
IdString getBoundPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return pip_to_net[pip.index];
|
return pip_to_net[pip.index];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingPipNet(PipId pip) const
|
IdString getConflictingPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
boost::shared_lock_guard<boost::shared_mutex> lock(mtx_);
|
||||||
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
return switches_locked[chip_info->pip_data[pip.index].switch_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
// Set pips
|
// Set pips
|
||||||
for (auto pip : ctx->getPips()) {
|
for (auto pip : ctx->getPips()) {
|
||||||
if (ctx->pip_to_net[pip.index] != IdString()) {
|
if (ctx->getBoundPipNet(pip) != IdString()) {
|
||||||
const PipInfoPOD &pi = ci.pip_data[pip.index];
|
const PipInfoPOD &pi = ci.pip_data[pip.index];
|
||||||
const SwitchInfoPOD &swi = bi.switches[pi.switch_index];
|
const SwitchInfoPOD &swi = bi.switches[pi.switch_index];
|
||||||
for (int i = 0; i < swi.num_bits; i++) {
|
for (int i = 0; i < swi.num_bits; i++) {
|
||||||
@ -199,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
NPNR_ASSERT(iez != -1);
|
NPNR_ASSERT(iez != -1);
|
||||||
|
|
||||||
bool input_en = false;
|
bool input_en = false;
|
||||||
if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) ||
|
if (!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_0)) ||
|
||||||
(ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) {
|
!ctx->checkWireAvail(ctx->getWireBelPin(bel, PIN_D_IN_1))) {
|
||||||
input_en = true;
|
input_en = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
}
|
}
|
||||||
// Set config bits in unused IO and RAM
|
// Set config bits in unused IO and RAM
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) {
|
if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) {
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||||
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;
|
||||||
@ -284,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out)
|
|||||||
set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false);
|
set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) {
|
} else if (ctx->checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_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 = bi.tiles_nonrouting[TILE_RAMB];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB];
|
||||||
|
Loading…
Reference in New Issue
Block a user