mirror of https://codeberg.org/topola/topola.git
test: Add stable multivibrator test, the first multilayer autorouting test
This commit is contained in:
parent
dd8a4c5808
commit
63764a7e29
|
|
@ -1,7 +1,6 @@
|
|||
// SPDX-FileCopyrightText: 2025 Topola contributors
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
use derive_getters::Getters;
|
||||
|
|
@ -16,12 +15,32 @@ use crate::{
|
|||
};
|
||||
|
||||
#[derive(Clone, Getters)]
|
||||
pub struct ConncompsWithPrincipalLayer {
|
||||
pub struct Conncomps {
|
||||
unionfind: UnionFind<usize>,
|
||||
}
|
||||
|
||||
impl ConncompsWithPrincipalLayer {
|
||||
pub fn new(board: &Board<impl AccessMesadata>, principal_layer: usize) -> Self {
|
||||
impl Conncomps {
|
||||
pub fn new(board: &Board<impl AccessMesadata>) -> Self {
|
||||
let mut unionfind = UnionFind::new(board.layout().drawing().geometry().dot_index_bound());
|
||||
|
||||
for node in board.layout().drawing().primitive_nodes() {
|
||||
Self::unionize_primitive_endpoint_dots(board, &mut unionfind, node);
|
||||
}
|
||||
|
||||
// Pins can have padstacks that span multiple layers. To account for
|
||||
// that, we have another loop to go over all the pins and connect all
|
||||
// their primitives.
|
||||
for pinname in board.pinnames() {
|
||||
Self::unionize_pin(board, &mut unionfind, pinname);
|
||||
}
|
||||
|
||||
Self { unionfind }
|
||||
}
|
||||
|
||||
pub fn new_with_principal_layer(
|
||||
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());
|
||||
|
||||
|
|
@ -42,23 +61,7 @@ impl ConncompsWithPrincipalLayer {
|
|||
// their primitives.
|
||||
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);
|
||||
}
|
||||
}
|
||||
Self::unionize_pin(board, &mut unionfind, pinname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,6 +102,29 @@ impl ConncompsWithPrincipalLayer {
|
|||
}
|
||||
}
|
||||
|
||||
fn unionize_pin(
|
||||
board: &Board<impl AccessMesadata>,
|
||||
unionfind: &mut UnionFind<usize>,
|
||||
pinname: &str,
|
||||
) {
|
||||
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 {
|
||||
return;
|
||||
};
|
||||
|
||||
for node in board.pinname_nodes(pinname) {
|
||||
if let GenericNode::Primitive(primitive) = node {
|
||||
Self::unionize_to_common(board, unionfind, primitive, first_fixed_dot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unionize_to_common(
|
||||
board: &Board<impl AccessMesadata>,
|
||||
unionfind: &mut UnionFind<usize>,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use petgraph::graph::{EdgeIndex, NodeIndex};
|
|||
use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use crate::{
|
||||
autorouter::{ratsnest::RatvertexNodeIndex, Autorouter},
|
||||
drawing::{
|
||||
band::BandTermsegIndex,
|
||||
dot::FixedDotIndex,
|
||||
|
|
@ -17,8 +18,6 @@ use crate::{
|
|||
triangulation::GetTrianvertexNodeIndex,
|
||||
};
|
||||
|
||||
use super::{ratsnest::RatvertexNodeIndex, Autorouter};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct RatlineUid {
|
||||
pub principal_layer: usize,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use spade::{handles::FixedVertexHandle, HasPosition, InsertionError, Point2};
|
|||
use specctra_core::mesadata::AccessMesadata;
|
||||
|
||||
use crate::{
|
||||
autorouter::conncomps::Conncomps,
|
||||
board::Board,
|
||||
drawing::{
|
||||
band::BandTermsegIndex,
|
||||
|
|
@ -31,7 +32,7 @@ use crate::{
|
|||
triangulation::{GetTrianvertexNodeIndex, Triangulation},
|
||||
};
|
||||
|
||||
use super::{conncomps::ConncompsWithPrincipalLayer, ratline::RatlineWeight};
|
||||
use super::ratline::RatlineWeight;
|
||||
|
||||
#[enum_dispatch(GetIndex)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
|
|
@ -113,7 +114,7 @@ impl Ratsnest {
|
|||
board: &Board<impl AccessMesadata>,
|
||||
principal_layer: usize,
|
||||
) -> Result<Self, InsertionError> {
|
||||
let conncomps = ConncompsWithPrincipalLayer::new(board, principal_layer);
|
||||
let conncomps = Conncomps::new_with_principal_layer(board, principal_layer);
|
||||
|
||||
let mut this = Self {
|
||||
graph: StableUnGraph::default(),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{fs::File, io::BufReader};
|
|||
|
||||
use topola::{
|
||||
autorouter::{
|
||||
conncomps::ConncompsWithPrincipalLayer,
|
||||
conncomps::Conncomps,
|
||||
history::{History, HistoryError},
|
||||
invoker::{Invoker, InvokerError},
|
||||
ratline::RatlineUid,
|
||||
|
|
@ -176,64 +176,25 @@ pub fn assert_layer_0_navnode_count(
|
|||
assert_eq!(navmesh.graph().node_count(), expected_count);
|
||||
}
|
||||
|
||||
pub fn assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
pub fn assert_that_all_ratlines_besides_gnd_are_autorouted(
|
||||
autorouter: &mut Autorouter<impl AccessMesadata>,
|
||||
layername: &str,
|
||||
) {
|
||||
let layer = autorouter
|
||||
.board()
|
||||
.layout()
|
||||
.rules()
|
||||
.layername_layer(layername)
|
||||
.unwrap();
|
||||
let conncomps = ConncompsWithPrincipalLayer::new(autorouter.board(), layer);
|
||||
let conncomps = Conncomps::new(autorouter.board());
|
||||
assert!(autorouter.board().layout().drawing().layer_count() >= 1);
|
||||
|
||||
for principal_layer in 0..autorouter.board().layout().drawing().layer_count() {
|
||||
for ratline in autorouter
|
||||
.ratsnests()
|
||||
.on_principal_layer(layer)
|
||||
.on_principal_layer(principal_layer)
|
||||
.graph()
|
||||
.edge_indices()
|
||||
.map(|index| RatlineUid {
|
||||
principal_layer: layer,
|
||||
principal_layer,
|
||||
index,
|
||||
})
|
||||
{
|
||||
let (origin_dot, destination_dot) = ratline.ref_(autorouter).endpoint_dots();
|
||||
|
||||
let origin_layer = autorouter
|
||||
.board()
|
||||
.layout()
|
||||
.drawing()
|
||||
.primitive(origin_dot)
|
||||
.layer();
|
||||
let destination_layer = autorouter
|
||||
.board()
|
||||
.layout()
|
||||
.drawing()
|
||||
.primitive(destination_dot)
|
||||
.layer();
|
||||
|
||||
if let (Some(origin_layername), Some(destination_layername)) = (
|
||||
autorouter
|
||||
.board()
|
||||
.layout()
|
||||
.rules()
|
||||
.layer_layername(origin_layer),
|
||||
autorouter
|
||||
.board()
|
||||
.layout()
|
||||
.rules()
|
||||
.layer_layername(destination_layer),
|
||||
) {
|
||||
assert_eq!(origin_layername, destination_layername);
|
||||
|
||||
if origin_layername != layername {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
|
||||
let origin_net = autorouter
|
||||
.board()
|
||||
.layout()
|
||||
|
|
@ -252,11 +213,12 @@ pub fn assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
|||
|
||||
if let Some(netname) = autorouter.board().layout().rules().net_netname(net) {
|
||||
// We don't route ground.
|
||||
let org = conncomps.unionfind().find(origin_dot.index());
|
||||
let desc = conncomps.unionfind().find(destination_dot.index());
|
||||
let origin = conncomps.unionfind().find(origin_dot.index());
|
||||
let destination = conncomps.unionfind().find(destination_dot.index());
|
||||
|
||||
if netname != "GND" {
|
||||
assert_eq!(org, desc);
|
||||
assert_eq!(origin, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,22 @@ fn test_unrouted_lm317_breakout() {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_astable_multivibrator() {
|
||||
let mut invoker = common::create_invoker_and_assert(common::load_design(
|
||||
"tests/multilayer/astable_multivibrator/astable_multivibrator.dsn",
|
||||
));
|
||||
|
||||
common::replay_and_assert_and_report(
|
||||
&mut invoker,
|
||||
"tests/multilayer/astable_multivibrator/autoroute_all.cmd",
|
||||
"plain",
|
||||
);
|
||||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_signal_integrity_test() {
|
||||
let invoker = common::create_invoker_and_assert(common::load_design(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"done": [
|
||||
{
|
||||
"MultilayerAutoroute": [
|
||||
[
|
||||
{
|
||||
"pin": "C1-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "C1-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "C2-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "C2-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "D1-1",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "D1-2",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "D2-1",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "D2-2",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "J1-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "J1-1",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "J2-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "J2-1",
|
||||
"layer": "F.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q1-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q1-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q1-3",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q2-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q2-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "Q2-3",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R1-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R1-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R2-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R2-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R3-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R3-2",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R4-1",
|
||||
"layer": "B.Cu"
|
||||
},
|
||||
{
|
||||
"pin": "R4-2",
|
||||
"layer": "B.Cu"
|
||||
}
|
||||
],
|
||||
{
|
||||
"anterouter": {
|
||||
"fanout_clearance": 200.0
|
||||
},
|
||||
"planar": {
|
||||
"principal_layer": 0,
|
||||
"presort_by": "RatlineIntersectionCountAndLength",
|
||||
"permutate": true,
|
||||
"router": {
|
||||
"routed_band_width": 100.0,
|
||||
"wrap_around_bands": true,
|
||||
"squeeze_through_under_bends": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"undone": []
|
||||
}
|
||||
|
|
@ -35,10 +35,7 @@ fn autoroute_4x4_1206_led_matrix_breakout(variant: &str) {
|
|||
);
|
||||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[apply(test_master)]
|
||||
|
|
@ -54,10 +51,7 @@ fn autoroute_4x4_1206_led_matrix_breakout_in_predefined_order(variant: &str) {
|
|||
);
|
||||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[apply(test_master)]
|
||||
|
|
@ -73,10 +67,7 @@ fn autoroute_tht_de9_to_tht_de9(variant: &str) {
|
|||
);
|
||||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[apply(test_master)]
|
||||
|
|
@ -91,10 +82,7 @@ fn autoroute_tht_de9_to_tht_de9_in_predefined_order(variant: &str) {
|
|||
);
|
||||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[apply(test_master)]
|
||||
|
|
@ -110,10 +98,7 @@ fn autoroute_0603_breakout(variant: &str) {
|
|||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
//common::assert_number_of_conncomps(&mut autorouter, 2);
|
||||
}
|
||||
|
||||
|
|
@ -132,10 +117,7 @@ fn autoroute_tht_diode_bridge_rectifier(variant: &str) {
|
|||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
//common::assert_number_of_conncomps(&mut autorouter, 4);
|
||||
common::assert_band_length(autorouter.board(), "J2-2", "D4-2", 15906.760439007436, 0.01);
|
||||
|
||||
|
|
@ -172,10 +154,7 @@ fn autoroute_4x_3rd_order_smd_lc_filters(variant: &str) {
|
|||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
//common::assert_number_of_conncomps(&mut autorouter, 16);
|
||||
}
|
||||
|
||||
|
|
@ -216,10 +195,7 @@ fn autoroute_vga_dac_breakout(variant: &str) {
|
|||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
}
|
||||
|
||||
#[apply(test_master)]
|
||||
|
|
@ -237,9 +213,6 @@ fn autoroute_smd_non_rectangular_buck_converter(variant: &str) {
|
|||
|
||||
let (mut autorouter, ..) = invoker.dissolve();
|
||||
|
||||
common::assert_that_all_single_layer_groundless_ratlines_are_autorouted(
|
||||
&mut autorouter,
|
||||
"F.Cu",
|
||||
);
|
||||
common::assert_that_all_ratlines_besides_gnd_are_autorouted(&mut autorouter);
|
||||
//common::assert_number_of_conncomps(&mut autorouter, 16);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue