From 2ad9a1d15717b9e9e03746a05b716ab0cdad8664 Mon Sep 17 00:00:00 2001 From: saji Date: Thu, 2 May 2024 16:11:24 -0500 Subject: [PATCH] wip: newtype nodeindex --- compiler/src/fitter.rs | 20 ++++++------- compiler/src/yosys_parser.rs | 55 +++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/compiler/src/fitter.rs b/compiler/src/fitter.rs index 8d9c244..f9541c0 100644 --- a/compiler/src/fitter.rs +++ b/compiler/src/fitter.rs @@ -1,5 +1,5 @@ use crate::pcf::PcfFile; -use crate::yosys_parser::{GalOLMC, GalSop, Graph, NamedPort, Net, Node}; +use crate::yosys_parser::{GalOLMC, GalSop, Graph, NamedPort, Net, Node, NodeIdx}; use galette::blueprint::Blueprint; use galette::chips::Chip; use log::info; @@ -26,10 +26,10 @@ pub enum MappingError { // attempt to map graph into blueprint /// Acquire the SOP associated with the OLMC. If it's -fn get_sop_for_olmc(graph: &Graph, olmc_idx: usize) -> Result { +fn get_sop_for_olmc(graph: &Graph, olmc_idx: NodeIdx) -> Result { let input = graph.get_node_port_conns(olmc_idx, "A"); assert_eq!(input.len(), 1, "OLMC input should have one netadjpair"); - let other_node = input[0].get_other(olmc_idx); + let other_node = input[0].get_other(olmc_idx).ok_or(MappingError::Unknown)?; let sop = graph .get_node(other_node.0) .ok_or(MappingError::MissingSOP)?; @@ -40,7 +40,7 @@ fn get_sop_for_olmc(graph: &Graph, olmc_idx: usize) -> Result) -> Result { +fn map_remaining_olcm(graph: &Graph, olmc: NodeIdx, unused: Vec<(usize, usize)>) -> Result { // (index, size) let mut chosen_row: Option<(usize, usize)> = None; // FIXME: implement. @@ -64,7 +64,7 @@ fn map_remaining_olcm(graph: &Graph, olmc: usize, unused: Vec<(usize, usize)>) - // at the end, if we have chosen a row, we can swap it in. match chosen_row { Some((row, size)) => { - info!("mapping {olmc} size {sopsize} to row {row} with size {size}"); + info!("mapping {olmc:?} size {sopsize} to row {row} with size {size}"); Ok(row) }, None => { @@ -73,8 +73,6 @@ fn map_remaining_olcm(graph: &Graph, olmc: usize, unused: Vec<(usize, usize)>) - } } -#[derive(Debug, Clone)] -struct GALMapEntry(GalOLMC, usize); // data and the entry in the graph pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result { let mut bp = Blueprint::new(chip); @@ -82,9 +80,9 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result< // phase one: OLMC mapping // start by finding the constraints. // - let mut olmcmap: Vec> = vec![None; chip.num_olmcs()]; + let mut olmcmap: Vec> = vec![None; chip.num_olmcs()]; - let mut deferrals: Vec = Vec::new(); + let mut deferrals: Vec = Vec::new(); // For all the OLMCs in the graph, we either map it directly since it's constrained to a pin, // or we defer it to later. @@ -110,11 +108,11 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result< .pin_to_olmc(pin.try_into()?) .ok_or(MappingError::Unknown)?; // TODO: check size of row vs size of SOP - info!("Found a real pin to map: Mapping node {o} onto row {olmc_row}"); + info!("Found a real pin to map: Mapping node {o:?} onto row {olmc_row}"); olmcmap[olmc_row] = Some(o); } None => { - info!("No port found, deferring placement for {o}"); + info!("No port found, deferring placement for {o:?}"); deferrals.push(o) } } diff --git a/compiler/src/yosys_parser.rs b/compiler/src/yosys_parser.rs index 08cf415..033bc4a 100644 --- a/compiler/src/yosys_parser.rs +++ b/compiler/src/yosys_parser.rs @@ -1,10 +1,8 @@ use crate::pcf::PcfFile; use galette::gal::Pin; -use log::error; use log::info; use serde::{de::Error, Deserialize, Deserializer, Serialize}; use serde_with::{serde_as, BoolFromInt}; -use std::collections::hash_map::Iter; use std::collections::HashMap; use std::str; @@ -228,13 +226,18 @@ impl NamedPort { } } +/// NodeIdx is an index into the node list to reference a specific node. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct NodeIdx(usize); + + #[derive(Debug, Clone)] pub struct NetAdjPair { pub net: Net, - idx1: usize, + idx1: NodeIdx, port1: String, port2: String, - idx2: usize, + idx2: NodeIdx, } impl PartialEq for NetAdjPair { @@ -270,21 +273,23 @@ impl NetAdjPair { pub fn uses_net(&self, net: &Net) -> bool { net == &self.net } - pub fn uses_nodeport(&self, idx: usize, port: &str) -> bool { + pub fn uses_nodeport(&self, idx: NodeIdx, port: &str) -> bool { (self.idx1 == idx && self.port1 == port) || (self.idx2 == idx && self.port2 == port) } - pub fn get_other(&self, my_idx: usize) -> (usize, &str) { + pub fn get_other(&self, my_idx: NodeIdx) -> Option<(NodeIdx, &str)> { if my_idx == self.idx1 { - (self.idx2, &self.port2) + Some((self.idx2, &self.port2)) } else if my_idx == self.idx2 { - (self.idx1, &self.port1) + Some((self.idx1, &self.port1)) } else { - (usize::MAX, "") + None } } } -/// A Node is an entry in our graph. A node has inputs and outputs. +/// A Node is an entry in our graph. A node has a set of connections that can be +/// read with `get_ports`. You can also see if a node accesses a given net with +/// `port_for_net` #[derive(Debug, PartialEq, Clone)] pub enum Node { Input(GalInput), @@ -312,23 +317,29 @@ impl Node { // Self::Olmc(go) => go.connections.input.to_vec(), // } // } - pub fn get_ports(&self) -> HashMap> { + + // Returns the hashmap of String (connection name) to a list of nets. + pub fn get_connections(&self) -> HashMap> { match self { Self::Olmc(ol) => ol.connections.clone(), Self::Input(i) => i.connections.clone(), Self::Sop(s) => s.connections.clone(), } } + + /// Returns the connection that contains this net, if any. pub fn port_for_net(&self, net: &Net) -> Option { - for (port, nets) in self.get_ports() { + for (port, nets) in self.get_connections() { if nets.contains(net) { return Some(port.to_string()); } } None } + + /// Get every net that this node uses. pub fn get_nets(&self) -> Vec { - self.get_ports() + self.get_connections() .iter() .flat_map(|(_, nets)| nets.clone()) .collect() @@ -373,8 +384,8 @@ impl Graph { let node2_port = node2.port_for_net(&net).expect("how"); let adj = NetAdjPair { net: net.clone(), - idx1, - idx2, + idx1: NodeIdx(idx1), + idx2: NodeIdx(idx2), port1: node1_port, port2: node2_port, }; @@ -388,11 +399,11 @@ impl Graph { } /// Find all nodes that are attached to this net in any way. /// Note that this is an expensive operation since it can't currently use the adjlist. - pub fn find_nodes(&self, net: &Net) -> Vec { + pub fn find_nodes_on_net(&self, net: &Net) -> Vec { let mut res = Vec::new(); for (idx, node) in self.nodelist.iter().enumerate() { if node.get_nets().contains(net) { - res.push(idx); + res.push(NodeIdx(idx)); } } res @@ -400,12 +411,12 @@ impl Graph { /// Retrieve a node from the node index /// TODO: make a newtype for the index. - pub fn get_node(&self, idx: usize) -> Option<&Node> { - self.nodelist.get(idx) + pub fn get_node(&self, idx: NodeIdx) -> Option<&Node> { + self.nodelist.get(idx.0) } // find the connections from the given node/port - pub fn get_node_port_conns(&self, nodeidx: usize, port: &str) -> Vec<&NetAdjPair> { + pub fn get_node_port_conns(&self, nodeidx: NodeIdx, port: &str) -> Vec<&NetAdjPair> { self.adjlist .iter() .filter(|adj| adj.uses_nodeport(nodeidx, port)) @@ -414,12 +425,12 @@ impl Graph { // TODO: get rid of this or refactor somehow????? // VERY BAD - pub fn get_olmc_idx(&self) -> Vec { + pub fn get_olmc_idx(&self) -> Vec { self.nodelist .iter() .enumerate() .filter_map(|(idx, node)| match node { - Node::Olmc(_) => Some(idx), + Node::Olmc(_) => Some(NodeIdx(idx)), _ => None, }) .collect()