ASIC place & route framework. This crate contains interface definitions of the core parts of the place & route flow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
5.2 KiB

* Copyright (c) 2020-2021 Thomas Kramer.
* This file is part of LibrEDA
* (see
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <>.
//! 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.
fn insert_buffers(
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(
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.",
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)
assert_eq!(sources.len(), 1, "Cannot handle more than one signal driver.");
let source = sources[0].clone();
self.insert_buffers(chip, source, &sinks)