use sv_lang::kinds::{ExpressionKind, SymbolKind};
use sv_lang::{Symbol, Type};
use crate::symid::SymbolId;
pub const DYNAMIC_ROWS: u32 = 1 << 14;
#[derive(Clone, Copy)]
pub struct PoolStatic<'d> {
pub var: Symbol<'d>,
pub first: u32,
pub count: u32,
}
pub struct EventPool<'d> {
pub statics: Vec<PoolStatic<'d>>,
pub static_rows: u32,
}
impl EventPool<'_> {
pub fn total_rows(&self) -> u32 {
self.dynamic_base() + DYNAMIC_ROWS
}
pub fn dynamic_base(&self) -> u32 {
2 * self.static_rows + 1
}
}
pub fn pool_key() -> SymbolId {
SymbolId::synthetic_tagged("event_pool")
}
pub fn static_key(var: &SymbolId) -> SymbolId {
var.derive("event_pool_static")
}
pub fn pool_of_key(var: &SymbolId) -> SymbolId {
var.derive("event_pool_of")
}
pub fn event_count(ty: &Type<'_>) -> Option<u32> {
let mut rows: u32 = 1;
let mut cur = *ty;
while cur.is_unpacked_array() && !super::storage::is_collection(&cur) {
rows = rows.checked_mul(cur.fixed_unpacked_array_range().width())?;
cur = cur.element_type()?;
}
cur.is_event().then_some(rows)
}
pub fn event_pool<'d>(body: &Symbol<'d>) -> Option<EventPool<'d>> {
if !needs_pool(body) {
return None;
}
let mut statics = Vec::new();
let mut next: u32 = 1;
for v in crate::netlist::state_items(body) {
if !matches!(v.kind(), SymbolKind::Variable | SymbolKind::FormalArgument) {
continue;
}
let Some(count) = v.value_type().as_ref().and_then(event_count) else {
continue;
};
statics.push(PoolStatic {
var: v,
first: next,
count,
});
next += count;
}
Some(EventPool {
statics,
static_rows: next - 1,
})
}
pub fn hierarchical_pool_event<'d>(e: &sv_lang::Expression<'d>) -> Option<Symbol<'d>> {
let mut e = *e;
loop {
if e.kind() == ExpressionKind::Conversion
&& let Some(inner) = e.conversion_operand()
{
e = inner;
} else if e.kind() == ExpressionKind::ElementSelect
&& let Some(base) = e.select_value()
{
e = base;
} else {
break;
}
}
if e.kind() != ExpressionKind::HierarchicalValue {
return None;
}
let sym = e.referenced_symbol()?;
if !sym.value_type().as_ref().and_then(event_count).is_some() {
return None;
}
let owner = crate::netlist::enclosing_instance_body(&sym)?;
event_pool(&owner).is_some().then_some(sym)
}
fn needs_pool(body: &Symbol<'_>) -> bool {
let automatic_event = |v: &Symbol<'_>| {
matches!(v.kind(), SymbolKind::Variable | SymbolKind::FormalArgument)
&& v.value_type().as_ref().and_then(event_count).is_some()
&& (v.kind() == SymbolKind::FormalArgument
|| v.variable_lifetime() != sv_lang::VariableLifetime::Static)
};
for m in crate::netlist::module_items(body) {
let kind = m.kind();
if kind == SymbolKind::Subroutine && m.members().any(|v| automatic_event(&v)) {
return true;
}
if kind != SymbolKind::Subroutine && kind != SymbolKind::ProceduralBlock {
continue;
}
let Some(code) = crate::process::cfg::proc_body(&m) else {
continue;
};
let mut stack = vec![code.as_sem_node()];
while let Some(n) = stack.pop() {
if let Some(s) = n.as_statement()
&& crate::process::cfg::block_scopes(&s)
.iter()
.any(|block| block.members().any(|v| automatic_event(&v)))
{
return true;
}
if let Some(s) = n.as_statement()
&& let Some(mut c) = s.condition()
{
while c.kind() == ExpressionKind::Conversion
&& let Some(x) = c.conversion_operand()
{
c = x;
}
if c.expr_type().is_some_and(|t| t.is_event()) {
return true;
}
}
if let Some(e) = n.as_expression() {
let event_typed = |x: Option<sv_lang::Expression<'_>>| {
x.and_then(|x| x.expr_type()).is_some_and(|t| t.is_event())
};
match e.kind() {
ExpressionKind::Assignment if event_typed(e.left()) => return true,
ExpressionKind::BinaryOp if event_typed(e.left()) || event_typed(e.right()) => {
return true;
}
ExpressionKind::UnaryOp if event_typed(e.operand()) => return true,
ExpressionKind::Conversion
if event_typed(e.conversion_operand()) && !event_typed(Some(e)) =>
{
return true;
}
_ => {}
}
}
stack.extend(crate::process::cfg::live_children(&n));
}
}
false
}