use std::fmt;
use crate::network::gates::{BinaryType, NaryType, TernaryType};
use crate::{Gate, Network};
#[derive(Clone, Copy, Debug)]
pub struct AreaParameters {
pub and: usize,
pub and3: usize,
pub xor: usize,
pub xor3: usize,
pub mux: usize,
pub maj: usize,
pub dff: usize,
}
impl AreaParameters {
pub fn vlsi() -> AreaParameters {
AreaParameters {
and: 4,
and3: 6,
xor: 8,
xor3: 16,
mux: 9,
maj: 6,
dff: 24,
}
}
pub fn fpga() -> AreaParameters {
AreaParameters {
and: 2,
and3: 3,
xor: 2,
xor3: 3,
mux: 3,
maj: 3,
dff: 4,
}
}
pub fn sat() -> AreaParameters {
AreaParameters {
and: 7,
and3: 10,
xor: 12,
xor3: 24,
mux: 13,
maj: 18,
dff: 20,
}
}
fn andn(&self, n: usize) -> usize {
if n < 2 {
0
} else {
self.and + (n - 2) * (self.and3 - self.and)
}
}
fn xorn(&self, n: usize) -> usize {
if n < 2 {
0
} else {
self.xor + (n - 2) * (self.xor3 - self.xor)
}
}
pub fn gate_area(&self, g: &Gate) -> usize {
use Gate::*;
match g {
Binary(_, BinaryType::And) => self.and,
Ternary(_, TernaryType::And) => self.and3,
Binary(_, BinaryType::Xor) => self.xor,
Ternary(_, TernaryType::Xor) => self.xor3,
Nary(v, tp) => match tp {
NaryType::And | NaryType::Or | NaryType::Nand | NaryType::Nor => self.andn(v.len()),
NaryType::Xor | NaryType::Xnor => self.xorn(v.len()),
},
Dff(_) => self.dff,
Ternary(_, TernaryType::Mux) => self.mux,
Ternary(_, TernaryType::Maj) => self.maj,
Buf(_) => 0,
Lut(_) => todo!("LUT area not modeled"),
}
}
pub fn area(&self, a: &Network) -> usize {
let mut ret = 0;
for i in 0..a.nb_nodes() {
ret += self.gate_area(a.gate(i));
}
ret
}
pub fn check(&self) {
assert!(self.and > 0);
assert!(self.xor > 0);
assert!(self.and3 > 0);
assert!(self.xor3 > 0);
assert!(self.mux > 0);
assert!(self.maj > 0);
assert!(self.and3 > self.and);
assert!(self.xor3 > self.xor);
assert!(self.maj > self.and);
assert!(self.and3 <= 2 * self.and);
assert!(self.xor3 <= 2 * self.xor);
assert!(self.xor < self.mux);
assert!(self.and < self.mux);
}
}
impl fmt::Display for AreaParameters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Area costs:")?;
writeln!(f, " And2: {}", self.and)?;
writeln!(f, " And3: {}", self.and3)?;
writeln!(f, " Xor2: {}", self.xor)?;
writeln!(f, " Xor3: {}", self.xor3)?;
writeln!(f, " Mux: {}", self.mux)?;
writeln!(f, " Maj: {}", self.maj)?;
writeln!(f, " Dff: {}", self.dff)?;
fmt::Result::Ok(())
}
}
#[cfg(test)]
mod tests {
use super::AreaParameters;
#[test]
fn test_consistent() {
AreaParameters::vlsi().check();
AreaParameters::fpga().check();
AreaParameters::sat().check();
}
}