awooter: router improvements and a bugfix
This commit is contained in:
parent
8fdb7c78c7
commit
1375277171
@ -146,6 +146,7 @@ extern "C" {
|
||||
float npnr_context_get_wire_delay(const Context *const ctx, uint64_t wire) { return ctx->getDelayNS(ctx->getWireDelay(unwrap_wire(wire)).maxDelay()); }
|
||||
float npnr_context_delay_epsilon(const Context *const ctx) { return ctx->getDelayNS(ctx->getDelayEpsilon()); }
|
||||
Loc npnr_context_get_pip_location(const Context *const ctx, uint64_t pip) { return ctx->getPipLocation(unwrap_pip(pip)); }
|
||||
bool npnr_context_check_pip_avail_for_net(const Context *const ctx, uint64_t pip, NetInfo *net) { return ctx->checkPipAvailForNet(unwrap_pip(pip), net); }
|
||||
|
||||
// This method's in C++ temporarily, while I figure out some better way of getting a pip iterator.
|
||||
Loc npnr_context_get_pip_direction(const Context *const ctx, uint64_t _pip) {
|
||||
@ -286,6 +287,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
int32_t npnr_netinfo_udata(NetInfo *const net) { return net->udata; }
|
||||
void npnr_netinfo_udata_set(NetInfo *const net, int32_t value) { net->udata = value; }
|
||||
|
||||
CellInfo* npnr_portref_cell(const PortRef *const port) { return port->cell; }
|
||||
Loc npnr_cellinfo_get_location(const CellInfo *const info) { return info->getLocation(); }
|
||||
|
@ -34,6 +34,13 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec<route::
|
||||
let mut arcs = vec![];
|
||||
for (name, net) in nets.to_vec().iter() {
|
||||
let net = unsafe { net.as_mut().unwrap() };
|
||||
let str = ctx.name_of(**name).to_str().unwrap().to_string();
|
||||
let verbose = false; //str == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
|
||||
|
||||
if verbose {
|
||||
dbg!(str, net.is_global());
|
||||
}
|
||||
|
||||
if net.is_global() {
|
||||
continue;
|
||||
}
|
||||
@ -53,7 +60,13 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec<route::
|
||||
sink_wire,
|
||||
sink,
|
||||
net.index(),
|
||||
))
|
||||
));
|
||||
|
||||
if verbose {
|
||||
let source_wire = ctx.name_of_wire(source_wire).to_str().unwrap();
|
||||
let sink_wire = ctx.name_of_wire(sink_wire).to_str().unwrap();
|
||||
dbg!(source_wire, sink_wire, net.index().into_inner());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,9 +195,9 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
|
||||
let (x_part, y_part, ne, se, sw, nw) = partition::find_partition_point_and_sanity_check(
|
||||
ctx,
|
||||
&nets,
|
||||
&partitionable_arcs[..],
|
||||
pips,
|
||||
&nets,
|
||||
0,
|
||||
ctx.grid_dim_x(),
|
||||
0,
|
||||
@ -221,7 +234,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
|
||||
partitions.par_iter().for_each(|(box_ne, box_sw, arcs)| {
|
||||
let mut router = route::Router::new(*box_ne, *box_sw);
|
||||
router.route(ctx, &nets, arcs, &progress);
|
||||
router.route(ctx, &nets, wires, arcs, &progress);
|
||||
});
|
||||
|
||||
log_info!("Routing miscellaneous arcs\n");
|
||||
@ -229,7 +242,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
Coord::new(0, 0),
|
||||
Coord::new(ctx.grid_dim_x(), ctx.grid_dim_y()),
|
||||
);
|
||||
router.route(ctx, &nets, &special_arcs, &progress);
|
||||
router.route(ctx, &nets, wires, &special_arcs, &progress);
|
||||
|
||||
let time = format!("{:.2}", (Instant::now() - start).as_secs_f32());
|
||||
log_info!("Routing took {}s\n", time.bold());
|
||||
|
@ -49,6 +49,12 @@ impl NetInfo {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct NetIndex(i32);
|
||||
|
||||
impl NetIndex {
|
||||
pub fn into_inner(self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PortRef {
|
||||
private: [u8; 0],
|
||||
@ -271,6 +277,10 @@ impl Context {
|
||||
unsafe { npnr_context_get_pip_direction(self, pip) }
|
||||
}
|
||||
|
||||
pub fn pip_avail_for_net(&self, pip: PipId, net: *mut NetInfo) -> bool {
|
||||
unsafe { npnr_context_check_pip_avail_for_net(self, pip, net) }
|
||||
}
|
||||
|
||||
pub fn check(&self) {
|
||||
unsafe { npnr_context_check(self) }
|
||||
}
|
||||
@ -346,6 +356,7 @@ extern "C-unwind" {
|
||||
fn npnr_context_get_pips_leak(ctx: *const Context, pips: *mut *mut PipId) -> u64;
|
||||
fn npnr_context_get_pip_location(ctx: *const Context, pip: PipId) -> Loc;
|
||||
fn npnr_context_get_pip_direction(ctx: *const Context, pip: PipId) -> Loc;
|
||||
fn npnr_context_check_pip_avail_for_net(ctx: *const Context, pip: PipId, net: *const NetInfo) -> bool;
|
||||
|
||||
fn npnr_context_check(ctx: *const Context);
|
||||
fn npnr_context_debug(ctx: *const Context) -> bool;
|
||||
@ -377,6 +388,7 @@ extern "C-unwind" {
|
||||
fn npnr_netinfo_users_leak(net: *mut NetInfo, users: *mut *mut *mut PortRef) -> u32;
|
||||
fn npnr_netinfo_is_global(net: *const NetInfo) -> bool;
|
||||
fn npnr_netinfo_udata(net: *const NetInfo) -> NetIndex;
|
||||
fn npnr_netinfo_udata_set(net: *mut NetInfo, value: NetIndex);
|
||||
|
||||
fn npnr_portref_cell(port: *const PortRef) -> *mut CellInfo;
|
||||
fn npnr_cellinfo_get_location(info: *const CellInfo) -> Loc;
|
||||
@ -434,6 +446,7 @@ impl<'a> Nets<'a> {
|
||||
let index = index_to_net.len() as i32;
|
||||
index_to_net.push(name);
|
||||
net_to_index.insert(net, index);
|
||||
unsafe { npnr_netinfo_udata_set(net, NetIndex(index)); }
|
||||
}
|
||||
// Note: the contents of `names` and `nets_ptr` are now lost.
|
||||
Self {
|
||||
|
@ -112,9 +112,9 @@ impl From<npnr::Loc> for Coord {
|
||||
|
||||
pub fn find_partition_point(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
nets: &npnr::Nets,
|
||||
x_start: i32,
|
||||
x_finish: i32,
|
||||
y_start: i32,
|
||||
@ -133,9 +133,9 @@ pub fn find_partition_point(
|
||||
while x_diff != 0 {
|
||||
(ne, se, sw, nw) = partition(
|
||||
ctx,
|
||||
nets,
|
||||
arcs,
|
||||
pips,
|
||||
nets,
|
||||
x,
|
||||
y,
|
||||
x_start..=x_finish,
|
||||
@ -178,9 +178,9 @@ pub fn find_partition_point(
|
||||
|
||||
(ne, se, sw, nw) = partition(
|
||||
ctx,
|
||||
nets,
|
||||
arcs,
|
||||
pips,
|
||||
nets,
|
||||
x,
|
||||
y,
|
||||
x_start..=x_finish,
|
||||
@ -251,9 +251,9 @@ fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 {
|
||||
/// result which is correct, without any care about speed or actual pathing optimality
|
||||
fn partition<R: RangeBounds<i32>>(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
nets: &npnr::Nets,
|
||||
x: i32,
|
||||
y: i32,
|
||||
x_bounds: R,
|
||||
@ -307,9 +307,8 @@ fn partition<R: RangeBounds<i32>>(
|
||||
let sink_coords: Coord = sink_loc.into();
|
||||
let sink_is_north = sink_coords.is_north_of(&partition_coords);
|
||||
let sink_is_east = sink_coords.is_east_of(&partition_coords);
|
||||
// let name = ctx.name_of(nets.name_from_index(arc.net())).to_str().unwrap().to_string();
|
||||
let verbose = false; // name == "IBusCachedPlugin_fetchPc_pc_LUT4_Z_15_B_CCU2C_S0$CCU2_FCI_INT";
|
||||
//"soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_24_B1_LUT4_Z_B_CCU2C_S0_CIN_CCU2C_COUT_S1_LUT4_D_Z_LUT4_Z_D_CCU2C_S0_CIN_CCU2C_COUT_CIN_CCU2C_COUT$CCU2_FCI_INT";
|
||||
let name = ctx.name_of(nets.name_from_index(arc.net())).to_str().unwrap().to_string();
|
||||
let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
|
||||
if source_is_north == sink_is_north && source_is_east == sink_is_east {
|
||||
let seg = source_coords.segment_from(&Coord::new(x, y));
|
||||
vec![(seg, arc.clone())]
|
||||
@ -618,16 +617,16 @@ fn partition<R: RangeBounds<i32>>(
|
||||
|
||||
pub fn find_partition_point_and_sanity_check(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
nets: &npnr::Nets,
|
||||
x_start: i32,
|
||||
x_finish: i32,
|
||||
y_start: i32,
|
||||
y_finish: i32,
|
||||
) -> (i32, i32, Vec<Arc>, Vec<Arc>, Vec<Arc>, Vec<Arc>) {
|
||||
let (x_part, y_part, ne, se, sw, nw) =
|
||||
find_partition_point(ctx, arcs, pips, nets, x_start, x_finish, y_start, y_finish);
|
||||
find_partition_point(ctx, nets, arcs, pips, x_start, x_finish, y_start, y_finish);
|
||||
|
||||
let mut invalid_arcs_in_ne = 0;
|
||||
let mut invalid_arcs_in_se = 0;
|
||||
|
@ -3,7 +3,7 @@ use std::collections::{BinaryHeap, HashMap};
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use crate::{
|
||||
npnr::{self, NetIndex, PipId},
|
||||
npnr::{self, NetIndex, PipId, WireId},
|
||||
partition,
|
||||
};
|
||||
|
||||
@ -106,11 +106,28 @@ impl PartialOrd for QueuedWire {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PerNetData {
|
||||
wires: HashMap<WireId, (PipId, u32)>,
|
||||
}
|
||||
|
||||
struct PerWireData {
|
||||
wire: WireId,
|
||||
curr_cong: u32,
|
||||
hist_cong: f32,
|
||||
unavailable: bool,
|
||||
reserved_net: Option<NetIndex>,
|
||||
pip_fwd: PipId,
|
||||
visited_fwd: bool,
|
||||
}
|
||||
|
||||
pub struct Router {
|
||||
box_ne: partition::Coord,
|
||||
box_sw: partition::Coord,
|
||||
bound_pip: HashMap<npnr::PipId, NetIndex>,
|
||||
wire_driver: HashMap<npnr::WireId, npnr::PipId>,
|
||||
nets: Vec<PerNetData>,
|
||||
wire_to_idx: HashMap<WireId, u32>,
|
||||
flat_wires: Vec<PerWireData>,
|
||||
dirty_wires: Vec<u32>,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
@ -118,8 +135,10 @@ impl Router {
|
||||
Self {
|
||||
box_ne,
|
||||
box_sw,
|
||||
bound_pip: HashMap::new(),
|
||||
wire_driver: HashMap::new(),
|
||||
nets: Vec::new(),
|
||||
wire_to_idx: HashMap::new(),
|
||||
flat_wires: Vec::new(),
|
||||
dirty_wires: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,9 +146,28 @@ impl Router {
|
||||
&mut self,
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
wires: &[npnr::WireId],
|
||||
arcs: &[Arc],
|
||||
progress: &MultiProgress,
|
||||
) {
|
||||
log_info!("Setting up router...\n");
|
||||
for _ in 0..nets.len() {
|
||||
self.nets.push(PerNetData { wires: HashMap::new() });
|
||||
}
|
||||
|
||||
for (idx, &wire) in wires.iter().enumerate() {
|
||||
self.flat_wires.push(PerWireData {
|
||||
wire,
|
||||
curr_cong: 0,
|
||||
hist_cong: 0.0,
|
||||
unavailable: false,
|
||||
reserved_net: None,
|
||||
pip_fwd: PipId::null(),
|
||||
visited_fwd: false
|
||||
});
|
||||
self.wire_to_idx.insert(wire, idx as u32);
|
||||
}
|
||||
|
||||
let progress = progress.add(ProgressBar::new(arcs.len() as u64));
|
||||
progress.set_style(
|
||||
ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}")
|
||||
@ -148,8 +186,7 @@ impl Router {
|
||||
if net.is_global() {
|
||||
continue;
|
||||
}
|
||||
//log_info!("{}\n", name);
|
||||
//log_info!(" {} to {}\n", ctx.name_of_wire(arc.source_wire).to_str().unwrap(), ctx.name_of_wire(arc.sink_wire).to_str().unwrap());
|
||||
|
||||
progress.inc(1);
|
||||
progress.set_message(name);
|
||||
self.route_arc(ctx, nets, arc);
|
||||
@ -159,10 +196,7 @@ impl Router {
|
||||
|
||||
fn route_arc(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arc: &Arc) {
|
||||
let mut queue = BinaryHeap::new();
|
||||
let mut visited = HashMap::new();
|
||||
|
||||
queue.push(QueuedWire::new(0.0, 0.0, arc.source_wire));
|
||||
visited.insert(arc.source_wire, npnr::PipId::null());
|
||||
|
||||
let mut found_sink = false;
|
||||
|
||||
@ -171,8 +205,7 @@ impl Router {
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
let verbose = false;
|
||||
//name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1";
|
||||
let verbose = false; //name == "soc0.processor.with_fpu.fpu_0.fpu_multiply_0.rin_CCU2C_S0_4$CCU2_FCI_INT";
|
||||
|
||||
while let Some(source) = queue.pop() {
|
||||
if source.wire == arc.sink_wire {
|
||||
@ -185,62 +218,65 @@ impl Router {
|
||||
}
|
||||
|
||||
for pip in ctx.get_downhill_pips(source.wire) {
|
||||
let pip_loc = ctx.pip_location(pip);
|
||||
let pip_coord = partition::Coord::from(pip_loc);
|
||||
if pip_coord.is_north_of(&self.box_ne) || pip_coord.is_east_of(&self.box_ne) {
|
||||
continue;
|
||||
}
|
||||
if pip_coord.is_south_of(&self.box_sw) || pip_coord.is_west_of(&self.box_sw) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!ctx->checkPipAvailForNet(dh, net))
|
||||
continue;
|
||||
WireId next = ctx->getPipDstWire(dh);
|
||||
int next_idx = wire_to_idx.at(next);
|
||||
if (was_visited_fwd(next_idx)) {
|
||||
// Don't expand the same node twice.
|
||||
continue;
|
||||
}
|
||||
auto &nwd = flat_wires.at(next_idx);
|
||||
if (nwd.unavailable)
|
||||
continue;
|
||||
// Reserved for another net
|
||||
if (nwd.reserved_net != -1 && nwd.reserved_net != net->udata)
|
||||
continue;
|
||||
// Don't allow the same wire to be bound to the same net with a different driving pip
|
||||
auto fnd_wire = nd.wires.find(next);
|
||||
if (fnd_wire != nd.wires.end() && fnd_wire->second.first != dh)
|
||||
continue;
|
||||
if (!thread_test_wire(t, nwd))
|
||||
continue; // thread safety issue
|
||||
*/
|
||||
|
||||
let sink = ctx.pip_dst_wire(pip);
|
||||
if visited.contains_key(&sink) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*let driver = self.wire_driver.get(&sink);
|
||||
if let Some(&driver) = driver {
|
||||
if driver != pip {
|
||||
continue;
|
||||
}
|
||||
if *self.bound_pip.get(&driver).unwrap() != arc.net {
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
|
||||
visited.insert(sink, pip);
|
||||
|
||||
if verbose {
|
||||
log_info!(" {}\n", ctx.name_of_pip(pip).to_str().unwrap());
|
||||
}
|
||||
|
||||
let pip_loc = ctx.pip_location(pip);
|
||||
let pip_coord = partition::Coord::from(pip_loc);
|
||||
if pip_coord.is_north_of(&self.box_ne) || pip_coord.is_east_of(&self.box_ne) {
|
||||
if verbose {
|
||||
log_info!(" out-of-bounds (NE)\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if pip_coord.is_south_of(&self.box_sw) || pip_coord.is_west_of(&self.box_sw) {
|
||||
if verbose {
|
||||
log_info!(" out-of-bounds (SW)\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if !ctx.pip_avail_for_net(pip, nets.net_from_index(arc.net())) {
|
||||
if verbose {
|
||||
log_info!(" pip unavailable for net\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let wire = ctx.pip_dst_wire(pip);
|
||||
let sink = *self.wire_to_idx.get(&wire).unwrap();
|
||||
if self.was_visited_fwd(sink) {
|
||||
if verbose {
|
||||
log_info!(" already visited\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let nd = &mut self.nets[arc.net().into_inner() as usize];
|
||||
let nwd = &self.flat_wires[sink as usize];
|
||||
if nwd.unavailable {
|
||||
if verbose {
|
||||
log_info!(" unavailable\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if let Some(net) = nwd.reserved_net && net != arc.net() {
|
||||
if verbose {
|
||||
log_info!(" reserved for other net\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Don't allow the same wire to be bound to the same net with a different driving pip
|
||||
if let Some((found_pip, _)) = nd.wires.get(&wire) && *found_pip != pip {
|
||||
if verbose {
|
||||
log_info!(" driven by other pip\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
self.set_visited_fwd(sink, pip);
|
||||
|
||||
let delay =
|
||||
source.cost + ctx.pip_delay(pip) + ctx.wire_delay(sink) + ctx.delay_epsilon();
|
||||
let qw = QueuedWire::new(delay, ctx.estimate_delay(sink, arc.sink_wire), sink);
|
||||
source.cost + ctx.pip_delay(pip) + ctx.wire_delay(wire) + ctx.delay_epsilon();
|
||||
let qw = QueuedWire::new(delay, ctx.estimate_delay(wire, arc.sink_wire), wire);
|
||||
queue.push(qw);
|
||||
}
|
||||
}
|
||||
@ -253,24 +289,64 @@ impl Router {
|
||||
ctx.name_of_wire(arc.sink_wire).to_str().unwrap()
|
||||
);
|
||||
|
||||
let mut wire = arc.sink_wire;
|
||||
while wire != arc.source_wire {
|
||||
/*if verbose {
|
||||
println!("Wire: {}", ctx.name_of_wire(wire).to_str().unwrap());
|
||||
}*/
|
||||
let pip = *visited.get(&wire).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Expected wire {} to have driving pip",
|
||||
ctx.name_of_wire(wire).to_str().unwrap()
|
||||
)
|
||||
});
|
||||
self.bind_pip(pip, arc.net);
|
||||
wire = ctx.pip_src_wire(pip);
|
||||
let source_wire = *self.wire_to_idx.get(&arc.source_wire).unwrap();
|
||||
let mut wire = *self.wire_to_idx.get(&arc.sink_wire).unwrap();
|
||||
while wire != source_wire {
|
||||
if verbose {
|
||||
println!("Wire: {}", ctx.name_of_wire(self.flat_wires[wire as usize].wire).to_str().unwrap());
|
||||
}
|
||||
let pip = self.flat_wires[wire as usize].pip_fwd;
|
||||
assert!(pip != PipId::null());
|
||||
self.bind_pip_internal(arc.net(), wire, pip);
|
||||
wire = *self.wire_to_idx.get(&ctx.pip_src_wire(pip)).unwrap();
|
||||
}
|
||||
|
||||
self.reset_wires();
|
||||
}
|
||||
|
||||
fn bind_pip(&mut self, pip: PipId, net: NetIndex) {
|
||||
//assert!(!self.bound_pip.contains_key(&pip));
|
||||
self.bound_pip.insert(pip, net);
|
||||
fn was_visited_fwd(&self, wire: u32) -> bool {
|
||||
self.flat_wires[wire as usize].visited_fwd
|
||||
}
|
||||
|
||||
fn set_visited_fwd(&mut self, wire: u32, pip: PipId) {
|
||||
let wd = &mut self.flat_wires[wire as usize];
|
||||
if !wd.visited_fwd {
|
||||
self.dirty_wires.push(wire);
|
||||
}
|
||||
wd.pip_fwd = pip;
|
||||
wd.visited_fwd = true;
|
||||
}
|
||||
|
||||
fn bind_pip_internal(&mut self, net: NetIndex, wire: u32, pip: PipId) {
|
||||
let wireid = self.flat_wires[wire as usize].wire;
|
||||
let net = &mut self.nets[net.into_inner() as usize];
|
||||
if let Some((bound_pip, usage)) = net.wires.get_mut(&wireid) {
|
||||
assert!(*bound_pip == pip);
|
||||
*usage += 1;
|
||||
} else {
|
||||
net.wires.insert(wireid, (pip, 1));
|
||||
self.flat_wires[wire as usize].curr_cong += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_wires(&mut self) {
|
||||
for &wire in &self.dirty_wires {
|
||||
self.flat_wires[wire as usize].pip_fwd = PipId::null();
|
||||
self.flat_wires[wire as usize].visited_fwd = false;
|
||||
}
|
||||
self.dirty_wires.clear();
|
||||
}
|
||||
/*
|
||||
void unbind_pip_internal(PerNetData &net, store_index<PortRef> user, WireId wire)
|
||||
{
|
||||
auto &wd = wire_data(wire);
|
||||
auto &b = net.wires.at(wd.w);
|
||||
--b.second;
|
||||
if (b.second == 0) {
|
||||
// No remaining arcs of this net bound to this wire
|
||||
--wd.curr_cong;
|
||||
net.wires.erase(wd.w);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user