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> {
|
||||
pub fn new(board: Board<M>) -> Result<Self, InsertionError> {
|
||||
let ratsnest = Ratsnest::new(board.layout())?;
|
||||
let ratsnest = Ratsnest::new(&board)?;
|
||||
Ok(Self { board, ratsnest })
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,51 +2,149 @@
|
|||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use derive_getters::Getters;
|
||||
use petgraph::unionfind::UnionFind;
|
||||
use specctra_core::rules::AccessRules;
|
||||
use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use crate::{
|
||||
drawing::{graph::PrimitiveIndex, primitive::GetJoints},
|
||||
board::Board,
|
||||
drawing::{dot::FixedDotIndex, graph::PrimitiveIndex, primitive::GetJoints},
|
||||
geometry::GenericNode,
|
||||
graph::GetIndex,
|
||||
layout::Layout,
|
||||
};
|
||||
|
||||
#[derive(Clone, Getters)]
|
||||
pub struct Conncomps {
|
||||
pub struct ConncompsWithPrincipalLayer {
|
||||
unionfind: UnionFind<usize>,
|
||||
}
|
||||
|
||||
impl Conncomps {
|
||||
pub fn new(layout: &Layout<impl AccessRules>) -> Self {
|
||||
let mut unionfind = UnionFind::new(layout.drawing().geometry().dot_index_bound());
|
||||
impl ConncompsWithPrincipalLayer {
|
||||
pub fn new(board: &Board<impl AccessMesadata>, principal_layer: usize) -> Self {
|
||||
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() {
|
||||
match primitive {
|
||||
PrimitiveIndex::FixedSeg(seg) => {
|
||||
let joints = layout.drawing().primitive(seg).joints();
|
||||
unionfind.union(joints.0.index(), joints.1.index());
|
||||
for node in board
|
||||
.layout()
|
||||
.drawing()
|
||||
.layer_primitive_nodes(principal_layer)
|
||||
{
|
||||
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 }
|
||||
}
|
||||
|
||||
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 petgraph::{data::Element, prelude::StableUnGraph};
|
||||
use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2};
|
||||
use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use crate::{
|
||||
autorouter::conncomps::Conncomps,
|
||||
autorouter::conncomps::ConncompsWithPrincipalLayer,
|
||||
board::Board,
|
||||
drawing::{
|
||||
band::BandTermsegIndex,
|
||||
dot::FixedDotIndex,
|
||||
graph::{GetMaybeNet, MakePrimitiveRef, PrimitiveIndex},
|
||||
primitive::MakePrimitiveShape,
|
||||
rules::AccessRules,
|
||||
},
|
||||
geometry::shape::AccessShape,
|
||||
graph::{GenericIndex, GetIndex, MakeRef},
|
||||
layout::{
|
||||
poly::{MakePolygon, PolyWeight},
|
||||
Layout,
|
||||
},
|
||||
layout::poly::{MakePolygon, PolyWeight},
|
||||
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
||||
};
|
||||
|
||||
|
|
@ -107,8 +105,8 @@ pub struct Ratsnest {
|
|||
}
|
||||
|
||||
impl Ratsnest {
|
||||
pub fn new(layout: &Layout<impl AccessRules>) -> Result<Self, InsertionError> {
|
||||
let conncomps = Conncomps::new(layout);
|
||||
pub fn new(board: &Board<impl AccessMesadata>) -> Result<Self, InsertionError> {
|
||||
let conncomps = ConncompsWithPrincipalLayer::new(board, 0);
|
||||
|
||||
let mut this = Self {
|
||||
graph: StableUnGraph::default(),
|
||||
|
|
@ -116,16 +114,16 @@ impl Ratsnest {
|
|||
|
||||
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 =
|
||||
|maybe_net: Option<usize>, vertex: RatvertexIndex, pos: Point| {
|
||||
if let Some(net) = maybe_net {
|
||||
triangulations
|
||||
.entry((layer, net))
|
||||
.entry(net)
|
||||
.or_insert_with(|| {
|
||||
Triangulation::new(RatvertexToHandleMap::new(
|
||||
layout.drawing().geometry().dot_index_bound(),
|
||||
layout.drawing().geometry().compound_index_bound(),
|
||||
board.layout().drawing().geometry().dot_index_bound(),
|
||||
board.layout().drawing().geometry().compound_index_bound(),
|
||||
))
|
||||
})
|
||||
.add_vertex(RatvertexWeight { vertex, pos })?;
|
||||
|
|
@ -133,30 +131,36 @@ impl Ratsnest {
|
|||
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 {
|
||||
// Dots that are parts of polys are ignored because ratlines
|
||||
// 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(
|
||||
layout.drawing().primitive(dot).maybe_net(),
|
||||
board.layout().drawing().primitive(dot).maybe_net(),
|
||||
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(
|
||||
layout.drawing().compound_weight(poly.into()).maybe_net(),
|
||||
board
|
||||
.layout()
|
||||
.drawing()
|
||||
.compound_weight(poly.into())
|
||||
.maybe_net(),
|
||||
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();
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> impl Iterator<Item = &K> + '_ {
|
||||
self.key_to_values.keys()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,11 @@ impl<M: AccessMesadata> Board<M> {
|
|||
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
|
||||
/// pin name.
|
||||
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)
|
||||
}
|
||||
|
||||
/// Creates band between the two nodes
|
||||
/// Registers that a band is between the two nodes.
|
||||
pub fn try_set_band_between_nodes(
|
||||
&mut self,
|
||||
recorder: &mut BoardDataEdit,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{fs::File, io::BufReader};
|
|||
|
||||
use topola::{
|
||||
autorouter::{
|
||||
conncomps::Conncomps,
|
||||
conncomps::ConncompsWithPrincipalLayer,
|
||||
history::{History, HistoryError},
|
||||
invoker::{Invoker, InvokerError},
|
||||
Autorouter,
|
||||
|
|
@ -174,7 +174,7 @@ pub fn assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
|||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
layername: &str,
|
||||
) {
|
||||
let conncomps = Conncomps::new(autorouter.board().layout());
|
||||
let conncomps = ConncompsWithPrincipalLayer::new(autorouter.board().layout());
|
||||
|
||||
for ratline in autorouter.ratsnest().graph().edge_indices() {
|
||||
let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots();
|
||||
|
|
|
|||
Loading…
Reference in New Issue