mirror of https://codeberg.org/topola/topola.git
feat(autorouter/autorouter): Impl. rudimentary multilayer reconfigurator (not yet functional)
This commit is contained in:
parent
0985e0a427
commit
b7fd6a0cab
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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<M: AccessMesadata> Autorouter<M> {
|
|||
&mut self,
|
||||
selection: &PinSelection,
|
||||
options: MultilayerAutorouteOptions,
|
||||
) -> Result<MultilayerAutorouteExecutionStepper, AutorouterError> {
|
||||
let planner = Planner::new(
|
||||
self,
|
||||
&self.selected_ratlines(selection, options.planar.principal_layer),
|
||||
);
|
||||
|
||||
MultilayerAutorouteExecutionStepper::new(
|
||||
) -> Result<MultilayerAutorouteReconfigurator, AutorouterError> {
|
||||
MultilayerAutorouteReconfigurator::new(
|
||||
self,
|
||||
self.selected_ratlines(selection, options.planar.principal_layer),
|
||||
planner.plan().clone(),
|
||||
options,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<M> {
|
||||
MultilayerAutoroute(MultilayerAutorouteExecutionStepper),
|
||||
MultilayerAutoroute(MultilayerAutorouteReconfigurator),
|
||||
PlanarAutoroute(PlanarAutorouteReconfigurator),
|
||||
TopoAutoroute(ng::AutorouteExecutionStepper<M>),
|
||||
PlaceVia(PlaceViaExecutionStepper),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Self, AutorouterError> {
|
||||
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<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, 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<M: AccessMesadata> Abort<Autorouter<M>> for MultilayerAutorouteExecutionSte
|
|||
}
|
||||
}
|
||||
|
||||
impl<M: AccessMesadata> Reconfigure<Autorouter<M>> for MultilayerAutorouteExecutionStepper {
|
||||
type Configuration = AnterouterPlan;
|
||||
type Output = Result<(), AutorouterError>;
|
||||
|
||||
fn reconfigure(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<impl AccessMesadata>,
|
||||
ratlines: Vec<RatlineUid>,
|
||||
options: MultilayerAutorouteOptions,
|
||||
) -> Result<Self, AutorouterError> {
|
||||
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<M: AccessMesadata>(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<Option<BoardEdit>, 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<M: AccessMesadata> Step<Autorouter<M>, Option<BoardEdit>, MultilayerReconfiguratorStatus>
|
||||
for MultilayerAutorouteReconfigurator
|
||||
{
|
||||
type Error = AutorouterError;
|
||||
|
||||
fn step(
|
||||
&mut self,
|
||||
autorouter: &mut Autorouter<M>,
|
||||
) -> Result<ControlFlow<Option<BoardEdit>, 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<M: AccessMesadata> Abort<Autorouter<M>> for MultilayerAutorouteReconfigurator {
|
||||
fn abort(&mut self, autorouter: &mut Autorouter<M>) {
|
||||
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<Navmesh, f64>> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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<RatlineUid>,
|
||||
}
|
||||
|
||||
impl MultilayerReconfigurer {
|
||||
pub fn new(
|
||||
autorouter: &Autorouter<impl AccessMesadata>,
|
||||
ratlines: Vec<RatlineUid>,
|
||||
options: &MultilayerAutorouteOptions,
|
||||
) -> Self {
|
||||
Self {
|
||||
original_ratlines: ratlines,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_configuration(
|
||||
&mut self,
|
||||
autorouter: &Autorouter<impl AccessMesadata>,
|
||||
) -> Option<AnterouterPlan> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -29,20 +29,24 @@ use super::{
|
|||
PlanarAutorouteOptions,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlanarAutorouteConfiguration {
|
||||
pub ratlines: Vec<RatlineUid>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PlanarAutorouteCosts {
|
||||
pub lengths: Vec<f64>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,24 @@ pub struct Planner {
|
|||
|
||||
impl Planner {
|
||||
pub fn new(autorouter: &Autorouter<impl AccessMesadata>, 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<impl AccessMesadata>,
|
||||
ratlines: &[RatlineUid],
|
||||
layer_map: BTreeMap<RatlineUid, usize>,
|
||||
) -> Self {
|
||||
let mut plan = AnterouterPlan {
|
||||
layer_map,
|
||||
ratline_terminating_schemes: BTreeMap::new(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ pub trait Reconfigure<Ctx> {
|
|||
) -> Self::Output;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ReconfiguratorStatus<Re, Ru> {
|
||||
Running(Ru),
|
||||
Reconfigured(Re),
|
||||
|
|
|
|||
Loading…
Reference in New Issue