port mapping, inputs on OLMC outputs consume the OLMC

This commit is contained in:
saji 2024-05-02 17:39:36 -05:00
parent 2ad9a1d157
commit 8bfcd28e0d
2 changed files with 83 additions and 30 deletions

View file

@ -1,5 +1,5 @@
use crate::pcf::PcfFile; use crate::pcf::PcfFile;
use crate::yosys_parser::{GalOLMC, GalSop, Graph, NamedPort, Net, Node, NodeIdx}; use crate::yosys_parser::{GalOLMC, GalSop, Graph, NamedPort, Net, Node, NodeIdx, PortDirection};
use galette::blueprint::Blueprint; use galette::blueprint::Blueprint;
use galette::chips::Chip; use galette::chips::Chip;
use log::info; use log::info;
@ -16,8 +16,8 @@ pub enum MappingError {
#[error("Could not find the SOP input")] #[error("Could not find the SOP input")]
MissingSOP, MissingSOP,
#[error("Could not find a sop to fit {0}")] #[error("Could not find a sop to fit SOP {0:?} of {1}")]
SopTooBig(usize), SopTooBig(String, usize),
#[error("Unknown error")] #[error("Unknown error")]
Unknown, Unknown,
@ -40,47 +40,83 @@ fn get_sop_for_olmc(graph: &Graph, olmc_idx: NodeIdx) -> Result<GalSop, MappingE
} }
} }
fn map_remaining_olcm(graph: &Graph, olmc: NodeIdx, unused: Vec<(usize, usize)>) -> Result<usize, MappingError> { fn map_remaining_olmc(
graph: &Graph,
olmc: NodeIdx,
unused: &Vec<(usize, usize)>,
) -> Result<(usize, usize), MappingError> {
// (index, size) // (index, size)
let mut chosen_row: Option<(usize, usize)> = None; let mut chosen_row: Option<(usize, usize)> = None;
// FIXME: implement. // FIXME: implement.
let sopsize: usize = get_sop_for_olmc(graph, olmc)?.parameters.depth as usize; let sop = get_sop_for_olmc(graph, olmc)?;
let sopsize: usize = sop.parameters.depth as usize;
for (olmc_idx, size) in unused { for (olmc_idx, size) in unused {
match chosen_row { match chosen_row {
None => { None => {
if size > sopsize { if size > &sopsize {
chosen_row = Some((olmc_idx, size)); chosen_row = Some((*olmc_idx, *size));
} }
} }
Some(r) => { Some(r) => {
// we do the comparison (size > SOP Size) // we do the comparison (size > SOP Size)
if size < r.1 && size > sopsize { if size < &r.1 && size > &sopsize {
chosen_row = Some((olmc_idx, size)); chosen_row = Some((*olmc_idx, *size));
} }
} }
} }
} }
// at the end, if we have chosen a row, we can swap it in. // at the end, if we have chosen a row, we can swap it in.
match chosen_row { match chosen_row {
Some((row, size)) => { Some(x) => {
info!("mapping {olmc:?} size {sopsize} to row {row} with size {size}"); info!(
Ok(row) "mapping {olmc:?} size {sopsize} to row {} with size {}",
}, x.0, x.1
None => { );
Err(MappingError::SopTooBig(sopsize)) Ok(x)
} }
None => Err(MappingError::SopTooBig("TODO FIXME".to_string(), sopsize)),
} }
} }
fn valid_inputs(chip: Chip) -> Vec<u32> {
match chip {
Chip::GAL16V8 => vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19,
],
Chip::GAL22V10 => vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
],
_ => panic!("unsupported chip"),
}
}
pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<Blueprint> { pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<Blueprint> {
let mut bp = Blueprint::new(chip); let mut bp = Blueprint::new(chip);
// phase zero: input mapping.
let mut pinmap: Vec<Option<String>> = vec![None; chip.num_pins()];
let valid_inp = valid_inputs(chip);
let mut olmcmap: Vec<Option<NodeIdx>> = vec![None; chip.num_olmcs()];
for port in &graph.ports {
let pin = port
.lookup(&pcf)
.ok_or(MappingError::MissingConstraint(port.clone()))?;
if valid_inp.contains(&pin) {
if let Some(olmcrow) = chip.pin_to_olmc(pin as usize) {
if port.direction == PortDirection::Input {
olmcmap[olmcrow] = Some(NodeIdx(usize::MAX));
} // otherwise we do not care!
}
} else {
return Err(MappingError::Unknown.into());
}
}
// phase one: OLMC mapping // phase one: OLMC mapping
// start by finding the constraints. // start by finding the constraints.
//
let mut olmcmap: Vec<Option<NodeIdx>> = vec![None; chip.num_olmcs()];
let mut deferrals: Vec<NodeIdx> = Vec::new(); let mut deferrals: Vec<NodeIdx> = Vec::new();
@ -108,7 +144,14 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
.pin_to_olmc(pin.try_into()?) .pin_to_olmc(pin.try_into()?)
.ok_or(MappingError::Unknown)?; .ok_or(MappingError::Unknown)?;
// TODO: check size of row vs size of SOP // TODO: check size of row vs size of SOP
// FIXME: -0 to size if registered, if comb, size - 1
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}");
// check if OLMC row is already in use
if let Some(o) = olmcmap[olmc_row] {
info!("already exists in {o:?}");
return Err(MappingError::Unknown.into());
}
olmcmap[olmc_row] = Some(o); olmcmap[olmc_row] = Some(o);
} }
None => { None => {
@ -124,14 +167,24 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
// to map remainders, we need to find the smallest SOP. // to map remainders, we need to find the smallest SOP.
// //
// Vec<(olmc_index,size)> // Vec<(olmc_index,size)>
let unused_rows = olmcmap let mut unused_rows = olmcmap
.iter() .iter()
.enumerate() .enumerate() // get the index
.filter_map(|(i, x)| if !x.is_some() { Some(i) } else { None }) .filter_map(|(i, x)| if x.is_none() { Some(i) } else { None }) // find the ones that are
.map(|i| (i, chip.num_rows_for_olmc(i))); .map(|i| (i, chip.num_rows_for_olmc(i)))
// find the smallest row that fits. .collect();
let olmc = deferrals[0]; // find the smallest row that fits.
for olmc in deferrals {
let row = map_remaining_olmc(graph, olmc, &unused_rows)?;
// insert into the mapping
olmcmap[row.0] = Some(olmc);
// remove this row from the available rows
// i.e only keep those that are not equal to this row.
unused_rows.retain(|r| r != &row);
}
// at this point, we have mapped every OLMC.
Ok(bp) Ok(bp)
} }

View file

@ -64,9 +64,9 @@ pub struct GalSop {
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
pub struct GALOLMCParameters { pub struct GALOLMCParameters {
#[serde(deserialize_with = "bool_from_binstr")] #[serde(deserialize_with = "bool_from_binstr")]
inverted: bool, pub inverted: bool,
#[serde(deserialize_with = "bool_from_binstr")] #[serde(deserialize_with = "bool_from_binstr")]
registered: bool, pub registered: bool,
} }
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -187,8 +187,8 @@ pub enum PortDirection {
#[derive(Debug, Clone, PartialEq, PartialOrd)] #[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct NamedPort { pub struct NamedPort {
pub name: String, pub name: String,
net: Net, pub net: Net,
direction: PortDirection, pub direction: PortDirection,
} }
use std::cmp::Ordering; use std::cmp::Ordering;
@ -228,7 +228,7 @@ impl NamedPort {
/// NodeIdx is an index into the node list to reference a specific node. /// NodeIdx is an index into the node list to reference a specific node.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeIdx(usize); pub struct NodeIdx(pub usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]