board,dsn: move layer and net name bidirectional lookup to `Mesadata`

This commit is contained in:
Mikolaj Wielgus 2024-06-08 21:37:19 +02:00
parent 98363fbfd1
commit 7a02877eb4
10 changed files with 115 additions and 82 deletions

View File

@ -31,6 +31,7 @@ serde_json = "1.0.117"
enum_dispatch = "0.3.12" enum_dispatch = "0.3.12"
itertools = "0.8.2" itertools = "0.8.2"
contracts = "0.6.3" contracts = "0.6.3"
bimap = "0.6.3"
log = "0.4" log = "0.4"
[dependencies.serde] [dependencies.serde]

View File

@ -67,8 +67,10 @@ impl Selection {
NodeIndex::Compound(compound) => board.layout().zone(compound).layer(), 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 { Some(Selector {
pin: pinname.to_string(), pin: pinname.to_string(),
layer: layername.to_string(), layer: layername.to_string(),

View File

@ -6,11 +6,10 @@ use spade::InsertionError;
use topola::{ use topola::{
autorouter::{ratsnest::Ratsnest, selection::Selection}, autorouter::{ratsnest::Ratsnest, selection::Selection},
board::Board, board::{mesadata::MesadataTrait, Board},
drawing::{ drawing::{
graph::{GetLayer, MakePrimitive}, graph::{GetLayer, MakePrimitive},
primitive::MakePrimitiveShape, primitive::MakePrimitiveShape,
rules::RulesTrait,
}, },
geometry::{ geometry::{
compound::CompoundManagerTrait, compound::CompoundManagerTrait,
@ -26,7 +25,7 @@ pub struct Overlay {
} }
impl Overlay { impl Overlay {
pub fn new(board: &Board<impl RulesTrait>) -> Result<Self, InsertionError> { pub fn new(board: &Board<impl MesadataTrait>) -> Result<Self, InsertionError> {
Ok(Self { Ok(Self {
ratsnest: Ratsnest::new(board.layout())?, ratsnest: Ratsnest::new(board.layout())?,
selection: Selection::new(), selection: Selection::new(),
@ -34,7 +33,7 @@ impl Overlay {
}) })
} }
pub fn click(&mut self, board: &Board<impl RulesTrait>, at: Point) { pub fn click(&mut self, board: &Board<impl MesadataTrait>, at: Point) {
let geoms: Vec<_> = board let geoms: Vec<_> = board
.layout() .layout()
.drawing() .drawing()
@ -65,7 +64,7 @@ impl Overlay {
fn toggle_selection_if_contains_point( fn toggle_selection_if_contains_point(
&mut self, &mut self,
board: &Board<impl RulesTrait>, board: &Board<impl MesadataTrait>,
node: NodeIndex, node: NodeIndex,
p: Point, p: Point,
) -> bool { ) -> bool {

View File

@ -24,8 +24,6 @@ use crate::{
pub struct Board<M: MesadataTrait> { pub struct Board<M: MesadataTrait> {
layout: Layout<M>, layout: Layout<M>,
node_to_pinname: HashMap<NodeIndex, String>, node_to_pinname: HashMap<NodeIndex, String>,
layer_to_layername: HashMap<u64, String>,
net_to_netname: HashMap<usize, String>,
pinname_pair_to_band: HashMap<(String, String), BandIndex>, pinname_pair_to_band: HashMap<(String, String), BandIndex>,
} }
@ -34,8 +32,6 @@ impl<M: MesadataTrait> Board<M> {
Self { Self {
layout, layout,
node_to_pinname: HashMap::new(), node_to_pinname: HashMap::new(),
layer_to_layername: HashMap::new(),
net_to_netname: HashMap::new(),
pinname_pair_to_band: HashMap::new(), pinname_pair_to_band: HashMap::new(),
} }
} }
@ -145,14 +141,6 @@ impl<M: MesadataTrait> Board<M> {
result 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<ZoneWeight>) -> FixedDotIndex { pub fn zone_apex(&mut self, zone: GenericIndex<ZoneWeight>) -> FixedDotIndex {
if let Some(apex) = self.layout.zone(zone).maybe_apex() { if let Some(apex) = self.layout.zone(zone).maybe_apex() {
apex apex
@ -176,14 +164,6 @@ impl<M: MesadataTrait> Board<M> {
self.node_to_pinname.get(&node) 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<BandIndex> { pub fn band_between_pins(&self, pinname1: &str, pinname2: &str) -> Option<BandIndex> {
if let Some(band) = self if let Some(band) = self
.pinname_pair_to_band .pinname_pair_to_band

View File

@ -2,9 +2,11 @@ use crate::{drawing::rules::RulesTrait, layout::NodeIndex};
// TODO: use this trait. // TODO: use this trait.
pub trait MesadataTrait: RulesTrait { pub trait MesadataTrait: RulesTrait {
/*fn node_pinname(&self, node: NodeIndex); fn bename_layer(&mut self, layer: u64, layername: String);
fn layer_layername(&self, layer: u64) -> &str; fn layer_layername(&self, layer: u64) -> Option<&str>;
fn layername_layer(&self, layername: &str) -> u64; fn layername_layer(&self, layername: &str) -> Option<u64>;
fn net_netname(&self, net: usize) -> &str;
fn netname_net(&self, netname: &str) -> usize;*/ fn bename_net(&mut self, net: usize, netname: String);
fn net_netname(&self, net: usize) -> Option<&str>;
fn netname_net(&self, netname: &str) -> Option<usize>;
} }

View File

@ -836,6 +836,12 @@ impl<CW: Copy, R: RulesTrait> Drawing<CW, R> {
&self.rules &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<CW, R> { pub fn guide(&self) -> Guide<CW, R> {
Guide::new(self) Guide::new(self)
} }

View File

@ -4,7 +4,7 @@ use geo::{point, Point, Rotate, Translate};
use thiserror::Error; use thiserror::Error;
use crate::{ use crate::{
board::Board, board::{mesadata::MesadataTrait, Board},
drawing::{dot::FixedDotWeight, seg::FixedSegWeight, Drawing}, drawing::{dot::FixedDotWeight, seg::FixedSegWeight, Drawing},
dsn::{ dsn::{
de, de,
@ -60,8 +60,7 @@ impl DsnDesign {
.layout() .layout()
.drawing() .drawing()
.rules() .rules()
.netname_to_net .netname_net(&net_pin_assignments.name)
.get(&net_pin_assignments.name)
.unwrap(); .unwrap();
// take the list of pins // take the list of pins
@ -70,7 +69,7 @@ impl DsnDesign {
.pins .pins
.names .names
.iter() .iter()
.map(|id| (id.clone(), *net)) .map(move |pinname| (pinname.clone(), net))
}) })
// flatten the nested iters into a single stream of tuples // flatten the nested iters into a single stream of tuples
.flatten(), .flatten(),
@ -88,8 +87,8 @@ impl DsnDesign {
.unwrap(); .unwrap();
for pin in &image.pin_vec { for pin in &image.pin_vec {
let pin_name = format!("{}-{}", place.name, pin.id); let pinname = format!("{}-{}", place.name, pin.id);
let net = pin_nets.get(&pin_name).unwrap(); let net = pin_nets.get(&pinname).unwrap();
let padstack = &self let padstack = &self
.pcb .pcb
@ -117,7 +116,7 @@ impl DsnDesign {
circle.diameter as f64 / 2.0, circle.diameter as f64 / 2.0,
layer as u64, layer as u64,
*net, *net,
Some(pin_name.clone()), Some(pinname.clone()),
) )
} }
Shape::Rect(rect) => { Shape::Rect(rect) => {
@ -139,7 +138,7 @@ impl DsnDesign {
rect.y2 as f64, rect.y2 as f64,
layer as u64, layer as u64,
*net, *net,
Some(pin_name.clone()), Some(pinname.clone()),
) )
} }
Shape::Path(path) => { Shape::Path(path) => {
@ -159,7 +158,7 @@ impl DsnDesign {
path.width as f64, path.width as f64,
layer as u64, layer as u64,
*net, *net,
Some(pin_name.clone()), Some(pinname.clone()),
) )
} }
Shape::Polygon(polygon) => { Shape::Polygon(polygon) => {
@ -179,7 +178,7 @@ impl DsnDesign {
polygon.width as f64, polygon.width as f64,
layer as u64, layer as u64,
*net, *net,
Some(pin_name.clone()), Some(pinname.clone()),
) )
} }
}; };
@ -189,12 +188,11 @@ impl DsnDesign {
} }
for via in &self.pcb.wiring.via_vec { for via in &self.pcb.wiring.via_vec {
let net = *board let net = board
.layout() .layout()
.drawing() .drawing()
.rules() .rules()
.netname_to_net .netname_net(&via.net)
.get(&via.net)
.unwrap(); .unwrap();
// find the padstack referenced by this via placement // find the padstack referenced by this via placement
@ -294,19 +292,17 @@ impl DsnDesign {
} }
for wire in self.pcb.wiring.wire_vec.iter() { for wire in self.pcb.wiring.wire_vec.iter() {
let layer = *board let layer = board
.layout() .layout()
.drawing() .drawing()
.rules() .rules()
.layername_to_layer .layername_layer(&wire.path.layer)
.get(&wire.path.layer)
.unwrap(); .unwrap();
let net = *board let net = board
.layout() .layout()
.drawing() .drawing()
.rules() .rules()
.netname_to_net .netname_net(&wire.net)
.get(&wire.net)
.unwrap(); .unwrap();
Self::add_path( Self::add_path(
@ -325,16 +321,22 @@ impl DsnDesign {
// The clones here are bad, we'll have something better later on. // 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() { for (layer, layername) in layername_to_layer.iter() {
board.bename_layer(*layer, layername.to_string()); 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() { for (net, netname) in netname_to_net.iter() {
board.bename_net(*net, netname.to_string()); board
.layout_mut()
.rules_mut()
.bename_net(*net, netname.to_string());
} }
board board
@ -343,15 +345,14 @@ impl DsnDesign {
fn layer( fn layer(
board: &Board<DsnMesadata>, board: &Board<DsnMesadata>,
layer_vec: &Vec<Layer>, layer_vec: &Vec<Layer>,
layer_name: &str, layername: &str,
front: bool, front: bool,
) -> usize { ) -> usize {
let image_layer = *board let image_layer = board
.layout() .layout()
.drawing() .drawing()
.rules() .rules()
.layername_to_layer .layername_layer(layername)
.get(layer_name)
.unwrap(); .unwrap();
if front { if front {

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use bimap::BiHashMap;
use crate::{ use crate::{
board::mesadata::MesadataTrait, board::mesadata::MesadataTrait,
drawing::rules::{Conditions, RulesTrait}, drawing::rules::{Conditions, RulesTrait},
@ -27,42 +29,44 @@ pub struct DsnMesadata {
// net class name -> rule // net class name -> rule
class_rules: HashMap<String, DsnRule>, class_rules: HashMap<String, DsnRule>,
// layernames -> layers for Layout // layername <-> layer for Layout
pub layername_to_layer: HashMap<String, u64>, pub layer_layername: BiHashMap<u64, String>,
// netnames -> nets for Layout
pub netname_to_net: HashMap<String, usize>, // netname <-> net for Layout
pub net_netname: BiHashMap<usize, String>,
// net -> netclass // net -> netclass
net_to_netclass: HashMap<usize, String>, net_netclass: HashMap<usize, String>,
} }
impl DsnMesadata { impl DsnMesadata {
pub fn from_pcb(pcb: &Pcb) -> Self { pub fn from_pcb(pcb: &Pcb) -> Self {
let layer_ids = HashMap::from_iter( let layer_layername = BiHashMap::from_iter(
pcb.structure pcb.structure
.layer_vec .layer_vec
.iter() .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? // 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 pcb.network
.class_vec .class_vec
.iter() .iter()
.flat_map(|class| &class.net_vec) .flat_map(|class| &class.net_vec)
.enumerate() .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( let class_rules = HashMap::from_iter(
pcb.network pcb.network
.class_vec .class_vec
.iter() .iter()
.inspect(|class| { .inspect(|class| {
for net in &class.net_vec { for netname in &class.net_vec {
let net_id = netname_to_net.get(net).unwrap(); let net = net_netname.get_by_right(netname).unwrap();
net_id_classes.insert(*net_id, class.name.clone()); net_netclass.insert(*net, class.name.clone());
} }
}) })
.map(|class| (class.name.clone(), DsnRule::from_dsn(&class.rule))), .map(|class| (class.name.clone(), DsnRule::from_dsn(&class.rule))),
@ -71,14 +75,14 @@ impl DsnMesadata {
Self { Self {
structure_rule: DsnRule::from_dsn(&pcb.structure.rule), structure_rule: DsnRule::from_dsn(&pcb.structure.rule),
class_rules, class_rules,
layername_to_layer: layer_ids, layer_layername,
netname_to_net, net_netname,
net_to_netclass: net_id_classes, net_netclass,
} }
} }
pub fn get_rule(&self, net: usize) -> &DsnRule { 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 self.class_rules
.get(netclass) .get(netclass)
.unwrap_or(&self.structure_rule) .unwrap_or(&self.structure_rule)
@ -118,5 +122,27 @@ impl RulesTrait for DsnMesadata {
} }
impl MesadataTrait 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<u64> {
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<usize> {
self.net_netname.get_by_right(netname).copied()
}
} }

View File

@ -211,6 +211,14 @@ impl<R: RulesTrait> Layout<R> {
&self.drawing &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<ZoneWeight>) -> Zone<R> { pub fn zone(&self, index: GenericIndex<ZoneWeight>) -> Zone<R> {
Zone::new(index, self) Zone::new(index, self)
} }

View File

@ -78,8 +78,16 @@ pub fn assert_single_layer_groundless_autoroute(
.layer(); .layer();
if let (Some(source_layername), Some(target_layername)) = ( if let (Some(source_layername), Some(target_layername)) = (
autorouter.board().layername(source_layer), autorouter
autorouter.board().layername(target_layer), .board()
.layout()
.rules()
.layer_layername(source_layer),
autorouter
.board()
.layout()
.rules()
.layer_layername(target_layer),
) { ) {
dbg!(source_layername, target_layername); dbg!(source_layername, target_layername);
assert_eq!(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(); 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. // We don't route ground.
if netname != "GND" { if netname != "GND" {
dbg!(source_dot, target_dot); dbg!(source_dot, target_dot);