From ee9f4b5566e1bfb395a814c8c1c0a0a112394b45 Mon Sep 17 00:00:00 2001 From: hakki Date: Fri, 27 Sep 2024 10:29:23 +0000 Subject: [PATCH] Write Specctra module documentation for Topola's library API (#34) Reviewed-on: https://codeberg.org/topola/topola/pulls/34 Co-authored-by: hakki Co-committed-by: hakki --- Cargo.toml | 3 +++ build.rs | 2 +- examples/example.dsn | 0 examples/specctra.rs | 24 ++++++++++++++++++++++ src/lib.rs | 2 ++ src/specctra/design.rs | 44 ++++++++++++++++++++++++++++++++++------ src/specctra/mesadata.rs | 38 ++++++++++++++++++++++++++++++++++ 7 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 examples/example.dsn create mode 100644 examples/specctra.rs diff --git a/Cargo.toml b/Cargo.toml index 52f59d6..9a1ba77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -126,3 +126,6 @@ contracts = { path = "vendored/contracts" } [build-dependencies] clap_mangen = "0.2.23" clap = {version="4.5.8", features = ["derive"] } + +[package.metadata.docs.rs] +cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"] diff --git a/build.rs b/build.rs index 254a664..e505139 100644 --- a/build.rs +++ b/build.rs @@ -2,7 +2,7 @@ include!("src/bin/topola/cli.rs"); use clap::CommandFactory; use clap_mangen::Man; use std::fs::{create_dir_all, File}; -// https://rust-cli.github.io/book/in-depth/docs.html + fn main() -> Result<(), Box> { let cmd = Cli::command(); let man = Man::new(cmd); diff --git a/examples/example.dsn b/examples/example.dsn new file mode 100644 index 0000000..e69de29 diff --git a/examples/specctra.rs b/examples/specctra.rs new file mode 100644 index 0000000..882526b --- /dev/null +++ b/examples/specctra.rs @@ -0,0 +1,24 @@ +use std::fs::File; +use std::io::BufReader; +use topola::autorouter::history::History; +use topola::autorouter::invoker::Command; +use topola::autorouter::invoker::Invoker; +use topola::autorouter::selection::PinSelection; +use topola::autorouter::Autorouter; +use topola::specctra::design::SpecctraDesign; + +fn main() -> Result<(), std::io::Error> { + let design_file = File::open("example.dsn")?; + let mut design_bufread = BufReader::new(design_file); + + let design = SpecctraDesign::load(design_bufread).unwrap(); + let board = design.make_board(); + + let mut invoker = Invoker::new(Autorouter::new(board).unwrap()); + + let mut file = File::create("example.ses").unwrap(); + design.write_ses(invoker.autorouter().board(), &mut file); + + let filename = design.get_name(); + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 2e0434e..90d0b78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![doc(html_favicon_url = "https://codeberg.org/topola/topola/raw/commit/e1b56875edf039aab9f41868826bcd3a92097133/assets/favicon.ico")] +#![doc(html_logo_url = "https://codeberg.org/topola/topola/raw/commit/e1b56875edf039aab9f41868826bcd3a92097133/assets/logo.svg")] #![cfg_attr(not(feature = "disable_contracts"), feature(try_blocks))] pub mod graph; diff --git a/src/specctra/design.rs b/src/specctra/design.rs index c7fe02b..e7fbec8 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -24,19 +24,35 @@ use crate::{ }; #[derive(Error, Debug)] + +/// Errors raised by [`SpecctraDesign::load`] pub enum LoadingError { + /// I/O file reading error from [`std::io::Error`] #[error(transparent)] Io(#[from] std::io::Error), + /// File parsing errors containing information about unexpected end of file, + /// or any other parsing issues with provided DSN file #[error(transparent)] Parse(#[from] read::ParseError), } + +/// This struct is responsible for managing the various Specctra components of a PCB design, +/// including parsing the DSN file, handling the resolution, unit of measurement, +/// and organizing the PCB's structure, placement, library, network, and wiring. +/// It provides functionality for reading from a DSN file and writing Specctra's .SES session files. #[derive(Debug)] pub struct SpecctraDesign { pcb: Pcb, } impl SpecctraDesign { + /// Loads a [`SpecctraDesign`] structure instance from a buffered reader. + /// + /// This function reads the Specctra Design data from an input stream. + /// Later the data is parsed and loaded into a [`SpecctraDesign`] structure, + /// allowing further operations such as rule validation, routing, or netlist management. + /// pub fn load(reader: impl std::io::BufRead) -> Result { let mut list_reader = ListTokenizer::new(reader); let dsn = list_reader.read_value::()?; @@ -44,14 +60,23 @@ impl SpecctraDesign { Ok(Self { pcb: dsn.pcb }) } + /// Function to get name of the DSN file + /// + /// This function returns the name of the `Pcb` objects pub fn get_name(&self) -> &str { &self.pcb.name } - - pub fn write_ses( + + /// Writes the Specctra Session (.ses) file format using the current board layout and mesadata. + /// + /// This function generates a Specctra SES session file that represents the board's net routing and + /// writes it to the provided output stream. The session data includes routed nets, wires, + /// layers, and other essential information for routing management. + /// + pub fn write_ses( &self, board: &Board, - writer: impl std::io::Write, + writer: impl std::io::Write, ) -> Result<(), std::io::Error> { let mesadata = board.mesadata(); let drawing = board.layout().drawing(); @@ -124,8 +149,8 @@ impl SpecctraDesign { structure::NetOut { name: mesadata.net_netname(net).unwrap().to_owned(), wire: vec![wire], - via: Vec::new(), - }, + via: Vec::new() + }, ); } } @@ -152,7 +177,14 @@ impl SpecctraDesign { ListWriter::new(writer).write_value(&ses) } - + + /// Generates a [`Board`] from the current PCB data. + /// + /// This function takes the internal `Pcb` structure and transforms it into a [`Board`] object, + /// which is used for layout and routing operations. The board is initialized with [`SpecctraMesadata`], + /// which includes layer and net mappings, and is populated with components, pins, vias, and wires + /// from the PCB definition. + /// pub fn make_board(&self) -> Board { let mesadata = SpecctraMesadata::from_pcb(&self.pcb); let mut board = Board::new(Layout::new(Drawing::new( diff --git a/src/specctra/mesadata.rs b/src/specctra/mesadata.rs index c53c35e..9c422ca 100644 --- a/src/specctra/mesadata.rs +++ b/src/specctra/mesadata.rs @@ -9,8 +9,18 @@ use crate::{ }; #[derive(Debug)] +/// [`SpecctraRule`] represents the basic routing constraints used by an auto-router, such as +/// the Specctra auto-router, in a PCB design process. This struct defines two key design +/// rules: the width of the trace and the minimum clearance between electrical features. pub struct SpecctraRule { + /// Specifies the width of the trace (or conductor) in millimeters. + /// This value ensures that the traces meet electrical + /// and mechanical requirements, such as current-carrying capacity or signal integrity. pub width: f64, + /// Defines the minimum clearance (spacing) between traces, pads, + /// or other conductive features on the PCB. Adequate clearance is important for + /// preventing electrical shorts or interference between signals, and is often + /// dictated by manufacturing constraints or voltage considerations. pub clearance: f64, } @@ -24,22 +34,43 @@ impl SpecctraRule { } #[derive(Debug)] +/// [`SpecctraMesadata`] holds the metadata required by the Specctra auto-router to +/// understand and enforce design rules across various net classes and layers in a PCB layout. +/// This struct encapsulates information about rules for individual nets, net classes, +/// layers, and their corresponding relationships. pub struct SpecctraMesadata { + + /// The default routing rule applied globally if no specific net class rule is defined. structure_rule: SpecctraRule, + // net class name -> rule + /// A map from net class names to their specific `SpecctraRule` constraints. + /// These rules are applied to all nets belonging to the respective net clas class_rules: HashMap, // layername <-> layer for Layout + /// A bidirectional map between layer indices and layer names, allowing translation + /// between index-based layers in the layout and user-defined layer names. pub layer_layername: BiHashMap, // netname <-> net for Layout + /// A bidirectional map between network indices and network names in the PCB layout, + /// providing an easy way to reference nets by name or index. pub net_netname: BiHashMap, // net -> netclass + /// A map that associates network indices with their respective net class names. + /// This is used to apply net class-specific routing rules to each net. net_netclass: HashMap, } + impl SpecctraMesadata { + /// Creates a [`SpecctraMesadata`] instance from a given `Pcb` reference. + /// + /// This function extracts the necessary metadata from the `Pcb` struct, such as + /// layer-to-layer name mappings, net-to-net name mappings, and net class rules. + /// pub fn from_pcb(pcb: &Pcb) -> Self { let layer_layername = BiHashMap::from_iter( pcb.structure @@ -81,6 +112,13 @@ impl SpecctraMesadata { } } + /// Retrieves the Specctra routing rule associated with a specified net ID. + /// + /// This function looks up the routing rule for a given net ID. It first checks if the net is + /// associated with a net class. If a net class is found, it retrieves the corresponding rule + /// from the class rules. If no class is associated, or if the class does not have a defined rule, + /// it defaults to the general structure rule. + /// pub fn get_rule(&self, net: usize) -> &SpecctraRule { if let Some(netclass) = self.net_netclass.get(&net) { self.class_rules