2022-12-02 19:48:05 +08:00
|
|
|
use std::collections::{BinaryHeap, HashMap};
|
2022-11-29 05:15:04 +08:00
|
|
|
|
2022-12-02 19:48:05 +08:00
|
|
|
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
2022-11-28 03:27:33 +08:00
|
|
|
|
2022-11-28 03:47:16 +08:00
|
|
|
use crate::{
|
|
|
|
npnr::{self, NetIndex, PipId},
|
|
|
|
partition,
|
|
|
|
};
|
2022-11-27 23:28:59 +08:00
|
|
|
|
2022-11-28 03:47:16 +08:00
|
|
|
#[derive(Clone)]
|
2022-11-27 23:28:59 +08:00
|
|
|
pub struct Arc {
|
|
|
|
source_wire: npnr::WireId,
|
|
|
|
source_loc: npnr::Loc,
|
|
|
|
sink_wire: npnr::WireId,
|
|
|
|
sink_loc: npnr::Loc,
|
2022-11-28 03:27:33 +08:00
|
|
|
net: npnr::NetIndex,
|
2022-11-27 23:28:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Arc {
|
2022-11-28 03:47:16 +08:00
|
|
|
pub fn new(
|
|
|
|
source_wire: npnr::WireId,
|
|
|
|
source_loc: npnr::Loc,
|
|
|
|
sink_wire: npnr::WireId,
|
|
|
|
sink_loc: npnr::Loc,
|
|
|
|
net: NetIndex,
|
|
|
|
) -> Self {
|
2022-11-27 23:28:59 +08:00
|
|
|
Self {
|
2022-11-28 03:47:16 +08:00
|
|
|
source_wire,
|
|
|
|
source_loc,
|
|
|
|
sink_wire,
|
|
|
|
sink_loc,
|
|
|
|
net,
|
2022-11-27 23:28:59 +08:00
|
|
|
}
|
|
|
|
}
|
2022-11-28 00:26:17 +08:00
|
|
|
|
2022-11-28 03:47:16 +08:00
|
|
|
pub fn split(&self, ctx: &npnr::Context, pip: npnr::PipId) -> (Self, Self) {
|
2022-11-28 00:26:17 +08:00
|
|
|
let pip_src = ctx.pip_src_wire(pip);
|
|
|
|
let pip_dst = ctx.pip_dst_wire(pip);
|
2022-11-28 03:47:16 +08:00
|
|
|
(
|
|
|
|
Self {
|
|
|
|
source_wire: self.source_wire,
|
|
|
|
source_loc: self.source_loc,
|
|
|
|
sink_wire: pip_src,
|
|
|
|
sink_loc: ctx.pip_location(pip),
|
|
|
|
net: self.net,
|
|
|
|
},
|
|
|
|
Self {
|
|
|
|
source_wire: pip_dst,
|
|
|
|
source_loc: ctx.pip_location(pip),
|
|
|
|
sink_wire: self.sink_wire,
|
|
|
|
sink_loc: self.sink_loc,
|
|
|
|
net: self.net,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_source_loc(&self) -> npnr::Loc {
|
|
|
|
self.source_loc
|
|
|
|
}
|
|
|
|
pub fn get_sink_loc(&self) -> npnr::Loc {
|
|
|
|
self.sink_loc
|
|
|
|
}
|
|
|
|
pub fn get_source_wire(&self) -> npnr::WireId {
|
|
|
|
self.source_wire
|
|
|
|
}
|
|
|
|
pub fn get_sink_wire(&self) -> npnr::WireId {
|
|
|
|
self.sink_wire
|
2022-11-28 00:26:17 +08:00
|
|
|
}
|
2022-11-29 05:15:04 +08:00
|
|
|
pub fn net(&self) -> npnr::NetIndex {
|
|
|
|
self.net
|
|
|
|
}
|
2022-11-27 23:28:59 +08:00
|
|
|
}
|
|
|
|
|
2022-11-28 03:27:33 +08:00
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
struct QueuedWire {
|
|
|
|
cost: f32,
|
|
|
|
togo: f32,
|
|
|
|
wire: npnr::WireId,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QueuedWire {
|
|
|
|
pub fn new(cost: f32, togo: f32, wire: npnr::WireId) -> Self {
|
2022-11-28 03:47:16 +08:00
|
|
|
Self { cost, togo, wire }
|
2022-11-28 03:27:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for QueuedWire {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.cost == other.cost && self.togo == other.togo && self.wire == other.wire
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for QueuedWire {}
|
|
|
|
|
|
|
|
impl Ord for QueuedWire {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
let me = self.cost + self.togo;
|
|
|
|
let other = other.cost + other.togo;
|
|
|
|
other.total_cmp(&me)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for QueuedWire {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 00:26:17 +08:00
|
|
|
pub struct Router {
|
2022-11-28 03:27:33 +08:00
|
|
|
box_ne: partition::Coord,
|
|
|
|
box_sw: partition::Coord,
|
|
|
|
bound_pip: HashMap<npnr::PipId, NetIndex>,
|
|
|
|
wire_driver: HashMap<npnr::WireId, npnr::PipId>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Router {
|
|
|
|
pub fn new(box_ne: partition::Coord, box_sw: partition::Coord) -> Self {
|
|
|
|
Self {
|
|
|
|
box_ne,
|
|
|
|
box_sw,
|
|
|
|
bound_pip: HashMap::new(),
|
|
|
|
wire_driver: HashMap::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-02 19:48:05 +08:00
|
|
|
pub fn route(
|
|
|
|
&mut self,
|
|
|
|
ctx: &npnr::Context,
|
|
|
|
nets: &npnr::Nets,
|
|
|
|
arcs: &[Arc],
|
|
|
|
progress: &MultiProgress,
|
|
|
|
) {
|
2022-11-30 09:20:14 +08:00
|
|
|
let progress = progress.add(ProgressBar::new(arcs.len() as u64));
|
2022-11-29 05:15:04 +08:00
|
|
|
progress.set_style(
|
|
|
|
ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}")
|
|
|
|
.unwrap()
|
|
|
|
.progress_chars("━╸ "),
|
|
|
|
);
|
|
|
|
|
2022-11-28 03:27:33 +08:00
|
|
|
for arc in arcs {
|
2022-11-29 05:15:04 +08:00
|
|
|
let net = unsafe { nets.net_from_index(arc.net).as_ref().unwrap() };
|
2022-11-29 09:55:24 +08:00
|
|
|
let name = ctx
|
|
|
|
.name_of(nets.name_from_index(arc.net))
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
2022-11-29 05:15:04 +08:00
|
|
|
|
|
|
|
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);
|
2022-11-28 03:27:33 +08:00
|
|
|
}
|
2022-11-29 05:15:04 +08:00
|
|
|
progress.finish_and_clear()
|
2022-11-28 03:27:33 +08:00
|
|
|
}
|
|
|
|
|
2022-11-29 05:15:04 +08:00
|
|
|
fn route_arc(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arc: &Arc) {
|
2022-11-28 03:27:33 +08:00
|
|
|
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());
|
|
|
|
|
2022-11-29 05:15:04 +08:00
|
|
|
let mut found_sink = false;
|
|
|
|
|
2022-11-29 09:55:24 +08:00
|
|
|
let name = ctx
|
|
|
|
.name_of(nets.name_from_index(arc.net))
|
|
|
|
.to_str()
|
|
|
|
.unwrap()
|
|
|
|
.to_string();
|
2022-11-29 11:08:54 +08:00
|
|
|
let verbose = false;
|
2022-12-02 19:48:05 +08:00
|
|
|
//name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1";
|
2022-11-29 05:15:04 +08:00
|
|
|
|
2022-11-28 03:27:33 +08:00
|
|
|
while let Some(source) = queue.pop() {
|
|
|
|
if source.wire == arc.sink_wire {
|
2022-11-29 05:15:04 +08:00
|
|
|
found_sink = true;
|
2022-11-28 03:27:33 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-11-29 05:15:04 +08:00
|
|
|
if verbose {
|
|
|
|
log_info!("{}:\n", ctx.name_of_wire(source.wire).to_str().unwrap());
|
|
|
|
}
|
|
|
|
|
2022-11-28 03:27:33 +08:00
|
|
|
for pip in ctx.get_downhill_pips(source.wire) {
|
2022-11-30 09:20:14 +08:00
|
|
|
let pip_loc = ctx.pip_location(pip);
|
2022-11-28 03:27:33 +08:00
|
|
|
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;
|
2022-11-30 09:20:14 +08:00
|
|
|
}
|
2022-11-28 03:27:33 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-11-29 05:15:04 +08:00
|
|
|
/*let driver = self.wire_driver.get(&sink);
|
2022-11-28 03:27:33 +08:00
|
|
|
if let Some(&driver) = driver {
|
|
|
|
if driver != pip {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if *self.bound_pip.get(&driver).unwrap() != arc.net {
|
|
|
|
continue;
|
|
|
|
}
|
2022-11-29 05:15:04 +08:00
|
|
|
}*/
|
2022-11-28 03:27:33 +08:00
|
|
|
|
|
|
|
visited.insert(sink, pip);
|
|
|
|
|
2022-11-29 05:15:04 +08:00
|
|
|
if verbose {
|
|
|
|
log_info!(" {}\n", ctx.name_of_pip(pip).to_str().unwrap());
|
|
|
|
}
|
|
|
|
|
2022-11-28 03:47:16 +08:00
|
|
|
let delay =
|
|
|
|
source.cost + ctx.pip_delay(pip) + ctx.wire_delay(sink) + ctx.delay_epsilon();
|
2022-11-28 03:27:33 +08:00
|
|
|
let qw = QueuedWire::new(delay, ctx.estimate_delay(sink, arc.sink_wire), sink);
|
|
|
|
queue.push(qw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-29 09:55:24 +08:00
|
|
|
assert!(
|
|
|
|
found_sink,
|
|
|
|
"didn't find sink wire for net {} between {} and {}",
|
|
|
|
name,
|
|
|
|
ctx.name_of_wire(arc.source_wire).to_str().unwrap(),
|
|
|
|
ctx.name_of_wire(arc.sink_wire).to_str().unwrap()
|
|
|
|
);
|
2022-11-29 05:15:04 +08:00
|
|
|
|
2022-11-28 03:27:33 +08:00
|
|
|
let mut wire = arc.sink_wire;
|
|
|
|
while wire != arc.source_wire {
|
2022-11-29 05:15:04 +08:00
|
|
|
/*if verbose {
|
|
|
|
println!("Wire: {}", ctx.name_of_wire(wire).to_str().unwrap());
|
|
|
|
}*/
|
2022-11-29 09:55:24 +08:00
|
|
|
let pip = *visited.get(&wire).unwrap_or_else(|| {
|
|
|
|
panic!(
|
|
|
|
"Expected wire {} to have driving pip",
|
|
|
|
ctx.name_of_wire(wire).to_str().unwrap()
|
|
|
|
)
|
|
|
|
});
|
2022-11-28 03:27:33 +08:00
|
|
|
self.bind_pip(pip, arc.net);
|
|
|
|
wire = ctx.pip_src_wire(pip);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bind_pip(&mut self, pip: PipId, net: NetIndex) {
|
2022-11-29 05:15:04 +08:00
|
|
|
//assert!(!self.bound_pip.contains_key(&pip));
|
2022-11-28 03:27:33 +08:00
|
|
|
self.bound_pip.insert(pip, net);
|
|
|
|
}
|
2022-11-28 00:26:17 +08:00
|
|
|
}
|