diff --git a/Cargo.toml b/Cargo.toml index 83cc0dd..a44e5a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ serde_json = "1.0.117" enum_dispatch = "0.3.12" itertools = "0.8.2" contracts = "0.6.3" +bimap = "0.6.3" log = "0.4" [dependencies.serde] diff --git a/src/autorouter/selection.rs b/src/autorouter/selection.rs index 45abf73..ff49aef 100644 --- a/src/autorouter/selection.rs +++ b/src/autorouter/selection.rs @@ -67,8 +67,10 @@ impl Selection { NodeIndex::Compound(compound) => board.layout().zone(compound).layer(), }; - if let (Some(pinname), Some(layername)) = (board.node_pinname(node), board.layername(layer)) - { + if let (Some(pinname), Some(layername)) = ( + board.node_pinname(node), + board.layout().rules().layer_layername(layer), + ) { Some(Selector { pin: pinname.to_string(), layer: layername.to_string(), diff --git a/src/bin/topola-egui/overlay.rs b/src/bin/topola-egui/overlay.rs index d56e14c..633ac21 100644 --- a/src/bin/topola-egui/overlay.rs +++ b/src/bin/topola-egui/overlay.rs @@ -6,11 +6,10 @@ use spade::InsertionError; use topola::{ autorouter::{ratsnest::Ratsnest, selection::Selection}, - board::Board, + board::{mesadata::MesadataTrait, Board}, drawing::{ graph::{GetLayer, MakePrimitive}, primitive::MakePrimitiveShape, - rules::RulesTrait, }, geometry::{ compound::CompoundManagerTrait, @@ -26,7 +25,7 @@ pub struct Overlay { } impl Overlay { - pub fn new(board: &Board) -> Result { + pub fn new(board: &Board) -> Result { Ok(Self { ratsnest: Ratsnest::new(board.layout())?, selection: Selection::new(), @@ -34,7 +33,7 @@ impl Overlay { }) } - pub fn click(&mut self, board: &Board, at: Point) { + pub fn click(&mut self, board: &Board, at: Point) { let geoms: Vec<_> = board .layout() .drawing() @@ -65,7 +64,7 @@ impl Overlay { fn toggle_selection_if_contains_point( &mut self, - board: &Board, + board: &Board, node: NodeIndex, p: Point, ) -> bool { diff --git a/src/board/board.rs b/src/board/board.rs index 87b095c..8570a85 100644 --- a/src/board/board.rs +++ b/src/board/board.rs @@ -24,8 +24,6 @@ use crate::{ pub struct Board { layout: Layout, node_to_pinname: HashMap, - layer_to_layername: HashMap, - net_to_netname: HashMap, pinname_pair_to_band: HashMap<(String, String), BandIndex>, } @@ -34,8 +32,6 @@ impl Board { Self { layout, node_to_pinname: HashMap::new(), - layer_to_layername: HashMap::new(), - net_to_netname: HashMap::new(), pinname_pair_to_band: HashMap::new(), } } @@ -145,14 +141,6 @@ impl Board { result } - pub fn bename_layer(&mut self, layer: u64, layername: String) { - self.layer_to_layername.insert(layer, layername); - } - - pub fn bename_net(&mut self, net: usize, netname: String) { - self.net_to_netname.insert(net, netname); - } - pub fn zone_apex(&mut self, zone: GenericIndex) -> FixedDotIndex { if let Some(apex) = self.layout.zone(zone).maybe_apex() { apex @@ -176,14 +164,6 @@ impl Board { self.node_to_pinname.get(&node) } - pub fn layername(&self, layer: u64) -> Option<&String> { - self.layer_to_layername.get(&layer) - } - - pub fn netname(&self, net: usize) -> Option<&String> { - self.net_to_netname.get(&net) - } - pub fn band_between_pins(&self, pinname1: &str, pinname2: &str) -> Option { if let Some(band) = self .pinname_pair_to_band diff --git a/src/board/mesadata.rs b/src/board/mesadata.rs index cdbf113..1e0b0f6 100644 --- a/src/board/mesadata.rs +++ b/src/board/mesadata.rs @@ -2,9 +2,11 @@ use crate::{drawing::rules::RulesTrait, layout::NodeIndex}; // TODO: use this trait. pub trait MesadataTrait: RulesTrait { - /*fn node_pinname(&self, node: NodeIndex); - fn layer_layername(&self, layer: u64) -> &str; - fn layername_layer(&self, layername: &str) -> u64; - fn net_netname(&self, net: usize) -> &str; - fn netname_net(&self, netname: &str) -> usize;*/ + fn bename_layer(&mut self, layer: u64, layername: String); + fn layer_layername(&self, layer: u64) -> Option<&str>; + fn layername_layer(&self, layername: &str) -> Option; + + fn bename_net(&mut self, net: usize, netname: String); + fn net_netname(&self, net: usize) -> Option<&str>; + fn netname_net(&self, netname: &str) -> Option; } diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index 4eb49d8..badf80d 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -836,6 +836,12 @@ impl Drawing { &self.rules } + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count()))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn rules_mut(&mut self) -> &mut R { + &mut self.rules + } + pub fn guide(&self) -> Guide { Guide::new(self) } diff --git a/src/dsn/design.rs b/src/dsn/design.rs index 1610ed7..1a20f1d 100644 --- a/src/dsn/design.rs +++ b/src/dsn/design.rs @@ -4,7 +4,7 @@ use geo::{point, Point, Rotate, Translate}; use thiserror::Error; use crate::{ - board::Board, + board::{mesadata::MesadataTrait, Board}, drawing::{dot::FixedDotWeight, seg::FixedSegWeight, Drawing}, dsn::{ de, @@ -60,8 +60,7 @@ impl DsnDesign { .layout() .drawing() .rules() - .netname_to_net - .get(&net_pin_assignments.name) + .netname_net(&net_pin_assignments.name) .unwrap(); // take the list of pins @@ -70,7 +69,7 @@ impl DsnDesign { .pins .names .iter() - .map(|id| (id.clone(), *net)) + .map(move |pinname| (pinname.clone(), net)) }) // flatten the nested iters into a single stream of tuples .flatten(), @@ -88,8 +87,8 @@ impl DsnDesign { .unwrap(); for pin in &image.pin_vec { - let pin_name = format!("{}-{}", place.name, pin.id); - let net = pin_nets.get(&pin_name).unwrap(); + let pinname = format!("{}-{}", place.name, pin.id); + let net = pin_nets.get(&pinname).unwrap(); let padstack = &self .pcb @@ -117,7 +116,7 @@ impl DsnDesign { circle.diameter as f64 / 2.0, layer as u64, *net, - Some(pin_name.clone()), + Some(pinname.clone()), ) } Shape::Rect(rect) => { @@ -139,7 +138,7 @@ impl DsnDesign { rect.y2 as f64, layer as u64, *net, - Some(pin_name.clone()), + Some(pinname.clone()), ) } Shape::Path(path) => { @@ -159,7 +158,7 @@ impl DsnDesign { path.width as f64, layer as u64, *net, - Some(pin_name.clone()), + Some(pinname.clone()), ) } Shape::Polygon(polygon) => { @@ -179,7 +178,7 @@ impl DsnDesign { polygon.width as f64, layer as u64, *net, - Some(pin_name.clone()), + Some(pinname.clone()), ) } }; @@ -189,12 +188,11 @@ impl DsnDesign { } for via in &self.pcb.wiring.via_vec { - let net = *board + let net = board .layout() .drawing() .rules() - .netname_to_net - .get(&via.net) + .netname_net(&via.net) .unwrap(); // find the padstack referenced by this via placement @@ -294,19 +292,17 @@ impl DsnDesign { } for wire in self.pcb.wiring.wire_vec.iter() { - let layer = *board + let layer = board .layout() .drawing() .rules() - .layername_to_layer - .get(&wire.path.layer) + .layername_layer(&wire.path.layer) .unwrap(); - let net = *board + let net = board .layout() .drawing() .rules() - .netname_to_net - .get(&wire.net) + .netname_net(&wire.net) .unwrap(); Self::add_path( @@ -325,16 +321,22 @@ impl DsnDesign { // The clones here are bad, we'll have something better later on. - let layername_to_layer = &board.layout().drawing().rules().layername_to_layer.clone(); + let layername_to_layer = &board.layout().drawing().rules().layer_layername.clone(); - for (layername, layer) in layername_to_layer.iter() { - board.bename_layer(*layer, layername.to_string()); + for (layer, layername) in layername_to_layer.iter() { + board + .layout_mut() + .rules_mut() + .bename_layer(*layer, layername.to_string()); } - let netname_to_net = &board.layout().drawing().rules().netname_to_net.clone(); + let netname_to_net = &board.layout().drawing().rules().net_netname.clone(); - for (netname, net) in netname_to_net.iter() { - board.bename_net(*net, netname.to_string()); + for (net, netname) in netname_to_net.iter() { + board + .layout_mut() + .rules_mut() + .bename_net(*net, netname.to_string()); } board @@ -343,15 +345,14 @@ impl DsnDesign { fn layer( board: &Board, layer_vec: &Vec, - layer_name: &str, + layername: &str, front: bool, ) -> usize { - let image_layer = *board + let image_layer = board .layout() .drawing() .rules() - .layername_to_layer - .get(layer_name) + .layername_layer(layername) .unwrap(); if front { diff --git a/src/dsn/mesadata.rs b/src/dsn/mesadata.rs index 267d3b7..253b901 100644 --- a/src/dsn/mesadata.rs +++ b/src/dsn/mesadata.rs @@ -1,5 +1,7 @@ use std::collections::HashMap; +use bimap::BiHashMap; + use crate::{ board::mesadata::MesadataTrait, drawing::rules::{Conditions, RulesTrait}, @@ -27,42 +29,44 @@ pub struct DsnMesadata { // net class name -> rule class_rules: HashMap, - // layernames -> layers for Layout - pub layername_to_layer: HashMap, - // netnames -> nets for Layout - pub netname_to_net: HashMap, + // layername <-> layer for Layout + pub layer_layername: BiHashMap, + + // netname <-> net for Layout + pub net_netname: BiHashMap, + // net -> netclass - net_to_netclass: HashMap, + net_netclass: HashMap, } impl DsnMesadata { pub fn from_pcb(pcb: &Pcb) -> Self { - let layer_ids = HashMap::from_iter( + let layer_layername = BiHashMap::from_iter( pcb.structure .layer_vec .iter() - .map(|layer| (layer.name.clone(), layer.property.index as u64)), + .map(|layer| (layer.property.index as u64, layer.name.clone())), ); // keeping this as a separate iter pass because it might be moved into a different struct later? - let netname_to_net = HashMap::from_iter( + let net_netname = BiHashMap::from_iter( pcb.network .class_vec .iter() .flat_map(|class| &class.net_vec) .enumerate() - .map(|(id, net)| (net.clone(), id)), + .map(|(net, netname)| (net, netname.clone())), ); - let mut net_id_classes = HashMap::new(); + let mut net_netclass = HashMap::new(); let class_rules = HashMap::from_iter( pcb.network .class_vec .iter() .inspect(|class| { - for net in &class.net_vec { - let net_id = netname_to_net.get(net).unwrap(); - net_id_classes.insert(*net_id, class.name.clone()); + for netname in &class.net_vec { + let net = net_netname.get_by_right(netname).unwrap(); + net_netclass.insert(*net, class.name.clone()); } }) .map(|class| (class.name.clone(), DsnRule::from_dsn(&class.rule))), @@ -71,14 +75,14 @@ impl DsnMesadata { Self { structure_rule: DsnRule::from_dsn(&pcb.structure.rule), class_rules, - layername_to_layer: layer_ids, - netname_to_net, - net_to_netclass: net_id_classes, + layer_layername, + net_netname, + net_netclass, } } pub fn get_rule(&self, net: usize) -> &DsnRule { - if let Some(netclass) = self.net_to_netclass.get(&net) { + if let Some(netclass) = self.net_netclass.get(&net) { self.class_rules .get(netclass) .unwrap_or(&self.structure_rule) @@ -118,5 +122,27 @@ impl RulesTrait for DsnMesadata { } impl MesadataTrait for DsnMesadata { - // + fn bename_layer(&mut self, layer: u64, layername: String) { + self.layer_layername.insert(layer, layername); + } + + fn layer_layername(&self, layer: u64) -> Option<&str> { + self.layer_layername.get_by_left(&layer).map(|s| s.as_str()) + } + + fn layername_layer(&self, layername: &str) -> Option { + self.layer_layername.get_by_right(layername).copied() + } + + fn bename_net(&mut self, net: usize, netname: String) { + self.net_netname.insert(net, netname); + } + + fn net_netname(&self, net: usize) -> Option<&str> { + self.net_netname.get_by_left(&net).map(|s| s.as_str()) + } + + fn netname_net(&self, netname: &str) -> Option { + self.net_netname.get_by_right(netname).copied() + } } diff --git a/src/layout/layout.rs b/src/layout/layout.rs index 0d02e69..3e6b840 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -211,6 +211,14 @@ impl Layout { &self.drawing } + pub fn rules(&self) -> &R { + self.drawing.rules() + } + + pub fn rules_mut(&mut self) -> &mut R { + self.drawing.rules_mut() + } + pub fn zone(&self, index: GenericIndex) -> Zone { Zone::new(index, self) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 8073405..390ec50 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -78,8 +78,16 @@ pub fn assert_single_layer_groundless_autoroute( .layer(); if let (Some(source_layername), Some(target_layername)) = ( - autorouter.board().layername(source_layer), - autorouter.board().layername(target_layer), + autorouter + .board() + .layout() + .rules() + .layer_layername(source_layer), + autorouter + .board() + .layout() + .rules() + .layer_layername(target_layer), ) { dbg!(source_layername, target_layername); assert_eq!(source_layername, target_layername); @@ -108,7 +116,7 @@ pub fn assert_single_layer_groundless_autoroute( let net = source_net.unwrap(); - if let Some(netname) = autorouter.board().netname(net) { + if let Some(netname) = autorouter.board().layout().rules().net_netname(net) { // We don't route ground. if netname != "GND" { dbg!(source_dot, target_dot);