mirror of https://codeberg.org/topola/topola.git
feat(autorouter/ratsnest): Have ratlines across layers
This commit is contained in:
parent
d74a06b2ea
commit
a4a000feb9
|
|
@ -73,7 +73,7 @@ pub struct Autorouter<M> {
|
||||||
|
|
||||||
impl<M: AccessMesadata> Autorouter<M> {
|
impl<M: AccessMesadata> Autorouter<M> {
|
||||||
pub fn new(board: Board<M>) -> Result<Self, InsertionError> {
|
pub fn new(board: Board<M>) -> Result<Self, InsertionError> {
|
||||||
let ratsnest = Ratsnest::new(board.layout())?;
|
let ratsnest = Ratsnest::new(&board)?;
|
||||||
Ok(Self { board, ratsnest })
|
Ok(Self { board, ratsnest })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,51 +2,149 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use derive_getters::Getters;
|
use derive_getters::Getters;
|
||||||
use petgraph::unionfind::UnionFind;
|
use petgraph::unionfind::UnionFind;
|
||||||
use specctra_core::rules::AccessRules;
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing::{graph::PrimitiveIndex, primitive::GetJoints},
|
board::Board,
|
||||||
|
drawing::{dot::FixedDotIndex, graph::PrimitiveIndex, primitive::GetJoints},
|
||||||
|
geometry::GenericNode,
|
||||||
graph::GetIndex,
|
graph::GetIndex,
|
||||||
layout::Layout,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Getters)]
|
#[derive(Clone, Getters)]
|
||||||
pub struct Conncomps {
|
pub struct ConncompsWithPrincipalLayer {
|
||||||
unionfind: UnionFind<usize>,
|
unionfind: UnionFind<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Conncomps {
|
impl ConncompsWithPrincipalLayer {
|
||||||
pub fn new(layout: &Layout<impl AccessRules>) -> Self {
|
pub fn new(board: &Board<impl AccessMesadata>, principal_layer: usize) -> Self {
|
||||||
let mut unionfind = UnionFind::new(layout.drawing().geometry().dot_index_bound());
|
let mut principally_visited_pins = BTreeSet::new();
|
||||||
|
let mut unionfind = UnionFind::new(board.layout().drawing().geometry().dot_index_bound());
|
||||||
|
|
||||||
for primitive in layout.drawing().primitive_nodes() {
|
for node in board
|
||||||
match primitive {
|
.layout()
|
||||||
PrimitiveIndex::FixedSeg(seg) => {
|
.drawing()
|
||||||
let joints = layout.drawing().primitive(seg).joints();
|
.layer_primitive_nodes(principal_layer)
|
||||||
unionfind.union(joints.0.index(), joints.1.index());
|
{
|
||||||
|
Self::unionize_primitive_endpoint_dots(board, &mut unionfind, node);
|
||||||
|
|
||||||
|
if let Some(pinname) = board.node_pinname(&GenericNode::Primitive(node)) {
|
||||||
|
principally_visited_pins.insert(pinname.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*for layer in 0..board.layout().drawing().layer_count() {
|
||||||
|
if layer != principal_layer {
|
||||||
|
for primitive in board.layout().drawing().layer_primitive_nodes(layer) {
|
||||||
|
if let Some(pinname) = board.node_pinname(&GenericNode::Primitive(primitive)) {
|
||||||
|
if !principally_visited_pins.contains(pinname) {
|
||||||
|
Self::unionize_by_primitive(board, &mut unionfind, primitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PrimitiveIndex::LoneLooseSeg(seg) => {
|
}
|
||||||
let joints = layout.drawing().primitive(seg).joints();
|
}*/
|
||||||
unionfind.union(joints.0.index(), joints.1.index());
|
|
||||||
|
//TODO for pinname in board.pins() if !principally_visited_pins.contains(pinname) for node in board.pinname_nodes() unionize to first found element
|
||||||
|
|
||||||
|
for pinname in board.pinnames() {
|
||||||
|
if principally_visited_pins.contains(pinname) {
|
||||||
|
let mut iter = board.pinname_nodes(pinname);
|
||||||
|
let Some(first_fixed_dot) = iter.find_map(|node| {
|
||||||
|
if let GenericNode::Primitive(PrimitiveIndex::FixedDot(first_fixed_dot)) = node
|
||||||
|
{
|
||||||
|
Some(first_fixed_dot)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
for node in board.pinname_nodes(pinname) {
|
||||||
|
if let GenericNode::Primitive(primitive) = node {
|
||||||
|
Self::unionize_to_common(board, &mut unionfind, primitive, first_fixed_dot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
PrimitiveIndex::SeqLooseSeg(seg) => {
|
|
||||||
let joints = layout.drawing().primitive(seg).joints();
|
|
||||||
unionfind.union(joints.0.index(), joints.1.index());
|
|
||||||
}
|
|
||||||
PrimitiveIndex::FixedBend(bend) => {
|
|
||||||
let joints = layout.drawing().primitive(bend).joints();
|
|
||||||
unionfind.union(joints.0.index(), joints.1.index());
|
|
||||||
}
|
|
||||||
PrimitiveIndex::LooseBend(bend) => {
|
|
||||||
let joints = layout.drawing().primitive(bend).joints();
|
|
||||||
unionfind.union(joints.0.index(), joints.1.index());
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { unionfind }
|
Self { unionfind }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unionize_primitive_endpoint_dots(
|
||||||
|
board: &Board<impl AccessMesadata>,
|
||||||
|
unionfind: &mut UnionFind<usize>,
|
||||||
|
primitive: PrimitiveIndex,
|
||||||
|
) {
|
||||||
|
match primitive {
|
||||||
|
PrimitiveIndex::FixedSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(joints.0.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::LoneLooseSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(joints.0.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::SeqLooseSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(joints.0.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::FixedBend(bend) => {
|
||||||
|
let joints = board.layout().drawing().primitive(bend).joints();
|
||||||
|
unionfind.union(joints.0.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::LooseBend(bend) => {
|
||||||
|
let joints = board.layout().drawing().primitive(bend).joints();
|
||||||
|
unionfind.union(joints.0.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unionize_to_common(
|
||||||
|
board: &Board<impl AccessMesadata>,
|
||||||
|
unionfind: &mut UnionFind<usize>,
|
||||||
|
primitive: PrimitiveIndex,
|
||||||
|
common: FixedDotIndex,
|
||||||
|
) {
|
||||||
|
match primitive {
|
||||||
|
PrimitiveIndex::FixedDot(dot) => {
|
||||||
|
unionfind.union(common.index(), dot.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::LooseDot(dot) => {
|
||||||
|
unionfind.union(common.index(), dot.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::FixedSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(common.index(), joints.0.index());
|
||||||
|
unionfind.union(common.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::LoneLooseSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(common.index(), joints.0.index());
|
||||||
|
unionfind.union(common.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::SeqLooseSeg(seg) => {
|
||||||
|
let joints = board.layout().drawing().primitive(seg).joints();
|
||||||
|
unionfind.union(common.index(), joints.0.index());
|
||||||
|
unionfind.union(common.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::FixedBend(bend) => {
|
||||||
|
let joints = board.layout().drawing().primitive(bend).joints();
|
||||||
|
unionfind.union(common.index(), joints.0.index());
|
||||||
|
unionfind.union(common.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
PrimitiveIndex::LooseBend(bend) => {
|
||||||
|
let joints = board.layout().drawing().primitive(bend).joints();
|
||||||
|
unionfind.union(common.index(), joints.0.index());
|
||||||
|
unionfind.union(common.index(), joints.1.index());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,22 +11,20 @@ use enum_dispatch::enum_dispatch;
|
||||||
use geo::Point;
|
use geo::Point;
|
||||||
use petgraph::{data::Element, prelude::StableUnGraph};
|
use petgraph::{data::Element, prelude::StableUnGraph};
|
||||||
use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2};
|
use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2};
|
||||||
|
use specctra_core::mesadata::AccessMesadata;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
autorouter::conncomps::Conncomps,
|
autorouter::conncomps::ConncompsWithPrincipalLayer,
|
||||||
|
board::Board,
|
||||||
drawing::{
|
drawing::{
|
||||||
band::BandTermsegIndex,
|
band::BandTermsegIndex,
|
||||||
dot::FixedDotIndex,
|
dot::FixedDotIndex,
|
||||||
graph::{GetMaybeNet, MakePrimitiveRef, PrimitiveIndex},
|
graph::{GetMaybeNet, MakePrimitiveRef, PrimitiveIndex},
|
||||||
primitive::MakePrimitiveShape,
|
primitive::MakePrimitiveShape,
|
||||||
rules::AccessRules,
|
|
||||||
},
|
},
|
||||||
geometry::shape::AccessShape,
|
geometry::shape::AccessShape,
|
||||||
graph::{GenericIndex, GetIndex, MakeRef},
|
graph::{GenericIndex, GetIndex, MakeRef},
|
||||||
layout::{
|
layout::poly::{MakePolygon, PolyWeight},
|
||||||
poly::{MakePolygon, PolyWeight},
|
|
||||||
Layout,
|
|
||||||
},
|
|
||||||
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -107,8 +105,8 @@ pub struct Ratsnest {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ratsnest {
|
impl Ratsnest {
|
||||||
pub fn new(layout: &Layout<impl AccessRules>) -> Result<Self, InsertionError> {
|
pub fn new(board: &Board<impl AccessMesadata>) -> Result<Self, InsertionError> {
|
||||||
let conncomps = Conncomps::new(layout);
|
let conncomps = ConncompsWithPrincipalLayer::new(board, 0);
|
||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
graph: StableUnGraph::default(),
|
graph: StableUnGraph::default(),
|
||||||
|
|
@ -116,16 +114,16 @@ impl Ratsnest {
|
||||||
|
|
||||||
let mut triangulations = BTreeMap::new();
|
let mut triangulations = BTreeMap::new();
|
||||||
|
|
||||||
for layer in 0..layout.drawing().layer_count() {
|
for layer in 0..board.layout().drawing().layer_count() {
|
||||||
let mut handle_ratvertex_weight =
|
let mut handle_ratvertex_weight =
|
||||||
|maybe_net: Option<usize>, vertex: RatvertexIndex, pos: Point| {
|
|maybe_net: Option<usize>, vertex: RatvertexIndex, pos: Point| {
|
||||||
if let Some(net) = maybe_net {
|
if let Some(net) = maybe_net {
|
||||||
triangulations
|
triangulations
|
||||||
.entry((layer, net))
|
.entry(net)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
Triangulation::new(RatvertexToHandleMap::new(
|
Triangulation::new(RatvertexToHandleMap::new(
|
||||||
layout.drawing().geometry().dot_index_bound(),
|
board.layout().drawing().geometry().dot_index_bound(),
|
||||||
layout.drawing().geometry().compound_index_bound(),
|
board.layout().drawing().geometry().compound_index_bound(),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.add_vertex(RatvertexWeight { vertex, pos })?;
|
.add_vertex(RatvertexWeight { vertex, pos })?;
|
||||||
|
|
@ -133,30 +131,36 @@ impl Ratsnest {
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
for node in layout.drawing().layer_primitive_nodes(layer) {
|
for node in board.layout().drawing().layer_primitive_nodes(layer) {
|
||||||
if let PrimitiveIndex::FixedDot(dot) = node {
|
if let PrimitiveIndex::FixedDot(dot) = node {
|
||||||
// Dots that are parts of polys are ignored because ratlines
|
// Dots that are parts of polys are ignored because ratlines
|
||||||
// should only go to their centerpoints.
|
// should only go to their centerpoints.
|
||||||
if layout.drawing().compounds(dot).next().is_none() {
|
if board.layout().drawing().compounds(dot).next().is_none() {
|
||||||
handle_ratvertex_weight(
|
handle_ratvertex_weight(
|
||||||
layout.drawing().primitive(dot).maybe_net(),
|
board.layout().drawing().primitive(dot).maybe_net(),
|
||||||
RatvertexIndex::FixedDot(dot),
|
RatvertexIndex::FixedDot(dot),
|
||||||
node.primitive_ref(layout.drawing()).shape().center(),
|
node.primitive_ref(board.layout().drawing())
|
||||||
|
.shape()
|
||||||
|
.center(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for poly in layout.layer_poly_nodes(layer) {
|
for poly in board.layout().layer_poly_nodes(layer) {
|
||||||
handle_ratvertex_weight(
|
handle_ratvertex_weight(
|
||||||
layout.drawing().compound_weight(poly.into()).maybe_net(),
|
board
|
||||||
|
.layout()
|
||||||
|
.drawing()
|
||||||
|
.compound_weight(poly.into())
|
||||||
|
.maybe_net(),
|
||||||
RatvertexIndex::Poly(poly),
|
RatvertexIndex::Poly(poly),
|
||||||
poly.ref_(layout).shape().center(),
|
poly.ref_(board.layout()).shape().center(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((_layer, _net), triangulation) in triangulations {
|
for (_net, triangulation) in triangulations {
|
||||||
let mut map = Vec::new();
|
let mut map = Vec::new();
|
||||||
|
|
||||||
for element in petgraph::algo::min_spanning_tree(&triangulation) {
|
for element in petgraph::algo::min_spanning_tree(&triangulation) {
|
||||||
|
|
|
||||||
|
|
@ -97,4 +97,8 @@ impl<K: Eq + Ord + Clone, V: Eq + Ord + Clone> BiBTreeMapSet<K, V> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> impl Iterator<Item = &K> + '_ {
|
||||||
|
self.key_to_values.keys()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,11 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
poly
|
poly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over all the pin names.
|
||||||
|
pub fn pinnames(&self) -> impl Iterator<Item = &String> + '_ {
|
||||||
|
self.pinname_nodes.keys()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns an iterator over the set of all nodes associated with a given
|
/// Returns an iterator over the set of all nodes associated with a given
|
||||||
/// pin name.
|
/// pin name.
|
||||||
pub fn pinname_nodes(&self, pinname: &str) -> impl Iterator<Item = NodeIndex> + '_ {
|
pub fn pinname_nodes(&self, pinname: &str) -> impl Iterator<Item = NodeIndex> + '_ {
|
||||||
|
|
@ -215,7 +220,7 @@ impl<M: AccessMesadata> Board<M> {
|
||||||
self.band_bandname.get_by_right(bandname)
|
self.band_bandname.get_by_right(bandname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates band between the two nodes
|
/// Registers that a band is between the two nodes.
|
||||||
pub fn try_set_band_between_nodes(
|
pub fn try_set_band_between_nodes(
|
||||||
&mut self,
|
&mut self,
|
||||||
recorder: &mut BoardDataEdit,
|
recorder: &mut BoardDataEdit,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use std::{fs::File, io::BufReader};
|
||||||
|
|
||||||
use topola::{
|
use topola::{
|
||||||
autorouter::{
|
autorouter::{
|
||||||
conncomps::Conncomps,
|
conncomps::ConncompsWithPrincipalLayer,
|
||||||
history::{History, HistoryError},
|
history::{History, HistoryError},
|
||||||
invoker::{Invoker, InvokerError},
|
invoker::{Invoker, InvokerError},
|
||||||
Autorouter,
|
Autorouter,
|
||||||
|
|
@ -174,7 +174,7 @@ pub fn assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||||
layername: &str,
|
layername: &str,
|
||||||
) {
|
) {
|
||||||
let conncomps = Conncomps::new(autorouter.board().layout());
|
let conncomps = ConncompsWithPrincipalLayer::new(autorouter.board().layout());
|
||||||
|
|
||||||
for ratline in autorouter.ratsnest().graph().edge_indices() {
|
for ratline in autorouter.ratsnest().graph().edge_indices() {
|
||||||
let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots();
|
let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue