awooter: partitioner improvements
This commit is contained in:
parent
8fd983af15
commit
522dd3da7c
@ -214,15 +214,12 @@ extern "C" {
|
||||
bool npnr_context_debug(const Context *const ctx) { return ctx->debug; }
|
||||
int npnr_context_id(const Context *const ctx, const char *const str) { return ctx->id(str).hash(); }
|
||||
const char *npnr_context_name_of(const Context *const ctx, IdString str) { return ctx->nameOf(str); }
|
||||
const char *npnr_context_name_of_pip(const Context *const ctx, uint64_t pip) { return ctx->nameOfPip(unwrap_pip(pip)); }
|
||||
const char *npnr_context_name_of_wire(const Context *const ctx, uint64_t wire) { return ctx->nameOfWire(unwrap_wire(wire)); }
|
||||
bool npnr_context_verbose(const Context *const ctx) { return ctx->verbose; }
|
||||
|
||||
uint64_t npnr_context_get_netinfo_source_wire(const Context *const ctx, const NetInfo *const net) { return wrap(ctx->getNetinfoSourceWire(net)); }
|
||||
uint64_t npnr_context_get_netinfo_sink_wire(const Context *const ctx, const NetInfo *const net, const PortRef *const sink, uint32_t n) {
|
||||
if (ctx == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return wrap(ctx->getNetinfoSinkWire(net, *sink, n));
|
||||
}
|
||||
uint64_t npnr_context_get_netinfo_sink_wire(const Context *const ctx, const NetInfo *const net, const PortRef *const sink, uint32_t n) { return wrap(ctx->getNetinfoSinkWire(net, *sink, n)); }
|
||||
|
||||
uint32_t npnr_context_nets_leak(const Context *const ctx, int **names, NetInfo ***nets) {
|
||||
auto name_vec = std::vector<int>{};
|
||||
|
@ -23,9 +23,9 @@ pub extern "C" fn npnr_router_awooter(ctx: Option<NonNull<npnr::Context>>) -> bo
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_arcs_from_nets(ctx: &npnr::Context, nets: npnr::Nets) -> Vec<route::Arc> {
|
||||
fn extract_arcs_from_nets(ctx: &npnr::Context, nets: &npnr::Nets) -> Vec<route::Arc> {
|
||||
let mut arcs = vec![];
|
||||
for (name, net) in nets.iter() {
|
||||
for (name, net) in nets.to_vec().iter() {
|
||||
let net = unsafe { net.as_mut().unwrap() };
|
||||
if net.is_global() {
|
||||
continue;
|
||||
@ -36,7 +36,7 @@ fn extract_arcs_from_nets(ctx: &npnr::Context, nets: npnr::Nets) -> Vec<route::A
|
||||
let source = cell.location();
|
||||
let source_wire = ctx.source_wire(net);
|
||||
|
||||
for sink_ref in nets.users_by_name(*name).unwrap().iter() {
|
||||
for sink_ref in nets.users_by_name(**name).unwrap().iter() {
|
||||
let sink = sink_ref.cell().unwrap();
|
||||
let sink = sink.location();
|
||||
for sink_wire in ctx.sink_wires(net, *sink_ref) {
|
||||
@ -81,10 +81,10 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
log_info!("Found {} nets\n", nets_str.bold());
|
||||
|
||||
let mut count = 0;
|
||||
for (name, net) in nets.iter() {
|
||||
let _src = ctx.source_wire(*net);
|
||||
for (&name, net) in nets.to_vec().iter() {
|
||||
let _src = ctx.source_wire(**net);
|
||||
let net = unsafe { net.as_mut().unwrap() };
|
||||
let users = nets.users_by_name(*name).unwrap().iter();
|
||||
let users = nets.users_by_name(name).unwrap().iter();
|
||||
for user in users {
|
||||
count += ctx.sink_wires(net, *user).len();
|
||||
}
|
||||
@ -92,7 +92,9 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
|
||||
log_info!("Found {} arcs\n", count.to_string().bold());
|
||||
|
||||
let (name, net) = nets
|
||||
let binding = nets
|
||||
.to_vec();
|
||||
let (name, net) = binding
|
||||
.iter()
|
||||
.max_by_key(|(name, net)| {
|
||||
let net = unsafe { net.as_mut().unwrap() };
|
||||
@ -109,7 +111,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
|
||||
let net = unsafe { net.as_mut().unwrap() };
|
||||
let count = nets
|
||||
.users_by_name(*name)
|
||||
.users_by_name(**name)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.fold(0, |acc, sink| acc + ctx.sink_wires(net, *sink).len())
|
||||
@ -117,7 +119,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
|
||||
log_info!(
|
||||
"Highest non-global fanout net is {}\n",
|
||||
ctx.name_of(*name).to_str().unwrap().bold()
|
||||
ctx.name_of(**name).to_str().unwrap().bold()
|
||||
);
|
||||
log_info!(" with {} arcs\n", count.bold());
|
||||
|
||||
@ -126,7 +128,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
let mut x1 = 0;
|
||||
let mut y1 = 0;
|
||||
|
||||
for sink in nets.users_by_name(*name).unwrap().iter() {
|
||||
for sink in nets.users_by_name(**name).unwrap().iter() {
|
||||
let cell = sink.cell().unwrap().location();
|
||||
x0 = x0.min(cell.x);
|
||||
y0 = y0.min(cell.y);
|
||||
@ -147,12 +149,15 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
rayon::current_num_threads().to_string().bold()
|
||||
);
|
||||
|
||||
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
let arcs = extract_arcs_from_nets(ctx, nets);
|
||||
let arcs = extract_arcs_from_nets(ctx, &nets);
|
||||
|
||||
let (x_part, y_part, ne, se, sw, nw) = partition::find_partition_point_and_sanity_check(
|
||||
ctx,
|
||||
&nets,
|
||||
&arcs[..],
|
||||
pips,
|
||||
0,
|
||||
@ -166,7 +171,7 @@ fn route(ctx: &mut npnr::Context) -> bool {
|
||||
log_info!("Partitioning took {:.2}s\n", time.as_secs_f32());
|
||||
|
||||
let mut router = route::Router::new(Coord::new(0, 0), Coord::new(x_part, y_part));
|
||||
router.route(ctx, &ne);
|
||||
router.route(ctx, &nets, &ne);
|
||||
|
||||
/*log_info!("=== level 2 NE:\n");
|
||||
let _ = find_partition_point(&ne, x_start, x, y_start, y);
|
||||
|
@ -278,6 +278,14 @@ impl Context {
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of(self, s)) }
|
||||
}
|
||||
|
||||
pub fn name_of_pip(&self, pip: PipId) -> &CStr {
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of_pip(self, pip)) }
|
||||
}
|
||||
|
||||
pub fn name_of_wire(&self, wire: WireId) -> &CStr {
|
||||
unsafe { CStr::from_ptr(npnr_context_name_of_wire(self, wire)) }
|
||||
}
|
||||
|
||||
pub fn verbose(&self) -> bool {
|
||||
unsafe { npnr_context_verbose(self) }
|
||||
}
|
||||
@ -331,6 +339,8 @@ extern "C" {
|
||||
fn npnr_context_debug(ctx: *const Context) -> bool;
|
||||
fn npnr_context_id(ctx: *const Context, s: *const c_char) -> IdString;
|
||||
fn npnr_context_name_of(ctx: *const Context, s: IdString) -> *const libc::c_char;
|
||||
fn npnr_context_name_of_pip(ctx: *const Context, pip: PipId) -> *const libc::c_char;
|
||||
fn npnr_context_name_of_wire(ctx: *const Context, wire: WireId) -> *const libc::c_char;
|
||||
fn npnr_context_verbose(ctx: *const Context) -> bool;
|
||||
|
||||
fn npnr_context_get_netinfo_source_wire(ctx: *const Context, net: *const NetInfo) -> WireId;
|
||||
@ -376,6 +386,9 @@ pub struct Nets<'a> {
|
||||
_data: PhantomData<&'a Context>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Nets<'_> {}
|
||||
unsafe impl Sync for Nets<'_> {}
|
||||
|
||||
impl<'a> Nets<'a> {
|
||||
/// Create a new store for the nets of a context.
|
||||
///
|
||||
@ -430,8 +443,19 @@ impl<'a> Nets<'a> {
|
||||
self.nets.len()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, IdString, *mut NetInfo> {
|
||||
self.nets.iter()
|
||||
pub fn name_from_index(&self, index: NetIndex) -> IdString {
|
||||
self.index_to_net[index.0 as usize]
|
||||
}
|
||||
|
||||
pub fn net_from_index(&self, index: NetIndex) -> *mut NetInfo {
|
||||
*self.nets.get(&self.name_from_index(index)).unwrap()
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<(&IdString, &*mut NetInfo)> {
|
||||
let mut v = Vec::new();
|
||||
v.extend(self.nets.iter());
|
||||
v.sort_by_key(|(name, _net)| name.0);
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ impl From<npnr::Loc> for Coord {
|
||||
|
||||
pub fn find_partition_point(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
x_start: i32,
|
||||
@ -91,6 +92,7 @@ pub fn find_partition_point(
|
||||
while x_diff != 0 {
|
||||
(ne, se, sw, nw) = partition(
|
||||
ctx,
|
||||
nets,
|
||||
arcs,
|
||||
pips,
|
||||
x,
|
||||
@ -135,6 +137,7 @@ pub fn find_partition_point(
|
||||
|
||||
(ne, se, sw, nw) = partition(
|
||||
ctx,
|
||||
nets,
|
||||
arcs,
|
||||
pips,
|
||||
x,
|
||||
@ -200,6 +203,7 @@ fn split_line_over_y(line: (npnr::Loc, npnr::Loc), y_location: i32) -> i32 {
|
||||
// A big thank you to @Spacecat-chan for fixing my broken and buggy partition code.
|
||||
fn partition<R: RangeBounds<i32>>(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
x: i32,
|
||||
@ -243,6 +247,22 @@ fn partition<R: RangeBounds<i32>>(
|
||||
if loc.x == x && loc.y == y {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_general_routing = |wire: &str| {
|
||||
wire.contains("H01") || wire.contains("V01") ||
|
||||
wire.contains("H02") || wire.contains("V02") ||
|
||||
wire.contains("H06") || wire.contains("V06")
|
||||
};
|
||||
|
||||
let src_wire = ctx.pip_src_wire(pip);
|
||||
let dst_wire = ctx.pip_dst_wire(pip);
|
||||
let src_name = ctx.name_of_wire(src_wire).to_str().unwrap();
|
||||
let dst_name = ctx.name_of_wire(dst_wire).to_str().unwrap();
|
||||
if !is_general_routing(src_name) || !is_general_routing(dst_name) {
|
||||
// ECP5 hack: whitelist allowed wires.
|
||||
continue;
|
||||
}
|
||||
|
||||
candidates += 1;
|
||||
|
||||
let pip_arc = std::sync::Arc::new((pip, AtomicUsize::new(0)));
|
||||
@ -328,7 +348,7 @@ fn partition<R: RangeBounds<i32>>(
|
||||
|
||||
let progress = ProgressBar::new(arcs.len() as u64);
|
||||
progress.set_style(
|
||||
ProgressStyle::with_template("[{elapsed}] [{bar:40.cyan/blue}] {msg}")
|
||||
ProgressStyle::with_template("[{elapsed}] [{bar:40.cyan/blue}] {msg:30!}")
|
||||
.unwrap()
|
||||
.progress_chars("━╸ "),
|
||||
);
|
||||
@ -362,6 +382,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 = name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1";
|
||||
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())]
|
||||
@ -383,6 +405,10 @@ fn partition<R: RangeBounds<i32>>(
|
||||
let selected_pip = find_best_pip(pips, arc);
|
||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
if verbose {
|
||||
log_info!("split arc {} to {} vertically across pip {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(selected_pip).to_str().unwrap());
|
||||
}
|
||||
|
||||
let (src_to_pip, pip_to_dst) = arc.split(ctx, selected_pip);
|
||||
let (seg1, seg2) = match (source_is_north, source_is_east) {
|
||||
(true, true) => (Segment::Northeast, Segment::Southeast),
|
||||
@ -410,6 +436,10 @@ fn partition<R: RangeBounds<i32>>(
|
||||
let selected_pip = find_best_pip(pips, arc);
|
||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
if verbose {
|
||||
log_info!("split arc {} to {} horizontally across pip {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(selected_pip).to_str().unwrap());
|
||||
}
|
||||
|
||||
let (src_to_pip, pip_to_dst) = arc.split(ctx, selected_pip);
|
||||
let (seg1, seg2) = match (source_is_north, source_is_east) {
|
||||
(true, true) => (Segment::Northeast, Segment::Northwest),
|
||||
@ -458,6 +488,10 @@ fn partition<R: RangeBounds<i32>>(
|
||||
let vert_pip = find_best_pip(pips, arc);
|
||||
explored_pips.fetch_add(pips.len(), std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
if verbose {
|
||||
log_info!("split arc {} to {} across pips {} and {}\n", ctx.name_of_wire(arc.get_source_wire()).to_str().unwrap(), ctx.name_of_wire(arc.get_sink_wire()).to_str().unwrap(), ctx.name_of_pip(horiz_pip).to_str().unwrap(), ctx.name_of_pip(vert_pip).to_str().unwrap());
|
||||
}
|
||||
|
||||
let horiz_loc: Coord = ctx.pip_location(horiz_pip).into();
|
||||
let horiz_is_east = horiz_loc.is_east_of(&partition_coords);
|
||||
let (src_to_mid1, mid1_to_mid2, mid2_to_dst) = if horiz_is_east == source_is_east {
|
||||
@ -610,6 +644,7 @@ fn partition<R: RangeBounds<i32>>(
|
||||
|
||||
pub fn find_partition_point_and_sanity_check(
|
||||
ctx: &npnr::Context,
|
||||
nets: &npnr::Nets,
|
||||
arcs: &[Arc],
|
||||
pips: &[npnr::PipId],
|
||||
x_start: i32,
|
||||
@ -618,7 +653,7 @@ pub fn find_partition_point_and_sanity_check(
|
||||
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, 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;
|
||||
|
@ -1,4 +1,6 @@
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
use std::{collections::{BinaryHeap, HashMap}, time::Duration};
|
||||
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
|
||||
use crate::{
|
||||
npnr::{self, NetIndex, PipId},
|
||||
@ -64,6 +66,9 @@ impl Arc {
|
||||
pub fn get_sink_wire(&self) -> npnr::WireId {
|
||||
self.sink_wire
|
||||
}
|
||||
pub fn net(&self) -> npnr::NetIndex {
|
||||
self.net
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -118,34 +123,62 @@ impl Router {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn route(&mut self, ctx: &npnr::Context, arcs: &[Arc]) {
|
||||
pub fn route(&mut self, ctx: &npnr::Context, nets: &npnr::Nets, arcs: &[Arc]) {
|
||||
let progress = ProgressBar::new(arcs.len() as u64);
|
||||
progress.set_style(
|
||||
ProgressStyle::with_template("[{elapsed}] [{bar:40.magenta/red}] {msg:30!}")
|
||||
.unwrap()
|
||||
.progress_chars("━╸ "),
|
||||
);
|
||||
|
||||
progress.enable_steady_tick(Duration::from_secs_f32(0.2));
|
||||
for arc in arcs {
|
||||
self.route_arc(ctx, arc);
|
||||
let net = unsafe { nets.net_from_index(arc.net).as_ref().unwrap() };
|
||||
let name = ctx.name_of(nets.name_from_index(arc.net)).to_str().unwrap().to_string();
|
||||
|
||||
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);
|
||||
}
|
||||
progress.finish_and_clear()
|
||||
}
|
||||
|
||||
fn route_arc(&mut self, ctx: &npnr::Context, arc: &Arc) {
|
||||
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;
|
||||
|
||||
let name = ctx.name_of(nets.name_from_index(arc.net)).to_str().unwrap().to_string();
|
||||
let verbose = name == "decode_to_execute_IS_RS2_SIGNED_LUT4_D_1_Z_CCU2C_B1_S0_CCU2C_S0_3_B1";
|
||||
|
||||
while let Some(source) = queue.pop() {
|
||||
if source.wire == arc.sink_wire {
|
||||
panic!("found the sink!");
|
||||
found_sink = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if verbose {
|
||||
log_info!("{}:\n", ctx.name_of_wire(source.wire).to_str().unwrap());
|
||||
}
|
||||
|
||||
for pip in ctx.get_downhill_pips(source.wire) {
|
||||
let pip_loc = ctx.pip_location(pip);
|
||||
/*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))
|
||||
@ -175,7 +208,7 @@ impl Router {
|
||||
continue;
|
||||
}
|
||||
|
||||
let driver = self.wire_driver.get(&sink);
|
||||
/*let driver = self.wire_driver.get(&sink);
|
||||
if let Some(&driver) = driver {
|
||||
if driver != pip {
|
||||
continue;
|
||||
@ -183,10 +216,14 @@ impl Router {
|
||||
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 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);
|
||||
@ -194,16 +231,21 @@ impl Router {
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
let mut wire = arc.sink_wire;
|
||||
while wire != arc.source_wire {
|
||||
let pip = *visited.get(&wire).unwrap();
|
||||
/*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);
|
||||
}
|
||||
}
|
||||
|
||||
fn bind_pip(&mut self, pip: PipId, net: NetIndex) {
|
||||
assert!(!self.bound_pip.contains_key(&pip));
|
||||
//assert!(!self.bound_pip.contains_key(&pip));
|
||||
self.bound_pip.insert(pip, net);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user