#![allow(unused_imports)]
use crate::value::{TimeValue, Value};
use llhd::ir::Unit;
use num::zero;
use std::{
cmp::Ordering,
collections::{BTreeMap, BinaryHeap, HashMap, HashSet},
fmt,
ops::{Index, IndexMut},
sync::Mutex,
};
pub struct State<'ll> {
pub module: &'ll llhd::ir::Module,
pub signals: Vec<Signal>,
pub probes: HashMap<SignalRef, Vec<String>>,
pub scope: Scope,
pub insts: Vec<Mutex<Instance<'ll>>>,
pub time: TimeValue,
pub events: BTreeMap<TimeValue, HashMap<ValuePointer, Value>>,
pub timed: BTreeMap<TimeValue, HashSet<InstanceRef>>,
}
impl<'ll> State<'ll> {
pub fn schedule_events<I>(&mut self, iter: I)
where
I: Iterator<Item = Event>,
{
let time = self.time.clone();
let probes = self.probes.clone();
for i in iter {
assert!(i.time >= time);
debug!(
"Schedule {} <- {} [@ {}]",
i.signal
.0
.iter()
.map(|s| {
let sig = s.target.unwrap_signal();
probes
.get(&sig)
.map(|n| n[0].clone())
.unwrap_or_else(|| format!("{:?}", sig))
})
.collect::<String>(),
i.value,
i.time,
);
self.events
.entry(i.time)
.or_insert_with(Default::default)
.insert(i.signal, i.value);
}
}
pub fn schedule_timed<I>(&mut self, iter: I)
where
I: Iterator<Item = TimedInstance>,
{
let time = self.time.clone();
for i in iter {
assert!(i.time >= time);
debug!("Schedule {:?} [@ {}]", i.inst, i.time);
self.timed
.entry(i.time)
.or_insert_with(Default::default)
.insert(i.inst);
}
}
pub fn take_next_events(&mut self) -> impl Iterator<Item = (ValuePointer, Value)> {
if let Some(x) = self.events.remove(&self.time) {
x.into_iter()
} else {
HashMap::new().into_iter()
}
}
pub fn take_next_timed(&mut self) -> impl Iterator<Item = InstanceRef> {
if let Some(x) = self.timed.remove(&self.time) {
x.into_iter()
} else {
HashSet::new().into_iter()
}
}
pub fn next_time(&self) -> Option<TimeValue> {
use std::cmp::min;
match (self.events.keys().next(), self.timed.keys().next()) {
(Some(e), Some(t)) => Some(min(e, t).clone()),
(Some(e), None) => Some(e.clone()),
(None, Some(t)) => Some(t.clone()),
(None, None) => None,
}
}
}
impl Index<SignalRef> for State<'_> {
type Output = Signal;
fn index(&self, idx: SignalRef) -> &Self::Output {
&self.signals[idx.0]
}
}
impl IndexMut<SignalRef> for State<'_> {
fn index_mut(&mut self, idx: SignalRef) -> &mut Self::Output {
&mut self.signals[idx.0]
}
}
impl<'ll> Index<InstanceRef> for State<'ll> {
type Output = Mutex<Instance<'ll>>;
fn index(&self, idx: InstanceRef) -> &Self::Output {
&self.insts[idx.0]
}
}
impl IndexMut<InstanceRef> for State<'_> {
fn index_mut(&mut self, idx: InstanceRef) -> &mut Self::Output {
&mut self.insts[idx.0]
}
}
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct SignalRef(usize);
impl SignalRef {
pub fn new(id: usize) -> SignalRef {
SignalRef(id)
}
pub fn as_usize(&self) -> usize {
self.0
}
}
impl fmt::Debug for SignalRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "s{}", self.0)
}
}
pub struct Signal {
ty: llhd::Type,
value: Value,
}
impl Signal {
pub fn new(ty: llhd::Type, value: Value) -> Signal {
Signal {
ty: ty,
value: value,
}
}
pub fn ty(&self) -> &llhd::Type {
&self.ty
}
pub fn value(&self) -> &Value {
&self.value
}
pub fn set_value(&mut self, value: Value) -> bool {
if self.value != value {
self.value = value;
true
} else {
false
}
}
}
pub struct Instance<'ll> {
pub values: HashMap<llhd::ir::Value, ValueSlot>,
pub kind: InstanceKind<'ll>,
pub state: InstanceState,
pub signals: Vec<SignalRef>,
pub signal_values: HashMap<SignalRef, llhd::ir::Value>,
}
impl<'ll> Instance<'ll> {
pub fn value(&self, id: llhd::ir::Value) -> &ValueSlot {
self.values.get(&id).unwrap()
}
pub fn set_value(&mut self, id: llhd::ir::Value, value: ValueSlot) {
self.values.insert(id, value);
}
pub fn name(&self) -> String {
match self.kind {
InstanceKind::Process { prok, .. } => prok.name().to_string(),
InstanceKind::Entity { entity, .. } => entity.name().to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValueSlot {
Signal(SignalRef),
Variable(Value),
Const(Value),
VariablePointer(ValuePointer),
SignalPointer(ValuePointer),
}
impl fmt::Display for ValueSlot {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueSlot::Signal(v) => fmt::Debug::fmt(v, f),
ValueSlot::Variable(v) => fmt::Display::fmt(v, f),
ValueSlot::Const(v) => fmt::Display::fmt(v, f),
ValueSlot::VariablePointer(v) => fmt::Display::fmt(v, f),
ValueSlot::SignalPointer(v) => fmt::Display::fmt(v, f),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ValuePointer(pub Vec<ValueSlice>);
impl fmt::Display for ValuePointer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let single = self.0.len() == 1;
if !single {
write!(f, "[")?;
}
let mut first = true;
for s in &self.0 {
if f.alternate() && !single {
write!(f, "\n ")?;
} else if !first {
write!(f, ", ")?;
}
write!(f, "{}", s)?;
first = false;
}
if !single {
if f.alternate() {
write!(f, "\n]")
} else {
write!(f, "]")
}
} else {
Ok(())
}
}
}
impl ValuePointer {
pub fn width(&self) -> usize {
self.0.iter().map(|s| s.width).sum()
}
pub fn offset_slices(&self) -> impl Iterator<Item = (usize, &ValueSlice)> {
let mut i = 0;
self.0.iter().map(move |s| {
let v = i;
i += s.width;
(v, s)
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ValueSlice {
pub target: ValueTarget,
pub select: Vec<ValueSelect>,
pub width: usize,
}
impl fmt::Display for ValueSlice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.target)?;
for s in &self.select {
write!(f, "{}", s)?;
}
Ok(())
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ValueTarget {
Value(llhd::ir::Value),
Variable(llhd::ir::Value),
Signal(SignalRef),
}
impl fmt::Display for ValueTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueTarget::Value(v) => write!(f, "{}", v),
ValueTarget::Variable(v) => write!(f, "*{}", v),
ValueTarget::Signal(v) => write!(f, "${:?}", v),
}
}
}
impl ValueTarget {
#[allow(dead_code)]
pub fn unwrap_value(&self) -> llhd::ir::Value {
match *self {
ValueTarget::Value(v) => v,
_ => panic!("value target is not a value"),
}
}
pub fn unwrap_variable(&self) -> llhd::ir::Value {
match *self {
ValueTarget::Variable(v) => v,
_ => panic!("value target is not a variable"),
}
}
pub fn unwrap_signal(&self) -> SignalRef {
match *self {
ValueTarget::Signal(v) => v,
_ => panic!("value target is not a signal"),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ValueSelect {
Field(usize),
Slice(usize, usize),
}
impl fmt::Display for ValueSelect {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValueSelect::Field(i) => write!(f, ".{}", i),
ValueSelect::Slice(o, l) => write!(f, "[{}+:{}]", o, l),
}
}
}
pub enum InstanceKind<'ll> {
Process {
prok: llhd::ir::Unit<'ll>,
next_block: Option<llhd::ir::Block>,
},
Entity {
entity: llhd::ir::Unit<'ll>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum InstanceState {
Ready,
Wait(Option<TimeValue>, Vec<SignalRef>),
Done,
}
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct InstanceRef(usize);
impl InstanceRef {
pub fn new(id: usize) -> InstanceRef {
InstanceRef(id)
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Event {
pub time: TimeValue,
pub signal: ValuePointer,
pub value: Value,
}
impl Ord for Event {
fn cmp(&self, rhs: &Event) -> Ordering {
match self.time.cmp(&rhs.time) {
Ordering::Equal => self.signal.cmp(&rhs.signal),
Ordering::Greater => Ordering::Less,
Ordering::Less => Ordering::Greater,
}
}
}
impl PartialOrd for Event {
fn partial_cmp(&self, rhs: &Event) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct TimedInstance {
pub time: TimeValue,
pub inst: InstanceRef,
}
impl Ord for TimedInstance {
fn cmp(&self, rhs: &TimedInstance) -> Ordering {
match self.time.cmp(&rhs.time) {
Ordering::Equal => self.inst.cmp(&rhs.inst),
Ordering::Greater => Ordering::Less,
Ordering::Less => Ordering::Greater,
}
}
}
impl PartialOrd for TimedInstance {
fn partial_cmp(&self, rhs: &TimedInstance) -> Option<Ordering> {
Some(self.cmp(rhs))
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Scope {
pub name: String,
pub probes: HashMap<SignalRef, Vec<String>>,
pub subscopes: Vec<Scope>,
}
impl Scope {
pub fn new(name: impl Into<String>) -> Scope {
Scope {
name: name.into(),
probes: Default::default(),
subscopes: vec![],
}
}
pub fn add_subscope(&mut self, scope: Scope) {
self.subscopes.push(scope);
}
pub fn add_probe(&mut self, signal: SignalRef, name: String) {
self.probes.entry(signal).or_insert(Vec::new()).push(name);
}
}