awooter: partitioner improvements

This commit is contained in:
Lofty 2022-11-28 21:15:04 +00:00
parent a7e25754e1
commit a1fb22909c
5 changed files with 136 additions and 33 deletions

View File

@ -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>{};

View File

@ -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);

View File

@ -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
}
}

View File

@ -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;

View File

@ -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);
}
}