libreda-pnr 0.0.4

Algorithm interface definitions of the LibrEDA place-and-route framework.
Documentation
// Copyright (c) 2020-2021 Thomas Kramer.
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! Trait definition for buffer insertion algorithms.

use crate::db::{TerminalId, Direction};

use crate::db::traits::*;
use num_traits::PrimInt;

/// Create a simple buffer tree between a specified source pin and
/// a set of sink pins.
/// The insertion strategy is up to the trait implementation.
pub trait SimpleBufferInsertion<LN: LayoutEdit + NetlistEdit>
    where LN::Coord: PrimInt {

    /// Error type that is returned on failure.
    type Error;

    /// Create a buffer tree between the source terminal
    /// and the sinks. The terminals are given together with their location to enable creation of
    /// a placement-aware buffer tree.
    ///
    /// On success: Return a list of created cell instances and a list of created nets.
    ///
    /// # Note
    /// All further information (which buffer to use, how many buffers to place, where to place them, etc.)
    /// is to be defined by the implementation of this trait.
    fn insert_buffers(
        &self,
        chip: &mut LN,
        signal_source: TerminalId<LN>,
        signal_sinks: &Vec<TerminalId<LN>>,
    ) -> Result<(Vec<LN::CellInstId>, Vec<LN::NetId>), Self::Error>;

    /// Replace the net by a buffer tree.
    /// 1) Identify signal driver and sinks by the direction of the pins.
    /// 2) Call `insert_buffers()`.
    ///
    /// On success: Return a list of created cell instances and a list of created nets.
    fn add_buffer_tree_on_net(
        &self,
        chip: &mut LN,
        net: &LN::NetId,
    ) -> Result<(Vec<LN::CellInstId>, Vec<LN::NetId>), Self::Error> {

        // Check if the net is a special net (LOW or HIGH).
        if chip.is_constant_net(net) {
            let parent_name = chip.cell_name(&chip.parent_cell_of_net(net));
            log::warn!("Net '{:?}' in '{}' probably requires a tie cell instead of a buffer.", net, parent_name);
        }

        // Find the sinks of the net and the source that drives the net.
        let mut sources = vec![]; // There should be only one source.
        let mut sinks = vec![];

        for t in chip.each_terminal_of_net(net) {
            // A pin of the parent cell is considered to be a source when it's direction is 'INPUT',
            // however a pin instance that connects to a child instance is considered a sink when it's direction is 'INPUT'.
            match &t {
                TerminalId::PinId(p) => {
                    match chip.pin_direction(p) {
                        Direction::Input => sources.push(t),
                        Direction::Output => sinks.push(t),
                        d => {
                            let cell_name = chip.cell_name(&chip.parent_cell_of_pin(&p));
                            let pin_name = chip.pin_name(p);
                            panic!("Cannot handle pin direction of pin '{}' in cell '{}': {:?} (must be input or output)", pin_name, cell_name, d)
                        }
                    }
                }
                TerminalId::PinInstId(p) => {
                    match chip.pin_direction(&chip.template_pin(p)) {
                        Direction::Input => sinks.push(t),
                        Direction::Output => sources.push(t),
                        d => {
                            let pin = chip.template_pin(p);
                            let cell_name = chip.cell_name(&chip.parent_cell_of_pin(&pin));
                            let pin_name = chip.pin_name(&pin);
                            panic!("Cannot handle pin direction of pin '{}' in cell '{}': {:?} (must be input or output)", pin_name, cell_name, d)
                        }
                    }
                }
            }
        }

        log::debug!("Number of drivers: {}", sources.len());
        log::debug!("Number of sinks: {}", sinks.len());

        if sources.len() != 1 {
            log::error!("Net must be driven by exactly one output pin but net {:?} is driven by {} output pins.",
                        chip.net_name(net),
                        sources.len()
            );
            // Print drivers of the net for easier debugging.
            for driver in &sources {
                let pin = match driver {
                    TerminalId::PinId(p) => p.clone(),
                    TerminalId::PinInstId(p) => chip.template_pin(p)
                };
                let pin_name = chip.pin_name(&pin);
                let cell = chip.parent_cell_of_pin(&pin);
                let cell_name = chip.cell_name(&cell);
                log::error!("Pin '{}' of cell '{}' drives the net.", pin_name, cell_name)
            }
        }

        if !sources.is_empty() {
            assert_eq!(sources.len(), 1, "Cannot handle more than one signal driver.");
            let source = sources[0].clone();

            self.insert_buffers(chip, source, &sinks)
        } else {
            log::warn!("Skip buffer tree on net '{:?}': No driver found.", chip.net_name(net));
            Ok((vec![], vec![]))
        }
    }
}