Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/bin/eqmap_asic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,11 @@ fn main() -> std::io::Result<()> {
PartitionMethod::ArcSet => {
mapper.insert_partitioned().map_err(std::io::Error::other)?;
}
PartitionMethod::DelayPaths => todo!("Implement delay-based partitioning"),
PartitionMethod::DelayPaths => {
mapper
.insert_delay_paths(1, 2)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a later PR, we could make these arguments to insert_delay_paths() top-level command line flags. Leave as is for now.

.map_err(std::io::Error::other)?;
}
}

let mut mapping = mapper.mappings();
Expand Down
6 changes: 5 additions & 1 deletion src/bin/eqmap_fpga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,11 @@ fn main() -> std::io::Result<()> {
PartitionMethod::ArcSet => {
mapper.insert_partitioned().map_err(std::io::Error::other)?;
}
PartitionMethod::DelayPaths => todo!("Implement delay-based partitioning"),
PartitionMethod::DelayPaths => {
mapper
.insert_delay_paths(1, 2)
.map_err(std::io::Error::other)?;
}
}

let mut mapping = mapper.mappings();
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub mod pass;
pub mod rewrite;
#[cfg(feature = "graph_dumps")]
pub mod serialize;
pub mod timing;
pub mod verilog;

#[cfg(test)]
Expand Down
33 changes: 30 additions & 3 deletions src/netlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
use crate::asic::CellLang;
use crate::driver::CircuitLang;
use crate::lut::LutLang;
use crate::timing::get_critical_paths;
use bitvec::field::BitField;
use egg::{Id, RecExpr, Symbol};
use nl_compiler::FromId;
use safety_net::graph::MultiDiGraph;
use safety_net::graph::{CombDepthInfo, MultiDiGraph};
use safety_net::{
Analysis, DrivenNet, Error, Identifier, Instantiable, Logic, Net, Netlist, Parameter,
format_id, iter::NetDFSIterator,
Expand Down Expand Up @@ -129,8 +130,7 @@ where
})
}
}

impl<'a, L: CircuitLang, I: Instantiable + LogicFunc<L>> LogicMapper<'a, L, I> {
impl<'a, L: CircuitLang, I: Instantiable + LogicFunc<L> + 'static> LogicMapper<'a, L, I> {
/// Map `nets` to [CircuitLang] nodes. `nets` that do not pass `filter_netref` *and* `filter_inst` become leaves.
fn insert_filtered<F, G>(
&mut self,
Expand Down Expand Up @@ -345,6 +345,33 @@ impl<'a, L: CircuitLang, I: Instantiable + LogicFunc<L>> LogicMapper<'a, L, I> {
pub fn mappings(self) -> Vec<LogicMapping<L, I>> {
self.mappings
}

/// Maps a critical delay path plus a bounded amount of surrounding fan-in logic.
pub fn insert_delay_paths(
&mut self,
topk: usize,
branch_factor: usize,
) -> Result<RecExpr<L>, String> {
let analysis = self
._netlist
.get_analysis::<CombDepthInfo<_>>()
.map_err(|e| e.to_string())?;

let mut expanded_nodes = HashSet::new();
let mut roots = Vec::new();

for critical_path in get_critical_paths(&analysis).take(topk) {
let endpoint = critical_path.endpoint();
expanded_nodes.extend(critical_path.expand_n_nodes(branch_factor));
Comment thread
danielpenas42 marked this conversation as resolved.
roots.push(endpoint);
}

if roots.is_empty() {
return Err("No critical endpoints found".to_string());
}

self.insert_filtered(roots, move |d| expanded_nodes.contains(d), |_| true)
}
}

/// Create an instantiable cell out of the [CellType]
Expand Down
98 changes: 98 additions & 0 deletions src/timing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*!

Timing analysis helpers for timing-aware optimization flows.

*/

use safety_net::DrivenNet;
use safety_net::Instantiable;
use safety_net::graph::CombDepthInfo;
use std::collections::HashSet;

#[derive(Debug)]
/// A representative critical path ending at a timing endpoint.
pub struct DelayPath<I: Instantiable> {
/// The path from endpoint backward through critical fan-in.
path: Vec<DrivenNet<I>>,
}

impl<I: Instantiable> DelayPath<I> {
/// Returns the depth/length of the delay path.
pub fn depth(&self) -> usize {
self.path.len()
}

/// The signal being driven by this path
pub fn endpoint(&self) -> DrivenNet<I> {
self.path[0].clone()
}

/// The nodes along the delay path as a slice
pub fn path(&self) -> &[DrivenNet<I>] {
&self.path
}
/// Expands and collects the transitive fan-in along the critical path provided by a branch factor of n.
pub fn expand_n_nodes(&self, n: usize) -> HashSet<DrivenNet<I>> {
let mut frontier: Vec<DrivenNet<I>> = self.path().to_vec();
let mut expanded_nodes: HashSet<DrivenNet<I>> = frontier.iter().cloned().collect();

for _ in 0..n {
let mut next_frontier = Vec::new();

for net in frontier {
let node = net.unwrap();

for input in node.inputs() {
if let Some(driver) = input.get_driver()
&& expanded_nodes.insert(driver.clone())
{
next_frontier.push(driver);
}
}
}

frontier = next_frontier;
}

expanded_nodes
}
}

impl<I: Instantiable> IntoIterator for DelayPath<I> {
type Item = DrivenNet<I>;
type IntoIter = std::vec::IntoIter<DrivenNet<I>>;

fn into_iter(self) -> Self::IntoIter {
self.path.into_iter()
}
}

fn build_path_from_endpoint<I: Instantiable>(
analysis: &CombDepthInfo<'_, I>,
endpoint: DrivenNet<I>,
) -> Option<DelayPath<I>> {
let mut path = Vec::new();
let mut current = endpoint;

while let Some(crit) = analysis.get_crit_input(&current.clone().unwrap()) {
path.push(current.clone());
if let Some(c) = crit.get_driver() {
current = c;
} else {
return None;
}
}

path.push(current);
Some(DelayPath { path })
}

/// Build the critical paths along each critical endpoint
pub fn get_critical_paths<I: Instantiable>(
analysis: &CombDepthInfo<'_, I>,
) -> impl Iterator<Item = DelayPath<I>> {
analysis
.get_critical_points()
.into_iter()
.flat_map(|p| build_path_from_endpoint(analysis, p))
}
Loading
Loading