From 8f59319902f857f1a58a8117c6f80ec33eade812 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Wed, 15 Oct 2025 15:12:46 +0200 Subject: [PATCH] feat(autorouter/autorouter): Have separate ratsnest for each (principal) layer --- committed.toml | 1 + crates/specctra-core/src/mesadata.rs | 20 +++++-- crates/topola-egui/src/displayer.rs | 6 +-- src/autorouter/anterouter.rs | 12 ++--- src/autorouter/autorouter.rs | 72 +++++++++++++++----------- src/autorouter/compare_detours.rs | 10 ++-- src/autorouter/invoker.rs | 32 ++++++------ src/autorouter/multilayer_autoroute.rs | 4 +- src/autorouter/permutator.rs | 4 +- src/autorouter/permuter.rs | 24 ++++----- src/autorouter/planar_autoroute.rs | 14 ++--- src/autorouter/planner.rs | 4 +- src/autorouter/presorter.rs | 20 ++++--- src/autorouter/ratline.rs | 57 ++++++++++++-------- src/autorouter/ratsnest.rs | 28 ++++++---- src/autorouter/ratsnests.rs | 7 ++- src/autorouter/scc.rs | 18 +++---- tests/common/mod.rs | 21 ++++++-- tests/single_layer.rs | 8 +-- 19 files changed, 215 insertions(+), 147 deletions(-) diff --git a/committed.toml b/committed.toml index b9f2c05..05d3481 100644 --- a/committed.toml +++ b/committed.toml @@ -36,6 +36,7 @@ allowed_scopes = [ "autorouter/pointroute", "autorouter/presorter", "autorouter/ratsnest", + "autorouter/ratsnests", "autorouter/ratline", "autorouter/remove_bands", "autorouter/selection", diff --git a/crates/specctra-core/src/mesadata.rs b/crates/specctra-core/src/mesadata.rs index 8ceb6fc..4d68958 100644 --- a/crates/specctra-core/src/mesadata.rs +++ b/crates/specctra-core/src/mesadata.rs @@ -21,12 +21,15 @@ pub trait AccessMesadata: AccessRules + std::panic::RefUnwindSafe { /// Renames a layer based on its index. fn bename_layer(&mut self, layer: usize, layername: String); - /// Retrieves the name of a layer by its index. + /// Retrieves the name of a layer from its index. fn layer_layername(&self, layer: usize) -> Option<&str>; - /// Retrieves the index of a layer by its name. + /// Retrieves the index of a layer from its name. fn layername_layer(&self, layername: &str) -> Option; + /// Return the number of the layers. + fn layer_count(&self) -> usize; + /// Renames a net based on its index. fn bename_net(&mut self, net: usize, netname: String); @@ -76,15 +79,18 @@ pub struct SpecctraMesadata { /// These rules are applied to all nets belonging to the respective net clas class_rules: BTreeMap, + /// Number of layers. + layer_count: usize, + // layername <-> layer for Layout /// A bidirectional map between layer indices and layer names, allowing translation /// between index-based layers in the layout and user-defined layer names. - pub layer_layername: BiBTreeMap, + layer_layername: BiBTreeMap, // netname <-> net for Layout /// A bidirectional map between network indices and network names in the PCB layout, /// providing an easy way to reference nets by name or index. - pub net_netname: BiBTreeMap, + net_netname: BiBTreeMap, // net -> netclass /// A map that associates network indices with their respective net class names. @@ -105,6 +111,7 @@ impl SpecctraMesadata { .enumerate() .map(|(index, layer)| (index, layer.name.clone())), ); + let layer_count = pcb.structure.layers.len(); // assign IDs to all nets named in pcb.network let net_netname = { @@ -157,6 +164,7 @@ impl SpecctraMesadata { structure_rule: SpecctraRule::from_dsn(&structure_rule), class_rules, layer_layername, + layer_count, net_netname, net_netclass, } @@ -204,6 +212,10 @@ impl AccessMesadata for SpecctraMesadata { self.layer_layername.get_by_right(layername).copied() } + fn layer_count(&self) -> usize { + self.layer_count + } + fn bename_net(&mut self, net: usize, netname: String) { self.net_netname.insert(net, netname); } diff --git a/crates/topola-egui/src/displayer.rs b/crates/topola-egui/src/displayer.rs index 3c71061..2742c2e 100644 --- a/crates/topola-egui/src/displayer.rs +++ b/crates/topola-egui/src/displayer.rs @@ -52,7 +52,7 @@ impl<'a> Displayer<'a> { self.display_layout(ctx); if menu_bar.show_ratsnest { - self.display_ratsnest(); + self.display_ratsnest(menu_bar); } if menu_bar.show_navmesh || menu_bar.show_guide_circles || menu_bar.show_guide_bitangents { @@ -161,14 +161,14 @@ impl<'a> Displayer<'a> { } } - fn display_ratsnest(&mut self) { + fn display_ratsnest(&mut self, menu_bar: &MenuBar) { let graph = self .workspace .interactor .invoker() .autorouter() .ratsnests() - .on_principal_layer(0) + .on_principal_layer(menu_bar.multilayer_autoroute_options.planar.principal_layer) .graph(); for edge in graph.edge_references() { if edge.weight().band_termseg.is_some() { diff --git a/src/autorouter/anterouter.rs b/src/autorouter/anterouter.rs index 4eab2d3..baf662f 100644 --- a/src/autorouter/anterouter.rs +++ b/src/autorouter/anterouter.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use geo::{point, Distance, Euclidean, Point}; -use petgraph::graph::{EdgeIndex, NodeIndex}; +use petgraph::graph::NodeIndex; use rstar::{Envelope, RTreeObject, AABB}; use serde::{Deserialize, Serialize}; use specctra_core::mesadata::AccessMesadata; @@ -13,7 +13,7 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ compass_direction::{CardinalDirection, CompassDirection, OrdinalDirection}, - ratline::RatlineIndex, + ratline::RatlineUid, Autorouter, }, board::edit::BoardEdit, @@ -42,7 +42,7 @@ pub enum TerminatingScheme { #[derive(Clone, Debug)] pub struct AnterouterPlan { - pub layer_map: BTreeMap, + pub layer_map: BTreeMap, pub ratline_endpoint_dot_to_terminating_scheme: BTreeMap, } @@ -67,8 +67,8 @@ impl Anterouter { autorouter .ratsnests - .on_principal_layer_mut(0) - .assign_layer_to_ratline(*ratline, *layer); + .on_principal_layer_mut(ratline.principal_layer) + .assign_layer_to_ratline(ratline.index, *layer); if let Some(terminating_scheme) = self .plan @@ -126,7 +126,7 @@ impl Anterouter { &mut self, autorouter: &mut Autorouter, ratvertex: NodeIndex, - ratline: EdgeIndex, + ratline: RatlineUid, source_dot: FixedDotIndex, target_layer: usize, options: &AnterouterOptions, diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index b99fc0b..e05dd6d 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -31,7 +31,7 @@ use super::{ place_via::PlaceViaExecutionStepper, planar_autoroute::PlanarAutorouteExecutionStepper, pointroute::PointrouteExecutionStepper, - ratline::RatlineIndex, + ratline::RatlineUid, ratsnest::RatvertexNodeIndex, remove_bands::RemoveBandsExecutionStepper, selection::{BandSelection, PinSelection}, @@ -89,7 +89,9 @@ impl Autorouter { point: Point, options: PlanarAutorouteOptions, ) -> Result { - let ratvertex = self.find_selected_ratvertex(selection).unwrap(); + let ratvertex = self + .find_selected_ratvertex(selection, options.principal_layer) + .unwrap(); let origin_dot = match self .ratsnests .on_principal_layer_mut(0) @@ -117,11 +119,14 @@ impl Autorouter { selection: &PinSelection, options: MultilayerAutorouteOptions, ) -> Result { - let planner = Planner::new(self, &self.selected_ratlines(selection)); + let planner = Planner::new( + self, + &self.selected_ratlines(selection, options.planar.principal_layer), + ); MultilayerAutorouteExecutionStepper::new( self, - self.selected_ratlines(selection), + self.selected_ratlines(selection, options.planar.principal_layer), planner.plan().clone(), options, ) @@ -132,27 +137,24 @@ impl Autorouter { selection: &PinSelection, options: PlanarAutorouteOptions, ) -> Result { - PlanarAutorouteExecutionPermutator::new(self, self.selected_ratlines(selection), options) + PlanarAutorouteExecutionPermutator::new( + self, + self.selected_ratlines(selection, options.principal_layer), + options, + ) } pub(super) fn planar_autoroute_ratlines( &mut self, - ratlines: Vec, + ratlines: Vec, options: PlanarAutorouteOptions, ) -> Result { PlanarAutorouteExecutionStepper::new(self, ratlines, options) } - pub fn undo_planar_autoroute( - &mut self, - selection: &PinSelection, - ) -> Result<(), AutorouterError> { - self.undo_planar_autoroute_ratlines(self.selected_ratlines(selection)) - } - pub(super) fn undo_planar_autoroute_ratlines( &mut self, - ratlines: Vec, + ratlines: Vec, ) -> Result<(), AutorouterError> { for ratline in ratlines.iter() { let band = ratline.ref_(self).band_termseg(); @@ -177,7 +179,7 @@ impl Autorouter { M: Clone, { self.topo_autoroute_ratlines( - self.selected_ratlines(selection), + self.selected_ratlines(selection, active_layer), allowed_edges, active_layer, width, @@ -187,7 +189,7 @@ impl Autorouter { pub(super) fn topo_autoroute_ratlines( &mut self, - ratlines: Vec, + ratlines: Vec, allowed_edges: BTreeSet, active_layer: usize, width: f64, @@ -281,7 +283,7 @@ impl Autorouter { selection: &PinSelection, options: PlanarAutorouteOptions, ) -> Result { - let ratlines = self.selected_ratlines(selection); + let ratlines = self.selected_ratlines(selection, options.principal_layer); if ratlines.len() < 2 { return Err(AutorouterError::NeedExactlyTwoRatlines); } @@ -290,8 +292,8 @@ impl Autorouter { pub(super) fn compare_detours_ratlines( &mut self, - ratline1: RatlineIndex, - ratline2: RatlineIndex, + ratline1: RatlineUid, + ratline2: RatlineUid, options: PlanarAutorouteOptions, ) -> Result { CompareDetoursExecutionStepper::new(self, ratline1, ratline2, options) @@ -304,29 +306,33 @@ impl Autorouter { MeasureLengthExecutionStepper::new(selection) } - pub(super) fn selected_ratlines(&self, selection: &PinSelection) -> Vec { + pub(super) fn selected_ratlines( + &self, + selection: &PinSelection, + principal_layer: usize, + ) -> Vec { self.ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() .edge_indices() - .filter(|ratline| { + .filter(|index| { let (source, target) = self .ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() - .edge_endpoints(*ratline) + .edge_endpoints(*index) .unwrap(); let source_ratvertex = self .ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() .node_weight(source) .unwrap() .node_index(); let to_ratvertex = self .ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() .node_weight(target) .unwrap() @@ -335,19 +341,27 @@ impl Autorouter { selection.contains_node(&self.board, source_ratvertex.into()) && selection.contains_node(&self.board, to_ratvertex.into()) }) + .map(|index| RatlineUid { + principal_layer, + index, + }) .collect() } - fn find_selected_ratvertex(&self, selection: &PinSelection) -> Option> { + fn find_selected_ratvertex( + &self, + selection: &PinSelection, + principal_layer: usize, + ) -> Option> { self.ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() .node_indices() .find(|ratvertex| { selection.contains_node( &self.board, self.ratsnests() - .on_principal_layer(0) + .on_principal_layer(principal_layer) .graph() .node_weight(*ratvertex) .unwrap() diff --git a/src/autorouter/compare_detours.rs b/src/autorouter/compare_detours.rs index e479b54..8ade3e2 100644 --- a/src/autorouter/compare_detours.rs +++ b/src/autorouter/compare_detours.rs @@ -19,15 +19,15 @@ use crate::{ use super::{ invoker::GetDebugOverlayData, planar_autoroute::{PlanarAutorouteContinueStatus, PlanarAutorouteExecutionStepper}, - ratline::RatlineIndex, + ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, }; pub struct CompareDetoursExecutionStepper { autoroute: PlanarAutorouteExecutionStepper, next_autoroute: Option, - ratline1: RatlineIndex, - ratline2: RatlineIndex, + ratline1: RatlineUid, + ratline2: RatlineUid, total_length1: f64, total_length2: f64, done: bool, @@ -36,8 +36,8 @@ pub struct CompareDetoursExecutionStepper { impl CompareDetoursExecutionStepper { pub fn new( autorouter: &mut Autorouter, - ratline1: RatlineIndex, - ratline2: RatlineIndex, + ratline1: RatlineUid, + ratline2: RatlineUid, options: PlanarAutorouteOptions, ) -> Result { Ok(Self { diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index 33ac4f8..9837745 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -178,27 +178,27 @@ impl Invoker { Command::TopoAutoroute { selection, allowed_edges, - active_layer, + active_layer: active_layer_name, routed_band_width, } => { - let ratlines = self.autorouter.selected_ratlines(selection); + let active_layer = self + .autorouter + .board + .layout() + .rules() + .layername_layer(active_layer_name) + .unwrap(); + let ratlines = self.autorouter.selected_ratlines(selection, active_layer); // TODO: consider "presort by pairwise detours" - ExecutionStepper::TopoAutoroute( - self.autorouter.topo_autoroute_ratlines( - ratlines, - allowed_edges.clone(), - self.autorouter - .board - .layout() - .rules() - .layername_layer(active_layer) - .unwrap(), - *routed_band_width, - None, - )?, - ) + ExecutionStepper::TopoAutoroute(self.autorouter.topo_autoroute_ratlines( + ratlines, + allowed_edges.clone(), + active_layer, + *routed_band_width, + None, + )?) } Command::PlaceVia(weight) => { ExecutionStepper::PlaceVia(self.autorouter.place_via(*weight)?) diff --git a/src/autorouter/multilayer_autoroute.rs b/src/autorouter/multilayer_autoroute.rs index 62e8e33..5596be4 100644 --- a/src/autorouter/multilayer_autoroute.rs +++ b/src/autorouter/multilayer_autoroute.rs @@ -13,7 +13,7 @@ use crate::{ invoker::GetDebugOverlayData, permutator::PlanarAutorouteExecutionPermutator, planar_autoroute::PlanarAutorouteContinueStatus, - ratline::RatlineIndex, + ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, }, board::edit::BoardEdit, @@ -36,7 +36,7 @@ pub struct MultilayerAutorouteExecutionStepper { impl MultilayerAutorouteExecutionStepper { pub fn new( autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: Vec, plan: AnterouterPlan, options: MultilayerAutorouteOptions, ) -> Result { diff --git a/src/autorouter/permutator.rs b/src/autorouter/permutator.rs index bf00d2f..8590035 100644 --- a/src/autorouter/permutator.rs +++ b/src/autorouter/permutator.rs @@ -12,7 +12,7 @@ use crate::{ permuter::{PermuteRatlines, RatlinesPermuter}, planar_autoroute::{PlanarAutorouteContinueStatus, PlanarAutorouteExecutionStepper}, presorter::{PresortParams, PresortRatlines, SccIntersectionsAndLengthPresorter}, - ratline::RatlineIndex, + ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, }, board::edit::BoardEdit, @@ -31,7 +31,7 @@ pub struct PlanarAutorouteExecutionPermutator { impl PlanarAutorouteExecutionPermutator { pub fn new( autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: Vec, options: PlanarAutorouteOptions, ) -> Result { let presorter = SccIntersectionsAndLengthPresorter::new( diff --git a/src/autorouter/permuter.rs b/src/autorouter/permuter.rs index 6ae6075..728582e 100644 --- a/src/autorouter/permuter.rs +++ b/src/autorouter/permuter.rs @@ -11,7 +11,7 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ planar_autoroute::PlanarAutorouteExecutionStepper, - presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineIndex, scc::Scc, Autorouter, + presorter::SccIntersectionsAndLengthPresorter, ratline::RatlineUid, scc::Scc, Autorouter, PlanarAutorouteOptions, }, drawing::graph::MakePrimitiveRef, @@ -25,7 +25,7 @@ pub trait PermuteRatlines { &mut self, autorouter: &mut Autorouter, stepper: &PlanarAutorouteExecutionStepper, - ) -> Option>; + ) -> Option>; } #[enum_dispatch(PermuteRatlines)] @@ -37,7 +37,7 @@ pub enum RatlinesPermuter { impl RatlinesPermuter { pub fn new( autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: Vec, presorter: SccIntersectionsAndLengthPresorter, options: &PlanarAutorouteOptions, ) -> Self { @@ -52,13 +52,13 @@ impl RatlinesPermuter { pub struct SccPermutationsRatlinePermuter { sccs_permutations_iter: Skip>>, - original_ratlines: Vec, + original_ratlines: Vec, } impl SccPermutationsRatlinePermuter { pub fn new( _autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: Vec, presorter: SccIntersectionsAndLengthPresorter, _options: &PlanarAutorouteOptions, ) -> Self { @@ -79,7 +79,7 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter { &mut self, autorouter: &mut Autorouter, _stepper: &PlanarAutorouteExecutionStepper, - ) -> Option> { + ) -> Option> { let scc_permutation = self.sccs_permutations_iter.next()?; let mut ratlines = vec![]; @@ -88,17 +88,17 @@ impl PermuteRatlines for SccPermutationsRatlinePermuter { if scc.node_indices().contains( &autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(ratline.principal_layer) .graph() - .edge_endpoints(*ratline) + .edge_endpoints(ratline.index) .unwrap() .0, ) && scc.node_indices().contains( &autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(ratline.principal_layer) .graph() - .edge_endpoints(*ratline) + .edge_endpoints(ratline.index) .unwrap() .1, ) { @@ -118,7 +118,7 @@ pub struct RatlineCutsRatlinePermuter { impl RatlineCutsRatlinePermuter { pub fn new( _autorouter: &mut Autorouter, - _ratlines: Vec, + _ratlines: Vec, _presorter: SccIntersectionsAndLengthPresorter, _options: &PlanarAutorouteOptions, ) -> Self { @@ -134,7 +134,7 @@ impl PermuteRatlines for RatlineCutsRatlinePermuter { &mut self, autorouter: &mut Autorouter, stepper: &PlanarAutorouteExecutionStepper, - ) -> Option> { + ) -> Option> { let curr_ratline = stepper.ratlines()[*stepper.curr_ratline_index()]; let terminating_dots = curr_ratline.ref_(autorouter).terminating_dots(); let bands_cut_by_ratline: Vec<_> = autorouter diff --git a/src/autorouter/planar_autoroute.rs b/src/autorouter/planar_autoroute.rs index 66899dd..c383489 100644 --- a/src/autorouter/planar_autoroute.rs +++ b/src/autorouter/planar_autoroute.rs @@ -25,7 +25,7 @@ use crate::{ }; use super::{ - invoker::GetDebugOverlayData, ratline::RatlineIndex, Autorouter, AutorouterError, + invoker::GetDebugOverlayData, ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, }; @@ -43,7 +43,7 @@ pub enum PlanarAutorouteContinueStatus { #[derive(Getters)] pub struct PlanarAutorouteExecutionStepper { /// The ratlines which we are routing. - ratlines: Vec, + ratlines: Vec, /// Keeps track of the current ratline being routed, if one is active. curr_ratline_index: usize, /// Stores the current route being processed, if any. @@ -64,7 +64,7 @@ impl PlanarAutorouteExecutionStepper { /// and stores the associated data for future routing steps. pub fn new( autorouter: &mut Autorouter, - ratlines: Vec, + ratlines: Vec, options: PlanarAutorouteOptions, ) -> Result { if ratlines.is_empty() { @@ -187,9 +187,9 @@ impl Step, Option, PlanarAutorouteCo autorouter .ratsnests - .on_principal_layer_mut(0) + .on_principal_layer_mut(self.options.principal_layer) .assign_band_termseg_to_ratline( - self.ratlines[self.curr_ratline_index], + self.ratlines[self.curr_ratline_index].index, band_termseg, ); @@ -236,13 +236,13 @@ impl Abort> for PlanarAutorouteExecutionStepper } impl Permutate> for PlanarAutorouteExecutionStepper { - type Index = RatlineIndex; + type Index = RatlineUid; type Output = Result<(), AutorouterError>; fn permutate( &mut self, autorouter: &mut Autorouter, - permutation: Vec, + permutation: Vec, ) -> Result<(), AutorouterError> { let Some(new_index) = permutation .iter() diff --git a/src/autorouter/planner.rs b/src/autorouter/planner.rs index c34982d..151c912 100644 --- a/src/autorouter/planner.rs +++ b/src/autorouter/planner.rs @@ -10,7 +10,7 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ anterouter::{AnterouterPlan, TerminatingScheme}, - ratline::RatlineIndex, + ratline::RatlineUid, Autorouter, }, drawing::{ @@ -27,7 +27,7 @@ pub struct Planner { } impl Planner { - pub fn new(autorouter: &Autorouter, ratlines: &[RatlineIndex]) -> Self { + pub fn new(autorouter: &Autorouter, ratlines: &[RatlineUid]) -> Self { let mut plan = AnterouterPlan { layer_map: ratlines .iter() diff --git a/src/autorouter/presorter.rs b/src/autorouter/presorter.rs index 13f3f4f..1f9cc9d 100644 --- a/src/autorouter/presorter.rs +++ b/src/autorouter/presorter.rs @@ -7,7 +7,7 @@ use enum_dispatch::enum_dispatch; use petgraph::algo::tarjan_scc; use specctra_core::mesadata::AccessMesadata; -use crate::autorouter::{ratline::RatlineIndex, scc::Scc, Autorouter}; +use crate::autorouter::{ratline::RatlineUid, scc::Scc, Autorouter}; pub struct PresortParams { pub intersector_count_weight: f64, @@ -19,8 +19,8 @@ pub trait PresortRatlines { fn presort_ratlines( &self, autorouter: &mut Autorouter, - ratlines: &[RatlineIndex], - ) -> Vec; + ratlines: &[RatlineUid], + ) -> Vec; } #[enum_dispatch(PresortRatlines)] @@ -36,12 +36,16 @@ pub struct SccIntersectionsAndLengthPresorter { impl SccIntersectionsAndLengthPresorter { pub fn new( autorouter: &mut Autorouter, - ratlines: &[RatlineIndex], + ratlines: &[RatlineUid], params: &PresortParams, ) -> Self { // FIXME: Unnecessary copy. - let mut filtered_ratsnest = autorouter.ratsnests().on_principal_layer(0).graph().clone(); - filtered_ratsnest.retain_edges(|_g, i| ratlines.contains(&i)); + let mut filtered_ratsnest = autorouter + .ratsnests() + .on_principal_layer(ratlines[0].principal_layer) + .graph() + .clone(); + filtered_ratsnest.retain_edges(|_g, i| ratlines.iter().any(|ratline| ratline.index == i)); let mut sccs: Vec<_> = tarjan_scc(&filtered_ratsnest) .into_iter() @@ -65,8 +69,8 @@ impl PresortRatlines for SccIntersectionsAndLengthPresorter { fn presort_ratlines( &self, autorouter: &mut Autorouter, - ratlines: &[RatlineIndex], - ) -> Vec { + ratlines: &[RatlineUid], + ) -> Vec { let mut presorted_ratlines = vec![]; for scc in self.sccs.iter() { diff --git a/src/autorouter/ratline.rs b/src/autorouter/ratline.rs index 241626c..764bcce 100644 --- a/src/autorouter/ratline.rs +++ b/src/autorouter/ratline.rs @@ -19,7 +19,11 @@ use crate::{ use super::{ratsnest::RatvertexNodeIndex, Autorouter}; -pub type RatlineIndex = EdgeIndex; +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct RatlineUid { + pub principal_layer: usize, + pub index: EdgeIndex, +} #[derive(Debug, Default, Clone, Copy)] pub struct RatlineWeight { @@ -27,7 +31,7 @@ pub struct RatlineWeight { pub band_termseg: Option, } -impl<'a, M: AccessMesadata + 'a> MakeRef<'a, Autorouter> for RatlineIndex { +impl<'a, M: AccessMesadata + 'a> MakeRef<'a, Autorouter> for RatlineUid { type Output = RatlineRef<'a, M>; fn ref_(&self, autorouter: &'a Autorouter) -> RatlineRef<'a, M> { RatlineRef::new(*self, autorouter) @@ -35,21 +39,24 @@ impl<'a, M: AccessMesadata + 'a> MakeRef<'a, Autorouter> for RatlineIndex { } pub struct RatlineRef<'a, M: AccessMesadata> { - index: RatlineIndex, + uid: RatlineUid, autorouter: &'a Autorouter, } impl<'a, M: AccessMesadata> RatlineRef<'a, M> { - pub fn new(index: RatlineIndex, autorouter: &'a Autorouter) -> Self { - Self { index, autorouter } + pub fn new(index: RatlineUid, autorouter: &'a Autorouter) -> Self { + Self { + uid: index, + autorouter, + } } pub fn band_termseg(&self) -> BandTermsegIndex { self.autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() - .edge_weight(self.index) + .edge_weight(self.uid.index) .unwrap() .band_termseg .unwrap() @@ -59,15 +66,15 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let (source, target) = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() - .edge_endpoints(self.index) + .edge_endpoints(self.uid.index) .unwrap(); let source_dot = match self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(source) .unwrap() @@ -80,7 +87,7 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let target_dot = match self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(target) .unwrap() @@ -97,15 +104,15 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let (source, target) = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() - .edge_endpoints(self.index) + .edge_endpoints(self.uid.index) .unwrap(); let source_dot = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(source) .unwrap() @@ -116,7 +123,7 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let target_dot = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(target) .unwrap() @@ -131,9 +138,9 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { pub fn layer(&self) -> usize { self.autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() - .edge_weight(self.index) + .edge_weight(self.uid.index) .unwrap() .layer } @@ -164,14 +171,18 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { }) } - pub fn interiorly_cut_ratlines(&self) -> impl Iterator + '_ { + pub fn interiorly_cut_ratlines(&self) -> impl Iterator + '_ { let self_line_segment = self.line_segment(); self.autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .edge_indices() + .map(|index| RatlineUid { + principal_layer: self.uid.principal_layer, + index, + }) .filter(move |other| { let (self_source, self_target) = self.endpoint_indices(); let (other_source, other_target) = other.ref_(self.autorouter).endpoint_indices(); @@ -201,7 +212,7 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let source_pos = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(source) .unwrap() @@ -209,7 +220,7 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { let target_pos = self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() .node_weight(target) .unwrap() @@ -221,9 +232,9 @@ impl<'a, M: AccessMesadata> RatlineRef<'a, M> { pub fn endpoint_indices(&self) -> (NodeIndex, NodeIndex) { self.autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(self.uid.principal_layer) .graph() - .edge_endpoints(self.index) + .edge_endpoints(self.uid.index) .unwrap() } } diff --git a/src/autorouter/ratsnest.rs b/src/autorouter/ratsnest.rs index 1fd2659..22886bb 100644 --- a/src/autorouter/ratsnest.rs +++ b/src/autorouter/ratsnest.rs @@ -9,7 +9,11 @@ use std::{ use enum_dispatch::enum_dispatch; use geo::Point; -use petgraph::{data::Element, graph::NodeIndex, prelude::StableUnGraph}; +use petgraph::{ + data::Element, + graph::{EdgeIndex, NodeIndex}, + prelude::StableUnGraph, +}; use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2}; use specctra_core::mesadata::AccessMesadata; @@ -27,10 +31,7 @@ use crate::{ triangulation::{GetTrianvertexNodeIndex, Triangulation}, }; -use super::{ - conncomps::ConncompsWithPrincipalLayer, - ratline::{RatlineIndex, RatlineWeight}, -}; +use super::{conncomps::ConncompsWithPrincipalLayer, ratline::RatlineWeight}; #[enum_dispatch(GetIndex)] #[derive(Debug, Clone, Copy, PartialEq)] @@ -108,8 +109,10 @@ pub struct Ratsnest { } impl Ratsnest { - pub fn new(board: &Board) -> Result { - let principal_layer = 0; + pub fn new( + board: &Board, + principal_layer: usize, + ) -> Result { let conncomps = ConncompsWithPrincipalLayer::new(board, principal_layer); let mut this = Self { @@ -239,16 +242,19 @@ impl Ratsnest { .insert(layer, terminating_dot); } - pub fn assign_layer_to_ratline(&mut self, ratline: RatlineIndex, layer: usize) { - self.graph.edge_weight_mut(ratline).unwrap().layer = layer; + pub fn assign_layer_to_ratline(&mut self, ratline_index: EdgeIndex, layer: usize) { + self.graph.edge_weight_mut(ratline_index).unwrap().layer = layer; } pub fn assign_band_termseg_to_ratline( &mut self, - ratline: RatlineIndex, + ratline_index: EdgeIndex, termseg: BandTermsegIndex, ) { - self.graph.edge_weight_mut(ratline).unwrap().band_termseg = Some(termseg); + self.graph + .edge_weight_mut(ratline_index) + .unwrap() + .band_termseg = Some(termseg); } pub fn graph(&self) -> &StableUnGraph { diff --git a/src/autorouter/ratsnests.rs b/src/autorouter/ratsnests.rs index fcdb22e..9f0618b 100644 --- a/src/autorouter/ratsnests.rs +++ b/src/autorouter/ratsnests.rs @@ -11,7 +11,12 @@ pub struct Ratsnests(Box<[Ratsnest]>); impl Ratsnests { pub fn new(board: &Board) -> Result { - Ok(Self(Box::new([Ratsnest::new(board)?]))) + Ok(Self( + (0..board.mesadata().layer_count()) + .map(|principal_layer| Ratsnest::new(board, principal_layer)) + .collect::, _>>() + .map(Vec::into_boxed_slice)?, + )) } pub fn on_principal_layer(&self, principal_layer: usize) -> &Ratsnest { diff --git a/src/autorouter/scc.rs b/src/autorouter/scc.rs index f8b8a84..28d2e8e 100644 --- a/src/autorouter/scc.rs +++ b/src/autorouter/scc.rs @@ -8,7 +8,7 @@ use specctra_core::mesadata::AccessMesadata; use crate::{ autorouter::{ - ratline::{RatlineIndex, RatlineWeight}, + ratline::{RatlineUid, RatlineWeight}, ratsnest::RatvertexWeight, Autorouter, }, @@ -27,7 +27,7 @@ pub struct Scc { impl Scc { pub fn new( autorouter: &mut Autorouter, - ratlines: &[RatlineIndex], + ratlines: &[RatlineUid], filtered_ratsnest: &StableUnGraph, node_indices: Vec>, ) -> Self { @@ -40,10 +40,10 @@ impl Scc { for ratline in ratlines.iter() { if this .node_indices - .contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().0) + .contains(&filtered_ratsnest.edge_endpoints(ratline.index).unwrap().0) && this .node_indices - .contains(&filtered_ratsnest.edge_endpoints(*ratline).unwrap().1) + .contains(&filtered_ratsnest.edge_endpoints(ratline.index).unwrap().1) { this.length += ratline.ref_(autorouter).length(); this.intersector_count += @@ -74,23 +74,23 @@ impl<'a, M: AccessMesadata> SccRef<'a, M> { Self { scc, autorouter } } - pub fn contains(&self, ratline: RatlineIndex) -> bool { + pub fn contains(&self, ratline: RatlineUid) -> bool { self.scc.node_indices().contains( &self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(ratline.principal_layer) .graph() - .edge_endpoints(ratline) + .edge_endpoints(ratline.index) .unwrap() .0, ) && self.scc.node_indices().contains( &self .autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(ratline.principal_layer) .graph() - .edge_endpoints(ratline) + .edge_endpoints(ratline.index) .unwrap() .1, ) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f1b3a04..339eabc 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -9,6 +9,7 @@ use topola::{ conncomps::ConncompsWithPrincipalLayer, history::{History, HistoryError}, invoker::{Invoker, InvokerError}, + ratline::RatlineUid, Autorouter, }, board::{edit::BoardEdit, AccessMesadata, Board}, @@ -125,7 +126,7 @@ pub fn assert_no_loose_nodes(autorouter: &Autorouter) { } } -pub fn assert_navnode_count( +pub fn assert_layer_0_navnode_count( autorouter: &mut Autorouter, origin_pin: &str, destination_pin: &str, @@ -136,6 +137,10 @@ pub fn assert_navnode_count( .on_principal_layer(0) .graph() .edge_indices() + .map(|index| RatlineUid { + principal_layer: 0, + index, + }) .collect::>() .iter() .find_map(|ratline| { @@ -175,13 +180,23 @@ pub fn assert_that_all_single_layer_groundless_ratlines_are_autorouted( autorouter: &mut Autorouter, layername: &str, ) { - let conncomps = ConncompsWithPrincipalLayer::new(autorouter.board(), 0); + let layer = autorouter + .board() + .layout() + .rules() + .layername_layer(layername) + .unwrap(); + let conncomps = ConncompsWithPrincipalLayer::new(autorouter.board(), layer); for ratline in autorouter .ratsnests() - .on_principal_layer(0) + .on_principal_layer(layer) .graph() .edge_indices() + .map(|index| RatlineUid { + principal_layer: 0, + index, + }) { let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots(); diff --git a/tests/single_layer.rs b/tests/single_layer.rs index 011b641..2673a95 100644 --- a/tests/single_layer.rs +++ b/tests/single_layer.rs @@ -100,7 +100,7 @@ fn autoroute_tht_de9_to_tht_de9_in_predefined_order(variant: &str) { #[apply(test_master)] fn autoroute_0603_breakout(variant: &str) { let mut autorouter = common::load_design("tests/single_layer/0603_breakout/0603_breakout.dsn"); - common::assert_navnode_count(&mut autorouter, "R1-2", "J1-2", 22); + common::assert_layer_0_navnode_count(&mut autorouter, "R1-2", "J1-2", 22); let mut invoker = common::create_invoker_and_assert(autorouter); common::replay_and_assert_and_report( &mut invoker, @@ -122,7 +122,7 @@ fn autoroute_tht_diode_bridge_rectifier(variant: &str) { let mut autorouter = common::load_design( "tests/single_layer/tht_diode_bridge_rectifier/tht_diode_bridge_rectifier.dsn", ); - common::assert_navnode_count(&mut autorouter, "J2-2", "D4-2", 68); + common::assert_layer_0_navnode_count(&mut autorouter, "J2-2", "D4-2", 68); let mut invoker = common::create_invoker_and_assert(autorouter); common::replay_and_assert_and_report( &mut invoker, @@ -162,7 +162,7 @@ fn autoroute_4x_3rd_order_smd_lc_filters(variant: &str) { let mut autorouter = common::load_design( "tests/single_layer/4x_3rd_order_smd_lc_filters/4x_3rd_order_smd_lc_filters.dsn", ); - common::assert_navnode_count(&mut autorouter, "J1-1", "L1-1", 558); + common::assert_layer_0_navnode_count(&mut autorouter, "J1-1", "L1-1", 558); let mut invoker = common::create_invoker_and_assert(autorouter); common::replay_and_assert_and_report( &mut invoker, @@ -206,7 +206,7 @@ fn test_tht_3pin_xlr_to_tht_3pin_xlr(#[case] variant: &str) { fn autoroute_vga_dac_breakout(variant: &str) { let mut autorouter = common::load_design("tests/single_layer/vga_dac_breakout/vga_dac_breakout.dsn"); - common::assert_navnode_count(&mut autorouter, "J1-2", "R4-1", 272); + common::assert_layer_0_navnode_count(&mut autorouter, "J1-2", "R4-1", 272); let mut invoker = common::create_invoker_and_assert(autorouter); common::replay_and_assert_and_report( &mut invoker,