Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8bb27f4
Add standalone VerilogA runner (openvaf-r --run)
Kreijstal Jun 24, 2026
51e8654
runner: also execute the analog body so @(initial_step) $strobe prints
Kreijstal Jun 24, 2026
7b40cdc
Point issue/crash-report URLs at the maintained fork (arpadbuermen/Op…
Kreijstal Jun 24, 2026
fee06b5
Implement digital gate features: @(cross/timer) events + transition()
Kreijstal Jun 24, 2026
3b32c8d
parser: don't panic on unsupported module-port syntax
Kreijstal Jun 24, 2026
c73a4ee
Arrays/indexing: grammar + HIR plumbing (foundation for scorecard 9/9)
Kreijstal Jun 24, 2026
811752e
Arrays: const-eval array dimensions (real x[a:b] -> Type::Array)
Kreijstal Jun 24, 2026
32f9d5c
Arrays: element read/write lowering (const + runtime index) + two bug…
Kreijstal Jun 24, 2026
6d64803
laplace_nd: state-space realization -> Butterworth filter compiles (8/9)
Kreijstal Jun 24, 2026
31c632e
genvar + bus nodes: RC ladder compiles -> scorecard 9/9
Kreijstal Jun 24, 2026
1eb16da
transition(): continuous slew-limited realization (Level-2)
Kreijstal Jun 24, 2026
39c657f
@(cross) state retention: cross-timestep latch state via prev_state/n…
Kreijstal Jun 24, 2026
b3bc1ef
transition(): accept real first argument
Kreijstal Jun 24, 2026
df8ea39
tests: behavioral regression tests for arrays and @(cross) retention
Kreijstal Jun 25, 2026
86ae31d
laplace_nd: widen integer coefficient literals to real (fixes compile…
Kreijstal Jun 25, 2026
47c97a9
vector ports: support ranged port declarations (input [0:3] in)
Kreijstal Jun 25, 2026
9015777
retained @(cross): support real-typed and array variables
Kreijstal Jun 25, 2026
942eeb7
indirect branch assignments (V(out) : f(...) == 0)
Kreijstal Jun 25, 2026
d10dd4e
sim_back: skip None outputs in compute_outputs (fixes #10)
Kreijstal Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 30 additions & 4 deletions openvaf/hir/src/body.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use hir_def::db::HirDefDB;
pub use hir_def::expr::Event;
pub use hir_def::expr::{Event, GlobalEvent};
use hir_def::DefWithBodyId;
pub use hir_def::{/*expr::CaseCond,*/ BuiltIn, Case, ExprId, Literal, ParamSysFun, StmtId, Type,};
use hir_ty::db::HirTyDB;
Expand Down Expand Up @@ -167,6 +167,7 @@ impl<'a> BodyRef<'a> {
Expr::Call { fun, args }
}
hir_def::Expr::Array(ref args) => Expr::Array(args),
hir_def::Expr::Index { base, index } => Expr::Index { base, index },
hir_def::Expr::Literal(ref literal) => Expr::Literal(literal),
_ => panic!("invalid HIR: {:?}", self.body.exprs[expr]),
}
Expand All @@ -187,11 +188,16 @@ impl<'a> BodyRef<'a> {
hir_def::Stmt::EventControl { ref event, body } => {
Some(Stmt::EventControl { event, body })
}
hir_def::Stmt::Assignment { val, .. } => {
hir_def::Stmt::Assignment { val, assignment_kind, .. } => {
let indirect = assignment_kind == syntax::ast::AssignOp::Indirect;
let stmt = match self.infere.assignment_destination[&stmnt] {
inference::AssignDst::Var(id) => {
Stmt::Assignment { lhs: AssignmentLhs::Variable(Variable { id }), rhs: val }
}
inference::AssignDst::VarElement { var, index } => Stmt::Assignment {
lhs: AssignmentLhs::ArrayElement { var: Variable { id: var }, index },
rhs: val,
},
inference::AssignDst::FunVar { fun, arg: None } => Stmt::Assignment {
lhs: AssignmentLhs::FunctionReturn(Function { id: fun }),
rhs: val,
Expand All @@ -201,12 +207,20 @@ impl<'a> BodyRef<'a> {
rhs: val,
},
inference::AssignDst::Flow(branch) => Stmt::Contribute {
kind: ContributeKind::Flow,
kind: if indirect {
ContributeKind::IndirectFlow
} else {
ContributeKind::Flow
},
branch: branch.into(),
rhs: val,
},
inference::AssignDst::Potential(branch) => Stmt::Contribute {
kind: ContributeKind::Potential,
kind: if indirect {
ContributeKind::IndirectPotential
} else {
ContributeKind::Potential
},
branch: branch.into(),
rhs: val,
},
Expand All @@ -231,12 +245,22 @@ pub enum AssignmentLhs {
Variable(Variable),
FunctionReturn(Function),
FunctionArg(FunctionArg),
/// `arr[index] = …` — assignment to an array element.
ArrayElement { var: Variable, index: ExprId },
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ContributeKind {
Flow,
Potential,
/// Indirect branch assignment `I(out) : f(...) == 0` — `out` becomes a current
/// source whose value is solved so the constraint `f == 0` holds. `rhs` is the
/// constraint equation.
IndirectFlow,
/// Indirect branch assignment `V(out) : f(...) == 0` — `out` becomes a voltage
/// source whose value is solved so the constraint `f == 0` holds. `rhs` is the
/// constraint equation.
IndirectPotential,
}

#[derive(Debug, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -270,6 +294,8 @@ pub enum Expr<'a> {
Select { cond: ExprId, then_val: ExprId, else_val: ExprId },
Call { fun: ResolvedFun, args: &'a [ExprId] },
Array(&'a [ExprId]),
/// Array element access `base[index]`.
Index { base: ExprId, index: ExprId },
Literal(&'a Literal),
}
impl Expr<'_> {
Expand Down
15 changes: 12 additions & 3 deletions openvaf/hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub use basedb::{BaseDB, FileId};
use hir_def::db::HirDefDB;
use hir_def::nameres::diagnostics::DefDiagnosticWrapped;
use hir_def::nameres::{DefMap, LocalScopeId, ScopeDefItem, ScopeOrigin};
use hir_def::DefWithBodyId;
use hir_def::{DefWithBodyId, ModuleBodyKind};
use hir_ty::diagnostics::InferenceDiagnosticWrapped;
use hir_ty::validation::{
self, BodyValidationDiagnostic, BodyValidationDiagnosticWrapped,
Expand Down Expand Up @@ -48,7 +48,7 @@ pub(crate) fn collect(db: &CompilationDB, root_file: FileId, sink: &mut impl Dia
collect_body_diagnostcs(
db,
sink,
DefWithBodyId::ModuleId { initial: true, module },
DefWithBodyId::ModuleId { kind: ModuleBodyKind::AnalogInitial, module },
&parse,
&sm,
root_file,
Expand All @@ -57,7 +57,16 @@ pub(crate) fn collect(db: &CompilationDB, root_file: FileId, sink: &mut impl Dia
collect_body_diagnostcs(
db,
sink,
DefWithBodyId::ModuleId { initial: false, module },
DefWithBodyId::ModuleId { kind: ModuleBodyKind::Analog, module },
&parse,
&sm,
root_file,
&ast_id_map,
);
collect_body_diagnostcs(
db,
sink,
DefWithBodyId::ModuleId { kind: ModuleBodyKind::Procedural, module },
&parse,
&sm,
root_file,
Expand Down
23 changes: 18 additions & 5 deletions openvaf/hir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ pub use hir_def::nameres::diagnostics::PathResolveError;
use hir_def::nameres::{DefMap, LocalScopeId, ScopeDefItem};
use hir_def::{
AliasParamId, BlockId, BlockLoc, BranchId, DefWithBodyId, DisciplineId, FunctionId,
LocalFunctionArgId, Lookup, ModuleId, ModuleLoc, NatureAttrId, NatureId, NodeId, ParamId,
VarId,
LocalFunctionArgId, Lookup, ModuleBodyKind, ModuleId, ModuleLoc, NatureAttrId, NatureId,
NodeId, ParamId, VarId,
};
pub use hir_def::{BuiltIn, Case, Literal, ParamSysFun, Path, Type};
pub use hir_ty::builtin;
Expand All @@ -37,7 +37,8 @@ pub use syntax::name::Name;

pub use crate::attributes::AstCache;
pub use crate::body::{
AssignmentLhs, Body, BodyRef, ContributeKind, Expr, ExprId, Ref, ResolvedFun, Stmt, StmtId,
AssignmentLhs, Body, BodyRef, ContributeKind, Event, Expr, ExprId, GlobalEvent, Ref,
ResolvedFun, Stmt, StmtId,
};
pub use crate::db::CompilationDB;

Expand Down Expand Up @@ -162,11 +163,23 @@ impl Module {
}

pub fn analog_initial_block(&self, db: &CompilationDB) -> Body {
Body::new(DefWithBodyId::ModuleId { initial: true, module: self.id }, db)
Body::new(
DefWithBodyId::ModuleId { kind: ModuleBodyKind::AnalogInitial, module: self.id },
db,
)
}

pub fn analog_block(&self, db: &CompilationDB) -> Body {
Body::new(DefWithBodyId::ModuleId { initial: false, module: self.id }, db)
Body::new(DefWithBodyId::ModuleId { kind: ModuleBodyKind::Analog, module: self.id }, db)
}

/// The imperative `initial`/`final` procedural body executed by the standalone
/// VerilogA runner (`openvaf-r run`). Empty for ordinary device models.
pub fn procedural_block(&self, db: &CompilationDB) -> Body {
Body::new(
DefWithBodyId::ModuleId { kind: ModuleBodyKind::Procedural, module: self.id },
db,
)
}

// todo: just temporary for VAE, this needs to be cleaned up
Expand Down
70 changes: 62 additions & 8 deletions openvaf/hir_def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ use basedb::lints::{Lint, LintSrc};
use basedb::{AttrDiagnostic, LintAttrs};
use lower::LowerCtx;
use stdx::Ieee64;
use syntax::name::AsName;
use syntax::{ast, AstNode, AstPtr};

use crate::db::HirDefDB;
use crate::item_tree::{DisciplineAttr, ItemTreeId, ItemTreeNode, NatureAttr};
use crate::nameres::{DefMapSource, LocalScopeId};
use crate::{
DefWithBodyId, DisciplineAttrLoc, DisciplineLoc, Expr, ExprId, FunctionLoc, Literal, Lookup,
ModuleLoc, NatureAttrLoc, NatureLoc, ParamId, ParamLoc, ScopeId, Stmt, StmtId, Type, VarLoc,
ModuleBodyKind, ModuleLoc, NatureAttrLoc, NatureLoc, ParamId, ParamLoc, ScopeId, Stmt, StmtId,
Type, VarLoc,
};

mod lower;
Expand Down Expand Up @@ -67,7 +69,7 @@ impl Body {
let (body, sm, _) = db.param_body_with_sourcemap(param);
return (body, sm);
}
DefWithBodyId::ModuleId { initial, module } => {
DefWithBodyId::ModuleId { kind, module } => {
let ModuleLoc { scope, id: item_tree } = module.lookup(db);

let ast_id = tree[item_tree].ast_id();
Expand All @@ -81,11 +83,39 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope,
registry: &registry,
genvar_names: ast
.module_items()
.filter_map(|it| match it {
ast::ModuleItem::GenvarDecl(g) => Some(g),
_ => None,
})
.flat_map(|g| g.names().map(|n| n.as_name()))
.collect(),
bus_names: ast
.module_items()
.filter_map(|it| match it {
ast::ModuleItem::NetDecl(net) if net.dimension().is_some() => Some(net),
_ => None,
})
.flat_map(|net| net.names().map(|n| n.as_name()))
.collect(),
module: Some(ast.clone()),
genvars: Vec::new(),
};
body.entry_stmts = if initial {
ast.analog_initial_behaviour().map(|stmt| ctx.collect_stmt(stmt)).collect()
} else {
ast.analog_behaviour().map(|stmt| ctx.collect_stmt(stmt)).collect()
body.entry_stmts = match kind {
ModuleBodyKind::AnalogInitial => {
ast.analog_initial_behaviour().map(|stmt| ctx.collect_stmt(stmt)).collect()
}
ModuleBodyKind::Analog => {
ast.analog_behaviour().map(|stmt| ctx.collect_stmt(stmt)).collect()
}
// Procedural runner lane: all `initial` blocks (source order) then
// all `final` blocks, as one imperative sequence.
ModuleBodyKind::Procedural => ast
.initial_behaviour()
.chain(ast.final_behaviour())
.map(|stmt| ctx.collect_stmt(stmt))
.collect(),
};
}

Expand All @@ -110,6 +140,10 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope,
registry: &registry,
genvar_names: Vec::new(),
bus_names: Vec::new(),
module: None,
genvars: Vec::new(),
};
body.entry_stmts = ast.body().map(|stmt| ctx.collect_stmt(stmt)).collect();
}
Expand All @@ -127,15 +161,23 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope,
registry: &registry,
genvar_names: Vec::new(),
bus_names: Vec::new(),
module: None,
genvars: Vec::new(),
};

let expr = if let Some(expr) = ast.default() {
ctx.collect_expr(expr)
} else {
let default_val = match db.var_data(var).ty {
Type::Real => Literal::Float(Ieee64::with_float(0.0)),
Type::Integer => Literal::Int(0),
_ => unreachable!("invalid var type (TODO arrays)"),
// Arrays have no scalar default (their elements are managed
// per-element during lowering); use 0.0 as a placeholder.
Type::Real | Type::Array { .. } => {
Literal::Float(Ieee64::with_float(0.0))
}
_ => unreachable!("invalid var type"),
};
ctx.alloc_expr_desugared(Expr::Literal(default_val))
};
Expand All @@ -160,6 +202,10 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope,
registry: &registry,
genvar_names: Vec::new(),
bus_names: Vec::new(),
module: None,
genvars: Vec::new(),
};
let expr = ctx.collect_opt_expr(ast.val());
let stmt = ctx.alloc_stmt_desugared(Stmt::Expr(expr));
Expand All @@ -182,6 +228,10 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope,
registry: &registry,
genvar_names: Vec::new(),
bus_names: Vec::new(),
module: None,
genvars: Vec::new(),
};
let expr = ctx.collect_opt_expr(ast.val());
let stmt = ctx.alloc_stmt_desugared(Stmt::Expr(expr));
Expand Down Expand Up @@ -216,6 +266,10 @@ impl Body {
ast_id_map: &ast_id_map,
curr_scope: (scope, ast_id.into()),
registry: &registry,
genvar_names: Vec::new(),
bus_names: Vec::new(),
module: None,
genvars: Vec::new(),
};

let default = ctx.collect_opt_expr(ast.default());
Expand Down
Loading
Loading