mirror of https://codeberg.org/topola/topola.git
186 lines
6.2 KiB
Rust
186 lines
6.2 KiB
Rust
// SPDX-FileCopyrightText: 2025 Topola contributors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
use std::iter::Skip;
|
|
|
|
use enum_dispatch::enum_dispatch;
|
|
use itertools::{Itertools, Permutations};
|
|
use specctra_core::mesadata::AccessMesadata;
|
|
|
|
use crate::{
|
|
autorouter::{
|
|
planar_autoroute::{PlanarAutorouteConfiguration, PlanarAutorouteExecutionStepper},
|
|
planar_preconfigurer::SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
|
ratline::RatlineUid,
|
|
scc::Scc,
|
|
Autorouter, PlanarAutorouteOptions,
|
|
},
|
|
drawing::graph::MakePrimitiveRef,
|
|
geometry::{GenericNode, GetLayer},
|
|
graph::MakeRef,
|
|
};
|
|
|
|
#[enum_dispatch]
|
|
pub trait MakeNextPlanarAutorouteConfiguration {
|
|
fn next_configuration(
|
|
&mut self,
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
stepper: &PlanarAutorouteExecutionStepper,
|
|
) -> Option<Vec<RatlineUid>>;
|
|
}
|
|
|
|
#[enum_dispatch(MakeNextPlanarAutorouteConfiguration)]
|
|
pub enum PlanarAutorouteReconfigurer {
|
|
RatlineCuts(RatlineCutsPlanarAutorouteReconfigurer),
|
|
SccPermutations(SccPermutationsPlanarAutorouteReconfigurer),
|
|
}
|
|
|
|
impl PlanarAutorouteReconfigurer {
|
|
pub fn new(
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
preconfiguration: PlanarAutorouteConfiguration,
|
|
presorter: SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
|
options: &PlanarAutorouteOptions,
|
|
) -> Self {
|
|
PlanarAutorouteReconfigurer::SccPermutations(
|
|
SccPermutationsPlanarAutorouteReconfigurer::new(
|
|
autorouter,
|
|
preconfiguration,
|
|
presorter,
|
|
options,
|
|
),
|
|
)
|
|
/*RatlinesPermuter::RatlineCuts(RatlineCutsRatlinePermuter::new(
|
|
autorouter, ratlines, presorter, options,
|
|
))*/
|
|
}
|
|
}
|
|
|
|
pub struct SccPermutationsPlanarAutorouteReconfigurer {
|
|
sccs_permutations_iter: Skip<Permutations<std::vec::IntoIter<Scc>>>,
|
|
initial_configuration: PlanarAutorouteConfiguration,
|
|
}
|
|
|
|
impl SccPermutationsPlanarAutorouteReconfigurer {
|
|
pub fn new(
|
|
_autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
preconfiguration: PlanarAutorouteConfiguration,
|
|
presorter: SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
|
_options: &PlanarAutorouteOptions,
|
|
) -> Self {
|
|
// TODO: Instead of instantiating presorter again here, get it from
|
|
// an argument.
|
|
let sccs = presorter.dissolve();
|
|
let sccs_len = sccs.len();
|
|
|
|
Self {
|
|
sccs_permutations_iter: sccs.into_iter().permutations(sccs_len).skip(1),
|
|
initial_configuration: preconfiguration,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MakeNextPlanarAutorouteConfiguration for SccPermutationsPlanarAutorouteReconfigurer {
|
|
fn next_configuration(
|
|
&mut self,
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
_stepper: &PlanarAutorouteExecutionStepper,
|
|
) -> Option<Vec<RatlineUid>> {
|
|
let scc_permutation = self.sccs_permutations_iter.next()?;
|
|
let mut ratlines = vec![];
|
|
|
|
for scc in scc_permutation {
|
|
for ratline in self.initial_configuration.ratlines.iter() {
|
|
if scc.node_indices().contains(
|
|
&autorouter
|
|
.ratsnests()
|
|
.on_principal_layer(ratline.principal_layer)
|
|
.graph()
|
|
.edge_endpoints(ratline.index)
|
|
.unwrap()
|
|
.0,
|
|
) && scc.node_indices().contains(
|
|
&autorouter
|
|
.ratsnests()
|
|
.on_principal_layer(ratline.principal_layer)
|
|
.graph()
|
|
.edge_endpoints(ratline.index)
|
|
.unwrap()
|
|
.1,
|
|
) {
|
|
ratlines.push(*ratline);
|
|
}
|
|
}
|
|
}
|
|
|
|
Some(ratlines)
|
|
}
|
|
}
|
|
|
|
pub struct RatlineCutsPlanarAutorouteReconfigurer {
|
|
//sccs: Vec<Vec<NodeIndex<usize>>>,
|
|
}
|
|
|
|
impl RatlineCutsPlanarAutorouteReconfigurer {
|
|
pub fn new(
|
|
_autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
_ratlines: Vec<RatlineUid>,
|
|
_presorter: SccIntersectionsAndLengthRatlinePlanarAutoroutePreconfigurer,
|
|
_options: &PlanarAutorouteOptions,
|
|
) -> Self {
|
|
/*Self {
|
|
sccs: presorter.dissolve(),
|
|
}*/
|
|
Self {}
|
|
}
|
|
}
|
|
|
|
impl MakeNextPlanarAutorouteConfiguration for RatlineCutsPlanarAutorouteReconfigurer {
|
|
fn next_configuration(
|
|
&mut self,
|
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
|
stepper: &PlanarAutorouteExecutionStepper,
|
|
) -> Option<Vec<RatlineUid>> {
|
|
let curr_ratline = stepper.configuration().ratlines[*stepper.curr_ratline_index()];
|
|
let terminating_dots = curr_ratline.ref_(autorouter).terminating_dots();
|
|
let bands_cut_by_ratline: Vec<_> = autorouter
|
|
.board()
|
|
.layout()
|
|
.bands_between_nodes(
|
|
terminating_dots
|
|
.0
|
|
.primitive_ref(autorouter.board().layout().drawing())
|
|
.layer(),
|
|
GenericNode::Primitive(terminating_dots.0.into()),
|
|
GenericNode::Primitive(terminating_dots.1.into()),
|
|
)
|
|
.collect();
|
|
|
|
// Find the first ratline corresponding to a band that is cut.
|
|
let first_cut_ratline_index = stepper
|
|
.configuration()
|
|
.ratlines
|
|
.iter()
|
|
.position(|ratline| {
|
|
for (band_uid, _) in &bands_cut_by_ratline {
|
|
if ratline.ref_(autorouter).band_termseg() == band_uid.0
|
|
|| ratline.ref_(autorouter).band_termseg() == band_uid.1
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
false
|
|
})
|
|
.unwrap();
|
|
|
|
// Swap the first ratline corresponding to a band that is cut with the
|
|
// ratline that we have failed routing.
|
|
let mut ratlines = stepper.configuration().ratlines.clone();
|
|
ratlines.swap(*stepper.curr_ratline_index(), first_cut_ratline_index);
|
|
|
|
Some(ratlines)
|
|
}
|
|
}
|