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::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::chips::Chip;
use log::info;
@ -16,8 +16,8 @@ pub enum MappingError {
#[error("Could not find the SOP input")]
MissingSOP,
#[error("Could not find a sop to fit {0}")]
SopTooBig(usize),
#[error("Could not find a sop to fit SOP {0:?} of {1}")]
SopTooBig(String, usize),
#[error("Unknown error")]
Unknown,
@ -25,7 +25,7 @@ pub enum MappingError {
// attempt to map graph into blueprint
/// Acquire the SOP associated with the OLMC. If it's
/// Acquire the SOP associated with the OLMC. If it's
fn get_sop_for_olmc(graph: &Graph, olmc_idx: NodeIdx) -> Result<GalSop, MappingError> {
let input = graph.get_node_port_conns(olmc_idx, "A");
assert_eq!(input.len(), 1, "OLMC input should have one netadjpair");
@ -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)
let mut chosen_row: Option<(usize, usize)> = None;
// 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 {
match chosen_row {
None => {
if size > sopsize {
chosen_row = Some((olmc_idx, size));
if size > &sopsize {
chosen_row = Some((*olmc_idx, *size));
}
}
Some(r) => {
// we do the comparison (size > SOP Size)
if size < r.1 && size > sopsize {
chosen_row = Some((olmc_idx, size));
if size < &r.1 && size > &sopsize {
chosen_row = Some((*olmc_idx, *size));
}
}
}
}
// 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}");
Ok(row)
},
None => {
Err(MappingError::SopTooBig(sopsize))
Some(x) => {
info!(
"mapping {olmc:?} size {sopsize} to row {} with size {}",
x.0, x.1
);
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> {
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
// start by finding the constraints.
//
let mut olmcmap: Vec<Option<NodeIdx>> = vec![None; chip.num_olmcs()];
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()?)
.ok_or(MappingError::Unknown)?;
// 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}");
// 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);
}
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.
//
// Vec<(olmc_index,size)>
let unused_rows = olmcmap
let mut unused_rows = olmcmap
.iter()
.enumerate()
.filter_map(|(i, x)| if !x.is_some() { Some(i) } else { None })
.map(|i| (i, chip.num_rows_for_olmc(i)));
// find the smallest row that fits.
.enumerate() // get the index
.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)))
.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)
}

View file

@ -64,9 +64,9 @@ pub struct GalSop {
#[serde(rename_all = "UPPERCASE")]
pub struct GALOLMCParameters {
#[serde(deserialize_with = "bool_from_binstr")]
inverted: bool,
pub inverted: bool,
#[serde(deserialize_with = "bool_from_binstr")]
registered: bool,
pub registered: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@ -187,8 +187,8 @@ pub enum PortDirection {
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct NamedPort {
pub name: String,
net: Net,
direction: PortDirection,
pub net: Net,
pub direction: PortDirection,
}
use std::cmp::Ordering;
@ -228,7 +228,7 @@ 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);
pub struct NodeIdx(pub usize);
#[derive(Debug, Clone)]