mirror of
https://github.com/annoyatron255/yosys4gal.git
synced 2024-12-22 18:52:23 +00:00
bugfixes, working on SOP stuff
This commit is contained in:
parent
5ac484b1a8
commit
a550d84750
30
compiler/Cargo.lock
generated
30
compiler/Cargo.lock
generated
|
@ -267,6 +267,29 @@ version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_filter"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@ -323,6 +346,12 @@ version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.60"
|
version = "0.1.60"
|
||||||
|
@ -676,6 +705,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap 4.5.4",
|
"clap 4.5.4",
|
||||||
|
"env_logger",
|
||||||
"galette",
|
"galette",
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
"regex",
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.81"
|
anyhow = "1.0.81"
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
|
env_logger = "0.11.3"
|
||||||
galette = "0.3.0"
|
galette = "0.3.0"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
|
use std::str::from_utf8;
|
||||||
|
|
||||||
use crate::pcf::PcfFile;
|
use crate::pcf::PcfFile;
|
||||||
use crate::yosys_parser::{GalOLMC, GalSop, Graph, NamedPort, Net, Node, NodeIdx, PortDirection};
|
use crate::yosys_parser::{GalInput, 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::{debug, info, warn};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use galette::gal::{Pin, Term};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum MappingError {
|
pub enum MappingError {
|
||||||
#[error("OLMC missing output: {0}")]
|
#[error("OLMC missing output: {0}")]
|
||||||
|
@ -26,18 +30,33 @@ pub enum MappingError {
|
||||||
// attempt to map graph into blueprint
|
// 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> {
|
fn get_sop_for_olmc(graph: &Graph, olmc_idx: &NodeIdx) -> Result<GalSop, MappingError> {
|
||||||
let input = graph.get_node_port_conns(olmc_idx, "A");
|
let input = graph.get_node_port_conns(olmc_idx, "A");
|
||||||
assert_eq!(input.len(), 1, "OLMC input should have one netadjpair");
|
let sops_on_net: Vec<_> = input
|
||||||
let other_node = input[0].get_other(olmc_idx).ok_or(MappingError::Unknown)?;
|
.iter()
|
||||||
let sop = graph
|
.filter_map(|i| {
|
||||||
.get_node(other_node.0)
|
let sop = i.get_other(olmc_idx)?;
|
||||||
.ok_or(MappingError::MissingSOP)?;
|
if sop.1 != "Y" {
|
||||||
if let Node::Sop(s) = sop {
|
return None;
|
||||||
Ok(s.clone())
|
};
|
||||||
} else {
|
let node = graph.get_node(&sop.0)?;
|
||||||
Err(MappingError::MissingSOP)
|
match node {
|
||||||
}
|
Node::Sop(s) => Some(s),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert_eq!(sops_on_net.len(), 1, "Should only be one sop driving a net");
|
||||||
|
Ok(sops_on_net[0].clone())
|
||||||
|
// 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)?;
|
||||||
|
// if let Node::Sop(s) = sop {
|
||||||
|
// Ok(s.clone())
|
||||||
|
// } else {
|
||||||
|
// Err(MappingError::MissingSOP)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_remaining_olmc(
|
fn map_remaining_olmc(
|
||||||
|
@ -48,7 +67,7 @@ fn map_remaining_olmc(
|
||||||
// (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 sop = get_sop_for_olmc(graph, olmc)?;
|
let sop = get_sop_for_olmc(graph, &olmc)?;
|
||||||
let sopsize: usize = sop.parameters.depth as usize;
|
let sopsize: usize = sop.parameters.depth as usize;
|
||||||
|
|
||||||
for (olmc_idx, size) in unused {
|
for (olmc_idx, size) in unused {
|
||||||
|
@ -79,6 +98,88 @@ fn map_remaining_olmc(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_hwpin_for_net(graph: &Graph, pcf: &PcfFile, net: &Net) -> Result<u32, MappingError> {
|
||||||
|
// this does a double lookup. first it finds the Input on the net,
|
||||||
|
// then it finds the port on the input of the GAL_INPUT.
|
||||||
|
// find the input on the net.
|
||||||
|
let inputs: Vec<&GalInput> = graph
|
||||||
|
.find_nodes_on_net(net)
|
||||||
|
.iter()
|
||||||
|
.filter_map(|n| match graph.get_node(n) {
|
||||||
|
Some(Node::Input(i)) => Some(i),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// now we have an array of inputs, this should be one elemnt.
|
||||||
|
if inputs.len() != 1 {
|
||||||
|
return Err(MappingError::Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
let port_nets = inputs[0]
|
||||||
|
.connections
|
||||||
|
.get("A")
|
||||||
|
.ok_or(MappingError::Unknown)?;
|
||||||
|
assert_eq!(port_nets.len(), 1, "should only be one input to GAL_INPUT");
|
||||||
|
let pnet = &port_nets[0];
|
||||||
|
|
||||||
|
if let Some(p) = graph.find_port(&pnet) {
|
||||||
|
info!("Found a port after traversing inputs");
|
||||||
|
// look up the pin.
|
||||||
|
p.lookup(pcf)
|
||||||
|
.ok_or(MappingError::MissingConstraint(p.clone()))
|
||||||
|
} else {
|
||||||
|
Err(MappingError::Unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Takes a gal sop, and turns it into a vec of mapped pins.
|
||||||
|
fn make_term_from_sop(graph: &Graph, sop: GalSop, pcf: &PcfFile) -> Term {
|
||||||
|
let table = sop.parameters.table.as_bytes();
|
||||||
|
|
||||||
|
let n_products = sop.parameters.depth;
|
||||||
|
let product_size = sop.parameters.width;
|
||||||
|
let chunksize = product_size * 2; // 00 for dontcare, 01 for negation, 10 for positive i think
|
||||||
|
|
||||||
|
let input_nets = sop.connections.get("A").unwrap();
|
||||||
|
|
||||||
|
let terms: Vec<Vec<Pin>> = table
|
||||||
|
.chunks(chunksize as usize)
|
||||||
|
.map(|chunk| {
|
||||||
|
// chunk is now a block of terms.
|
||||||
|
let terms: Vec<&str> = chunk.chunks(2).map(|c| from_utf8(c).unwrap()).collect();
|
||||||
|
// create our term
|
||||||
|
let pins: Vec<Pin> = terms
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(idx, p)| {
|
||||||
|
let net_for_pin = input_nets.get(idx).unwrap();
|
||||||
|
// now use the helper to find the true hardware pin
|
||||||
|
let hwpin: usize =
|
||||||
|
find_hwpin_for_net(graph, pcf, net_for_pin).unwrap() as usize;
|
||||||
|
// we now have our hardware pin number!
|
||||||
|
match *p {
|
||||||
|
"01" => Some(Pin {
|
||||||
|
pin: hwpin,
|
||||||
|
neg: true,
|
||||||
|
}),
|
||||||
|
"10" => Some(Pin {
|
||||||
|
pin: hwpin,
|
||||||
|
neg: false,
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
pins
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
assert_eq!(n_products as usize, terms.len());
|
||||||
|
Term {
|
||||||
|
line_num: 0,
|
||||||
|
pins: terms,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn valid_inputs(chip: Chip) -> Vec<u32> {
|
fn valid_inputs(chip: Chip) -> Vec<u32> {
|
||||||
match chip {
|
match chip {
|
||||||
Chip::GAL16V8 => vec![
|
Chip::GAL16V8 => vec![
|
||||||
|
@ -94,9 +195,6 @@ fn valid_inputs(chip: Chip) -> Vec<u32> {
|
||||||
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 valid_inp = valid_inputs(chip);
|
||||||
let mut olmcmap: Vec<Option<NodeIdx>> = vec![None; chip.num_olmcs()];
|
let mut olmcmap: Vec<Option<NodeIdx>> = vec![None; chip.num_olmcs()];
|
||||||
|
|
||||||
|
@ -108,13 +206,16 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
|
||||||
if let Some(olmcrow) = chip.pin_to_olmc(pin as usize) {
|
if let Some(olmcrow) = chip.pin_to_olmc(pin as usize) {
|
||||||
if port.direction == PortDirection::Input {
|
if port.direction == PortDirection::Input {
|
||||||
olmcmap[olmcrow] = Some(NodeIdx(usize::MAX));
|
olmcmap[olmcrow] = Some(NodeIdx(usize::MAX));
|
||||||
} // otherwise we do not care!
|
} // otherwise we do not care at this point!
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(MappingError::Unknown.into());
|
// we don't have a constraint for this port
|
||||||
|
return Err(MappingError::MissingConstraint(port.clone()).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Graph adj list is {:?}", graph.adjlist);
|
||||||
|
|
||||||
// phase one: OLMC mapping
|
// phase one: OLMC mapping
|
||||||
// start by finding the constraints.
|
// start by finding the constraints.
|
||||||
|
|
||||||
|
@ -123,16 +224,21 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
|
||||||
// For all the OLMCs in the graph, we either map it directly since it's constrained to a pin,
|
// 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.
|
// or we defer it to later.
|
||||||
for o in graph.get_olmc_idx() {
|
for o in graph.get_olmc_idx() {
|
||||||
|
debug!("Processing OLMC {o}");
|
||||||
|
debug!("Value = {:?}", graph.get_node(&o));
|
||||||
// find all the
|
// find all the
|
||||||
let others: Vec<Net> = graph
|
|
||||||
.get_node_port_conns(o, "Y")
|
let n: &Net;
|
||||||
.iter()
|
if let Some(Node::Olmc(olmc)) = graph.get_node(&o) {
|
||||||
.map(|adj| adj.net.clone())
|
n = &olmc.connections.get("Y").ok_or(MappingError::Unknown)?[0];
|
||||||
.collect();
|
} else {
|
||||||
|
warn!("Could not find output net! Silently skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// if it's got a port we map it now else we defer it.
|
// if it's got a port we map it now else we defer it.
|
||||||
|
|
||||||
let port = graph.find_port(&others[0]);
|
let port = graph.find_port(n);
|
||||||
|
|
||||||
match port {
|
match port {
|
||||||
Some(port) => {
|
Some(port) => {
|
||||||
|
@ -164,8 +270,8 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
|
||||||
let num_mapped = olmcmap.iter().filter(|x| x.is_some()).count();
|
let num_mapped = olmcmap.iter().filter(|x| x.is_some()).count();
|
||||||
info!("Mapped {num_mapped} OLMCS, {} deferred", deferrals.len());
|
info!("Mapped {num_mapped} OLMCS, {} deferred", deferrals.len());
|
||||||
|
|
||||||
// to map remainders, we need to find the smallest SOP.
|
// to map the deferred ones, we need to find the smallest SOP that is still large enough for
|
||||||
//
|
// it.
|
||||||
// Vec<(olmc_index,size)>
|
// Vec<(olmc_index,size)>
|
||||||
let mut unused_rows = olmcmap
|
let mut unused_rows = olmcmap
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -175,8 +281,10 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// find the smallest row that fits.
|
// find the smallest row that fits.
|
||||||
|
info!("Starting deferred mapping process");
|
||||||
for olmc in deferrals {
|
for olmc in deferrals {
|
||||||
let row = map_remaining_olmc(graph, olmc, &unused_rows)?;
|
let row = map_remaining_olmc(graph, olmc, &unused_rows)?;
|
||||||
|
debug!("Found a mapping for {olmc} in row {} size {}", row.0, row.1);
|
||||||
// insert into the mapping
|
// insert into the mapping
|
||||||
olmcmap[row.0] = Some(olmc);
|
olmcmap[row.0] = Some(olmc);
|
||||||
// remove this row from the available rows
|
// remove this row from the available rows
|
||||||
|
@ -185,7 +293,32 @@ pub fn graph_convert(graph: &Graph, pcf: PcfFile, chip: Chip) -> anyhow::Result<
|
||||||
}
|
}
|
||||||
|
|
||||||
// at this point, we have mapped every OLMC.
|
// at this point, we have mapped every OLMC.
|
||||||
// now use the blueprint to set the settings.
|
// find the SOPs and for each sop, find
|
||||||
|
info!("Deferred mapping complete, starting SOP mapping");
|
||||||
|
for (idx, olmc) in olmcmap.iter().enumerate() {
|
||||||
|
match olmc {
|
||||||
|
Some(node) => {
|
||||||
|
debug!("Mapping node {node} at row {idx}");
|
||||||
|
let sop = get_sop_for_olmc(graph, node)?;
|
||||||
|
debug!("Got SOP {:?} attached to node", sop);
|
||||||
|
let term = make_term_from_sop(graph, sop, &pcf);
|
||||||
|
debug!("Got term {:?}", term);
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(bp)
|
Ok(bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sop_to_term() -> Result<()> {
|
||||||
|
let pct = "set_io pinName 1";
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
pub mod pcf;
|
pub mod pcf;
|
||||||
pub mod yosys_parser;
|
pub mod yosys_parser;
|
||||||
|
mod fitter;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand, Args};
|
use clap::{Parser, Subcommand, Args};
|
||||||
|
use crate::pcf::parse_pcf;
|
||||||
use crate::yosys_parser::{YosysDoc, Graph};
|
use crate::yosys_parser::{YosysDoc, Graph};
|
||||||
|
use crate::fitter::graph_convert;
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use serde_json::from_slice;
|
use serde_json::from_slice;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use galette::chips::Chip;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use env_logger;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
|
@ -18,6 +23,7 @@ struct Cli {
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// Validate a yosys netlist JSON file.
|
/// Validate a yosys netlist JSON file.
|
||||||
Validate(ValidateArgs),
|
Validate(ValidateArgs),
|
||||||
|
Synth(SynthArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
@ -27,6 +33,15 @@ struct ValidateArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Args)]
|
||||||
|
struct SynthArgs {
|
||||||
|
#[arg(required = true, value_hint = clap::ValueHint::DirPath)]
|
||||||
|
netlist: PathBuf,
|
||||||
|
#[arg(required = true, value_hint = clap::ValueHint::DirPath)]
|
||||||
|
constraints: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn validate(v: ValidateArgs) -> Result<()>{
|
fn validate(v: ValidateArgs) -> Result<()>{
|
||||||
let f = fs::read(v.file)?;
|
let f = fs::read(v.file)?;
|
||||||
|
|
||||||
|
@ -44,9 +59,38 @@ fn validate(v: ValidateArgs) -> Result<()>{
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn synth(s: SynthArgs) -> Result<()> {
|
||||||
|
let f = fs::read(s.netlist)?;
|
||||||
|
|
||||||
|
let data: YosysDoc = from_slice(f.as_slice())?;
|
||||||
|
|
||||||
|
let g = Graph::from(data);
|
||||||
|
let res = g.validate().map_err(|x| x.to_string());
|
||||||
|
if let Err(e) = res {
|
||||||
|
bail!(e);
|
||||||
|
}
|
||||||
|
println!("Validation Complete!");
|
||||||
|
println!("Stats:");
|
||||||
|
println!("Nodes: {}", g.nodelist.len());
|
||||||
|
println!("Edges: {}", g.adjlist.len());
|
||||||
|
|
||||||
|
// load the pcf
|
||||||
|
let pcf_file = &fs::read(s.constraints)?;
|
||||||
|
let pcf_string = std::str::from_utf8(pcf_file)?;
|
||||||
|
let pcf = parse_pcf(pcf_string);
|
||||||
|
|
||||||
|
let res = graph_convert(&g, pcf, Chip::GAL16V8);
|
||||||
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()>{
|
fn main() -> Result<()>{
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
|
env_logger::init();
|
||||||
match args.command {
|
match args.command {
|
||||||
Commands::Validate(v) => validate(v),
|
Commands::Validate(v) => validate(v),
|
||||||
|
Commands::Synth(s) => synth(s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use log::info;
|
||||||
use serde::{de::Error, Deserialize, Deserializer, Serialize};
|
use serde::{de::Error, Deserialize, Deserializer, Serialize};
|
||||||
use serde_with::{serde_as, BoolFromInt};
|
use serde_with::{serde_as, BoolFromInt};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Serialize, Clone, Deserialize, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -230,6 +231,12 @@ impl NamedPort {
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct NodeIdx(pub usize);
|
pub struct NodeIdx(pub usize);
|
||||||
|
|
||||||
|
impl fmt::Display for NodeIdx {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "(Nodeindex: {})", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NetAdjPair {
|
pub struct NetAdjPair {
|
||||||
|
@ -273,13 +280,13 @@ impl NetAdjPair {
|
||||||
pub fn uses_net(&self, net: &Net) -> bool {
|
pub fn uses_net(&self, net: &Net) -> bool {
|
||||||
net == &self.net
|
net == &self.net
|
||||||
}
|
}
|
||||||
pub fn uses_nodeport(&self, idx: NodeIdx, 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)
|
(&self.idx1 == idx && self.port1 == port) || (&self.idx2 == idx && self.port2 == port)
|
||||||
}
|
}
|
||||||
pub fn get_other(&self, my_idx: NodeIdx) -> Option<(NodeIdx, &str)> {
|
pub fn get_other(&self, my_idx: &NodeIdx) -> Option<(NodeIdx, &str)> {
|
||||||
if my_idx == self.idx1 {
|
if my_idx == &self.idx1 {
|
||||||
Some((self.idx2, &self.port2))
|
Some((self.idx2, &self.port2))
|
||||||
} else if my_idx == self.idx2 {
|
} else if my_idx == &self.idx2 {
|
||||||
Some((self.idx1, &self.port1))
|
Some((self.idx1, &self.port1))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -396,12 +403,12 @@ impl Graph {
|
||||||
|
|
||||||
/// Retrieve a node from the node index
|
/// Retrieve a node from the node index
|
||||||
/// TODO: make a newtype for the index.
|
/// TODO: make a newtype for the index.
|
||||||
pub fn get_node(&self, idx: NodeIdx) -> Option<&Node> {
|
pub fn get_node(&self, idx: &NodeIdx) -> Option<&Node> {
|
||||||
self.nodelist.get(idx.0)
|
self.nodelist.get(idx.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the connections from the given node/port
|
// find the connections from the given node/port ONLY WORKS FOR NON_PORT DEVICES.
|
||||||
pub fn get_node_port_conns(&self, nodeidx: NodeIdx, port: &str) -> Vec<&NetAdjPair> {
|
pub fn get_node_port_conns(&self, nodeidx: &NodeIdx, port: &str) -> Vec<&NetAdjPair> {
|
||||||
self.adjlist
|
self.adjlist
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|adj| adj.uses_nodeport(nodeidx, port))
|
.filter(|adj| adj.uses_nodeport(nodeidx, port))
|
||||||
|
@ -527,12 +534,61 @@ type Parameters = HashMap<String, String>;
|
||||||
|
|
||||||
pub trait Cell {
|
pub trait Cell {
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
fn connections(&self) -> &Connections;
|
|
||||||
fn params(&self) -> &Parameters;
|
|
||||||
fn ctype(&self) -> CellType;
|
fn ctype(&self) -> CellType;
|
||||||
|
|
||||||
|
fn get_connection(&self, conn: &str) -> Option<&Vec<Net>>;
|
||||||
|
fn get_param(&self, param: &str) -> Option<&String>;
|
||||||
fn nets(&self) -> Vec<Net>;
|
fn nets(&self) -> Vec<Net>;
|
||||||
fn uses_net(&self, net: Net) -> bool;
|
fn uses_net(&self, net: Net) -> bool;
|
||||||
fn net_on_port(&self, net: Net) -> Option<String>;
|
}
|
||||||
|
|
||||||
|
pub struct GalCell {
|
||||||
|
name: Option<String>,
|
||||||
|
ctype: CellType,
|
||||||
|
connections: Connections,
|
||||||
|
params: Parameters,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GalCell {
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.clone().unwrap_or("unnamed".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_connection(&self, conn: &str) -> Option<&Vec<Net>> {
|
||||||
|
self.connections.get(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the parameter from the cell. Note that this does not
|
||||||
|
/// have.
|
||||||
|
pub fn get_param(&self, param: &str) -> Option<&String> {
|
||||||
|
self.params.get(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get all of the nets that this cell uses
|
||||||
|
pub fn nets(&self) -> Vec<&Net> {
|
||||||
|
self.connections.iter().flat_map(|x| x.1).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the net is used at all by the cell
|
||||||
|
pub fn uses_net(&self, net: &Net) -> bool {
|
||||||
|
self.nets().contains(&net)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the port that uses the given net, if any.
|
||||||
|
pub fn get_port_for_net(&self, net: &Net) -> Option<&str> {
|
||||||
|
for (port, nets) in self.connections.iter() {
|
||||||
|
if nets.contains(net) {
|
||||||
|
return Some(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the underlying Cell type, used to differentiate available
|
||||||
|
/// connections
|
||||||
|
pub fn ctype(&self) -> &CellType {
|
||||||
|
&self.ctype
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue