diff --git a/committed.toml b/committed.toml index ae59d4c..fc1c1e1 100644 --- a/committed.toml +++ b/committed.toml @@ -28,10 +28,12 @@ allowed_scopes = [ "autorouter/invoker", "autorouter/measure_length", "autorouter/multilayer_autoroute", - "autorouter/planar_reconfigurator", - "autorouter/planar_reconfigurer", + "autorouter/multilayer_reconfigurator", + "autorouter/multilayer_reconfigurer", "autorouter/place_via", "autorouter/planar_autoroute", + "autorouter/planar_reconfigurator", + "autorouter/planar_reconfigurer", "autorouter/planner", "autorouter/pointroute", "autorouter/presorter", diff --git a/crates/specctra-core/src/mesadata.rs b/crates/specctra-core/src/mesadata.rs index 9f9771e..640108d 100644 --- a/crates/specctra-core/src/mesadata.rs +++ b/crates/specctra-core/src/mesadata.rs @@ -105,7 +105,6 @@ 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 = { diff --git a/src/autorouter/autorouter.rs b/src/autorouter/autorouter.rs index 14c0d3e..2765e98 100644 --- a/src/autorouter/autorouter.rs +++ b/src/autorouter/autorouter.rs @@ -12,10 +12,9 @@ use thiserror::Error; use crate::{ autorouter::{ - multilayer_autoroute::{MultilayerAutorouteExecutionStepper, MultilayerAutorouteOptions}, - planar_reconfigurator::PlanarAutorouteReconfigurator, - planner::Planner, - ratsnests::Ratsnests, + multilayer_autoroute::MultilayerAutorouteOptions, + multilayer_reconfigurator::MultilayerAutorouteReconfigurator, + planar_reconfigurator::PlanarAutorouteReconfigurator, ratsnests::Ratsnests, }, board::{AccessMesadata, Board}, drawing::{band::BandTermsegIndex, graph::MakePrimitiveRef}, @@ -119,16 +118,10 @@ impl Autorouter { &mut self, selection: &PinSelection, options: MultilayerAutorouteOptions, - ) -> Result { - let planner = Planner::new( - self, - &self.selected_ratlines(selection, options.planar.principal_layer), - ); - - MultilayerAutorouteExecutionStepper::new( + ) -> Result { + MultilayerAutorouteReconfigurator::new( self, self.selected_ratlines(selection, options.planar.principal_layer), - planner.plan().clone(), options, ) } diff --git a/src/autorouter/execution.rs b/src/autorouter/execution.rs index 211e5d6..b866cc6 100644 --- a/src/autorouter/execution.rs +++ b/src/autorouter/execution.rs @@ -9,7 +9,8 @@ use serde::{Deserialize, Serialize}; use crate::{ autorouter::{ - multilayer_autoroute::{MultilayerAutorouteExecutionStepper, MultilayerAutorouteOptions}, + multilayer_autoroute::MultilayerAutorouteOptions, + multilayer_reconfigurator::MultilayerAutorouteReconfigurator, planar_reconfigurator::PlanarAutorouteReconfigurator, }, board::{edit::BoardEdit, AccessMesadata}, @@ -49,7 +50,7 @@ pub enum Command { #[enum_dispatch(GetDebugOverlayData)] pub enum ExecutionStepper { - MultilayerAutoroute(MultilayerAutorouteExecutionStepper), + MultilayerAutoroute(MultilayerAutorouteReconfigurator), PlanarAutoroute(PlanarAutorouteReconfigurator), TopoAutoroute(ng::AutorouteExecutionStepper), PlaceVia(PlaceViaExecutionStepper), diff --git a/src/autorouter/invoker.rs b/src/autorouter/invoker.rs index d6d0ba1..15c65c7 100644 --- a/src/autorouter/invoker.rs +++ b/src/autorouter/invoker.rs @@ -32,7 +32,7 @@ use super::{ execution::{Command, ExecutionStepper}, history::{History, HistoryError}, measure_length::MeasureLengthExecutionStepper, - multilayer_autoroute::MultilayerAutorouteExecutionStepper, + multilayer_reconfigurator::MultilayerAutorouteReconfigurator, place_via::PlaceViaExecutionStepper, planar_reconfigurator::PlanarAutorouteReconfigurator, remove_bands::RemoveBandsExecutionStepper, diff --git a/src/autorouter/mod.rs b/src/autorouter/mod.rs index e4112c7..a7a8fca 100644 --- a/src/autorouter/mod.rs +++ b/src/autorouter/mod.rs @@ -12,6 +12,8 @@ pub mod history; pub mod invoker; pub mod measure_length; pub mod multilayer_autoroute; +pub mod multilayer_reconfigurator; +pub mod multilayer_reconfigurer; pub mod place_via; pub mod planar_autoroute; pub mod planar_reconfigurator; diff --git a/src/autorouter/multilayer_autoroute.rs b/src/autorouter/multilayer_autoroute.rs index 326258b..dafbb59 100644 --- a/src/autorouter/multilayer_autoroute.rs +++ b/src/autorouter/multilayer_autoroute.rs @@ -11,7 +11,6 @@ use crate::{ autorouter::{ anterouter::{Anterouter, AnterouterOptions, AnterouterPlan}, invoker::GetDebugOverlayData, - planar_autoroute::PlanarAutorouteContinueStatus, planar_reconfigurator::{PlanarAutorouteReconfigurator, PlanarReconfiguratorStatus}, ratline::RatlineUid, Autorouter, AutorouterError, PlanarAutorouteOptions, @@ -20,7 +19,7 @@ use crate::{ drawing::graph::PrimitiveIndex, geometry::{edit::Edit, primitive::PrimitiveShape}, router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper}, - stepper::{Abort, EstimateProgress, ReconfiguratorStatus, Step}, + stepper::{Abort, EstimateProgress, ReconfiguratorStatus, Reconfigure, Step}, }; #[derive(Clone, Copy, Debug, Deserialize, Serialize)] @@ -32,8 +31,7 @@ pub struct MultilayerAutorouteOptions { pub struct MultilayerAutorouteExecutionStepper { planar: PlanarAutorouteReconfigurator, anteroute_edit: BoardEdit, - // TODO: Obviously, we need something more sophisticated here. - planar_autoroute_reconfiguration_count: u64, + options: MultilayerAutorouteOptions, } impl MultilayerAutorouteExecutionStepper { @@ -43,14 +41,14 @@ impl MultilayerAutorouteExecutionStepper { plan: AnterouterPlan, options: MultilayerAutorouteOptions, ) -> Result { - let mut assigner = Anterouter::new(plan); + let mut anterouter = Anterouter::new(plan); let mut anteroute_edit = BoardEdit::new(); - assigner.anteroute(autorouter, &mut anteroute_edit, &options.anterouter); + anterouter.anteroute(autorouter, &mut anteroute_edit, &options.anterouter); Ok(Self { planar: PlanarAutorouteReconfigurator::new(autorouter, ratlines, options.planar)?, anteroute_edit, - planar_autoroute_reconfiguration_count: 0, + options: options.clone(), }) } } @@ -70,12 +68,9 @@ impl Step, Option, PlanarReconfigura // FIXME: Unnecessary large clone. Ok(ControlFlow::Break(Some(self.anteroute_edit.clone()))) } - Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(result))) => { - self.planar_autoroute_reconfiguration_count += 1; - Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured( - result, - ))) - } + Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(result))) => Ok( + ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(result)), + ), x => x, } } @@ -87,6 +82,25 @@ impl Abort> for MultilayerAutorouteExecutionSte } } +impl Reconfigure> for MultilayerAutorouteExecutionStepper { + type Configuration = AnterouterPlan; + type Output = Result<(), AutorouterError>; + + fn reconfigure( + &mut self, + autorouter: &mut Autorouter, + plan: AnterouterPlan, + ) -> Result<(), AutorouterError> { + self.planar.abort(autorouter); + autorouter.board.apply_edit(&self.anteroute_edit.reverse()); + + let mut anterouter = Anterouter::new(plan); + let mut anteroute_edit = BoardEdit::new(); + anterouter.anteroute(autorouter, &mut anteroute_edit, &self.options.anterouter); + Ok(()) + } +} + impl EstimateProgress for MultilayerAutorouteExecutionStepper { type Value = f64; diff --git a/src/autorouter/multilayer_reconfigurator.rs b/src/autorouter/multilayer_reconfigurator.rs new file mode 100644 index 0000000..4e2f73f --- /dev/null +++ b/src/autorouter/multilayer_reconfigurator.rs @@ -0,0 +1,151 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use std::ops::ControlFlow; + +use specctra_core::mesadata::AccessMesadata; + +use crate::{ + autorouter::{ + invoker::GetDebugOverlayData, + multilayer_autoroute::{MultilayerAutorouteExecutionStepper, MultilayerAutorouteOptions}, + multilayer_reconfigurer::MultilayerReconfigurer, + planar_reconfigurator::PlanarReconfiguratorStatus, + planner::Planner, + ratline::RatlineUid, + Autorouter, AutorouterError, + }, + board::edit::BoardEdit, + drawing::graph::PrimitiveIndex, + geometry::primitive::PrimitiveShape, + router::{navcord::Navcord, navmesh::Navmesh, thetastar::ThetastarStepper}, + stepper::{Abort, EstimateProgress, ReconfiguratorStatus, Reconfigure, Step}, +}; + +pub type MultilayerReconfiguratorStatus = ReconfiguratorStatus<(), PlanarReconfiguratorStatus>; + +pub struct MultilayerAutorouteReconfigurator { + stepper: MultilayerAutorouteExecutionStepper, + reconfigurer: MultilayerReconfigurer, + options: MultilayerAutorouteOptions, + // TODO: Obviously, we need something more sophisticated here. + planar_autoroute_reconfiguration_count: u64, +} + +impl MultilayerAutorouteReconfigurator { + pub fn new( + autorouter: &mut Autorouter, + ratlines: Vec, + options: MultilayerAutorouteOptions, + ) -> Result { + let planner = Planner::new(autorouter, &ratlines); + let reconfigurer = MultilayerReconfigurer::new(autorouter, ratlines.clone(), &options); + + Ok(Self { + stepper: MultilayerAutorouteExecutionStepper::new( + autorouter, + ratlines, + planner.plan().clone(), + options, + )?, + reconfigurer, + options, + planar_autoroute_reconfiguration_count: 0, + }) + } + + fn reconfigure( + &mut self, + autorouter: &mut Autorouter, + ) -> Result, MultilayerReconfiguratorStatus>, AutorouterError> + { + loop { + let Some(plan) = self.reconfigurer.next_configuration(autorouter) else { + return Ok(ControlFlow::Break(None)); + }; + + match self.stepper.reconfigure(autorouter, plan) { + Ok(_) => { + return Ok(ControlFlow::Continue( + ReconfiguratorStatus::Reconfigured(()), + )) + } + Err(AutorouterError::NothingToUndoForReconfiguration) => continue, + Err(err) => return Err(err), + } + } + } +} + +impl Step, Option, MultilayerReconfiguratorStatus> + for MultilayerAutorouteReconfigurator +{ + type Error = AutorouterError; + + fn step( + &mut self, + autorouter: &mut Autorouter, + ) -> Result, MultilayerReconfiguratorStatus>, AutorouterError> + { + match self.stepper.step(autorouter) { + Ok(ControlFlow::Break(maybe_edit)) => Ok(ControlFlow::Break(maybe_edit)), + Ok(ControlFlow::Continue(ReconfiguratorStatus::Running(status))) => { + Ok(ControlFlow::Continue(ReconfiguratorStatus::Running( + ReconfiguratorStatus::Running(status), + ))) + } + Ok(ControlFlow::Continue(ReconfiguratorStatus::Reconfigured(status))) => { + self.planar_autoroute_reconfiguration_count += 1; + + if self.planar_autoroute_reconfiguration_count >= 100 { + self.planar_autoroute_reconfiguration_count = 0; + self.reconfigure(autorouter) + } else { + Ok(ControlFlow::Continue(ReconfiguratorStatus::Running( + ReconfiguratorStatus::Reconfigured(status), + ))) + } + } + Err(_) => self.reconfigure(autorouter), + } + } +} + +impl Abort> for MultilayerAutorouteReconfigurator { + fn abort(&mut self, autorouter: &mut Autorouter) { + self.stepper.abort(autorouter) + } +} + +impl EstimateProgress for MultilayerAutorouteReconfigurator { + type Value = f64; + + fn estimate_progress_value(&self) -> f64 { + // TODO. + self.stepper.estimate_progress_value() + } + + fn estimate_progress_maximum(&self) -> f64 { + // TODO. + self.stepper.estimate_progress_maximum() + } +} + +impl GetDebugOverlayData for MultilayerAutorouteReconfigurator { + fn maybe_thetastar(&self) -> Option<&ThetastarStepper> { + self.stepper.maybe_thetastar() + } + + fn maybe_navcord(&self) -> Option<&Navcord> { + self.stepper.maybe_navcord() + } + + fn ghosts(&self) -> &[PrimitiveShape] { + self.stepper.ghosts() + } + + fn obstacles(&self) -> &[PrimitiveIndex] { + self.stepper.obstacles() + } +} diff --git a/src/autorouter/multilayer_reconfigurer.rs b/src/autorouter/multilayer_reconfigurer.rs new file mode 100644 index 0000000..92db76e --- /dev/null +++ b/src/autorouter/multilayer_reconfigurer.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025 Topola contributors +// +// SPDX-License-Identifier: MIT + +use std::time::SystemTime; + +use specctra_core::mesadata::AccessMesadata; + +use crate::autorouter::{ + anterouter::AnterouterPlan, multilayer_autoroute::MultilayerAutorouteOptions, planner::Planner, + ratline::RatlineUid, Autorouter, +}; + +pub struct MultilayerReconfigurer { + original_ratlines: Vec, +} + +impl MultilayerReconfigurer { + pub fn new( + autorouter: &Autorouter, + ratlines: Vec, + options: &MultilayerAutorouteOptions, + ) -> Self { + Self { + original_ratlines: ratlines, + } + } + + pub fn next_configuration( + &mut self, + autorouter: &Autorouter, + ) -> Option { + let planner = Planner::new_from_layer_map( + autorouter, + &self.original_ratlines, + self.original_ratlines + .iter() + .enumerate() + .map(|(_, ratline)| (*ratline, Self::crude_random_bit())) + .collect(), + ); + + Some(planner.plan().clone()) + } + + fn crude_random_bit() -> usize { + let duration_since_epoch = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); + let timestamp_nanos = duration_since_epoch.as_nanos(); + (timestamp_nanos % 2) as usize + } +} diff --git a/src/autorouter/planar_autoroute.rs b/src/autorouter/planar_autoroute.rs index a72be3f..09cb089 100644 --- a/src/autorouter/planar_autoroute.rs +++ b/src/autorouter/planar_autoroute.rs @@ -29,20 +29,24 @@ use super::{ PlanarAutorouteOptions, }; +#[derive(Clone, Debug)] pub struct PlanarAutorouteConfiguration { pub ratlines: Vec, } +#[derive(Clone, Debug)] pub struct PlanarAutorouteCosts { pub lengths: Vec, } +#[derive(Clone, Debug)] pub struct PlanarAutorouteConfigurationResult { pub configuration: PlanarAutorouteConfiguration, pub costs: PlanarAutorouteCosts, } -/// Represents the current status of the autoroute operation. +/// The current status of the autoroute operation. +#[derive(Clone, Copy, Debug)] pub enum PlanarAutorouteContinueStatus { /// The autoroute is currently running and in progress. Running, diff --git a/src/autorouter/planner.rs b/src/autorouter/planner.rs index 126895e..0431aa9 100644 --- a/src/autorouter/planner.rs +++ b/src/autorouter/planner.rs @@ -28,12 +28,24 @@ pub struct Planner { impl Planner { pub fn new(autorouter: &Autorouter, ratlines: &[RatlineUid]) -> Self { - let mut plan = AnterouterPlan { - layer_map: ratlines + Self::new_from_layer_map( + autorouter, + ratlines, + ratlines .iter() .enumerate() .map(|(i, ratline)| (*ratline, i % 2)) .collect(), + ) + } + + pub fn new_from_layer_map( + autorouter: &Autorouter, + ratlines: &[RatlineUid], + layer_map: BTreeMap, + ) -> Self { + let mut plan = AnterouterPlan { + layer_map, ratline_terminating_schemes: BTreeMap::new(), }; diff --git a/src/stepper.rs b/src/stepper.rs index 3f836b9..c2e80cd 100644 --- a/src/stepper.rs +++ b/src/stepper.rs @@ -65,6 +65,7 @@ pub trait Reconfigure { ) -> Self::Output; } +#[derive(Clone, Copy, Debug)] pub enum ReconfiguratorStatus { Running(Ru), Reconfigured(Re),