use std::{
cmp::{Ordering, Reverse},
collections::BinaryHeap,
num::{NonZeroU64, NonZeroUsize},
};
use awint::{awi::*, awint_dag::triple_arena::Advancer};
use crate::{
ensemble::{Ensemble, PBack, PLNode, PTNode, Referent},
Error,
};
#[derive(Debug, Clone, Copy)]
pub enum BasicValueKind {
Opaque,
Zero,
Umax,
Imax,
Imin,
Uone,
}
#[derive(Debug, Clone, Copy)]
pub struct BasicValue {
pub kind: BasicValueKind,
pub nzbw: NonZeroUsize,
}
impl BasicValue {
pub fn nzbw(&self) -> NonZeroUsize {
self.nzbw
}
pub fn bw(&self) -> usize {
self.nzbw().get()
}
#[must_use]
pub fn get(&self, inx: usize) -> Option<Option<bool>> {
if inx >= self.bw() {
None
} else {
Some(match self.kind {
BasicValueKind::Opaque => None,
BasicValueKind::Zero => Some(false),
BasicValueKind::Umax => Some(true),
BasicValueKind::Imax => Some(inx != (self.bw() - 1)),
BasicValueKind::Imin => Some(inx == (self.bw() - 1)),
BasicValueKind::Uone => Some(inx == 0),
})
}
}
}
#[derive(Debug, Clone)]
pub enum CommonValue<'a> {
Bits(&'a Bits),
Basic(BasicValue),
}
impl<'a> CommonValue<'a> {
pub fn nzbw(&self) -> NonZeroUsize {
match self {
CommonValue::Bits(x) => x.nzbw(),
CommonValue::Basic(basic) => basic.nzbw(),
}
}
pub fn bw(&self) -> usize {
self.nzbw().get()
}
pub fn get(&self, inx: usize) -> Option<Option<bool>> {
match self {
CommonValue::Bits(bits) => bits.get(inx).map(Some),
CommonValue::Basic(basic) => basic.get(inx),
}
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum Value {
ConstUnknown,
Unknown,
Const(bool),
Dynam(bool),
}
impl Value {
pub fn known_value(self) -> Option<bool> {
match self {
Value::ConstUnknown => None,
Value::Unknown => None,
Value::Const(b) => Some(b),
Value::Dynam(b) => Some(b),
}
}
pub fn is_known(self) -> bool {
match self {
Value::ConstUnknown | Value::Unknown => false,
Value::Const(_) | Value::Dynam(_) => true,
}
}
pub fn is_const(self) -> bool {
match self {
Value::Unknown | Value::Dynam(_) => false,
Value::ConstUnknown | Value::Const(_) => true,
}
}
pub fn constified(self) -> Self {
match self {
Value::ConstUnknown => self,
Value::Unknown => Value::ConstUnknown,
Value::Const(_) => self,
Value::Dynam(b) => Value::Const(b),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DynamicValue {
ConstUnknown,
Const(bool),
Dynam(PBack),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvalPhase {
Change,
Request,
}
#[derive(Debug, Clone, Copy)]
pub enum ChangeKind {
LNode(PLNode),
TNode(PTNode),
Manual(PBack, Value),
}
#[derive(Debug, Clone, Copy)]
pub struct Event {
pub partial_ord_num: NonZeroU64,
pub change_kind: ChangeKind,
}
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.partial_ord_num == other.partial_ord_num
}
}
impl Eq for Event {}
impl PartialOrd for Event {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.partial_ord_num.cmp(&other.partial_ord_num))
}
}
impl Ord for Event {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_ord_num.cmp(&other.partial_ord_num)
}
}
#[derive(Debug, Clone)]
pub struct Evaluator {
phase: EvalPhase,
events: BinaryHeap<Reverse<Event>>,
}
impl Evaluator {
pub fn new() -> Self {
Self {
phase: EvalPhase::Change,
events: BinaryHeap::new(),
}
}
pub fn check_clear(&mut self) -> Result<(), Error> {
if !self.events.is_empty() {
return Err(Error::OtherStr("events need to be empty"));
}
self.events.clear();
self.events.shrink_to_fit();
Ok(())
}
pub fn are_events_empty(&self) -> bool {
self.events.is_empty()
}
pub fn push_event(&mut self, event: Event) {
self.events.push(Reverse(event))
}
#[must_use]
pub fn pop_event(&mut self) -> Option<Event> {
self.events.pop().map(|e| e.0)
}
}
impl Ensemble {
pub fn switch_to_change_phase(&mut self) {
if self.evaluator.phase != EvalPhase::Change {
self.evaluator.phase = EvalPhase::Change;
}
}
pub fn restart_request_phase(&mut self) -> Result<(), Error> {
let mut event_gas = self.backrefs.len_keys() * 4;
while let Some(event) = self.evaluator.pop_event() {
let res = self.handle_event(event);
if res.is_err() {
self.evaluator.push_event(event)
}
res?;
if let Some(x) = event_gas.checked_sub(1) {
event_gas = x;
} else {
return Err(Error::OtherStr("ran out of event gas"));
}
}
self.evaluator.phase = EvalPhase::Request;
Ok(())
}
pub fn switch_to_request_phase(&mut self) -> Result<(), Error> {
if self.evaluator.phase != EvalPhase::Request {
self.restart_request_phase()
} else {
Ok(())
}
}
pub fn change_value(
&mut self,
p_back: PBack,
value: Value,
source_partial_ord_num: NonZeroU64,
) -> Result<(), Error> {
if let Some(equiv) = self.backrefs.get_val_mut(p_back) {
if equiv.val == value {
return Ok(())
}
if equiv.val.is_const() && (equiv.val != value) {
return Err(Error::OtherStr(
"tried to change a constant (probably, `retro_const_*` was used followed by a \
contradicting `retro_*`, or some invariant was broken)",
))
}
equiv.val = value;
if equiv.evaluator_partial_order <= source_partial_ord_num {
equiv.evaluator_partial_order = source_partial_ord_num.checked_add(1).unwrap();
}
let equiv_partial_ord_num = equiv.evaluator_partial_order;
self.switch_to_change_phase();
let mut adv = self.backrefs.advancer_surject(p_back);
while let Some(p_back) = adv.advance(&self.backrefs) {
let referent = *self.backrefs.get_key(p_back).unwrap();
match referent {
Referent::ThisEquiv
| Referent::ThisLNode(_)
| Referent::ThisTNode(_)
| Referent::ThisStateBit(..) => (),
Referent::Input(p_lnode) => {
self.evaluator.push_event(Event {
partial_ord_num: equiv_partial_ord_num,
change_kind: ChangeKind::LNode(p_lnode),
});
}
Referent::Driver(p_tnode) => {
self.evaluator.push_event(Event {
partial_ord_num: equiv_partial_ord_num,
change_kind: ChangeKind::TNode(p_tnode),
});
}
Referent::ThisRNode(_) => (),
}
}
Ok(())
} else {
Err(Error::InvalidPtr)
}
}
fn handle_event(&mut self, event: Event) -> Result<(), Error> {
match event.change_kind {
ChangeKind::LNode(p_lnode) => self.eval_lnode(p_lnode),
ChangeKind::TNode(p_tnode) => self.eval_tnode(p_tnode),
ChangeKind::Manual(p_back, val) => self.manual_change(p_back, val),
}
}
pub fn manual_change(&mut self, p_back: PBack, val: Value) -> Result<(), Error> {
self.change_value(p_back, val, NonZeroU64::new(1).unwrap())
}
pub fn eval_lnode(&mut self, p_lnode: PLNode) -> Result<(), Error> {
let p_back = self.lnodes.get(p_lnode).unwrap().p_self;
let (val, partial_ord_num) = self.calculate_lnode_value(p_lnode)?;
self.change_value(p_back, val, partial_ord_num)
}
pub fn eval_tnode(&mut self, p_tnode: PTNode) -> Result<(), Error> {
let tnode = self.tnodes.get(p_tnode).unwrap();
if tnode.delay().is_zero() {
let p_driver = tnode.p_driver;
let equiv = self.backrefs.get_val(p_driver).unwrap();
let partial_ord_num = equiv.evaluator_partial_order;
self.change_value(tnode.p_self, equiv.val, partial_ord_num)
} else {
self.delayer
.insert_delayed_tnode_event(p_tnode, tnode.delay());
Ok(())
}
}
pub fn request_value(&mut self, p_back: PBack) -> Result<Value, Error> {
if let Some(equiv) = self.backrefs.get_val_mut(p_back) {
if equiv.val.is_const() {
return Ok(equiv.val)
}
self.switch_to_request_phase()?;
Ok(self.backrefs.get_val(p_back).unwrap().val)
} else {
Err(Error::InvalidPtr)
}
}
}
impl Default for Evaluator {
fn default() -> Self {
Self::new()
}
}