1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
// Copyright (c) 2020-2022 Thomas Kramer.
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Remove buffer cells or buffer trees from a netlist while preserving the logic function.
use crate::db::*;
use std::collections::{HashMap, HashSet};
/// Buffer removal engine. Removes non-inverting buffers and inverting buffers.
/// Buffer cells are identified by name. The names must be specified manually using `add_non_inverting_buffer()` and `add_inverting_buffer()`.
pub struct BufferRemover {
non_inverting_buffer_cells: HashSet<String>,
inverting_buffer_cells: HashSet<String>,
}
impl BufferRemover {
/// Register the name of a non-inverting buffer cell.
pub fn register_non_inverting_buffer(&mut self, name: String) {
self.non_inverting_buffer_cells.insert(name);
}
/// Register the name of a inverting buffer cell.
pub fn register_inverting_buffer(&mut self, name: String) {
self.inverting_buffer_cells.insert(name);
}
/// Find buffer cells by their name.
/// Take only cells which have exactly one input and one output.
/// Return a hashmap with cell IDs as keys and (input pin, output pin) pairs as values.
fn get_valid_buffer_cells_by_names<N>(
&self,
netlist: &N,
names: &HashSet<String>,
) -> HashMap<N::CellId, (N::PinId, N::PinId)>
where
N: NetlistBase,
{
names
.iter()
.filter_map(|name| netlist.cell_by_name(name.as_str()))
// Test if has unique input/output pair.
.filter_map(|cell| {
let cell = netlist.cell_ref(&cell);
let inputs: Vec<_> = cell.each_input_pin().collect();
let outputs: Vec<_> = cell.each_input_pin().collect();
if inputs.len() == 1 && outputs.len() == 1 {
let i = inputs.into_iter().next().unwrap().id();
let o = outputs.into_iter().next().unwrap().id();
Some((cell.id(), (i, o)))
} else {
// Can't work with this cell.
None
}
})
.collect()
}
/// Remove all the non-inverting buffers from the `top` circuit.
/// They are found by the name which is specified using `.add_non_inverting_buffer()`.
/// Return the number of removed buffer instances.
pub fn remove_non_inverting_buffers<N>(&self, netlist: &mut N, top: &N::CellId) -> usize
where
N: NetlistEdit,
{
// Find the buffer cells to be removed.
let buffer_cells =
self.get_valid_buffer_cells_by_names(netlist, &self.non_inverting_buffer_cells);
let mut num_removed_instances = 0;
for (buffer_cell, (input_pin, output_pin)) in buffer_cells {
// Find all instances of this buffer cell in `top`.
let buffer_instances: Vec<_> = netlist
.cell_ref(top)
.each_cell_instance()
.filter(|inst| inst.template_id() == buffer_cell)
.map(|inst| inst.id())
.collect();
for inst in buffer_instances {
self.remove_non_inverting_buffer(netlist, &inst, &input_pin, &output_pin);
num_removed_instances += 1;
}
}
num_removed_instances
}
/// Remove a non-inverting buffer cell and merge the nets at the input and output.
fn remove_non_inverting_buffer<N>(
&self,
netlist: &mut N,
buffer_instance: &N::CellInstId,
input_pin: &N::PinId,
output_pin: &N::PinId,
) where
N: NetlistEdit,
{
let input_net =
netlist.net_of_pin_instance(&netlist.pin_instance(buffer_instance, input_pin));
let output_net =
netlist.net_of_pin_instance(&netlist.pin_instance(buffer_instance, output_pin));
netlist.remove_cell_instance(buffer_instance);
if let (Some(i), Some(o)) = (input_net, output_net) {
netlist.replace_net(&o, &i);
}
}
}