Write Specctra module documentation for Topola's library API (#34)

Reviewed-on: https://codeberg.org/topola/topola/pulls/34
Co-authored-by: hakki <hakki@noreply.codeberg.org>
Co-committed-by: hakki <hakki@noreply.codeberg.org>
This commit is contained in:
hakki 2024-09-27 10:29:23 +00:00 committed by mikolaj
parent d43983a84d
commit ee9f4b5566
7 changed files with 106 additions and 7 deletions

View File

@ -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"]

View File

@ -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<dyn std::error::Error>> {
let cmd = Cli::command();
let man = Man::new(cmd);

0
examples/example.dsn Normal file
View File

24
examples/specctra.rs Normal file
View File

@ -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(())
}

View File

@ -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;

View File

@ -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<SpecctraDesign, LoadingError> {
let mut list_reader = ListTokenizer::new(reader);
let dsn = list_reader.read_value::<DsnFile>()?;
@ -44,10 +60,19 @@ 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
}
/// 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<SpecctraMesadata>,
@ -124,7 +149,7 @@ impl SpecctraDesign {
structure::NetOut {
name: mesadata.net_netname(net).unwrap().to_owned(),
wire: vec![wire],
via: Vec::new(),
via: Vec::new()
},
);
}
@ -153,6 +178,13 @@ impl SpecctraDesign {
ListWriter::new(writer).write_value(&ses)
}
/// Generates a [`Board<SpecctraMesadata>`] 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<SpecctraMesadata> {
let mesadata = SpecctraMesadata::from_pcb(&self.pcb);
let mut board = Board::new(Layout::new(Drawing::new(

View File

@ -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<String, SpecctraRule>,
// 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<usize, String>,
// 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<usize, String>,
// 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<usize, String>,
}
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