2022-11-27 01:11:18 +08:00
use std ::{
collections ::HashMap ,
ptr ::NonNull ,
sync ::{ atomic ::AtomicUsize , Mutex } ,
} ;
2022-11-25 13:34:46 +08:00
use colored ::Colorize ;
use indicatif ::{ ProgressBar , ProgressStyle } ;
use rayon ::prelude ::* ;
2022-11-20 11:20:09 +08:00
#[ macro_use ]
mod npnr ;
2022-11-21 10:48:00 +08:00
enum Subpartition {
Part ( Box < Partition > ) ,
Nets ( Vec < Net > ) ,
}
struct Partition {
parts : [ Option < Subpartition > ; 4 ] ,
2022-11-23 11:31:50 +08:00
borders : [ [ Vec < npnr ::WireId > ; 4 ] ; 4 ] ,
2022-11-21 10:48:00 +08:00
}
struct Net {
source : npnr ::WireId ,
2022-11-23 11:31:50 +08:00
sinks : Vec < npnr ::WireId > ,
2022-11-21 10:48:00 +08:00
}
2022-11-20 11:20:09 +08:00
#[ no_mangle ]
pub extern " C " fn npnr_router_awooter ( ctx : Option < NonNull < npnr ::Context > > ) -> bool {
std ::panic ::catch_unwind ( move | | {
let ctx : & mut npnr ::Context = unsafe { ctx . expect ( " non-null context " ) . as_mut ( ) } ;
route ( ctx )
} )
. unwrap_or_else ( | x | {
if let Ok ( x ) = x . downcast ::< String > ( ) {
log_error! ( " caught panic: {} " , x ) ;
}
false
} )
}
2022-11-23 11:31:50 +08:00
type ArcVec = Vec < ( ( i32 , i32 ) , ( i32 , i32 ) ) > ;
fn find_partition_point (
2022-11-25 13:34:46 +08:00
ctx : & npnr ::Context ,
nets : & npnr ::Nets ,
pips : & [ npnr ::PipId ] ,
2022-11-23 11:31:50 +08:00
x_start : i32 ,
x_finish : i32 ,
y_start : i32 ,
y_finish : i32 ,
) -> ( i32 , i32 , ArcVec , ArcVec , ArcVec , ArcVec ) {
let mut x = ( ( x_finish - x_start ) / 2 ) + x_start ;
let mut y = ( ( y_finish - y_start ) / 2 ) + y_start ;
let mut x_diff = ( x_finish - x_start ) / 4 ;
let mut y_diff = ( y_finish - y_start ) / 4 ;
2022-11-26 23:35:31 +08:00
let mut ne ;
let mut se ;
let mut sw ;
let mut nw ;
2022-11-23 11:31:50 +08:00
while x_diff ! = 0 {
2022-11-25 13:34:46 +08:00
( ne , se , sw , nw ) = partition_nets ( ctx , nets , pips , x , y ) ;
2022-11-23 11:31:50 +08:00
let north = ne . len ( ) + nw . len ( ) ;
let south = se . len ( ) + sw . len ( ) ;
2022-11-25 13:34:46 +08:00
let nets = ( north + south ) as f64 ;
let ne_dist = f64 ::abs ( ( ( ne . len ( ) as f64 ) / nets ) - 0.25 ) ;
let se_dist = f64 ::abs ( ( ( se . len ( ) as f64 ) / nets ) - 0.25 ) ;
let sw_dist = f64 ::abs ( ( ( sw . len ( ) as f64 ) / nets ) - 0.25 ) ;
let nw_dist = f64 ::abs ( ( ( nw . len ( ) as f64 ) / nets ) - 0.25 ) ;
let distortion = 100.0 * ( ne_dist + se_dist + sw_dist + nw_dist ) ;
// Stop early if Good Enough.
if distortion < = 5.0 {
return ( x , y , ne , se , sw , nw ) ;
}
2022-11-26 20:44:17 +08:00
x + = match north . cmp ( & south ) {
std ::cmp ::Ordering ::Less = > x_diff ,
std ::cmp ::Ordering ::Equal = > 0 ,
std ::cmp ::Ordering ::Greater = > - x_diff ,
} ;
2022-11-23 11:31:50 +08:00
let east = ne . len ( ) + se . len ( ) ;
let west = nw . len ( ) + sw . len ( ) ;
2022-11-26 20:44:17 +08:00
y + = match east . cmp ( & west ) {
std ::cmp ::Ordering ::Less = > y_diff ,
std ::cmp ::Ordering ::Equal = > 0 ,
std ::cmp ::Ordering ::Greater = > - y_diff ,
} ;
2022-11-23 11:31:50 +08:00
x_diff > > = 1 ;
y_diff > > = 1 ;
}
2022-11-25 13:34:46 +08:00
( ne , se , sw , nw ) = partition_nets ( ctx , nets , pips , x , y ) ;
2022-11-23 11:31:50 +08:00
let north = ne . len ( ) + nw . len ( ) ;
let south = se . len ( ) + sw . len ( ) ;
let nets = ( north + south ) as f64 ;
let ne_dist = f64 ::abs ( ( ( ne . len ( ) as f64 ) / nets ) - 0.25 ) ;
let se_dist = f64 ::abs ( ( ( se . len ( ) as f64 ) / nets ) - 0.25 ) ;
let sw_dist = f64 ::abs ( ( ( sw . len ( ) as f64 ) / nets ) - 0.25 ) ;
let nw_dist = f64 ::abs ( ( ( nw . len ( ) as f64 ) / nets ) - 0.25 ) ;
log_info! (
" Distortion: {:.02}% \n " ,
100.0 * ( ne_dist + se_dist + sw_dist + nw_dist )
) ;
( x , y , ne , se , sw , nw )
}
2022-11-26 23:35:31 +08:00
/// finds the y location a line would be split at if you split it at a certain x location
///
/// the function assumes the line goes on forever in both directions, and it truncates the actual coordinate
2022-11-27 01:09:20 +08:00
fn split_line_over_x ( line : ( npnr ::Loc , npnr ::Loc ) , x_location : i32 ) -> i32 {
2022-11-26 23:35:31 +08:00
if line . 0. x = = line . 0. y {
// the line is a straight line in the direction, there is either infinite solutions, or none
// we simply average the y coordinate to give a "best effort" guess
return ( line . 0. y + line . 1. y ) / 2 ;
}
let x_diff = line . 0. x - line . 1. x ;
let y_diff = line . 0. y - line . 1. y ;
// i hope for no overflows, maybe promote to i64 to be sure?
( y_diff * x_location + line . 0. y * x_diff - line . 0. x * y_diff ) / x_diff
}
/// finds the x location a line would be split at if you split it at a certain y location, assuming the line goes on forever in both directions
fn split_line_over_y ( line : ( npnr ::Loc , npnr ::Loc ) , y_location : i32 ) -> i32 {
// laziness supreme!
split_line_over_x (
(
npnr ::Loc {
x : line . 0. y ,
y : line . 0. x ,
z : 0 ,
} ,
npnr ::Loc {
x : line . 1. y ,
y : line . 1. x ,
z : 0 ,
} ,
) ,
y_location ,
)
}
enum Segment {
Northeast ,
Southeast ,
Southwest ,
Northwest ,
}
// A big thank you to @Spacecat-chan for fixing my broken and buggy partition code.
2022-11-25 13:34:46 +08:00
fn partition_nets (
ctx : & npnr ::Context ,
nets : & npnr ::Nets ,
pips : & [ npnr ::PipId ] ,
x : i32 ,
y : i32 ,
) -> ( ArcVec , ArcVec , ArcVec , ArcVec ) {
2022-11-26 23:35:31 +08:00
let mut pips_n = HashMap ::new ( ) ;
let mut pips_e = HashMap ::new ( ) ;
let mut pips_s = HashMap ::new ( ) ;
let mut pips_w = HashMap ::new ( ) ;
2022-11-25 13:34:46 +08:00
let mut ne = Vec ::new ( ) ;
let mut se = Vec ::new ( ) ;
let mut sw = Vec ::new ( ) ;
let mut nw = Vec ::new ( ) ;
2022-11-27 01:09:20 +08:00
let mut part_horiz = AtomicUsize ::new ( 0 ) ;
let mut part_vert = AtomicUsize ::new ( 0 ) ;
let mut part_diag = AtomicUsize ::new ( 0 ) ;
2022-11-25 13:34:46 +08:00
let x_str = format! ( " X = {} " , x ) ;
let y_str = format! ( " Y = {} " , y ) ;
log_info! (
" Partitioning arcs along {}, {} \n " ,
2022-11-26 20:44:17 +08:00
x_str . bold ( ) ,
y_str . bold ( )
2022-11-25 13:34:46 +08:00
) ;
2022-11-26 20:44:17 +08:00
// BUG: because pips don't specify direction, this puts pips of opposite directions
// in the same entry. This is bad, since it could lead to selecting a pip of the
// wrong direction.
2022-11-26 23:35:31 +08:00
//
// Possibly fixed? I need to double-check.
2022-11-27 01:11:18 +08:00
2022-11-26 23:35:31 +08:00
let mut candidates = 0 ;
let mut north = 0 ;
let mut east = 0 ;
let mut south = 0 ;
let mut west = 0 ;
2022-11-25 13:34:46 +08:00
for & pip in pips {
let loc = ctx . pip_location ( pip ) ;
if loc . x = = x | | loc . y = = y {
2022-11-26 23:35:31 +08:00
let dir = ctx . pip_direction ( pip ) ;
// This pip seems internal; skip it.
if dir . x = = 0 & & dir . y = = 0 {
continue ;
}
2022-11-27 01:09:20 +08:00
candidates + = 1 ;
if dir . x < 0 {
2022-11-26 23:35:31 +08:00
north + = 1 ;
pips_n
2022-11-27 01:11:18 +08:00
. entry ( ( loc . x , loc . y ) )
. and_modify ( | pip_list : & mut Vec < ( npnr ::PipId , Vec < npnr ::IdString > ) > | {
pip_list . push ( ( pip , Vec ::new ( ) ) )
} )
. or_insert_with ( | | vec! [ ( pip , Vec ::new ( ) ) ] ) ;
2022-11-26 23:35:31 +08:00
}
2022-11-27 01:09:20 +08:00
if dir . x > 0 {
2022-11-26 23:35:31 +08:00
south + = 1 ;
pips_s
2022-11-27 01:11:18 +08:00
. entry ( ( loc . x , loc . y ) )
. and_modify ( | pip_list : & mut Vec < ( npnr ::PipId , Vec < npnr ::IdString > ) > | {
pip_list . push ( ( pip , Vec ::new ( ) ) )
} )
. or_insert_with ( | | vec! [ ( pip , Vec ::new ( ) ) ] ) ;
2022-11-26 23:35:31 +08:00
}
2022-11-27 01:09:20 +08:00
if dir . y < 0 {
2022-11-26 23:35:31 +08:00
east + = 1 ;
pips_e
2022-11-27 01:11:18 +08:00
. entry ( ( loc . x , loc . y ) )
. and_modify ( | pip_list : & mut Vec < ( npnr ::PipId , Vec < npnr ::IdString > ) > | {
pip_list . push ( ( pip , Vec ::new ( ) ) )
} )
. or_insert_with ( | | vec! [ ( pip , Vec ::new ( ) ) ] ) ;
2022-11-26 23:35:31 +08:00
}
2022-11-26 20:44:17 +08:00
2022-11-27 01:09:20 +08:00
if dir . y > 0 {
2022-11-26 23:35:31 +08:00
west + = 1 ;
pips_w
2022-11-27 01:11:18 +08:00
. entry ( ( loc . x , loc . y ) )
. and_modify ( | pip_list : & mut Vec < ( npnr ::PipId , Vec < npnr ::IdString > ) > | {
pip_list . push ( ( pip , Vec ::new ( ) ) )
} )
. or_insert_with ( | | vec! [ ( pip , Vec ::new ( ) ) ] ) ;
2022-11-26 23:35:31 +08:00
}
2022-11-25 13:34:46 +08:00
}
}
2022-11-27 01:11:18 +08:00
log_info! (
" Out of {} candidate pips: \n " ,
candidates . to_string ( ) . bold ( )
) ;
2022-11-26 23:35:31 +08:00
log_info! ( " {} are north-bound \n " , north . to_string ( ) . bold ( ) ) ;
log_info! ( " {} are east-bound \n " , east . to_string ( ) . bold ( ) ) ;
log_info! ( " {} are south-bound \n " , south . to_string ( ) . bold ( ) ) ;
log_info! ( " {} are west-bound \n " , west . to_string ( ) . bold ( ) ) ;
2022-11-27 01:09:20 +08:00
let pips_n = Mutex ::new ( pips_n ) ;
let pips_e = Mutex ::new ( pips_e ) ;
let pips_s = Mutex ::new ( pips_s ) ;
let pips_w = Mutex ::new ( pips_w ) ;
2022-11-25 13:34:46 +08:00
let progress = ProgressBar ::new ( nets . len ( ) as u64 ) ;
progress . set_style (
2022-11-26 20:44:17 +08:00
ProgressStyle ::with_template ( " [{elapsed}] [{bar:40.cyan/blue}] {msg} " )
. unwrap ( )
. progress_chars ( " ━╸ " ) ,
2022-11-25 13:34:46 +08:00
) ;
2022-11-27 01:09:20 +08:00
let mut explored_pips = AtomicUsize ::new ( 0 ) ;
2022-11-26 23:35:31 +08:00
2022-11-25 13:34:46 +08:00
for ( name , net ) in nets . iter ( ) {
let mut message = ctx . name_of ( * name ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
2022-11-25 15:12:14 +08:00
let message = if message . len ( ) > 31 {
message . truncate ( 28 ) ;
2022-11-25 13:34:46 +08:00
format! ( " {} ... " , message )
} else {
message
} ;
progress . set_message ( message ) ;
progress . inc ( 1 ) ;
let net = unsafe { net . as_mut ( ) . unwrap ( ) } ;
if net . is_global ( ) {
continue ;
}
let source = unsafe { net . driver ( ) . as_ref ( ) . unwrap ( ) } ;
let source = source . cell ( ) ;
if source . is_none ( ) {
continue ;
}
let source = source . unwrap ( ) . location ( ) ;
let source_is_north = source . x < x ;
let source_is_east = source . y < y ;
let source_wire = ctx . source_wire ( net ) ;
2022-11-26 23:35:31 +08:00
// I want to merge the "find best pip" code into a closure
// but doing so gives lifetime errors, and you can't describe
// lifetimes in a closure, as far as I can tell.
2022-11-27 01:11:18 +08:00
let arcs = nets
. users_by_name ( * name )
. unwrap ( )
. iter ( )
. flat_map ( | sink | {
let sink = unsafe { sink . as_ref ( ) . unwrap ( ) } ;
ctx . sink_wires ( net , sink )
. into_iter ( )
. map ( move | sink_wire | ( sink , sink_wire ) )
} )
. flat_map ( | ( sink , sink_wire ) | {
let sink_loc = sink . cell ( ) . unwrap ( ) . location ( ) ;
let sink_is_north = sink_loc . x < x ;
let sink_is_east = sink_loc . y < y ;
if source_is_north = = sink_is_north & & source_is_east = = sink_is_east {
let arc = ( ( source . x , source . y ) , ( sink_loc . x , sink_loc . y ) ) ;
let seg = match ( source_is_north , source_is_east ) {
( true , true ) = > Segment ::Northeast ,
( true , false ) = > Segment ::Northwest ,
( false , true ) = > Segment ::Southeast ,
( false , false ) = > Segment ::Southwest ,
} ;
vec! [ ( seg , arc ) ]
} else if source_is_north ! = sink_is_north & & source_is_east = = sink_is_east {
let middle = ( x , ( source . y + sink_loc . y ) / 2 ) ;
2022-11-27 02:57:53 +08:00
let middle = ( middle . 0. clamp ( 1 , ctx . grid_dim_x ( ) - 1 ) , middle . 1. clamp ( 1 , ctx . grid_dim_y ( ) - 1 ) ) ;
2022-11-27 01:11:18 +08:00
let mut pips_s = pips_s . lock ( ) . unwrap ( ) ;
let mut pips_n = pips_n . lock ( ) . unwrap ( ) ;
let pips = match source_is_north {
true = > pips_s . get_mut ( & middle ) . unwrap ( ) ,
false = > pips_n . get_mut ( & middle ) . unwrap ( ) ,
} ;
let ( selected_pip , pip_uses ) = pips
. iter_mut ( )
. min_by_key ( | ( pip , uses ) | {
let src_to_pip =
ctx . estimate_delay ( source_wire , ctx . pip_src_wire ( * pip ) ) ;
let pip_to_snk = ctx . estimate_delay ( ctx . pip_dst_wire ( * pip ) , sink_wire ) ;
let uses = uses . len ( ) - ( uses . contains ( name ) as usize ) ;
( 1000.0 * ( src_to_pip + ( ( uses + 1 ) as f32 ) * pip_to_snk ) ) as u64
} )
. unwrap ( ) ;
pip_uses . push ( * name ) ;
let selected_pip = * selected_pip ;
explored_pips . fetch_add ( pips . len ( ) , std ::sync ::atomic ::Ordering ::SeqCst ) ;
let pip_loc = ctx . pip_location ( selected_pip ) ;
let src_to_pip = ( ( source . x , source . y ) , ( pip_loc . x , pip_loc . y ) ) ;
let pip_to_dst = ( ( pip_loc . x , pip_loc . y ) , ( sink_loc . x , sink_loc . y ) ) ;
let ( seg1 , seg2 ) = match ( source_is_north , source_is_east ) {
( true , true ) = > ( Segment ::Northeast , Segment ::Southeast ) ,
( true , false ) = > ( Segment ::Northwest , Segment ::Southwest ) ,
( false , true ) = > ( Segment ::Southeast , Segment ::Northeast ) ,
( false , false ) = > ( Segment ::Southwest , Segment ::Northwest ) ,
} ;
part_horiz . fetch_add ( 1 , std ::sync ::atomic ::Ordering ::SeqCst ) ;
vec! [ ( seg1 , src_to_pip ) , ( seg2 , pip_to_dst ) ]
} else if source_is_north = = sink_is_north & & source_is_east ! = sink_is_east {
let middle = ( ( source . x + sink_loc . x ) / 2 , y ) ;
2022-11-27 02:57:53 +08:00
let middle = ( middle . 0. clamp ( 1 , ctx . grid_dim_x ( ) - 1 ) , middle . 1. clamp ( 1 , ctx . grid_dim_y ( ) - 1 ) ) ;
2022-11-27 01:11:18 +08:00
let mut pips_e = pips_e . lock ( ) . unwrap ( ) ;
let mut pips_w = pips_w . lock ( ) . unwrap ( ) ;
let pips = match source_is_east {
true = > pips_w . get_mut ( & middle ) . unwrap ( ) ,
2022-11-27 02:57:53 +08:00
false = > pips_e . get_mut ( & middle ) . unwrap_or_else ( | | panic! ( " \n while partitioning an arc between ( {} , {} ) and ( {} , {} ) \n ( {} , {} ) does not exist in the pip library \n " , source . x , source . y , sink_loc . x , sink_loc . y , middle . 0 , middle . 1 ) ) ,
2022-11-27 01:11:18 +08:00
} ;
let ( selected_pip , pip_uses ) = pips
. iter_mut ( )
. min_by_key ( | ( pip , uses ) | {
let src_to_pip =
ctx . estimate_delay ( source_wire , ctx . pip_src_wire ( * pip ) ) ;
let pip_to_snk = ctx . estimate_delay ( ctx . pip_dst_wire ( * pip ) , sink_wire ) ;
let uses = uses . len ( ) - ( uses . contains ( name ) as usize ) ;
( 1000.0 * ( src_to_pip + ( ( uses + 1 ) as f32 ) * pip_to_snk ) ) as u64
} )
. unwrap ( ) ;
pip_uses . push ( * name ) ;
let selected_pip = * selected_pip ;
explored_pips . fetch_add ( pips . len ( ) , std ::sync ::atomic ::Ordering ::SeqCst ) ;
let pip_loc = ctx . pip_location ( selected_pip ) ;
let src_to_pip = ( ( source . x , source . y ) , ( pip_loc . x , pip_loc . y ) ) ;
let pip_to_dst = ( ( pip_loc . x , pip_loc . y ) , ( sink_loc . x , sink_loc . y ) ) ;
let ( seg1 , seg2 ) = match ( source_is_north , source_is_east ) {
( true , true ) = > ( Segment ::Northeast , Segment ::Northwest ) ,
( true , false ) = > ( Segment ::Northwest , Segment ::Northeast ) ,
( false , true ) = > ( Segment ::Southeast , Segment ::Southwest ) ,
( false , false ) = > ( Segment ::Southwest , Segment ::Southeast ) ,
} ;
part_vert . fetch_add ( 1 , std ::sync ::atomic ::Ordering ::SeqCst ) ;
vec! [ ( seg1 , src_to_pip ) , ( seg2 , pip_to_dst ) ]
} else {
let middle = ( x , split_line_over_x ( ( source , sink_loc ) , x ) ) ;
2022-11-27 02:57:53 +08:00
let middle = ( middle . 0. clamp ( 1 , ctx . grid_dim_x ( ) - 1 ) , middle . 1. clamp ( 1 , ctx . grid_dim_y ( ) - 1 ) ) ;
2022-11-27 01:11:18 +08:00
let mut pips_e = pips_e . lock ( ) . unwrap ( ) ;
let mut pips_w = pips_w . lock ( ) . unwrap ( ) ;
let pips = match source_is_east {
true = > pips_w . get_mut ( & middle ) . unwrap ( ) ,
false = > pips_e . get_mut ( & middle ) . unwrap ( ) ,
} ;
let ( horiz_pip , pip_uses ) = pips
. iter_mut ( )
. min_by_key ( | ( pip , uses ) | {
let src_to_pip =
ctx . estimate_delay ( source_wire , ctx . pip_src_wire ( * pip ) ) ;
let pip_to_snk = ctx . estimate_delay ( ctx . pip_dst_wire ( * pip ) , sink_wire ) ;
let uses = uses . len ( ) - ( uses . contains ( name ) as usize ) ;
( 1000.0 * ( src_to_pip + ( ( uses + 1 ) as f32 ) * pip_to_snk ) ) as u64
} )
. unwrap ( ) ;
pip_uses . push ( * name ) ;
let horiz_pip = * horiz_pip ;
explored_pips . fetch_add ( pips . len ( ) , std ::sync ::atomic ::Ordering ::SeqCst ) ;
let middle = ( split_line_over_y ( ( source , sink_loc ) , y ) , y ) ;
2022-11-27 02:57:53 +08:00
let middle = ( middle . 0. clamp ( 1 , ctx . grid_dim_x ( ) - 1 ) , middle . 1. clamp ( 1 , ctx . grid_dim_y ( ) - 1 ) ) ;
2022-11-27 01:11:18 +08:00
let mut pips_s = pips_s . lock ( ) . unwrap ( ) ;
let mut pips_n = pips_n . lock ( ) . unwrap ( ) ;
let pips = match source_is_north {
true = > pips_s . get_mut ( & middle ) . unwrap ( ) ,
false = > pips_n . get_mut ( & middle ) . unwrap ( ) ,
2022-11-26 23:35:31 +08:00
} ;
2022-11-27 01:11:18 +08:00
let ( vert_pip , pip_uses ) = pips
. iter_mut ( )
. min_by_key ( | ( pip , uses ) | {
let src_to_pip =
ctx . estimate_delay ( source_wire , ctx . pip_src_wire ( * pip ) ) ;
let pip_to_snk = ctx . estimate_delay ( ctx . pip_dst_wire ( * pip ) , sink_wire ) ;
let uses = uses . len ( ) - ( uses . contains ( name ) as usize ) ;
( 1000.0 * ( src_to_pip + ( ( uses + 1 ) as f32 ) * pip_to_snk ) ) as u64
} )
. unwrap ( ) ;
pip_uses . push ( * name ) ;
let vert_pip = * vert_pip ;
explored_pips . fetch_add ( pips . len ( ) , std ::sync ::atomic ::Ordering ::SeqCst ) ;
let horiz_loc = ctx . pip_location ( horiz_pip ) ;
let horiz_is_east = horiz_loc . y < y ;
let vert_loc = ctx . pip_location ( vert_pip ) ;
let ( src_to_mid1 , mid1_to_mid2 , mid2_to_dst ) =
if horiz_is_east = = source_is_east {
(
( ( source . x , source . y ) , ( horiz_loc . x , horiz_loc . y ) ) ,
( ( horiz_loc . x , horiz_loc . y ) , ( vert_loc . x , vert_loc . y ) ) ,
( ( vert_loc . x , vert_loc . y ) , ( sink_loc . x , sink_loc . y ) ) ,
)
} else {
(
( ( source . x , source . y ) , ( vert_loc . x , vert_loc . y ) ) ,
( ( vert_loc . x , vert_loc . y ) , ( horiz_loc . x , horiz_loc . y ) ) ,
( ( horiz_loc . x , horiz_loc . y ) , ( sink_loc . x , sink_loc . y ) ) ,
)
} ;
let ( seg1 , seg2 , seg3 ) = match ( source_is_north , source_is_east , horiz_is_east )
{
( true , true , true ) = > {
( Segment ::Northeast , Segment ::Southeast , Segment ::Southwest )
}
( true , true , false ) = > {
( Segment ::Northeast , Segment ::Northwest , Segment ::Southwest )
}
( true , false , true ) = > {
( Segment ::Northwest , Segment ::Northeast , Segment ::Southeast )
}
( true , false , false ) = > {
( Segment ::Northwest , Segment ::Southwest , Segment ::Southeast )
}
( false , true , true ) = > {
( Segment ::Southeast , Segment ::Northeast , Segment ::Northwest )
}
( false , true , false ) = > {
( Segment ::Southeast , Segment ::Southwest , Segment ::Northwest )
}
( false , false , true ) = > {
( Segment ::Southwest , Segment ::Southeast , Segment ::Northeast )
}
( false , false , false ) = > {
( Segment ::Southwest , Segment ::Northwest , Segment ::Northeast )
}
} ;
part_diag . fetch_add ( 1 , std ::sync ::atomic ::Ordering ::SeqCst ) ;
vec! [
( seg1 , src_to_mid1 ) ,
( seg2 , mid1_to_mid2 ) ,
( seg3 , mid2_to_dst ) ,
]
}
} )
. collect ::< Vec < _ > > ( ) ;
2022-11-27 01:09:20 +08:00
for ( segment , arc ) in arcs {
match segment {
Segment ::Northeast = > ne . push ( arc ) ,
Segment ::Southeast = > se . push ( arc ) ,
Segment ::Southwest = > sw . push ( arc ) ,
Segment ::Northwest = > nw . push ( arc ) ,
2022-11-25 13:34:46 +08:00
}
}
}
2022-11-25 15:12:14 +08:00
progress . finish_and_clear ( ) ;
2022-11-25 13:34:46 +08:00
2022-11-27 01:11:18 +08:00
log_info! (
" {} pips explored \n " ,
explored_pips . get_mut ( ) . to_string ( ) . bold ( )
) ;
2022-11-26 23:35:31 +08:00
2022-11-25 13:34:46 +08:00
let north = ne . len ( ) + nw . len ( ) ;
let south = se . len ( ) + sw . len ( ) ;
let nets = ( north + south ) as f64 ;
2022-11-26 20:44:17 +08:00
let ne_dist = ( ( ne . len ( ) as f64 ) / nets ) - 0.25 ;
let se_dist = ( ( se . len ( ) as f64 ) / nets ) - 0.25 ;
let sw_dist = ( ( sw . len ( ) as f64 ) / nets ) - 0.25 ;
let nw_dist = ( ( nw . len ( ) as f64 ) / nets ) - 0.25 ;
2022-11-25 13:34:46 +08:00
let ne_str = ne . len ( ) . to_string ( ) ;
let se_str = se . len ( ) . to_string ( ) ;
let sw_str = sw . len ( ) . to_string ( ) ;
let nw_str = nw . len ( ) . to_string ( ) ;
2022-11-26 20:44:17 +08:00
let dist_str = | dist : f64 | {
if dist > 0.20 {
" (way too many nets) " . red ( )
} else if dist > 0.05 {
" (too many nets) " . yellow ( )
} else if dist < - 0.05 {
" (too few nets) " . yellow ( )
} else if dist < - 0.20 {
" (way too few nets) " . red ( )
} else {
" (balanced) " . green ( )
}
} ;
2022-11-25 13:34:46 +08:00
log_info! (
" {} arcs partitioned horizontally \n " ,
2022-11-27 01:09:20 +08:00
part_horiz . get_mut ( ) . to_string ( ) . bold ( )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
" {} arcs partitioned vertically \n " ,
2022-11-27 01:09:20 +08:00
part_vert . get_mut ( ) . to_string ( ) . bold ( )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
" {} arcs partitioned both ways \n " ,
2022-11-27 01:09:20 +08:00
part_diag . get_mut ( ) . to_string ( ) . bold ( )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
2022-11-26 20:44:17 +08:00
" {} arcs in the northeast {} \n " ,
ne_str . color ( if ne_dist . abs ( ) > 0.20 {
colored ::Color ::Red
} else if ne_dist . abs ( ) > 0.05 {
colored ::Color ::Yellow
2022-11-25 13:34:46 +08:00
} else {
2022-11-26 20:44:17 +08:00
colored ::Color ::Green
} ) ,
dist_str ( ne_dist )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
2022-11-26 20:44:17 +08:00
" {} arcs in the southeast {} \n " ,
se_str . color ( if se_dist . abs ( ) > 0.20 {
colored ::Color ::Red
} else if se_dist . abs ( ) > 0.05 {
colored ::Color ::Yellow
2022-11-25 13:34:46 +08:00
} else {
2022-11-26 20:44:17 +08:00
colored ::Color ::Green
} ) ,
dist_str ( se_dist )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
2022-11-26 20:44:17 +08:00
" {} arcs in the southwest {} \n " ,
sw_str . color ( if sw_dist . abs ( ) > 0.20 {
colored ::Color ::Red
} else if sw_dist . abs ( ) > 0.05 {
colored ::Color ::Yellow
2022-11-25 13:34:46 +08:00
} else {
2022-11-26 20:44:17 +08:00
colored ::Color ::Green
} ) ,
dist_str ( sw_dist )
2022-11-25 13:34:46 +08:00
) ;
log_info! (
2022-11-26 20:44:17 +08:00
" {} arcs in the northwest {} \n " ,
nw_str . color ( if nw_dist . abs ( ) > 0.20 {
colored ::Color ::Red
} else if nw_dist . abs ( ) > 0.05 {
colored ::Color ::Yellow
2022-11-25 13:34:46 +08:00
} else {
2022-11-26 20:44:17 +08:00
colored ::Color ::Green
} ) ,
dist_str ( nw_dist )
2022-11-25 13:34:46 +08:00
) ;
( ne , se , sw , nw )
}
2022-11-20 11:20:09 +08:00
fn route ( ctx : & mut npnr ::Context ) -> bool {
2022-11-26 20:44:17 +08:00
log_info! (
" {}{}{}{}{}{} from Rust! \n " ,
" A " . red ( ) ,
" w " . green ( ) ,
" o " . yellow ( ) ,
" o " . blue ( ) ,
" o " . magenta ( ) ,
" o " . cyan ( )
) ;
2022-11-20 11:20:09 +08:00
log_info! (
" Running on a {}x{} grid \n " ,
2022-11-26 20:44:17 +08:00
ctx . grid_dim_x ( ) . to_string ( ) . bold ( ) ,
ctx . grid_dim_y ( ) . to_string ( ) . bold ( ) ,
2022-11-20 11:20:09 +08:00
) ;
2022-11-21 10:48:00 +08:00
2022-11-25 13:34:46 +08:00
let wires = ctx . wires_leaking ( ) ;
2022-11-26 20:44:17 +08:00
log_info! ( " Found {} wires \n " , wires . len ( ) . to_string ( ) . bold ( ) ) ;
2022-11-25 13:34:46 +08:00
let pips = ctx . pips_leaking ( ) ;
2022-11-26 20:44:17 +08:00
log_info! ( " Found {} pips \n " , pips . len ( ) . to_string ( ) . bold ( ) ) ;
2022-11-24 07:55:33 +08:00
2022-11-24 07:02:30 +08:00
let nets = npnr ::Nets ::new ( ctx ) ;
2022-11-25 13:34:46 +08:00
let nets_str = nets . len ( ) . to_string ( ) ;
2022-11-26 20:44:17 +08:00
log_info! ( " Found {} nets \n " , nets_str . bold ( ) ) ;
2022-11-21 10:48:00 +08:00
2022-11-23 11:31:50 +08:00
let mut count = 0 ;
2022-11-24 07:02:30 +08:00
for ( name , net ) in nets . iter ( ) {
2022-11-23 11:31:50 +08:00
let _src = ctx . source_wire ( * net ) ;
let net = unsafe { net . as_mut ( ) . unwrap ( ) } ;
2022-11-24 07:02:30 +08:00
let users = nets . users_by_name ( * name ) . unwrap ( ) . iter ( ) ;
for user in users {
2022-11-27 01:09:20 +08:00
count + = ctx . sink_wires ( net , * user ) . len ( ) ;
2022-11-23 11:31:50 +08:00
}
}
2022-11-26 20:44:17 +08:00
log_info! ( " Found {} arcs \n " , count . to_string ( ) . bold ( ) ) ;
2022-11-23 11:31:50 +08:00
let ( name , net ) = nets
. iter ( )
2022-11-24 07:02:30 +08:00
. max_by_key ( | ( name , net ) | {
2022-11-23 11:31:50 +08:00
let net = unsafe { net . as_mut ( ) . unwrap ( ) } ;
if net . is_global ( ) {
0
} else {
2022-11-24 07:02:30 +08:00
nets . users_by_name ( * * name )
. unwrap ( )
. iter ( )
2022-11-27 01:09:20 +08:00
. fold ( 0 , | acc , sink | acc + ctx . sink_wires ( net , * sink ) . len ( ) )
2022-11-23 11:31:50 +08:00
}
} )
. unwrap ( ) ;
let net = unsafe { net . as_mut ( ) . unwrap ( ) } ;
2022-11-24 07:02:30 +08:00
let count = nets
. users_by_name ( * name )
. unwrap ( )
. iter ( )
2022-11-27 01:09:20 +08:00
. fold ( 0 , | acc , sink | acc + ctx . sink_wires ( net , * sink ) . len ( ) )
2022-11-25 13:34:46 +08:00
. to_string ( ) ;
2022-11-23 11:31:50 +08:00
log_info! (
2022-11-26 20:44:17 +08:00
" Highest non-global fanout net is {} \n " ,
ctx . name_of ( * name ) . to_str ( ) . unwrap ( ) . bold ( )
2022-11-23 11:31:50 +08:00
) ;
2022-11-26 20:44:17 +08:00
log_info! ( " with {} arcs \n " , count . bold ( ) ) ;
2022-11-23 11:31:50 +08:00
let mut x0 = 0 ;
let mut y0 = 0 ;
let mut x1 = 0 ;
let mut y1 = 0 ;
2022-11-24 07:02:30 +08:00
for sink in nets . users_by_name ( * name ) . unwrap ( ) . iter ( ) {
2022-11-23 11:31:50 +08:00
let sink = unsafe { sink . as_ref ( ) . unwrap ( ) } ;
2022-11-25 13:34:46 +08:00
let cell = sink . cell ( ) . unwrap ( ) . location ( ) ;
x0 = x0 . min ( cell . x ) ;
y0 = y0 . min ( cell . y ) ;
x1 = x1 . max ( cell . x ) ;
y1 = y1 . max ( cell . y ) ;
2022-11-23 11:31:50 +08:00
}
2022-11-25 13:34:46 +08:00
let coords_min = format! ( " ( {} , {} ) " , x0 , y0 ) ;
let coords_max = format! ( " ( {} , {} ) " , x1 , y1 ) ;
log_info! (
2022-11-25 15:12:14 +08:00
" which spans from {} to {} \n " ,
2022-11-26 20:44:17 +08:00
coords_min . bold ( ) ,
coords_max . bold ( )
2022-11-25 13:34:46 +08:00
) ;
2022-11-23 11:31:50 +08:00
2022-11-27 02:57:53 +08:00
log_info! ( " rayon reports {} threads available \n " , rayon ::current_num_threads ( ) . to_string ( ) . bold ( ) ) ;
2022-11-26 23:35:31 +08:00
let ( x_part , y_part , ne , se , sw , nw ) =
find_partition_point ( ctx , & nets , pips , 0 , ctx . grid_dim_x ( ) , 0 , ctx . grid_dim_y ( ) ) ;
let mut invalid_arcs_in_ne = 0 ;
let mut invalid_arcs_in_se = 0 ;
let mut invalid_arcs_in_sw = 0 ;
let mut invalid_arcs_in_nw = 0 ;
for ( ( source_x , source_y ) , ( sink_x , sink_y ) ) in ne {
if source_x > x_part | | source_y > y_part | | sink_x > x_part | | sink_y > y_part {
invalid_arcs_in_ne + = 1 ;
}
}
for ( ( source_x , source_y ) , ( sink_x , sink_y ) ) in se {
if source_x < x_part | | source_y > y_part | | sink_x < x_part | | sink_y > y_part {
invalid_arcs_in_se + = 1 ;
}
}
for ( ( source_x , source_y ) , ( sink_x , sink_y ) ) in sw {
if source_x < x_part | | source_y < y_part | | sink_x < x_part | | sink_y < y_part {
invalid_arcs_in_sw + = 1 ;
}
}
for ( ( source_x , source_y ) , ( sink_x , sink_y ) ) in nw {
if source_x > x_part | | source_y < y_part | | sink_x > x_part | | sink_y < y_part {
invalid_arcs_in_nw + = 1 ;
}
}
if [
invalid_arcs_in_ne ,
invalid_arcs_in_se ,
invalid_arcs_in_sw ,
invalid_arcs_in_nw ,
]
. into_iter ( )
. all ( | x | x = = 0 )
{
2022-11-27 01:11:18 +08:00
log_info! (
" {} \n " ,
" Found no arcs crossing partition boundaries. " . green ( )
) ;
2022-11-26 23:35:31 +08:00
} else {
println! ( " {} " , " found arcs crossing partition boundaries! " . yellow ( ) ) ;
println! ( " count in ne: {} " , invalid_arcs_in_ne . to_string ( ) . bold ( ) ) ;
println! ( " count in se: {} " , invalid_arcs_in_se . to_string ( ) . bold ( ) ) ;
println! ( " count in sw: {} " , invalid_arcs_in_sw . to_string ( ) . bold ( ) ) ;
println! ( " count in nw: {} " , invalid_arcs_in_nw . to_string ( ) . bold ( ) ) ;
}
2022-11-24 07:55:33 +08:00
2022-11-23 11:31:50 +08:00
/* log_info!("=== level 2 NE:\n");
let _ = find_partition_point ( & ne , x_start , x , y_start , y ) ;
log_info! ( " === level 2 SE: \n " ) ;
let _ = find_partition_point ( & se , x , x_finish , y_start , y ) ;
log_info! ( " === level 2 SW: \n " ) ;
let _ = find_partition_point ( & sw , x , x_finish , y , y_finish ) ;
log_info! ( " === level 2 NW: \n " ) ;
let _ = find_partition_point ( & nw , x_start , x , y , y_finish ) ; * /
2022-11-20 11:20:09 +08:00
true
2022-11-23 11:31:50 +08:00
}