use crate::network::{BinaryType, NaryType, TernaryType};
use crate::{Network, Signal};
use super::Fault;
#[derive(Clone, Debug)]
pub struct SimpleSimulator<'a> {
aig: &'a Network,
pub input_values: Vec<u64>,
pub node_values: Vec<u64>,
}
fn pol_to_word(s: Signal) -> u64 {
let pol = s.raw() & 1;
(!(pol as u64)).wrapping_add(1)
}
fn maj(a: u64, b: u64, c: u64) -> u64 {
(b & c) | (a & (b | c))
}
fn mux(s: u64, a: u64, b: u64) -> u64 {
(s & a) | (!s & b)
}
impl<'a> SimpleSimulator<'a> {
pub fn from_aig(aig: &'a Network) -> SimpleSimulator<'a> {
assert!(aig.is_topo_sorted());
SimpleSimulator {
aig,
input_values: vec![0; aig.nb_inputs()],
node_values: vec![0; aig.nb_nodes()],
}
}
pub fn run(&mut self, input_values: &Vec<Vec<u64>>) -> Vec<Vec<u64>> {
self.check();
self.reset();
let mut ret = Vec::new();
for (i, v) in input_values.iter().enumerate() {
if i != 0 {
self.run_dff();
}
self.copy_inputs(v.as_slice());
self.run_comb();
ret.push(self.get_output_values());
}
ret
}
pub fn run_with_faults(
&mut self,
input_values: &Vec<Vec<u64>>,
faults: &Vec<Fault>,
) -> Vec<Vec<u64>> {
self.check();
self.reset();
let mut ret = Vec::new();
for (i, v) in input_values.iter().enumerate() {
if i != 0 {
self.run_dff();
}
self.copy_inputs(v.as_slice());
self.run_comb_with_faults(faults);
ret.push(self.get_output_values());
}
ret
}
pub fn reset(&mut self) {
self.input_values = vec![0; self.aig.nb_inputs()];
self.node_values = vec![0; self.aig.nb_nodes()];
}
fn check(&self) {
assert!(self.aig.is_topo_sorted());
assert_eq!(self.input_values.len(), self.aig.nb_inputs());
assert_eq!(self.node_values.len(), self.aig.nb_nodes());
}
fn get_value(&self, s: Signal) -> u64 {
if s == Signal::zero() {
0
} else if s == Signal::one() {
!0
} else if s.is_input() {
self.input_values[s.input() as usize] ^ pol_to_word(s)
} else {
debug_assert!(s.is_var());
self.node_values[s.var() as usize] ^ pol_to_word(s)
}
}
pub fn copy_inputs(&mut self, inputs: &[u64]) {
assert_eq!(inputs.len(), self.input_values.len());
self.input_values.copy_from_slice(inputs);
}
pub fn run_dff(&mut self) {
use crate::Gate::*;
let mut next_values = self.node_values.clone();
for i in 0..self.aig.nb_nodes() {
let g = self.aig.gate(i);
if let Dff([d, en, res]) = g {
let dv = self.get_value(*d);
let env = self.get_value(*en);
let resv = self.get_value(*res);
let prevv = self.node_values[i];
let val = !resv & ((env & dv) | (!env & prevv));
next_values[i] = val;
}
}
self.node_values = next_values;
}
pub fn run_gate(&self, i: usize) -> u64 {
use crate::Gate::*;
let g = self.aig.gate(i);
match g {
Binary([a, b], tp) => {
let va = self.get_value(*a);
let vb = self.get_value(*b);
match tp {
BinaryType::And => va & vb,
BinaryType::Xor => va ^ vb,
}
}
Ternary([a, b, c], tp) => {
let va = self.get_value(*a);
let vb = self.get_value(*b);
let vc = self.get_value(*c);
match tp {
TernaryType::And => va & vb & vc,
TernaryType::Xor => va ^ vb ^ vc,
TernaryType::Maj => maj(va, vb, vc),
TernaryType::Mux => mux(va, vb, vc),
}
}
Dff(_) => self.node_values[i],
Nary(v, tp) => match tp {
NaryType::And => self.compute_andn(v, false, false),
NaryType::Or => self.compute_andn(v, true, true),
NaryType::Nand => self.compute_andn(v, false, true),
NaryType::Nor => self.compute_andn(v, true, false),
NaryType::Xor => self.compute_xorn(v, false),
NaryType::Xnor => self.compute_xorn(v, true),
},
Buf(s) => self.get_value(*s),
Lut(_) => todo!("Simulation of Lut not implemented"),
}
}
pub fn run_gate_with_input_stuck(&self, i: usize, input: usize, value: bool) -> u64 {
assert!(input < self.aig.gate(i).dependencies().len());
let v = if value { !0u64 } else { 0u64 };
use crate::Gate::*;
let g = self.aig.gate(i);
match g {
Binary([a, b], tp) => {
let va = if input == 0 { v } else { self.get_value(*a) };
let vb = if input == 1 { v } else { self.get_value(*b) };
match tp {
BinaryType::And => va & vb,
BinaryType::Xor => va ^ vb,
}
}
Ternary([a, b, c], tp) => {
let va = if input == 0 { v } else { self.get_value(*a) };
let vb = if input == 1 { v } else { self.get_value(*b) };
let vc = if input == 2 { v } else { self.get_value(*c) };
match tp {
TernaryType::And => va & vb & vc,
TernaryType::Xor => va ^ vb ^ vc,
TernaryType::Maj => maj(va, vb, vc),
TernaryType::Mux => mux(va, vb, vc),
}
}
Dff(_) => self.node_values[i],
Nary(v, tp) => match tp {
NaryType::And => self.compute_andn_with_input_stuck(v, false, false, input, value),
NaryType::Or => self.compute_andn_with_input_stuck(v, true, true, input, value),
NaryType::Nand => self.compute_andn_with_input_stuck(v, false, true, input, value),
NaryType::Nor => self.compute_andn_with_input_stuck(v, true, false, input, value),
NaryType::Xor => self.compute_xorn_with_input_stuck(v, false, input, value),
NaryType::Xnor => self.compute_xorn_with_input_stuck(v, true, input, value),
},
Buf(_) => v,
Lut(_) => todo!("Simulation of Lut not implemented"),
}
}
pub fn run_comb_with_faults(&mut self, faults: &Vec<Fault>) {
assert!(!Fault::has_duplicate_gate(faults));
for i in 0..self.aig.nb_nodes() {
self.node_values[i] = self.run_gate(i);
for f in faults {
match f {
Fault::OutputStuckAtFault { gate, value } => {
if *gate == i {
self.node_values[i] = if *value { !0u64 } else { 0u64 };
}
}
Fault::InputStuckAtFault { gate, input, value } => {
if *gate == i {
self.node_values[i] =
self.run_gate_with_input_stuck(*gate, *input, *value);
}
}
}
}
}
}
pub fn run_comb(&mut self) {
for i in 0..self.aig.nb_nodes() {
self.node_values[i] = self.run_gate(i);
}
}
fn compute_andn(&self, v: &[Signal], inv_in: bool, inv_out: bool) -> u64 {
let mut ret = !0u64;
for s in v {
ret &= self.get_value(s ^ inv_in);
}
if inv_out {
!ret
} else {
ret
}
}
fn compute_xorn(&self, v: &[Signal], inv_out: bool) -> u64 {
let mut ret = 0u64;
for s in v {
ret ^= self.get_value(*s);
}
if inv_out {
!ret
} else {
ret
}
}
fn compute_andn_with_input_stuck(
&self,
v: &[Signal],
inv_in: bool,
inv_out: bool,
input: usize,
value: bool,
) -> u64 {
let val = if value ^ inv_in { !0u64 } else { 0u64 };
let mut ret = !0u64;
for (i, s) in v.iter().enumerate() {
ret &= if i == input {
val
} else {
self.get_value(s ^ inv_in)
};
}
if inv_out {
!ret
} else {
ret
}
}
fn compute_xorn_with_input_stuck(
&self,
v: &[Signal],
inv_out: bool,
input: usize,
value: bool,
) -> u64 {
let val = if value { !0u64 } else { 0u64 };
let mut ret = 0u64;
for (i, s) in v.iter().enumerate() {
ret ^= if i == input { val } else { self.get_value(*s) };
}
if inv_out {
!ret
} else {
ret
}
}
fn get_output_values(&self) -> Vec<u64> {
let mut ret = Vec::new();
for o in 0..self.aig.nb_outputs() {
ret.push(self.get_value(self.aig.output(o)));
}
ret
}
}